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 (C) 2018 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>
54#include <clipper.hpp>
57#include <geometry/vertex_set.h>
58#include <math/box2.h>
59#include <math/vector2d.h>
60
61#include <wx/log.h>
62
63// ADVANCED_CFG::GetCfg() cannot be used on msys2/mingw builds (link failure)
64// So we use the ADVANCED_CFG default values
65#if defined( __MINGW32__ )
66 #define TRIANGULATESIMPLIFICATIONLEVEL 50
67 #define TRIANGULATEMINIMUMAREA 1000
68#else
69 #define TRIANGULATESIMPLIFICATIONLEVEL ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel
70 #define TRIANGULATEMINIMUMAREA ADVANCED_CFG::GetCfg().m_TriangulateMinimumArea
71#endif
72
73#define TRIANGULATE_TRACE "triangulate"
74
76{
77public:
80 m_vertices_original_size( 0 ), m_result( aResult )
81 {};
82
85 {
86 m_bbox = aPoly.BBox();
88
89 if( !m_bbox.GetWidth() || !m_bbox.GetHeight() )
90 return true;
91
95 VERTEX* firstVertex = createList( aPoly );
96
97 for( const VECTOR2I& pt : aPoly.CPoints() )
98 m_result.AddVertex( pt );
99
100 if( !firstVertex || firstVertex->prev == firstVertex->next )
101 return true;
102
103 wxLogTrace( TRIANGULATE_TRACE, "Created list with %f area", firstVertex->area() );
104
106 firstVertex->updateList();
107
112 if( aHintData && aHintData->Vertices().size() == m_vertices.size() )
113 {
114 m_result.SetTriangles( aHintData->Triangles() );
115 return true;
116 }
117 else
118 {
119 auto retval = earcutList( firstVertex );
120
121 if( !retval )
122 {
123 wxLogTrace( TRIANGULATE_TRACE, "Tesselation failed, logging remaining vertices" );
124 logRemaining();
125 }
126
127 m_vertices.clear();
128 return retval;
129 }
130 }
131
132private:
133
138 {
139 std::set<VERTEX*> seen;
140 wxLog::EnableLogging();
141 for( VERTEX& p : m_vertices )
142 {
143 if( !p.next || p.next == &p || seen.find( &p ) != seen.end() )
144 continue;
145
146 logVertices( &p, &seen );
147 }
148 }
149
150 void logVertices( VERTEX* aStart, std::set<VERTEX*>* aSeen )
151 {
152 if( aSeen && aSeen->count( aStart ) )
153 return;
154
155 if( aSeen )
156 aSeen->insert( aStart );
157
158 int count = 1;
159 VERTEX* p = aStart->next;
160 wxString msg = wxString::Format( "Vertices: %d,%d,", static_cast<int>( aStart->x ),
161 static_cast<int>( aStart->y ) );
162
163 do
164 {
165 msg += wxString::Format( "%d,%d,", static_cast<int>( p->x ), static_cast<int>( p->y ) );
166
167 if( aSeen )
168 aSeen->insert( p );
169
170 p = p->next;
171 count++;
172 } while( p != aStart );
173
174 if( count < 3 ) // Don't log anything that only has 2 or fewer points
175 return;
176
177 msg.RemoveLast();
178 wxLogTrace( TRIANGULATE_TRACE, msg );
179 }
180
186 {
187 if( !aStart || aStart->next == aStart->prev )
188 return aStart;
189
190 VERTEX* p = aStart;
191 VERTEX* next = p->next;
192 VERTEX* retval = aStart;
193 int count = 0;
194
195 double sq_dist = TRIANGULATESIMPLIFICATIONLEVEL;
196 sq_dist *= sq_dist;
197
198 do
199 {
200 VECTOR2D diff = VECTOR2D( next->x - p->x, next->y - p->y );
201
202 if( diff.SquaredEuclideanNorm() < sq_dist )
203 {
204 if( next == aStart )
205 {
206 retval = p;
207 aStart->remove();
208 count++;
209 break;
210 }
211
212 next = next->next;
213 p->next->remove();
214 count++;
215 retval = p;
216 }
217 else
218 {
219 p = next;
220 next = next->next;
221 }
222 } while( p != aStart && next && p );
223
224 wxLogTrace( TRIANGULATE_TRACE, "Removed %d points in simplifyList", count );
225
226 if( count )
227 return retval;
228
229 return nullptr;
230 }
231
232
241 {
242 VERTEX* retval = nullptr;
243 size_t count = 0;
244
245 if( ( retval = simplifyList( aStart ) ) )
246 aStart = retval;
247
248 wxASSERT( aStart->next && aStart->prev );
249
250 VERTEX* p = aStart->next;
251
252 while( p != aStart && p->next && p->prev )
253 {
254 // We make a dummy triangle that is actually part of the existing line segment
255 // and measure its area. This will not be exactly zero due to floating point
256 // errors. We then look for areas that are less than 4 times the area of the
257 // dummy triangle. For small triangles, this is a small number
258 VERTEX tmp( 0, 0.5 * ( p->prev->x + p->next->x ), 0.5 * ( p->prev->y + p->next->y ), this );
259 double null_area = 4.0 * std::abs( area( p->prev, &tmp, p->next ) );
260
261 if( *p == *( p->next ) || std::abs( area( p->prev, p, p->next ) ) <= null_area )
262 {
263 // This is a spike, remove it, leaving only one point
264 if( *( p->next ) == *( p->prev ) )
265 p->next->remove();
266
267 p = p->prev;
268 p->next->remove();
269 retval = p;
270 ++count;
271
272 if( p == p->next )
273 break;
274
275 // aStart was removed above, so we need to reset it
276 if( !aStart->next )
277 aStart = p->prev;
278
279 continue;
280 }
281
282 p = p->next;
283 };
284
286 if( !p->next || p->next == p || p->next == p->prev )
287 return p;
288
289 // We needed an end point above that wouldn't be removed, so
290 // here we do the final check for this as a Steiner point
291 VERTEX tmp( 0, 0.5 * ( p->prev->x + p->next->x ),
292 0.5 * ( p->prev->y + p->next->y ), this );
293 double null_area = 4.0 * std::abs( area( p->prev, &tmp, p->next ) );
294
295 if( std::abs( area( p->prev, p, p->next ) ) <= null_area )
296 {
297 retval = p->next;
298 p->remove();
299 ++count;
300 }
301
302 wxLogTrace( TRIANGULATE_TRACE, "Removed %zu NULL triangles", count );
303
304 return retval;
305 }
306
320 bool earcutList( VERTEX* aPoint, int pass = 0 )
321 {
322 wxLogTrace( TRIANGULATE_TRACE, "earcutList starting at %p for pass %d", aPoint, pass );
323
324 if( !aPoint )
325 return true;
326
327 VERTEX* stop = aPoint;
328 VERTEX* prev;
329 VERTEX* next;
330 int internal_pass = 1;
331
332 while( aPoint->prev != aPoint->next )
333 {
334 prev = aPoint->prev;
335 next = aPoint->next;
336
337 if( aPoint->isEar() )
338 {
339 // Tiny ears cannot be seen on the screen
340 if( !isTooSmall( aPoint ) )
341 {
342 m_result.AddTriangle( prev->i, aPoint->i, next->i );
343 }
344 else
345 {
346 wxLogTrace( TRIANGULATE_TRACE, "Ignoring tiny ear with area %f",
347 area( prev, aPoint, next ) );
348 }
349
350 aPoint->remove();
351
352 // Skip one vertex as the triangle will account for the prev node
353 aPoint = next->next;
354 stop = next->next;
355
356 continue;
357 }
358
359 VERTEX* nextNext = next->next;
360
361 if( *prev != *nextNext && intersects( prev, aPoint, next, nextNext ) &&
362 locallyInside( prev, nextNext ) &&
363 locallyInside( nextNext, prev ) )
364 {
365 wxLogTrace( TRIANGULATE_TRACE,
366 "Local intersection detected. Merging minor triangle with area %f",
367 area( prev, aPoint, nextNext ) );
368 m_result.AddTriangle( prev->i, aPoint->i, nextNext->i );
369
370 // remove two nodes involved
371 next->remove();
372 aPoint->remove();
373
374 aPoint = nextNext;
375 stop = nextNext;
376
377 continue;
378 }
379
380 aPoint = next;
381
382 /*
383 * We've searched the entire polygon for available ears and there are still
384 * un-sliced nodes remaining.
385 */
386 if( aPoint == stop && aPoint->prev != aPoint->next )
387 {
388 VERTEX* newPoint;
389
390 // Removing null triangles will remove steiner points as well as colinear points
391 // that are three in a row. Because our next step is to subdivide the polygon,
392 // we need to allow it to add the subdivided points first. This is why we only
393 // run the RemoveNullTriangles function after the first pass.
394 if( ( internal_pass == 2 ) && ( newPoint = removeNullTriangles( aPoint ) ) )
395 {
396 // There are no remaining triangles in the list
397 if( newPoint->next == newPoint->prev )
398 break;
399
400 aPoint = newPoint;
401 stop = newPoint;
402 continue;
403 }
404
405 ++internal_pass;
406
407 // This will subdivide the polygon 2 times. The first pass will add enough points
408 // such that each edge is less than the average edge length. If this doesn't work
409 // The next pass will remove the null triangles (above) and subdivide the polygon
410 // again, this time adding one point to each long edge (and thereby changing the locations)
411 if( internal_pass < 4 )
412 {
413 wxLogTrace( TRIANGULATE_TRACE, "Subdividing polygon" );
414 subdividePolygon( aPoint, internal_pass );
415 continue;
416 }
417
418 // If we don't have any NULL triangles left, cut the polygon in two and try again
419 wxLogTrace( TRIANGULATE_TRACE, "Splitting polygon" );
420
421 if( !splitPolygon( aPoint ) )
422 return false;
423
424 break;
425 }
426 }
427
428 // Check to see if we are left with only three points in the polygon
429 if( aPoint->next && aPoint->prev == aPoint->next->next )
430 {
431 // Three concave points will never be able to be triangulated because they were
432 // created by an intersecting polygon, so just drop them.
433 if( area( aPoint->prev, aPoint, aPoint->next ) >= 0 )
434 return true;
435 }
436
437 /*
438 * At this point, our polygon should be fully tessellated.
439 */
440 if( aPoint->prev != aPoint->next )
441 return std::abs( aPoint->area() ) > TRIANGULATEMINIMUMAREA;
442
443 return true;
444 }
445
446
451 bool isTooSmall( const VERTEX* aPoint ) const
452 {
453 double min_area = TRIANGULATEMINIMUMAREA;
454 double prev_sq_len = ( aPoint->prev->x - aPoint->x ) * ( aPoint->prev->x - aPoint->x ) +
455 ( aPoint->prev->y - aPoint->y ) * ( aPoint->prev->y - aPoint->y );
456 double next_sq_len = ( aPoint->next->x - aPoint->x ) * ( aPoint->next->x - aPoint->x ) +
457 ( aPoint->next->y - aPoint->y ) * ( aPoint->next->y - aPoint->y );
458 double opp_sq_len = ( aPoint->next->x - aPoint->prev->x ) * ( aPoint->next->x - aPoint->prev->x ) +
459 ( aPoint->next->y - aPoint->prev->y ) * ( aPoint->next->y - aPoint->prev->y );
460
461 return ( prev_sq_len < min_area || next_sq_len < min_area || opp_sq_len < min_area );
462 }
463
467 void subdividePolygon( VERTEX* aStart, int pass = 0 )
468 {
469 VERTEX* p = aStart;
470
471 struct VertexComparator {
472 bool operator()(const std::pair<VERTEX*,double>& a, const std::pair<VERTEX*,double>& b) const {
473 return a.second > b.second;
474 }
475 };
476
477 std::set<std::pair<VERTEX*,double>, VertexComparator> longest;
478 double avg = 0.0;
479
480 do
481 {
482 double len = ( p->x - p->next->x ) * ( p->x - p->next->x ) +
483 ( p->y - p->next->y ) * ( p->y - p->next->y );
484 longest.emplace( p, len );
485
486 avg += len;
487 p = p->next;
488 } while (p != aStart);
489
490 avg /= longest.size();
491 wxLogTrace( TRIANGULATE_TRACE, "Average length: %f", avg );
492
493 for( auto it = longest.begin(); it != longest.end() && it->second > avg; ++it )
494 {
495 wxLogTrace( TRIANGULATE_TRACE, "Subdividing edge with length %f", it->second );
496 VERTEX* a = it->first;
497 VERTEX* b = a->next;
498 VERTEX* last = a;
499
500 // We adjust the number of divisions based on the pass in order to progressively
501 // subdivide the polygon when triangulation fails
502 int divisions = avg / it->second + 2 + pass;
503 double step = 1.0 / divisions;
504
505 for( int i = 1; i < divisions; i++ )
506 {
507 double x = a->x * ( 1.0 - step * i ) + b->x * ( step * i );
508 double y = a->y * ( 1.0 - step * i ) + b->y * ( step * i );
509 last = insertTriVertex( VECTOR2I( x, y ), last );
510 }
511 }
512
513 // update z-order of the vertices
514 aStart->updateList();
515 }
516
523 bool splitPolygon( VERTEX* start )
524 {
525 VERTEX* origPoly = start;
526
527 // If we have fewer than 4 points, we cannot split the polygon
528 if( !start || !start->next || start->next == start->prev
529 || start->next->next == start->prev )
530 {
531 return true;
532 }
533
534 // Our first attempts to split the polygon will be at overlapping points.
535 // These are natural split points and we only need to switch the loop directions
536 // to generate two new loops. Since they are overlapping, we are do not
537 // need to create a new segment to disconnect the two loops.
538 do
539 {
540 std::vector<VERTEX*> overlapPoints;
541 VERTEX* z_pt = origPoly;
542
543 while ( z_pt->prevZ && *z_pt->prevZ == *origPoly )
544 z_pt = z_pt->prevZ;
545
546 overlapPoints.push_back( z_pt );
547
548 while( z_pt->nextZ && *z_pt->nextZ == *origPoly )
549 {
550 z_pt = z_pt->nextZ;
551 overlapPoints.push_back( z_pt );
552 }
553
554 if( overlapPoints.size() != 2 || overlapPoints[0]->next == overlapPoints[1]
555 || overlapPoints[0]->prev == overlapPoints[1] )
556 {
557 origPoly = origPoly->next;
558 continue;
559 }
560
561 if( overlapPoints[0]->area( overlapPoints[1] ) < 0 || overlapPoints[1]->area( overlapPoints[0] ) < 0 )
562 {
563 wxLogTrace( TRIANGULATE_TRACE, "Split generated a hole, skipping" );
564 origPoly = origPoly->next;
565 continue;
566 }
567
568 wxLogTrace( TRIANGULATE_TRACE, "Splitting at overlap point %f, %f", overlapPoints[0]->x, overlapPoints[0]->y );
569 std::swap( overlapPoints[0]->next, overlapPoints[1]->next );
570 overlapPoints[0]->next->prev = overlapPoints[0];
571 overlapPoints[1]->next->prev = overlapPoints[1];
572
573 overlapPoints[0]->updateList();
574 overlapPoints[1]->updateList();
575 logVertices( overlapPoints[0], nullptr );
576 logVertices( overlapPoints[1], nullptr );
577 bool retval = earcutList( overlapPoints[0] ) && earcutList( overlapPoints[1] );
578
579 wxLogTrace( TRIANGULATE_TRACE, "%s at first overlap split", retval ? "Success" : "Failed" );
580 return retval;
581
582
583 } while ( origPoly != start );
584
585 // If we've made it through the split algorithm and we still haven't found a
586 // set of overlapping points, we need to create a new segment to split the polygon
587 // into two separate polygons. We do this by finding the two vertices that form
588 // a valid line (does not cross the existing polygon)
589 do
590 {
591 VERTEX* marker = origPoly->next->next;
592
593 while( marker != origPoly->prev )
594 {
595 // Find a diagonal line that is wholly enclosed by the polygon interior
596 if( origPoly->next && origPoly->i != marker->i && goodSplit( origPoly, marker ) )
597 {
598 VERTEX* newPoly = origPoly->split( marker );
599
600 origPoly->updateList();
601 newPoly->updateList();
602
603 bool retval = earcutList( origPoly ) && earcutList( newPoly );
604
605 wxLogTrace( TRIANGULATE_TRACE, "%s at split", retval ? "Success" : "Failed" );
606 return retval;
607 }
608
609 marker = marker->next;
610 }
611
612 origPoly = origPoly->next;
613 } while( origPoly != start );
614
615 wxLogTrace( TRIANGULATE_TRACE, "Could not find a valid split point" );
616 return false;
617 }
618
628 bool goodSplit( const VERTEX* a, const VERTEX* b ) const
629 {
630 bool a_on_edge = ( a->nextZ && *a == *a->nextZ ) || ( a->prevZ && *a == *a->prevZ );
631 bool b_on_edge = ( b->nextZ && *b == *b->nextZ ) || ( b->prevZ && *b == *b->prevZ );
632 bool no_intersect = a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon( a, b );
633 bool local_split = locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b );
634 bool same_dir = area( a->prev, a, b->prev ) != 0.0 || area( a, b->prev, b ) != 0.0;
635 bool has_len = ( *a == *b ) && area( a->prev, a, a->next ) > 0 && area( b->prev, b, b->next ) > 0;
636 bool pos_area = a->area( b ) > 0 && b->area( a ) > 0;
637
638 return no_intersect && local_split && ( same_dir || has_len ) && !a_on_edge && !b_on_edge && pos_area;
639
640 }
641
642
643 constexpr int sign( double aVal ) const
644 {
645 return ( aVal > 0 ) - ( aVal < 0 );
646 }
647
651 constexpr bool overlapping( const VERTEX* p, const VERTEX* q, const VERTEX* r ) const
652 {
653 return q->x <= std::max( p->x, r->x ) &&
654 q->x >= std::min( p->x, r->x ) &&
655 q->y <= std::max( p->y, r->y ) &&
656 q->y >= std::min( p->y, r->y );
657 }
658
664 bool intersects( const VERTEX* p1, const VERTEX* q1, const VERTEX* p2, const VERTEX* q2 ) const
665 {
666 int sign1 = sign( area( p1, q1, p2 ) );
667 int sign2 = sign( area( p1, q1, q2 ) );
668 int sign3 = sign( area( p2, q2, p1 ) );
669 int sign4 = sign( area( p2, q2, q1 ) );
670
671 if( sign1 != sign2 && sign3 != sign4 )
672 return true;
673
674 if( sign1 == 0 && overlapping( p1, p2, q1 ) )
675 return true;
676
677 if( sign2 == 0 && overlapping( p1, q2, q1 ) )
678 return true;
679
680 if( sign3 == 0 && overlapping( p2, p1, q2 ) )
681 return true;
682
683 if( sign4 == 0 && overlapping( p2, q1, q2 ) )
684 return true;
685
686
687 return false;
688 }
689
696 bool intersectsPolygon( const VERTEX* a, const VERTEX* b ) const
697 {
698 for( size_t ii = 0; ii < m_vertices_original_size; ii++ )
699 {
700 const VERTEX* p = &m_vertices[ii];
701 const VERTEX* q = &m_vertices[( ii + 1 ) % m_vertices_original_size];
702
703 if( p->i == a->i || p->i == b->i || q->i == a->i || q->i == b->i )
704 continue;
705
706 if( intersects( p, q, a, b ) )
707 return true;
708 }
709
710 return false;
711 }
712
720 {
721 m_result.AddVertex( pt );
722 return insertVertex( m_result.GetVertexCount() - 1, pt, nullptr );
723 }
724
725private:
728};
729
730#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:165
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:9
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:153
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:86
VERTEX * insertVertex(int aIndex, const VECTOR2I &pt, VERTEX *last, void *aUserData=nullptr)
Insert a vertex into the vertex set.
Definition: vertex_set.cpp:190
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:212
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:244
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:126
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690