Я уже реализовал сканирование Грэма, но я вижу, что узким местом моей программы является сортировка (80% времени). Я хочу улучшить это, сейчас я делаю следующее:
std::sort(intersections.begin() + 1, intersections.end(), [&minElement](Point const& a, Point const& b)
{return angle (minElement - a, XAxis) < angle (minElement - b,XAxis);});
Что дает мне точный угол, но это не дешево, потому что моя функция угла выглядит следующим образом:
float angle (const Point& v1, const Point& v2) {
return dot (v1, v2) / (v1.Length () * v2.Length ());
}
В функции Length мне нужно сделать квадратный корень, что является одной из самых дорогих операций. Но так я получаю хороший заказ.
Я попытался упорядочить массив по Slope, dot, ccw и даже удалить только sqrt из моего сравнения, но ничего из этого не дает мне тот же порядок. Можете ли вы дать мне какой-нибудь совет?
Когда вы сортируете точки по их относительным углам, вам не нужно знать точный угол, который образуют две точки. Скорее, вам просто нужно знать, находится ли одна точка слева или справа от другой.
Изображение, например, вы хотите сравнить две точки (х1, Y1) и (х2, Y2), предполагая, что самая нижняя точка находится в (хп, Yп). Посмотрите на два вектора V1 = (х1 — Иксп, Y1 — Yп) и V2 = (х2 — Иксп, Y2 — Yп). Чтобы определить, v1 находится слева или справа от v2, Это означает, что вы хотите посмотреть на знак угла, идущего от V1 к V2. Если это положительно, то V2 находится слева от V1, и если это отрицательно, то V1 находится слева от V2.
2D-перекрестное произведение обладает хорошим свойством
v1 × V2 = | V1| | v2| Sin (θ)
где θ — угол, образованный переходом от v1 к V2. Это означает, что θ> 0, если v1 находится справа от v2 и наоборот, что приятно, так как позволяет сравнивать, куда идет, просто взяв перекрестный продукт!
Другими словами:
2D формула кросс-произведения определяется как
(? x1, Δy1) × (Δx2, Δy2) = (Δx1 Δy2 — ? x2 Δy1)
Где, здесь, Δx1 представляет х1 — Иксп, и т.п.
Таким образом, вы можете вычислить вышеуказанное количество, а затем посмотреть на его знак, чтобы определить, как эти две точки связаны друг с другом. Квадратные корни не нужны!
Вы можете сделать специальную оптимизацию через кэширование.
Во-первых, Length () может кэшировать свой результат в переменной-члене. Вам нужно только аннулировать это значение в случае изменения точки (и, возможно, это не так). Вы можете выполнить ленивый расчет, поэтому Length проверит, имеет ли оно значение, и вычислит / сохранит, если его нет, затем вернет сохраненное значение.
Во-вторых, для данного minElement и xAxis, угол (минЭлемент — а, ось X) становится функцией от 1 аргумента, поэтому вы можете сохранять (кэшировать) его значения для каждой точки перед сортировкой и использовать компаратор для подготовленных значений.
Наивный подход к этим вещам: использовать подкласс Point в главном алгоритме, чтобы у каждой точки уже были необходимые методы и место для кэшированных значений.