c++algorithmdata-structuresdiscrete-space

Find all points of a grid within a circle, ordered by norm


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

  1. being sort-able;
  2. 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;
}

Solution

  • 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:

    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"));
    }