Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPTess.h"
25 : #include "SPLog.h"
26 : #include "SPTessTypes.h"
27 : #include "SPTessSimd.hpp"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::geom {
30 :
31 : static constexpr VerboseFlag TessVerbose = VerboseFlag::None;
32 :
33 : struct Tesselator::Data : ObjectAllocator {
34 : // potential root face edges (connected to right non-convex angle)
35 : Vec2 _bmax, _bmin, _event;
36 :
37 : TessResult *_result = nullptr;
38 : EdgeDict* _edgeDict = nullptr;
39 : VertexPriorityQueue *_vertexQueue = nullptr;
40 :
41 : float _mathTolerance = std::numeric_limits<float>::epsilon() * 4.0f;
42 :
43 : Winding _winding = Winding::NonZero;
44 : float _antialiasValue = 0.0f;
45 : uint32_t _nvertexes = 0;
46 : uint8_t _markValue = 0;
47 :
48 : RelocateRule _relocateRule = RelocateRule::Auto;
49 :
50 : bool _dryRun = false;
51 : bool _valid = true;
52 :
53 : Vertex *_eventVertex = nullptr;
54 :
55 : memory::vector<Vertex *> _protectedVertexes;
56 : memory::vector<HalfEdge *> _protectedEdges;
57 :
58 : Data(memory::pool_t *p);
59 :
60 : void computeInterior();
61 :
62 : // Compute boundary face contour, also - split vertexes in subboundaries for antialiasing
63 : uint32_t computeBoundary();
64 :
65 : bool tessellateInterior();
66 : bool tessellateMonoRegion(HalfEdge *, uint8_t);
67 : void sweepVertex(VertexPriorityQueue &pq, EdgeDict &dict, Vertex *v);
68 : HalfEdge * processIntersect(Vertex *, const EdgeDictNode *, HalfEdge *, Vec2 &, IntersectionEvent ev);
69 : HalfEdge * processIntersect(Vertex *, const EdgeDictNode *, Vec2 &, IntersectionEvent ev);
70 :
71 : Edge *makeEdgeLoop(const Vec2 &origin);
72 :
73 : Vertex *makeVertex(HalfEdge *eOrig);
74 :
75 : HalfEdge *pushVertex(HalfEdge *e, const Vec2 &, bool clockwise = false, bool returnNew = false);
76 : HalfEdge *connectEdges(HalfEdge *eOrg, HalfEdge *eDst);
77 :
78 : Vertex *splitEdge(HalfEdge *, const Vec2 &);
79 : Vertex *splitEdge(HalfEdge *, HalfEdge *eOrg2, const Vec2 &);
80 :
81 : HalfEdge *getFirstEdge(Vertex *org) const;
82 : bool mergeVertexes(Vertex *org, Vertex *merge);
83 : HalfEdge * removeEdge(HalfEdge *);
84 :
85 : HalfEdge * removeDegenerateEdges(HalfEdge *, uint32_t *nedges, bool safeRemove);
86 : bool removeDegenerateEdges(FaceEdge *, size_t &removed);
87 :
88 : bool processEdgeOverlap(Vertex *v, HalfEdge *e1, HalfEdge *e2);
89 :
90 : bool isDegenerateTriangle(HalfEdge *);
91 :
92 : uint32_t followBoundary(FaceEdge *, HalfEdge *, uint8_t);
93 : void splitVertex(HalfEdge *first, HalfEdge *last);
94 : void displaceBoundary(FaceEdge *);
95 : };
96 :
97 257418 : Tesselator::~Tesselator() {
98 128709 : if (_data) {
99 128709 : auto pool = _data->_pool;
100 128709 : _data->~Data();
101 128468 : _data = nullptr;
102 128468 : memory::pool::destroy(pool);
103 : }
104 257162 : }
105 :
106 128520 : bool Tesselator::init(memory::pool_t *pool) {
107 128520 : auto p = memory::pool::create(pool);
108 128386 : memory::pool::context ctx(p);
109 :
110 128348 : _data = new (p) Data(p);
111 128325 : return true;
112 128329 : }
113 :
114 5693 : void Tesselator::setAntialiasValue(float value) {
115 5693 : _data->_antialiasValue = value;
116 5693 : }
117 :
118 0 : float Tesselator::getAntialiasValue() const {
119 0 : return _data->_antialiasValue;
120 : }
121 :
122 5665 : void Tesselator::setRelocateRule(RelocateRule rule) {
123 5665 : _data->_relocateRule = rule;
124 5665 : }
125 :
126 0 : Tesselator::RelocateRule Tesselator::getRelocateRule() const {
127 0 : return _data->_relocateRule;
128 : }
129 :
130 128596 : void Tesselator::setWindingRule(Winding winding) {
131 128596 : _data->_winding = winding;
132 128596 : }
133 :
134 0 : Winding Tesselator::getWindingRule() const {
135 0 : return _data->_winding;
136 : }
137 :
138 0 : void Tesselator::preallocate(uint32_t n) {
139 0 : _data->preallocateVertexes(n);
140 0 : _data->preallocateEdges(n);
141 0 : }
142 :
143 444898 : Tesselator::Cursor Tesselator::beginContour(bool clockwise) {
144 444898 : return Cursor{nullptr, nullptr, clockwise};
145 : }
146 :
147 2913501 : bool Tesselator::pushVertex(Cursor &cursor, const Vec2 &vertex) {
148 2913501 : if (!vertex.isValid()) {
149 : return false;
150 : }
151 :
152 2897376 : if (!cursor.closed) {
153 2839831 : if (cursor.count == 0) {
154 180128 : cursor.origin = vertex;
155 : }
156 :
157 : if constexpr (TessVerbose != VerboseFlag::None) {
158 : std::cout << std::setprecision(std::numeric_limits<float>::digits10 + 1)
159 : << "Push: " << vertex << "\n";
160 : }
161 :
162 2839831 : cursor.edge = _data->pushVertex(cursor.edge, vertex, cursor.isClockwise);
163 2800794 : ++ cursor.count;
164 2800794 : return true;
165 : }
166 :
167 : return false;
168 : }
169 :
170 3659750 : bool Tesselator::pushStrokeVertex(Cursor &cursor, const Vec2 &vertex, const Vec2 &offset) {
171 3659750 : if (!vertex.isValid() || !offset.isValid()) {
172 241350 : return false;
173 : }
174 :
175 3418400 : if (!cursor.closed) {
176 3347725 : if (cursor.count == 0) {
177 264950 : cursor.origin = vertex;
178 : }
179 :
180 : if constexpr (TessVerbose != VerboseFlag::None) {
181 : std::cout << std::setprecision(std::numeric_limits<float>::digits10 + 1)
182 : << "Push (stroke): " << vertex << ", " << offset << "\n";
183 : }
184 :
185 3347725 : if (!cursor.edge) {
186 264950 : cursor.root = cursor.edge = _data->pushVertex(cursor.edge, vertex + offset, cursor.isClockwise);
187 264950 : cursor.edge = _data->pushVertex(cursor.edge, vertex - offset, cursor.isClockwise);
188 : } else {
189 3082775 : _data->pushVertex(cursor.edge->getLeftLoopPrev(), vertex - offset, cursor.isClockwise);
190 3082775 : cursor.edge = _data->pushVertex(cursor.edge->getLeftLoopPrev(), vertex + offset, cursor.isClockwise, true);
191 : }
192 :
193 3347725 : ++ cursor.count;
194 3347725 : return true;
195 : }
196 : return false;
197 : }
198 :
199 5875 : bool Tesselator::pushStrokeTop(Cursor &cursor, const Vec2 &vertex) {
200 5875 : if (!vertex.isValid()) {
201 : return false;
202 : }
203 :
204 5875 : if (!cursor.closed) {
205 5875 : if (cursor.count == 0) {
206 0 : cursor.origin = vertex;
207 : }
208 :
209 : if constexpr (TessVerbose != VerboseFlag::None) {
210 : std::cout << std::setprecision(std::numeric_limits<float>::digits10 + 1)
211 : << "Push (stroke-top): " << vertex << "\n";
212 : }
213 :
214 5875 : if (!cursor.edge) {
215 0 : cursor.root = cursor.edge = _data->pushVertex(cursor.edge, vertex, cursor.isClockwise);
216 : } else {
217 5875 : cursor.edge = _data->pushVertex(cursor.edge->getLeftLoopPrev(), vertex, cursor.isClockwise, true);
218 : }
219 :
220 5875 : ++ cursor.count;
221 5875 : return true;
222 : }
223 : return false;
224 : }
225 :
226 7550 : bool Tesselator::pushStrokeBottom(Cursor &cursor, const Vec2 &vertex) {
227 7550 : if (!vertex.isValid()) {
228 : return false;
229 : }
230 :
231 7500 : if (!cursor.closed) {
232 7500 : if (cursor.count == 0) {
233 0 : cursor.origin = vertex;
234 : }
235 :
236 : if constexpr (TessVerbose != VerboseFlag::None) {
237 : std::cout << std::setprecision(std::numeric_limits<float>::digits10 + 1)
238 : << "Push (stroke-bottom): " << vertex << "\n";
239 : }
240 :
241 7500 : if (!cursor.edge) {
242 0 : cursor.root = cursor.edge = _data->pushVertex(cursor.edge, vertex, cursor.isClockwise);
243 : } else {
244 7500 : _data->pushVertex(cursor.edge->getLeftLoopPrev(), vertex, cursor.isClockwise);
245 : }
246 :
247 7500 : ++ cursor.count;
248 7500 : return true;
249 : }
250 : return false;
251 : }
252 :
253 237399 : bool Tesselator::closeContour(Cursor &cursor) {
254 237399 : if (cursor.closed) {
255 : return false;
256 : }
257 :
258 180068 : cursor.closed = true;
259 :
260 180068 : cursor.edge = _data->removeDegenerateEdges(cursor.edge, &cursor.count, true);
261 :
262 180576 : if (cursor.edge) {
263 : if constexpr (TessVerbose != VerboseFlag::None) {
264 : std::cout << "Contour:\n";
265 : cursor.edge->foreachOnFace([&] (HalfEdge &e) {
266 : std::cout << TessVerbose << "\t" << e << "\n";
267 : });
268 : }
269 179782 : _data->trimVertexes();
270 179215 : return true;
271 : } else {
272 : if constexpr (TessVerbose != VerboseFlag::None) {
273 : std::cout << "Fail to add empty contour\n";
274 : }
275 : }
276 794 : _data->trimVertexes();
277 796 : return false;
278 : }
279 :
280 259400 : bool Tesselator::closeStrokeContour(Cursor &cursor) {
281 259400 : if (cursor.closed) {
282 : return false;
283 : }
284 :
285 259400 : cursor.closed = true;
286 :
287 259400 : if (cursor.root) {
288 259400 : _data->_vertexes[cursor.root->vertex]->relocate(cursor.edge->origin);
289 259400 : _data->_vertexes[cursor.root->sym()->vertex]->relocate(cursor.edge->getLeftLoopPrev()->origin);
290 : }
291 :
292 259400 : cursor.edge = _data->removeDegenerateEdges(cursor.edge, &cursor.count, true);
293 :
294 259400 : if (cursor.edge) {
295 : if constexpr (TessVerbose != VerboseFlag::None) {
296 : std::cout << "Contour:\n";
297 : cursor.edge->foreachOnFace([&] (HalfEdge &e) {
298 : std::cout << TessVerbose << "\t" << e << "\n";
299 : });
300 : }
301 : return true;
302 : } else {
303 : if constexpr (TessVerbose != VerboseFlag::None) {
304 : std::cout << "Fail to add empty contour\n";
305 : }
306 : }
307 25 : _data->trimVertexes();
308 25 : return false;
309 : }
310 :
311 128612 : bool Tesselator::prepare(TessResult &res) {
312 128612 : _data->_result = &res;
313 128612 : _data->_vertexOffset = res.nvertexes;
314 :
315 128612 : if (_data->_relocateRule == RelocateRule::Monotonize && _data->_antialiasValue > 0.0f) {
316 225 : _data->_dryRun = true;
317 : }
318 :
319 128612 : _data->computeInterior();
320 :
321 128504 : if (_data->_antialiasValue > 0.0f) {
322 5675 : auto nBoundarySegments = _data->computeBoundary();
323 :
324 : if constexpr (TessVerbose != VerboseFlag::None) {
325 : for (auto &it : _data->_boundaries) {
326 : if (!it->_degenerate) {
327 : std::cout << "Boundary:\n";
328 : it->foreach([&] (const FaceEdge &edge) {
329 : std::cout << "\t" << edge << "\n";
330 : });
331 : }
332 : }
333 : }
334 :
335 5706 : if (_data->_relocateRule == RelocateRule::Monotonize) {
336 450 : for (auto &it : _data->_boundaries) {
337 225 : if (it->_degenerate) {
338 0 : continue;
339 : }
340 : auto e = it;
341 : do {
342 950 : _data->displaceBoundary(e);
343 950 : e = e->_next;
344 950 : } while (e != it);
345 : }
346 :
347 225 : _data->_dryRun = false;
348 :
349 1175 : for (auto &it : _data->_vertexes) {
350 950 : if (!it) {
351 0 : continue;
352 : }
353 :
354 : if constexpr (TessVerbose != VerboseFlag::None) {
355 : std::cout << "Vertex: " << *it << "\n";
356 : }
357 :
358 950 : auto e = it->_edge;
359 : do {
360 1900 : auto edge = e->getEdge();
361 1900 : SPASSERT(!edge->invalidated, "Tess: failed: edge was invalidated but still in use");
362 1900 : edge->direction = nan();
363 1900 : edge->node = nullptr;
364 1900 : e->origin = it->_origin;
365 1900 : e->_realWinding = 0;
366 1900 : e = e->_originNext;
367 1900 : } while (e != it->_edge);
368 : }
369 :
370 225 : _data->computeInterior();
371 : }
372 :
373 5706 : if (!_data->tessellateInterior()) {
374 0 : _data->_valid = false;
375 0 : _data->_result = nullptr;
376 0 : return false;
377 : }
378 :
379 5697 : res.nvertexes += _data->_exportVertexes.size() + nBoundarySegments;
380 5695 : res.nfaces += _data->_faceEdges.size() + nBoundarySegments * 2;
381 5691 : return true;
382 : } else {
383 122829 : if (!_data->tessellateInterior()) {
384 175 : _data->_valid = false;
385 175 : _data->_result = nullptr;
386 175 : return false;
387 : }
388 :
389 122737 : res.nvertexes += _data->_exportVertexes.size();
390 122703 : res.nfaces += _data->_faceEdges.size();
391 122681 : return true;
392 : }
393 : return false;
394 : }
395 :
396 128680 : bool Tesselator::write(TessResult &res) {
397 128680 : if (!_data->_valid) {
398 : return false;
399 : }
400 :
401 128505 : uint32_t triangle[3] = { 0 };
402 :
403 230886 : auto exportQuad = [&, this] (uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br) {
404 230886 : triangle[0] = _data->_vertexOffset + tl;
405 116012 : triangle[1] = _data->_vertexOffset + bl;
406 116012 : triangle[2] = _data->_vertexOffset + tr;
407 :
408 116012 : res.pushTriangle(res.target, triangle);
409 :
410 114874 : triangle[0] = _data->_vertexOffset + bl;
411 114874 : triangle[1] = _data->_vertexOffset + br;
412 114874 : triangle[2] = _data->_vertexOffset + tr;
413 :
414 114874 : res.pushTriangle(res.target, triangle);
415 243587 : };
416 :
417 128505 : if (_data->_antialiasValue > 0.0f) {
418 : uint32_t tl, tr, bl, br, origin;
419 :
420 5714 : uint32_t nexports = _data->_exportVertexes.size();
421 :
422 11434 : for (auto &it : _data->_boundaries) {
423 5707 : if (it->_degenerate) {
424 0 : continue;
425 : }
426 :
427 : origin = nexports;
428 : auto e = it;
429 :
430 5707 : if (_data->_relocateRule == RelocateRule::Monotonize) {
431 : // boundaries already relocated
432 225 : e = e->_next;
433 :
434 225 : res.pushVertex(res.target, nexports + _data->_vertexOffset, e->_displaced, e->_value);
435 225 : ++ nexports;
436 :
437 : do {
438 : // e and e->next should be ready
439 725 : tl = nexports - 1;
440 : tr = nexports;
441 725 : bl = e->_vertex->_exportIdx;
442 :
443 725 : e = e->_next;
444 :
445 725 : br = e->_vertex->_exportIdx;
446 :
447 725 : res.pushVertex(res.target, nexports + _data->_vertexOffset, e->_displaced, 0.0f);
448 :
449 725 : exportQuad(tl, tr, bl, br);
450 725 : ++ nexports;
451 725 : } while (e != it);
452 :
453 : // export first edge
454 : tl = tr;
455 : tr = origin;
456 : bl = br;
457 225 : br = e->_next->_vertex->_exportIdx;
458 225 : exportQuad(tl, tr, bl, br);
459 : } else {
460 5482 : _data->displaceBoundary(e);
461 :
462 5494 : e = e->_next;
463 :
464 5494 : res.pushVertex(res.target, nexports + _data->_vertexOffset, e->_displaced, e->_value);
465 5495 : ++ nexports;
466 :
467 : do {
468 108730 : _data->displaceBoundary(e);
469 :
470 : // e and e->next should be ready
471 109778 : tl = nexports - 1;
472 : tr = nexports;
473 109778 : bl = e->_vertex->_exportIdx;
474 :
475 109778 : e = e->_next;
476 :
477 109778 : br = e->_vertex->_exportIdx;
478 :
479 109778 : res.pushVertex(res.target, nexports + _data->_vertexOffset, e->_displaced, 0.0f);
480 :
481 109594 : exportQuad(tl, tr, bl, br);
482 108732 : ++ nexports;
483 108732 : } while (e != it);
484 :
485 : // export first edge
486 : tl = tr;
487 : tr = origin;
488 : bl = br;
489 5497 : br = e->_next->_vertex->_exportIdx;
490 5497 : exportQuad(tl, tr, bl, br);
491 : }
492 : }
493 : }
494 :
495 9091480 : for (auto &it : _data->_exportVertexes) {
496 8958560 : if (it) {
497 8958560 : res.pushVertex(res.target, it->_exportIdx + _data->_vertexOffset, it->_origin, 1.0f);
498 : }
499 : }
500 :
501 128539 : auto mark = ++ _data->_markValue;
502 8845270 : for (auto &it : _data->_faceEdges) {
503 8725504 : if (it->_mark != mark && isWindingInside(_data->_winding, it->_realWinding)) {
504 8727157 : uint32_t vertex = 0;
505 :
506 8727157 : it->foreachOnFace([&, this] (HalfEdge &edge) {
507 26035040 : if (vertex < 3) {
508 : #if DEBUG
509 26035897 : if (_data->_vertexes.size() >= edge.vertex) {
510 26034578 : const auto v = _data->_vertexes[edge.vertex];
511 25996865 : if (v) {
512 25996865 : const auto qidx = v->_exportIdx;
513 25996865 : triangle[vertex] = qidx + _data->_vertexOffset;
514 : } else {
515 0 : std::cout << "Invalid vertex: " << edge.vertex << "\n";
516 0 : ::abort();
517 : }
518 : } else {
519 0 : std::cout << "Invalid vertex index: " << edge.vertex << " of " << _data->_vertexes.size() << "\n";
520 0 : ::abort();
521 : }
522 : #else
523 : triangle[vertex] = _data->_vertexes[edge.vertex]->_exportIdx + _data->_vertexOffset;
524 : #endif
525 : }
526 25996008 : edge._mark = mark;
527 25996008 : ++ vertex;
528 25996008 : });
529 :
530 8707361 : if (vertex == 3) {
531 8707182 : res.pushTriangle(res.target, triangle);
532 : /*if (skipTriangles > 0) {
533 : -- skipTriangles;
534 : } else {
535 : if (ntriangles > 0) {
536 : res.pushTriangle(res.target, triangle);
537 : -- ntriangles;
538 : } else {
539 : break;
540 : }
541 : }*/
542 : }
543 : }
544 : }
545 :
546 128467 : return true;
547 : }
548 :
549 128406 : Tesselator::Data::Data(memory::pool_t *p)
550 128406 : : ObjectAllocator(p) { }
551 :
552 128839 : void Tesselator::Data::computeInterior() {
553 128839 : _exportVertexes.clear();
554 :
555 128766 : EdgeDict dict(_pool, 8);
556 128878 : VertexPriorityQueue pq(_pool, _vertexes);
557 :
558 128958 : _edgeDict = &dict;
559 128958 : _vertexQueue = &pq;
560 :
561 : Vertex *v, *vNext;
562 8977985 : while ((v = pq.extractMin()) != nullptr) {
563 : for (;;) {
564 9125324 : vNext = pq.getMin();
565 9139623 : if (vNext == NULL || !VertEq(vNext, v, _mathTolerance)) {
566 : break;
567 : }
568 :
569 263845 : vNext = pq.extractMin();
570 263842 : mergeVertexes(v, vNext);
571 : }
572 :
573 8878064 : dict.update(v, _mathTolerance);
574 :
575 8928295 : sweepVertex(pq, dict, v);
576 : }
577 :
578 128708 : _edgeDict = nullptr;
579 128708 : _vertexQueue = nullptr;
580 128708 : }
581 :
582 5676 : uint32_t Tesselator::Data::computeBoundary() {
583 5676 : _nvertexes = _vertexes.size(); // for new vertexes handling
584 : uint32_t nsegments = 0;
585 5671 : auto mark = ++ _markValue;
586 :
587 11391 : for (auto &it : _edgesOfInterests) {
588 5672 : if (!it) {
589 0 : continue;
590 : }
591 5672 : auto e = it->getEdge();
592 5694 : if (e->left._mark != mark) {
593 5693 : if (!isWindingInside(_winding, e->left._realWinding)) {
594 3920 : nsegments += followBoundary(nullptr, &e->left, mark);
595 : } else {
596 1773 : e->left._mark = mark;
597 : }
598 : }
599 5712 : if (e->right._mark != mark) {
600 5710 : if (!isWindingInside(_winding, e->right._realWinding)) {
601 1770 : nsegments += followBoundary(nullptr, &e->right, mark);
602 : } else {
603 3940 : e->right._mark = mark;
604 : }
605 : }
606 : }
607 :
608 11422 : for (auto &it : _boundaries) {
609 5701 : size_t removed = 0;
610 5701 : if (!removeDegenerateEdges(it, removed)) {
611 0 : it->_degenerate = true;
612 0 : nsegments -= removed;
613 : }
614 : }
615 :
616 5704 : return nsegments;
617 : }
618 :
619 128548 : bool Tesselator::Data::tessellateInterior() {
620 128548 : auto mark = ++ _markValue;
621 :
622 2286915 : for (auto &it : _edgesOfInterests) {
623 2157944 : if (!it) {
624 15 : continue;
625 : }
626 2157929 : auto e = it->getEdge();
627 2158741 : if (e->left._mark != mark) {
628 966330 : if (isWindingInside(_winding, e->left._realWinding)) {
629 : if constexpr (TessVerbose != VerboseFlag::None) {
630 : uint32_t vertex = 0;
631 : std::cout << "Inside Face: \n";
632 : e->left.foreachOnFace([&](HalfEdge &edge) {
633 : std::cout << "\t" << TessVerbose << vertex ++ << "; " << edge << "\n";
634 : });
635 : }
636 :
637 883967 : if (!tessellateMonoRegion(&e->left, mark)) {
638 175 : return false;
639 : }
640 : } else {
641 82363 : e->left._mark = mark;
642 : }
643 : }
644 2158366 : if (e->right._mark != mark) {
645 1480536 : if (isWindingInside(_winding, e->right._realWinding)) {
646 : if constexpr (TessVerbose != VerboseFlag::None) {
647 : uint32_t vertex = 0;
648 : std::cout << "Inside Face: \n";
649 : e->right.foreachOnFace([&](HalfEdge &edge) {
650 : std::cout << "\t" << TessVerbose << vertex ++ << "; " << edge << "\n";
651 : });
652 : }
653 :
654 344509 : if (!tessellateMonoRegion(&e->right, mark)) {
655 : return false;
656 : }
657 : } else {
658 1136027 : e->right._mark = mark;
659 : }
660 : }
661 : }
662 128421 : return true;
663 : }
664 :
665 1228314 : bool Tesselator::Data::tessellateMonoRegion(HalfEdge *edge, uint8_t v) {
666 1228314 : if (edge->_leftNext->_leftNext == edge) {
667 : return true;
668 : }
669 :
670 1228239 : edge = removeDegenerateEdges(edge, nullptr, false);
671 1228882 : if (!edge) {
672 : return true;
673 : }
674 :
675 : HalfEdge *up = edge, *lo;
676 :
677 : /* All edges are oriented CCW around the boundary of the region.
678 : * First, find the half-edge whose origin vertex is rightmost.
679 : * Since the sweep goes from left to right, face->anEdge should
680 : * be close to the edge we want.
681 : */
682 1932729 : for (; VertLeq(up->getDstVec(), up->getOrgVec()); up = up->getLeftLoopPrev())
683 : ;
684 6471180 : for (; VertLeq(up->getOrgVec(), up->getDstVec()); up = up->getLeftLoopNext())
685 : ;
686 1228609 : lo = up->getLeftLoopPrev();
687 :
688 : if constexpr (TessVerbose == VerboseFlag::Full) {
689 : std::cout << "Start: Up: " << *up << "\n";
690 : std::cout << "Start: Lo: " << *lo << "\n";
691 : }
692 :
693 1228864 : up->_mark = v;
694 1228864 : lo->_mark = v;
695 :
696 : const Vec2 * v0, *v1, *v2;
697 :
698 10051327 : while (up->getLeftLoopNext() != lo) {
699 8805087 : if (VertLeq(up->getDstVec(), lo->getOrgVec())) {
700 : if constexpr (TessVerbose == VerboseFlag::Full) {
701 : std::cout << "Lo: " << *lo << "\n";
702 : std::cout << "Up: " << *up << "\n";
703 : }
704 :
705 : /* up->Dst is on the left. It is safe to form triangles from lo->Org.
706 : * The EdgeGoesLeft test guarantees progress even when some triangles
707 : * are CW, given that the upper and lower chains are truly monotone.
708 : */
709 4355380 : v0 = &lo->getOrgVec();
710 4380378 : v1 = &lo->getDstVec();
711 4381653 : v2 = &lo->getLeftLoopNext()->getDstVec();
712 :
713 7907203 : while (lo->getLeftLoopNext() != up // invariant is not reached
714 7908789 : && (lo->getLeftLoopNext()->goesLeft()
715 1625623 : || Vec2::isCounterClockwise(*v0, *v1, *v2))) {
716 3535861 : auto tempHalfEdge = connectEdges(lo->getLeftLoopNext(), lo);
717 3536382 : if (tempHalfEdge == nullptr) {
718 100 : return false;
719 : }
720 :
721 3536282 : lo = tempHalfEdge->sym();
722 3536609 : v0 = &lo->getOrgVec();
723 3536599 : v1 = &lo->getDstVec();
724 3536501 : v2 = &lo->getLeftLoopNext()->getDstVec();
725 :
726 3536862 : if (!isDegenerateTriangle(tempHalfEdge)) {
727 3484275 : _faceEdges.emplace_back(tempHalfEdge);
728 : }
729 : }
730 4377290 : lo = lo->getLeftLoopPrev();
731 4377527 : lo->_mark = v;
732 : } else {
733 : if constexpr (TessVerbose == VerboseFlag::Full) {
734 : std::cout << "Up: " << *up << "\n";
735 : std::cout << "Lo: " << *lo << "\n";
736 : }
737 :
738 4452466 : v0 = &up->getDstVec();
739 4449410 : v1 = &up->getOrgVec();
740 4449793 : v2 = &up->getLeftLoopPrev()->getOrgVec();
741 :
742 : /* lo->Org is on the left. We can make CCW triangles from up->Dst. */
743 8106062 : while (lo->getLeftLoopNext() != up
744 8108155 : && (up->getLeftLoopPrev()->goesRight()
745 1709514 : || !Vec2::isCounterClockwise(*v0, *v1, *v2))) {
746 3668156 : auto tempHalfEdge = connectEdges(up, up->getLeftLoopPrev());
747 3669097 : if (tempHalfEdge == nullptr) {
748 75 : return false;
749 : }
750 :
751 3669022 : up = tempHalfEdge->sym();
752 3669290 : v0 = &up->getDstVec();
753 3669168 : v1 = &up->getOrgVec();
754 3669163 : v2 = &up->getLeftLoopPrev()->getOrgVec();
755 :
756 3669379 : if (!isDegenerateTriangle(tempHalfEdge)) {
757 3664166 : _faceEdges.emplace_back(tempHalfEdge);
758 : }
759 : }
760 4443920 : up = up->getLeftLoopNext();
761 4444936 : up->_mark = v;
762 : }
763 : }
764 :
765 : /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
766 : * can be tessellated in a fan from this leftmost vertex.
767 : */
768 1636251 : while (lo->getLeftLoopNext()->getLeftLoopNext() != up) {
769 408233 : auto tempHalfEdge = connectEdges(lo->getLeftLoopNext(), lo);
770 408245 : if (tempHalfEdge == nullptr) {
771 0 : return false;
772 : }
773 408245 : if (!isDegenerateTriangle(tempHalfEdge)) {
774 408239 : _faceEdges.emplace_back(tempHalfEdge);
775 : }
776 408197 : lo = tempHalfEdge->sym();
777 408200 : lo->_mark = v;
778 : }
779 :
780 1228180 : if (!isDegenerateTriangle(lo)) {
781 1228329 : _faceEdges.emplace_back(lo);
782 : }
783 : return true;
784 : }
785 :
786 8925853 : void Tesselator::Data::sweepVertex(VertexPriorityQueue &pq, EdgeDict &dict, Vertex *v) {
787 1679380 : auto doConnectEdges = [&, this] (HalfEdge *source, HalfEdge *target) {
788 : if constexpr (TessVerbose != VerboseFlag::None) {
789 : std::cout << "\t\tConnect: \n\t\t\t" << *source << "\n\t\t\t" << *target << "\n";
790 : }
791 839576 : auto eNew = connectEdges(source->getLeftLoopPrev(), target);
792 839804 : _edgesOfInterests.emplace_back(eNew);
793 839124 : return eNew;
794 8925853 : };
795 :
796 9588757 : auto onVertex = [&, this] (VertexType type, Edge *fullEdge, HalfEdge *e, HalfEdge *eNext) {
797 9588757 : if (_dryRun) {
798 : return;
799 : }
800 9587820 : auto ePrev = e->getLeftLoopPrev();
801 9591925 : auto ePrevEdge = ePrev->getEdge();
802 9611868 : switch (type) {
803 817559 : case VertexType::Start:
804 : // 1. Insert e(i) in T and set helper(e, i) to v(i).
805 817559 : if (!fullEdge->node) {
806 817540 : fullEdge->node = dict.push(fullEdge, e->_realWinding);
807 : }
808 817399 : fullEdge->node->helper = Helper{e, eNext, type };
809 817399 : break;
810 827429 : case VertexType::End:
811 : // 1. if helper(e, i-1) is a merge vertex
812 : // 2. then Insert the diagonal connecting v(i) to helper(e, i~1) in T.
813 : // 3. Delete e(i-1) from T.
814 827429 : if (auto dictNode = ePrevEdge->node) {
815 827354 : if (dictNode->helper.type == VertexType::Merge) {
816 71980 : doConnectEdges(e, dictNode->helper.e1);
817 : }
818 :
819 : // dict.pop(dictNode);
820 : // ePrev->getEdge()->node = nullptr;
821 : }
822 : break;
823 435925 : case VertexType::Split:
824 : // 1. Search in T to find the edge e(j) directly left of v(i)
825 : // 2. Insert the diagonal connecting v(i) to helper(e, j) in D.
826 : // 3. helper(e, j) <— v(i)
827 : // 4. Insert e(i) in T and set helper(e, i) to v(i)
828 : if constexpr (TessVerbose == VerboseFlag::Full) {
829 : std::cout << "\t\te: " << *e << "\n";
830 : }
831 435925 : if (auto edgeBelow = dict.getEdgeBelow(e->origin, e->vertex)) {
832 : if constexpr (TessVerbose != VerboseFlag::None) {
833 : std::cout << "\t\tedgeBelow: " << *edgeBelow << "\n";
834 : }
835 435904 : if (edgeBelow->helper.e1) {
836 435904 : auto tmpE = doConnectEdges(e, edgeBelow->helper.e1);
837 435768 : edgeBelow->helper = Helper{tmpE, eNext, type };
838 : }
839 : }
840 435768 : if (!fullEdge->node) {
841 435769 : fullEdge->node = dict.push(fullEdge, e->_realWinding);
842 : }
843 435793 : fullEdge->node->helper = Helper{e, eNext, type };
844 435793 : break;
845 426395 : case VertexType::Merge:
846 : // 1. if helper(e, i-1) is a merge vertex
847 : // 2. then Insert the diagonal connecting v, to helper(e, i-1) in D.
848 : // 3. Delete e(i - 1) from T.
849 : if constexpr (TessVerbose == VerboseFlag::Full) {
850 : std::cout << "\t\tePrevEdge: " << *ePrevEdge << "\n";
851 : }
852 426395 : if (auto dictNode = ePrevEdge->node) {
853 4849 : if (dictNode->helper.type == VertexType::Merge) {
854 4849 : doConnectEdges(e, dictNode->helper.e1);
855 4851 : dictNode->helper.type = VertexType::RegularTop;
856 : }
857 :
858 : // dict.pop(dictNode);
859 : // ePrev->getEdge()->node = nullptr;
860 : }
861 :
862 : // 4. Search in T to find the edge e(j) directly left of v(i)
863 : // 5. if helper(e, j) is a merge vertex
864 : // 6. then Insert the diagonal connecting v, to helper(e, j) in D.
865 : // 7. helper(e, j) <— v(i)
866 426397 : if (auto edgeBelow = dict.getEdgeBelow(e->origin, e->vertex)) {
867 : if constexpr (TessVerbose != VerboseFlag::None) {
868 : std::cout << "\t\tedgeBelow: " << *edgeBelow << "\n";
869 : }
870 426336 : if (edgeBelow->helper.type == VertexType::Merge) {
871 4355 : e = doConnectEdges(e, edgeBelow->helper.e1);
872 : }
873 426334 : edgeBelow->helper = Helper{e, eNext, type };
874 : }
875 : break;
876 3511943 : case VertexType::RegularBottom: // boundary above vertex
877 : // 2. if helper(e, i-1) is a merge vertex
878 : // 3. then Insert the diagonal connecting v, to helper(e, i-1) in D
879 : // 4. Delete e(i-1) from T.
880 : // 5. Insert e(i) in T and set helper(e, i) to v(i)
881 : if constexpr (TessVerbose == VerboseFlag::Full) {
882 : std::cout << "\t\tePrevEdge: " << *ePrevEdge << "\n";
883 : }
884 3511943 : if (auto dictNode = ePrevEdge->node) {
885 213555 : if (dictNode->helper.type == VertexType::Merge) {
886 213428 : doConnectEdges(e, dictNode->helper.e1);
887 : }
888 :
889 213493 : dict.pop(dictNode);
890 213481 : ePrevEdge->node = nullptr;
891 : }
892 3511869 : if (!fullEdge->node) {
893 3510482 : fullEdge->node = dict.push(fullEdge, e->_realWinding);
894 : }
895 3511898 : fullEdge->node->helper = Helper{e, eNext, type };
896 3511898 : break;
897 3592617 : case VertexType::RegularTop: // boundary below vertex
898 : // 6. Search in T to find the edge e(j) directly left of v(i)
899 : // 7. if helper(e, j) is a merge vertex
900 : // 8. then Insert the diagonal connecting v(i) to helper(e, j) in D.
901 : // 9. helper(e, j) <- v(i)
902 3592617 : if (auto edgeBelow = dict.getEdgeBelow(e->origin, e->vertex)) {
903 3581845 : if (edgeBelow->helper.type == VertexType::Merge) {
904 109153 : e = doConnectEdges(e, edgeBelow->helper.e1);
905 : }
906 3581801 : edgeBelow->helper = Helper{e, eNext, type };
907 : }
908 : break;
909 : }
910 8925853 : };
911 :
912 : if constexpr (TessVerbose != VerboseFlag::None) {
913 : std::cout << "Sweep event: " << v->_uniqueIdx << ": " << v->_origin << "\n";
914 : }
915 :
916 8925853 : _event = v->_origin;
917 :
918 8925853 : Vec2 tmp;
919 : IntersectionEvent event;
920 :
921 : // first - process intersections
922 : // Intersection can split some edge in dictionary with event vertex,
923 : // so, event vertex will no longer be valid for iteration
924 : do {
925 8925853 : if (auto node = dict.checkForIntersects(v, tmp, event, _mathTolerance)) {
926 : //if (VertLeq(v->_origin, tmp)) {
927 604 : if (processIntersect(v, node, tmp, event) == nullptr) {
928 50 : return;
929 : }
930 : //} else {
931 : // std::cout << "Test\n";
932 : //}
933 : }
934 : } while (0);
935 :
936 : VertexType type;
937 8951549 : HalfEdge * e = v->_edge, *eEnd = v->_edge, *eNext = nullptr;
938 : Edge *fullEdge = nullptr;
939 :
940 8951549 : _eventVertex = v;
941 :
942 : do {
943 18590476 : e->getEdge()->updateInfo();
944 18571819 : fullEdge = e->getEdge();
945 18577976 : if (e->goesRight()) {
946 : // push outcoming edge
947 9330492 : if (auto node = dict.checkForIntersects(e, tmp, event, _mathTolerance)) {
948 : // edges in dictionary should be still valid
949 : // intersections preserves left subedge, and no
950 : // intersection points can be at the left of sweep line
951 : //if (VertLeq(v->_origin, tmp)) {
952 77565 : processIntersect(v, node, e, tmp, event);
953 : //} else {
954 : // std::cout << "Test\n";
955 : //}
956 77566 : if (!_eventVertex) {
957 : return;
958 : }
959 77516 : e = v->_edge;
960 : }
961 : }
962 18588000 : e = e->_originNext;
963 18588000 : } while (e != v->_edge);
964 :
965 : // rotate to first left non-convex angle counterclockwise
966 : // its critical for correct winding calculations
967 8949073 : eEnd = e = getFirstEdge(v);
968 :
969 : do {
970 18538843 : fullEdge = e->getEdge();
971 :
972 : // save original next to prevent new edges processing
973 : // new edges always added between e and eNext around origin
974 18481223 : eNext = e->_originNext;
975 :
976 18481223 : if (e->goesRight()) {
977 9252785 : if (e->_originNext->goesRight()) {
978 4629277 : if (AngleIsConvex(e, e->_originNext)) {
979 : // winding can be taken from edge below bottom (next) edge
980 : // or 0 if there is no edges below
981 991492 : auto edgeBelow = dict.getEdgeBelow(e->_originNext->getEdge());
982 991077 : if (!edgeBelow) {
983 217240 : e->_realWinding = e->_originNext->_realWinding = 0;
984 : } else {
985 773837 : e->_realWinding = e->_originNext->sym()->_realWinding = edgeBelow->windingAbove;
986 : }
987 :
988 : if constexpr (TessVerbose != VerboseFlag::None) {
989 : std::cout << "\tright-convex: " << e << " " << e->getDstVec() << " - " << e->getOrgVec() << " - " << e->_originNext->getDstVec()
990 : << " = " << e->_realWinding;
991 : }
992 :
993 : type = VertexType::Split;
994 991095 : if (isWindingInside(_winding, e->_realWinding)) {
995 : if constexpr (TessVerbose != VerboseFlag::None) {
996 : std::cout << "; Split\n";
997 : }
998 435925 : onVertex(VertexType::Split, fullEdge, e, e->_originNext);
999 : } else {
1000 : if constexpr (TessVerbose != VerboseFlag::None) {
1001 : std::cout << "\n";
1002 : }
1003 : }
1004 : } else {
1005 1323427 : _edgesOfInterests.emplace_back(e);
1006 :
1007 1322665 : e->_realWinding = e->_originNext->sym()->_realWinding = e->sym()->_realWinding + e->sym()->_winding;
1008 :
1009 : if constexpr (TessVerbose != VerboseFlag::None) {
1010 : std::cout << "\tright: " << e << " " << e->getDstVec() << " - " << e->getOrgVec() << " - " << e->_originNext->getDstVec()
1011 : << " = " << e->_realWinding << "(" << e->sym()->_realWinding << "+" << e->sym()->_winding << ")";
1012 : }
1013 :
1014 : type = VertexType::Start;
1015 1322935 : if (isWindingInside(_winding, e->_realWinding)) {
1016 : if constexpr (TessVerbose != VerboseFlag::None) {
1017 : std::cout << "; Start\n";
1018 : }
1019 817606 : onVertex(VertexType::Start, fullEdge, e, e->_originNext);
1020 : } else {
1021 : if constexpr (TessVerbose != VerboseFlag::None) {
1022 : std::cout << "\n";
1023 : }
1024 : }
1025 : }
1026 : } else {
1027 : // right-to-left
1028 6951693 : e->_realWinding = e->_originNext->sym()->_realWinding;
1029 :
1030 : if constexpr (TessVerbose != VerboseFlag::None) {
1031 : std::cout << "\tright-to-left: " << e << " " << e->getDstVec() << " - " << e->getOrgVec() << " - " << e->_originNext->getDstVec()
1032 : << " = " << e->_realWinding << "(" << e->_originNext->sym()->_realWinding << ":" << e->_originNext->_realWinding << ")";
1033 : }
1034 :
1035 : type = VertexType::RegularBottom;
1036 6952481 : if (isWindingInside(_winding, e->_realWinding)) {
1037 : if constexpr (TessVerbose != VerboseFlag::None) {
1038 : std::cout << "; RegularBottom\n";
1039 : }
1040 3510874 : onVertex(VertexType::RegularBottom, fullEdge, e, e->_originNext);
1041 : } else {
1042 : if constexpr (TessVerbose != VerboseFlag::None) {
1043 : std::cout << "\n";
1044 : }
1045 : }
1046 : }
1047 :
1048 : // std::cout << "\t\tpush edge" << fullEdge->getLeftVec() << " - " << fullEdge->getRightVec()
1049 : // << " winding: " << e->_realWinding << "\n";
1050 :
1051 : // push outcoming edge
1052 9267202 : if (!fullEdge->node) {
1053 4528481 : fullEdge->node = dict.push(fullEdge, e->_realWinding);
1054 4527748 : if (isWindingInside(_winding, e->_realWinding)) {
1055 475 : fullEdge->node->helper = Helper{e, e->_originNext, type };
1056 : }
1057 : }
1058 : } else {
1059 : // remove incoming edge
1060 9297442 : if (e->_originNext->goesRight()) {
1061 : // left-to-right
1062 6993490 : e->_originNext->sym()->_realWinding = e->_realWinding;
1063 :
1064 : if constexpr (TessVerbose != VerboseFlag::None) {
1065 : std::cout << "\tleft-to-right: " << e << " " << e->getDstVec() << " - " << e->getOrgVec() << " - " << e->_originNext->getDstVec()
1066 : << " = " << e->_realWinding;
1067 : }
1068 :
1069 : type = VertexType::RegularTop;
1070 6992844 : if (isWindingInside(_winding, e->_realWinding)) {
1071 : if constexpr (TessVerbose != VerboseFlag::None) {
1072 : std::cout << "; RegularTop\n";
1073 : }
1074 3592658 : onVertex(VertexType::RegularTop, fullEdge, e, e->_originNext);
1075 : } else {
1076 : if constexpr (TessVerbose != VerboseFlag::None) {
1077 : std::cout << "\n";
1078 : }
1079 : }
1080 :
1081 : } else {
1082 4628454 : if (AngleIsConvex(e, e->_originNext)) {
1083 : if constexpr (TessVerbose != VerboseFlag::None) {
1084 : std::cout << "\tleft-convex: " << e << " " << e->getDstVec() << " - " << e->getOrgVec() << " - " << e->_originNext->getDstVec()
1085 : << " = " << e->_realWinding;
1086 : }
1087 :
1088 : type = VertexType::Merge;
1089 977687 : if (isWindingInside(_winding, e->_realWinding)) {
1090 : if constexpr (TessVerbose != VerboseFlag::None) {
1091 : std::cout << "; Merge\n";
1092 : }
1093 426375 : onVertex(VertexType::Merge, fullEdge, e, e->_originNext);
1094 : } else {
1095 : if constexpr (TessVerbose != VerboseFlag::None) {
1096 : std::cout << "\n";
1097 : }
1098 : }
1099 :
1100 : } else {
1101 : if constexpr (TessVerbose != VerboseFlag::None) {
1102 : std::cout << "\tleft: " << e << " " << e->getDstVec() << " - " << e->getOrgVec() << " - " << e->_originNext->getDstVec()
1103 : << " = " << e->_realWinding;
1104 : }
1105 :
1106 : type = VertexType::End;
1107 1336844 : if (isWindingInside(_winding, e->_realWinding)) {
1108 : if constexpr (TessVerbose != VerboseFlag::None) {
1109 : std::cout << "; End\n";
1110 : }
1111 827637 : onVertex(VertexType::End, fullEdge, e, e->_originNext);
1112 : } else {
1113 : if constexpr (TessVerbose != VerboseFlag::None) {
1114 : std::cout << "\n";
1115 : }
1116 : }
1117 : }
1118 : }
1119 :
1120 9297252 : if (fullEdge->node) {
1121 9296812 : if (fullEdge->node->helper.type != VertexType::Merge) {
1122 9003769 : dict.pop(fullEdge->node);
1123 8941237 : fullEdge->node = nullptr;
1124 : }
1125 : }
1126 : }
1127 18501189 : e = eNext;
1128 18501189 : } while( e != eEnd );
1129 :
1130 8915703 : _eventVertex = nullptr;
1131 :
1132 8915703 : v->_exportIdx = _exportVertexes.size();
1133 8862948 : _exportVertexes.emplace_back(v);
1134 : }
1135 :
1136 82668 : HalfEdge *Tesselator::Data::processIntersect(Vertex *v, const EdgeDictNode *edge1, HalfEdge *edge2, Vec2 &intersect, IntersectionEvent ev) {
1137 : if constexpr (TessVerbose != VerboseFlag::None) {
1138 : if (edge2) {
1139 : std::cout << "Intersect: " << edge1->org << " - " << edge1->dst() << " X "
1140 : << edge2->getOrgVec() << " - " << edge2->getDstVec() << " = " << intersect << ": " << ev << "\n";
1141 : } else {
1142 : std::cout << "Intersect: " << edge1->org << " - " << edge1->dst() << " X "
1143 : << v->_origin << " = " << intersect << ": " << ev << "\n";
1144 : }
1145 : }
1146 :
1147 82562 : auto fixDictEdge = [&] (const EdgeDictNode *e) {
1148 82562 : e->edge->direction = nan();
1149 82556 : e->edge->updateInfo();
1150 82559 : auto &org = e->edge->getOrgVec();
1151 82559 : auto &dst = e->edge->getDstVec();
1152 : auto tmp = const_cast<EdgeDictNode *>(e);
1153 82559 : if (e->edge->inverted) {
1154 36319 : tmp->norm = org - dst;
1155 36319 : tmp->value.z = org.x;
1156 36319 : tmp->value.w = org.y;
1157 36319 : tmp->horizontal = std::abs(tmp->norm.x) > std::numeric_limits<float>::epsilon();
1158 : } else {
1159 46240 : tmp->norm = dst - org;
1160 46240 : tmp->value.z = dst.x;
1161 46240 : tmp->value.w = dst.y;
1162 46240 : tmp->horizontal = std::abs(tmp->norm.x) > std::numeric_limits<float>::epsilon();
1163 : }
1164 82556 : };
1165 :
1166 87523 : auto checkRecursive = [&, this] (HalfEdge *e) {
1167 82423 : if (auto node = _edgeDict->checkForIntersects(e, intersect, ev, _mathTolerance)) {
1168 5100 : processIntersect(v, node, e, intersect, ev);
1169 : }
1170 165092 : };
1171 :
1172 : Vertex *vertex = nullptr;
1173 :
1174 82668 : switch (ev) {
1175 82427 : case IntersectionEvent::Regular:
1176 : // split both edge1 and edge2, recursive check on new edge2 segments
1177 82427 : vertex = splitEdge(edge1->edge->inverted ? &edge1->edge->right : &edge1->edge->left, edge2, intersect);
1178 : if constexpr (TessVerbose != VerboseFlag::None) {
1179 : std::cout << "\tVertex: " << *vertex << "\n";
1180 : }
1181 82428 : fixDictEdge(edge1);
1182 82423 : checkRecursive(edge2);
1183 82427 : _vertexQueue->insert(vertex);
1184 : break;
1185 0 : case IntersectionEvent::EventIsIntersection:
1186 : // two cases: edges overlap or edge2 starts on edge1
1187 : // in either cases we just split edge1, then merge vertexes
1188 : // if edges is overlapping - it will be processed when new edge1 segment checked for intersections
1189 : // edge2 can be null here
1190 0 : vertex = splitEdge(edge1->edge->getPostitive(), intersect);
1191 0 : fixDictEdge(edge1);
1192 0 : if (!mergeVertexes(v, vertex)) {
1193 0 : releaseVertex(v);
1194 0 : return nullptr;
1195 : }
1196 : break;
1197 107 : case IntersectionEvent::EdgeConnection1:
1198 : // Edge2 ends somewhere on Edge1
1199 : // split Edge1, next segment will be checked on next sweep event
1200 107 : vertex = splitEdge(edge2->getEdge()->getPostitive(), intersect);
1201 107 : if (!mergeVertexes(_vertexes[edge1->edge->getNegative()->vertex], vertex)) {
1202 0 : releaseVertex(_vertexes[edge1->edge->getNegative()->vertex]);
1203 0 : return nullptr;
1204 : }
1205 : break;
1206 134 : case IntersectionEvent::EdgeConnection2:
1207 : // Edge1 ends somewhere on Edge2
1208 : // split Edge2, perform recursive checks on new segment
1209 134 : vertex = splitEdge(edge1->edge->getPostitive(), intersect);
1210 134 : fixDictEdge(edge1);
1211 134 : if (!mergeVertexes(_vertexes[edge2->getEdge()->getNegative()->vertex], vertex)) {
1212 0 : releaseVertex(_vertexes[edge2->getEdge()->getNegative()->vertex]);
1213 0 : return nullptr;
1214 : }
1215 : break;
1216 : }
1217 :
1218 : return edge2;
1219 : }
1220 :
1221 604 : HalfEdge *Tesselator::Data::processIntersect(Vertex *v, const EdgeDictNode *edge1, Vec2 &intersect, IntersectionEvent ev) {
1222 : if constexpr (TessVerbose != VerboseFlag::None) {
1223 : std::cout << "Intersect: " << edge1->org << " - " << edge1->dst() << " X "
1224 : << v->_origin << " = " << intersect << ": " << ev << "\n";
1225 : }
1226 :
1227 604 : auto fixDictEdge = [&] (const EdgeDictNode *e) {
1228 604 : e->edge->direction = nan();
1229 604 : e->edge->updateInfo();
1230 604 : auto &org = e->edge->getOrgVec();
1231 604 : auto &dst = e->edge->getDstVec();
1232 : auto tmp = const_cast<EdgeDictNode *>(e);
1233 604 : if (e->edge->inverted) {
1234 184 : tmp->norm = org - dst;
1235 184 : tmp->value.z = org.x;
1236 184 : tmp->value.w = org.y;
1237 184 : tmp->horizontal = std::abs(tmp->norm.x) > std::numeric_limits<float>::epsilon();
1238 : } else {
1239 420 : tmp->norm = dst - org;
1240 420 : tmp->value.z = dst.x;
1241 420 : tmp->value.w = dst.y;
1242 420 : tmp->horizontal = std::abs(tmp->norm.x) > std::numeric_limits<float>::epsilon();
1243 : }
1244 604 : };
1245 :
1246 : Vertex *vertex = nullptr;
1247 :
1248 604 : switch (ev) {
1249 604 : case IntersectionEvent::EventIsIntersection:
1250 : // two cases: edges overlap or edge2 starts on edge1
1251 : // in either cases we just split edge1, then merge vertexes
1252 : // if edges is overlapping - it will be processed when new edge1 segment checked for intersections
1253 : // edge2 can be null here
1254 604 : vertex = splitEdge(edge1->edge->getPostitive(), intersect);
1255 604 : fixDictEdge(edge1);
1256 604 : if (!mergeVertexes(v, vertex)) {
1257 0 : releaseVertex(v);
1258 0 : return nullptr;
1259 : }
1260 : break;
1261 : default:
1262 : return nullptr;
1263 : }
1264 :
1265 604 : return edge1->edge->getPostitive();
1266 : }
1267 :
1268 445124 : Edge *Tesselator::Data::makeEdgeLoop(const Vec2 &origin) {
1269 445124 : Edge *edge = allocEdge();
1270 :
1271 445129 : makeVertex(&edge->left)->_origin = origin;
1272 444429 : edge->right.copyOrigin(&edge->left);
1273 :
1274 444472 : edge->left.origin = edge->right.origin = origin;
1275 444472 : edge->left._leftNext = &edge->left; edge->left._originNext = &edge->right;
1276 444472 : edge->right._leftNext = &edge->right; edge->right._originNext = &edge->left;
1277 :
1278 444472 : return edge;
1279 : }
1280 :
1281 9649822 : Vertex *Tesselator::Data::makeVertex(HalfEdge *eOrig) {
1282 9649822 : Vertex *vNew = allocVertex();
1283 9582280 : vNew->insertBefore(eOrig);
1284 9588959 : return vNew;
1285 : }
1286 :
1287 9554119 : HalfEdge *Tesselator::Data::pushVertex(HalfEdge *e, const Vec2 &origin, bool clockwise, bool returnNew) {
1288 9554119 : if (!e) {
1289 : /* Make a self-loop (one vertex, one edge). */
1290 445111 : auto edge = makeEdgeLoop(origin);
1291 :
1292 444467 : edge->left._winding = (clockwise ? -1 : 1);
1293 444467 : edge->right._winding = (clockwise ? 1 : -1);
1294 444467 : e = &edge->left;
1295 : } else {
1296 : // split primary edge
1297 :
1298 9109008 : Edge *eNew = allocEdge(); // make new edge pair
1299 9123500 : Vertex *v = makeVertex(&eNew->left); // make _sym as origin, because _leftNext will be clockwise
1300 9069932 : v->_origin = origin;
1301 :
1302 9069932 : HalfEdge::splitEdgeLoops(e, &eNew->left, v);
1303 :
1304 9072018 : if (returnNew) {
1305 : e = &eNew->left;
1306 : }
1307 : }
1308 :
1309 9516485 : if (origin.x < _bmin.x) _bmin.x = origin.x;
1310 9516485 : if (origin.x > _bmax.x) _bmax.x = origin.x;
1311 9516485 : if (origin.y < _bmin.y) _bmin.y = origin.y;
1312 9516485 : if (origin.y > _bmax.y) _bmax.y = origin.y;
1313 :
1314 9516485 : ++ _nvertexes;
1315 :
1316 9516485 : return e;
1317 : }
1318 :
1319 8426670 : HalfEdge *Tesselator::Data::connectEdges(HalfEdge *eOrg, HalfEdge *eDst) {
1320 8426670 : if (eOrg->sym()->vertex == eDst->vertex) {
1321 175 : std::cout << "ERROR: connectEdges on same vertex:\n\t" << *eOrg << "\n\t" << *eOrg->sym() << "\n\t" << *eDst << "\n";
1322 175 : return nullptr;
1323 : }
1324 :
1325 : // for triangle cut - eDst->lnext = eOrg
1326 8427591 : Edge *edge = allocEdge();
1327 8422333 : HalfEdge *eNew = &edge->left; // make new edge pair
1328 8422333 : HalfEdge *eNewSym = eNew->sym();
1329 8423730 : HalfEdge *ePrev = eDst->_originNext->sym();
1330 8423651 : HalfEdge *eNext = eOrg->_leftNext;
1331 :
1332 8423651 : eNew->_realWinding = eNewSym->_realWinding = eOrg->_realWinding;
1333 :
1334 8423651 : eNew->copyOrigin(eOrg->sym());
1335 8423916 : eNew->sym()->copyOrigin(eDst);
1336 :
1337 8424042 : ePrev->_leftNext = eNewSym; eNewSym->_leftNext = eNext; // external left chain
1338 8424042 : eNew->_leftNext = eDst; eOrg->_leftNext = eNew; // internal left chain
1339 :
1340 8424042 : eNew->_originNext = eOrg->sym(); eNext->_originNext = eNew; // org vertex chain
1341 8421700 : eNewSym->_originNext = ePrev->sym(); eDst->_originNext = eNewSym; // dst vertex chain
1342 :
1343 : if constexpr (TessVerbose != VerboseFlag::None) {
1344 : std::cout << "\t\t\tConnected: " << *eNew << "\n";
1345 : }
1346 :
1347 8420448 : edge->updateInfo();
1348 :
1349 8443640 : return eNew;
1350 : }
1351 :
1352 1230 : Vertex *Tesselator::Data::splitEdge(HalfEdge *eOrg1, const Vec2 &vec) {
1353 : Vertex *v = nullptr;
1354 :
1355 : if constexpr (TessVerbose != VerboseFlag::None) {
1356 : std::cout << "SplitEdge:\n\t" << *eOrg1 << "\n";
1357 : }
1358 :
1359 1230 : HalfEdge *eNew = &allocEdge()->left; // make new edge pair
1360 1230 : v = makeVertex(eNew); // make _sym as origin, because _leftNext will be clockwise
1361 1230 : v->_origin = vec;
1362 :
1363 1230 : auto v2 = _vertexes[eOrg1->sym()->vertex];
1364 :
1365 1230 : HalfEdge::splitEdgeLoops(eOrg1, eNew, v);
1366 :
1367 1230 : if (v2->_edge == eOrg1->sym()) {
1368 598 : v2->_edge = eNew->sym();
1369 : }
1370 :
1371 1229 : eNew->getEdge()->direction = nan();
1372 1229 : eNew->getEdge()->updateInfo();
1373 :
1374 : if constexpr (TessVerbose != VerboseFlag::None) {
1375 : std::cout << "\t" << *eOrg1 << "\n\t" << *eNew << "\n";
1376 : }
1377 :
1378 1230 : return v;
1379 : }
1380 :
1381 82425 : Vertex *Tesselator::Data::splitEdge(HalfEdge *eOrg1, HalfEdge *eOrg2, const Vec2 &vec2) {
1382 : Vertex *v = nullptr;
1383 : HalfEdge *oPrevOrg = nullptr;
1384 : HalfEdge *oPrevNew = nullptr;
1385 :
1386 82425 : const Edge *fullEdge1 = eOrg1->getEdge();
1387 82421 : const Edge *fullEdge2 = eOrg2->getEdge();
1388 :
1389 : // swap edges if eOrg2 will be upper then eOrg1
1390 82424 : if (fullEdge2->direction > fullEdge1->direction) {
1391 : auto tmp = eOrg2;
1392 : eOrg2 = eOrg1;
1393 : eOrg1 = tmp;
1394 : }
1395 :
1396 : do {
1397 : // split primary edge
1398 82424 : HalfEdge *eNew = &allocEdge()->left; // make new edge pair
1399 82427 : v = makeVertex(eNew); // make _sym as origin, because _leftNext will be clockwise
1400 82410 : v->_origin = vec2;
1401 :
1402 82410 : auto v2 = _vertexes[eOrg1->sym()->vertex];
1403 :
1404 82411 : HalfEdge::splitEdgeLoops(eOrg1, eNew, v);
1405 :
1406 82407 : if (v2->_edge == eOrg1->sym()) {
1407 39322 : v2->_edge = eNew->sym();
1408 : }
1409 :
1410 : oPrevOrg = eNew;
1411 82410 : oPrevNew = eOrg1->sym();
1412 :
1413 82412 : eNew->getEdge()->updateInfo();
1414 : } while (0);
1415 :
1416 : do {
1417 82428 : auto v2 = _vertexes[eOrg2->sym()->vertex];
1418 :
1419 : // split and join secondary edge
1420 82414 : HalfEdge *eNew = &allocEdge()->left; // make new edge pair
1421 :
1422 82414 : HalfEdge::splitEdgeLoops(eOrg2, eNew, v);
1423 82413 : HalfEdge::joinEdgeLoops(eOrg2, oPrevOrg);
1424 82417 : HalfEdge::joinEdgeLoops(eNew->sym(), oPrevNew);
1425 :
1426 82418 : if (v2->_edge == eOrg2->sym()) {
1427 35729 : v2->_edge = eNew->sym();
1428 : }
1429 :
1430 82416 : eNew->getEdge()->direction = nan();
1431 82418 : eNew->getEdge()->updateInfo();
1432 : } while (0);
1433 :
1434 82428 : return v;
1435 : }
1436 :
1437 : // rotate to first left non-convex angle counterclockwise
1438 8949166 : HalfEdge *Tesselator::Data::getFirstEdge(Vertex *v) const {
1439 8949166 : auto e = v->_edge;
1440 : do {
1441 13975394 : if (e->goesRight()) {
1442 8638983 : if (e->_originNext->goesRight()) {
1443 3308986 : if (AngleIsConvex(e, e->_originNext)) {
1444 : // convex right angle is solution
1445 991450 : return e;
1446 : } else {
1447 : // non-convex right angle, skip
1448 : }
1449 : } else {
1450 : // right-to-left angle, next angle is solution
1451 6991877 : return e->_originNext;
1452 : }
1453 : } else {
1454 5341409 : if (e->_originNext->goesLeft()) {
1455 3476625 : if (AngleIsConvex(e, e->_originNext)) {
1456 : // convex left angle, next angle is solution
1457 978488 : return e->_originNext;
1458 : } else {
1459 : // non-convex left angle, skip
1460 : }
1461 : } else {
1462 : // left-to-right angle, skip
1463 : }
1464 : }
1465 5026278 : e = e->_originNext;
1466 5026278 : } while ( e != v->_edge );
1467 : return e;
1468 : }
1469 :
1470 2717838 : static bool Tesselator_checkConnectivity(HalfEdge *eOrg) {
1471 : if constexpr (TessVerbose != VerboseFlag::None) {
1472 : auto eOrgTmp = eOrg;
1473 : auto n = 0;
1474 : while (n < 100) {
1475 : eOrgTmp = eOrgTmp->_originNext;
1476 : if (eOrgTmp == eOrg) {
1477 : break;
1478 : }
1479 : ++ n;
1480 : }
1481 :
1482 : if (n >= 100) {
1483 : return false;
1484 : }
1485 : }
1486 :
1487 2717838 : return true;
1488 : }
1489 :
1490 543581 : bool Tesselator::Data::mergeVertexes(Vertex *org, Vertex *merge) {
1491 543581 : if (std::find(_protectedVertexes.begin(), _protectedVertexes.end(), org) != _protectedVertexes.end()) {
1492 : return true;
1493 : }
1494 :
1495 543579 : if (std::find(_protectedVertexes.begin(), _protectedVertexes.end(), merge) != _protectedVertexes.end()) {
1496 : return true;
1497 : }
1498 :
1499 : if constexpr (TessVerbose != VerboseFlag::None) {
1500 : std::cout << TessVerbose << "Merge:\n\t" << *org << "\n";
1501 : org->foreach([&] (const HalfEdge &e) {
1502 : std::cout << "\t\t" << e << "\n";
1503 : });
1504 :
1505 : std::cout << "\t" << *merge << "\n";
1506 : merge->foreach([&] (const HalfEdge &e) {
1507 : std::cout << "\t\t" << e << "\n";
1508 : });
1509 : }
1510 :
1511 1087287 : auto insertNext = [&] (HalfEdge *l, HalfEdge *r) {
1512 1087287 : auto lNext = l->_originNext;
1513 :
1514 1087287 : if (r->_originNext != r) {
1515 543757 : auto rOriginPrev = r->getOriginPrev();
1516 543757 : auto rLeftPrev = r->getLeftLoopPrev();
1517 :
1518 543757 : rOriginPrev->_originNext = r->_originNext;
1519 543757 : rLeftPrev->_leftNext = rOriginPrev;
1520 : }
1521 :
1522 1087287 : r->_originNext = lNext; r->sym()->_leftNext = l;
1523 1087285 : lNext->sym()->_leftNext = r; l->_originNext = r;
1524 1087283 : return r;
1525 : };
1526 :
1527 561033 : auto mergeEdges = [&] (HalfEdge *eOrg, HalfEdge *eMerge) {
1528 561033 : if (eOrg->_leftNext->sym() == eMerge) {
1529 : if constexpr (TessVerbose != VerboseFlag::None) {
1530 : std::cout << "Merge next (auto):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1531 : }
1532 :
1533 1406 : return insertNext(eOrg, eMerge);
1534 559626 : } else if (eMerge->_leftNext->sym() == eOrg) {
1535 : if constexpr (TessVerbose != VerboseFlag::None) {
1536 : std::cout << "Merge prev (auto):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1537 : }
1538 :
1539 279056 : insertNext(eOrg->getOriginPrev(), eMerge);
1540 279056 : return eOrg;
1541 : } else {
1542 280572 : auto eOrgCcw = Vec2::isCounterClockwise(org->_origin, eOrg->getDstVec(), eOrg->_leftNext->getDstVec());
1543 280572 : auto eMergeCcw = Vec2::isCounterClockwise(org->_origin, eMerge->getDstVec(), eMerge->_leftNext->getDstVec());
1544 280571 : if (eOrgCcw == eMergeCcw) {
1545 88586 : if (eOrg->goesRight() && eMerge->goesRight()) {
1546 79280 : if (VertLeq(eOrg->getDstVec(), eMerge->getDstVec())) {
1547 : if constexpr (TessVerbose != VerboseFlag::None) {
1548 : std::cout << "Merge prev (direct):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1549 : }
1550 :
1551 79059 : insertNext(eOrg->getOriginPrev(), eMerge);
1552 79059 : return eOrg;
1553 : } else {
1554 : if constexpr (TessVerbose != VerboseFlag::None) {
1555 : std::cout << "Merge next (direct):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1556 : }
1557 :
1558 219 : return insertNext(eOrg, eMerge);
1559 : }
1560 : } else {
1561 9306 : if (VertLeq(eOrg->getDstVec(), eMerge->getDstVec())) {
1562 : if constexpr (TessVerbose != VerboseFlag::None) {
1563 : std::cout << "Merge next (reverse):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1564 : }
1565 :
1566 9183 : return insertNext(eOrg, eMerge);
1567 : } else {
1568 : if constexpr (TessVerbose != VerboseFlag::None) {
1569 : std::cout << "Merge prev (reverse):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1570 : }
1571 :
1572 125 : insertNext(eOrg->getOriginPrev(), eMerge);
1573 125 : return eOrg;
1574 : }
1575 : }
1576 191985 : } else if (eOrgCcw) {
1577 : if constexpr (TessVerbose != VerboseFlag::None) {
1578 : std::cout << "Merge prev (ccw):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1579 : }
1580 :
1581 99556 : auto r = insertNext(eOrg, eMerge);
1582 99556 : return r;
1583 : } else {
1584 : if constexpr (TessVerbose != VerboseFlag::None) {
1585 : std::cout << "Merge next (ccw):\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1586 : }
1587 :
1588 92429 : insertNext(eOrg->getOriginPrev(), eMerge);
1589 92429 : return eOrg;
1590 : }
1591 : }
1592 543573 : };
1593 :
1594 543573 : auto eOrg = org->_edge;
1595 543573 : auto eMerge = merge->_edge;
1596 : auto eMergeEnd = eMerge;
1597 :
1598 1087155 : float lA = EdgeAngle(eOrg->getNormVec(), eOrg->getOriginNext()->getNormVec());
1599 :
1600 : // merge common edges, if any
1601 : do {
1602 1087385 : auto eMergeNext = eMerge->_originNext;
1603 :
1604 1087385 : if (eMerge->sym()->vertex == org->_uniqueIdx && eMergeNext->_originNext == eMerge) {
1605 50 : org->_edge = removeEdge(eMerge);
1606 50 : releaseVertex(merge);
1607 : if constexpr (TessVerbose == VerboseFlag::Full) {
1608 : std::cout << TessVerbose << "Out:\n\t" << *org << "\n";
1609 : }
1610 50 : return true;
1611 : }
1612 :
1613 : eMerge = eMergeNext;
1614 1087332 : } while (eMerge != eMergeEnd);
1615 :
1616 543529 : if (!Tesselator_checkConnectivity(org->_edge)) {
1617 0 : log::error("geom::Tesselator", "Pizdets");
1618 : }
1619 :
1620 : do {
1621 1087289 : auto eMergeNext = eMerge->_originNext;
1622 :
1623 : do {
1624 : if constexpr (TessVerbose != VerboseFlag::None) {
1625 : std::cout << "eMerge: " << *eMerge << "\n";
1626 : }
1627 1813623 : auto rA = EdgeAngle(eOrg->getNormVec(), eMerge->getNormVec());
1628 1813620 : if (EdgeAngleIsBelowTolerance(rA, _mathTolerance)) {
1629 561031 : auto tmpOrg = mergeEdges(eOrg, eMerge);
1630 :
1631 : /*if (eMerge == eMerge->_originNext) {
1632 : std::cout << "Final:\n\t" << *eMerge << "\n";
1633 : }*/
1634 :
1635 561028 : if (!Tesselator_checkConnectivity(org->_edge)) {
1636 0 : log::error("geom::Tesselator", "Pizdets");
1637 : }
1638 :
1639 561028 : eMerge->origin = eOrg->origin;
1640 561028 : eMerge->vertex = eOrg->vertex;
1641 : eOrg = tmpOrg;
1642 561028 : lA = EdgeAngle(eOrg->getNormVec(), eOrg->getOriginNext()->getNormVec());
1643 561032 : break;
1644 1252589 : } else if (rA < lA) {
1645 : if constexpr (TessVerbose != VerboseFlag::None) {
1646 : std::cout << "Insert next:\n\t" << *eOrg << "\n\t" << *eMerge << "\n";
1647 : }
1648 :
1649 : /*if (eMerge == eMerge->_originNext) {
1650 : std::cout << "Final:\n\t" << *eMerge << "\n";
1651 : }
1652 :
1653 : std::cout << "Final2:"
1654 : << "\n\tnext-next: " << *eMergeNext->_originNext
1655 : << "\n\tnext: " << *eMergeNext
1656 : << "\n\tmerge: " << *eMerge
1657 : << "\n\tprev: " << *eMerge->getOriginPrev()
1658 : << "\n";*/
1659 526257 : auto tmpOrg = insertNext(eOrg, eMerge);
1660 :
1661 : /*std::cout << "Final3:\n\tmerge: " << *eMergeNext
1662 : << "\n\tnext: " << *eMergeNext->_originNext
1663 : << "\n\tprev: " << *eMergeNext->getOriginPrev()
1664 : << "\n";*/
1665 526256 : if (eMergeNext->_originNext == eMerge) {
1666 0 : std::cout << "Final4:\n\t" << *eMerge << "\n";
1667 : }
1668 :
1669 526256 : if (!Tesselator_checkConnectivity(org->_edge)) {
1670 0 : log::error("geom::Tesselator", "Pizdets");
1671 : }
1672 :
1673 526256 : eMerge->origin = eOrg->origin;
1674 526256 : eMerge->vertex = eOrg->vertex;
1675 : eOrg = tmpOrg;
1676 526256 : lA = EdgeAngle(eOrg->getNormVec(), eOrg->getOriginNext()->getNormVec());
1677 526258 : break;
1678 : } else {
1679 726332 : eOrg = eOrg->_originNext;
1680 726332 : lA = EdgeAngle(eOrg->getNormVec(), eOrg->getOriginNext()->getNormVec());
1681 : }
1682 726334 : } while (true);
1683 :
1684 1087290 : if (eMerge == eMergeNext) {
1685 : break;
1686 : }
1687 : eMerge = eMergeNext;
1688 543760 : } while (eMerge != eMergeEnd);
1689 :
1690 543530 : if (!Tesselator_checkConnectivity(org->_edge)) {
1691 0 : log::error("geom::Tesselator", "Pizdets");
1692 : }
1693 :
1694 543530 : if (merge->_queueHandle != maxOf<QueueHandle>()) {
1695 278529 : _vertexQueue->remove(merge->_queueHandle);
1696 278529 : merge->_queueHandle = maxOf<QueueHandle>();
1697 : }
1698 :
1699 543528 : releaseVertex(merge);
1700 :
1701 : // remove degenerates
1702 :
1703 : // remove ears - edge cycles on same vertex
1704 543524 : auto eOrgEnd = eOrg = org->_edge;
1705 :
1706 543524 : if (!Tesselator_checkConnectivity(eOrg)) {
1707 0 : log::error("geom::Tesselator", "Pizdets");
1708 : }
1709 :
1710 : do {
1711 : if constexpr (TessVerbose != VerboseFlag::None) {
1712 : std::cout << TessVerbose << "\t\tRemoveEars: " << *eOrg << "\n";
1713 : }
1714 :
1715 2175636 : auto eOrgNext = eOrg->_originNext;
1716 :
1717 2175636 : if (eOrg->_leftNext->sym() == eOrg->_originNext && eOrg->_originNext->_leftNext->sym() == eOrg) {
1718 : auto eOrgJoin = eOrgNext;
1719 :
1720 : if constexpr (TessVerbose != VerboseFlag::None) {
1721 : std::cout << TessVerbose << "\t\t\t: " << *eOrg << "\n";
1722 : std::cout << TessVerbose << "\t\t\t: " << *eOrgJoin << "\n";
1723 : }
1724 141 : eOrgNext = eOrgJoin->_originNext;
1725 :
1726 141 : auto orgPrev = eOrg->getOriginPrev();
1727 141 : auto orgLeftPrev = eOrg->getLeftLoopPrev();
1728 141 : auto joinLeftPrev = eOrgJoin->getLeftLoopPrev();
1729 :
1730 141 : orgPrev->_originNext = eOrgJoin->_originNext;
1731 141 : orgLeftPrev->_leftNext = eOrg->_leftNext->_leftNext;
1732 141 : joinLeftPrev->_leftNext = eOrgJoin->_leftNext->_leftNext;
1733 :
1734 141 : auto vertex = _vertexes[eOrg->_leftNext->vertex];
1735 :
1736 141 : auto orgEdge = eOrg->getEdge();
1737 141 : if (orgEdge->node) {
1738 0 : _edgeDict->pop(orgEdge->node);
1739 0 : orgEdge->node = nullptr;
1740 : }
1741 141 : releaseEdge(orgEdge);
1742 :
1743 141 : auto joinEdge = eOrgJoin->getEdge();
1744 141 : if (joinEdge->node) {
1745 0 : _edgeDict->pop(joinEdge->node);
1746 0 : joinEdge->node = nullptr;
1747 : }
1748 141 : releaseEdge(joinEdge);
1749 :
1750 : // we can not touch vertexes, that was already exported
1751 : if (VertLeq(_event, vertex->_origin)) {
1752 141 : if ( vertex->_queueHandle != maxOf<QueueHandle>()) {
1753 91 : _vertexQueue->remove(vertex->_queueHandle);
1754 91 : vertex->_queueHandle = maxOf<QueueHandle>();
1755 : }
1756 141 : if (vertex == _eventVertex) {
1757 50 : _eventVertex = nullptr;
1758 : }
1759 : }
1760 :
1761 141 : releaseVertex(vertex);
1762 :
1763 141 : if (eOrg == eOrgEnd || eOrgJoin == eOrgEnd) {
1764 16 : eOrgEnd = org->_edge = eOrgNext->getOriginPrev();
1765 : }
1766 :
1767 141 : if (eOrg == eOrgEnd || eOrgJoin == eOrgEnd || eOrg == eOrgNext) {
1768 : // origin vertex is empty
1769 0 : if (org == _eventVertex) {
1770 0 : _eventVertex = nullptr;
1771 : }
1772 :
1773 0 : org->_edge = nullptr;
1774 0 : log::error("geom::Tesselator", "Pizdets");
1775 0 : return false;
1776 : }
1777 : }
1778 :
1779 : eOrg = eOrgNext;
1780 2175640 : } while (eOrg != eOrgEnd);
1781 :
1782 : if constexpr (TessVerbose != VerboseFlag::None) {
1783 : std::cout << "\tResult (pre): " << eOrg->vertex << "\n";
1784 : org->foreach([&] (const HalfEdge &e) {
1785 : std::cout << "\t\t" << e << "\n";
1786 : if constexpr (TessVerbose == VerboseFlag::Full) {
1787 : e.foreachOnFace([&] (const HalfEdge &e) {
1788 : std::cout << "\t\t\t" << e << "\n";
1789 : });
1790 : }
1791 : });
1792 : }
1793 :
1794 : // process overlaps
1795 543528 : _protectedVertexes.emplace_back(org);
1796 :
1797 543523 : eOrgEnd = eOrg = org->_edge;
1798 : if constexpr (TessVerbose != VerboseFlag::None) {
1799 : std::cout << "Start: " << eOrg->vertex << " (" << _protectedVertexes.size() << "): " << *eOrg << "\n";
1800 : }
1801 : do {
1802 : //std::cout << "\tOverlaps: " << eOrg->vertex << " (" << _protectedVertexes.size() << "): " << *eOrg << "\n";
1803 1924697 : auto eOrgNext = eOrg->_originNext;
1804 :
1805 1924697 : float a = EdgeAngle(eOrg->getNormVec(), eOrgNext->getNormVec());
1806 1924735 : if (EdgeAngleIsBelowTolerance(a, _mathTolerance)) {
1807 : auto eOrgJoin = eOrgNext;
1808 :
1809 541193 : eOrgNext = eOrgJoin->_originNext;
1810 :
1811 541193 : if (processEdgeOverlap(org, eOrg, eOrgJoin)) {
1812 278883 : eOrgEnd = eOrg = org->_edge;
1813 278883 : eOrgNext = eOrg->_originNext;
1814 : } else {
1815 262282 : if (eOrgJoin == eOrgEnd) {
1816 : break;
1817 : }
1818 : }
1819 : }
1820 :
1821 : eOrg = eOrgNext;
1822 1888522 : } while (eOrg != eOrgEnd);
1823 :
1824 : // remove loops
1825 543533 : eOrgEnd = eOrg = org->_edge;
1826 : do {
1827 1858036 : auto eOrgNext = eOrg->_originNext;
1828 :
1829 1858036 : if (eOrg->_leftNext->_leftNext == eOrg) {
1830 280346 : auto next = eOrg->_leftNext->sym();
1831 280350 : if (next == eOrgNext) {
1832 280348 : if (org->_edge == eOrg || eOrgEnd == eOrg) {
1833 18582 : eOrgEnd = org->_edge = eOrgNext;
1834 : }
1835 :
1836 280348 : auto eOrgPrev = eOrg->getOriginPrev();
1837 280348 : auto eOrgSym = eOrg->sym();
1838 280348 : auto eOrgSymPrev = eOrgSym->getLeftLoopPrev();
1839 280348 : auto eOrgSymOrgPrev = eOrgSym->getOriginPrev();
1840 280348 : auto eNextSym = next->sym();
1841 :
1842 280348 : if (next->_winding != eOrg->_winding) {
1843 258789 : next->_winding += eOrg->_winding;
1844 : }
1845 280348 : if (eNextSym->_winding != eOrgSym->_winding) {
1846 258789 : eNextSym->_winding += eOrgSym->_winding;
1847 : }
1848 :
1849 : if constexpr (TessVerbose != VerboseFlag::None) {
1850 : std::cout << "Remove loop: " << eOrg->vertex << " (" << _protectedVertexes.size() << "):\n"
1851 : "\t" << *eOrg << "\n\t" << *eOrg->_leftNext << "\n";
1852 : }
1853 :
1854 280348 : eOrgSymPrev->_leftNext = eNextSym;
1855 280348 : eNextSym->_leftNext = eOrgSym->_leftNext;
1856 :
1857 280348 : eOrgPrev->_originNext = eOrg->_originNext;
1858 280348 : eOrgSymOrgPrev->_originNext = eOrgSym->_originNext;
1859 :
1860 280348 : _vertexes[eOrgSymOrgPrev->vertex]->_edge = eOrgSym->_originNext;
1861 :
1862 : if constexpr (TessVerbose != VerboseFlag::None) {
1863 : _vertexes[eOrgSymOrgPrev->vertex]->foreach([&] (const HalfEdge &e) {
1864 : std::cout << "\tVertex " << eOrgSymOrgPrev->vertex << ": " << e << "\n";
1865 : });
1866 : }
1867 :
1868 280345 : auto joinEdge = eOrg->getEdge();
1869 280345 : if (joinEdge->node) {
1870 40 : _edgeDict->pop(joinEdge->node);
1871 40 : joinEdge->node = nullptr;
1872 : }
1873 280345 : releaseEdge(joinEdge);
1874 : }
1875 : }
1876 :
1877 : eOrg = eOrgNext;
1878 1858027 : } while (eOrg != eOrgEnd);
1879 :
1880 : if constexpr (TessVerbose != VerboseFlag::None) {
1881 : std::cout << "\tResult (post): " << eOrg->vertex << "\n";
1882 : org->foreach([&] (const HalfEdge &e) {
1883 : std::cout << "\t\t" << e << "\n";
1884 : if constexpr (TessVerbose == VerboseFlag::Full) {
1885 : e.foreachOnFace([&] (const HalfEdge &e) {
1886 : std::cout << "\t\t\t" << e << "\n";
1887 : });
1888 : }
1889 : });
1890 : }
1891 :
1892 543524 : _protectedVertexes.pop_back();
1893 : return true;
1894 : }
1895 :
1896 163000 : HalfEdge *Tesselator::Data::removeEdge(HalfEdge *e) {
1897 163000 : auto eSym = e->sym();
1898 :
1899 163037 : auto eLeftPrev = e->getLeftLoopPrev();
1900 163068 : auto eSymLeftPrev = eSym->getLeftLoopPrev();
1901 163115 : auto eOriginPrev = e->getOriginPrev();
1902 163127 : auto eSymOriginPrev = eSym->getOriginPrev();
1903 :
1904 163226 : e->_originNext->origin = e->_leftNext->origin;
1905 163226 : e->_originNext->vertex = e->_leftNext->vertex;
1906 :
1907 163226 : e->_originNext->getEdge()->direction = nan();
1908 163169 : e->_originNext->getEdge()->updateInfo();
1909 :
1910 163724 : eLeftPrev->_leftNext = e->_leftNext;
1911 163724 : eSymLeftPrev->_leftNext = eSym->_leftNext;
1912 :
1913 163724 : eOriginPrev->_originNext = eSym->_originNext;
1914 163724 : eSymOriginPrev->_originNext = e->_originNext;
1915 :
1916 163724 : releaseEdge(e->getEdge());
1917 :
1918 162465 : return eSymOriginPrev->_originNext;
1919 : }
1920 :
1921 1667580 : HalfEdge * Tesselator::Data::removeDegenerateEdges(HalfEdge *e, uint32_t *nedges, bool safeRemove) {
1922 : auto eEnd = e;
1923 :
1924 : do {
1925 20631554 : if (!e) {
1926 : break;
1927 : }
1928 20631554 : auto eLnext = e->_leftNext;
1929 :
1930 20631554 : auto edge = e->getEdge();
1931 20631654 : auto edgeNext = eLnext->getEdge();
1932 :
1933 20632025 : edge->updateInfo();
1934 20619068 : edgeNext->updateInfo();
1935 :
1936 41585283 : while (VertEq(e->getOrgVec(), e->getDstVec(), _mathTolerance) && e->_leftNext->_leftNext != e) {
1937 : if constexpr (TessVerbose != VerboseFlag::None) {
1938 : std::cout << "Remove degenerate: " << *e << "\n";
1939 : }
1940 :
1941 160291 : if (eEnd == e) {
1942 : eEnd = eLnext;
1943 : }
1944 :
1945 160291 : auto vertex = _vertexes[e->sym()->vertex];
1946 159500 : auto merge = _vertexes[e->vertex];
1947 :
1948 : auto tmp = e;
1949 : e = eLnext;
1950 159531 : eLnext = e->_leftNext;
1951 :
1952 159531 : vertex->_edge = removeEdge(tmp);
1953 :
1954 159074 : if (safeRemove) {
1955 159015 : releaseVertex(merge);
1956 : }
1957 :
1958 159083 : if (nedges) {
1959 159033 : -- *nedges;
1960 : }
1961 :
1962 159083 : edge = e->getEdge();
1963 159135 : edgeNext = eLnext->getEdge();
1964 :
1965 159203 : edge->updateInfo();
1966 159146 : edgeNext->updateInfo();
1967 : }
1968 :
1969 20632709 : if (eLnext->_leftNext == e) {
1970 : // Degenerate contour (one or two edges)
1971 :
1972 823 : if (eLnext != e) {
1973 784 : if (safeRemove) {
1974 784 : releaseVertex(_vertexes[eLnext->vertex]);
1975 781 : releaseVertex(_vertexes[eLnext->sym()->vertex]);
1976 : }
1977 783 : releaseEdge(eLnext->getEdge());
1978 782 : if (nedges) {
1979 782 : -- *nedges;
1980 : }
1981 : }
1982 821 : if (safeRemove) {
1983 821 : releaseVertex(_vertexes[e->vertex]);
1984 820 : releaseVertex(_vertexes[e->sym()->vertex]);
1985 : }
1986 820 : releaseEdge(e->getEdge());
1987 819 : if (nedges) {
1988 819 : -- *nedges;
1989 : }
1990 819 : return nullptr; // last edge destroyed
1991 : }
1992 :
1993 : // check and remove tail-like structs
1994 20631886 : if (FloatEq(edge->direction, edgeNext->direction, _mathTolerance)) {
1995 79597 : if (safeRemove) {
1996 3405 : if (eEnd == eLnext) {
1997 : eEnd = eLnext->_leftNext;
1998 : }
1999 :
2000 : HalfEdge *tmp = eLnext;
2001 :
2002 : // we need to recheck e for another degenerate cases
2003 3405 : if (e == eEnd) {
2004 279 : eEnd = e = e->getLeftLoopPrev();
2005 : } else {
2006 3126 : e = e->getLeftLoopPrev();
2007 : }
2008 :
2009 : if (safeRemove) {
2010 3405 : auto vertex = _vertexes[tmp->sym()->vertex];
2011 3403 : auto merge = _vertexes[tmp->vertex];
2012 :
2013 3404 : vertex->_edge = removeEdge(tmp);
2014 3401 : releaseVertex(merge);
2015 : } else {
2016 : auto vertex = _vertexes[tmp->sym()->vertex];
2017 : vertex->_edge = removeEdge(tmp);
2018 : }
2019 :
2020 3402 : if (nedges) {
2021 3402 : -- *nedges;
2022 : }
2023 76192 : } else if (eLnext->_leftNext->_leftNext == e) {
2024 : return nullptr;
2025 : }
2026 : }
2027 20631833 : e = e->_leftNext;
2028 20631833 : } while (e && e != eEnd);
2029 :
2030 : return eEnd;
2031 : }
2032 :
2033 541174 : bool Tesselator::Data::processEdgeOverlap(Vertex *org, HalfEdge *e1, HalfEdge *e2) {
2034 541174 : if (std::find(_protectedEdges.begin(), _protectedEdges.end(), e1) != _protectedEdges.end()) {
2035 : return false;
2036 : }
2037 :
2038 280457 : if (std::find(_protectedEdges.begin(), _protectedEdges.end(), e2) != _protectedEdges.end()) {
2039 : return false;
2040 : }
2041 :
2042 :
2043 : if constexpr (TessVerbose != VerboseFlag::None) {
2044 : std::cout << "processEdgeOverlap:\n\t" << *e1 << "\n\t" << *e2 << "\n";
2045 : }
2046 :
2047 280429 : if (e1->goesLeft()) {
2048 10723 : if (!VertLeq(e2->getDstVec(), e1->getDstVec())) {
2049 75 : std::swap(e1, e2); // split e2
2050 : }
2051 : } else {
2052 269709 : if (!VertLeq(e1->getDstVec(), e2->getDstVec())) {
2053 279 : std::swap(e1, e2); // split e2
2054 : }
2055 : }
2056 :
2057 : Vertex *vMerge;
2058 560863 : if (!VertEq(e1->getDstVec(), e2->getDstVec(), _mathTolerance)) {
2059 385 : vMerge = splitEdge(e2, e1->getDstVec());
2060 : } else {
2061 280046 : vMerge = _vertexes[e2->sym()->vertex];
2062 : }
2063 :
2064 : if constexpr (TessVerbose != VerboseFlag::None) {
2065 : std::cout << "Overlap: " << *e2 << "\n";
2066 : }
2067 :
2068 280425 : auto vOrgIdx = e1->sym()->vertex;
2069 280427 : auto vOrg = _vertexes[vOrgIdx];
2070 :
2071 280424 : _protectedEdges.emplace_back(e2->sym());
2072 280422 : _protectedEdges.emplace_back(e1->sym());
2073 :
2074 280425 : if (vOrg != vMerge) {
2075 278913 : if (std::find(_protectedVertexes.begin(), _protectedVertexes.end(), vOrg) != _protectedVertexes.end()) {
2076 : return false;
2077 : }
2078 :
2079 278890 : if (std::find(_protectedVertexes.begin(), _protectedVertexes.end(), vMerge) != _protectedVertexes.end()) {
2080 : return false;
2081 : }
2082 :
2083 278892 : mergeVertexes(vOrg, vMerge);
2084 :
2085 278887 : _protectedEdges.pop_back();
2086 278885 : _protectedEdges.pop_back();
2087 :
2088 278883 : return true;
2089 : }
2090 :
2091 1512 : _protectedEdges.pop_back();
2092 1513 : _protectedEdges.pop_back();
2093 :
2094 : return false;
2095 : }
2096 :
2097 8832940 : bool Tesselator::Data::isDegenerateTriangle(HalfEdge *e) {
2098 8832940 : if (e->_leftNext->_leftNext == e) {
2099 : return true;
2100 : }
2101 :
2102 : auto eEnd = e;
2103 :
2104 : do {
2105 26260887 : auto eLnext = e->_leftNext;
2106 :
2107 26260887 : auto edge = e->getEdge();
2108 26265589 : auto edgeNext = eLnext->getEdge();
2109 :
2110 26268800 : edge->updateInfo();
2111 26246712 : edgeNext->updateInfo();
2112 :
2113 : // check and remove tail-like structs
2114 26242037 : if (FloatEq(edge->direction, edgeNext->direction, _mathTolerance)) {
2115 : return true;
2116 : }
2117 : e = eLnext;
2118 26194248 : } while (e != eEnd);
2119 :
2120 : return false;
2121 : }
2122 :
2123 5703 : bool Tesselator::Data::removeDegenerateEdges(FaceEdge *e, size_t &removed) {
2124 5703 : if (e->_next->_next == e) {
2125 : return true;
2126 : }
2127 :
2128 : auto eEnd = e;
2129 :
2130 : do {
2131 116368 : auto eLnext = e->_next;
2132 :
2133 116368 : while (VertEq(e->_vertex, eLnext->_vertex, _mathTolerance) && e->_next->_next != e) {
2134 : eLnext = e->_next->_next;
2135 :
2136 0 : if (eEnd == e->_next) {
2137 : eEnd = eLnext;
2138 : }
2139 :
2140 0 : e->_next = e->_next->_next;
2141 0 : ++ removed;
2142 : }
2143 :
2144 116380 : if (eLnext->_next == e) {
2145 0 : if (eLnext != e) {
2146 0 : ++ removed;
2147 : }
2148 0 : ++ removed;
2149 0 : return false; // last edge destroyed
2150 : }
2151 :
2152 : // check and remove tail-like structs
2153 116380 : if (FloatEq(e->_direction, eLnext->_direction, _mathTolerance)) {
2154 0 : if (eLnext->_next->_next == e) {
2155 0 : removed += 3;
2156 0 : return false;
2157 : }
2158 : }
2159 : e = eLnext;
2160 116380 : } while (e != eEnd);
2161 :
2162 : return true;
2163 : }
2164 :
2165 5673 : uint32_t Tesselator::Data::followBoundary(FaceEdge *face, HalfEdge *e, uint8_t mark) {
2166 113456 : auto findNext = [&, this] (HalfEdge *eNext) {
2167 113444 : if (eNext->_originNext->_originNext == eNext) {
2168 : // simple vertex
2169 : return eNext;
2170 : } else {
2171 : // find next boundary in opposite direction to separate subboundaries
2172 : auto prev = eNext->_originNext;
2173 12 : while (isWindingInside(_winding, prev->_realWinding) && prev != eNext) {
2174 8 : prev = prev->_originNext;
2175 : }
2176 4 : if (prev != eNext) {
2177 0 : splitVertex(eNext, prev);
2178 : }
2179 4 : return prev;
2180 : }
2181 : return eNext;
2182 5673 : };
2183 :
2184 : uint32_t nsegments = 0;
2185 : // assume left loop is outside
2186 119123 : while (e->_mark != mark) {
2187 113409 : auto target = e->_leftNext;
2188 113409 : auto eNext = findNext(target);
2189 :
2190 113624 : if (!face) {
2191 5674 : face = allocFaceEdge();
2192 5667 : _boundaries.emplace_back(face);
2193 5667 : face->_next = face;
2194 : } else {
2195 107950 : auto tmp = allocFaceEdge();
2196 107585 : tmp->_next = face->_next;
2197 107585 : face->_next = tmp;
2198 107585 : face = tmp;
2199 : }
2200 :
2201 113252 : ++ nsegments;
2202 113252 : face->_vertex = _vertexes[e->vertex];
2203 113354 : face->_displaced = face->_origin = e->origin;
2204 113354 : face->_direction = e->getEdge()->direction;
2205 :
2206 113450 : if (target != eNext) {
2207 0 : face->_splitVertex = true;
2208 : } else if (face->_vertex->_uniqueIdx >= _nvertexes) {
2209 :
2210 : }
2211 :
2212 113450 : e->_mark = mark;
2213 : e = eNext;
2214 : }
2215 5714 : return nsegments;
2216 : }
2217 :
2218 0 : void Tesselator::Data::splitVertex(HalfEdge *first, HalfEdge *last) {
2219 : // create new vertex for first->orgNext -> last
2220 0 : auto org = _vertexes[first->vertex];
2221 0 : auto vertex = allocVertex();
2222 :
2223 0 : auto front = first->_originNext;
2224 0 : auto back = last->_originNext;
2225 :
2226 0 : first->getLeftLoopPrev()->_leftNext = last;
2227 0 : first->_originNext = back;
2228 :
2229 0 : last->getLeftLoopPrev()->_leftNext = first;
2230 0 : last->_originNext = front;
2231 :
2232 0 : org->_edge = front;
2233 0 : vertex->_edge = first;
2234 0 : vertex->_origin = front->origin;
2235 :
2236 : auto e = first;
2237 : do {
2238 0 : e->vertex = vertex->_uniqueIdx;
2239 0 : e = e->_originNext;
2240 0 : } while (e != first);
2241 :
2242 0 : if (org->_exportIdx != maxOf<uint32_t>()) {
2243 0 : vertex->_exportIdx = uint32_t(_exportVertexes.size());
2244 0 : _exportVertexes.emplace_back(vertex);
2245 : }
2246 0 : }
2247 :
2248 115187 : void Tesselator::Data::displaceBoundary(FaceEdge *edge) {
2249 : auto &v0 = edge->_origin;
2250 115187 : auto &v1 = edge->_next->_origin;
2251 115187 : auto &v2 = edge->_next->_next->_origin;
2252 :
2253 : // use optimized combined direction/normal func
2254 115187 : Vec4 result;
2255 115187 : getVertexNormal(&v0.x, &v1.x, &v2.x, &result.x);
2256 :
2257 115457 : if (std::isnan(result.y) || result.y > 4.0f) {
2258 420 : edge->_next->_value = 1.0f - 4.0f / result.y;
2259 420 : result.y = 4.0f;
2260 : }
2261 :
2262 115296 : float offsetValue = _antialiasValue;
2263 : bool shouldRelocate = false;
2264 115296 : switch (_relocateRule) {
2265 650 : case RelocateRule::Never: offsetValue += _antialiasValue * 0.5f; break;
2266 1600 : case RelocateRule::Always:
2267 : case RelocateRule::Monotonize:
2268 1600 : shouldRelocate = true; break;
2269 113046 : case RelocateRule::Auto:
2270 113046 : if (edge->_next->_splitVertex) {
2271 : shouldRelocate = true;
2272 : } else {
2273 113089 : offsetValue += _antialiasValue * 0.5f;
2274 : }
2275 : break;
2276 : }
2277 :
2278 115296 : const float mod = copysign(result.y * offsetValue, result.x);
2279 :
2280 115296 : edge->_next->_displaced = Vec2(v1.x + result.z * mod, v1.y + result.w * mod);
2281 :
2282 116101 : if (shouldRelocate) {
2283 1600 : if (edge->_next->_vertex) {
2284 1600 : edge->_next->_vertex->relocate(Vec2(v1.x - result.z * mod, v1.y - result.w * mod));
2285 1600 : SPASSERT(!std::isnan(edge->_next->_vertex->_origin.x) && !std::isnan(edge->_next->_vertex->_origin.y),
2286 : "Tess: displaced vertex is NaN");
2287 : }
2288 : }
2289 116101 : }
2290 :
2291 : }
|