Я написал реализацию алгоритма выпуклой оболочки С ++, которая должна была быть тривиальной.Мой код ниже следует формулам / подходу от документов .Я использую метод под названием «Джарвис марш».
Он отлично работает для 20000 точек и гораздо меньше с точки зрения производительности, но если я рандомизирую порядок массива входных точек (используя std::shuffle
), я мог бы видетьчто иногда он показывает ошибку
После перетасовки вектора ввода тех же точек:
(зеленая линия рассчитана для выпуклой оболочки для заданных черных точек)
Вы можете подумать, что ошибка связана с "последней" выпуклой линией корпуса.Но это несколько иное, что можно наблюдать здесь:
Код:
using namespace std;
vector<Point> m_in;
inline double cross(const Point &a, const Point &b)
{
return (a.x * b.y) - (b.x * a.y);
}
// conterclockwise test
inline bool CCW(const Point &p, const Point &i, const Point &q)
{
// auto a = p.x,
// b = p.y,
// c = i.x,
// d = i.y,
// e = q.x,
// f = q.y;
// the same:
// return ((f - b) * (c - a)) > ((d - b) * (e - a));
// the same:
// Point va { c - a, d - b }; // i - p
// Point vb { e - a, f - b }; // q - p
// return cross(va, vb) > 0;
// the same, compact:
return cross(i - p, q - p) > 0;
}
void Reset(vector<Point> &in)
{
m_in = move(in);
}
vector<Line> GetLine() const
{
vector<Line> res;
Point l = m_in.front();
for(auto &i : m_in)
{
if(l.x < i.x)
{
l = i;
}
}
Point p = l;
for(auto &pi : m_in)
{
Point q = pi;
for(auto &i : m_in)
{
if(CCW(p, i, q))
{
q = i;
}
}
res.push_back(Line { p, q });
p = q;
}
return res;
}
На основе изображения:
Типы, чтобы быть ясным:
struct Point
{
double x, y;
friend Point operator+(const Point& a, const Point& b);
friend Point operator-(const Point& a, const Point& b);
friend bool operator!=(const Point& a, const Point& b);
};
struct Line
{
Point a;
Point b;
};
В конце я не вижу: где конкретная ошибка вэтот код?