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