37constexpr int signValue(std::partial_ordering order) {
38 return order > 0 ? 1 : (order < 0 ? -1 : 0);
47template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
48template <
class OnVertex,
class OnBlocked>
49void Triangulation<TriangleType_, SegmentType_>::expandVisibility(
50 const PointType& origin, VisibilityCone start, std::vector<VisibilityCone>& scratch,
51 OnVertex onVertex, OnBlocked onBlocked)
const {
53 scratch.push_back(start);
54 while (!scratch.empty()) {
55 const VisibilityCone cone = scratch.back();
57 if (blocksVisibility(cone.tri, cone.side)) {
61 const TriIndex entered = triangles_[
static_cast<std::size_t
>(cone.tri)].nbr[cone.side];
62 const int back = findSide(entered, cone.tri);
63 const auto& v = triangles_[
static_cast<std::size_t
>(entered)].v;
67 const VertexIndex apex = v[back];
69 origin, vertices_[
static_cast<std::size_t
>(cone.right)],
70 vertices_[
static_cast<std::size_t
>(apex)]));
72 origin, vertices_[
static_cast<std::size_t
>(cone.left)],
73 vertices_[
static_cast<std::size_t
>(apex)]));
75 VertexIndex rightChildLeft = cone.left;
76 VertexIndex leftChildRight = cone.right;
77 bool crossRight =
true;
78 bool crossLeft =
true;
79 if (fromRight > 0 && fromLeft < 0) {
86 rightChildLeft = apex;
87 leftChildRight = apex;
88 }
else if (fromRight <= 0) {
100 scratch.push_back({entered,
static_cast<std::int8_t
>((back + 2) % 3),
101 leftChildRight, cone.left});
104 scratch.push_back({entered,
static_cast<std::int8_t
>((back + 1) % 3),
105 cone.right, rightChildLeft});
110template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
111std::vector<std::vector<typename Triangulation<TriangleType_, SegmentType_>::VertexIndex>>
112Triangulation<TriangleType_, SegmentType_>::clearVisibleAdjacency()
const {
113 std::vector<std::vector<VertexIndex>> adjacency(vertices_.size());
114 if (domainTriangleCount_ == 0) {
117 const VertexIndex vertexCount =
static_cast<VertexIndex
>(vertices_.size());
118 std::vector<VisibilityCone> scratch;
119 const auto ignore = [](
const VisibilityCone&) {};
121 for (VertexIndex source = GHOST + 1; source < vertexCount; ++source) {
122 const TriIndex seed = incidentTriangleOf(source);
123 if (seed == NO_TRI) {
126 const PointType& origin = vertices_[
static_cast<std::size_t
>(source)];
127 auto& visible = adjacency[
static_cast<std::size_t
>(source)];
128 const auto report = [&](VertexIndex w) { visible.push_back(w); };
134 visitVertexFan(seed, source, [&](TriIndex t) {
138 const auto& v = triangles_[
static_cast<std::size_t
>(t)].v;
139 const int i = v[0] == source ? 0 : (v[1] == source ? 1 : 2);
140 const VertexIndex clockwise = v[(i + 1) % 3];
144 if (!blocksVisibility(t, (i + 2) % 3)) {
145 visible.push_back(clockwise);
147 expandVisibility(origin,
148 {t,
static_cast<std::int8_t
>(i), clockwise, v[(i + 2) % 3]},
149 scratch, report, ignore);
155template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
156typename Triangulation<TriangleType_, SegmentType_>::TriIndex
157Triangulation<TriangleType_, SegmentType_>::inDomainTriangleAt(
const PointType& query,
158 TriIndex start)
const {
159 TriIndex real = start;
160 if (real == NO_TRI) {
166 const auto& v = triangles_[
static_cast<std::size_t
>(real)].v;
167 const int atGhost = v[0] == GHOST ? 0 : (v[1] == GHOST ? 1 : 2);
168 const PointType& a = vertices_[
static_cast<std::size_t
>(v[(atGhost + 1) % 3])];
169 const PointType& b = vertices_[
static_cast<std::size_t
>(v[(atGhost + 2) % 3])];
173 real = triangles_[
static_cast<std::size_t
>(real)].nbr[atGhost];
174 if (real == NO_TRI || isGhost(real)) {
178 if (inDomain(real)) {
184 const auto& v = triangles_[
static_cast<std::size_t
>(real)].v;
185 for (
int i = 0; i < 3; ++i) {
186 if (v[i] == GHOST || !(vertices_[
static_cast<std::size_t
>(v[i])] == query)) {
189 TriIndex answer = NO_TRI;
190 visitVertexFan(real, v[i], [&](TriIndex t) {
191 if (answer == NO_TRI && inDomain(t)) {
197 for (
int s = 0; s < 3; ++s) {
198 const VertexIndex a = v[(s + 1) % 3];
199 const VertexIndex b = v[(s + 2) % 3];
200 if (a == GHOST || b == GHOST) {
203 const PointType& pa = vertices_[
static_cast<std::size_t
>(a)];
204 const PointType& pb = vertices_[
static_cast<std::size_t
>(b)];
208 const TriIndex across = triangles_[
static_cast<std::size_t
>(real)].nbr[s];
209 if (inDomain(across)) {
216template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
217typename Triangulation<TriangleType_, SegmentType_>::VisibilitySeeds
218Triangulation<TriangleType_, SegmentType_>::visibilitySeeds(
const PointType& query)
const {
219 VisibilitySeeds seeds;
220 if (domainTriangleCount_ == 0) {
223 TriIndex found = locateIndex(query);
224 if (!inDomain(found)) {
225 found = inDomainTriangleAt(query, found);
227 if (found == NO_TRI) {
230 seeds.located =
true;
234 const auto& fv = triangles_[
static_cast<std::size_t
>(found)].v;
237 for (
int i = 0; i < 3; ++i) {
238 if (vertices_[
static_cast<std::size_t
>(fv[i])] == query) {
243 for (
int s = 0; s < 3; ++s) {
244 if (
orientationSign(vertices_[
static_cast<std::size_t
>(fv[(s + 1) % 3])],
245 vertices_[
static_cast<std::size_t
>(fv[(s + 2) % 3])],
254 const auto addCone = [&](TriIndex t,
int side) {
255 const auto& v = triangles_[
static_cast<std::size_t
>(t)].v;
256 seeds.cones.push_back({t,
static_cast<std::int8_t
>(side), v[(side + 1) % 3],
261 const VertexIndex self = fv[atVertex];
262 visitVertexFan(found, self, [&](TriIndex t) {
266 const auto& v = triangles_[
static_cast<std::size_t
>(t)].v;
267 const int i = v[0] == self ? 0 : (v[1] == self ? 1 : 2);
274 seeds.direct.emplace_back(v[(i + 1) % 3], blocksVisibility(t, (i + 2) % 3));
275 seeds.direct.emplace_back(v[(i + 2) % 3], blocksVisibility(t, (i + 1) % 3));
278 }
else if (onSide >= 0) {
282 const bool grazes = blocksVisibility(found, onSide);
283 seeds.direct.emplace_back(fv[(onSide + 1) % 3], grazes);
284 seeds.direct.emplace_back(fv[(onSide + 2) % 3], grazes);
285 const TriIndex across = triangles_[
static_cast<std::size_t
>(found)].nbr[onSide];
286 for (
const TriIndex t : {found, across}) {
290 const int s = t == found ? onSide :
static_cast<int>(findSide(t, found));
291 seeds.direct.emplace_back(triangles_[
static_cast<std::size_t
>(t)].v[s],
false);
292 addCone(t, (s + 1) % 3);
293 addCone(t, (s + 2) % 3);
296 for (
int i = 0; i < 3; ++i) {
297 seeds.direct.emplace_back(fv[i],
false);
299 for (
int s = 0; s < 3; ++s) {
307 const auto upperHalf = [&](VertexIndex w) {
308 const PointType& p = vertices_[
static_cast<std::size_t
>(w)];
309 return p.y() > query.y() || (p.y() == query.y() && p.x() > query.x()) ? 0 : 1;
311 std::sort(seeds.cones.begin(), seeds.cones.end(),
312 [&](
const VisibilityCone& a,
const VisibilityCone& b) {
313 const int half = upperHalf(a.right);
314 const int other = upperHalf(b.right);
318 return orientationSign(query, vertices_[
static_cast<std::size_t
>(a.right)],
319 vertices_[
static_cast<std::size_t
>(b.right)]) > 0;
326 const std::size_t count = seeds.cones.size();
327 std::size_t firstBreak = count;
328 for (std::size_t k = 0; k < count && firstBreak == count; ++k) {
329 if (seeds.cones[(k + count - 1) % count].left != seeds.cones[k].right) {
333 seeds.fullTurn = firstBreak == count;
334 if (seeds.fullTurn) {
335 seeds.arcs.push_back(0);
337 std::rotate(seeds.cones.begin(),
338 seeds.cones.begin() +
static_cast<std::ptrdiff_t
>(firstBreak),
340 for (std::size_t k = 0; k < count; ++k) {
341 if (k == 0 || seeds.cones[k - 1].left != seeds.cones[k].right) {
342 seeds.arcs.push_back(k);
347 std::sort(seeds.direct.begin(), seeds.direct.end());
348 seeds.direct.erase(std::unique(seeds.direct.begin(), seeds.direct.end(),
349 [](
const auto& a,
const auto& b) {
350 return a.first == b.first;
356template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
357std::vector<typename Triangulation<TriangleType_, SegmentType_>::VertexIndex>
358Triangulation<TriangleType_, SegmentType_>::visibleIds(
const PointType& query,
359 const VisibilitySeeds& seeds,
360 bool grazing)
const {
361 std::vector<VertexIndex> found;
362 if (!seeds.located) {
365 for (
const auto& [vertex, grazes] : seeds.direct) {
366 if (grazing || !grazes) {
367 found.push_back(vertex);
370 std::vector<VisibilityCone> scratch;
371 const auto report = [&](VertexIndex w) { found.push_back(w); };
372 const auto ignore = [](
const VisibilityCone&) {};
373 for (
const VisibilityCone& cone : seeds.cones) {
374 expandVisibility(query, cone, scratch, report, ignore);
376 std::sort(found.begin(), found.end());
377 found.erase(std::unique(found.begin(), found.end()), found.end());
381template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
382std::vector<typename Triangulation<TriangleType_, SegmentType_>::PointType>
385 const VisibilitySeeds seeds = visibilitySeeds(query);
386 std::vector<PointType> result;
387 for (
const VertexIndex v : visibleIds(query, seeds,
false)) {
388 result.push_back(vertices_[
static_cast<std::size_t
>(v)]);
394template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
395std::vector<typename Triangulation<TriangleType_, SegmentType_>::PointType>
397 const VisibilitySeeds seeds = visibilitySeeds(query);
398 std::vector<VertexIndex> reached = visibleIds(query, seeds,
true);
399 if (reached.empty()) {
406 const std::size_t direct = reached.size();
407 for (std::size_t k = 0; k < direct; ++k) {
408 VertexIndex current = reached[k];
409 if (!passesThrough(current)) {
412 VertexIndex next = nextVertexAlongRay(query, current);
413 while (next != GHOST) {
414 reached.push_back(next);
415 if (!passesThrough(next)) {
418 const VertexIndex previous = current;
420 next = nextVertexAlongRay(vertices_[
static_cast<std::size_t
>(previous)], current);
423 std::sort(reached.begin(), reached.end());
424 reached.erase(std::unique(reached.begin(), reached.end()), reached.end());
425 std::vector<PointType> result;
426 result.reserve(reached.size());
427 for (
const VertexIndex v : reached) {
428 result.push_back(vertices_[
static_cast<std::size_t
>(v)]);
434template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
435bool Triangulation<TriangleType_, SegmentType_>::passesThrough(VertexIndex m)
const {
436 const TriIndex seed = incidentTriangleOf(m);
437 if (seed == NO_TRI) {
442 VertexIndex clockwise = GHOST;
443 VertexIndex counter = GHOST;
446 visitVertexFan(seed, m, [&](TriIndex t) {
451 const auto& tri = triangles_[
static_cast<std::size_t
>(t)];
452 const int i = tri.v[0] == m ? 0 : (tri.v[1] == m ? 1 : 2);
453 if (!inDomain(tri.nbr[(i + 2) % 3])) {
454 clockwise = tri.v[(i + 1) % 3];
457 if (!inDomain(tri.nbr[(i + 1) % 3])) {
458 counter = tri.v[(i + 2) % 3];
468 if (extremes != 2 || clockwise == GHOST || counter == GHOST) {
474 return detail::signValue(
orientationSign(vertices_[
static_cast<std::size_t
>(m)],
475 vertices_[
static_cast<std::size_t
>(clockwise)],
476 vertices_[
static_cast<std::size_t
>(counter)])) <= 0;
479template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
480typename Triangulation<TriangleType_, SegmentType_>::VertexIndex
481Triangulation<TriangleType_, SegmentType_>::nextVertexAlongRay(
const PointType& tail,
482 VertexIndex current)
const {
483 const TriIndex seed = incidentTriangleOf(current);
484 if (seed == NO_TRI) {
487 const PointType& head = vertices_[
static_cast<std::size_t
>(current)];
493 const int forwardHalf =
494 (head.y() > tail.y() || (head.y() == tail.y() && head.x() > tail.x())) ? 0 : 1;
495 const auto sameRay = [&](VertexIndex w) {
496 const PointType& p = vertices_[
static_cast<std::size_t
>(w)];
497 const int half = (p.y() > head.y() || (p.y() == head.y() && p.x() > head.x())) ? 0 : 1;
498 return half == forwardHalf;
500 const auto side = [&](VertexIndex w) {
501 return detail::signValue(
507 VertexIndex onEdge = GHOST;
508 TriIndex entry = NO_TRI;
510 visitVertexFan(seed, current, [&](TriIndex t) {
511 if (onEdge != GHOST || entry != NO_TRI || !inDomain(t)) {
514 const auto& v = triangles_[
static_cast<std::size_t
>(t)].v;
515 const int i = v[0] == current ? 0 : (v[1] == current ? 1 : 2);
516 const VertexIndex clockwise = v[(i + 1) % 3];
517 const VertexIndex counter = v[(i + 2) % 3];
518 const int fromClockwise = side(clockwise);
519 const int fromCounter = side(counter);
520 if (fromClockwise == 0 && sameRay(clockwise)) {
522 }
else if (fromCounter == 0 && sameRay(counter)) {
524 }
else if (fromClockwise < 0 && fromCounter > 0) {
529 if (onEdge != GHOST) {
534 if (entry == NO_TRI || blocksVisibility(entry, entrySide)) {
542 TriIndex tri = triangles_[
static_cast<std::size_t
>(entry)].nbr[entrySide];
543 int back = findSide(tri, entry);
545 const auto& v = triangles_[
static_cast<std::size_t
>(tri)].v;
546 const VertexIndex apex = v[back];
547 const int fromApex = side(apex);
553 const int leaving = fromApex == side(v[(back + 1) % 3]) ? (back + 1) % 3 : (back + 2) % 3;
554 if (blocksVisibility(tri, leaving)) {
557 const TriIndex next = triangles_[
static_cast<std::size_t
>(tri)].nbr[leaving];
558 back = findSide(next, tri);
563template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
564std::vector<std::vector<typename Triangulation<TriangleType_, SegmentType_>::VertexIndex>>
565Triangulation<TriangleType_, SegmentType_>::visibleAdjacency()
const {
566 auto adjacency = clearVisibleAdjacency();
567 if (domainTriangleCount_ == 0) {
570 const VertexIndex vertexCount =
static_cast<VertexIndex
>(vertices_.size());
576 for (TriIndex t = 0; t < firstGhost_; ++t) {
580 for (
int side = 0; side < 3; ++side) {
581 if (!blocksVisibility(t, side)) {
584 const TriIndex across = triangles_[
static_cast<std::size_t
>(t)].nbr[side];
585 if (inDomain(across) && across < t) {
588 const VertexIndex a = triangles_[
static_cast<std::size_t
>(t)].v[(side + 1) % 3];
589 const VertexIndex b = triangles_[
static_cast<std::size_t
>(t)].v[(side + 2) % 3];
590 adjacency[
static_cast<std::size_t
>(a)].push_back(b);
591 adjacency[
static_cast<std::size_t
>(b)].push_back(a);
601 std::vector<std::uint8_t> crossable(vertices_.size(), 0);
602 bool anyCrossable =
false;
603 for (VertexIndex m = GHOST + 1; m < vertexCount; ++m) {
604 crossable[
static_cast<std::size_t
>(m)] = passesThrough(m) ? 1 : 0;
605 anyCrossable = anyCrossable || crossable[
static_cast<std::size_t
>(m)] != 0;
612 std::vector<std::pair<VertexIndex, VertexIndex>> chained;
613 for (VertexIndex source = GHOST + 1; source < vertexCount; ++source) {
614 const std::size_t direct = adjacency[
static_cast<std::size_t
>(source)].size();
615 for (std::size_t k = 0; k < direct; ++k) {
616 VertexIndex previous = source;
617 VertexIndex current = adjacency[
static_cast<std::size_t
>(source)][k];
618 while (crossable[
static_cast<std::size_t
>(current)] != 0) {
619 const VertexIndex next =
620 nextVertexAlongRay(vertices_[
static_cast<std::size_t
>(previous)], current);
624 chained.emplace_back(source, next);
630 for (
const auto& [a, b] : chained) {
631 adjacency[
static_cast<std::size_t
>(a)].push_back(b);
632 adjacency[
static_cast<std::size_t
>(b)].push_back(a);
637template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
638std::vector<std::vector<typename Triangulation<TriangleType_, SegmentType_>::VertexIndex>>
639Triangulation<TriangleType_, SegmentType_>::wallNeighbors()
const {
640 std::vector<std::vector<VertexIndex>> walls(vertices_.size());
641 for (TriIndex t = 0; t < firstGhost_; ++t) {
645 for (
int side = 0; side < 3; ++side) {
646 if (!blocksVisibility(t, side)) {
649 const TriIndex across = triangles_[
static_cast<std::size_t
>(t)].nbr[side];
650 if (inDomain(across) && across < t) {
653 const VertexIndex a = triangles_[
static_cast<std::size_t
>(t)].v[(side + 1) % 3];
654 const VertexIndex b = triangles_[
static_cast<std::size_t
>(t)].v[(side + 2) % 3];
655 walls[
static_cast<std::size_t
>(a)].push_back(b);
656 walls[
static_cast<std::size_t
>(b)].push_back(a);
662template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
663Graph<typename Triangulation<TriangleType_, SegmentType_>::PointType>
666 const VertexIndex vertexCount =
static_cast<VertexIndex
>(vertices_.size());
667 for (VertexIndex v = GHOST + 1; v < vertexCount; ++v) {
668 result.
addVertex(vertices_[
static_cast<std::size_t
>(v)]);
670 const auto adjacency = clearVisibleAdjacency();
671 for (VertexIndex u = GHOST + 1; u < vertexCount; ++u) {
672 for (
const VertexIndex w : adjacency[
static_cast<std::size_t
>(u)]) {
674 result.
addEdge(vertices_[
static_cast<std::size_t
>(u)],
675 vertices_[
static_cast<std::size_t
>(w)]);
682template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
686 const VertexIndex vertexCount =
static_cast<VertexIndex
>(vertices_.size());
687 for (VertexIndex v = GHOST + 1; v < vertexCount; ++v) {
688 result.
addVertex(vertices_[
static_cast<std::size_t
>(v)]);
690 const auto adjacency = visibleAdjacency();
691 for (VertexIndex u = GHOST + 1; u < vertexCount; ++u) {
692 for (
const VertexIndex w : adjacency[
static_cast<std::size_t
>(u)]) {
694 result.
addEdge(vertices_[
static_cast<std::size_t
>(u)],
695 vertices_[
static_cast<std::size_t
>(w)]);
702template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
706 const VertexIndex vertexCount =
static_cast<VertexIndex
>(vertices_.size());
707 for (VertexIndex v = GHOST + 1; v < vertexCount; ++v) {
708 result.
addVertex(vertices_[
static_cast<std::size_t
>(v)]);
710 const auto adjacency = visibleAdjacency();
711 const auto walls = wallNeighbors();
717 const auto tangent = [&](VertexIndex u, VertexIndex w) {
718 const auto& incident = walls[
static_cast<std::size_t
>(u)];
719 if (incident.empty()) {
723 for (
const VertexIndex
x : incident) {
724 const int order = detail::signValue(
726 vertices_[
static_cast<std::size_t
>(w)],
727 vertices_[
static_cast<std::size_t
>(
x)]));
729 if (seen != 0 && seen != order) {
738 for (VertexIndex u = GHOST + 1; u < vertexCount; ++u) {
739 for (
const VertexIndex w : adjacency[
static_cast<std::size_t
>(u)]) {
740 if (u < w && tangent(u, w) && tangent(w, u)) {
741 result.
addEdge(vertices_[
static_cast<std::size_t
>(u)],
742 vertices_[
static_cast<std::size_t
>(w)]);
749template <TriangleConcept TriangleType_, SegmentConcept SegmentType_>
750template <
class ResultNumber>
755 const VisibilitySeeds seeds = visibilitySeeds(query);
756 if (!seeds.located) {
759 const ResultNumber originX = detail::asNumber<ResultNumber>(query.x());
760 const ResultNumber originY = detail::asNumber<ResultNumber>(query.y());
768 const auto rayHit = [&](VertexIndex through, VertexIndex a, VertexIndex b) {
769 const PointType& target = vertices_[
static_cast<std::size_t
>(through)];
770 const PointType& head = vertices_[
static_cast<std::size_t
>(a)];
771 const PointType& tail = vertices_[
static_cast<std::size_t
>(b)];
772 const ResultNumber dx = detail::asNumber<ResultNumber>(target.x()) - originX;
773 const ResultNumber dy = detail::asNumber<ResultNumber>(target.y()) - originY;
774 const ResultNumber edgeX =
775 detail::asNumber<ResultNumber>(tail.x()) - detail::asNumber<ResultNumber>(head.x());
776 const ResultNumber edgeY =
777 detail::asNumber<ResultNumber>(tail.y()) - detail::asNumber<ResultNumber>(head.y());
778 const ResultNumber toEdgeX = detail::asNumber<ResultNumber>(head.x()) - originX;
779 const ResultNumber toEdgeY = detail::asNumber<ResultNumber>(head.y()) - originY;
780 const ResultNumber along = toEdgeX * edgeY - toEdgeY * edgeX;
781 const ResultNumber sweep = dx * edgeY - dy * edgeX;
782 const ResultNumber scale = along / sweep;
783 return ResultPoint(originX + scale * dx, originY + scale * dy);
786 std::vector<ResultPoint> ring;
787 const auto append = [&](
const ResultPoint& p) {
788 if (ring.empty() || !(ring.back() == p)) {
793 std::vector<VisibilityCone> scratch;
794 const auto ignore = [](VertexIndex) {};
795 const std::size_t count = seeds.cones.size();
796 for (std::size_t arc = 0; arc < seeds.arcs.size(); ++arc) {
797 const std::size_t begin = seeds.arcs[arc];
798 const std::size_t end = arc + 1 < seeds.arcs.size() ? seeds.arcs[arc + 1] : count;
802 if (!seeds.fullTurn) {
803 append(ResultPoint(originX, originY));
805 for (std::size_t k = begin; k < end; ++k) {
806 expandVisibility(query, seeds.cones[k], scratch, ignore,
807 [&](
const VisibilityCone& cone) {
811 const auto& v = triangles_[static_cast<std::size_t>(cone.tri)].v;
812 const VertexIndex a = v[(cone.side + 1) % 3];
813 const VertexIndex b = v[(cone.side + 2) % 3];
814 append(rayHit(cone.right, a, b));
815 append(rayHit(cone.left, a, b));
819 while (ring.size() > 1 && ring.front() == ring.back()) {
822 if (ring.size() < 3) {
829 std::rotate(ring.begin(), std::min_element(ring.begin(), ring.end()), ring.end());
837template <
class Po
intType,
class LabelType>
840 const std::size_t n = corners.size();
848 for (
const auto& corner : corners) {
851 for (std::size_t i = 0; i < n; ++i) {
852 for (std::size_t j = i + 1; j < n; ++j) {
853 result.
addEdge(corners[i], corners[j]);
861template <
class Po
intType,
class LabelType>
866 for (
const auto& corner : corners) {
874template <
class Po
intType,
class LabelType>
877 const std::size_t n = corners.size();
886template <
class Po
intType,
class LabelType>
895template <
class Po
intType,
class LabelType>
904template <
class Po
intType,
class LabelType>
905template <
class ResultNumber>
918template <
class Po
intType_,
class LabelType>
925template <
class Po
intType_,
class LabelType>
927 return holes().empty() ?
outer().clearVisibilityGraph()
931template <
class Po
intType_,
class LabelType>
933 return holes().empty() ?
outer().reducedVisibilityGraph()
937template <
class Po
intType_,
class LabelType>
940 return holes().empty() ?
outer().visibleVertices(query)
944template <
class Po
intType_,
class LabelType>
947 return holes().empty() ?
outer().clearlyVisibleVertices(query)
951template <
class Po
intType_,
class LabelType>
952template <
class ResultNumber>
956 return holes().empty()
Undirected simple graph stored as adjacency sets.
Definition graph.hpp:38
void addVertex(const Vertex &vertex)
Adds a vertex if it is not already present.
Definition graph.hpp:213
void addEdge(const Vertex &u, const Vertex &v)
Adds an undirected edge and its endpoints.
Definition graph.hpp:225
Simple undirected graph with hashable vertices.
Definition arrangement.hpp:67
@ x
Definition intervaltree.hpp:24
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
void sortAround(std::vector< Point< Number, Label > > &points, const Point< CenterNumber, CenterLabel > &p)
Sorts points counterclockwise around a center point.
Definition sortpoints.hpp:48
Two-dimensional point with optional label payload.
Definition point.hpp:129
std::vector< PointType > clearlyVisibleVertices(const PointType &query) const
The region's vertices clearly visible from query.
Definition visibilitygraph.hpp:945
Graph< PointType > reducedVisibilityGraph() const
Returns the reduced visibility graph of the region's vertices.
Definition visibilitygraph.hpp:932
Graph< PointType > visibilityGraph() const
Returns the visibility graph of the region's vertices.
Definition visibilitygraph.hpp:919
std::vector< PointType > visibleVertices(const PointType &query) const
The region's vertices visible from query.
Definition visibilitygraph.hpp:938
constexpr const PolygonType & outer() const
Returns the outer boundary.
Definition polygonwithholes.hpp:178
Graph< PointType > clearVisibilityGraph() const
Returns the clear visibility graph of the region's vertices.
Definition visibilitygraph.hpp:926
PointType_ PointType
Definition polygonwithholes.hpp:90
constexpr const std::vector< PolygonType > & holes() const
Returns the holes in canonical order.
Definition polygonwithholes.hpp:202
auto triangulation() const
Builds the constrained Delaunay triangulation of this region.
Definition triangulation.hpp:6930
Polygon< Point< ResultNumber > > regularizedVisiblePolygon(const PointType &query) const
The part of the region visible from query, regularized.
Definition visibilitygraph.hpp:954
Closed simple polygon stored by its vertices.
Definition polygon.hpp:59
Graph< PointType > visibilityGraph() const
Returns the visibility graph of the polygon vertices.
Definition visibilitygraph.hpp:838
Graph< PointType > clearVisibilityGraph() const
Returns the clear visibility graph of the polygon vertices.
Definition visibilitygraph.hpp:862
std::vector< PointType > clearlyVisibleVertices(const PointType &query) const
The polygon vertices clearly visible from query.
Definition visibilitygraph.hpp:896
constexpr bool isConvex() const
Tests whether the polygon is convex.
Definition polygon.hpp:423
auto triangulation() const
Builds the constrained Delaunay triangulation of this polygon.
Definition triangulation.hpp:6860
constexpr Polygon()=default
Creates a polygon with no vertex.
constexpr std::size_t size() const
Returns the number of vertices in the polygon.
Definition polygon.hpp:259
Polygon< Point< ResultNumber > > regularizedVisiblePolygon(const PointType &query) const
The part of the polygon visible from query, regularized.
Definition visibilitygraph.hpp:906
std::vector< PointType > visibleVertices(const PointType &query) const
The polygon vertices visible from query.
Definition visibilitygraph.hpp:887
PointType_ PointType
Definition polygon.hpp:60
constexpr std::vector< PointType > vertices() const
Returns the vertices of the polygon (translation applied).
Definition polygon.hpp:587
Graph< PointType > reducedVisibilityGraph() const
Returns the reduced visibility graph of the polygon vertices.
Definition visibilitygraph.hpp:875
constexpr bool isDegenerate() const
Checks if the polygon is degenerate (has zero area).
Definition polygon.hpp:319
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
Graph< PointType > reducedVisibilityGraph() const
Returns the reduced visibility graph of the mesh vertices.
Definition visibilitygraph.hpp:704
Graph< PointType > visibilityGraph() const
Returns the visibility graph of the mesh vertices.
Definition visibilitygraph.hpp:684
Polygon< Point< ResultNumber > > regularizedVisiblePolygon(const PointType &query) const
The region of the domain visible from query, regularized.
Definition visibilitygraph.hpp:752
std::vector< PointType > visibleVertices(const PointType &query) const
The mesh vertices visible from query.
Definition visibilitygraph.hpp:396
typename TriangleType::PointType PointType
Definition triangulation.hpp:176
std::vector< PointType > clearlyVisibleVertices(const PointType &query) const
The mesh vertices clearly visible from query.
Definition visibilitygraph.hpp:383
Graph< PointType > clearVisibilityGraph() const
Returns the clear visibility graph of the mesh vertices.
Definition visibilitygraph.hpp:664