KiCad PCB EDA Suite
shape_line_chain.cpp
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) 2013-2017 CERN
5  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <algorithm>
26 
28 #include <geometry/shape_circle.h>
29 #include <trigo.h>
30 #include "clipper.hpp"
31 
32 
33 ClipperLib::Path SHAPE_LINE_CHAIN::convertToClipper( bool aRequiredOrientation ) const
34 {
35  ClipperLib::Path c_path;
36 
37  for( int i = 0; i < PointCount(); i++ )
38  {
39  const VECTOR2I& vertex = CPoint( i );
40  c_path.push_back( ClipperLib::IntPoint( vertex.x, vertex.y ) );
41  }
42 
43  if( Orientation( c_path ) != aRequiredOrientation )
44  ReversePath( c_path );
45 
46  return c_path;
47 }
48 
49 
50 bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const
51 {
52  // fixme: ugly!
53  SEG s( aP, aP );
54  return this->Collide( s, aClearance );
55 }
56 
57 
58 void SHAPE_LINE_CHAIN::Rotate( double aAngle, const VECTOR2I& aCenter )
59 {
60  for( std::vector<VECTOR2I>::iterator i = m_points.begin(); i != m_points.end(); ++i )
61  {
62  (*i) -= aCenter;
63  (*i) = (*i).Rotate( aAngle );
64  (*i) += aCenter;
65  }
66 }
67 
68 
69 bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const
70 {
71  BOX2I box_a( aSeg.A, aSeg.B - aSeg.A );
72  BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
73 
74  for( int i = 0; i < SegmentCount(); i++ )
75  {
76  const SEG& s = CSegment( i );
77  BOX2I box_b( s.A, s.B - s.A );
78 
79  BOX2I::ecoord_type d = box_a.SquaredDistance( box_b );
80 
81  if( d < dist_sq )
82  {
83  if( s.Collide( aSeg, aClearance ) )
84  return true;
85  }
86  }
87 
88  return false;
89 }
90 
91 
93 {
94  SHAPE_LINE_CHAIN a( *this );
95 
96  reverse( a.m_points.begin(), a.m_points.end() );
97  a.m_closed = m_closed;
98 
99  return a;
100 }
101 
102 
104 {
105  int l = 0;
106 
107  for( int i = 0; i < SegmentCount(); i++ )
108  l += CSegment( i ).Length();
109 
110  return l;
111 }
112 
113 
114 void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP )
115 {
116  if( aEndIndex < 0 )
117  aEndIndex += PointCount();
118 
119  if( aStartIndex < 0 )
120  aStartIndex += PointCount();
121 
122  if( aStartIndex == aEndIndex )
123  m_points[aStartIndex] = aP;
124  else
125  {
126  m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 );
127  m_points[aStartIndex] = aP;
128  }
129 }
130 
131 
132 void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine )
133 {
134  if( aEndIndex < 0 )
135  aEndIndex += PointCount();
136 
137  if( aStartIndex < 0 )
138  aStartIndex += PointCount();
139 
140  m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
141  m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() );
142 }
143 
144 
145 void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
146 {
147  if( aEndIndex < 0 )
148  aEndIndex += PointCount();
149 
150  if( aStartIndex < 0 )
151  aStartIndex += PointCount();
152 
153  m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
154 }
155 
156 
157 int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP, bool aOutlineOnly ) const
158 {
159  int d = INT_MAX;
160 
161  if( IsClosed() && PointInside( aP ) && !aOutlineOnly )
162  return 0;
163 
164  for( int s = 0; s < SegmentCount(); s++ )
165  d = std::min( d, CSegment( s ).Distance( aP ) );
166 
167  return d;
168 }
169 
170 
172 {
173  int ii = -1;
174  int min_dist = 2;
175 
176  int found_index = Find( aP );
177 
178  for( int s = 0; s < SegmentCount(); s++ )
179  {
180  const SEG seg = CSegment( s );
181  int dist = seg.Distance( aP );
182 
183  // make sure we are not producing a 'slightly concave' primitive. This might happen
184  // if aP lies very close to one of already existing points.
185  if( dist < min_dist && seg.A != aP && seg.B != aP )
186  {
187  min_dist = dist;
188  if( found_index < 0 )
189  ii = s;
190  else if( s < found_index )
191  ii = s;
192  }
193  }
194 
195  if( ii < 0 )
196  ii = found_index;
197 
198  if( ii >= 0 )
199  {
200  m_points.insert( m_points.begin() + ii + 1, aP );
201 
202  return ii + 1;
203  }
204 
205  return -1;
206 }
207 
208 
209 int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const
210 {
211  for( int s = 0; s < PointCount(); s++ )
212  if( CPoint( s ) == aP )
213  return s;
214 
215  return -1;
216 }
217 
218 
220 {
221  for( int s = 0; s < SegmentCount(); s++ )
222  if( CSegment( s ).Distance( aP ) <= 1 )
223  return s;
224 
225  return -1;
226 }
227 
228 
229 const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const
230 {
231  SHAPE_LINE_CHAIN rv;
232 
233  if( aEndIndex < 0 )
234  aEndIndex += PointCount();
235 
236  if( aStartIndex < 0 )
237  aStartIndex += PointCount();
238 
239  for( int i = aStartIndex; i <= aEndIndex; i++ )
240  rv.Append( m_points[i] );
241 
242  return rv;
243 }
244 
245 
247 {
249  m_origin( aOrigin ) {};
250 
253  {
254  return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
255  }
256 
258 };
259 
260 
261 int SHAPE_LINE_CHAIN::Intersect( const SEG& aSeg, INTERSECTIONS& aIp ) const
262 {
263  for( int s = 0; s < SegmentCount(); s++ )
264  {
265  OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg );
266 
267  if( p )
268  {
269  INTERSECTION is;
270  is.our = CSegment( s );
271  is.their = aSeg;
272  is.p = *p;
273  aIp.push_back( is );
274  }
275  }
276 
277  compareOriginDistance comp( aSeg.A );
278  sort( aIp.begin(), aIp.end(), comp );
279 
280  return aIp.size();
281 }
282 
283 
285 {
286  BOX2I bb_other = aChain.BBox();
287 
288  for( int s1 = 0; s1 < SegmentCount(); s1++ )
289  {
290  const SEG& a = CSegment( s1 );
291  const BOX2I bb_cur( a.A, a.B - a.A );
292 
293  if( !bb_other.Intersects( bb_cur ) )
294  continue;
295 
296  for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
297  {
298  const SEG& b = aChain.CSegment( s2 );
299  INTERSECTION is;
300 
301  if( a.Collinear( b ) )
302  {
303  is.our = a;
304  is.their = b;
305 
306  if( a.Contains( b.A ) ) { is.p = b.A; aIp.push_back( is ); }
307  if( a.Contains( b.B ) ) { is.p = b.B; aIp.push_back( is ); }
308  if( b.Contains( a.A ) ) { is.p = a.A; aIp.push_back( is ); }
309  if( b.Contains( a.B ) ) { is.p = a.B; aIp.push_back( is ); }
310  }
311  else
312  {
313  OPT_VECTOR2I p = a.Intersect( b );
314 
315  if( p )
316  {
317  is.p = *p;
318  is.our = a;
319  is.their = b;
320  aIp.push_back( is );
321  }
322  }
323  }
324  }
325 
326  return aIp.size();
327 }
328 
329 
331 {
332  int sum = 0;
333 
334  for( int i = 0; i < SegmentCount(); i++ )
335  {
336  const SEG seg = CSegment( i );
337  int d = seg.Distance( aP );
338 
339  if( d <= 1 )
340  {
341  sum += ( aP - seg.A ).EuclideanNorm();
342  return sum;
343  }
344  else
345  sum += seg.Length();
346  }
347 
348  return -1;
349 }
350 
351 
352 bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUseBBoxCache ) const
353 {
354  /*
355  * Don't check the bounding box unless it's cached. Building it is about the same speed as
356  * the rigorous test below and so just slows things down by doing potentially two tests.
357  */
358  if( aUseBBoxCache && !m_bbox.Contains( aPt ) )
359  return false;
360 
361  if( !m_closed || PointCount() < 3 )
362  return false;
363 
364  bool inside = false;
365 
377  const std::vector<VECTOR2I>& points = CPoints();
378  int pointCount = points.size();
379 
380  for( int i = 0; i < pointCount; )
381  {
382  const auto p1 = points[ i++ ];
383  const auto p2 = points[ i == pointCount ? 0 : i ];
384  const auto diff = p2 - p1;
385 
386  if( diff.y != 0 )
387  {
388  const int d = rescale( diff.x, ( aPt.y - p1.y ), diff.y );
389 
390  if( ( ( p1.y > aPt.y ) != ( p2.y > aPt.y ) ) && ( aPt.x - p1.x < d ) )
391  inside = !inside;
392  }
393  }
394 
395  // If accuracy is 0 then we need to make sure the point isn't actually on the edge.
396  // If accuracy is 1 then we don't really care whether or not the point is *exactly* on the
397  // edge, so we skip edge processing for performance.
398  // If accuracy is > 1, then we use "OnEdge(accuracy-1)" as a proxy for "Inside(accuracy)".
399  if( aAccuracy == 0 )
400  return inside && !PointOnEdge( aPt );
401  else if( aAccuracy == 1 )
402  return inside;
403  else
404  return inside || PointOnEdge( aPt, aAccuracy - 1 );
405 }
406 
407 
408 bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aPt, int aAccuracy ) const
409 {
410  return EdgeContainingPoint( aPt, aAccuracy ) >= 0;
411 }
412 
413 int SHAPE_LINE_CHAIN::EdgeContainingPoint( const VECTOR2I& aPt, int aAccuracy ) const
414 {
415  if( !PointCount() )
416  return -1;
417 
418  else if( PointCount() == 1 )
419  {
420  VECTOR2I dist = m_points[0] - aPt;
421  return ( hypot( dist.x, dist.y ) <= aAccuracy + 1 ) ? 0 : -1;
422  }
423 
424  for( int i = 0; i < SegmentCount(); i++ )
425  {
426  const SEG s = CSegment( i );
427 
428  if( s.A == aPt || s.B == aPt )
429  return i;
430 
431  if( s.Distance( aPt ) <= aAccuracy + 1 )
432  return i;
433  }
434 
435  return -1;
436 }
437 
438 
439 bool SHAPE_LINE_CHAIN::CheckClearance( const VECTOR2I& aP, const int aDist) const
440 {
441  if( !PointCount() )
442  return false;
443 
444  else if( PointCount() == 1 )
445  return m_points[0] == aP;
446 
447  for( int i = 0; i < SegmentCount(); i++ )
448  {
449  const SEG s = CSegment( i );
450 
451  if( s.A == aP || s.B == aP )
452  return true;
453 
454  if( s.Distance( aP ) <= aDist )
455  return true;
456  }
457 
458  return false;
459 }
460 
461 
463 {
464  for( int s1 = 0; s1 < SegmentCount(); s1++ )
465  {
466  for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ )
467  {
468  const VECTOR2I s2a = CSegment( s2 ).A, s2b = CSegment( s2 ).B;
469 
470  if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) )
471  {
472  INTERSECTION is;
473  is.our = CSegment( s1 );
474  is.their = CSegment( s2 );
475  is.p = s2a;
476  return is;
477  }
478  else if( CSegment( s1 ).Contains( s2b ) &&
479  // for closed polylines, the ending point of the
480  // last segment == starting point of the first segment
481  // this is a normal case, not self intersecting case
482  !( IsClosed() && s1 == 0 && s2 == SegmentCount()-1 ) )
483  {
484  INTERSECTION is;
485  is.our = CSegment( s1 );
486  is.their = CSegment( s2 );
487  is.p = s2b;
488  return is;
489  }
490  else
491  {
492  OPT_VECTOR2I p = CSegment( s1 ).Intersect( CSegment( s2 ), true );
493 
494  if( p )
495  {
496  INTERSECTION is;
497  is.our = CSegment( s1 );
498  is.their = CSegment( s2 );
499  is.p = *p;
500  return is;
501  }
502  }
503  }
504  }
505 
507 }
508 
509 
511 {
512  std::vector<VECTOR2I> pts_unique;
513 
514  if( PointCount() < 2 )
515  {
516  return *this;
517  }
518  else if( PointCount() == 2 )
519  {
520  if( m_points[0] == m_points[1] )
521  m_points.pop_back();
522 
523  return *this;
524  }
525 
526  int i = 0;
527  int np = PointCount();
528 
529  // stage 1: eliminate duplicate vertices
530  while( i < np )
531  {
532  int j = i + 1;
533 
534  while( j < np && CPoint( i ) == CPoint( j ) )
535  j++;
536 
537  pts_unique.push_back( CPoint( i ) );
538  i = j;
539  }
540 
541  m_points.clear();
542  np = pts_unique.size();
543 
544  i = 0;
545 
546  // stage 1: eliminate collinear segments
547  while( i < np - 2 )
548  {
549  const VECTOR2I p0 = pts_unique[i];
550  const VECTOR2I p1 = pts_unique[i + 1];
551  int n = i;
552 
553  while( n < np - 2 && SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 )
554  n++;
555 
556  m_points.push_back( p0 );
557 
558  if( n > i )
559  i = n;
560 
561  if( n == np )
562  {
563  m_points.push_back( pts_unique[n - 1] );
564  return *this;
565  }
566 
567  i++;
568  }
569 
570  if( np > 1 )
571  m_points.push_back( pts_unique[np - 2] );
572 
573  m_points.push_back( pts_unique[np - 1] );
574 
575  return *this;
576 }
577 
578 
580 {
581  int min_d = INT_MAX;
582  int nearest = 0;
583 
584  for( int i = 0; i < SegmentCount(); i++ )
585  {
586  int d = CSegment( i ).Distance( aP );
587 
588  if( d < min_d )
589  {
590  min_d = d;
591  nearest = i;
592  }
593  }
594 
595  return CSegment( nearest ).NearestPoint( aP );
596 }
597 
598 
599 const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const SEG& aSeg, int& dist ) const
600 {
601  int nearest = 0;
602 
603  dist = INT_MAX;
604  for( int i = 0; i < PointCount(); i++ )
605  {
606  int d = aSeg.LineDistance( CPoint( i ) );
607 
608  if( d < dist )
609  {
610  dist = d;
611  nearest = i;
612  }
613  }
614 
615  return CPoint( nearest );
616 }
617 
618 
619 const std::string SHAPE_LINE_CHAIN::Format() const
620 {
621  std::stringstream ss;
622 
623  ss << m_points.size() << " " << ( m_closed ? 1 : 0 ) << " ";
624 
625  for( int i = 0; i < PointCount(); i++ )
626  ss << m_points[i].x << " " << m_points[i].y << " "; // Format() << " ";
627 
628  return ss.str();
629 }
630 
631 
633 {
634  SHAPE_LINE_CHAIN a(*this), b( aOther );
635  a.Simplify();
636  b.Simplify();
637 
638  if( a.m_points.size() != b.m_points.size() )
639  return false;
640 
641  for( int i = 0; i < a.PointCount(); i++)
642  if( a.CPoint( i ) != b.CPoint( i ) )
643  return false;
644  return true;
645 }
646 
647 
649 {
651  return Intersect( aChain, dummy ) != 0;
652 }
653 
654 
656 {
657  return new SHAPE_LINE_CHAIN( *this );
658 }
659 
660 bool SHAPE_LINE_CHAIN::Parse( std::stringstream& aStream )
661 {
662  int n_pts;
663 
664  m_points.clear();
665  aStream >> n_pts;
666 
667  // Rough sanity check, just make sure the loop bounds aren't absolutely outlandish
668  if( n_pts < 0 || n_pts > int( aStream.str().size() ) )
669  return false;
670 
671  aStream >> m_closed;
672 
673  for( int i = 0; i < n_pts; i++ )
674  {
675  int x, y;
676  aStream >> x;
677  aStream >> y;
678  m_points.push_back( VECTOR2I( x, y ) );
679  }
680 
681  return true;
682 }
683 
684 
685 const VECTOR2I SHAPE_LINE_CHAIN::PointAlong( int aPathLength ) const
686 {
687  int total = 0;
688 
689  if( aPathLength == 0 )
690  return CPoint( 0 );
691 
692  for( int i = 0; i < SegmentCount(); i++ )
693  {
694  const SEG& s = CSegment( i );
695  int l = s.Length();
696 
697  if( total + l >= aPathLength )
698  {
699  VECTOR2I d( s.B - s.A );
700  return s.A + d.Resize( aPathLength - total );
701  }
702 
703  total += l;
704  }
705 
706  return CPoint( -1 );
707 }
708 
710 {
711  // see https://www.mathopenref.com/coordpolygonarea2.html
712 
713  if( !m_closed )
714  return 0.0;
715 
716  double area = 0.0;
717  int size = m_points.size();
718 
719  for( int i = 0, j = size - 1; i < size; ++i )
720  {
721  area += ( (double) m_points[j].x + m_points[i].x ) * ( (double) m_points[j].y - m_points[i].y );
722  j = i;
723  }
724 
725  return -area * 0.5;
726 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:123
int Length() const
Function Length()
Definition: seg.h:296
int Find(const VECTOR2I &aP) const
Function Find()
BOX2I m_bbox
cached bounding box
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Function NearestPoint()
int FindSegment(const VECTOR2I &aP) const
Function FindSegment()
int Split(const VECTOR2I &aP)
Function Split()
int EdgeContainingPoint(const VECTOR2I &aP, int aAccuracy=0) const
Function EdgeContainingPoint()
int Distance(const SEG &aSeg) const
Function Distance()
Definition: seg.h:199
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Function Intersect()
std::vector< INTERSECTION > INTERSECTIONS
static const int dist[10][10]
Definition: ar_matrix.cpp:320
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Function PointOnEdge()
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Function Intersect()
Definition: seg.cpp:132
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex=-1) const
Function Slice()
VECTOR2I p
point of intersection between our and their.
ecoord_type SquaredDistance(const Vec &aP) const
Definition: box2.h:440
int Distance(const VECTOR2I &aP, bool aOutlineOnly=false) const
Function Distance()
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Function LineDistance()
Definition: seg.h:357
const SHAPE_LINE_CHAIN Reverse() const
Function Reverse()
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
int PointCount() const
Function PointCount()
const OPT< INTERSECTION > SelfIntersecting() const
Function SelfIntersecting()
bool Collide(const VECTOR2I &aP, int aClearance=0) const override
Function Collide()
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
int PathLength(const VECTOR2I &aP) const
Function PathLength()
ClipperLib::Path convertToClipper(bool aRequiredOrientation) const
Creates a new Clipper path from the SHAPE_LINE_CHAIN in a given orientation.
bool Parse(std::stringstream &aStream) override
SHAPE_LINE_CHAIN & Simplify()
Function Simplify()
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:234
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
bool m_closed
is the line chain closed?
SHAPE_LINE_CHAIN()
Constructor Initializes an empty line chain.
void Rotate(double aAngle, const VECTOR2I &aCenter)
Function Rotate rotates all vertices by a given angle.
SEG their
segment belonging from the aOther argument of Intersect()
const BOX2I BBox(int aClearance=0) const override
Function BBox()
const std::vector< VECTOR2I > & CPoints() const
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:34
VECTOR2I ::extended_type ecoord_type
Definition: box2.h:49
std::vector< VECTOR2I > m_points
array of vertices
bool CheckClearance(const VECTOR2I &aP, const int aDist) const
Function CheckClearance()
bool Contains(const Vec &aPoint) const
Function Contains.
Definition: box2.h:149
bool Contains(const VECTOR2I &aP) const
Definition: seg.cpp:188
bool Intersects(const SHAPE_LINE_CHAIN &aChain) const
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Function NearestPoint()
Definition: seg.h:374
Class SHAPE.
Definition: shape.h:58
void Remove(int aStartIndex, int aEndIndex)
Function Remove()
const std::string Format() const override
int SegmentCount() const
Function SegmentCount()
double Area() const
bool Collinear(const SEG &aSeg) const
Function Collinear()
Definition: seg.h:235
Definition: seg.h:36
VECTOR2< T > Resize(T aNewLength) const
Function Resize returns a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:385
VECTOR2< T > Rotate(double aAngle) const
Function Rotate rotates the vector by a given angle.
Definition: vector2d.h:370
const SEG CSegment(int aIndex) const
Function CSegment()
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
T rescale(T aNumerator, T aValue, T aDenominator)
Function rescale()
Class SHAPE_LINE_CHAIN.
size_t i
Definition: json11.cpp:597
VECTOR2I A
Definition: seg.h:44
int Length() const
Function Length()
static void reverse(privcurve_t *curve)
Definition: trace.cpp:1025
boost::optional< T > OPT
Definition: optional.h:7
bool operator()(const SHAPE_LINE_CHAIN::INTERSECTION &aA, const SHAPE_LINE_CHAIN::INTERSECTION &aB)
bool Collide(const SEG &aSeg, int aClearance) const
Definition: seg.cpp:167
SHAPE * Clone() const override
Function Clone()
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const
Function PointInside()
bool IsClosed() const
Function IsClosed()
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Function Replace()
SEG our
segment belonging from the (this) argument of Intersect()
const VECTOR2I PointAlong(int aPathLength) const
bool CompareGeometry(const SHAPE_LINE_CHAIN &aOther) const
compareOriginDistance(VECTOR2I &aOrigin)
#define min(a, b)
Definition: auxiliary.h:85
VECTOR2I B
Definition: seg.h:45