Looking for a C++ solution.
I had thoughts whether to ask this question over here or MathExchange etc. but since it's more of a programming based question thus posting here.
Real problem:
I have an XML with field as:
<part name='01' x='351' y='151'/>
Where x and y, I am storing as QPointf object. Also, I require the name=01 value which I am mapping together with the QPointf object to create a map.
Now there are certain operations that I need to do on this map :
First I need to get all the points(QPointf) and draw over an image.
Second, I will modify the x and y value of certain points getting the points from the GUI.
When I get the points from GUI, I need to check x and y value in each Qpointf inside map.
Problem in simpler form:
I am looking for a data structure such that instead of having a map of key and QPointf, it makes parsing and looking for x and y value of points(QPointf) easier. Just that the QPointf and key should form a unique pair with each other, so that parsing through the entire list of points to find certain (x,y) and modifying it is faster and even when x and y value of QPointf is modified the key attached to it is same.
PS: I hope I was clear with the problem, if there is anything unclear then please edit/comment so that the question can be improved.
My guess is here that your most important aspect is finding a certain set of x and y points when a user uses the UI. There are many acceleration structures possible, but I would probably recommend a point index grid. That is, you partition the indices of points into 2D buckets. When a user chooses a point in the UI, you can do a quick look-up on what bucket the point is in, and you can then iterate over only the points present in that bucket to find the actual point.
As for your data, I would store it in an array:
struct NamePoint {
int name, x, y;
};
std::vector<NamePoint> points;
Now you would create a point index grid that refers to the points array. Implementing one yourself might be worthwhile, but otherwise I know that there exists an OpenVDB version that works.
I made a small dirty implementation so you can see the principle. I have no checks for inputs, so if you're not careful you will access out of the bounds of the vector (e.g., calling pointIndexGrid.indicesForPoint(5, 5) gives segmentation fault).
#include <iostream>
#include <vector>
#include <limits>
struct NamePoint {
int name, x, y;
};
template <typename T> // Just so any array type can work
struct PointIndexGrid {
using ArrayType = T;
using size_type = typename ArrayType::size_type;
PointIndexGrid(const ArrayType& points, int gridSize)
: mGridSize(gridSize)
{
// Find the domain. We will create a 2D vector which will all contain another vector with indices.
maxX = maxY = std::numeric_limits<int>::min();
minX = minY = std::numeric_limits<int>::max();
for (const auto& p : points) {
maxX = p.x > maxX ? p.x : maxX;
maxY = p.y > maxY ? p.y : maxY;
minX = p.x < minX ? p.x : minX;
minY = p.x < minY ? p.x : minY;
}
// create buckets
int nbrXBuckets = (maxX - minX)/mGridSize + 1; // Due to integer arithmetics we round down -- lets add one extra just in case
int nbrYBuckets = (maxY - minY)/mGridSize + 1;
for (int n = 0; n < nbrXBuckets; ++n) {
mBuckets.emplace_back(std::vector<std::vector<size_type>>(nbrYBuckets));
}
// Partition points
for (size_type i = 0; i < points.size(); ++i) {
int xBucket = (points[i].x - minX)/mGridSize; // this is the method how to easily calculate the bucket. Pure arithmetics -- goes fast
int yBucket = (points[i].y - minY)/mGridSize;
mBuckets[xBucket][yBucket].emplace_back(i);
}
}
std::vector<size_type> indicesForPoint(int x, int y)
{
int xBucket = (x - minX)/mGridSize; // Same as above
int yBucket = (y - minY)/mGridSize;
return mBuckets[xBucket][yBucket];
}
private:
int mGridSize;
int maxX, minX;
int maxY, minY;
std::vector<std::vector<std::vector<size_type>>> mBuckets;
};
int main() {
std::vector<NamePoint> points;
points.emplace_back(NamePoint{1, 1, 1});
points.emplace_back(NamePoint{2, 1, 2});
points.emplace_back(NamePoint{3, 1, 2});
points.emplace_back(NamePoint{4, 2, 2});
points.emplace_back(NamePoint{5, 3, 3});
PointIndexGrid<std::vector<NamePoint>> pointIndexGrid(points, 2);
std::cout << "Indices for (1, 1): " << std::endl;
for (const auto& i : pointIndexGrid.indicesForPoint(1, 1)) {
std::cout << " " << i << std::endl;
}
std::cout << "Indices for (3, 3): " << std::endl;
for (const auto& i : pointIndexGrid.indicesForPoint(3, 3)) {
std::cout << " " << i << std::endl;
}
}
This prints out:
Indices for (1, 1):
0
1
2
3
Indices for (3, 3):
4
So to find a point at a specific (x, y):
Partition all points using the PointIndexGrid.
Use pointIndexGrid.indicesForPoint(x, y).
Iterate through all indices there (and look up the points in the points-array).
Grab the point that you want.
So if I understood correctly you just want an easy way to store your points data.
This isn't the best in terms of performance but if you are not planing on changing it every frame it will work no problem:
#include <map>
typedef std::map<int, std::pair<float, float>> PointContainer;
QPointf* fromPointContainer(PointContainer points)
{
QPointf array = new QPointf[points.size()];
for (size_t i; i < points.size(); i++)
array[i] = QPointf(points[i].first, points[i].second);
return array;
}
int main() {
PointContainer points;
points[0] = { 1.6f/*x*/, 5.8f/*y*/ };
QPointf* array = fromPointContainer(points);
//render here
delete array;//don't forget to delete the array allocated with new
return 0;
}
Related
What would be the best way of resampling a curve into even length segments using C++? What I have is a set of points that represents a 2d curve. In my example below I have a point struct with x and y components and a vector of points with test positions. Each pair of points represents a segment on the curve. Example resample curves are the images below. The red circles are the original positions the green circles are the target positions after the resample.
struct Point
{
float x, y;
};
std::vector<Point> Points;
int numPoints = 5;
float positions[] = {
0.0350462, -0.0589667,
0.0688311, 0.240896,
0.067369, 0.557199,
-0.024258, 0.715255,
0.0533231, 0.948694,
};
// Add points
int offset = 2;
for (int i =0; i < numPoints; i++)
{
offset = i * 2;
Point pt;
pt.x = positions[offset];
pt.y = positions[offset+1];
Points.push_back(pt);
}
See if this works for you. Resampled points are equidistant from each other on the linear interpolation of the source vector's points.
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
struct Point {
double x, y;
};
// Distance gives the Euclidean distance between two Points
double Distance(const Point& a, const Point& b) {
const double dx = b.x - a.x;
const double dy = b.y - a.y;
const double lsq = dx*dx + dy*dy;
return std::sqrt(lsq);
}
// LinearCurveLength calculates the total length of the linear
// interpolation through a vector of Points. It is the sum of
// the Euclidean distances between all consecutive points in
// the vector.
double LinearCurveLength(std::vector<Point> const &points) {
auto start = points.begin();
if(start == points.end()) return 0;
auto finish = start + 1;
double sum = 0;
while(finish != points.end()) {
sum += Distance(*start, *finish);
start = finish++;
}
return sum;
}
// Gives a vector of Points which are sampled as equally-spaced segments
// taken along the linear interpolation between points in the source.
// In general, consecutive points in the result will not be equidistant,
// because of a corner-cutting effect.
std::vector<Point> UniformLinearInterpolation(std::vector<Point> const &source, std::size_t target_count) {
std::vector<Point> result;
if(source.size() < 2 || target_count < 2) {
// degenerate source vector or target_count value
// for simplicity, this returns an empty result
// but special cases may be handled when appropriate for the application
return result;
}
// total_length is the total length along a linear interpolation
// of the source points.
const double total_length = LinearCurveLength(source);
// segment_length is the length between result points, taken as
// distance traveled between these points on a linear interpolation
// of the source points. The actual Euclidean distance between
// points in the result vector can vary, and is always less than
// or equal to segment_length.
const double segment_length = total_length / (target_count - 1);
// start and finish are the current source segment's endpoints
auto start = source.begin();
auto finish = start + 1;
// src_segment_offset is the distance along a linear interpolation
// of the source curve from its first point to the start of the current
// source segment.
double src_segment_offset = 0;
// src_segment_length is the length of a line connecting the current
// source segment's start and finish points.
double src_segment_length = Distance(*start, *finish);
// The first point in the result is the same as the first point
// in the source.
result.push_back(*start);
for(std::size_t i=1; i<target_count-1; ++i) {
// next_offset is the distance along a linear interpolation
// of the source curve from its beginning to the location
// of the i'th point in the result.
// segment_length is multiplied by i here because iteratively
// adding segment_length could accumulate error.
const double next_offset = segment_length * i;
// Check if next_offset lies inside the current source segment.
// If not, move to the next source segment and update the
// source segment offset and length variables.
while(src_segment_offset + src_segment_length < next_offset) {
src_segment_offset += src_segment_length;
start = finish++;
src_segment_length = Distance(*start, *finish);
}
// part_offset is the distance into the current source segment
// associated with the i'th point's offset.
const double part_offset = next_offset - src_segment_offset;
// part_ratio is part_offset's normalized distance into the
// source segment. Its value is between 0 and 1,
// where 0 locates the next point at "start" and 1
// locates it at "finish". In-between values represent a
// weighted location between these two extremes.
const double part_ratio = part_offset / src_segment_length;
// Use part_ratio to calculate the next point's components
// as weighted averages of components of the current
// source segment's points.
result.push_back({
start->x + part_ratio * (finish->x - start->x),
start->y + part_ratio * (finish->y - start->y)
});
}
// The first and last points of the result are exactly
// the same as the first and last points from the input,
// so the iterated calculation above skips calculating
// the last point in the result, which is instead copied
// directly from the source vector here.
result.push_back(source.back());
return result;
}
int main() {
std::vector<Point> points = {
{ 0.0350462, -0.0589667},
{ 0.0688311, 0.240896 },
{ 0.067369, 0.557199 },
{-0.024258, 0.715255 },
{ 0.0533231, 0.948694 }
};
std::cout << "Source Points:\n";
for(const auto& point : points) {
std::cout << std::setw(14) << point.x << " " << std::setw(14) << point.y << '\n';
}
std::cout << '\n';
auto interpolated = UniformLinearInterpolation(points, 7);
std::cout << "Interpolated Points:\n";
for(const auto& point : interpolated) {
std::cout << std::setw(14) << point.x << " " << std::setw(14) << point.y << '\n';
}
std::cout << '\n';
std::cout << "Source linear interpolated length: " << LinearCurveLength(points) << '\n';
std::cout << "Interpolation's linear interpolated length: " << LinearCurveLength(interpolated) << '\n';
}
For green points equidistant along the polyline:
The first run: walk through point list, calculate length of every segment and cumulative length up to current point. Pseudocode:
cumlen[0] = 0;
for (int i=1; i < numPoints; i++) {
len = Sqrt((Point[i].x - Point[i-1].x)^2 + (Point[i].y - Point [i-1].y)^2)
cumlen[i] = cumlen[i-1] + len;
}
Now find length of every new piece
plen = cumlen[numpoints-1] / numpieces;
Now the second run - walk through point list and insert new points in appropriate segments.
i = 0;
for (ip=0; ip<numpieces; ip++) {
curr = plen * ip;
while cumlen[i+1] < curr
i++;
P[ip].x = Points[i].x + (curr - cumlen[i]) * (Points[i+1].x - Points[i].x) /
(cumlen[i+1] - cumlen[i]);
..the same for y
}
Examples of real output for numpieces > numPoints and vice versa
I have a 2 vectors of size 4 to store coordinates of a shape (square/rectangle). 1st vector is for x and 2nd for y. To find out the area of the shape, I need the difference in their length. How do I find the difference between 2 elements within the same vector? Using square as an example:
vector<int> x(4);
vector<int> y(4);
double Square::computeArea()
{
int length;
double area;
if (x[0] == x[1]) //x coordinates are the same
{
length = y[0] - y[1]; //difference in y coordinates to find the length, need help here
}
else if (x[1] == x[2]
{
length = y[1] - y[2];
}
else if ... //repeat
area = length * length;
if (area < 0) { area = -area; }
setArea(area)
return area;
}
If your rectangle has edges which are parallel to the axis, and the points are ordered clockwise (or counterclockwise), you can simply use the first and third element of the arrays:
int yedge, xedge;
xedge = abs(x[0] - x[2]);
if ( xedge == 0 ) //beware, this check works well only for ints!
return area = 0.0;
else yedge = abs(y[0] - y[2]);
return area = xedge * yedge;
If you have more general convex quadrilaterals use something like this:
int dx20 = x[2] - x[0];
int dy10 = y[1] - y[0];
int dy20 = y[2] - y[0];
int dx10 = x[1] - x[0];
int dy30 = y[3] - y[0];
int dx30 = x[3] - x[0];
area = 0.5*abs(dx20*dy10-dy20*dx10);
area += 0.5*abs(dx20*dy30-dy20*dx30);
The beauty of C++ and OOP is that you can think more in terms of the problem than how to program it.
If I were in your place I would use std::pair to save the coordinates.
And have a class representing the rectangle.
I am using the distance between point 1 and 2 as length, and point 1 and 4 as width. It may not be the correct approach in all cases but it should show you have to go about programming your function.
using namespace std;
class Rectangle // Class Rectangle
{
public:
Rectangle(vector<pair<double, double>> neWcoordinates);
double computeArea();
private:
vector<pair<double, double>> coordinates;
};
double Rectangle::computeArea()
{
double length = sqrt(pow(coordinates[0].first-coordinates[1].first,2)+pow(coordinates[0].second-coordinates[1].second,2)
);
double width = sqrt(pow(coordinates[0].first-coordinates[3].first,2)+pow(coordinates[0].second-coordinates[3].second,2));
return length*width;
}
Lets say I have two AABB based areas, each area defined by two coordinates mins{x, y} and maxs{x, y}, I want to find the middle connection point between them.
Since my english is not good, I can't explain all with my words,
see the following picture for easier understanding:
http://i.*.com/WokivEe.png
All I need to find is the red point coordinates.
so If we move this into programming question, actual data structures would look like this:
struct Vec2D {
float x, y;
}
struct Rectangle {
Vec2D min;
Vec2D max;
}
Rectangle obj[2]
Anyone got an idea for an algorithm?
Along either the X or Y axis, sort the coordinates of the sides that touch into order. Then average the 2nd and 3rd ones in that list to find their midpoint. I hope this answers the question sufficiently.
Here is a little algorithm that first find which sides of the objects are closest, and then uses the 4 points along the common side to make a list, sorted along the common axis. The average of the 2 middle points of the sorted list are the answer. This will work for both horizontal and vertical sides. I added accessor functions to the data structures so that they can be indexed; e.g., for a Vec2D, coordinate(0) is the x value and coordinate(1) is the y value.
#include <math.h>
#include <iostream>
#include <limits>
struct Vec2D {
float x, y;
float coordinate(int axis)
{
return (axis & 1) ? y : x;
}
};
struct Rectangle {
Vec2D min;
Vec2D max;
Vec2D corner(int j)
{
return (j & 1) ? max : min;
}
// Get the other corner along the given axis
Vec2D along(int j, int ax)
{
Vec2D p = corner(j);
if (0 == ax)
{
p.x = corner(1-j).x;
}
else
{
p.y = corner(1-j).y;
}
return p;
}
};
using namespace std;
inline Vec2D* vp(const void* p)
{
return (Vec2D*) p;
}
static int compare_x(const void*a, const void*b)
{
if (vp(a)->x < vp(b)->x)
{
return -1;
}
else
if (vp(a)->x > vp(b)->x)
{
return 1;
}
return 0;
}
static int compare_y(const void*a, const void*b)
{
if (vp(a)->y < vp(b)->y)
{
return -1;
}
else
if (vp(a)->y > vp(b)->y)
{
return 1;
}
return 0;
}
int main(void) {
int ax; // axis index
int c0, c1;
float gap = numeric_limits<float>::max();
struct Rectangle obj[2] = {0,2,10,10,10,5,15,20};
struct
{
int ax,c0,c1;
} closest;
// Find out which sides are the closest to each other
for(ax = 0; 2 > ax; ++ax) // Look at x axis and y axis
{
for(c0 = 0; 2 > c0; ++c0) // Look at both corners of obj[0]
{
for(c1 = 0; 2 > c1; ++c1) // Look at both corners of obj[1]
{
float dist = fabs(obj[0].corner(c0).coordinate(ax) - obj[1].corner(c1).coordinate(ax));
if (dist < gap)
{
gap = dist;
closest.ax = ax;
closest.c0 = c0;
closest.c1 = c1;
}
}
}
}
int other = 1 - closest.ax; // The other axis
cout << "The closest gap is along the " << (closest.ax ? 'y' : 'x') << " axis\n";
cout << "The common side is along the " << (other ? 'y' : 'x') << " direction\n";
// Make a list of the 4 points along the common side
Vec2D list[4];
list[0] = obj[0].corner(closest.c0);
list[1] = obj[0].along(closest.c0, other);
list[2] = obj[1].corner(closest.c1);
list[3] = obj[1].along(closest.c1, other);
// Sort them into order along the common axis
qsort(list, 4, sizeof(Vec2D), closest.ax ? compare_x : compare_y);
// Get the average of the 2 middle points along the common axis.
Vec2D answer = {
(list[1].x + list[2].x) / 2,
(list[1].y + list[2].y) / 2
};
cout << "(" << answer.x << "," << answer.y << ")\n";
}
I was searching for the closest pair code and i found this which has used qsort() library function. I basically didn't get the concept of how it's compare parameter works. Explanation related to this particular code will be more appreciated. Thanks.
#include <iostream>
#include <float.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
// A structure to represent a Point in 2D plane
struct Point
{
int x, y;
};
/* Following two functions are needed for library function qsort().
Refer: http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/ */
// Needed to sort array of points according to X coordinate
int compareX(const void* a, const void* b)
{
Point *p1 = (Point *)a, *p2 = (Point *)b;
return (p1->x - p2->x);
}
// Needed to sort array of points according to Y coordinate
int compareY(const void* a, const void* b)
{
Point *p1 = (Point *)a, *p2 = (Point *)b;
return (p1->y - p2->y);
}
// A utility function to find the distance between two points
float dist(Point p1, Point p2)
{
return sqrt( (p1.x - p2.x)*(p1.x - p2.x) +
(p1.y - p2.y)*(p1.y - p2.y)
);
}
// A Brute Force method to return the smallest distance between two points
// in P[] of size n
float bruteForce(Point P[], int n)
{
float min = FLT_MAX;
for (int i = 0; i < n; ++i)
for (int j = i+1; j < n; ++j)
if (dist(P[i], P[j]) < min)
min = dist(P[i], P[j]);
return min;
}
// A utility function to find minimum of two float values
float min(float x, float y)
{
return (x < y)? x : y;
}
// A utility function to find the distance beween the closest points of
// strip of given size. All points in strip[] are sorted accordint to
// y coordinate. They all have an upper bound on minimum distance as d.
// Note that this method seems to be a O(n^2) method, but it's a O(n)
// method as the inner loop runs at most 6 times
float stripClosest(Point strip[], int size, float d)
{
float min = d; // Initialize the minimum distance as d
// Pick all points one by one and try the next points till the difference
// between y coordinates is smaller than d.
// This is a proven fact that this loop runs at most 6 times
for (int i = 0; i < size; ++i)
for (int j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j)
if (dist(strip[i],strip[j]) < min)
min = dist(strip[i], strip[j]);
return min;
}
// A recursive function to find the smallest distance. The array Px contains
// all points sorted according to x coordinates and Py contains all points
// sorted according to y coordinates
float closestUtil(Point Px[], Point Py[], int n)
{
// If there are 2 or 3 points, then use brute force
if (n <= 3)
return bruteForce(Px, n);
// Find the middle point
int mid = n/2;
Point midPoint = Px[mid];
// Divide points in y sorted array around the vertical line.
// Assumption: All x coordinates are distinct.
Point Pyl[mid+1]; // y sorted points on left of vertical line
Point Pyr[n-mid-1]; // y sorted points on right of vertical line
int li = 0, ri = 0; // indexes of left and right subarrays
for (int i = 0; i < n; i++)
{
if (Py[i].x <= midPoint.x)
Pyl[li++] = Py[i];
else
Pyr[ri++] = Py[i];
}
// Consider the vertical line passing through the middle point
// calculate the smallest distance dl on left of middle point and
// dr on right side
float dl = closestUtil(Px, Pyl, mid);
float dr = closestUtil(Px + mid, Pyr, n-mid);
// Find the smaller of two distances
float d = min(dl, dr);
// Build an array strip[] that contains points close (closer than d)
// to the line passing through the middle point
Point strip[n];
int j = 0;
for (int i = 0; i < n; i++)
if (abs(Py[i].x - midPoint.x) < d)
strip[j] = Py[i], j++;
// Find the closest points in strip. Return the minimum of d and closest
// distance is strip[]
return min(d, stripClosest(strip, j, d) );
}
// The main functin that finds the smallest distance
// This method mainly uses closestUtil()
float closest(Point P[], int n)
{
Point Px[n];
Point Py[n];
for (int i = 0; i < n; i++)
{
Px[i] = P[i];
Py[i] = P[i];
}
qsort(Px, n, sizeof(Point), compareX);
qsort(Py, n, sizeof(Point), compareY);
// Use recursive function closestUtil() to find the smallest distance
return closestUtil(Px, Py, n);
}
// Driver program to test above functions
int main()
{
Point P[] = {{2, 3}, {12, 30}, {40, 50}, {5, 1}, {12, 10}, {3, 4}};
int n = sizeof(P) / sizeof(P[0]);
cout << "The smallest distance is " << closest(P, n);
return 0;
}
The last parameter of qsort is a pointer to a function with a specific signature: it must take two void* pointers, and return an int that indicates which of the two passed items is smaller or if the two items are the same. The specifics are here, but generally a positive result indicates that the second item is smaller, a negative indicates that the first item is smaller, and zero indicates the equaliity.
The implementation of compareX
int compareX(const void* a, const void* b)
{
Point *p1 = (Point *)a, *p2 = (Point *)b;
return (p1->x - p2->x);
}
follows the general pattern for comparison functions. First, it converts the void* pointer to the Point type, because it "knows" that it is used together with an array of Point structures. Then it subtracts the x coordinates of the two points:
p1->x - p2->x
Note that the result of the subtraction is going to be positive if the second point's x is smaller, negative when the second point's x is greater, and zero when the two xs are the same. This is precisely what qsort wants the cmp function to do, so the subtraction operation fulfills the contract of the comparison function.
How would you solve the problem of finding the points of a (integer) grid within a circle centered on the origin of the axis, with the results ordered by norm, as in distance from the centre, in C++?
I wrote an implementation that works (yeah, I know, it is extremely inefficient, but for my problem anything more would be overkill). I'm extremely new to C++, so my biggest problem was finding a data structure capable of
being sort-able;
being able to save an array in one of its elements,
rather than the implementation of the algorithm. My code is as follows. Thanks in advance, everyone!
typedef std::pair<int, int[2]> norm_vec2d;
bool norm_vec2d_cmp (norm_vec2d a, norm_vec2d b)
{
bool bo;
bo = (a.first < b.first ? true: false);
return bo;
}
int energy_to_momenta_2D (int energy, std::list<norm_vec2d> *momenta)
{
int i, j, norm, n=0;
int energy_root = (int) std::sqrt(energy);
norm_vec2d temp;
for (i=-energy_root; i<=energy_root; i++)
{
for (j =-energy_root; j<=energy_root; j++)
{
norm = i*i + j*j;
if (norm <= energy)
{
temp.first = norm;
temp.second[0] = i;
temp.second[1] = j;
(*momenta).push_back (temp);
n++;
}
}
}
(*momenta).sort(norm_vec2d_cmp);
return n;
}
How would you solve the problem of finding the points of a (integer) grid within a circle centered on the origin of the axis, with the results ordered by norm, as in distance from the centre, in C++?
I wouldn't use a std::pair to hold the points. I'd create my own more descriptive type.
struct Point {
int x;
int y;
int square() const { return x*x + y*y; }
Point(int x = 0, int y = 0)
: x(x), y(y) {}
bool operator<(const Point& pt) const {
if( square() < pt.square() )
return true;
if( pt.square() < square() )
return false;
if( x < pt.x )
return true;
if( pt.x < x)
return false;
return y < pt.y;
}
friend std::ostream& operator<<(std::ostream& os, const Point& pt) {
return os << "(" << pt.x << "," << pt.y << ")";
}
};
This data structure is (probably) exactly the same size as two ints, it is less-than comparable, it is assignable, and it is easily printable.
The algorithm walks through all of the valid points that satisfy x=[0,radius] && y=[0,x] && (x,y) inside circle:
std::set<Point>
GetListOfPointsInsideCircle(double radius = 1) {
std::set<Point> result;
// Only examine bottom half of quadrant 1, then
// apply symmetry 8 ways
for(Point pt(0,0); pt.x <= radius; pt.x++, pt.y = 0) {
for(; pt.y <= pt.x && pt.square()<=radius*radius; pt.y++) {
result.insert(pt);
result.insert(Point(-pt.x, pt.y));
result.insert(Point(pt.x, -pt.y));
result.insert(Point(-pt.x, -pt.y));
result.insert(Point(pt.y, pt.x));
result.insert(Point(-pt.y, pt.x));
result.insert(Point(pt.y, -pt.x));
result.insert(Point(-pt.y, -pt.x));
}
}
return result;
}
I chose a std::set to hold the data for two reasons:
It is stored is sorted order, so I don't have to std::sort it, and
It rejects duplicates, so I don't have to worry about points whose reflection are identical
Finally, using this algorithm is dead simple:
int main () {
std::set<Point> vp = GetListOfPointsInsideCircle(2);
std::copy(vp.begin(), vp.end(),
std::ostream_iterator<Point>(std::cout, "\n"));
}
It's always worth it to add a point class for such geometric problem, since usually you have more than one to solve. But I don't think it's a good idea to overload the 'less' operator to satisfy the first need encountered. Because:
Specifying the comparator where you sort will make it clear what order you want there.
Specifying the comparator will allow to easily change it without affecting your generic point class.
Distance to origin is not a bad order, but for a grid but it's probably better to use row and columns (sort by x first then y).
Such comparator is slower and will thus slow any other set of points where you don't even care about norm.
Anyway, here is a simple solution using a specific comparator and trying to optimize a bit:
struct v2i{
int x,y;
v2i(int px, int py) : x(px), y(py) {}
int norm() const {return x*x+y*y;}
};
bool r_comp(const v2i& a, const v2i& b)
{ return a.norm() < b.norm(); }
std::vector<v2i> result;
for(int x = -r; x <= r; ++x) {
int my = r*r - x*x;
for(int y = 0; y*y <= my; ++y) {
result.push_back(v2i(x,y));
if(y > 0)
result.push_back(v2i(x,-y));
}
}
std::sort(result.begin(), result.end(), r_comp);