KiCad PCB EDA Suite
convert_drawsegment_list_to_polygon.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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
32 #include <trigo.h>
33 #include <macros.h>
34 
35 #include <math/vector2d.h>
36 #include <class_drawsegment.h>
37 #include <class_module.h>
38 #include <base_units.h>
42 
43 
56 static unsigned close_ness( const wxPoint& aLeft, const wxPoint& aRight )
57 {
58  // Don't need an accurate distance calculation, just something
59  // approximating it, for relative ordering.
60  return unsigned( std::abs( aLeft.x - aRight.x ) + abs( aLeft.y - aRight.y ) );
61 }
62 
72 inline bool close_enough( const wxPoint& aLeft, const wxPoint& aRight, unsigned aLimit )
73 {
74  // We don't use an accurate distance calculation, just something
75  // approximating it, since aLimit is non-exact anyway except when zero.
76  return close_ness( aLeft, aRight ) <= aLimit;
77 }
78 
88 inline bool close_st( const wxPoint& aReference, const wxPoint& aFirst, const wxPoint& aSecond )
89 {
90  // We don't use an accurate distance calculation, just something
91  // approximating to find the closest to the reference.
92  return close_ness( aReference, aFirst ) <= close_ness( aReference, aSecond );
93 }
94 
95 
105 static DRAWSEGMENT* findPoint( const wxPoint& aPoint, std::vector< DRAWSEGMENT* >& aList, unsigned aLimit )
106 {
107  unsigned min_d = INT_MAX;
108  int ndx_min = 0;
109 
110  // find the point closest to aPoint and perhaps exactly matching aPoint.
111  for( size_t i = 0; i < aList.size(); ++i )
112  {
113  DRAWSEGMENT* graphic = aList[i];
114  unsigned d;
115 
116  switch( graphic->GetShape() )
117  {
118  case S_ARC:
119  if( aPoint == graphic->GetArcStart() || aPoint == graphic->GetArcEnd() )
120  {
121  aList.erase( aList.begin() + i );
122  return graphic;
123  }
124 
125  d = close_ness( aPoint, graphic->GetArcStart() );
126  if( d < min_d )
127  {
128  min_d = d;
129  ndx_min = i;
130  }
131 
132  d = close_ness( aPoint, graphic->GetArcEnd() );
133  if( d < min_d )
134  {
135  min_d = d;
136  ndx_min = i;
137  }
138  break;
139 
140  default:
141  if( aPoint == graphic->GetStart() || aPoint == graphic->GetEnd() )
142  {
143  aList.erase( aList.begin() + i );
144  return graphic;
145  }
146 
147  d = close_ness( aPoint, graphic->GetStart() );
148  if( d < min_d )
149  {
150  min_d = d;
151  ndx_min = i;
152  }
153 
154  d = close_ness( aPoint, graphic->GetEnd() );
155  if( d < min_d )
156  {
157  min_d = d;
158  ndx_min = i;
159  }
160  }
161  }
162 
163  if( min_d <= aLimit )
164  {
165  DRAWSEGMENT* graphic = aList[ndx_min];
166  aList.erase( aList.begin() + ndx_min );
167  return graphic;
168  }
169 
170  return NULL;
171 }
172 
173 
185 bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SET& aPolygons,
186  wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation )
187 {
188  if( aSegList.size() == 0 )
189  return true;
190 
191  wxString msg;
192 
193  // Make a working copy of aSegList, because the list is modified during calculations
194  std::vector< DRAWSEGMENT* > segList = aSegList;
195 
196  DRAWSEGMENT* graphic;
197  wxPoint prevPt;
198 
199  // Find edge point with minimum x, this should be in the outer polygon
200  // which will define the perimeter polygon polygon.
201  wxPoint xmin = wxPoint( INT_MAX, 0 );
202  int xmini = 0;
203 
204  for( size_t i = 0; i < segList.size(); i++ )
205  {
206  graphic = (DRAWSEGMENT*) segList[i];
207 
208  switch( graphic->GetShape() )
209  {
210  case S_SEGMENT:
211  {
212  if( graphic->GetStart().x < xmin.x )
213  {
214  xmin = graphic->GetStart();
215  xmini = i;
216  }
217 
218  if( graphic->GetEnd().x < xmin.x )
219  {
220  xmin = graphic->GetEnd();
221  xmini = i;
222  }
223  }
224  break;
225 
226  case S_ARC:
227  // Freerouter does not yet understand arcs, so approximate
228  // an arc with a series of short lines and put those
229  // line segments into the !same! PATH.
230  {
231  wxPoint pstart = graphic->GetArcStart();
232  wxPoint center = graphic->GetCenter();
233  double angle = -graphic->GetAngle();
234  double radius = graphic->GetRadius();
235  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );
236  wxPoint pt;
237 
238  for( int step = 1; step<=steps; ++step )
239  {
240  double rotation = ( angle * step ) / steps;
241 
242  pt = pstart;
243 
244  RotatePoint( &pt, center, rotation );
245 
246  if( pt.x < xmin.x )
247  {
248  xmin = pt;
249  xmini = i;
250  }
251  }
252  }
253  break;
254 
255  case S_CIRCLE:
256  {
257  wxPoint pt = graphic->GetCenter();
258 
259  // pt has minimum x point
260  pt.x -= graphic->GetRadius();
261 
262  // when the radius <= 0, this is a mal-formed circle. Skip it
263  if( graphic->GetRadius() > 0 && pt.x < xmin.x )
264  {
265  xmin = pt;
266  xmini = i;
267  }
268  }
269  break;
270 
271  case S_CURVE:
272  {
273  graphic->RebuildBezierToSegmentsPointsList( graphic->GetWidth() );
274 
275  for( unsigned int jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
276  {
277  wxPoint pt = graphic->GetBezierPoints()[jj];
278 
279  if( pt.x < xmin.x )
280  {
281  xmin = pt;
282  xmini = i;
283  }
284  }
285  }
286  break;
287 
288  case S_POLYGON:
289  {
290  const auto poly = graphic->GetPolyShape();
291  MODULE* module = aSegList[0]->GetParentModule();
292  double orientation = module ? module->GetOrientation() : 0.0;
293  VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 );
294 
295  for( auto iter = poly.CIterate(); iter; iter++ )
296  {
297  auto pt = *iter;
298  RotatePoint( pt, orientation );
299  pt += offset;
300 
301  if( pt.x < xmin.x )
302  {
303  xmin.x = pt.x;
304  xmin.y = pt.y;
305  xmini = i;
306  }
307  }
308  }
309  break;
310  default:
311  break;
312  }
313  }
314 
315  // Grab the left most point, assume its on the board's perimeter, and see if we
316  // can put enough graphics together by matching endpoints to formulate a cohesive
317  // polygon.
318 
319  graphic = (DRAWSEGMENT*) segList[xmini];
320 
321  // The first DRAWSEGMENT is in 'graphic', ok to remove it from 'items'
322  segList.erase( segList.begin() + xmini );
323 
324  // Output the outline perimeter as polygon.
325  if( graphic->GetShape() == S_CIRCLE )
326  {
327  TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), aTolerance );
328  }
329  else if( graphic->GetShape() == S_POLYGON )
330  {
331  MODULE* module = graphic->GetParentModule(); // NULL for items not in footprints
332  double orientation = module ? module->GetOrientation() : 0.0;
333  VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 );
334 
335  aPolygons.NewOutline();
336 
337  for( auto it = graphic->GetPolyShape().CIterate( 0 ); it; it++ )
338  {
339  auto pt = *it;
340  RotatePoint( pt, orientation );
341  pt += offset;
342  aPolygons.Append( pt );
343  }
344  }
345  else
346  {
347  // Polygon start point. Arbitrarily chosen end of the
348  // segment and build the poly from here.
349 
350  wxPoint startPt = wxPoint( graphic->GetEnd() );
351  prevPt = graphic->GetEnd();
352  aPolygons.NewOutline();
353  aPolygons.Append( prevPt );
354 
355  // Do not append the other end point yet of this 'graphic', this first
356  // 'graphic' might be an arc or a curve.
357 
358  for(;;)
359  {
360  switch( graphic->GetShape() )
361  {
362  case S_SEGMENT:
363  {
364  wxPoint nextPt;
365 
366  // Use the line segment end point furthest away from
367  // prevPt as we assume the other end to be ON prevPt or
368  // very close to it.
369 
370  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
371  nextPt = graphic->GetEnd();
372  else
373  nextPt = graphic->GetStart();
374 
375  aPolygons.Append( nextPt );
376  prevPt = nextPt;
377  }
378  break;
379 
380  case S_ARC:
381  // We do not support arcs in polygons, so approximate
382  // an arc with a series of short lines and put those
383  // line segments into the !same! PATH.
384  {
385  wxPoint pstart = graphic->GetArcStart();
386  wxPoint pend = graphic->GetArcEnd();
387  wxPoint pcenter = graphic->GetCenter();
388  double angle = -graphic->GetAngle();
389  double radius = graphic->GetRadius();
390  int steps = GetArcToSegmentCount( radius, aTolerance, angle / 10.0 );
391 
392  if( !close_enough( prevPt, pstart, aTolerance ) )
393  {
394  wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
395 
396  angle = -angle;
397  std::swap( pstart, pend );
398  }
399 
400  wxPoint nextPt;
401 
402  for( int step = 1; step<=steps; ++step )
403  {
404  double rotation = ( angle * step ) / steps;
405  nextPt = pstart;
406  RotatePoint( &nextPt, pcenter, rotation );
407 
408  aPolygons.Append( nextPt );
409  }
410 
411  prevPt = nextPt;
412  }
413  break;
414 
415  case S_CURVE:
416  // We do not support Bezier curves in polygons, so approximate
417  // with a series of short lines and put those
418  // line segments into the !same! PATH.
419  {
420  wxPoint nextPt;
421  bool reverse = false;
422 
423  // Use the end point furthest away from
424  // prevPt as we assume the other end to be ON prevPt or
425  // very close to it.
426 
427  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
428  nextPt = graphic->GetEnd();
429  else
430  {
431  nextPt = graphic->GetStart();
432  reverse = true;
433  }
434 
435  if( reverse )
436  {
437  for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
438  aPolygons.Append( graphic->GetBezierPoints()[jj] );
439  }
440  else
441  {
442  for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
443  aPolygons.Append( graphic->GetBezierPoints()[jj] );
444  }
445 
446  prevPt = nextPt;
447  }
448  break;
449 
450  default:
451  if( aErrorText )
452  {
453  msg.Printf( "Unsupported DRAWSEGMENT type %s.",
454  BOARD_ITEM::ShowShape( graphic->GetShape() ) );
455 
456  *aErrorText << msg << "\n";
457  }
458 
459  if( aErrorLocation )
460  *aErrorLocation = graphic->GetPosition();
461 
462  return false;
463  }
464 
465  // Get next closest segment.
466 
467  graphic = findPoint( prevPt, segList, aTolerance );
468 
469  // If there are no more close segments, check if the board
470  // outline polygon can be closed.
471 
472  if( !graphic )
473  {
474  if( close_enough( startPt, prevPt, aTolerance ) )
475  {
476  // Close the polygon back to start point
477  // aPolygons.Append( startPt ); // not needed
478  }
479  else
480  {
481  if( aErrorText )
482  {
483  msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ),
484  StringFromValue( MILLIMETRES, prevPt.x, true ),
485  StringFromValue( MILLIMETRES, prevPt.y, true ) );
486 
487  *aErrorText << msg << "\n";
488  }
489 
490  if( aErrorLocation )
491  *aErrorLocation = prevPt;
492 
493  return false;
494  }
495  break;
496  }
497  }
498  }
499 
500  while( segList.size() )
501  {
502  // emit a signal layers keepout for every interior polygon left...
503  int hole = aPolygons.NewHole();
504 
505  graphic = (DRAWSEGMENT*) segList[0];
506  segList.erase( segList.begin() );
507 
508  // Both circles and polygons on the edge cuts layer are closed items that
509  // do not connect to other elements, so we process them independently
510  if( graphic->GetShape() == S_POLYGON )
511  {
512  MODULE* module = graphic->GetParentModule(); // NULL for items not in footprints
513  double orientation = module ? module->GetOrientation() : 0.0;
514  VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 );
515 
516  for( auto it = graphic->GetPolyShape().CIterate(); it; it++ )
517  {
518  auto val = *it;
519  RotatePoint( val, orientation );
520  val += offset;
521 
522  aPolygons.Append( val, -1, hole );
523  }
524  }
525  else if( graphic->GetShape() == S_CIRCLE )
526  {
527  // make a circle by segments;
528  wxPoint center = graphic->GetCenter();
529  double angle = 3600.0;
530  wxPoint start = center;
531  int radius = graphic->GetRadius();
532  int steps = std::max<int>( 4, GetArcToSegmentCount( radius, aTolerance, 360.0 ) );
533  wxPoint nextPt;
534 
535  start.x += radius;
536 
537  for( int step = 0; step < steps; ++step )
538  {
539  double rotation = ( angle * step ) / steps;
540  nextPt = start;
541  RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
542  aPolygons.Append( nextPt, -1, hole );
543  }
544  }
545  else
546  {
547  // Polygon start point. Arbitrarily chosen end of the
548  // segment and build the poly from here.
549 
550  wxPoint startPt( graphic->GetEnd() );
551  prevPt = graphic->GetEnd();
552  aPolygons.Append( prevPt, -1, hole );
553 
554  // do not append the other end point yet, this first 'graphic' might be an arc
555  for(;;)
556  {
557  switch( graphic->GetShape() )
558  {
559  case S_SEGMENT:
560  {
561  wxPoint nextPt;
562 
563  // Use the line segment end point furthest away from
564  // prevPt as we assume the other end to be ON prevPt or
565  // very close to it.
566 
567  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
568  {
569  nextPt = graphic->GetEnd();
570  }
571  else
572  {
573  nextPt = graphic->GetStart();
574  }
575 
576  prevPt = nextPt;
577  aPolygons.Append( prevPt, -1, hole );
578  }
579  break;
580 
581  case S_ARC:
582  // Freerouter does not yet understand arcs, so approximate
583  // an arc with a series of short lines and put those
584  // line segments into the !same! PATH.
585  {
586  wxPoint pstart = graphic->GetArcStart();
587  wxPoint pend = graphic->GetArcEnd();
588  wxPoint pcenter = graphic->GetCenter();
589  double angle = -graphic->GetAngle();
590  int radius = graphic->GetRadius();
591  int steps = GetArcToSegmentCount( radius, aTolerance, angle / 10.0 );
592 
593  if( !close_enough( prevPt, pstart, aTolerance ) )
594  {
595  wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
596 
597  angle = -angle;
598  std::swap( pstart, pend );
599  }
600 
601  wxPoint nextPt;
602 
603  for( int step = 1; step <= steps; ++step )
604  {
605  double rotation = ( angle * step ) / steps;
606 
607  nextPt = pstart;
608  RotatePoint( &nextPt, pcenter, rotation );
609 
610  aPolygons.Append( nextPt, -1, hole );
611  }
612 
613  prevPt = nextPt;
614  }
615  break;
616 
617  case S_CURVE:
618  // We do not support Bezier curves in polygons, so approximate
619  // with a series of short lines and put those
620  // line segments into the !same! PATH.
621  {
622  wxPoint nextPt;
623  bool reverse = false;
624 
625  // Use the end point furthest away from
626  // prevPt as we assume the other end to be ON prevPt or
627  // very close to it.
628 
629  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
630  nextPt = graphic->GetEnd();
631  else
632  {
633  nextPt = graphic->GetStart();
634  reverse = true;
635  }
636 
637  if( reverse )
638  {
639  for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
640  aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole );
641  }
642  else
643  {
644  for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
645  aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole );
646  }
647 
648  prevPt = nextPt;
649  }
650  break;
651 
652  default:
653  if( aErrorText )
654  {
655  msg.Printf( "Unsupported DRAWSEGMENT type %s.",
656  BOARD_ITEM::ShowShape( graphic->GetShape() ) );
657 
658  *aErrorText << msg << "\n";
659  }
660 
661  if( aErrorLocation )
662  *aErrorLocation = graphic->GetPosition();
663 
664  return false;
665  }
666 
667  // Get next closest segment.
668 
669  graphic = findPoint( prevPt, segList, aTolerance );
670 
671  // If there are no more close segments, check if polygon
672  // can be closed.
673 
674  if( !graphic )
675  {
676  if( close_enough( startPt, prevPt, aTolerance ) )
677  {
678  // Close the polygon back to start point
679  // aPolygons.Append( startPt, -1, hole ); // not needed
680  }
681  else
682  {
683  if( aErrorText )
684  {
685  msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ),
686  StringFromValue( MILLIMETRES, prevPt.x, true ),
687  StringFromValue( MILLIMETRES, prevPt.y, true ) );
688 
689  *aErrorText << msg << "\n";
690  }
691 
692  if( aErrorLocation )
693  *aErrorLocation = prevPt;
694 
695  return false;
696  }
697  break;
698  }
699  }
700  }
701  }
702 
703  // All of the silliness that follows is to work around the segment iterator
704  // while checking for collisions.
705  // TODO: Implement proper segment and point iterators that follow std
706  for( auto seg1 = aPolygons.IterateSegmentsWithHoles(); seg1; seg1++ )
707  {
708  auto seg2 = seg1;
709 
710  for( ++seg2; seg2; seg2++ )
711  {
712  // Check for exact overlapping segments. This is not viewed
713  // as an intersection below
714  if( *seg1 == *seg2 ||
715  ( ( *seg1 ).A == ( *seg2 ).B && ( *seg1 ).B == ( *seg2 ).A ) )
716  {
717  if( aErrorLocation )
718  {
719  aErrorLocation->x = ( *seg1 ).A.x;
720  aErrorLocation->y = ( *seg1 ).A.y;
721  }
722 
723  return false;
724  }
725 
726  if( auto pt = seg1.Get().Intersect( seg2.Get(), true ) )
727  {
728  if( aErrorLocation )
729  {
730  aErrorLocation->x = pt->x;
731  aErrorLocation->y = pt->y;
732  }
733 
734  return false;
735  }
736  }
737  }
738 
739  return true;
740 }
741 
742 #include <class_board.h>
743 #include <collectors.h>
744 
745 /* This function is used to extract a board outlines (3D view, automatic zones build ...)
746  * Any closed outline inside the main outline is a hole
747  * All contours should be closed, i.e. valid closed polygon vertices
748  */
750  wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation )
751 {
752  PCB_TYPE_COLLECTOR items;
753 
754  // Get all the DRAWSEGMENTS and module graphics into 'items',
755  // then keep only those on layer == Edge_Cuts.
756  static const KICAD_T scan_graphics[] = { PCB_LINE_T, PCB_MODULE_EDGE_T, EOT };
757  items.Collect( aBoard, scan_graphics );
758 
759  // Make a working copy of aSegList, because the list is modified during calculations
760  std::vector< DRAWSEGMENT* > segList;
761 
762  for( int ii = 0; ii < items.GetCount(); ii++ )
763  {
764  if( items[ii]->GetLayer() == Edge_Cuts )
765  segList.push_back( static_cast< DRAWSEGMENT* >( items[ii] ) );
766  }
767 
768  bool success = ConvertOutlineToPolygon( segList, aOutlines, aErrorText, aTolerance, aErrorLocation );
769 
770  if( !success || !aOutlines.OutlineCount() )
771  {
772  // Creates a valid polygon outline is not possible.
773  // So uses the board edge cuts bounding box to create a
774  // rectangular outline
775  // When no edge cuts items, build a contour
776  // from global bounding box
777 
778  EDA_RECT bbbox = aBoard->GetBoardEdgesBoundingBox();
779 
780  // If null area, uses the global bounding box.
781  if( ( bbbox.GetWidth() ) == 0 || ( bbbox.GetHeight() == 0 ) )
782  bbbox = aBoard->ComputeBoundingBox();
783 
784  // Ensure non null area. If happen, gives a minimal size.
785  if( ( bbbox.GetWidth() ) == 0 || ( bbbox.GetHeight() == 0 ) )
786  bbbox.Inflate( Millimeter2iu( 1.0 ) );
787 
788  aOutlines.RemoveAllContours();
789  aOutlines.NewOutline();
790 
791  wxPoint corner;
792  aOutlines.Append( bbbox.GetOrigin() );
793 
794  corner.x = bbbox.GetOrigin().x;
795  corner.y = bbbox.GetEnd().y;
796  aOutlines.Append( corner );
797 
798  aOutlines.Append( bbbox.GetEnd() );
799 
800  corner.x = bbbox.GetEnd().x;
801  corner.y = bbbox.GetOrigin().y;
802  aOutlines.Append( corner );
803  }
804 
805  return success;
806 }
int NewHole(int aOutline=-1)
Creates a new hole in a given outline
static wxString ShowShape(STROKE_T aShape)
Function ShowShape converts the enum STROKE_T integer value to a wxString.
double GetOrientation() const
Definition: class_module.h:202
int OutlineCount() const
Returns the number of outlines in the set
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, wxPoint aCenter, int aRadius, int aError)
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
Implementation of conversion functions that require both schematic and board internal units.
const wxPoint GetCenter() const override
Function GetCenter()
const EDA_RECT GetBoardEdgesBoundingBox() const
Function GetBoardEdgesBoundingBox Returns the board bounding box calculated using exclusively the boa...
Definition: class_board.h:804
STROKE_T GetShape() const
const wxPoint GetArcEnd() const
polygon (not yet used for tracks, but could be in microwave apps)
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_BezierPoints vertex list that approximate the Bezier curve by a list of segments Has me...
int GetWidth() const
Definition: eda_rect.h:119
const wxPoint GetPosition() const override
usual segment : line with rounded ends
const std::vector< wxPoint > & GetBezierPoints() const
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:206
bool ConvertOutlineToPolygon(std::vector< DRAWSEGMENT * > &aSegList, SHAPE_POLY_SET &aPolygons, wxString *aErrorText, unsigned int aTolerance, wxPoint *aErrorLocation)
Function ConvertOutlineToPolygon build a polygon (with holes) from a DRAWSEGMENT list,...
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
#define abs(a)
Definition: auxiliary.h:84
static unsigned close_ness(const wxPoint &aLeft, const wxPoint &aRight)
Function close_ness is a non-exact distance (also called Manhattan distance) used to approximate the ...
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
bool close_st(const wxPoint &aReference, const wxPoint &aFirst, const wxPoint &aSecond)
Function close_st is a local method of qualifying if either the start of end point of a segment is cl...
This file contains miscellaneous commonly used macros and functions.
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, wxString *aErrorText, unsigned int aTolerance, wxPoint *aErrorLocation)
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:113
const wxPoint GetEnd() const
Definition: eda_rect.h:116
Class SHAPE_POLY_SET.
const wxPoint GetOrigin() const
Definition: eda_rect.h:114
Arcs (with rounded ends)
MODULE * GetParentModule() const
Function GetParentModule returns a pointer to the parent module, or NULL if DRAWSEGMENT does not belo...
a few functions useful in geometry calculations.
const wxPoint & GetArcStart() const
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
SHAPE_POLY_SET & GetPolyShape()
Bezier Curve.
bool close_enough(const wxPoint &aLeft, const wxPoint &aRight, unsigned aLimit)
Function close_enough is a local and tunable method of qualifying the proximity of two points.
int NewOutline()
Creates a new empty polygon in the set and returns its index
#define _(s)
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
void Collect(BOARD_ITEM *aBoard, const KICAD_T aScanList[])
Collect BOARD_ITEM objects using this class's Inspector method, which does the collection.
Definition: collectors.cpp:514
int GetHeight() const
Definition: eda_rect.h:120
int GetWidth() const
double GetAngle() const
Class to handle a graphic segment.
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:161
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
size_t i
Definition: json11.cpp:597
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
static DRAWSEGMENT * findPoint(const wxPoint &aPoint, std::vector< DRAWSEGMENT * > &aList, unsigned aLimit)
Searches for a DRAWSEGMENT matching a given end point or start point in a list, and if found,...
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
static void reverse(privcurve_t *curve)
Definition: trace.cpp:1025
static bool GetLayer(MODEL_VRML &aModel, LAYER_NUM layer, VRML_LAYER **vlayer)
EDA_RECT ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Function ComputeBoundingBox calculates the bounding box containing all board items (or board edge seg...
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Module description (excepted pads)
Collect all BOARD_ITEM objects of a given set of KICAD_T type(s).
Definition: collectors.h:621
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
const wxPoint GetPosition() const override
Definition: class_module.h:197
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
wxString StringFromValue(EDA_UNITS_T aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:217
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)