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 1382 of file class_module.cpp.

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

Referenced by MODULE::CoverageRatio().

1383 {
1384  aPolySet.NewOutline();
1385 
1386  aPolySet.Append( aRect.GetX(), aRect.GetY() );
1387  aPolySet.Append( aRect.GetX()+aRect.width, aRect.GetY() );
1388  aPolySet.Append( aRect.GetX()+aRect.width, aRect.GetY()+aRect.height );
1389  aPolySet.Append( aRect.GetX(), aRect.GetY()+aRect.height );
1390 }
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(), BOARD_ITEM::FormatInternalUnits(), FROM_UTF8(), DRAWSEGMENT::GetAngle(), DRAWSEGMENT::GetArcEnd(), DRAWSEGMENT::GetArcStart(), GetArcToSegmentCount(), DRAWSEGMENT::GetCenter(), GetChars(), DRAWSEGMENT::GetEnd(), DRAWSEGMENT::GetRadius(), DRAWSEGMENT::GetShape(), DRAWSEGMENT::GetStart(), i, SHAPE_POLY_SET::NewHole(), SHAPE_POLY_SET::NewOutline(), RotatePoint(), S_ARC, S_CIRCLE, S_SEGMENT, BOARD_ITEM::ShowShape(), 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  default:
268  break;
269  }
270  }
271 
272  // Grab the left most point, assume its on the board's perimeter, and see if we
273  // can put enough graphics together by matching endpoints to formulate a cohesive
274  // polygon.
275 
276  graphic = (DRAWSEGMENT*) segList[xmini];
277 
278  // The first DRAWSEGMENT is in 'graphic', ok to remove it from 'items'
279  segList.erase( segList.begin() + xmini );
280 
281  // Output the Edge.Cuts perimeter as circle or polygon.
282  if( graphic->GetShape() == S_CIRCLE )
283  {
284  int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_LOW_DEF, 360.0 );
285  TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), steps );
286  }
287  else
288  {
289  // Polygon start point. Arbitrarily chosen end of the
290  // segment and build the poly from here.
291 
292  wxPoint startPt = wxPoint( graphic->GetEnd() );
293  prevPt = graphic->GetEnd();
294  aPolygons.NewOutline();
295  aPolygons.Append( prevPt );
296 
297  // Do not append the other end point yet of this 'graphic', this first
298  // 'graphic' might be an arc.
299 
300  for(;;)
301  {
302  switch( graphic->GetShape() )
303  {
304  case S_SEGMENT:
305  {
306  wxPoint nextPt;
307 
308  // Use the line segment end point furthest away from
309  // prevPt as we assume the other end to be ON prevPt or
310  // very close to it.
311 
312  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
313  nextPt = graphic->GetEnd();
314  else
315  nextPt = graphic->GetStart();
316 
317  aPolygons.Append( nextPt );
318  prevPt = nextPt;
319  }
320  break;
321 
322  case S_ARC:
323  // We do not support arcs in polygons, so approximate
324  // an arc with a series of short lines and put those
325  // line segments into the !same! PATH.
326  {
327  wxPoint pstart = graphic->GetArcStart();
328  wxPoint pend = graphic->GetArcEnd();
329  wxPoint pcenter = graphic->GetCenter();
330  double angle = -graphic->GetAngle();
331  double radius = graphic->GetRadius();
332  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );
333 
334  if( !close_enough( prevPt, pstart, aTolerance ) )
335  {
336  wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
337 
338  angle = -angle;
339  std::swap( pstart, pend );
340  }
341 
342  wxPoint nextPt;
343 
344  for( int step = 1; step<=steps; ++step )
345  {
346  double rotation = ( angle * step ) / steps;
347  nextPt = pstart;
348  RotatePoint( &nextPt, pcenter, rotation );
349 
350  aPolygons.Append( nextPt );
351  }
352 
353  prevPt = nextPt;
354  }
355  break;
356 
357  default:
358  if( aErrorText )
359  {
360  msg.Printf( _( "Unsupported DRAWSEGMENT type %s" ),
361  GetChars( BOARD_ITEM::ShowShape( graphic->GetShape() ) ) );
362 
363  *aErrorText << msg << "\n";
364  }
365 
366  return false;
367  }
368 
369  // Get next closest segment.
370 
371  graphic = findPoint( prevPt, segList, aTolerance );
372 
373  // If there are no more close segments, check if the board
374  // outline polygon can be closed.
375 
376  if( !graphic )
377  {
378  if( close_enough( startPt, prevPt, aTolerance ) )
379  {
380  // Close the polygon back to start point
381  // aPolygons.Append( startPt ); // not needed
382  }
383  else
384  {
385  if( aErrorText )
386  {
387  msg.Printf(
388  _( "Unable to find the next boundary segment with an endpoint of (%s mm, %s mm). "
389  "graphic outline must form a contiguous, closed polygon." ),
390  GetChars( FROM_UTF8( BOARD_ITEM::FormatInternalUnits( prevPt.x ).c_str() ) ),
391  GetChars( FROM_UTF8( BOARD_ITEM::FormatInternalUnits( prevPt.y ).c_str() ) )
392  );
393 
394  *aErrorText << msg << "\n";
395  }
396 
397  return false;
398  }
399  break;
400  }
401  }
402  }
403 
404  while( segList.size() )
405  {
406  // emit a signal layers keepout for every interior polygon left...
407  int hole = aPolygons.NewHole();
408 
409  graphic = (DRAWSEGMENT*) segList[0];
410  segList.erase( segList.begin() );
411 
412  if( graphic->GetShape() == S_CIRCLE )
413  {
414  // make a circle by segments;
415  wxPoint center = graphic->GetCenter();
416  double angle = 3600.0;
417  wxPoint start = center;
418  int radius = graphic->GetRadius();
419  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 );
420  wxPoint nextPt;
421 
422  start.x += radius;
423 
424  for( int step = 0; step < steps; ++step )
425  {
426  double rotation = ( angle * step ) / steps;
427  nextPt = start;
428  RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
429  aPolygons.Append( nextPt, -1, hole );
430  }
431  }
432  else
433  {
434  // Polygon start point. Arbitrarily chosen end of the
435  // segment and build the poly from here.
436 
437  wxPoint startPt( graphic->GetEnd() );
438  prevPt = graphic->GetEnd();
439  aPolygons.Append( prevPt, -1, hole );
440 
441  // do not append the other end point yet, this first 'graphic' might be an arc
442  for(;;)
443  {
444  switch( graphic->GetShape() )
445  {
446  case S_SEGMENT:
447  {
448  wxPoint nextPt;
449 
450  // Use the line segment end point furthest away from
451  // prevPt as we assume the other end to be ON prevPt or
452  // very close to it.
453 
454  if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
455  {
456  nextPt = graphic->GetEnd();
457  }
458  else
459  {
460  nextPt = graphic->GetStart();
461  }
462 
463  prevPt = nextPt;
464  aPolygons.Append( prevPt, -1, hole );
465  }
466  break;
467 
468  case S_ARC:
469  // Freerouter does not yet understand arcs, so approximate
470  // an arc with a series of short lines and put those
471  // line segments into the !same! PATH.
472  {
473  wxPoint pstart = graphic->GetArcStart();
474  wxPoint pend = graphic->GetArcEnd();
475  wxPoint pcenter = graphic->GetCenter();
476  double angle = -graphic->GetAngle();
477  int radius = graphic->GetRadius();
478  int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );
479 
480  if( !close_enough( prevPt, pstart, aTolerance ) )
481  {
482  wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );
483 
484  angle = -angle;
485  std::swap( pstart, pend );
486  }
487 
488  wxPoint nextPt;
489 
490  for( int step = 1; step <= steps; ++step )
491  {
492  double rotation = ( angle * step ) / steps;
493 
494  nextPt = pstart;
495  RotatePoint( &nextPt, pcenter, rotation );
496 
497  aPolygons.Append( nextPt, -1, hole );
498  }
499 
500  prevPt = nextPt;
501  }
502  break;
503 
504  default:
505  if( aErrorText )
506  {
507  msg.Printf( _( "Unsupported DRAWSEGMENT type %s" ),
508  GetChars( BOARD_ITEM::ShowShape( graphic->GetShape() ) ) );
509 
510  *aErrorText << msg << "\n";
511  }
512 
513  return false;
514  }
515 
516  // Get next closest segment.
517 
518  graphic = findPoint( prevPt, segList, aTolerance );
519 
520  // If there are no more close segments, check if polygon
521  // can be closed.
522 
523  if( !graphic )
524  {
525  if( close_enough( startPt, prevPt, aTolerance ) )
526  {
527  // Close the polygon back to start point
528  // aPolygons.Append( startPt, -1, hole ); // not needed
529  }
530  else
531  {
532  if( aErrorText )
533  {
534  msg.Printf(
535  _( "Unable to find the next graphic segment with an endpoint of (%s mm, %s mm).\n"
536  "Edit graphics, making them contiguous polygons each." ),
537  GetChars( FROM_UTF8( BOARD_ITEM::FormatInternalUnits( prevPt.x ).c_str() ) ),
538  GetChars( FROM_UTF8( BOARD_ITEM::FormatInternalUnits( prevPt.y ).c_str() ) )
539  );
540 
541  *aErrorText << msg << "\n";
542  }
543 
544  return false;
545  }
546  break;
547  }
548  }
549  }
550  }
551 
552  return true;
553 }
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.
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
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...
usual segment : line with rounded ends
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
static std::string FormatInternalUnits(int aValue)
Function FormatInternalUnits converts aValue from board internal units to a string appropriate for wr...
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)
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
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
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...
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 1366 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().

1367 {
1368  double area = 0.0;
1369  for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
1370  {
1371  SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
1372  // Ensure the curr outline is closed, to calculate area
1373  outline.SetClosed( true );
1374 
1375  area += outline.Area();
1376  }
1377 
1378  return area;
1379 }
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