KiCad PCB EDA Suite
class_module.cpp File Reference

MODULE class implementation. More...

#include <fctsys.h>
#include <gr_basic.h>
#include <plotter.h>
#include <class_drawpanel.h>
#include <trigo.h>
#include <confirm.h>
#include <kicad_string.h>
#include <pcbnew.h>
#include <richio.h>
#include <filter_reader.h>
#include <macros.h>
#include <msgpanel.h>
#include <bitmaps.h>
#include <unordered_set>
#include <pcb_edit_frame.h>
#include <class_board.h>
#include <class_edge_mod.h>
#include <class_module.h>
#include <convert_basic_shapes_to_polygon.h>
#include <view/view.h>

Go to the source code of this file.

Functions

static double polygonArea (SHAPE_POLY_SET &aPolySet)
 
static void addRect (SHAPE_POLY_SET &aPolySet, wxRect aRect)
 
bool ConvertOutlineToPolygon (std::vector< DRAWSEGMENT * > &aSegList, SHAPE_POLY_SET &aPolygons, wxString *aErrorText, unsigned int aTolerance)
 Function ConvertOutlineToPolygon build a polygon (with holes) from a DRAWSEGMENT list, which is expected to be a outline, therefore a closed main outline with perhaps closed inner outlines. More...
 

Detailed Description

MODULE class implementation.

TEXT_MODULE class implementation.

Definition in file class_module.cpp.

Function Documentation

static void addRect ( SHAPE_POLY_SET aPolySet,
wxRect  aRect 
)
static

Definition at line 1391 of file class_module.cpp.

References SHAPE_POLY_SET::Append(), and SHAPE_POLY_SET::NewOutline().

Referenced by MODULE::CoverageRatio().

1392 {
1393  aPolySet.NewOutline();
1394 
1395  aPolySet.Append( aRect.GetX(), aRect.GetY() );
1396  aPolySet.Append( aRect.GetX()+aRect.width, aRect.GetY() );
1397  aPolySet.Append( aRect.GetX()+aRect.width, aRect.GetY()+aRect.height );
1398  aPolySet.Append( aRect.GetX(), aRect.GetY()+aRect.height );
1399 }
int NewOutline()
Creates a new empty polygon in the set and returns its index
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) ...
bool ConvertOutlineToPolygon ( std::vector< DRAWSEGMENT * > &  aSegList,
SHAPE_POLY_SET aPolygons,
wxString *  aErrorText,
unsigned int  aTolerance 
)

Function ConvertOutlineToPolygon build a polygon (with holes) from a DRAWSEGMENT list, which is expected to be a outline, therefore a closed main outline with perhaps closed inner outlines.

These closed inner outlines are considered as holes in the main outline

Parameters
aSegListthe initial list of drawsegments (only lines, circles and arcs).
aPolygonswill contain the complex polygon.
aToleranceis the max distance between points that is still accepted as connected (internal units)
aErrorTextis a wxString to return error message.

Definition at line 181 of file convert_drawsegment_list_to_polygon.cpp.

References PNS::angle(), SHAPE_POLY_SET::Append(), close_enough(), close_st(), findPoint(), DRAWSEGMENT::GetAngle(), DRAWSEGMENT::GetArcEnd(), DRAWSEGMENT::GetArcStart(), GetArcToSegmentCount(), DRAWSEGMENT::GetBezierPoints(), DRAWSEGMENT::GetCenter(), DRAWSEGMENT::GetEnd(), DRAWSEGMENT::GetRadius(), DRAWSEGMENT::GetShape(), DRAWSEGMENT::GetStart(), DRAWSEGMENT::GetWidth(), i, MILLIMETRES, SHAPE_POLY_SET::NewHole(), SHAPE_POLY_SET::NewOutline(), DRAWSEGMENT::RebuildBezierToSegmentsPointsList(), reverse(), RotatePoint(), S_ARC, S_CIRCLE, S_CURVE, S_SEGMENT, BOARD_ITEM::ShowShape(), StringFromValue(), TransformCircleToPolygon(), wxPoint::x, and wxPoint::y.

Referenced by BuildBoardPolygonOutlines(), MODULE::BuildPolyCourtyard(), and MODULE::CoverageRatio().

