std:: установить собственный компаратор для 2D точек

Мне нужен список не дублированных 2D точек, поэтому я использую std::set с пользовательской функцией сравнения. У функции, которую я использую, возникают проблемы после вставки точек, потому что иногда std::find не находит уже вставленные точки.

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

Должен ли я предварительно заказать 2d точки перед вставкой в std::set или есть лучшая функция сравнения для 2d точек?

Мне нужно использовать std::find после ввода всех точек для получения индексов конечной точки.

Я использую родной C++ на Microsoft Visual Studio 2010.

2 ответа

Решение

Ваша функция сравнения неверна. Убери + толерантность. Это не полезно при попытке определить абсолютный порядок среди значений с плавающей запятой. Например, он не обеспечивает транзитивность эквивалентности. То есть если A == B (т.е. f(A, B) а также f(B, A) оба ложные) и B == C, то это не обязательно тот случай, когда A == C когда у вас есть эта корректировка толерантности там.

Просто сделай это:

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

Во-первых, если у вас нет причин не делать этого, лучше просто определить operator< для вашего класса это означает меньше печатать при использовании std::set и т.д., и означает, что вы можете использовать инфикс <, Во-вторых, как указывает Бенджамин, не должно быть необходимости tolerance, В-третьих, вы можете упростить логику сравнения.

Вы должны иметь что-то вроде:

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

Тогда вы можете просто использовать std::set<MyPoint2D>,

Другие вопросы по тегам