22template <
class ANumber,
class BNumber>
23using Exact1DNumber = std::conditional_t<
24 std::is_floating_point_v<ANumber> || std::is_floating_point_v<BNumber>,
25 double, Rational<BigInt>>;
36struct is_area_cut_target : std::false_type {};
38template <
class Po
intType,
class Label>
39struct is_area_cut_target<
Rectangle<PointType, Label>> : std::true_type {};
41template <
class Po
intType,
class Label>
42struct is_area_cut_target<
Triangle<PointType, Label>> : std::true_type {};
45inline constexpr bool is_area_cut_target_v = is_area_cut_target<std::remove_cvref_t<T>>::value;
53template <
class Polygon,
class OtherSegment>
54constexpr bool polygonBoundaryContainsSegment(
const Polygon& polygon,
const OtherSegment& other) {
55 const auto boundary = polygon.edges();
56 for (
const auto&
edge : boundary) {
57 if (
edge.contains(other)) {
70template <
class RectangleType,
class FirstPo
int,
class SecondPo
int>
71constexpr bool lineIntersectsRectangle(
const RectangleType& rectangle,
const FirstPoint& first,
const SecondPoint& second) {
74 using Coordinate = sign_coordinate_t<
typename FirstPoint::NumberType,
75 typename SecondPoint::NumberType,
76 typename RectangleType::NumberType>;
77 const auto a = filtered<Coordinate>(first);
78 const auto b = filtered<Coordinate>(second);
79 bool has_positive =
false;
80 bool has_negative =
false;
81 const auto vertices = rectangle.vertices();
82 for (
const auto&
vertex : vertices) {
83 const auto side = orientationSignOf(a, b, filtered<Coordinate>(
vertex)).value();
84 if (side == std::partial_ordering::equivalent) {
87 has_positive = has_positive || side == std::partial_ordering::greater;
88 has_negative = has_negative || side == std::partial_ordering::less;
90 return has_positive && has_negative;
109template <
class RectangleType,
class FirstPo
int,
class SecondPo
int>
110constexpr bool segmentIntersectsRectangle(
const RectangleType& rectangle,
const FirstPoint& first,
const SecondPoint& second) {
111 const auto& low = rectangle.min();
112 const auto& high = rectangle.max();
114 const bool rising_x = first.x() < second.x();
115 if ((rising_x ? first.x() : second.x()) > high.x() ||
116 (rising_x ? second.x() : first.x()) < low.x()) {
119 const bool rising_y = first.y() < second.y();
120 if ((rising_y ? first.y() : second.y()) > high.y() ||
121 (rising_y ? second.y() : first.y()) < low.y()) {
124 return lineIntersectsRectangle(rectangle, first, second);
133template <
class RectangleType,
class FirstPo
int,
class SecondPo
int>
134constexpr bool lineIntersectsRectangleInterior(
const RectangleType& rectangle,
const FirstPoint& first,
const SecondPoint& second) {
135 bool has_positive =
false;
136 bool has_negative =
false;
137 const auto vertices = rectangle.vertices();
138 for (
const auto&
vertex : vertices) {
140 has_positive = has_positive || side == std::partial_ordering::greater;
141 has_negative = has_negative || side == std::partial_ordering::less;
143 return has_positive && has_negative;
155template <
class RectangleType,
class FirstPo
int,
class SecondPo
int>
156constexpr bool segmentIntersectsRectangleInteriorExact(
const RectangleType& rectangle,
const FirstPoint& first,
const SecondPoint& second) {
157 using Coordinate = promoted_number_t<std::common_type_t<
158 std::remove_cvref_t<
decltype(rectangle.min().
x())>,
159 std::remove_cvref_t<
decltype(first.x())>,
160 std::remove_cvref_t<
decltype(second.x())>>>;
164 const TestSegment segment{SegmentPoint(first), SegmentPoint(second)};
165 if (segment.isDegenerate()) {
169 if (rectangle.interiorContains(first) || rectangle.interiorContains(second)) {
173 if (!lineIntersectsRectangleInterior(rectangle, first, second)) {
177 const auto edges = rectangle.edges();
178 std::array<bool, 4> edge_hits{};
179 int distinct_boundary_contacts = 0;
180 for (std::size_t i = 0; i < edges.size(); ++i) {
181 edge_hits[i] = segment.intersects(edges[i]);
182 distinct_boundary_contacts += edge_hits[i] ? 1 : 0;
185 if (distinct_boundary_contacts < 2) {
189 const auto vertices = rectangle.vertices();
190 if (segment.contains(vertices[0]) && edge_hits[0] && edge_hits[3]) {
191 --distinct_boundary_contacts;
193 if (segment.contains(vertices[1]) && edge_hits[0] && edge_hits[1]) {
194 --distinct_boundary_contacts;
196 if (segment.contains(vertices[2]) && edge_hits[1] && edge_hits[2]) {
197 --distinct_boundary_contacts;
199 if (segment.contains(vertices[3]) && edge_hits[2] && edge_hits[3]) {
200 --distinct_boundary_contacts;
203 return distinct_boundary_contacts >= 2;
219template <
class Remover, MonotoneChainConcept Chain>
220constexpr bool separatesChain(
const Remover& remover,
const Chain& chain) {
221 const std::size_t n = chain.size();
227 bool touched =
false;
228 for (std::size_t i = 0; i + 1 < n; ++i) {
230 if (
edge.intersects(remover)) {
231 const bool connected = active && remover.contains(chain[i]);
233 if (active && !touched) {
239 if (i == 0 && remover.contains(chain[0])) {
242 if (i + 2 == n && remover.contains(chain[n - 1])) {
246 if (active && !touched) {
253 return active && !touched;
271template <
class Number>
272using region_exact_number_t =
273 std::conditional_t<std::is_floating_point_v<Number>, double, Rational<BigInt>>;
282template <
class Region, HalfplaneConcept OtherHalfplane>
283constexpr bool regionInsideHalfplane(
const Region& region,
const OtherHalfplane& halfplane) {
284 std::remove_cvref_t<Region> copy(region);
285 return !copy.insert(halfplane);
292template <
class Region, HalfplaneConcept OtherHalfplane>
293constexpr bool regionInsideHalfplaneInterior(
const Region& region,
const OtherHalfplane& halfplane) {
294 return regionInsideHalfplane(region, halfplane) && !region.intersects(halfplane.asLine());
303template <
class Region, Po
intConcept FirstPo
int, Po
intConcept SecondPo
int>
304constexpr bool regionStrictlyOnBothSides(
const Region& region,
const FirstPoint& first,
const SecondPoint& second) {
306 return !regionInsideHalfplane(region, left) && !regionInsideHalfplane(region, left.opposite());
315template <
class Region>
316constexpr auto degenerateRegionCarrier(
const Region& region) {
317 using E = region_exact_number_t<typename Region::NumberType>;
319 using Carrier = std::variant<EPoint, Segment<EPoint>, Ray<EPoint>, Line<EPoint>>;
320 if (region.isBounded()) {
323 const auto verts = region.template vertices<E>();
326 for (
const auto& v : verts) {
337 return Carrier(Segment<EPoint>(lo, hi));
341 for (std::size_t i = 0; i < region.size(); ++i) {
342 const auto e = region.template
edge<E>(i);
343 if (
const auto* ray = std::get_if<Ray<EPoint>>(&e)) {
344 return Carrier(*ray);
346 if (
const auto* line = std::get_if<Line<EPoint>>(&e)) {
347 return Carrier(*line);
351 return Carrier(
EPoint(region[0].source()));
363template <
class Region, RectangleConcept BoundingRectangle>
364constexpr std::remove_cvref_t<Region> regionClippedToBox(
const Region& region,
const BoundingRectangle& bounds) {
365 using Result = std::remove_cvref_t<Region>;
366 using RegionPoint =
typename Result::PointType;
367 using N =
typename Result::NumberType;
368 using RegionHalfplane =
typename Result::HalfplaneType;
381 const auto roundOutward = [](
const auto& value,
bool up) -> N {
385 const auto reduced = value.simplified();
386 const auto numerator = reduced.numerator();
387 const auto denominator = reduced.denominator();
388 auto quotient = numerator / denominator;
389 const bool exact = quotient * denominator == numerator;
390 if (!exact && (numerator < 0) == !up) {
391 quotient = up ? quotient + 1 : quotient - 1;
398 const RegionPoint lo(roundOutward(bounds.min().x(),
false) - margin,
399 roundOutward(bounds.min().y(),
false) - margin);
400 const RegionPoint hi(roundOutward(bounds.max().x(),
true) + margin,
401 roundOutward(bounds.max().y(),
true) + margin);
402 const RegionPoint lohi(lo.x(), hi.y());
403 const RegionPoint hilo(hi.x(), lo.y());
404 Result result(region);
405 result.insert(RegionHalfplane(lo, hilo));
406 result.insert(RegionHalfplane(hilo, hi));
407 result.insert(RegionHalfplane(hi, lohi));
408 result.insert(RegionHalfplane(lohi, lo));
423template <
class HoledRegion,
class EdgePredicate>
424constexpr bool everyHoledRegionEdge(
const HoledRegion& region, EdgePredicate&& predicate) {
425 for (
const auto&
edge : region.outer().edgesView()) {
426 if (!predicate(
edge)) {
430 for (
const auto& hole : region.holes()) {
431 for (
const auto&
edge : hole.edgesView()) {
432 if (!predicate(
edge)) {
Projective duality and polar-transform helpers.
Definition arrangement.hpp:67
@ x
Definition intervaltree.hpp:24
Rectangle() -> Rectangle< Point<>, NoLabel >
Definition rectangle.hpp:2384
constexpr bool is_Rational_v
Definition rational.hpp:37
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37
Point< ERational > EPoint
Definition pgl.hpp:98
constexpr std::partial_ordering orientationSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Classifies the orientation of three points.
Definition orientation.hpp:544
Segment() -> Segment< Point<>, NoLabel >
Halfplane() -> Halfplane< Point<>, NoLabel >
Polygon() -> Polygon< Point<>, NoLabel >
Definition polygon.hpp:3200
Triangle() -> Triangle< Point<>, NoLabel >
Definition triangle.hpp:2029