KiCad PCB EDA Suite
PolyLine.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  * Few parts of this code come from FreePCB, released under the GNU General Public License V2.
5  * (see http://www.freepcb.com/ )
6  *
7  * Copyright (C) 2012-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
8  * Copyright (C) 2012-2015 KiCad Developers, see CHANGELOG.TXT for contributors.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27 
33 //
34 // implementation for kicad, using clipper polygon clipping library
35 // for transformations not handled (at least for Kicad) by boost::polygon
36 //
37 #include <cmath>
38 #include <vector>
39 #include <algorithm>
40 
41 #include <fctsys.h>
42 #include <common.h> // KiROUND
43 
44 #include <PolyLine.h>
45 #include <bezier_curves.h>
47 #include <math_for_graphics.h>
49 
50 
52 {
54  m_hatchPitch = 0;
55  m_layer = F_Cu;
56  m_flags = 0;
57 }
58 
59 CPolyLine::CPolyLine( const CPolyLine& aCPolyLine)
60 {
61  Copy( &aCPolyLine );
62  m_HatchLines = aCPolyLine.m_HatchLines; // vector <> copy
63 }
64 
65 
66 // destructor, removes display elements
67 //
69 {
70  UnHatch();
71 }
72 
73 /* Removes corners which create a null segment edge
74  * (i.e. when 2 successive corners are at the same location)
75  * returns the count of removed corners.
76  */
78 {
79  int removed = 0;
80  unsigned startcountour = 0;
81 
82  for( unsigned icnt = 1; icnt < m_CornersList.GetCornersCount(); icnt ++ )
83  {
84  unsigned last = icnt-1;
85  if( m_CornersList[icnt].end_contour )
86  {
87  last = startcountour;
88  startcountour = icnt+1;
89  }
90 
91  if( ( m_CornersList[last].x == m_CornersList[icnt].x ) &&
92  ( m_CornersList[last].y == m_CornersList[icnt].y ) )
93  {
94  DeleteCorner( icnt );
95  icnt--;
96  removed ++;
97  }
98 
99  if( m_CornersList[icnt].end_contour )
100  {
101  startcountour = icnt+1;
102  icnt++;
103  }
104  }
105 
106  return removed;
107 }
108 
109 
110 /* Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
111  * and removes null segments.
112  * param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
113  * needed by the normalization
114  * return the polygon count (always >= 1, because there is at least one polygon)
115  * There are new polygons only if the polygon count is > 1
116  */
117 int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
118 {
120 
121  // We are expecting only one main outline, but this main outline can have holes
122  // if holes: combine holes and remove them from the main outline.
123  // Note also we are using SHAPE_POLY_SET::PM_STRICTLY_SIMPLE in polygon
124  // calculations, but it is not mandatory. It is used mainly
125  // because there is usually only very few vertices in area outlines
126  SHAPE_POLY_SET::POLYGON& outline = polySet.Polygon( 0 );
127  SHAPE_POLY_SET holesBuffer;
128 
129  // Move holes stored in outline to holesBuffer:
130  // The first SHAPE_LINE_CHAIN is the main outline, others are holes
131  while( outline.size() > 1 )
132  {
133  holesBuffer.AddOutline( outline.back() );
134  outline.pop_back();
135  }
136 
138 
139  // If any hole, substract it to main outline
140  if( holesBuffer.OutlineCount() )
141  {
142  holesBuffer.Simplify( SHAPE_POLY_SET::PM_FAST);
143  polySet.BooleanSubtract( holesBuffer, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
144  }
145 
147 
148  // Note: we can have more than outline, because a self intersecting outline will be
149  // broken to non intersecting polygons, and removing holes can also create a few polygons
150  for( int ii = 0; ii < polySet.OutlineCount(); ii++ )
151  {
152  CPolyLine* polyline = this;
153 
154  if( ii > 0 )
155  {
156  polyline = new CPolyLine;
157  polyline->ImportSettings( this );
158  aNewPolygonList->push_back( polyline );
159  }
160 
161  SHAPE_POLY_SET pnew;
162  pnew.NewOutline();
163  pnew.Polygon( 0 ) = polySet.CPolygon( ii );
164 
165  polyline->m_CornersList = ConvertPolySetToPolyList( pnew );
166  polyline->RemoveNullSegments();
167  }
168 
169  return polySet.OutlineCount();
170 }
171 
177 {
178  SetLayer( aPoly->GetLayer() );
179  SetHatchStyle( aPoly->GetHatchStyle() );
180  SetHatchPitch( aPoly->GetHatchPitch() );
181 }
182 
183 /* initialize a contour
184  * set layer, hatch style, and starting point
185  */
186 void CPolyLine::Start( LAYER_NUM layer, int x, int y, int hatch )
187 {
188  m_layer = layer;
189  SetHatchStyle( (enum HATCH_STYLE) hatch );
190  CPolyPt poly_pt( x, y );
191  poly_pt.end_contour = false;
192 
193  m_CornersList.Append( poly_pt );
194 }
195 
196 
197 // add a corner to unclosed polyline
198 //
199 void CPolyLine::AppendCorner( int x, int y )
200 {
201  UnHatch();
202  CPolyPt poly_pt( x, y );
203  poly_pt.end_contour = false;
204 
205  // add entries for new corner
206  m_CornersList.Append( poly_pt );
207 }
208 
209 // move corner of polyline
210 //
211 void CPolyLine::MoveCorner( int ic, int x, int y )
212 {
213  UnHatch();
214  m_CornersList[ic].x = x;
215  m_CornersList[ic].y = y;
216  Hatch();
217 }
218 
219 
220 // delete corner and adjust arrays
221 //
223 {
224  UnHatch();
225  int icont = GetContour( ic );
226  int iend = GetContourEnd( icont );
227  bool closed = icont < GetContoursCount() - 1 || GetClosed();
228 
229  if( !closed )
230  {
231  // open contour, must be last contour
233  }
234  else
235  {
236  // closed contour
238 
239  if( ic == iend )
240  m_CornersList[ic - 1].end_contour = true;
241  }
242 
243  if( closed && GetContourSize( icont ) < 3 )
244  {
245  // delete the entire contour
246  RemoveContour( icont );
247  }
248 }
249 
250 
251 /******************************************/
252 void CPolyLine::RemoveContour( int icont )
253 /******************************************/
254 
255 
260 {
261  UnHatch();
262  int istart = GetContourStart( icont );
263  int iend = GetContourEnd( icont );
264 
265  int polycount = GetContoursCount();
266 
267  if( icont == 0 && polycount == 1 )
268  {
269  // remove the only contour
270  wxASSERT( 0 );
271  }
272  else
273  {
274  // remove closed contour
275  for( int ic = iend; ic>=istart; ic-- )
276  {
278  }
279  }
280 
281  Hatch();
282 }
283 
284 
285 CPolyLine* CPolyLine::Chamfer( unsigned int aDistance )
286 {
287  // Null segments create serious issues in calculations.
288  // remove them:
290 
291  CPolyLine* newPoly = new CPolyLine;
292 
293  if( !aDistance )
294  {
295  newPoly->Copy( this );
296  return newPoly;
297  }
298 
299  int polycount = GetContoursCount();
300 
301  for( int contour = 0; contour < polycount; contour++ )
302  {
303  unsigned int startIndex = GetContourStart( contour );
304  unsigned int endIndex = GetContourEnd( contour );
305 
306  for( unsigned int index = startIndex; index <= endIndex; index++ )
307  {
308  // Current vertex
309  int x1 = m_CornersList[index].x;
310  int y1 = m_CornersList[index].y;
311  double xa, ya; // Previous vertex
312  double xb, yb; // Next vertex
313 
314  if( index == startIndex )
315  {
316  xa = m_CornersList[endIndex].x - x1;
317  ya = m_CornersList[endIndex].y - y1;
318  }
319  else
320  {
321  xa = m_CornersList[index - 1].x - x1;
322  ya = m_CornersList[index - 1].y - y1;
323  }
324 
325  if( index == endIndex )
326  {
327  xb = m_CornersList[startIndex].x - x1;
328  yb = m_CornersList[startIndex].y - y1;
329  }
330  else
331  {
332  xb = m_CornersList[index + 1].x - x1;
333  yb = m_CornersList[index + 1].y - y1;
334  }
335 
336  double lena = hypot( xa, ya );
337  double lenb = hypot( xb, yb );
338  double distance = aDistance;
339 
340  // Chamfer one half of an edge at most
341  if( 0.5 * lena < distance )
342  distance = 0.5 * lena;
343 
344  if( 0.5 * lenb < distance )
345  distance = 0.5 * lenb;
346 
347  int nx1 = KiROUND( distance * xa / lena );
348  int ny1 = KiROUND( distance * ya / lena );
349 
350  if( index == startIndex )
351  newPoly->Start( GetLayer(), x1 + nx1, y1 + ny1, GetHatchStyle() );
352  else
353  newPoly->AppendCorner( x1 + nx1, y1 + ny1 );
354 
355  int nx2 = KiROUND( distance * xb / lenb );
356  int ny2 = KiROUND( distance * yb / lenb );
357 
358  // Due to rounding errors, repeated corners could be added; this check prevents it
359  if(nx1 != nx2 || ny1 != ny2)
360  newPoly->AppendCorner( x1 + nx2, y1 + ny2 );
361  }
362 
363  newPoly->CloseLastContour();
364  }
365 
366  return newPoly;
367 }
368 
369 
370 CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments )
371 {
372  // Null segments create serious issues in calculations.
373  // remove them:
375 
376  CPolyLine* newPoly = new CPolyLine;
377 
378  if( !aRadius )
379  {
380  newPoly->Copy( this );
381  return newPoly;
382  }
383 
384  int polycount = GetContoursCount();
385 
386  for( int contour = 0; contour < polycount; contour++ )
387  {
388  unsigned int startIndex = GetContourStart( contour );
389  unsigned int endIndex = GetContourEnd( contour );
390 
391  for( unsigned int index = startIndex; index <= endIndex; index++ )
392  {
393  // Current vertex
394  int x1 = m_CornersList[index].x;
395  int y1 = m_CornersList[index].y;
396  double xa, ya; // Previous vertex
397  double xb, yb; // Next vertex
398 
399  if( index == startIndex )
400  {
401  xa = m_CornersList[endIndex].x - x1;
402  ya = m_CornersList[endIndex].y - y1;
403  }
404  else
405  {
406  xa = m_CornersList[index - 1].x - x1;
407  ya = m_CornersList[index - 1].y - y1;
408  }
409 
410  if( index == endIndex )
411  {
412  xb = m_CornersList[startIndex].x - x1;
413  yb = m_CornersList[startIndex].y - y1;
414  }
415  else
416  {
417  xb = m_CornersList[index + 1].x - x1;
418  yb = m_CornersList[index + 1].y - y1;
419  }
420 
421  double lena = hypot( xa, ya );
422  double lenb = hypot( xb, yb );
423  double cosine = ( xa * xb + ya * yb ) / ( lena * lenb );
424 
425  double radius = aRadius;
426  double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 );
427 
428  // Do nothing in case of parallel edges
429  if( std::isinf( denom ) )
430  continue;
431 
432  // Limit rounding distance to one half of an edge
433  if( 0.5 * lena * denom < radius )
434  radius = 0.5 * lena * denom;
435 
436  if( 0.5 * lenb * denom < radius )
437  radius = 0.5 * lenb * denom;
438 
439  // Calculate fillet arc absolute center point (xc, yx)
440  double k = radius / sqrt( .5 * ( 1 - cosine ) );
441  double lenab = sqrt( ( xa / lena + xb / lenb ) * ( xa / lena + xb / lenb ) +
442  ( ya / lena + yb / lenb ) * ( ya / lena + yb / lenb ) );
443  double xc = x1 + k * ( xa / lena + xb / lenb ) / lenab;
444  double yc = y1 + k * ( ya / lena + yb / lenb ) / lenab;
445 
446  // Calculate arc start and end vectors
447  k = radius / sqrt( 2 / ( 1 + cosine ) - 1 );
448  double xs = x1 + k * xa / lena - xc;
449  double ys = y1 + k * ya / lena - yc;
450  double xe = x1 + k * xb / lenb - xc;
451  double ye = y1 + k * yb / lenb - yc;
452 
453  // Cosine of arc angle
454  double argument = ( xs * xe + ys * ye ) / ( radius * radius );
455 
456  if( argument < -1 ) // Just in case...
457  argument = -1;
458  else if( argument > 1 )
459  argument = 1;
460 
461  double arcAngle = acos( argument );
462 
463  // Calculate the number of segments
464  double tempSegments = (double) aSegments * ( arcAngle / ( 2 * M_PI ) );
465 
466  if( tempSegments - (int) tempSegments > 0 )
467  tempSegments++;
468 
469  unsigned int segments = (unsigned int) tempSegments;
470 
471  double deltaAngle = arcAngle / segments;
472  double startAngle = atan2( -ys, xs );
473 
474  // Flip arc for inner corners
475  if( xa * yb - ya * xb <= 0 )
476  deltaAngle *= -1;
477 
478  double nx = xc + xs;
479  double ny = yc + ys;
480 
481  if( index == startIndex )
482  newPoly->Start( GetLayer(), KiROUND( nx ), KiROUND( ny ), GetHatchStyle() );
483  else
484  newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) );
485 
486  // Store the previous added corner to make a sanity check
487  int prevX = KiROUND(nx);
488  int prevY = KiROUND(ny);
489 
490  for( unsigned int j = 0; j < segments; j++ )
491  {
492  nx = xc + cos( startAngle + (j + 1) * deltaAngle ) * radius;
493  ny = yc - sin( startAngle + (j + 1) * deltaAngle ) * radius;
494 
495  // Due to rounding errors, repeated corners could be added; this check prevents it
496  if(KiROUND(nx) != prevX || KiROUND(ny) != prevY)
497  {
498  newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) );
499  prevX = KiROUND(nx);
500  prevY = KiROUND(ny);
501  }
502  }
503  }
504 
505  newPoly->CloseLastContour();
506  }
507 
508  return newPoly;
509 }
510 
511 
512 /******************************************/
514 /******************************************/
515 
516 
521 {
523 }
524 
525 
532 void CPolyLine::InsertCorner( int ic, int x, int y )
533 {
534  UnHatch();
535 
536  if( (unsigned) (ic) >= m_CornersList.GetCornersCount() )
537  {
538  m_CornersList.Append( CPolyPt( x, y ) );
539  }
540  else
541  {
542  m_CornersList.InsertCorner(ic, CPolyPt( x, y ) );
543  }
544 
545  if( (unsigned) (ic + 1) < m_CornersList.GetCornersCount() )
546  {
547  if( m_CornersList[ic].end_contour )
548  {
549  m_CornersList[ic + 1].end_contour = true;
550  m_CornersList[ic].end_contour = false;
551  }
552  }
553 
554  Hatch();
555 }
556 
557 
558 // undraw polyline by removing all graphic elements from display list
560 {
561  m_HatchLines.clear();
562 }
563 
564 
566 {
567  int xmin = INT_MAX;
568  int ymin = INT_MAX;
569  int xmax = INT_MIN;
570  int ymax = INT_MIN;
571 
572  for( unsigned i = 0; i< m_CornersList.GetCornersCount(); i++ )
573  {
574  xmin = std::min( xmin, m_CornersList[i].x );
575  xmax = std::max( xmax, m_CornersList[i].x );
576  ymin = std::min( ymin, m_CornersList[i].y );
577  ymax = std::max( ymax, m_CornersList[i].y );
578  }
579 
580  EDA_RECT r;
581  r.SetOrigin( wxPoint( xmin, ymin ) );
582  r.SetEnd( wxPoint( xmax, ymax ) );
583 
584  return r;
585 }
586 
587 
589 {
590  int xmin = INT_MAX;
591  int ymin = INT_MAX;
592  int xmax = INT_MIN;
593  int ymax = INT_MIN;
594  int istart = GetContourStart( icont );
595  int iend = GetContourEnd( icont );
596 
597  for( int i = istart; i<=iend; i++ )
598  {
599  xmin = std::min( xmin, m_CornersList[i].x );
600  xmax = std::max( xmax, m_CornersList[i].x );
601  ymin = std::min( ymin, m_CornersList[i].y );
602  ymax = std::max( ymax, m_CornersList[i].y );
603  }
604 
605  EDA_RECT r;
606  r.SetOrigin( wxPoint( xmin, ymin ) );
607  r.SetEnd( wxPoint( xmax, ymax ) );
608 
609  return r;
610 }
611 
612 
614 {
616 }
617 
618 
619 
621 {
622  if( !m_cornersList.size() )
623  return 0;
624 
625  // count the number of corners flagged end_contour
626  int ncont = 0;
627 
628  for( unsigned ic = 0; ic < m_cornersList.size(); ic++ )
629  if( m_cornersList[ic].end_contour )
630  ncont++;
631 
632  // The last corner can be not yet flagged end_contour.
633  // It was not counted, but the polygon exists, so count it
634  if( !m_cornersList[m_cornersList.size() - 1].end_contour )
635  ncont++;
636 
637  return ncont;
638 }
639 
640 
642 {
643  int ncont = 0;
644 
645  for( int i = 0; i<ic; i++ )
646  {
647  if( m_CornersList[i].end_contour )
648  ncont++;
649  }
650 
651  return ncont;
652 }
653 
654 
656 {
657  if( icont == 0 )
658  return 0;
659 
660  int ncont = 0;
661 
662  for( unsigned i = 0; i<m_CornersList.GetCornersCount(); i++ )
663  {
664  if( m_CornersList[i].end_contour )
665  {
666  ncont++;
667 
668  if( ncont == icont )
669  return i + 1;
670  }
671  }
672 
673  wxASSERT( 0 );
674  return 0;
675 }
676 
677 
678 int CPolyLine::GetContourEnd( int icont )
679 {
680  if( icont < 0 )
681  return 0;
682 
683  if( icont == GetContoursCount() - 1 )
684  return m_CornersList.GetCornersCount() - 1;
685 
686  int ncont = 0;
687 
688  for( unsigned i = 0; i<m_CornersList.GetCornersCount(); i++ )
689  {
690  if( m_CornersList[i].end_contour )
691  {
692  if( ncont == icont )
693  return i;
694 
695  ncont++;
696  }
697  }
698 
699  wxASSERT( 0 );
700  return 0;
701 }
702 
703 
705 {
706  return GetContourEnd( icont ) - GetContourStart( icont ) + 1;
707 }
708 
709 
711 {
712  if( m_CornersList.GetCornersCount() == 0 )
713  return false;
714  else
715  return m_CornersList[m_CornersList.GetCornersCount() - 1].end_contour;
716 }
717 
718 
719 // Creates hatch lines inside the outline of the complex polygon
720 //
721 // sort function used in ::Hatch to sort points by descending wxPoint.x values
722 bool sort_ends_by_descending_X( const wxPoint& ref, const wxPoint& tst )
723 {
724  return tst.x < ref.x;
725 }
726 
727 
729 {
730  m_HatchLines.clear();
731 
732  if( m_hatchStyle == NO_HATCH || m_hatchPitch == 0 )
733  return;
734 
735  if( !GetClosed() ) // If not closed, the poly is beeing created and not finalised. Not not hatch
736  return;
737 
738  // define range for hatch lines
739  int min_x = m_CornersList[0].x;
740  int max_x = m_CornersList[0].x;
741  int min_y = m_CornersList[0].y;
742  int max_y = m_CornersList[0].y;
743 
744  for( unsigned ic = 1; ic < m_CornersList.GetCornersCount(); ic++ )
745  {
746  if( m_CornersList[ic].x < min_x )
747  min_x = m_CornersList[ic].x;
748 
749  if( m_CornersList[ic].x > max_x )
750  max_x = m_CornersList[ic].x;
751 
752  if( m_CornersList[ic].y < min_y )
753  min_y = m_CornersList[ic].y;
754 
755  if( m_CornersList[ic].y > max_y )
756  max_y = m_CornersList[ic].y;
757  }
758 
759  // Calculate spacing between 2 hatch lines
760  int spacing;
761 
762  if( m_hatchStyle == DIAGONAL_EDGE )
763  spacing = m_hatchPitch;
764  else
765  spacing = m_hatchPitch * 2;
766 
767  // set the "length" of hatch lines (the length on horizontal axis)
768  double hatch_line_len = m_hatchPitch;
769 
770  // To have a better look, give a slope depending on the layer
771  LAYER_NUM layer = GetLayer();
772  int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1
773  double slope = 0.707106 * slope_flag; // 45 degrees slope
774  int max_a, min_a;
775 
776  if( slope_flag == 1 )
777  {
778  max_a = KiROUND( max_y - slope * min_x );
779  min_a = KiROUND( min_y - slope * max_x );
780  }
781  else
782  {
783  max_a = KiROUND( max_y - slope * max_x );
784  min_a = KiROUND( min_y - slope * min_x );
785  }
786 
787  min_a = (min_a / spacing) * spacing;
788 
789  // calculate an offset depending on layer number,
790  // for a better look of hatches on a multilayer board
791  int offset = (layer * 7) / 8;
792  min_a += offset;
793 
794  // now calculate and draw hatch lines
795  int nc = m_CornersList.GetCornersCount();
796 
797  // loop through hatch lines
798  #define MAXPTS 200 // Usually we store only few values per one hatch line
799  // depending on the compexity of the zone outline
800 
801  static std::vector <wxPoint> pointbuffer;
802  pointbuffer.clear();
803  pointbuffer.reserve( MAXPTS + 2 );
804 
805  for( int a = min_a; a < max_a; a += spacing )
806  {
807  // get intersection points for this hatch line
808 
809  // Note: because we should have an even number of intersections with the
810  // current hatch line and the zone outline (a closed polygon,
811  // or a set of closed polygons), if an odd count is found
812  // we skip this line (should not occur)
813  pointbuffer.clear();
814  int i_start_contour = 0;
815 
816  for( int ic = 0; ic<nc; ic++ )
817  {
818  double x, y, x2, y2;
819  int ok;
820 
821  if( m_CornersList[ic].end_contour ||
822  ( ic == (int) (m_CornersList.GetCornersCount() - 1) ) )
823  {
824  ok = FindLineSegmentIntersection( a, slope,
825  m_CornersList[ic].x, m_CornersList[ic].y,
826  m_CornersList[i_start_contour].x,
827  m_CornersList[i_start_contour].y,
828  &x, &y, &x2, &y2 );
829  i_start_contour = ic + 1;
830  }
831  else
832  {
833  ok = FindLineSegmentIntersection( a, slope,
834  m_CornersList[ic].x, m_CornersList[ic].y,
835  m_CornersList[ic + 1].x, m_CornersList[ic + 1].y,
836  &x, &y, &x2, &y2 );
837  }
838 
839  if( ok )
840  {
841  wxPoint point( KiROUND( x ), KiROUND( y ) );
842  pointbuffer.push_back( point );
843  }
844 
845  if( ok == 2 )
846  {
847  wxPoint point( KiROUND( x2 ), KiROUND( y2 ) );
848  pointbuffer.push_back( point );
849  }
850 
851  if( pointbuffer.size() >= MAXPTS ) // overflow
852  {
853  wxASSERT( 0 );
854  break;
855  }
856  }
857 
858  // ensure we have found an even intersection points count
859  // because intersections are the ends of segments
860  // inside the polygon(s) and a segment has 2 ends.
861  // if not, this is a strange case (a bug ?) so skip this hatch
862  if( pointbuffer.size() % 2 != 0 )
863  continue;
864 
865  // sort points in order of descending x (if more than 2) to
866  // ensure the starting point and the ending point of the same segment
867  // are stored one just after the other.
868  if( pointbuffer.size() > 2 )
869  sort( pointbuffer.begin(), pointbuffer.end(), sort_ends_by_descending_X );
870 
871  // creates lines or short segments inside the complex polygon
872  for( unsigned ip = 0; ip < pointbuffer.size(); ip += 2 )
873  {
874  double dx = pointbuffer[ip + 1].x - pointbuffer[ip].x;
875 
876  // Push only one line for diagonal hatch,
877  // or for small lines < twice the line len
878  // else push 2 small lines
879  if( m_hatchStyle == DIAGONAL_FULL || fabs( dx ) < 2 * hatch_line_len )
880  {
881  m_HatchLines.push_back( CSegment( pointbuffer[ip], pointbuffer[ip + 1] ) );
882  }
883  else
884  {
885  double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y;
886  slope = dy / dx;
887 
888  if( dx > 0 )
889  dx = hatch_line_len;
890  else
891  dx = -hatch_line_len;
892 
893  double x1 = pointbuffer[ip].x + dx;
894  double x2 = pointbuffer[ip + 1].x - dx;
895  double y1 = pointbuffer[ip].y + dx * slope;
896  double y2 = pointbuffer[ip + 1].y - dx * slope;
897 
898  m_HatchLines.push_back( CSegment( pointbuffer[ip].x,
899  pointbuffer[ip].y,
900  KiROUND( x1 ), KiROUND( y1 ) ) );
901 
902  m_HatchLines.push_back( CSegment( pointbuffer[ip + 1].x,
903  pointbuffer[ip + 1].y,
904  KiROUND( x2 ), KiROUND( y2 ) ) );
905  }
906  }
907  }
908 }
909 
910 
911 // test to see if a point is inside polyline
912 //
913 bool CPolyLine::TestPointInside( int px, int py )
914 {
915  if( !GetClosed() )
916  {
917  wxASSERT( 0 );
918  }
919 
920  // Test all polygons.
921  // Since the first is the main outline, and other are holes,
922  // if the tested point is inside only one contour, it is inside the whole polygon
923  // (in fact inside the main outline, and outside all holes).
924  // if inside 2 contours (the main outline + an hole), it is outside the poly.
925  int polycount = GetContoursCount();
926  bool inside = false;
927 
928  for( int icont = 0; icont < polycount; icont++ )
929  {
930  int istart = GetContourStart( icont );
931  int iend = GetContourEnd( icont );
932 
933  // test point inside the current polygon
934  if( TestPointInsidePolygon( m_CornersList, istart, iend, px, py ) )
935  inside = not inside;
936  }
937 
938  return inside;
939 }
940 
941 
942 // copy data from another CPolyLine, but don't draw it
943 void CPolyLine::Copy( const CPolyLine* src )
944 {
945  UnHatch();
946  m_layer = src->m_layer;
947  m_hatchStyle = src->m_hatchStyle;
948  m_hatchPitch = src->m_hatchPitch;
949  m_flags = src->m_flags;
952 }
953 
954 
955 /*
956  * return true if the corner aCornerIdx is on a hole inside the main outline
957  * and false if it is on the main outline
958  */
959 bool CPolyLine::IsCutoutContour( int aCornerIdx )
960 {
961  int ncont = GetContour( aCornerIdx );
962 
963  if( ncont == 0 ) // the first contour is the main outline, not an hole
964  return false;
965 
966  return true;
967 }
968 
969 
970 void CPolyLine::MoveOrigin( int x_off, int y_off )
971 {
972  UnHatch();
973 
974  for( int ic = 0; ic < GetCornersCount(); ic++ )
975  {
976  SetX( ic, GetX( ic ) + x_off );
977  SetY( ic, GetY( ic ) + y_off );
978  }
979 
980  Hatch();
981 }
982 
983 /*
984  * AppendArc:
985  * adds segments to current contour to approximate the given arc
986  */
987 void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num )
988 {
989  // get radius
990  double radius = ::Distance( xi, yi, xf, yf );
991 
992  // get angles of start pint and end point
993  double th_i = atan2( (double) (yi - yc), (double) (xi - xc) );
994  double th_f = atan2( (double) (yf - yc), (double) (xf - xc) );
995  double th_d = (th_f - th_i) / (num - 1);
996  double theta = th_i;
997 
998  // generate arc
999  for( int ic = 0; ic < num; ic++ )
1000  {
1001  int x = xc + KiROUND( radius * cos( theta ) );
1002  int y = yc + KiROUND( radius * sin( theta ) );
1003  AppendCorner( x, y );
1004  theta += th_d;
1005  }
1006 
1007  CloseLastContour();
1008 }
1009 
1010 
1011 void CPolyLine::AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3 )
1012 {
1013  std::vector<wxPoint> polyPoints;
1014 
1015  BEZIER_POLY converter( x1, y1, x2, y2, x3, y3 );
1016  converter.GetPoly( polyPoints );
1017 
1018  for( const auto& pt : polyPoints )
1019  AppendCorner( pt.x, pt.y );
1020 }
1021 
1022 
1023 void CPolyLine::AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 )
1024 {
1025  std::vector<wxPoint> polyPoints;
1026 
1027  BEZIER_POLY converter( x1, y1, x2, y2, x3, y3, x4, y4 );
1028  converter.GetPoly( polyPoints );
1029 
1030  for( const auto& pt : polyPoints )
1031  AppendCorner( pt.x, pt.y );
1032 }
1033 
1034 
1035 /*
1036  * Function Distance
1037  * Calculates the distance between a segment and a polygon (with holes):
1038  * param aStart is the starting point of the segment.
1039  * param aEnd is the ending point of the segment.
1040  * param aWidth is the width of the segment.
1041  * return distance between the segment and outline.
1042  * 0 if segment intersects or is inside
1043  */
1044 int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth )
1045 {
1046  // We calculate the min dist between the segment and each outline segment
1047  // However, if the segment to test is inside the outline, and does not cross
1048  // any edge, it can be seen outside the polygon.
1049  // Therefore test if a segment end is inside ( testing only one end is enough )
1050  if( TestPointInside( aStart.x, aStart.y ) )
1051  return 0;
1052 
1053  int distance = INT_MAX;
1054  int polycount = GetContoursCount();
1055 
1056  for( int icont = 0; icont < polycount; icont++ )
1057  {
1058  int ic_start = GetContourStart( icont );
1059  int ic_end = GetContourEnd( icont );
1060 
1061  // now test spacing between area outline and segment
1062  for( int ic2 = ic_start; ic2 <= ic_end; ic2++ )
1063  {
1064  int bx1 = GetX( ic2 );
1065  int by1 = GetY( ic2 );
1066  int bx2, by2;
1067 
1068  if( ic2 == ic_end )
1069  {
1070  bx2 = GetX( ic_start );
1071  by2 = GetY( ic_start );
1072  }
1073  else
1074  {
1075  bx2 = GetX( ic2 + 1 );
1076  by2 = GetY( ic2 + 1 );
1077  }
1078 
1079  int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
1080  aStart.x, aStart.y, aEnd.x, aEnd.y,
1081  aWidth,
1082  1, // min clearance, should be > 0
1083  NULL, NULL );
1084 
1085  if( distance > d )
1086  distance = d;
1087 
1088  if( distance <= 0 )
1089  return 0;
1090  }
1091  }
1092 
1093  return distance;
1094 }
1095 
1096 
1097 /*
1098  * Function Distance
1099  * Calculates the distance between a point and polygon (with holes):
1100  * param aPoint is the coordinate of the point.
1101  * return distance between the point and outline.
1102  * 0 if the point is inside
1103  */
1104 int CPolyLine::Distance( const wxPoint& aPoint )
1105 {
1106  // We calculate the dist between the point and each outline segment
1107  // If the point is inside the outline, the dist is 0.
1108  if( TestPointInside( aPoint.x, aPoint.y ) )
1109  return 0;
1110 
1111  int distance = INT_MAX;
1112  int polycount = GetContoursCount();
1113 
1114  for( int icont = 0; icont < polycount; icont++ )
1115  {
1116  int ic_start = GetContourStart( icont );
1117  int ic_end = GetContourEnd( icont );
1118 
1119  // now test spacing between area outline and segment
1120  for( int ic2 = ic_start; ic2 <= ic_end; ic2++ )
1121  {
1122  int bx1 = GetX( ic2 );
1123  int by1 = GetY( ic2 );
1124  int bx2, by2;
1125 
1126  if( ic2 == ic_end )
1127  {
1128  bx2 = GetX( ic_start );
1129  by2 = GetY( ic_start );
1130  }
1131  else
1132  {
1133  bx2 = GetX( ic2 + 1 );
1134  by2 = GetY( ic2 + 1 );
1135  }
1136 
1137  int d = KiROUND( GetPointToLineSegmentDistance( aPoint.x, aPoint.y,
1138  bx1, by1, bx2, by2 ) );
1139 
1140  if( distance > d )
1141  distance = d;
1142 
1143  if( distance <= 0 )
1144  return 0;
1145  }
1146  }
1147 
1148  return distance;
1149 }
1150 
1151 
1152 /* test is the point aPos is near (< aDistMax ) a vertex
1153  * return int = the index of the first corner of the vertex, or -1 if not found.
1154  */
1155 int CPolyLine::HitTestForEdge( const wxPoint& aPos, int aDistMax ) const
1156 {
1157  unsigned lim = m_CornersList.GetCornersCount();
1158  int corner = -1; // Set to not found
1159  unsigned first_corner_pos = 0;
1160 
1161  for( unsigned item_pos = 0; item_pos < lim; item_pos++ )
1162  {
1163  unsigned end_segm = item_pos + 1;
1164 
1165  /* the last corner of the current outline is tested
1166  * the last segment of the current outline starts at current corner, and ends
1167  * at the first corner of the outline
1168  */
1169  if( m_CornersList.IsEndContour ( item_pos ) || end_segm >= lim )
1170  {
1171  unsigned tmp = first_corner_pos;
1172  first_corner_pos = end_segm; // first_corner_pos is the beginning of next outline
1173  end_segm = tmp; // end_segm is the beginning of the current outline
1174  }
1175 
1176  // test the dist between segment and ref point
1178  aPos.x, aPos.y,
1179  m_CornersList.GetX( item_pos ),
1180  m_CornersList.GetY( item_pos ),
1181  m_CornersList.GetX( end_segm ),
1182  m_CornersList.GetY( end_segm ) ) );
1183 
1184  if( dist < aDistMax )
1185  {
1186  corner = item_pos;
1187  aDistMax = dist;
1188  }
1189  }
1190 
1191  return corner;
1192 }
1193 
1194 /* test is the point aPos is near (< aDistMax ) a corner
1195  * return int = the index of corner of the, or -1 if not found.
1196  */
1197 int CPolyLine::HitTestForCorner( const wxPoint& aPos, int aDistMax ) const
1198 {
1199  int corner = -1; // Set to not found
1200  wxPoint delta;
1201  unsigned lim = m_CornersList.GetCornersCount();
1202 
1203  for( unsigned item_pos = 0; item_pos < lim; item_pos++ )
1204  {
1205  delta.x = aPos.x - m_CornersList.GetX( item_pos );
1206  delta.y = aPos.y - m_CornersList.GetY( item_pos );
1207 
1208  // Calculate a distance:
1209  int dist = std::max( abs( delta.x ), abs( delta.y ) );
1210 
1211  if( dist < aDistMax ) // this corner is a candidate:
1212  {
1213  corner = item_pos;
1214  aDistMax = dist;
1215  }
1216  }
1217 
1218  return corner;
1219 }
1220 
1221 
1233 {
1234  // first, check for sides intersecting other sides
1235  int n_cont = GetContoursCount();
1236 
1237  // make bounding rect for each contour
1238  std::vector<EDA_RECT> cr;
1239  cr.reserve( n_cont );
1240 
1241  for( int icont = 0; icont<n_cont; icont++ )
1242  cr.push_back( GetBoundingBox( icont ) );
1243 
1244  for( int icont = 0; icont<n_cont; icont++ )
1245  {
1246  int is_start = GetContourStart( icont );
1247  int is_end = GetContourEnd( icont );
1248 
1249  for( int is = is_start; is<=is_end; is++ )
1250  {
1251  int is_prev = is - 1;
1252 
1253  if( is_prev < is_start )
1254  is_prev = is_end;
1255 
1256  int is_next = is + 1;
1257 
1258  if( is_next > is_end )
1259  is_next = is_start;
1260 
1261  int x1i = GetX( is );
1262  int y1i = GetY( is );
1263  int x1f = GetX( is_next );
1264  int y1f = GetY( is_next );
1265 
1266  // check for intersection with any other sides
1267  for( int icont2 = icont; icont2 < n_cont; icont2++ )
1268  {
1269  if( !cr[icont].Intersects( cr[icont2] ) )
1270  {
1271  // rectangles don't overlap, do nothing
1272  }
1273  else
1274  {
1275  int is2_start = GetContourStart( icont2 );
1276  int is2_end = GetContourEnd( icont2 );
1277 
1278  for( int is2 = is2_start; is2<=is2_end; is2++ )
1279  {
1280  int is2_prev = is2 - 1;
1281 
1282  if( is2_prev < is2_start )
1283  is2_prev = is2_end;
1284 
1285  int is2_next = is2 + 1;
1286 
1287  if( is2_next > is2_end )
1288  is2_next = is2_start;
1289 
1290  if( icont != icont2
1291  || ( is2 != is && is2 != is_prev && is2 != is_next &&
1292  is != is2_prev && is != is2_next )
1293  )
1294  {
1295  int x2i = GetX( is2 );
1296  int y2i = GetY( is2 );
1297  int x2f = GetX( is2_next );
1298  int y2f = GetY( is2_next );
1299  int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f,
1300  x2i, y2i, x2f, y2f );
1301  if( ret )
1302  {
1303  // intersection between non-adjacent sides
1304  return true;
1305  }
1306  }
1307  }
1308  }
1309  }
1310  }
1311  }
1312 
1313  return false;
1314 }
1315 
1317 {
1318  SHAPE_POLY_SET rv;
1319 
1320  unsigned corners_count = aList.GetCornersCount();
1321 
1322  // Enter main outline: this is the first contour
1323  unsigned ic = 0;
1324 
1325  if( !corners_count )
1326  return rv;
1327 
1328  int index = 0;
1329 
1330  while( ic < corners_count )
1331  {
1332  int hole = -1;
1333 
1334  if( index == 0 )
1335  {
1336  rv.NewOutline();
1337  hole = -1;
1338  }
1339  else
1340  {
1341  hole = rv.NewHole();
1342  }
1343 
1344  while( ic < corners_count )
1345  {
1346  rv.Append( aList.GetX( ic ), aList.GetY( ic ), 0, hole );
1347 
1348  if( aList.IsEndContour( ic ) )
1349  break;
1350 
1351  ic++;
1352  }
1353  ic++;
1354 
1355  index++;
1356  }
1357 
1358  return rv;
1359 }
1360 
1361 
1363 {
1364  CPOLYGONS_LIST list;
1365  CPolyPt corner, firstCorner;
1366 
1367  const SHAPE_POLY_SET::POLYGON& poly = aPolyset.CPolygon( 0 );
1368 
1369  for( unsigned int jj = 0; jj < poly.size() ; jj++ )
1370  {
1371  const SHAPE_LINE_CHAIN& path = poly[jj];
1372 
1373  for( int i = 0; i < path.PointCount(); i++ )
1374  {
1375  const VECTOR2I &v = path.CPoint( i );
1376 
1377  corner.x = v.x;
1378  corner.y = v.y;
1379  corner.end_contour = false;
1380 
1381  if( i == 0 )
1382  firstCorner = corner;
1383 
1384  list.AddCorner( corner );
1385  }
1386 
1387  firstCorner.end_contour = true;
1388  list.AddCorner( firstCorner );
1389  }
1390 
1391  return list;
1392 }
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
int NewHole(int aOutline=-1)
Creates a new hole in a given outline
void SetHatchPitch(int pitch)
Definition: PolyLine.h:424
double GetPointToLineSegmentDistance(int x, int y, int xi, int yi, int xf, int yf)
Function GetPointToLineSegmentDistance Get distance between line segment and point.
bool IsEndContour(int ic) const
Definition: PolyLine.h:131
const CPOLYGONS_LIST ConvertPolySetToPolyList(const SHAPE_POLY_SET &aPolyset)
Definition: PolyLine.cpp:1362
void AppendArc(int xi, int yi, int xf, int yf, int xc, int yc, int num)
Function AppendArc.
Definition: PolyLine.cpp:987
~CPolyLine()
Definition: PolyLine.cpp:68
const EDA_RECT GetBoundingBox()
Definition: PolyLine.cpp:565
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
void Copy(const CPolyLine *src)
Definition: PolyLine.cpp:943
void UnHatch()
Definition: PolyLine.cpp:559
int GetY(int ic) const
Definition: PolyLine.h:385
void Start(LAYER_NUM layer, int x, int y, int hatch)
Definition: PolyLine.cpp:186
int PointCount() const
Function PointCount()
enum HATCH_STYLE GetHatchStyle() const
Definition: PolyLine.h:399
void SetX(int ic, int x)
Definition: PolyLine.h:409
void AppendCorner(int x, int y)
Definition: PolyLine.cpp:199
void AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3)
Definition: PolyLine.cpp:1011
void Hatch()
Definition: PolyLine.cpp:728
int GetContourEnd(int icont)
Function GetContourEnd.
Definition: PolyLine.cpp:678
void GetPoly(std::vector< wxPoint > &aOutput)
Converts Bezier curve to a polygon.
void RemoveContour(int icont)
Function RemoveContour.
Definition: PolyLine.cpp:252
static const int dist[10][10]
Definition: dist.cpp:57
void RemoveAllContours(void)
function RemoveAllContours removes all corners from the list.
Definition: PolyLine.cpp:513
void SetOrigin(const wxPoint &pos)
const SHAPE_POLY_SET ConvertPolyListToPolySet(const CPOLYGONS_LIST &aList)
Definition: PolyLine.cpp:1316
CPOLYGONS_LIST m_CornersList
Definition: PolyLine.h:487
unsigned GetCornersCount() const
Definition: PolyLine.h:146
CPolyLine * Fillet(unsigned int aRadius, unsigned int aSegments)
Function Fillet returns a filleted version of a polygon.
Definition: PolyLine.cpp:370
LAYER_NUM m_layer
Definition: PolyLine.h:480
int GetClearanceBetweenSegments(int x1i, int y1i, int x1f, int y1f, int w1, int x2i, int y2i, int x2f, int y2f, int w2, int max_cl, int *x, int *y)
int OutlineCount() const
Returns the number of outlines in the set
int Distance(const wxPoint &aPoint)
Function Distance Calculates the distance between a point and the zone:
Definition: PolyLine.cpp:1104
int HitTestForCorner(const wxPoint &aPos, int aDistMax) const
Function HitTestForCorner test is the point aPos is near (< aDistMax ) a corner.
Definition: PolyLine.cpp:1197
#define abs(a)
Definition: auxiliary.h:84
static const int delta[8][2]
Definition: solve.cpp:112
int RemoveNullSegments()
Function RemoveNullSegments Removes corners which create a null segment edge (i.e.
Definition: PolyLine.cpp:77
std::vector< CSegment > m_HatchLines
Definition: PolyLine.h:488
int GetContourSize(int icont)
Function GetContourSize.
Definition: PolyLine.cpp:704
CPolyLine * Chamfer(unsigned int aDistance)
Function Chamfer returns a chamfered version of a polygon.
Definition: PolyLine.cpp:285
bool TestPointInsidePolygon(const CPOLYGONS_LIST &aPolysList, int aIdxstart, int aIdxend, int aRefx, int aRefy)
Function TestPointInsidePolygon test if a point is inside or outside a polygon.
enum HATCH_STYLE m_hatchStyle
Definition: PolyLine.h:481
bool sort_ends_by_descending_X(const wxPoint &ref, const wxPoint &tst)
Definition: PolyLine.cpp:722
Class SHAPE_POLY_SET.
void MoveOrigin(int x_off, int y_off)
Definition: PolyLine.cpp:970
void SetEnd(int x, int y)
int GetContoursCount() const
Function GetContoursCount.
Definition: PolyLine.cpp:620
void SetY(int ic, int y)
Definition: PolyLine.h:414
int GetX(int ic) const
Definition: PolyLine.h:384
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
bool FindLineSegmentIntersection(double a, double b, int xi, int yi, int xf, int yf, double *x1, double *y1, double *x2, double *y2, double *dist)
bool IsCutoutContour(int aCornerIdx)
Definition: PolyLine.cpp:959
int GetHatchPitch() const
Definition: PolyLine.h:396
int GetContoursCount() const
Function GetContoursCount.
Definition: PolyLine.cpp:613
int NewOutline()
Creates a new empty polygon in the set and returns its index
void DeleteCorner(int aIdx)
Definition: PolyLine.h:148
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
LAYER_NUM GetLayer() const
Definition: PolyLine.h:337
int HitTestForEdge(const wxPoint &aPos, int aDistMax) const
Function HitTestForEdge test is the point aPos is near (< aDistMax ) a vertex.
Definition: PolyLine.cpp:1155
#define MAXPTS
int m_flags
Definition: PolyLine.h:485
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index
Bezier curves to polygon converter.
Definition: bezier_curves.h:34
void SetHatchStyle(enum HATCH_STYLE style)
Definition: PolyLine.h:419
int GetCornersCount() const
Definition: PolyLine.h:339
void CloseLastContour()
function CloseLastContour Set the .end_contour member of the last corner of the last contour to true ...
Definition: PolyLine.h:254
#define max(a, b)
Definition: auxiliary.h:86
bool GetClosed()
Definition: PolyLine.cpp:710
Class SHAPE_LINE_CHAIN.
void RemoveAllContours(void)
Definition: PolyLine.h:143
void DeleteCorner(int ic)
Function DeleteCorner remove the given corner.
Definition: PolyLine.cpp:222
Class EDA_RECT handles the component boundary box.
void AddCorner(const CPolyPt &aCorner)
function AddCorner add a corner to the list
Definition: PolyLine.h:188
bool end_contour
Definition: PolyLine.h:97
void Append(const CPOLYGONS_LIST &aList)
Definition: PolyLine.h:160
The common library.
int GetContourStart(int icont)
Function GetContourStart.
Definition: PolyLine.cpp:655
int GetY(int ic) const
Definition: PolyLine.h:128
int GetX(int ic) const
Definition: PolyLine.h:126
const POLYGON & CPolygon(int aIndex) const
bool IsPolygonSelfIntersecting()
Function IsPolygonSelfIntersecting Test a CPolyLine for self-intersection of vertex (all contours)...
Definition: PolyLine.cpp:1232
int GetContour(int ic)
Function GetContour.
Definition: PolyLine.cpp:641
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp ...
POLYGON & Polygon(int aIndex)
Returns the aIndex-th subpolygon in the set
void MoveCorner(int ic, int x, int y)
Definition: PolyLine.cpp:211
CPOLYGONS_LIST handle a list of contours (polygons corners).
Definition: PolyLine.h:114
bool FindSegmentIntersections(int xi, int yi, int xf, int yf, int xi2, int yi2, int xf2, int yf2)
void InsertCorner(int aPosition, const CPolyPt &aItem)
Definition: PolyLine.h:179
int NormalizeAreaOutlines(std::vector< CPolyLine * > *aNewPolygonList)
Function NormalizeAreaOutlines Convert a self-intersecting polygon to one (or more) non self-intersec...
Definition: PolyLine.cpp:117
bool TestPointInside(int x, int y)
Definition: PolyLine.cpp:913
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
std::vector< CPolyPt > m_cornersList
Definition: PolyLine.h:117
void InsertCorner(int ic, int x, int y)
Function InsertCorner insert a new corner between two existing corners.
Definition: PolyLine.cpp:532
#define min(a, b)
Definition: auxiliary.h:85
int m_hatchPitch
Definition: PolyLine.h:482
void SetLayer(LAYER_NUM aLayer)
Definition: PolyLine.h:336
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline) ...
void ImportSettings(const CPolyLine *aPoly)
Function ImportSettings Copy settings (layer, hatch styles) from aPoly.
Definition: PolyLine.cpp:176