30namespace pgl::detail {
40inline constexpr std::size_t xySweepMinSegments = 128;
69template <SegmentConcept Segment,
class Visitor>
70bool visitXYSweepPairs(
const std::vector<Segment>& segments, Visitor visit) {
72 using NumberType =
typename PointType::NumberType;
75 const std::size_t count = segments.size();
79 if (count >
static_cast<std::size_t
>(std::numeric_limits<std::uint32_t>::max())) {
80 throw std::length_error(
"xy sweep exceeds its 32-bit segment capacity");
85 std::vector<IndexedSegment> indexed;
86 indexed.reserve(count);
87 for (std::size_t i = 0; i < count; ++i) {
88 indexed.emplace_back(segments[i].min(), segments[i].max(),
89 static_cast<std::uint32_t
>(i));
97 std::vector<Event> events;
98 events.reserve(2 * count);
99 for (
const IndexedSegment& segment : indexed) {
100 const auto box = segment.bbox();
101 events.push_back({box.min().x(),
false, segment.label()});
102 events.push_back({box.max().x(),
true, segment.label()});
107 std::sort(events.begin(), events.end(), [](
const Event& a,
const Event& b) {
114 return !a.closing && b.closing;
118 for (
const Event& event : events) {
119 const IndexedSegment& segment = indexed[
event.index];
121 active.
erase(segment);
128 return visit(
static_cast<std::size_t
>(event.index),
129 static_cast<std::size_t
>(other.label()));
159template<
class Rational = pgl::Rational<pgl::BigInt>,
class Container>
161 using Point = Container::value_type::PointType;
168 for (
const auto &s : segments) {
170 v.push_back(converted);
173 std::vector<std::array<Seg,2>> ret;
174 pgl::detail::visitXYSweepPairs(v, [&v,&ret](std::size_t i, std::size_t j) {
177 if (s1.crosses(s2)) {
180 ret.push_back({s1,s2});
202template<
class Rational = pgl::Rational<pgl::BigInt>,
class Container>
204 using Point = Container::value_type::PointType;
211 for (
const auto &s : segments) {
213 v.push_back(converted);
216 std::vector<std::array<Seg,2>> ret;
217 pgl::detail::visitXYSweepPairs(v, [&v,&ret](std::size_t i, std::size_t j) {
220 if (s1.intersects(s2)) {
223 ret.push_back({s1,s2});
244template <
class Po
intType_,
class LabelType>
245template <
class Rational>
247 using Number =
typename PointType::NumberType;
248 const std::ptrdiff_t n =
static_cast<std::ptrdiff_t
>(
size());
253 std::vector<pgl::Segment<PointType>>
edges;
254 edges.reserve(
static_cast<std::size_t
>(n));
255 for (std::ptrdiff_t i = 0; i < n; ++i) {
257 if (
edge.isDegenerate()) {
266 if constexpr (!std::is_floating_point_v<Number>) {
268 pgl::detail::BentleyOttmann<Rational, pgl::Segment<PointType>> bo;
269 return bo.testPolygon(
edges);
271 }
else if (
edges.size() > detail::xySweepMinSegments) {
272 const std::size_t last =
edges.size() - 1;
273 bool notSimple =
false;
274 detail::visitXYSweepPairs(
edges, [&
edges, last, ¬Simple](std::size_t a, std::size_t b) {
276 const bool adjacent = (a + 1 == b) || (b + 1 == a) ||
277 (a == 0 && b == last) || (b == 0 && a == last);
278 notSimple = adjacent ?
edges[a].interiorsIntersect(
edges[b])
285 for (std::ptrdiff_t i = 0; i < n; ++i) {
286 for (std::ptrdiff_t j = i + 1; j < n; ++j) {
287 const bool adjacent = (j == i + 1) || (i == 0 && j == n - 1);
312template <
class Po
intType_,
class TLabel>
313template <
class Rational>
315 using Number =
typename PointType::NumberType;
316 const std::ptrdiff_t n =
static_cast<std::ptrdiff_t
>(
size());
321 std::vector<pgl::Segment<PointType>>
edges;
322 edges.reserve(
static_cast<std::size_t
>(n - 1));
323 for (std::ptrdiff_t i = 0; i + 1 < n; ++i) {
325 if (
edge.isDegenerate()) {
334 if constexpr (!std::is_floating_point_v<Number>) {
335 if (
edges.size() > 8) {
336 pgl::detail::BentleyOttmann<Rational, pgl::Segment<PointType>> bo;
337 return bo.testPolyLine(
edges);
339 }
else if (
edges.size() > detail::xySweepMinSegments) {
340 bool notSimple =
false;
341 detail::visitXYSweepPairs(
edges, [&
edges, ¬Simple](std::size_t a, std::size_t b) {
344 const bool adjacent = (a + 1 == b) || (b + 1 == a);
345 notSimple = adjacent ?
edges[a].interiorsIntersect(
edges[b])
352 const std::ptrdiff_t m =
static_cast<std::ptrdiff_t
>(
edges.size());
353 for (std::ptrdiff_t i = 0; i < m; ++i) {
354 for (std::ptrdiff_t j = i + 1; j < m; ++j) {
357 const bool adjacent = (j == i + 1);
void insert(const ShapeType &shape)
Inserts shape and its selected closed bounding-box interval.
Definition intervaltree.hpp:690
bool visitProjectionsIntersecting(const Q &q, Fn fn) const
Visits projected-interval intersections, stopping early if fn returns true.
Definition intervaltree.hpp:790
bool erase(const ShapeType &shape)
Removes one stored shape equal to shape.
Definition intervaltree.hpp:721
Mutable one-dimensional interval tree over projected bounded shapes.
Definition arrangement.hpp:67
@ x
Definition intervaltree.hpp:24
auto xyIntersections(const Container &segments)
Finds all intersecting segment pairs with a bounding-box sweep.
Definition xysweep.hpp:203
auto xyCrossings(const Container &segments)
Finds all crossing segment pairs with a bounding-box sweep.
Definition xysweep.hpp:160
@ edge
Definition bitmatrix.hpp:37
IntervalTree(const Container &) -> IntervalTree< typename Container::value_type >
Segment() -> Segment< Point<>, NoLabel >
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr bool intersects(const OtherChain &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1596
bool isSimple() const
Tests whether the polygon is simple (its boundary does not touch or cross itself).
Definition xysweep.hpp:246
constexpr std::size_t size() const
Returns the number of vertices in the polygon.
Definition polygon.hpp:259
constexpr bool interiorsIntersect(const OtherChain &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:1833
constexpr std::vector< Segment< PointType > > edges() const
Returns the edges of the polygon.
Definition polygon.hpp:598
constexpr PointType get(std::ptrdiff_t index) const
Cyclic access: same as operator[] but index is taken modulo size(); negative indices wrap from the en...
Definition polygon.hpp:169
bool isSimple() const
Tests whether the polyline is simple (it does not touch or cross itself).
Definition xysweep.hpp:314
constexpr PointType get(std::ptrdiff_t index) const
Accesses a vertex by index modulo the vertex count.
Definition polyline.hpp:174
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:1848
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1620
constexpr std::vector< Segment< PointType > > edges() const
Returns the edges of the polyline.
Definition polyline.hpp:585
constexpr std::size_t size() const
Returns the number of vertices in the polyline.
Definition polyline.hpp:388
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
TPoint PointType
Definition segment.hpp:59