std::set custom comparator for 2D points

眉间皱痕 提交于 2020-03-02 14:52:37

问题


I need a list of non-duplicated 2D points, so I use a std::set with a custom comparison function. The function I use has problems after inserting points because sometimes the std::find does not find the already inserted points.

const double tolerance = 0.1;
struct MyPoint2D
{
  MyPoint2D(double x, double y) : _x(x), _y(y) {}
  double _x, _y;
};
auto compMyPoint2D = [&](const MyPoint2D& pointA, const MyPoint2D& pointB) -> bool
{
  if (pointA._x < pointB._x - tolerance) return true;
  if (pointA._x > pointB._x + tolerance) return false;
  if (pointA._y < pointB._y - tolerance) return true;
  return false;
};
std::set<MyPoint2D, decltype(compMyPoint2D)> orderedMyPoints(compMyPoint2D);
MyPoint2D pointA(0.66,1.14);
MyPoint2D pointB(0.75, 0.0);
MyPoint2D pointC(0.57,1.19);
orderedMyPoints.insert(pointA);
orderedMyPoints.insert(pointB);
orderedMyPoints.insert(pointC);
if (orderedMyPoints.find(pointC)==orderedMyPoints.end())
{
  std::cout << "Not found" << std::endl;
  orderedMyPoints.insert(pointC);
  if (orderedMyPoints.find(pointC)==orderedMyPoints.end())
    std::cout << "Still not found" << std::endl;
}

Would I need to preorder the 2d points before inserting into the std::set or there is a better comparison function for 2d points?

I need to use std::find after inserting all points to obtain the final point indexes.

I'm using native C++ on Microsoft Visual Studio 2010.


回答1:


Your comparison function is wrong. Take out the +-tolerance. That's not useful when trying to determine an absolute order among floating point values. It doesn't enforce transitivity of equivalence, for example. That is, if A == B (i.e. f(A, B) and f(B, A) are both false) and B == C, then it is not necessarily the case that A == C when you have that tolerance adjustment in there.

Just do this:

if (pointA._x < pointB._x) return true;
if (pointA._x > pointB._x) return false;
if (pointA._y < pointB._y) return true;
return false;



回答2:


Firstly, unless you have a reason not to, it's preferable to just define operator< for your class, this means less typing when using std::set etc, and means you can using infix <. Secondly, as Benjamin points out, there should be no need for tolerance. Thirdly, you can simplify the logic of the comparison.

You should have something like:

bool operator<(const MyPoint2D& lhs, const MyPoint2D& rhs)
{
    return lhs._x < rhs._x || (lhs._x == rhs._x && lhs._y < rhs._y);
}

Then you can just use std::set<MyPoint2D>.



来源:https://stackoverflow.com/questions/34047772/stdset-custom-comparator-for-2d-points

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!