KiCad PCB EDA Suite
convert_basic_shapes_to_polygon.h File Reference
#include <geometry/shape_poly_set.h>
#include <geometry/geometry_utils.h>
#include <wx/gdicmn.h>

Go to the source code of this file.

Enumerations

enum  RECT_CHAMFER_POSITIONS : int {
  RECT_NO_CHAMFER = 0, RECT_CHAMFER_TOP_LEFT = 1, RECT_CHAMFER_TOP_RIGHT = 2, RECT_CHAMFER_BOTTOM_LEFT = 4,
  RECT_CHAMFER_BOTTOM_RIGHT = 8, RECT_CHAMFER_ALL
}
 

Functions

int ConvertArcToPolyline (SHAPE_LINE_CHAIN &aPolyline, VECTOR2I aCenter, int aRadius, double aStartAngleDeg, double aArcAngleDeg, double aAccuracy, ERROR_LOC aErrorLoc)
 Generate a polyline to approximate a arc. More...
 
void TransformCircleToPolygon (SHAPE_LINE_CHAIN &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
 Convert a circle to a polygon, using multiple straight lines. More...
 
void TransformCircleToPolygon (SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
 Convert a circle to a polygon, using multiple straight lines. More...
 
void TransformOvalToPolygon (SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aStart, const wxPoint &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
 Convert a oblong shape to a polygon, using multiple segments. More...
 
void TransformTrapezoidToPolygon (SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aDeltaX, int aDeltaY, int aInflate, int aError, ERROR_LOC aErrorLoc)
 Convert a rectangle or trapezoid to a polygon. More...
 
void TransformRoundChamferedRectToPolygon (SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
 Convert a rectangle with rounded corners and/or chamfered corners to a polygon. More...
 
void TransformArcToPolygon (SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aStart, const wxPoint &aMid, const wxPoint &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
 Convert arc to multiple straight segments. More...
 
void TransformRingToPolygon (SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
 Convert arcs to multiple straight segments. More...
 

Enumeration Type Documentation

◆ RECT_CHAMFER_POSITIONS

Function Documentation

◆ ConvertArcToPolyline()

int ConvertArcToPolyline ( SHAPE_LINE_CHAIN aPolyline,
VECTOR2I  aCenter,
int  aRadius,
double  aStartAngleDeg,
double  aArcAngleDeg,
double  aAccuracy,
ERROR_LOC  aErrorLoc 
)

Generate a polyline to approximate a arc.

Parameters
aPolylineis a buffer to store the polyline.
aCenteris the center of the arc.
aRadiusis the radius of the arc.
aStartAngleDegis the starting point (in degrees) of the arc.
aArcAngleDegis the angle (in degrees) of the arc.
aErroris the internal units allowed for error approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.

Definition at line 503 of file convert_basic_shapes_to_polygon.cpp.

506 {
507  double endAngle = aStartAngleDeg + aArcAngleDeg;
508  int n = 2;
509 
510  if( aRadius >= aAccuracy )
511  n = GetArcToSegmentCount( aRadius, aAccuracy, aArcAngleDeg )+1; // n >= 3
512 
513  if( aErrorLoc == ERROR_OUTSIDE )
514  {
515  int seg360 = std::abs( KiROUND( n * 360.0 / aArcAngleDeg ) );
516  int actual_delta_radius = CircleToEndSegmentDeltaRadius( aRadius, seg360 );
517  aRadius += actual_delta_radius;
518  }
519 
520  for( int i = 0; i <= n ; i++ )
521  {
522  double rot = aStartAngleDeg;
523  rot += ( aArcAngleDeg * i ) / n;
524 
525  double x = aCenter.x + aRadius * cos( rot * M_PI / 180.0 );
526  double y = aCenter.y + aRadius * sin( rot * M_PI / 180.0 );
527 
528  aPolyline.Append( KiROUND( x ), KiROUND( y ) );
529  }
530 
531  return n;
532 }
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)

References SHAPE_LINE_CHAIN::Append(), CircleToEndSegmentDeltaRadius(), ERROR_OUTSIDE, GetArcToSegmentCount(), KiROUND(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by DSN::SPECCTRA_DB::makeIMAGE(), and TransformArcToPolygon().

◆ TransformArcToPolygon()

void TransformArcToPolygon ( SHAPE_POLY_SET aCornerBuffer,
const wxPoint &  aStart,
const wxPoint &  aMid,
const wxPoint &  aEnd,
int  aWidth,
int  aError,
ERROR_LOC  aErrorLoc 
)

Convert arc to multiple straight segments.

Parameters
aCornerBufferis a buffer to store the polygon.
aCentreis the center of the arc or circle.
aStartis the start point of the arc or a point on the circle.
aArcAngleis the arc angle in 0.1 degrees. For a circle, aArcAngle = 3600.
aWidthis the width (thickness) of the line.
aErroris the internal units allowed for error in approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.

We start by making rounded ends on the arc

Definition at line 535 of file convert_basic_shapes_to_polygon.cpp.

538 {
539  SEG startToEnd( aStart, aEnd );
540  int distanceToMid = startToEnd.Distance( aMid );
541 
542  if( distanceToMid <= 1 )
543  {
544  // Not an arc but essentially a straight line with a small error
545  TransformOvalToPolygon( aCornerBuffer, aStart, aEnd, aWidth + distanceToMid, aError,
546  aErrorLoc );
547  return;
548  }
549 
550  SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
551  // Currentlye have currently 2 algos:
552  // the first approximates the thick arc from its outlines
553  // the second approximates the thick arc from segments given by SHAPE_ARC
554  // using SHAPE_ARC::ConvertToPolyline
555  // The actual approximation errors are similar but not exactly the same.
556  //
557  // For now, both algorithms are kept, the second is the initial algo used in Kicad.
558 
559 #if 1
560  // This appproximation convert the 2 ends to polygons, arc outer to polyline
561  // and arc inner to polyline and merge shapes.
562  int radial_offset = ( aWidth + 1 ) / 2;
563 
564  SHAPE_POLY_SET polyshape;
565  std::vector<VECTOR2I> outside_pts;
566 
568  TransformCircleToPolygon( polyshape, aStart, radial_offset, aError, aErrorLoc );
569  TransformCircleToPolygon( polyshape, aEnd, radial_offset, aError, aErrorLoc );
570 
571  // The circle polygon is built with a even number of segments, so the
572  // horizontal diameter has 2 corners on the biggest diameter
573  // Rotate these 2 corners to match the start and ens points of inner and outer
574  // end points of the arc appoximation outlines, build below.
575  // The final shape is much better.
576  double arc_angle_start_deg = arc.GetStartAngle();
577  double arc_angle = arc.GetCentralAngle();
578  double arc_angle_end_deg = arc_angle_start_deg + arc_angle;
579 
580  if( arc_angle_start_deg != 0 && arc_angle_start_deg != 180.0 )
581  polyshape.Outline(0).Rotate( arc_angle_start_deg * M_PI/180.0, aStart );
582 
583  if( arc_angle_end_deg != 0 && arc_angle_end_deg != 180.0 )
584  polyshape.Outline(1).Rotate( arc_angle_end_deg * M_PI/180.0, aEnd );
585 
586  VECTOR2I center = arc.GetCenter();
587  int radius = arc.GetRadius();
588 
589  int arc_outer_radius = radius + radial_offset;
590  int arc_inner_radius = radius - radial_offset;
591  ERROR_LOC errorLocInner = ERROR_OUTSIDE;
592  ERROR_LOC errorLocOuter = ERROR_INSIDE;
593 
594  if( aErrorLoc == ERROR_OUTSIDE )
595  {
596  errorLocInner = ERROR_INSIDE;
597  errorLocOuter = ERROR_OUTSIDE;
598  }
599 
600  polyshape.NewOutline();
601 
602  ConvertArcToPolyline( polyshape.Outline(2), center, arc_outer_radius,
603  arc_angle_start_deg, arc_angle, aError, errorLocOuter );
604 
605  if( arc_inner_radius > 0 )
606  ConvertArcToPolyline( polyshape.Outline(2), center, arc_inner_radius,
607  arc_angle_end_deg, -arc_angle, aError, errorLocInner );
608  else
609  polyshape.Append( center );
610 #else
611  // This appproximation use SHAPE_ARC to convert the 2 ends to polygons,
612  // approximate arc to polyline, convert the polyline corners to outer and inner
613  // corners of outer and inner utliners and merge shapes.
614  double defaultErr;
615  SHAPE_LINE_CHAIN arcSpine = arc.ConvertToPolyline( SHAPE_ARC::DefaultAccuracyForPCB(),
616  &defaultErr);
617  int radius = arc.GetRadius();
618  int radial_offset = ( aWidth + 1 ) / 2;
619  SHAPE_POLY_SET polyshape;
620  std::vector<VECTOR2I> outside_pts;
621 
622  // delta is the effective error approximation to build a polyline from an arc
623  int segCnt360 = arcSpine.GetSegmentCount()*360.0/arc.GetCentralAngle();;
624  int delta = CircleToEndSegmentDeltaRadius( radius+radial_offset, std::abs(segCnt360) );
625 
627  TransformCircleToPolygon( polyshape, aStart, radial_offset, aError, aErrorLoc );
628  TransformCircleToPolygon( polyshape, aEnd, radial_offset, aError, aErrorLoc );
629 
630  // The circle polygon is built with a even number of segments, so the
631  // horizontal diameter has 2 corners on the biggest diameter
632  // Rotate these 2 corners to match the start and ens points of inner and outer
633  // end points of the arc appoximation outlines, build below.
634  // The final shape is much better.
635  double arc_angle_end_deg = arc.GetStartAngle();
636 
637  if( arc_angle_end_deg != 0 && arc_angle_end_deg != 180.0 )
638  polyshape.Outline(0).Rotate( arc_angle_end_deg * M_PI/180.0, arcSpine.GetPoint( 0 ) );
639 
640  arc_angle_end_deg = arc.GetEndAngle();
641 
642  if( arc_angle_end_deg != 0 && arc_angle_end_deg != 180.0 )
643  polyshape.Outline(1).Rotate( arc_angle_end_deg * M_PI/180.0, arcSpine.GetPoint( -1 ) );
644 
645  if( aErrorLoc == ERROR_OUTSIDE )
646  radial_offset += delta + defaultErr/2;
647  else
648  radial_offset -= defaultErr/2;
649 
650  if( radial_offset < 0 )
651  radial_offset = 0;
652 
653  polyshape.NewOutline();
654 
655  VECTOR2I center = arc.GetCenter();
656  int last_index = arcSpine.GetPointCount() -1;
657 
658  for( std::size_t ii = 0; ii <= last_index; ++ii )
659  {
660  VECTOR2I offset = arcSpine.GetPoint( ii ) - center;
661  int curr_rd = radius;
662 
663  polyshape.Append( offset.Resize( curr_rd - radial_offset ) + center );
664  outside_pts.emplace_back( offset.Resize( curr_rd + radial_offset ) + center );
665  }
666 
667  for( auto it = outside_pts.rbegin(); it != outside_pts.rend(); ++it )
668  polyshape.Append( *it );
669 #endif
670 
671  // Can be removed, but usefull to display the outline:
672  polyshape.Simplify( SHAPE_POLY_SET::PM_FAST );
673 
674  aCornerBuffer.Append( polyshape );
675 
676 }
virtual size_t GetSegmentCount() const override
virtual size_t GetPointCount() const override
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
Define a general 2D-vector/point.
Definition: vector2d.h:61
static double DefaultAccuracyForPCB()
Definition: shape_arc.h:220
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
void TransformOvalToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aStart, const wxPoint &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount)
Convert a oblong shape to a polygon, using multiple segments.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount)
Convert a circle to a polygon, using multiple straight lines.
void Simplify(POLYGON_MODE aFastMode)
int ConvertArcToPolyline(SHAPE_LINE_CHAIN &aPolyline, VECTOR2I aCenter, int aRadius, double aStartAngleDeg, double aArcAngleDeg, double aAccuracy, ERROR_LOC aErrorLoc)
Generate a polyline to approximate a arc.
int NewOutline()
Creates a new hole in a given outline.
virtual const VECTOR2I GetPoint(int aIndex) const override
void Rotate(double aAngle, const VECTOR2I &aCenter=VECTOR2I(0, 0)) override
Rotate all vertices by a given angle.
Definition: seg.h:40
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:404
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
constexpr int delta
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...

References SHAPE_POLY_SET::Append(), CircleToEndSegmentDeltaRadius(), ConvertArcToPolyline(), SHAPE_ARC::ConvertToPolyline(), SHAPE_ARC::DefaultAccuracyForPCB(), delta, SEG::Distance(), ERROR_INSIDE, ERROR_OUTSIDE, SHAPE_ARC::GetCenter(), SHAPE_ARC::GetCentralAngle(), SHAPE_ARC::GetEndAngle(), SHAPE_LINE_CHAIN::GetPoint(), SHAPE_LINE_CHAIN::GetPointCount(), SHAPE_ARC::GetRadius(), SHAPE_LINE_CHAIN::GetSegmentCount(), SHAPE_ARC::GetStartAngle(), SHAPE_POLY_SET::NewOutline(), SHAPE_POLY_SET::Outline(), SHAPE_POLY_SET::PM_FAST, VECTOR2< T >::Resize(), SHAPE_LINE_CHAIN::Rotate(), SHAPE_POLY_SET::Simplify(), TransformCircleToPolygon(), and TransformOvalToPolygon().

Referenced by BOOST_AUTO_TEST_CASE(), KIGFX::PCB_PAINTER::draw(), CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers(), PCB_TRACK::TransformShapeWithClearanceToPolygon(), and EDA_SHAPE::TransformShapeWithClearanceToPolygon().

◆ TransformCircleToPolygon() [1/2]

void TransformCircleToPolygon ( SHAPE_LINE_CHAIN aCornerBuffer,
const wxPoint &  aCenter,
int  aRadius,
int  aError,
ERROR_LOC  aErrorLoc,
int  aMinSegCount = 0 
)

Convert a circle to a polygon, using multiple straight lines.

Parameters
aCornerBufferis a buffer to store the polygon.
aCenteris the center of the circle.
aRadiusis the radius of the circle.
aErroris the internal units allowed for error approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.
aMinSegCountis the min count of segments to approximate. Default = 0 to do not force a min count.

Definition at line 42 of file convert_basic_shapes_to_polygon.cpp.

44 {
45  wxPoint corner_position;
46  int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 );
47  numSegs = std::max( aMinSegCount, numSegs );
48 
49  // The shape will be built with a even number of segs. Reason: the horizontal
50  // diameter begins and ends to points on the actual circle, or circle
51  // expanded by aError if aErrorLoc == ERROR_OUTSIDE.
52  // This is used by Arc to Polygon shape convert.
53  if( numSegs & 1 )
54  numSegs++;
55 
56  int delta = 3600 / numSegs; // rotate angle in 0.1 degree
57  int radius = aRadius;
58 
59  if( aErrorLoc == ERROR_OUTSIDE )
60  {
61  // The outer radius should be radius+aError
62  // Recalculate the actual approx error, as it can be smaller than aError
63  // because numSegs is clamped to a minimal value
64  int actual_delta_radius = CircleToEndSegmentDeltaRadius( radius, numSegs );
65  radius += GetCircleToPolyCorrection( actual_delta_radius );
66  }
67 
68  for( int angle = 0; angle < 3600; angle += delta )
69  {
70  corner_position.x = radius;
71  corner_position.y = 0;
72  RotatePoint( &corner_position, angle );
73  corner_position += aCenter;
74  aCornerBuffer.Append( corner_position.x, corner_position.y );
75  }
76 
77  aCornerBuffer.SetClosed( true );
78 }
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int GetCircleToPolyCorrection(int aMaxError)
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
constexpr int delta
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)

References PNS::angle(), SHAPE_LINE_CHAIN::Append(), CircleToEndSegmentDeltaRadius(), delta, ERROR_OUTSIDE, GetArcToSegmentCount(), GetCircleToPolyCorrection(), RotatePoint(), and SHAPE_LINE_CHAIN::SetClosed().

Referenced by ZONE_FILLER::addHatchFillTypeOnZone(), addHoleToPolygon(), ZONE_FILLER::buildCopperItemClearances(), ConvertOutlineToPolygon(), D_CODE::ConvertShapeToPolygon(), BOARD_ADAPTER::createLayers(), AM_PRIMITIVE::DrawBasicShape(), DSN::SPECCTRA_DB::makeIMAGE(), CONVERT_TOOL::makePolysFromCircles(), PAD::MergePrimitivesAsPolygon(), TransformArcToPolygon(), TransformRingToPolygon(), PCB_TRACK::TransformShapeWithClearanceToPolygon(), PCB_DIMENSION_BASE::TransformShapeWithClearanceToPolygon(), EDA_SHAPE::TransformShapeWithClearanceToPolygon(), and PAD::TransformShapeWithClearanceToPolygon().

◆ TransformCircleToPolygon() [2/2]

void TransformCircleToPolygon ( SHAPE_POLY_SET aCornerBuffer,
const wxPoint &  aCenter,
int  aRadius,
int  aError,
ERROR_LOC  aErrorLoc,
int  aMinSegCount = 0 
)

Convert a circle to a polygon, using multiple straight lines.

Parameters
aCornerBufferis a buffer to store the polygon.
aCenteris the center of the circle.
aRadiusis the radius of the circle.
aErroris the internal units allowed for error in approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.
aMinSegCountis the min count of segments to approximate. Default = 0 to do not force a min count.

Definition at line 81 of file convert_basic_shapes_to_polygon.cpp.

83 {
84  wxPoint corner_position;
85  int numSegs = GetArcToSegmentCount( aRadius, aError, 360.0 );
86  numSegs = std::max( aMinSegCount, numSegs);
87 
88  // The shape will be built with a even number of segs. Reason: the horizontal
89  // diameter begins and ends to points on the actual circle, or circle
90  // expanded by aError if aErrorLoc == ERROR_OUTSIDE.
91  // This is used by Arc to Polygon shape convert.
92  if( numSegs & 1 )
93  numSegs++;
94 
95  int delta = 3600 / numSegs; // rotate angle in 0.1 degree
96  int radius = aRadius;
97 
98  if( aErrorLoc == ERROR_OUTSIDE )
99  {
100  // The outer radius should be radius+aError
101  // Recalculate the actual approx error, as it can be smaller than aError
102  // because numSegs is clamped to a minimal value
103  int actual_delta_radius = CircleToEndSegmentDeltaRadius( radius, numSegs );
104  radius += GetCircleToPolyCorrection( actual_delta_radius );
105  }
106 
107  aCornerBuffer.NewOutline();
108 
109  for( int angle = 0; angle < 3600; angle += delta )
110  {
111  corner_position.x = radius;
112  corner_position.y = 0;
113  RotatePoint( &corner_position, angle );
114  corner_position += aCenter;
115  aCornerBuffer.Append( corner_position.x, corner_position.y );
116  }
117 
118  // Finish circle
119  corner_position.x = radius;
120  corner_position.y = 0;
121  corner_position += aCenter;
122  aCornerBuffer.Append( corner_position.x, corner_position.y );
123 }
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
int GetCircleToPolyCorrection(int aMaxError)
int NewOutline()
Creates a new hole in a given outline.
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
constexpr int delta
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...

References PNS::angle(), SHAPE_POLY_SET::Append(), CircleToEndSegmentDeltaRadius(), delta, ERROR_OUTSIDE, GetArcToSegmentCount(), GetCircleToPolyCorrection(), SHAPE_POLY_SET::NewOutline(), and RotatePoint().

◆ TransformOvalToPolygon()

void TransformOvalToPolygon ( SHAPE_POLY_SET aCornerBuffer,
const wxPoint &  aStart,
const wxPoint &  aEnd,
int  aWidth,
int  aError,
ERROR_LOC  aErrorLoc,
int  aMinSegCount = 0 
)

Convert a oblong shape to a polygon, using multiple segments.

It is similar to TransformRoundedEndsSegmentToPolygon, but the polygon is outside the actual oblong shape (a segment with rounded ends). It is suitable to create oblong clearance areas because multiple segments create a smaller area than the circle. The radius of the circle to approximate must be bigger ( radius*aCorrectionFactor) to create segments outside the circle.

Parameters
aCornerBufferis a buffer to store the polygon.
aStartis the first point of the segment.
aEndis the second point of the segment.
aWidthis the width of the segment.
aErroris the internal units allowed for error in approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.
aMinSegCountis the min count of segments to approximate. Default = 0 to do not force a min count.

Definition at line 126 of file convert_basic_shapes_to_polygon.cpp.

129 {
130  // To build the polygonal shape outside the actual shape, we use a bigger
131  // radius to build rounded ends.
132  // However, the width of the segment is too big.
133  // so, later, we will clamp the polygonal shape with the bounding box
134  // of the segment.
135  int radius = aWidth / 2;
136  int numSegs = GetArcToSegmentCount( radius, aError, 360.0 );
137  numSegs = std::max( aMinSegCount, numSegs );
138 
139  int delta = 3600 / numSegs; // rotate angle in 0.1 degree
140 
141  if( aErrorLoc == ERROR_OUTSIDE )
142  {
143  // The outer radius should be radius+aError
144  // Recalculate the actual approx error, as it can be smaller than aError
145  // because numSegs is clamped to a minimal value
146  int actual_delta_radius = CircleToEndSegmentDeltaRadius( radius, numSegs );
147  int correction = GetCircleToPolyCorrection( actual_delta_radius );
148  radius += correction;
149  }
150 
151  // end point is the coordinate relative to aStart
152  wxPoint endp = aEnd - aStart;
153  wxPoint startp = aStart;
154  wxPoint corner;
155  SHAPE_POLY_SET polyshape;
156 
157  polyshape.NewOutline();
158 
159  // normalize the position in order to have endp.x >= 0
160  // it makes calculations more easy to understand
161  if( endp.x < 0 )
162  {
163  endp = aStart - aEnd;
164  startp = aEnd;
165  }
166 
167  // delta_angle is in radian
168  double delta_angle = atan2( (double)endp.y, (double)endp.x );
169  int seg_len = KiROUND( EuclideanNorm( endp ) );
170 
171  // Compute the outlines of the segment, and creates a polygon
172  // Note: the polygonal shape is built from the equivalent horizontal
173  // segment starting at {0,0}, and ending at {seg_len,0}
174 
175  // add right rounded end:
176 
177  for( int angle = 0; angle < 1800; angle += delta )
178  {
179  corner = wxPoint( 0, radius );
180  RotatePoint( &corner, angle );
181  corner.x += seg_len;
182  polyshape.Append( corner.x, corner.y );
183  }
184 
185  // Finish arc:
186  corner = wxPoint( seg_len, -radius );
187  polyshape.Append( corner.x, corner.y );
188 
189  // add left rounded end:
190  for( int angle = 0; angle < 1800; angle += delta )
191  {
192  corner = wxPoint( 0, -radius );
193  RotatePoint( &corner, angle );
194  polyshape.Append( corner.x, corner.y );
195  }
196 
197  // Finish arc:
198  corner = wxPoint( 0, radius );
199  polyshape.Append( corner.x, corner.y );
200 
201  // Now trim the edges of the polygonal shape which will be slightly outside the
202  // track width.
203  SHAPE_POLY_SET bbox;
204  bbox.NewOutline();
205  // Build the bbox (a horizontal rectangle).
206  int halfwidth = aWidth / 2; // Use the exact segment width for the bbox height
207  corner.x = -radius - 2; // use a bbox width slightly bigger to avoid
208  // creating useless corner at segment ends
209  corner.y = halfwidth;
210  bbox.Append( corner.x, corner.y );
211  corner.y = -halfwidth;
212  bbox.Append( corner.x, corner.y );
213  corner.x = radius + seg_len + 2;
214  bbox.Append( corner.x, corner.y );
215  corner.y = halfwidth;
216  bbox.Append( corner.x, corner.y );
217 
218  // Now, clamp the shape
220  // Note the final polygon is a simple, convex polygon with no hole
221  // due to the shape of initial polygons
222 
223  // Rotate and move the polygon to its right location
224  polyshape.Rotate( delta_angle, VECTOR2I( 0, 0 ) );
225  polyshape.Move( startp );
226 
227  aCornerBuffer.Append( polyshape);
228 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
void Move(const VECTOR2I &aVector) override
Represent a set of closed polygons.
int GetCircleToPolyCorrection(int aMaxError)
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
int NewOutline()
Creates a new hole in a given outline.
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
constexpr int delta
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...

References PNS::angle(), SHAPE_POLY_SET::Append(), SHAPE_POLY_SET::BooleanIntersection(), CircleToEndSegmentDeltaRadius(), delta, ERROR_OUTSIDE, EuclideanNorm(), GetArcToSegmentCount(), GetCircleToPolyCorrection(), KiROUND(), SHAPE_POLY_SET::Move(), SHAPE_POLY_SET::NewOutline(), SHAPE_POLY_SET::PM_STRICTLY_SIMPLE, SHAPE_POLY_SET::Rotate(), and RotatePoint().

Referenced by addTextSegmToPoly(), BOARD_ADAPTER::buildPadOutlineAsPolygon(), CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers(), DIALOG_PAD_PROPERTIES::padValuesOK(), DXF_PLOTTER::PlotPoly(), DXF_PLOTTER::ThickSegment(), TransformArcToPolygon(), PAD::TransformHoleWithClearanceToPolygon(), PCB_TRACK::TransformShapeWithClearanceToPolygon(), PCB_DIMENSION_BASE::TransformShapeWithClearanceToPolygon(), EDA_SHAPE::TransformShapeWithClearanceToPolygon(), and PAD::TransformShapeWithClearanceToPolygon().

◆ TransformRingToPolygon()

void TransformRingToPolygon ( SHAPE_POLY_SET aCornerBuffer,
const wxPoint &  aCentre,
int  aRadius,
int  aWidth,
int  aError,
ERROR_LOC  aErrorLoc 
)

Convert arcs to multiple straight segments.

Parameters
aCornerBufferis a buffer to store the polygon.
aCentreis the center of the arc or circle.
aRadiusis the radius of the circle.
aWidthis the width (thickness) of the ring.
aErroris the internal units allowed for error in approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.

Definition at line 679 of file convert_basic_shapes_to_polygon.cpp.

681 {
682  int inner_radius = aRadius - ( aWidth / 2 );
683  int outer_radius = inner_radius + aWidth;
684 
685  if( inner_radius <= 0 )
686  { //In this case, the ring is just a circle (no hole inside)
687  TransformCircleToPolygon( aCornerBuffer, aCentre, aRadius + ( aWidth / 2 ), aError,
688  aErrorLoc );
689  return;
690  }
691 
692  SHAPE_POLY_SET buffer;
693 
694  TransformCircleToPolygon( buffer, aCentre, outer_radius, aError, aErrorLoc );
695 
696  // Build the hole:
697  buffer.NewHole();
698  // The circle is the hole, so the approximation error location is the opposite of aErrorLoc
699  ERROR_LOC inner_err_loc = aErrorLoc == ERROR_OUTSIDE ? ERROR_INSIDE : ERROR_OUTSIDE;
700  TransformCircleToPolygon( buffer.Hole( 0, 0 ), aCentre, inner_radius,
701  aError, inner_err_loc );
702 
704  aCornerBuffer.Append( buffer );
705 }
int NewHole(int aOutline=-1)
Adds a new outline to the set and returns its index.
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Represent a set of closed polygons.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount)
Convert a circle to a polygon, using multiple straight lines.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...

References SHAPE_POLY_SET::Append(), ERROR_INSIDE, ERROR_OUTSIDE, SHAPE_POLY_SET::Fracture(), SHAPE_POLY_SET::Hole(), SHAPE_POLY_SET::NewHole(), SHAPE_POLY_SET::PM_FAST, and TransformCircleToPolygon().

Referenced by BOARD_ADAPTER::buildPadOutlineAsPolygon(), AM_PRIMITIVE::DrawBasicShape(), and EDA_SHAPE::TransformShapeWithClearanceToPolygon().

◆ TransformRoundChamferedRectToPolygon()

void TransformRoundChamferedRectToPolygon ( SHAPE_POLY_SET aCornerBuffer,
const wxPoint &  aPosition,
const wxSize &  aSize,
double  aRotation,
int  aCornerRadius,
double  aChamferRatio,
int  aChamferCorners,
int  aInflate,
int  aError,
ERROR_LOC  aErrorLoc 
)

Convert a rectangle with rounded corners and/or chamfered corners to a polygon.

Convert rounded corners arcs to multiple straight lines. This will generate at least 16 segments per circle.

Parameters
aCornerBufferis a buffer to store the polygon.
aPositionis the coordinate of the center of the rectangle.
aSizeis the size of the rectangle.
aCornerRadiusis the radius of rounded corners (can be 0).
aRotationis the rotation in 0.1 degrees of the rectangle.
aChamferRatiois the ratio between smaller rect side and chamfer value.
aChamferCornersis the identifier of the corners to chamfer:
  • 0 = no chamfer
  • 1 = TOP_LEFT
  • 2 = TOP_RIGHT
  • 4 = BOTTOM_LEFT
  • 8 = BOTTOM_RIGHT One can have more than one chamfered corner by ORing the corner identifiers.
aInflateis the (positive) shape inflation or 0
aErroris the IU allowed for error in approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.

Definition at line 437 of file convert_basic_shapes_to_polygon.cpp.

441 {
442  SHAPE_POLY_SET outline;
443  wxSize size( aSize / 2 );
444  int chamferCnt = std::bitset<8>( aChamferCorners ).count();
445  double chamferDeduct = 0;
446 
447  if( aInflate < 0 )
448  {
449  size.x = std::max( 1, size.x + aInflate );
450  size.y = std::max( 1, size.y + aInflate );
451  chamferDeduct = aInflate * ( 2.0 - M_SQRT2 );
452  aCornerRadius = std::max( 0, aCornerRadius + aInflate );
453  aInflate = 0;
454  }
455 
456  std::vector<ROUNDED_CORNER> corners;
457  corners.reserve( 4 + chamferCnt );
458  corners.push_back( ROUNDED_CORNER( -size.x, -size.y, aCornerRadius ) );
459  corners.push_back( ROUNDED_CORNER( size.x, -size.y, aCornerRadius ) );
460  corners.push_back( ROUNDED_CORNER( size.x, size.y, aCornerRadius ) );
461  corners.push_back( ROUNDED_CORNER( -size.x, size.y, aCornerRadius ) );
462 
463  if( aChamferCorners )
464  {
465  int shorterSide = std::min( aSize.x, aSize.y );
466  int chamfer = std::max( 0, KiROUND( aChamferRatio * shorterSide + chamferDeduct ) );
469  int sign[8] = { 0, 1, -1, 0, 0, -1, 1, 0 };
470 
471  for( int cc = 0, pos = 0; cc < 4; cc++, pos++ )
472  {
473  if( !( aChamferCorners & chamId[cc] ) )
474  continue;
475 
476  corners[pos].m_radius = 0;
477 
478  if( chamfer == 0 )
479  continue;
480 
481  corners.insert( corners.begin() + pos + 1, corners[pos] );
482  corners[pos].m_position.x += sign[( 2 * cc ) & 7] * chamfer;
483  corners[pos].m_position.y += sign[( 2 * cc - 2 ) & 7] * chamfer;
484  corners[pos + 1].m_position.x += sign[( 2 * cc + 1 ) & 7] * chamfer;
485  corners[pos + 1].m_position.y += sign[( 2 * cc - 1 ) & 7] * chamfer;
486  pos++;
487  }
488 
489  if( chamferCnt > 1 && 2 * chamfer >= shorterSide )
490  CornerListRemoveDuplicates( corners );
491  }
492 
493  CornerListToPolygon( outline, corners, aInflate, aError, aErrorLoc );
494 
495  if( aRotation != 0.0 )
496  outline.Rotate( DECIDEG2RAD( -aRotation ), VECTOR2I( 0, 0 ) );
497 
498  outline.Move( VECTOR2I( aPosition ) );
499  aCornerBuffer.Append( outline );
500 }
int sign(T val)
Definition: util.h:104
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
void Move(const VECTOR2I &aVector) override
Represent a set of closed polygons.
void CornerListRemoveDuplicates(std::vector< ROUNDED_CORNER > &aCorners)
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void CornerListToPolygon(SHAPE_POLY_SET &outline, std::vector< ROUNDED_CORNER > &aCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...

References SHAPE_POLY_SET::Append(), CornerListRemoveDuplicates(), CornerListToPolygon(), DECIDEG2RAD(), KiROUND(), SHAPE_POLY_SET::Move(), RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT, RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT, SHAPE_POLY_SET::Rotate(), and sign().

Referenced by PAD::BuildEffectiveShapes(), CreatePadsShapesSection(), GERBER_PLOTTER::FlashPadChamferRoundRect(), PSLIKE_PLOTTER::FlashPadRoundRect(), GERBER_PLOTTER::FlashPadRoundRect(), HPGL_PLOTTER::FlashPadRoundRect(), DXF_PLOTTER::FlashPadRoundRect(), DSN::SPECCTRA_DB::makePADSTACK(), and PAD::TransformShapeWithClearanceToPolygon().

◆ TransformTrapezoidToPolygon()

void TransformTrapezoidToPolygon ( SHAPE_POLY_SET aCornerBuffer,
const wxPoint &  aPosition,
const wxSize &  aSize,
double  aRotation,
int  aDeltaX,
int  aDeltaY,
int  aInflate,
int  aError,
ERROR_LOC  aErrorLoc 
)

Convert a rectangle or trapezoid to a polygon.

This will generate at least 16 segments per circle (when using inflate).

Parameters
aCornerBufferis a buffer to store the polygon.
aPositionis the coordinate of the center of the rectangle.
aSizeis the size of the rectangle.
aDeltaXis the delta for trapezoids in X direction
aDeltaYis the delta for trapezoids in Y direction
aInflateis the (positive) shape inflation or 0
aErroris the IU allowed for error in approximation.
aErrorLocdetermines if the approximation error be placed outside or inside the polygon.

Definition at line 364 of file convert_basic_shapes_to_polygon.cpp.

367 {
368  SHAPE_POLY_SET outline;
369  wxSize size( aSize / 2 );
370  std::vector<ROUNDED_CORNER> corners;
371 
372  if( aInflate < 0 )
373  {
374  if( !aDeltaX && !aDeltaY ) // rectangle
375  {
376  size.x = std::max( 1, size.x + aInflate );
377  size.y = std::max( 1, size.y + aInflate );
378  }
379  else if( aDeltaX ) // horizontal trapezoid
380  {
381  double slope = (double) aDeltaX / size.x;
382  int yShrink = KiROUND( ( std::hypot( size.x, aDeltaX ) * aInflate ) / size.x );
383  size.y = std::max( 1, size.y + yShrink );
384  size.x = std::max( 1, size.x + aInflate );
385  aDeltaX = KiROUND( size.x * slope );
386 
387  if( aDeltaX > size.y ) // shrinking turned the trapezoid into a triangle
388  {
389  corners.reserve( 3 );
390  corners.push_back( ROUNDED_CORNER( -size.x, -size.y - aDeltaX ) );
391  corners.push_back( ROUNDED_CORNER( KiROUND( size.y / slope ), 0 ) );
392  corners.push_back( ROUNDED_CORNER( -size.x, size.y + aDeltaX ) );
393  }
394  }
395  else // vertical trapezoid
396  {
397  double slope = (double) aDeltaY / size.y;
398  int xShrink = KiROUND( ( std::hypot( size.y, aDeltaY ) * aInflate ) / size.y );
399  size.x = std::max( 1, size.x + xShrink );
400  size.y = std::max( 1, size.y + aInflate );
401  aDeltaY = KiROUND( size.y * slope );
402 
403  if( aDeltaY > size.x )
404  {
405  corners.reserve( 3 );
406  corners.push_back( ROUNDED_CORNER( 0, -KiROUND( size.x / slope ) ) );
407  corners.push_back( ROUNDED_CORNER( size.x + aDeltaY, size.y ) );
408  corners.push_back( ROUNDED_CORNER( -size.x - aDeltaY, size.y ) );
409  }
410  }
411 
412  aInflate = 0;
413  }
414 
415  if( corners.empty() )
416  {
417  corners.reserve( 4 );
418  corners.push_back( ROUNDED_CORNER( -size.x + aDeltaY, -size.y - aDeltaX ) );
419  corners.push_back( ROUNDED_CORNER( size.x - aDeltaY, -size.y + aDeltaX ) );
420  corners.push_back( ROUNDED_CORNER( size.x + aDeltaY, size.y - aDeltaX ) );
421  corners.push_back( ROUNDED_CORNER( -size.x - aDeltaY, size.y + aDeltaX ) );
422 
423  if( std::abs( aDeltaY ) == std::abs( size.x ) || std::abs( aDeltaX ) == std::abs( size.y ) )
424  CornerListRemoveDuplicates( corners );
425  }
426 
427  CornerListToPolygon( outline, corners, aInflate, aError, aErrorLoc );
428 
429  if( aRotation != 0.0 )
430  outline.Rotate( DECIDEG2RAD( -aRotation ), VECTOR2I( 0, 0 ) );
431 
432  outline.Move( VECTOR2I( aPosition ) );
433  aCornerBuffer.Append( outline );
434 }
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
void Move(const VECTOR2I &aVector) override
Represent a set of closed polygons.
void CornerListRemoveDuplicates(std::vector< ROUNDED_CORNER > &aCorners)
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void CornerListToPolygon(SHAPE_POLY_SET &outline, std::vector< ROUNDED_CORNER > &aCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...

References SHAPE_POLY_SET::Append(), CornerListRemoveDuplicates(), CornerListToPolygon(), DECIDEG2RAD(), KiROUND(), SHAPE_POLY_SET::Move(), and SHAPE_POLY_SET::Rotate().

Referenced by PAD::TransformShapeWithClearanceToPolygon().