summaryrefslogtreecommitdiffhomepage
path: root/src/hole-cut.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/hole-cut.cpp')
-rw-r--r--src/hole-cut.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/hole-cut.cpp b/src/hole-cut.cpp
new file mode 100644
index 00000000..f87a6c2f
--- /dev/null
+++ b/src/hole-cut.cpp
@@ -0,0 +1,189 @@
+#include "hole.hpp"
+#include "compat/array-size.hpp"
+#include "compat/iota.hpp"
+#include "compat/map.hpp"
+//#include <mg/Functions.h>
+
+#ifdef __GNUG__
+#pragma GCC diagnostic ignored "-Wswitch-default"
+//#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+namespace floormat {
+namespace {
+
+using bbox = cut_rectangle_result::bbox;
+using rect = cut_rectangle_result::rect;
+
+enum shift : uint8_t { __ = 0, x0 = 1 << 0, x1 = 1 << 1, y0 = 1 << 2, y1 = 1 << 3, };
+enum class location : uint8_t { R0, R1, H0, H1, };
+
+struct coords
+{
+ location x0 : 2;
+ location x1 : 2;
+ location y0 : 2;
+ location y1 : 2;
+};
+
+struct element
+{
+ uint8_t size;
+ std::array<coords, 8> array;
+};
+
+constexpr element make_element(uint8_t s)
+{
+ // ReSharper disable CppIdenticalOperandsInBinaryExpression
+ // NOLINTBEGIN(*-simplify)
+ switch (s)
+ {
+ using enum location;
+ case x0|x1|y0|y1: return element{1, {{ // 9.1
+ {R0, R1, R0, R1},
+ }}};
+ case __|__|__|__: return element{8, {{ // 14.1
+ {R0, H0, R0, H0},
+ {H0, H1, R0, H0},
+ {H1, R1, R0, H0},
+ {R0, H0, H0, H1},
+ {H1, R1, H0, H1},
+ {R0, H0, H1, R1},
+ {H0, H1, H0, R1},
+ {H1, R1, H1, R1},
+ }}};
+
+ case x0|x1|__|__: return element{2, {{ // 13.1
+ {R0, R1, R0, H0},
+ {R0, R1, H1, R1},
+ }}};
+ case __|__|y0|y1: return element{2, {{ // 13.2
+ {R0, H0, H1, R1},
+ {H1, R1, R0, R1},
+ }}};
+
+ case x0|x1|y0|__: return element{1, {{ // 12.1
+ {R0, R1, H1, R1},
+ }}};
+ case x0|x1|__|y1: return element{1, {{ // 12.2
+ {R0, R1, R0, H0},
+ }}};
+ case x0|__|y0|y1: return element{1, {{ // 12.3
+ {H1, R1, R0, R1},
+ }}};
+ case __|x1|y0|y1: return element{1, {{ // 12.4
+ {R0, H0, R0, R1},
+ }}};
+
+ case x0|__|__|__: return element{3, {{ // 10.1
+ {R0, R1, R0, H0},
+ {H1, R1, H0, H1},
+ {R0, R1, H1, R1},
+ }}};
+ case __|x1|__|__: return element{3, {{ // 10.2
+ {R0, R1, R0, H0},
+ {R0, H0, H0, H1},
+ {R0, R1, H1, R1},
+ }}};
+ case __|__|y0|__: return element{3, {{ // 10.3
+ {R0, H0, R0, R1},
+ {H0, H1, H0, R1},
+ {H1, R1, R0, R1},
+ }}};
+ case __|__|__|y1: return element{3, {{ // 10.4
+ {R0, H0, R0, R1},
+ {H0, H1, R0, H0},
+ {H1, R1, R0, R1},
+ }}};
+
+ case x0|__|y0|__: return element{2, {{ // 11.1
+ {H1, R1, R0, H1},
+ {R0, R1, H1, R1},
+ }}};
+ case __|x1|y0|__: return element{2, {{ // 11.2
+ {R0, H0, R0, H1},
+ {R0, R1, H1, R1},
+ }}};
+ case x0|__|__|y1: return element{2, {{ // 11.3
+ {R0, R1, R0, H0},
+ {H1, R1, H0, R1},
+ }}};
+ case __|x1|__|y1: return element{2, {{ // 11.4
+ {R0, R1, R0, H0},
+ {R0, H0, H0, H1},
+ }}};
+ }
+ // NOLINTEND(*-simplify)
+ // ReSharper restore CppIdenticalOperandsInBinaryExpression
+ std::unreachable();
+}
+
+constexpr auto elements = map(make_element, iota_array<uint8_t, 16>);
+
+constexpr auto get_value_from_coord(Vector2i r0, Vector2i r1, Vector2i h0, Vector2i h1, coords c)
+{
+ const auto xs = std::array{ r0.x(), r1.x(), h0.x(), h1.x(), };
+ const auto ys = std::array{ r0.y(), r1.y(), h0.y(), h1.y(), };
+ const auto x0 = xs[(uint8_t)c.x0];
+ const auto x1 = xs[(uint8_t)c.x1];
+ const auto y0 = ys[(uint8_t)c.y0];
+ const auto y1 = ys[(uint8_t)c.y1];
+ return rect{ Vector2i{x0, y0}, Vector2i{x1, y1} };
+}
+
+[[nodiscard]]
+constexpr bool
+check_empty(Vector2i r0, Vector2i r1, Vector2i h0, Vector2i h1, Vector2ub input_bb, Vector2ub hole_bb)
+{
+ bool iempty = Vector2ui{input_bb}.product() == 0;
+ bool hempty = Vector2ui{hole_bb}.product() == 0;
+ bool empty_before_x = h1.x() <= r0.x();
+ bool empty_after_x = h0.x() >= r1.x();
+ bool empty_before_y = h1.y() <= r0.y();
+ bool empty_after_y = h0.y() >= r1.y();
+
+ return iempty | hempty | empty_before_x | empty_after_x | empty_before_y | empty_after_y;
+}
+
+constexpr cut_rectangle_result cut_rectangleʹ(bbox input, bbox hole)
+{
+ auto ihalf = Vector2i{input.bbox_size/2};
+ auto r0 = input.position - ihalf;
+ auto r1 = input.position + Vector2i{input.bbox_size} - ihalf;
+
+ auto hhalf = Vector2i{hole.bbox_size/2};
+ auto h0 = hole.position - hhalf;
+ auto h1 = hole.position + Vector2i{hole.bbox_size} - hhalf;
+
+ if (check_empty(r0, r1, h0, h1, input.bbox_size, hole.bbox_size))
+ return {0, {}};
+
+ const bool sx = h0.x() <= r0.x();
+ const bool ex = h1.x() >= r1.x();
+ const bool sy = h0.y() <= r0.y();
+ const bool ey = h1.y() >= r1.y();
+
+ auto val = uint8_t(sx << 0 | ex << 1 | sy << 2 | ey << 3);
+ CORRADE_ASSUME(val < 16);
+ const auto elt = elements[val];
+ cut_rectangle_result res = {
+ .size = elt.size,
+ .array = {},
+ };
+
+ const auto sz = elt.size;
+ CORRADE_ASSUME(sz <= 8);
+
+ for (auto i = 0u; i < sz; i++)
+ res.array[i] = get_value_from_coord(r0, r1, h0, h1, elt.array[i]);
+
+ return res;
+}
+
+} // namespace
+
+cut_rectangle_result cut_rectangle(bbox input, bbox hole)
+{
+ return cut_rectangleʹ(input, hole);
+}
+} // namespace floormat