KiCad PCB EDA Suite
Loading...
Searching...
No Matches
polygon_triangulation.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 *
23 * Based on Uniform Plane Subdivision algorithm from Lamot, Marko, and Borut Žalik.
24 * "A fast polygon triangulation algorithm based on uniform plane subdivision."
25 * Computers & graphics 27, no. 2 (2003): 239-253.
26 *
27 * Code derived from:
28 * K-3D which is Copyright (c) 2005-2006, Romain Behar, GPL-2, license above
29 * earcut which is Copyright (c) 2016, Mapbox, ISC
30 *
31 * ISC License:
32 * Permission to use, copy, modify, and/or distribute this software for any purpose
33 * with or without fee is hereby granted, provided that the above copyright notice
34 * and this permission notice appear in all copies.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
37 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
38 * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
39 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
40 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
41 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
42 * THIS SOFTWARE.
43 *
44 */
45
46#ifndef __POLYGON_TRIANGULATION_H
47#define __POLYGON_TRIANGULATION_H
48
49#include <algorithm>
50#include <deque>
51#include <cmath>
52
53#include <advanced_config.h>
56#include <geometry/vertex_set.h>
57#include <math/box2.h>
58#include <math/vector2d.h>
59
60#include <wx/log.h>
61
62// ADVANCED_CFG::GetCfg() cannot be used on msys2/mingw builds (link failure)
63// So we use the ADVANCED_CFG default values
64#if defined( __MINGW32__ )
65 #define TRIANGULATESIMPLIFICATIONLEVEL 50
66 #define TRIANGULATEMINIMUMAREA 1000
67#else
68 #define TRIANGULATESIMPLIFICATIONLEVEL ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel
69 #define TRIANGULATEMINIMUMAREA ADVANCED_CFG::GetCfg().m_TriangulateMinimumArea
70#endif
71
72#define TRIANGULATE_TRACE "triangulate"
73
75{
76public:
79 m_vertices_original_size( 0 ), m_result( aResult )
80 {};
81
84 {
85 m_bbox = aPoly.BBox();
87
88 if( !m_bbox.GetWidth() || !m_bbox.GetHeight() )
89 return true;
90
94 VERTEX* firstVertex = createList( aPoly );
95
96 for( const VECTOR2I& pt : aPoly.CPoints() )
97 m_result.AddVertex( pt );
98
99 if( !firstVertex || firstVertex->prev == firstVertex->next )
100 return true;
101
102 wxLogTrace( TRIANGULATE_TRACE, "Created list with %f area", firstVertex->area() );
103
105 firstVertex->updateList();
106
111 if( aHintData && aHintData->Vertices().size() == m_vertices.size() )
112 {
113 m_result.SetTriangles( aHintData->Triangles() );
114 return true;
115 }
116 else
117 {
118 auto retval = earcutList( firstVertex );
119
120 if( !retval )
121 {
122 wxLogTrace( TRIANGULATE_TRACE, "Tesselation failed, logging remaining vertices" );
123 logRemaining();
124 }
125
126 m_vertices.clear();
127 return retval;
128 }
129 }
130
131private:
132
137 {
138 std::set<VERTEX*> seen;
139 wxLog::EnableLogging();
140 for( VERTEX& p : m_vertices )
141 {
142 if( !p.next || p.next == &p || seen.find( &p ) != seen.end() )
143 continue;
144
145 logVertices( &p, &seen );
146 }
147 }
148
149 void logVertices( VERTEX* aStart, std::set<VERTEX*>* aSeen )
150 {
151 if( aSeen && aSeen->count( aStart ) )
152 return;
153
154 if( aSeen )
155 aSeen->insert( aStart );
156
157 int count = 1;
158 VERTEX* p = aStart->next;
159 wxString msg = wxString::Format( "Vertices: %d,%d,", static_cast<int>( aStart->x ),
160 static_cast<int>( aStart->y ) );
161
162 do
163 {
164 msg += wxString::Format( "%d,%d,", static_cast<int>( p->x ), static_cast<int>( p->y ) );
165
166 if( aSeen )
167 aSeen->insert( p );
168
169 p = p->next;
170 count++;
171 } while( p != aStart );
172
173 if( count < 3 ) // Don't log anything that only has 2 or fewer points
174 return;
175
176 msg.RemoveLast();
177 wxLogTrace( TRIANGULATE_TRACE, msg );
178 }
179
185 {
186 if( !aStart || aStart->next == aStart->prev )
187 return aStart;
188
189 VERTEX* p = aStart;
190 VERTEX* next = p->next;
191 VERTEX* retval = aStart;
192 int count = 0;
193
194 double sq_dist = TRIANGULATESIMPLIFICATIONLEVEL;
195 sq_dist *= sq_dist;
196
197 do
198 {
199 VECTOR2D diff = VECTOR2D( next->x - p->x, next->y - p->y );
200
201 if( diff.SquaredEuclideanNorm() < sq_dist )
202 {
203 if( next == aStart )
204 {
205 retval = p;
206 aStart->remove();
207 count++;
208 break;
209 }
210
211 next = next->next;
212 p->next->remove();
213 count++;
214 retval = p;
215 }
216 else
217 {
218 p = next;
219 next = next->next;
220 }
221 } while( p != aStart && next && p );
222
223 wxLogTrace( TRIANGULATE_TRACE, "Removed %d points in simplifyList", count );
224
225 if( count )
226 return retval;
227
228 return nullptr;
229 }
230
231
240 {
241 VERTEX* retval = nullptr;
242 size_t count = 0;
243
244 if( ( retval = simplifyList( aStart ) ) )
245 aStart = retval;
246
247 wxASSERT( aStart->next && aStart->prev );
248
249 VERTEX* p = aStart->next;
250
251 while( p != aStart && p->next && p->prev )
252 {
253 // We make a dummy triangle that is actually part of the existing line segment
254 // and measure its area. This will not be exactly zero due to floating point
255 // errors. We then look for areas that are less than 4 times the area of the
256 // dummy triangle. For small triangles, this is a small number
257 VERTEX tmp( 0, 0.5 * ( p->prev->x + p->next->x ), 0.5 * ( p->prev->y + p->next->y ), this );
258 double null_area = 4.0 * std::abs( area( p->prev, &tmp, p->next ) );
259
260 if( *p == *( p->next ) || std::abs( area( p->prev, p, p->next ) ) <= null_area )
261 {
262 // This is a spike, remove it, leaving only one point
263 if( *( p->next ) == *( p->prev ) )
264 p->next->remove();
265
266 p = p->prev;
267 p->next->remove();
268 retval = p;
269 ++count;
270
271 if( p == p->next )
272 break;
273
274 // aStart was removed above, so we need to reset it
275 if( !aStart->next )
276 aStart = p->prev;
277
278 continue;
279 }
280
281 p = p->next;
282 };
283
285 if( !p->next || p->next == p || p->next == p->prev )
286 return p;
287
288 // We needed an end point above that wouldn't be removed, so
289 // here we do the final check for this as a Steiner point
290 VERTEX tmp( 0, 0.5 * ( p->prev->x + p->next->x ),
291 0.5 * ( p->prev->y + p->next->y ), this );
292 double null_area = 4.0 * std::abs( area( p->prev, &tmp, p->next ) );
293
294 if( std::abs( area( p->prev, p, p->next ) ) <= null_area )
295 {
296 retval = p->next;
297 p->remove();
298 ++count;
299 }
300
301 wxLogTrace( TRIANGULATE_TRACE, "Removed %zu NULL triangles", count );
302
303 return retval;
304 }
305
319 bool earcutList( VERTEX* aPoint, int pass = 0 )
320 {
321 wxLogTrace( TRIANGULATE_TRACE, "earcutList starting at %p for pass %d", aPoint, pass );
322
323 if( !aPoint )
324 return true;
325
326 VERTEX* stop = aPoint;
327 VERTEX* prev;
328 VERTEX* next;
329 int internal_pass = 1;
330
331 while( aPoint->prev != aPoint->next )
332 {
333 prev = aPoint->prev;
334 next = aPoint->next;
335
336 if( aPoint->isEar() )
337 {
338 // Tiny ears cannot be seen on the screen
339 if( !isTooSmall( aPoint ) )
340 {
341 m_result.AddTriangle( prev->i, aPoint->i, next->i );
342 }
343 else
344 {
345 wxLogTrace( TRIANGULATE_TRACE, "Ignoring tiny ear with area %f",
346 area( prev, aPoint, next ) );
347 }
348
349 aPoint->remove();
350
351 // Skip one vertex as the triangle will account for the prev node
352 aPoint = next->next;
353 stop = next->next;
354
355 continue;
356 }
357
358 VERTEX* nextNext = next->next;
359
360 if( *prev != *nextNext && intersects( prev, aPoint, next, nextNext ) &&
361 locallyInside( prev, nextNext ) &&
362 locallyInside( nextNext, prev ) )
363 {
364 wxLogTrace( TRIANGULATE_TRACE,
365 "Local intersection detected. Merging minor triangle with area %f",
366 area( prev, aPoint, nextNext ) );
367 m_result.AddTriangle( prev->i, aPoint->i, nextNext->i );
368
369 // remove two nodes involved
370 next->remove();
371 aPoint->remove();
372
373 aPoint = nextNext;
374 stop = nextNext;
375
376 continue;
377 }
378
379 aPoint = next;
380
381 /*
382 * We've searched the entire polygon for available ears and there are still
383 * un-sliced nodes remaining.
384 */
385 if( aPoint == stop && aPoint->prev != aPoint->next )
386 {
387 VERTEX* newPoint;
388
389 // Removing null triangles will remove steiner points as well as colinear points
390 // that are three in a row. Because our next step is to subdivide the polygon,
391 // we need to allow it to add the subdivided points first. This is why we only
392 // run the RemoveNullTriangles function after the first pass.
393 if( ( internal_pass == 2 ) && ( newPoint = removeNullTriangles( aPoint ) ) )
394 {
395 // There are no remaining triangles in the list
396 if( newPoint->next == newPoint->prev )
397 break;
398
399 aPoint = newPoint;
400 stop = newPoint;
401 continue;
402 }
403
404 ++internal_pass;
405
406 // This will subdivide the polygon 2 times. The first pass will add enough points
407 // such that each edge is less than the average edge length. If this doesn't work
408 // The next pass will remove the null triangles (above) and subdivide the polygon
409 // again, this time adding one point to each long edge (and thereby changing the locations)
410 if( internal_pass < 4 )
411 {
412 wxLogTrace( TRIANGULATE_TRACE, "Subdividing polygon" );
413 subdividePolygon( aPoint, internal_pass );
414 continue;
415 }
416
417 // If we don't have any NULL triangles left, cut the polygon in two and try again
418 wxLogTrace( TRIANGULATE_TRACE, "Splitting polygon" );
419
420 if( !splitPolygon( aPoint ) )
421 return false;
422
423 break;
424 }
425 }
426
427 // Check to see if we are left with only three points in the polygon
428 if( aPoint->next && aPoint->prev == aPoint->next->next )
429 {
430 // Three concave points will never be able to be triangulated because they were
431 // created by an intersecting polygon, so just drop them.
432 if( area( aPoint->prev, aPoint, aPoint->next ) >= 0 )
433 return true;
434 }
435
436 /*
437 * At this point, our polygon should be fully tessellated.
438 */
439 if( aPoint->prev != aPoint->next )
440 return std::abs( aPoint->area() ) > TRIANGULATEMINIMUMAREA;
441
442 return true;
443 }
444
445
450 bool isTooSmall( const VERTEX* aPoint ) const
451 {
452 double min_area = TRIANGULATEMINIMUMAREA;
453 double prev_sq_len = ( aPoint->prev->x - aPoint->x ) * ( aPoint->prev->x - aPoint->x ) +
454 ( aPoint->prev->y - aPoint->y ) * ( aPoint->prev->y - aPoint->y );
455 double next_sq_len = ( aPoint->next->x - aPoint->x ) * ( aPoint->next->x - aPoint->x ) +
456 ( aPoint->next->y - aPoint->y ) * ( aPoint->next->y - aPoint->y );
457 double opp_sq_len = ( aPoint->next->x - aPoint->prev->x ) * ( aPoint->next->x - aPoint->prev->x ) +
458 ( aPoint->next->y - aPoint->prev->y ) * ( aPoint->next->y - aPoint->prev->y );
459
460 return ( prev_sq_len < min_area || next_sq_len < min_area || opp_sq_len < min_area );
461 }
462
466 void subdividePolygon( VERTEX* aStart, int pass = 0 )
467 {
468 VERTEX* p = aStart;
469
470 struct VertexComparator {
471 bool operator()(const std::pair<VERTEX*,double>& a, const std::pair<VERTEX*,double>& b) const {
472 return a.second > b.second;
473 }
474 };
475
476 std::set<std::pair<VERTEX*,double>, VertexComparator> longest;
477 double avg = 0.0;
478
479 do
480 {
481 double len = ( p->x - p->next->x ) * ( p->x - p->next->x ) +
482 ( p->y - p->next->y ) * ( p->y - p->next->y );
483 longest.emplace( p, len );
484
485 avg += len;
486 p = p->next;
487 } while (p != aStart);
488
489 avg /= longest.size();
490 wxLogTrace( TRIANGULATE_TRACE, "Average length: %f", avg );
491
492 for( auto it = longest.begin(); it != longest.end() && it->second > avg; ++it )
493 {
494 wxLogTrace( TRIANGULATE_TRACE, "Subdividing edge with length %f", it->second );
495 VERTEX* a = it->first;
496 VERTEX* b = a->next;
497 VERTEX* last = a;
498
499 // We adjust the number of divisions based on the pass in order to progressively
500 // subdivide the polygon when triangulation fails
501 int divisions = avg / it->second + 2 + pass;
502 double step = 1.0 / divisions;
503
504 for( int i = 1; i < divisions; i++ )
505 {
506 double x = a->x * ( 1.0 - step * i ) + b->x * ( step * i );
507 double y = a->y * ( 1.0 - step * i ) + b->y * ( step * i );
508 last = insertTriVertex( VECTOR2I( x, y ), last );
509 }
510 }
511
512 // update z-order of the vertices
513 aStart->updateList();
514 }
515
522 bool splitPolygon( VERTEX* start )
523 {
524 VERTEX* origPoly = start;
525
526 // If we have fewer than 4 points, we cannot split the polygon
527 if( !start || !start->next || start->next == start->prev
528 || start->next->next == start->prev )
529 {
530 return true;
531 }
532
533 // Our first attempts to split the polygon will be at overlapping points.
534 // These are natural split points and we only need to switch the loop directions
535 // to generate two new loops. Since they are overlapping, we are do not
536 // need to create a new segment to disconnect the two loops.
537 do
538 {
539 std::vector<VERTEX*> overlapPoints;
540 VERTEX* z_pt = origPoly;
541
542 while ( z_pt->prevZ && *z_pt->prevZ == *origPoly )
543 z_pt = z_pt->prevZ;
544
545 overlapPoints.push_back( z_pt );
546
547 while( z_pt->nextZ && *z_pt->nextZ == *origPoly )
548 {
549 z_pt = z_pt->nextZ;
550 overlapPoints.push_back( z_pt );
551 }
552
553 if( overlapPoints.size() != 2 || overlapPoints[0]->next == overlapPoints[1]
554 || overlapPoints[0]->prev == overlapPoints[1] )
555 {
556 origPoly = origPoly->next;
557 continue;
558 }
559
560 if( overlapPoints[0]->area( overlapPoints[1] ) < 0 || overlapPoints[1]->area( overlapPoints[0] ) < 0 )
561 {
562 wxLogTrace( TRIANGULATE_TRACE, "Split generated a hole, skipping" );
563 origPoly = origPoly->next;
564 continue;
565 }
566
567 wxLogTrace( TRIANGULATE_TRACE, "Splitting at overlap point %f, %f", overlapPoints[0]->x, overlapPoints[0]->y );
568 std::swap( overlapPoints[0]->next, overlapPoints[1]->next );
569 overlapPoints[0]->next->prev = overlapPoints[0];
570 overlapPoints[1]->next->prev = overlapPoints[1];
571
572 overlapPoints[0]->updateList();
573 overlapPoints[1]->updateList();
574 logVertices( overlapPoints[0], nullptr );
575 logVertices( overlapPoints[1], nullptr );
576 bool retval = earcutList( overlapPoints[0] ) && earcutList( overlapPoints[1] );
577
578 wxLogTrace( TRIANGULATE_TRACE, "%s at first overlap split", retval ? "Success" : "Failed" );
579 return retval;
580
581
582 } while ( origPoly != start );
583
584 // If we've made it through the split algorithm and we still haven't found a
585 // set of overlapping points, we need to create a new segment to split the polygon
586 // into two separate polygons. We do this by finding the two vertices that form
587 // a valid line (does not cross the existing polygon)
588 do
589 {
590 VERTEX* marker = origPoly->next->next;
591
592 while( marker != origPoly->prev )
593 {
594 // Find a diagonal line that is wholly enclosed by the polygon interior
595 if( origPoly->next && origPoly->i != marker->i && goodSplit( origPoly, marker ) )
596 {
597 VERTEX* newPoly = origPoly->split( marker );
598
599 origPoly->updateList();
600 newPoly->updateList();
601
602 bool retval = earcutList( origPoly ) && earcutList( newPoly );
603
604 wxLogTrace( TRIANGULATE_TRACE, "%s at split", retval ? "Success" : "Failed" );
605 return retval;
606 }
607
608 marker = marker->next;
609 }
610
611 origPoly = origPoly->next;
612 } while( origPoly != start );
613
614 wxLogTrace( TRIANGULATE_TRACE, "Could not find a valid split point" );
615 return false;
616 }
617
627 bool goodSplit( const VERTEX* a, const VERTEX* b ) const
628 {
629 bool a_on_edge = ( a->nextZ && *a == *a->nextZ ) || ( a->prevZ && *a == *a->prevZ );
630 bool b_on_edge = ( b->nextZ && *b == *b->nextZ ) || ( b->prevZ && *b == *b->prevZ );
631 bool no_intersect = a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon( a, b );
632 bool local_split = locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b );
633 bool same_dir = area( a->prev, a, b->prev ) != 0.0 || area( a, b->prev, b ) != 0.0;
634 bool has_len = ( *a == *b ) && area( a->prev, a, a->next ) > 0 && area( b->prev, b, b->next ) > 0;
635 bool pos_area = a->area( b ) > 0 && b->area( a ) > 0;
636
637 return no_intersect && local_split && ( same_dir || has_len ) && !a_on_edge && !b_on_edge && pos_area;
638
639 }
640
641
642 constexpr int sign( double aVal ) const
643 {
644 return ( aVal > 0 ) - ( aVal < 0 );
645 }
646
650 constexpr bool overlapping( const VERTEX* p, const VERTEX* q, const VERTEX* r ) const
651 {
652 return q->x <= std::max( p->x, r->x ) &&
653 q->x >= std::min( p->x, r->x ) &&
654 q->y <= std::max( p->y, r->y ) &&
655 q->y >= std::min( p->y, r->y );
656 }
657
663 bool intersects( const VERTEX* p1, const VERTEX* q1, const VERTEX* p2, const VERTEX* q2 ) const
664 {
665 int sign1 = sign( area( p1, q1, p2 ) );
666 int sign2 = sign( area( p1, q1, q2 ) );
667 int sign3 = sign( area( p2, q2, p1 ) );
668 int sign4 = sign( area( p2, q2, q1 ) );
669
670 if( sign1 != sign2 && sign3 != sign4 )
671 return true;
672
673 if( sign1 == 0 && overlapping( p1, p2, q1 ) )
674 return true;
675
676 if( sign2 == 0 && overlapping( p1, q2, q1 ) )
677 return true;
678
679 if( sign3 == 0 && overlapping( p2, p1, q2 ) )
680 return true;
681
682 if( sign4 == 0 && overlapping( p2, q1, q2 ) )
683 return true;
684
685
686 return false;
687 }
688
695 bool intersectsPolygon( const VERTEX* a, const VERTEX* b ) const
696 {
697 for( size_t ii = 0; ii < m_vertices_original_size; ii++ )
698 {
699 const VERTEX* p = &m_vertices[ii];
700 const VERTEX* q = &m_vertices[( ii + 1 ) % m_vertices_original_size];
701
702 if( p->i == a->i || p->i == b->i || q->i == a->i || q->i == b->i )
703 continue;
704
705 if( intersects( p, q, a, b ) )
706 return true;
707 }
708
709 return false;
710 }
711
719 {
720 m_result.AddVertex( pt );
721 return insertVertex( m_result.GetVertexCount() - 1, pt, nullptr );
722 }
723
724private:
727};
728
729#endif //__POLYGON_TRIANGULATION_H
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr size_type GetHeight() const
Definition: box2.h:215
SHAPE_POLY_SET::TRIANGULATED_POLYGON & m_result
bool intersects(const VERTEX *p1, const VERTEX *q1, const VERTEX *p2, const VERTEX *q2) const
Check for intersection between two segments, end points included.
bool splitPolygon(VERTEX *start)
If we cannot find an ear to slice in the current polygon list, we use this to split the polygon into ...
constexpr int sign(double aVal) const
void logVertices(VERTEX *aStart, std::set< VERTEX * > *aSeen)
VERTEX * insertTriVertex(const VECTOR2I &pt, VERTEX *last)
Create an entry in the vertices lookup and optionally inserts the newly created vertex into an existi...
bool goodSplit(const VERTEX *a, const VERTEX *b) const
Check if a segment joining two vertices lies fully inside the polygon.
VERTEX * simplifyList(VERTEX *aStart)
Simplify the line chain by removing points that are too close to each other.
POLYGON_TRIANGULATION(SHAPE_POLY_SET::TRIANGULATED_POLYGON &aResult)
constexpr bool overlapping(const VERTEX *p, const VERTEX *q, const VERTEX *r) const
If p, q, and r are collinear and r lies between p and q, then return true.
void logRemaining()
Outputs a list of vertices that have not yet been triangulated.
VERTEX * removeNullTriangles(VERTEX *aStart)
Iterate through the list to remove NULL triangles if they exist.
bool intersectsPolygon(const VERTEX *a, const VERTEX *b) const
Check whether the segment from vertex a -> vertex b crosses any of the segments of the polygon of whi...
bool isTooSmall(const VERTEX *aPoint) const
Check whether a given vertex is too small to matter.
bool earcutList(VERTEX *aPoint, int pass=0)
Walk through a circular linked list starting at aPoint.
void subdividePolygon(VERTEX *aStart, int pass=0)
Inserts a new vertex halfway between each existing pair of vertices.
bool TesselatePolygon(const SHAPE_LINE_CHAIN &aPoly, SHAPE_POLY_SET::TRIANGULATED_POLYGON *aHintData)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const std::vector< VECTOR2I > & CPoints() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void AddVertex(const VECTOR2I &aP)
const std::deque< VECTOR2I > & Vertices() const
const std::deque< TRI > & Triangles() const
void AddTriangle(int a, int b, int c)
void SetTriangles(const std::deque< TRI > &aTriangles)
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
Definition: vector2d.h:307
std::deque< VERTEX > m_vertices
Definition: vertex_set.h:343
bool middleInside(const VERTEX *a, const VERTEX *b) const
Check if the middle of the segment from a to b is inside the polygon.
Definition: vertex_set.cpp:183
VERTEX * createList(const SHAPE_LINE_CHAIN &points, VERTEX *aTail=nullptr, void *aUserData=nullptr)
Create a list of vertices from a line chain.
Definition: vertex_set.cpp:27
bool locallyInside(const VERTEX *a, const VERTEX *b) const
Check whether the segment from vertex a -> vertex b is inside the polygon around the immediate area o...
Definition: vertex_set.cpp:171
BOX2I m_bbox
Definition: vertex_set.h:342
double area(const VERTEX *p, const VERTEX *q, const VERTEX *r) const
Return the twice the signed area of the triangle formed by vertices p, q, and r.
Definition: vertex_set.cpp:104
VERTEX * insertVertex(int aIndex, const VECTOR2I &pt, VERTEX *last, void *aUserData=nullptr)
Insert a vertex into the vertex set.
Definition: vertex_set.cpp:208
VERTEX * split(VERTEX *b)
Split the referenced polygon between the reference point and vertex b, assuming they are in the same ...
Definition: vertex_set.cpp:230
const double x
Definition: vertex_set.h:235
VERTEX * next
Definition: vertex_set.h:241
VERTEX * prevZ
Definition: vertex_set.h:247
void updateList()
After inserting or changing nodes, this function should be called to remove duplicate vertices and en...
Definition: vertex_set.h:121
VERTEX * nextZ
Definition: vertex_set.h:248
VERTEX * prev
Definition: vertex_set.h:240
const int i
Definition: vertex_set.h:234
void remove()
Remove the node from the linked list and z-ordered linked list.
Definition: vertex_set.h:84
double area(const VERTEX *aEnd=nullptr) const
Returns the signed area of the polygon connected to the current vertex, optionally ending at a specif...
Definition: vertex_set.h:202
bool isEar(bool aMatchUserData=false) const
Check whether the given vertex is in the middle of an ear.
Definition: vertex_set.cpp:262
const double y
Definition: vertex_set.h:236
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
#define TRIANGULATE_TRACE
#define TRIANGULATEMINIMUMAREA
#define TRIANGULATESIMPLIFICATIONLEVEL
CITER next(CITER it)
Definition: ptree.cpp:124
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694