#include #include #include #include namespace psemek::ui::impl { size_polygon shift(size_polygon polygon, geom::vector 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 range(size_polygon const & polygon, int dimension) { geom::interval result; for (auto const & p : polygon) result |= p[dimension]; return result; } size_polygon cut(size_polygon const & polygon, int dimension, geom::interval 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 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(); } }