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  SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
540  // Currentlye have currently 2 algos:
541  // the first approximates the thick arc from its outlines
542  // the second approximates the thick arc from segments given by SHAPE_ARC
543  // using SHAPE_ARC::ConvertToPolyline
544  // The actual approximation errors are similar but not exactly the same.
545  //
546  // For now, both algorithms are kept, the second is the initial algo used in Kicad.
547 
548 #if 1
549  // This appproximation convert the 2 ends to polygons, arc outer to polyline
550  // and arc inner to polyline and merge shapes.
551  int radial_offset = ( aWidth + 1 ) / 2;
552 
553  SHAPE_POLY_SET polyshape;
554  std::vector<VECTOR2I> outside_pts;
555 
557  TransformCircleToPolygon( polyshape, aStart, radial_offset, aError, aErrorLoc );
558  TransformCircleToPolygon( polyshape, aEnd, radial_offset, aError, aErrorLoc );
559 
560  // The circle polygon is built with a even number of segments, so the
561  // horizontal diameter has 2 corners on the biggest diameter
562  // Rotate these 2 corners to match the start and ens points of inner and outer
563  // end points of the arc appoximation outlines, build below.
564  // The final shape is much better.
565  double arc_angle_start_deg = arc.GetStartAngle();
566  double arc_angle = arc.GetCentralAngle();
567  double arc_angle_end_deg = arc_angle_start_deg + arc_angle;
568 
569  if( arc_angle_start_deg != 0 && arc_angle_start_deg != 180.0 )
570  polyshape.Outline(0).Rotate( arc_angle_start_deg * M_PI/180.0, aStart );
571 
572  if( arc_angle_end_deg != 0 && arc_angle_end_deg != 180.0 )
573  polyshape.Outline(1).Rotate( arc_angle_end_deg * M_PI/180.0, aEnd );
574 
575  VECTOR2I center = arc.GetCenter();
576  int radius = arc.GetRadius();
577 
578  int arc_outer_radius = radius + radial_offset;
579  int arc_inner_radius = radius - radial_offset;
580  ERROR_LOC errorLocInner = ERROR_OUTSIDE;
581  ERROR_LOC errorLocOuter = ERROR_INSIDE;
582 
583  if( aErrorLoc == ERROR_OUTSIDE )
584  {
585  errorLocInner = ERROR_INSIDE;
586  errorLocOuter = ERROR_OUTSIDE;
587  }
588 
589  polyshape.NewOutline();
590 
591  ConvertArcToPolyline( polyshape.Outline(2), center, arc_outer_radius,
592  arc_angle_start_deg, arc_angle, aError, errorLocOuter );
593 
594  if( arc_inner_radius > 0 )
595  ConvertArcToPolyline( polyshape.Outline(2), center, arc_inner_radius,
596  arc_angle_end_deg, -arc_angle, aError, errorLocInner );
597  else
598  polyshape.Append( center );
599 #else
600  // This appproximation use SHAPE_ARC to convert the 2 ends to polygons,
601  // approximate arc to polyline, convert the polyline corners to outer and inner
602  // corners of outer and inner utliners and merge shapes.
603  double defaultErr;
604  SHAPE_LINE_CHAIN arcSpine = arc.ConvertToPolyline( SHAPE_ARC::DefaultAccuracyForPCB(),
605  &defaultErr);
606  int radius = arc.GetRadius();
607  int radial_offset = ( aWidth + 1 ) / 2;
608  SHAPE_POLY_SET polyshape;
609  std::vector<VECTOR2I> outside_pts;
610 
611  // delta is the effective error approximation to build a polyline from an arc
612  int segCnt360 = arcSpine.GetSegmentCount()*360.0/arc.GetCentralAngle();;
613  int delta = CircleToEndSegmentDeltaRadius( radius+radial_offset, std::abs(segCnt360) );
614 
616  TransformCircleToPolygon( polyshape, aStart, radial_offset, aError, aErrorLoc );
617  TransformCircleToPolygon( polyshape, aEnd, radial_offset, aError, aErrorLoc );
618 
619  // The circle polygon is built with a even number of segments, so the
620  // horizontal diameter has 2 corners on the biggest diameter
621  // Rotate these 2 corners to match the start and ens points of inner and outer
622  // end points of the arc appoximation outlines, build below.
623  // The final shape is much better.
624  double arc_angle_end_deg = arc.GetStartAngle();
625 
626  if( arc_angle_end_deg != 0 && arc_angle_end_deg != 180.0 )
627  polyshape.Outline(0).Rotate( arc_angle_end_deg * M_PI/180.0, arcSpine.GetPoint( 0 ) );
628 
629  arc_angle_end_deg = arc.GetEndAngle();
630 
631  if( arc_angle_end_deg != 0 && arc_angle_end_deg != 180.0 )
632  polyshape.Outline(1).Rotate( arc_angle_end_deg * M_PI/180.0, arcSpine.GetPoint( -1 ) );
633 
634  if( aErrorLoc == ERROR_OUTSIDE )
635  radial_offset += delta + defaultErr/2;
636  else
637  radial_offset -= defaultErr/2;
638 
639  if( radial_offset < 0 )
640  radial_offset = 0;
641 
642  polyshape.NewOutline();
643 
644  VECTOR2I center = arc.GetCenter();
645  int last_index = arcSpine.GetPointCount() -1;
646 
647  for( std::size_t ii = 0; ii <= last_index; ++ii )
648  {
649  VECTOR2I offset = arcSpine.GetPoint( ii ) - center;
650  int curr_rd = radius;
651 
652  polyshape.Append( offset.Resize( curr_rd - radial_offset ) + center );
653  outside_pts.emplace_back( offset.Resize( curr_rd + radial_offset ) + center );
654  }
655 
656  for( auto it = outside_pts.rbegin(); it != outside_pts.rend(); ++it )
657  polyshape.Append( *it );
658 #endif
659 
660  // Can be removed, but usefull to display the outline:
661  polyshape.Simplify( SHAPE_POLY_SET::PM_FAST );
662 
663  aCornerBuffer.Append( polyshape );
664 
665 }
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 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.
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 (an zero-thickness chain of connected line segments).
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, 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(), and TransformCircleToPolygon().

