2015-12-02 2 views
2

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

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.

ответ

5

Ваша функция сравнения неправильно. Выньте + -толерантность. Это не полезно при попытке определить абсолютный порядок среди значений с плавающей запятой. Например, он не обеспечивает транзитивности эквивалентности. То есть, если 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; 
+0

спасибо! Моя идея состояла в том, чтобы использовать 'std :: set', чтобы очистить список точек и получить как ту же точку на две точки ближе, чем допуск (поэтому допуск такой большой, 0,1), но я вижу, что невозможно сделайте это с помощью 'std :: set'. – JordiS

2

Во-первых, если у вас нет оснований не, это предпочтительнее, чтобы просто определить 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>.

+1

Если 'A' - {0,1}, а' B' - {1,0}, это вернет true для обеих символов A

+0

@BenjaminLindley Ах да, спасибо. редактирование должно делать трюк – Daniel

 Смежные вопросы

  • Нет связанных вопросов^_^