|
|
@@ -0,0 +1,76 @@
|
|
|
+//
|
|
|
+// weiler_atherton.cxx
|
|
|
+// math
|
|
|
+//
|
|
|
+// Created by Sam Jaffe on 5/21/19.
|
|
|
+// Copyright © 2019 Sam Jaffe. All rights reserved.
|
|
|
+//
|
|
|
+
|
|
|
+#include <vector>
|
|
|
+
|
|
|
+#include "expect/expect.hpp"
|
|
|
+#include "game/math/common.hpp"
|
|
|
+#include "game/math/shape.hpp"
|
|
|
+
|
|
|
+namespace math {
|
|
|
+ // https://github.com/cabooom/weiler-atherton
|
|
|
+ using polygon = std::vector<dim2::point>;
|
|
|
+
|
|
|
+ struct weiler_atherton {
|
|
|
+ weiler_atherton(polygon const & s, polygon const & c);
|
|
|
+
|
|
|
+ static void inject_point(std::vector<dim2::point> & vec,
|
|
|
+ dim2::line const & on, dim2::point const & pt);
|
|
|
+ void test_intersection(dim2::line const & s, dim2::line const & c);
|
|
|
+
|
|
|
+ polygon const &subject, clipping;
|
|
|
+ std::vector<dim2::point> p_subject, p_clipping;
|
|
|
+ std::vector<dim2::point> enters, exits;
|
|
|
+ };
|
|
|
+
|
|
|
+ weiler_atherton::weiler_atherton(polygon const & s, polygon const & c)
|
|
|
+ : subject(s), clipping(c), p_subject(s), p_clipping(c) {}
|
|
|
+
|
|
|
+ void weiler_atherton::inject_point(std::vector<dim2::point> & vec,
|
|
|
+ dim2::line const & on,
|
|
|
+ dim2::point const & pt) {
|
|
|
+ auto start = std::find(vec.begin(), vec.end(), on.first);
|
|
|
+ auto end = std::find(vec.begin(), vec.end(), on.second);
|
|
|
+ auto lnsq = [](dim2::point const & a) { return (a).dot(a); };
|
|
|
+ float dist = lnsq(pt - *start);
|
|
|
+ auto cmp = [&](dim2::point const & a) { return lnsq(*start - a) >= dist; };
|
|
|
+ vec.insert(std::find_if(start, end, cmp), pt);
|
|
|
+ }
|
|
|
+
|
|
|
+ void weiler_atherton::test_intersection(dim2::line const & s,
|
|
|
+ dim2::line const & c) {
|
|
|
+ expects_graceful(intersects(s, c), void());
|
|
|
+ auto point = lines::intersection(s, c);
|
|
|
+ if (orient(s, point) == anticlockwise) {
|
|
|
+ enters.emplace_back(point);
|
|
|
+ } else {
|
|
|
+ exits.emplace_back(point);
|
|
|
+ }
|
|
|
+ inject_point(p_subject, s, point);
|
|
|
+ inject_point(p_clipping, c, point);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<polygon> intersection(polygon const & lhs, polygon const & rhs) {
|
|
|
+ std::vector<polygon> rval;
|
|
|
+ expects_graceful(lhs.size() >= 3 && rhs.size() >= 3, rval);
|
|
|
+ // TODO: Assert that lhs and rhs are clockwise polygons with orient
|
|
|
+
|
|
|
+ weiler_atherton wa(lhs, rhs);
|
|
|
+
|
|
|
+ for (std::size_t i = 0; i < lhs.size(); ++i) {
|
|
|
+ std::size_t i2 = (i + 1) % lhs.size();
|
|
|
+ dim2::line left{lhs[i], lhs[i2]};
|
|
|
+ for (std::size_t j = 0; j < rhs.size(); ++j) {
|
|
|
+ std::size_t j2 = (j + 1) % rhs.size();
|
|
|
+ wa.test_intersection(left, {rhs[j], rhs[j2]});
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return rval;
|
|
|
+ }
|
|
|
+}
|