183 {
184  if( aSegList.size() == 0 )
185  return true;
186 
187  wxString msg;
188 
189  // Make a working copy of aSegList, because the list is modified during calculations
190  std::vector< DRAWSEGMENT* > segList = aSegList;
191 
192  DRAWSEGMENT* graphic;
193  wxPoint prevPt;
194 
195  // Find edge point with minimum x, this should be in the outer polygon
196  // which will define the perimeter Edge.Cuts polygon.
197  wxPoint xmin = wxPoint( INT_MAX, 0 );
198  int xmini = 0;
199 
200  for( size_t i = 0; i < segList.size(); i++ )
201  {
202  graphic = (DRAWSEGMENT*) segList[i];
203 
204  switch( graphic->GetShape() )
205  {
206  case S_SEGMENT:
207  {
208  if( graphic->GetStart().x < xmin.x )
209  {
210  xmin = graphic->GetStart();
211  xmini = i;
212  }
213 
214  if( graphic->GetEnd().x < xmin.x )
215  {
216  xmin = graphic->GetEnd();
217  xmini = i;
218  }
219  }
220  break;
221 
222  case S_ARC:
223  // Freerouter does not yet understand arcs, so approximate
224  // an arc with a series of short lines and put those
225  // line segments into the !same! PATH.
226  {
227  wxPoint pstart = graphic->GetArcStart();
228  wxPoint center = graphic->GetCenter();
229  double angle = -graphic->GetAngle();
230  double radius = graphic->GetRadius();
231  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );
232  wxPoint pt;
233 
234  for( int step = 1; step<=steps; ++step )
235  {
236  double rotation = ( angle * step ) / steps;
237 
238  pt = pstart;
239 
240  RotatePoint( &pt, center, rotation );
241 
242  if( pt.x < xmin.x )
243  {
244  xmin = pt;
245  xmini = i;
246  }
247  }
248  }
249  break;
250 
251  case S_CIRCLE:
252  {
253  wxPoint pt = graphic->GetCenter();
254 
255  // pt has minimum x point
256  pt.x -= graphic->GetRadius();
257 
258  // when the radius <= 0, this is a mal-formed circle. Skip it
259  if( graphic->GetRadius() > 0 && pt.x < xmin.x )
260  {
261  xmin = pt;
262  xmini = i;
263  }
264  }
265  break;
266 
267  case S_CURVE:
268  {
269  graphic->RebuildBezierToSegmentsPointsList( graphic->GetWidth() );
270 
271  for( unsigned int jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
272  {
273  wxPoint pt = graphic->GetBezierPoints()[jj];
274 
275  if( pt.x < xmin.x )
276  {
277  xmin = pt;
278  xmini = i;
279  }
280  }
281  }
282  break;
283 
284  default:
285  break;
286  }
287  }
288 
289  // Grab the left most point, assume its on the board's perimeter, and see if we
290  // can put enough graphics together by matching endpoints to formulate a cohesive
291  // polygon.
292 
293  graphic = (DRAWSEGMENT*) segList[xmini];
294 
295  // The first DRAWSEGMENT is in 'graphic', ok to remove it from 'items'
296  segList.erase( segList.begin() + xmini );
297 
298  // Output the Edge.Cuts perimeter as circle or polygon.
299  if( graphic->GetShape() == S_CIRCLE )
300  {
301  int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_LOW_DEF, 360.0 );
302  TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), steps );
303  }
304  else
305  {
306  // Polygon start point. Arbitrarily chosen end of the
307  // segment and build the poly from here.
308 
309  wxPoint startPt = wxPoint( graphic->GetEnd() );
310  prevPt = graphic->GetEnd();
311  aPolygons.NewOutline();
312  aPolygons.Append( prevPt );
313 
314  // Do not append the other end point yet of this 'graphic', this first
315  // 'graphic' might be an arc or a curve.
316 
317  for(;;)
318  {
319  switch( graphic->GetShape() )
320  {
321  case S_SEGMENT:
322  {
323  wxPoint nextPt;
324 
325  // Use the line segment end point furthest away from
326  // prevPt as we assume the other end to be ON prevPt or
327  // very close to it.
328 
329  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
330  nextPt = graphic->GetEnd();
331  else
332  nextPt = graphic->GetStart();
333 
334  aPolygons.Append( nextPt );
335  prevPt = nextPt;
336  }
337  break;
338 
339  case S_ARC:
340  // We do not support arcs in polygons, so approximate
341  // an arc with a series of short lines and put those
342  // line segments into the !same! PATH.
343  {
344  wxPoint pstart = graphic->GetArcStart();
345  wxPoint pend = graphic->GetArcEnd();
346  wxPoint pcenter = graphic->GetCenter();
347  double angle = -graphic->GetAngle();
348  double radius = graphic->GetRadius();
349  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );
350 
351  if( !close_enough( prevPt, pstart, aTolerance ) )
352  {
353  wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
354 
355  angle = -angle;
356  std::swap( pstart, pend );
357  }
358 
359  wxPoint nextPt;
360 
361  for( int step = 1; step<=steps; ++step )
362  {
363  double rotation = ( angle * step ) / steps;
364  nextPt = pstart;
365  RotatePoint( &nextPt, pcenter, rotation );
366 
367  aPolygons.Append( nextPt );
368  }
369 
370  prevPt = nextPt;
371  }
372  break;
373 
374  case S_CURVE:
375  // We do not support Bezier curves in polygons, so approximate
376  // with a series of short lines and put those
377  // line segments into the !same! PATH.
378  {
379  wxPoint nextPt;
380  bool reverse = false;
381 
382  // Use the end point furthest away from
383  // prevPt as we assume the other end to be ON prevPt or
384  // very close to it.
385 
386  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
387  nextPt = graphic->GetEnd();
388  else
389  {
390  nextPt = graphic->GetStart();
391  reverse = true;
392  }
393 
394  if( reverse )
395  {
396  for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
397  aPolygons.Append( graphic->GetBezierPoints()[jj] );
398  }
399  else
400  {
401  for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
402  aPolygons.Append( graphic->GetBezierPoints()[jj] );
403  }
404 
405  prevPt = nextPt;
406  }
407  break;
408 
409  default:
410  if( aErrorText )
411  {
412  msg.Printf( "Unsupported DRAWSEGMENT type %s.",
413  BOARD_ITEM::ShowShape( graphic->GetShape() ) );
414 
415  *aErrorText << msg << "\n";
416  }
417 
418  return false;
419  }
420 
421  // Get next closest segment.
422 
423  graphic = findPoint( prevPt, segList, aTolerance );
424 
425  // If there are no more close segments, check if the board
426  // outline polygon can be closed.
427 
428  if( !graphic )
429  {
430  if( close_enough( startPt, prevPt, aTolerance ) )
431  {
432  // Close the polygon back to start point
433  // aPolygons.Append( startPt ); // not needed
434  }
435  else
436  {
437  if( aErrorText )
438  {
439  msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ),
440  StringFromValue( MILLIMETRES, prevPt.x, true ),
441  StringFromValue( MILLIMETRES, prevPt.y, true ) );
442 
443  *aErrorText << msg << "\n";
444  }
445 
446  return false;
447  }
448  break;
449  }
450  }
451  }
452 
453  while( segList.size() )
454  {
455  // emit a signal layers keepout for every interior polygon left...
456  int hole = aPolygons.NewHole();
457 
458  graphic = (DRAWSEGMENT*) segList[0];
459  segList.erase( segList.begin() );
460 
461  if( graphic->GetShape() == S_CIRCLE )
462  {
463  // make a circle by segments;
464  wxPoint center = graphic->GetCenter();
465  double angle = 3600.0;
466  wxPoint start = center;
467  int radius = graphic->GetRadius();
468  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 );
469  wxPoint nextPt;
470 
471  start.x += radius;
472 
473  for( int step = 0; step < steps; ++step )
474  {
475  double rotation = ( angle * step ) / steps;
476  nextPt = start;
477  RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
478  aPolygons.Append( nextPt, -1, hole );
479  }
480  }
481  else
482  {
483  // Polygon start point. Arbitrarily chosen end of the
484  // segment and build the poly from here.
485 
486  wxPoint startPt( graphic->GetEnd() );
487  prevPt = graphic->GetEnd();
488  aPolygons.Append( prevPt, -1, hole );
489 
490  // do not append the other end point yet, this first 'graphic' might be an arc
491  for(;;)
492  {
493  switch( graphic->GetShape() )
494  {
495  case S_SEGMENT:
496  {
497  wxPoint nextPt;
498 
499  // Use the line segment end point furthest away from
500  // prevPt as we assume the other end to be ON prevPt or
501  // very close to it.
502 
503  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
504  {
505  nextPt = graphic->GetEnd();
506  }
507  else
508  {
509  nextPt = graphic->GetStart();
510  }
511 
512  prevPt = nextPt;
513  aPolygons.Append( prevPt, -1, hole );
514  }
515  break;
516 
517  case S_ARC:
518  // Freerouter does not yet understand arcs, so approximate
519  // an arc with a series of short lines and put those
520  // line segments into the !same! PATH.
521  {
522  wxPoint pstart = graphic->GetArcStart();
523  wxPoint pend = graphic->GetArcEnd();
524  wxPoint pcenter = graphic->GetCenter();
525  double angle = -graphic->GetAngle();
526  int radius = graphic->GetRadius();
527  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );
528 
529  if( !close_enough( prevPt, pstart, aTolerance ) )
530  {
531  wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
532 
533  angle = -angle;
534  std::swap( pstart, pend );
535  }
536 
537  wxPoint nextPt;
538 
539  for( int step = 1; step <= steps; ++step )
540  {
541  double rotation = ( angle * step ) / steps;
542 
543  nextPt = pstart;
544  RotatePoint( &nextPt, pcenter, rotation );
545 
546  aPolygons.Append( nextPt, -1, hole );
547  }
548 
549  prevPt = nextPt;
550  }
551  break;
552 
553  case S_CURVE:
554  // We do not support Bezier curves in polygons, so approximate
555  // with a series of short lines and put those
556  // line segments into the !same! PATH.
557  {
558  wxPoint nextPt;
559  bool reverse = false;
560 
561  // Use the end point furthest away from
562  // prevPt as we assume the other end to be ON prevPt or
563  // very close to it.
564 
565  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
566  nextPt = graphic->GetEnd();
567  else
568  {
569  nextPt = graphic->GetStart();
570  reverse = true;
571  }
572 
573  if( reverse )
574  {
575  for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
576  aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole );
577  }
578  else
579  {
580  for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
581  aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole );
582  }
583 
584  prevPt = nextPt;
585  }
586  break;
587 
588  default:
589  if( aErrorText )
590  {
591  msg.Printf( "Unsupported DRAWSEGMENT type %s.",
592  BOARD_ITEM::ShowShape( graphic->GetShape() ) );
593 
594  *aErrorText << msg << "\n";
595  }
596 
597  return false;
598  }
599 
600  // Get next closest segment.
601 
602  graphic = findPoint( prevPt, segList, aTolerance );
603 
604  // If there are no more close segments, check if polygon
605  // can be closed.
606 
607  if( !graphic )
608  {
609  if( close_enough( startPt, prevPt, aTolerance ) )
610  {
611  // Close the polygon back to start point
612  // aPolygons.Append( startPt, -1, hole ); // not needed
613  }
614  else
615  {
616  if( aErrorText )
617  {
618  msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ),
619  StringFromValue( MILLIMETRES, prevPt.x, true ),
620  StringFromValue( MILLIMETRES, prevPt.y, true ) );
621 
622  *aErrorText << msg << "\n";
623  }
624 
625  return false;
626  }
627  break;
628  }
629  }
630  }
631  }
632 
633  return true;
634 }
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.
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
const wxPoint GetCenter() const override
Function GetCenter()
void TransformCircleToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCenter, int aRadius, int aCircleToSegmentsCount)
Function TransformCircleToPolygon convert a circle to a polygon, using multiple straight lines...
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_BezierPoints vertex list that approximate the Bezier curve by a list of segments Has me...
usual segment : line with rounded ends
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
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...
const wxPoint & GetArcStart() const
STROKE_T GetShape() const
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
Arcs (with rounded ends)
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
const std::vector< wxPoint > & GetBezierPoints() const
double GetAngle() const
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
size_t i
Definition: json11.cpp:597
const wxPoint GetArcEnd() const
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...
static void reverse(privcurve_t *curve)
Definition: trace.cpp:1025
int GetWidth() const
wxString StringFromValue(EDA_UNITS_T aUnits, int aValue, bool aAddUnitSymbol, bool aUseMils)
Function StringFromValue returns the string from aValue according to units (inch, mm ...
Definition: base_units.cpp:210
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
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) ...
static double polygonArea ( SHAPE_POLY_SET aPolySet)
static

Definition at line 1375 of file class_module.cpp.

References SHAPE_LINE_CHAIN::Area(), SHAPE_POLY_SET::Outline(), SHAPE_POLY_SET::OutlineCount(), and SHAPE_LINE_CHAIN::SetClosed().

Referenced by MODULE::CoverageRatio().

1376 {
1377  double area = 0.0;
1378  for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
1379  {
1380  SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
1381  // Ensure the curr outline is closed, to calculate area
1382  outline.SetClosed( true );
1383 
1384  area += outline.Area();
1385  }
1386 
1387  return area;
1388 }
int OutlineCount() const
Returns the number of outlines in the set
void SetClosed(bool aClosed)
Function SetClosed()
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
Class SHAPE_LINE_CHAIN.
double Area() const