Add geom::polygon_distance

This commit is contained in:
Nikita Lisitsa 2022-12-15 20:11:06 +03:00
parent d01a8186d8
commit 3f382651c4

View file

@ -6,6 +6,7 @@
#include <psemek/geom/simplex.hpp>
#include <psemek/geom/gauss.hpp>
#include <psemek/geom/contains.hpp>
#include <psemek/util/range.hpp>
namespace psemek::geom
{
@ -93,4 +94,71 @@ namespace psemek::geom
return std::min(distance(p, simplex{s[0], s[1]}), std::min(distance(p, simplex{s[1], s[2]}), distance(p, simplex{s[2], s[0]})));
}
template <typename T, typename Iterator>
std::pair<T, vector<T, 2>> signed_polygon_distance_direction(point<T, 2> const & p, Iterator begin, Iterator end)
{
std::pair<T, vector<T, 2>> result{limits<T>::max(), vector<T, 2>::zero()};
for (auto it = begin; it < end; ++it)
{
auto v = p - *it;
auto l = length(v);
if (make_min(result.first, l))
result.second = v / l;
}
for (auto it = begin, prev = std::prev(end); it != end; prev = it++)
{
auto v = p - *prev;
auto r = *it - *prev;
auto t = geom::dot(v, r) / geom::dot(r, r);
if (0 <= t && t <= 1)
{
v -= r * t;
auto l = length(v);
if (make_min(result.first, l))
result.second = v / l;
}
}
if (polygon_contains(begin, end, p))
{
result.first = -result.first;
result.second = -result.second;
}
return result;
}
template <typename T, typename Polygon>
std::pair<T, vector<T, 2>> signed_polygon_distance_direction(point<T, 2> const & p, Polygon const & polygon)
{
return signed_polygon_distance_direction(p, util::begin(polygon), util::end(polygon));
}
template <typename T, typename Iterator>
T signed_polygon_distance(point<T, 2> const & p, Iterator begin, Iterator end)
{
return signed_polygon_distance_direction(p, begin, end).first;
}
template <typename T, typename Polygon>
T signed_polygon_distance(point<T, 2> const & p, Polygon const & polygon)
{
return signed_polygon_distance(p, util::begin(polygon), util::end(polygon));
}
template <typename T, typename Iterator>
T polygon_distance(point<T, 2> const & p, Iterator begin, Iterator end)
{
return std::max(T{0}, signed_polygon_distance(p, begin, end));
}
template <typename T, typename Polygon>
T polygon_distance(point<T, 2> const & p, Polygon const & polygon)
{
return polygon_distance(p, util::begin(polygon), util::end(polygon));
}
}