135 lines
3.6 KiB
C++
135 lines
3.6 KiB
C++
#include <psemek/ui/impl/size_polygon_utils.hpp>
|
|
#include <psemek/geom/math.hpp>
|
|
#include <psemek/util/not_implemented.hpp>
|
|
#include <psemek/util/cyclic_iterator.hpp>
|
|
|
|
namespace psemek::ui::impl
|
|
{
|
|
|
|
size_polygon shift(size_polygon polygon, geom::vector<float, 2> const & delta)
|
|
{
|
|
for (auto & p : polygon)
|
|
p += delta;
|
|
return polygon;
|
|
}
|
|
|
|
size_polygon min(size_polygon const & polygon, int dimension)
|
|
{
|
|
if (polygon.empty())
|
|
return {};
|
|
|
|
size_polygon result;
|
|
|
|
auto cit = util::make_cyclic_iterator(polygon);
|
|
std::size_t iterations = 0;
|
|
|
|
for (auto next = std::next(cit); (*next)[dimension] <= (*cit)[dimension] && iterations < polygon.size(); cit = next++, ++iterations);
|
|
|
|
if (iterations == polygon.size())
|
|
return polygon;
|
|
|
|
for (auto prev = std::prev(cit); (*prev)[dimension] <= (*cit)[dimension]; cit = prev--);
|
|
|
|
for (auto cjt = cit; (*cjt)[dimension] == (*cit)[dimension]; ++cjt)
|
|
result.push_back(*cjt);
|
|
|
|
return result;
|
|
}
|
|
|
|
size_polygon intersect(size_polygon const & polygon1, size_polygon const & polygon2)
|
|
{
|
|
// TODO: https://www.cs.jhu.edu/~misha/Spring16/ORourke82.pdf
|
|
(void)polygon1;
|
|
(void)polygon2;
|
|
util::not_implemented();
|
|
}
|
|
|
|
geom::interval<float> range(size_polygon const & polygon, int dimension)
|
|
{
|
|
geom::interval<float> result;
|
|
for (auto const & p : polygon)
|
|
result |= p[dimension];
|
|
return result;
|
|
}
|
|
|
|
size_polygon cut(size_polygon const & polygon, int dimension, geom::interval<float> const & range)
|
|
{
|
|
size_polygon result;
|
|
std::size_t iterations = 0;
|
|
for (auto it = util::make_cyclic_iterator(polygon), next_it = std::next(it); iterations != polygon.size(); (it = next_it++), ++iterations)
|
|
{
|
|
auto const & curr = *it;
|
|
auto const & next = *next_it;
|
|
|
|
auto intersection = [&](float value)
|
|
{
|
|
// curr + (next - curr) * t = value
|
|
float t = (value - curr[dimension]) / (next[dimension] - curr[dimension]);
|
|
geom::point<float, 2> p;
|
|
p[dimension] = value;
|
|
p[dimension ^ 1] = geom::lerp(curr[dimension ^ 1], next[dimension ^ 1], t);
|
|
return p;
|
|
};
|
|
|
|
auto classify = [&](float value)
|
|
{
|
|
if (value < range.min)
|
|
return -2;
|
|
else if (value == range.min)
|
|
return -1;
|
|
else if (value < range.max)
|
|
return 0;
|
|
else if (value == range.max)
|
|
return 1;
|
|
else // (value > range.max)
|
|
return 2;
|
|
};
|
|
|
|
int const curr_class = classify(curr[dimension]);
|
|
int const next_class = classify(next[dimension]);
|
|
|
|
if (curr_class >= -1 && curr_class <= 1)
|
|
result.push_back(curr);
|
|
|
|
bool const min = (curr_class == -2 && next_class >= 0) || (curr_class >= 0 && next_class == -2);
|
|
bool const max = (curr_class == 2 && next_class <= 0) || (curr_class <= 0 && next_class == 2);
|
|
|
|
|
|
if (range.min == range.max)
|
|
{
|
|
if (min) result.push_back(intersection(range.min));
|
|
}
|
|
else
|
|
{
|
|
if (min) result.push_back(intersection(range.min));
|
|
if (max) result.push_back(intersection(range.max));
|
|
|
|
if (min && max && curr_class == 2)
|
|
std::swap(result.back(), result[result.size() - 2]);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
size_polygon sum_along(size_polygon const & polygon1, size_polygon const & polygon2, int dimension)
|
|
{
|
|
if (polygon1.empty() || polygon2.empty())
|
|
return size_polygon{};
|
|
|
|
int const other_dimension = dimension ^ 1;
|
|
|
|
auto range1 = range(polygon1, other_dimension);
|
|
auto range2 = range(polygon2, other_dimension);
|
|
|
|
auto common_range = range1 & range2;
|
|
if (common_range.empty())
|
|
return size_polygon{};
|
|
|
|
auto cut1 = cut(polygon1, other_dimension, common_range);
|
|
auto cut2 = cut(polygon2, other_dimension, common_range);
|
|
|
|
util::not_implemented();
|
|
}
|
|
|
|
}
|