Referenced by BOOST_AUTO_TEST_CASE(), KIGFX::PCB_PAINTER::draw(), CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers(), PCB_TRACK::TransformShapeWithClearanceToPolygon(), and PCB_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(), PCB_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:623
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(), PAD::TransformHoleWithClearanceToPolygon(), PCB_TRACK::TransformShapeWithClearanceToPolygon(), PCB_DIMENSION_BASE::TransformShapeWithClearanceToPolygon(), PCB_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 668 of file convert_basic_shapes_to_polygon.cpp.

670 {
671  int inner_radius = aRadius - ( aWidth / 2 );
672  int outer_radius = inner_radius + aWidth;
673 
674  if( inner_radius <= 0 )
675  { //In this case, the ring is just a circle (no hole inside)
676  TransformCircleToPolygon( aCornerBuffer, aCentre, aRadius + ( aWidth / 2 ), aError,
677  aErrorLoc );
678  return;
679  }
680 
681  SHAPE_POLY_SET buffer;
682 
683  TransformCircleToPolygon( buffer, aCentre, outer_radius, aError, aErrorLoc );
684 
685  // Build the hole:
686  buffer.NewHole();
687  // The circle is the hole, so the approximation error location is the opposite of aErrorLoc
688  ERROR_LOC inner_err_loc = aErrorLoc == ERROR_OUTSIDE ? ERROR_INSIDE : ERROR_OUTSIDE;
689  TransformCircleToPolygon( buffer.Hole( 0, 0 ), aCentre, inner_radius,
690  aError, inner_err_loc );
691 
693  aCornerBuffer.Append( buffer );
694 }
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 PCB_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:623
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( aDeltaY == size.x || aDeltaX == 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:623
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().