39 int aError,
ERROR_LOC aErrorLoc,
int aMinSegCount )
43 numSegs = std::max( aMinSegCount, numSegs );
66 corner_position.
x = radius;
67 corner_position.
y = 0;
69 corner_position += aCenter;
70 aBuffer.
Append( corner_position.
x, corner_position.
y );
78 int aError,
ERROR_LOC aErrorLoc,
int aMinSegCount )
82 numSegs = std::max( aMinSegCount, numSegs );
107 corner_position.
x = radius;
108 corner_position.
y = 0;
110 corner_position += aCenter;
111 aBuffer.
Append( corner_position.
x, corner_position.
y );
115 corner_position.
x = radius;
116 corner_position.
y = 0;
117 corner_position += aCenter;
118 aBuffer.
Append( corner_position.
x, corner_position.
y );
123 int aWidth,
int aError,
ERROR_LOC aErrorLoc,
int aMinSegCount )
130 int radius = aWidth / 2;
132 numSegs = std::max( aMinSegCount, numSegs );
135 numSegs = ( numSegs + 7 ) / 8 * 8;
161 endp = aStart - aEnd;
179 polyshape.
Append( corner.
x, corner.
y );
183 corner =
VECTOR2I( seg_len, -radius );
184 polyshape.
Append( corner.
x, corner.
y );
191 polyshape.
Append( corner.
x, corner.
y );
196 polyshape.
Append( corner.
x, corner.
y );
203 int halfwidth = aWidth / 2;
204 corner.
x = -radius - 2;
206 corner.
y = halfwidth;
208 corner.
y = -halfwidth;
210 corner.
x = radius + seg_len + 2;
212 corner.
y = halfwidth;
221 polyshape.
Rotate( -delta_angle );
222 polyshape.
Move( startp );
224 aBuffer.
Append( polyshape);
239 int aInflate,
int aError,
ERROR_LOC aErrorLoc )
241 assert( aInflate >= 0 );
243 VECTOR2I incoming = aCorners[0].m_position - aCorners.back().m_position;
245 for(
int n = 0, count = aCorners.size(); n < count; n++ )
262 if( ( incoming.
x == 0 && outgoing.y == 0 ) || ( incoming.
y == 0 && outgoing.x == 0 ) )
269 double cosNum = (double) incoming.
x * outgoing.x + (
double) incoming.
y * outgoing.y;
270 double cosDen = (double) incoming.
EuclideanNorm() * outgoing.EuclideanNorm();
271 double angle = acos( cosNum / cosDen );
272 tanAngle2 = tan( ( M_PI - angle ) / 2 );
276 if( aInflate && tanAngle2 )
279 cornerPosition += incoming.
Resize( aInflate / tanAngle2 )
290 while( lastSeg > angDelta )
295 while( lastSeg < -angDelta )
299 EDA_ANGLE angPos = lastSeg.
IsZero() ? angDelta : ( angDelta + lastSeg ) / 2;
301 double arcTransitionDistance = ( tanAngle2 > 0 ) ? ( radius / tanAngle2 ) : 0;
302 VECTOR2I arcStart = cornerPosition - incoming.
Resize( arcTransitionDistance );
309 arcStartOrigin = arcStart - arcCenter;
310 outline.
Append( arcStart );
318 arcStartOrigin = arcStart - arcCenter;
322 SEG outlineIn( cornerPosition - incoming, cornerPosition );
324 arcEnd = cornerPosition;
326 while( angPos < endAngle )
333 if( outlineIn.
Side( pt ) > 0 )
337 wxCHECK_RET(
intersect, wxT(
"No solutions exist!" ) );
344 endAngle -= angDelta;
349 for( ; angPos < endAngle; angPos += angDelta )
353 outline.
Append( pt + arcCenter );
366 VECTOR2I prev = aCorners[0].m_position;
368 for(
int pos = aCorners.size() - 1; pos >= 0; pos-- )
370 if( aCorners[pos].m_position == prev )
371 aCorners.erase( aCorners.begin() + pos );
373 prev = aCorners[pos].m_position;
380 int aDeltaY,
int aInflate,
int aError,
ERROR_LOC aErrorLoc )
384 std::vector<ROUNDED_CORNER> corners;
388 if( !aDeltaX && !aDeltaY )
390 size.
x = std::max( 1, size.
x + aInflate );
391 size.
y = std::max( 1, size.
y + aInflate );
395 double slope = (double) aDeltaX / size.
x;
396 int yShrink =
KiROUND( ( std::hypot( size.
x, aDeltaX ) * aInflate ) / size.
x );
397 size.
y = std::max( 1, size.
y + yShrink );
398 size.
x = std::max( 1, size.
x + aInflate );
399 aDeltaX =
KiROUND( size.
x * slope );
401 if( aDeltaX > size.
y )
403 corners.reserve( 3 );
404 corners.emplace_back( -size.
x, -size.
y - aDeltaX );
405 corners.emplace_back(
KiROUND( size.
y / slope ), 0 );
406 corners.emplace_back( -size.
x, size.
y + aDeltaX );
411 double slope = (double) aDeltaY / size.
y;
412 int xShrink =
KiROUND( ( std::hypot( size.
y, aDeltaY ) * aInflate ) / size.
y );
413 size.
x = std::max( 1, size.
x + xShrink );
414 size.
y = std::max( 1, size.
y + aInflate );
415 aDeltaY =
KiROUND( size.
y * slope );
417 if( aDeltaY > size.
x )
419 corners.reserve( 3 );
420 corners.emplace_back( 0, -
KiROUND( size.
x / slope ) );
421 corners.emplace_back( size.
x + aDeltaY, size.
y );
422 corners.emplace_back( -size.
x - aDeltaY, size.
y );
429 if( corners.empty() )
431 corners.reserve( 4 );
432 corners.emplace_back( -size.
x + aDeltaY, -size.
y - aDeltaX );
433 corners.emplace_back( size.
x - aDeltaY, -size.
y + aDeltaX );
434 corners.emplace_back( size.
x + aDeltaY, size.
y - aDeltaX );
435 corners.emplace_back( -size.
x - aDeltaY, size.
y + aDeltaX );
444 outline.
Rotate( aRotation );
447 aBuffer.
Append( outline );
453 int aCornerRadius,
double aChamferRatio,
454 int aChamferCorners,
int aInflate,
int aError,
459 int chamferCnt = std::bitset<8>( aChamferCorners ).count();
460 double chamferDeduct = 0;
464 size.
x = std::max( 1, size.
x + aInflate );
465 size.
y = std::max( 1, size.
y + aInflate );
466 chamferDeduct = aInflate * ( 2.0 - M_SQRT2 );
467 aCornerRadius = std::max( 0, aCornerRadius + aInflate );
471 std::vector<ROUNDED_CORNER> corners;
472 corners.reserve( 4 + chamferCnt );
473 corners.emplace_back( -size.
x, -size.
y, aCornerRadius );
474 corners.emplace_back( size.
x, -size.
y, aCornerRadius );
475 corners.emplace_back( size.
x, size.
y, aCornerRadius );
476 corners.emplace_back( -size.
x, size.
y, aCornerRadius );
478 if( aChamferCorners )
480 int shorterSide = std::min( aSize.
x, aSize.
y );
481 int chamfer = std::max( 0,
KiROUND( aChamferRatio * shorterSide + chamferDeduct ) );
484 int sign[8] = { 0, 1, -1, 0, 0, -1, 1, 0 };
486 for(
int cc = 0, pos = 0; cc < 4; cc++, pos++ )
488 if( !( aChamferCorners & chamId[cc] ) )
491 corners[pos].m_radius = 0;
496 corners.insert( corners.begin() + pos + 1, corners[pos] );
497 corners[pos].m_position.x +=
sign[( 2 * cc ) & 7] *
chamfer;
498 corners[pos].m_position.y +=
sign[( 2 * cc - 2 ) & 7] *
chamfer;
499 corners[pos + 1].m_position.x +=
sign[( 2 * cc + 1 ) & 7] *
chamfer;
500 corners[pos + 1].m_position.y +=
sign[( 2 * cc - 1 ) & 7] *
chamfer;
504 if( chamferCnt > 1 && 2 *
chamfer >= shorterSide )
511 outline.
Rotate( aRotation );
513 outline.
Move( aPosition );
514 aBuffer.
Append( outline );
524 if( aRadius >= aAccuracy )
536 for(
int i = 0; i <= n; i++, rot +=
delta )
538 double x = aCenter.
x + aRadius * rot.
Cos();
539 double y = aCenter.
y + aRadius * rot.
Sin();
552 int errorRadius = aRadius + actual_delta_radius;
554 double x = aCenter.
x + aRadius * aStartAngle.
Cos();
555 double y = aCenter.
y + aRadius * aStartAngle.
Sin();
561 for(
int i = 0; i < n; i++, rot +=
delta )
563 x = aCenter.
x + errorRadius * rot.
Cos();
564 y = aCenter.
y + errorRadius * rot.
Sin();
569 x = aCenter.
x + aRadius * ( aStartAngle + aArcAngle ).Cos();
570 y = aCenter.
y + aRadius * ( aStartAngle + aArcAngle ).Sin();
582 SEG startToEnd( aStart, aEnd );
583 int distanceToMid = startToEnd.
Distance( aMid );
585 if( distanceToMid <= 1 )
595 SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
598 EDA_ANGLE arc_angle_end = arc_angle_start + arc_angle;
602 std::swap( arc_angle_start, arc_angle_end );
603 arc =
SHAPE_ARC( aEnd, aMid, aStart, aWidth );
604 arc_angle = -arc_angle;
607 int radial_offset = arc.
GetWidth() / 2;
608 int arc_outer_radius = arc.
GetRadius() + radial_offset;
609 int arc_inner_radius = arc.
GetRadius() - radial_offset;
624 aError, errorLocOuter );
631 if( arc_inner_radius > 0 )
634 -arc_angle, aError, errorLocInner );
637 aBuffer.
Append( polyshape );
642 int aWidth,
int aError,
ERROR_LOC aErrorLoc )
644 int inner_radius = aRadius - ( aWidth / 2 );
645 int outer_radius = inner_radius + aWidth;
647 if( inner_radius <= 0 )
663 aError, inner_err_loc );
const VECTOR2I ReflectPoint(const VECTOR2I &aP) const
Reflect a point using this segment as axis.
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
EDA_ANGLE GetCentralAngle() const
const VECTOR2I & GetP1() const
EDA_ANGLE GetStartAngle() const
VECTOR2I GetCenter() const
const VECTOR2I & GetP0() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
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)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int NewHole(int aOutline=-1)
Creates a new hole in a given outline.
void Move(const VECTOR2I &aVector) override
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
void CornerListToPolygon(SHAPE_POLY_SET &outline, std::vector< ROUNDED_CORNER > &aCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
void TransformRingToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
int ConvertArcToPolyline(SHAPE_LINE_CHAIN &aPolyline, VECTOR2I aCenter, int aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aArcAngle, double aAccuracy, ERROR_LOC aErrorLoc)
Generate a polyline to approximate a arc.
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
void CornerListRemoveDuplicates(std::vector< ROUNDED_CORNER > &aCorners)
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount)
Convert a oblong shape to a polygon, using multiple segments.
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &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.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount)
Convert a circle to a polygon, using multiple straight lines.
void TransformTrapezoidToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aDeltaX, int aDeltaY, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle or trapezoid to a polygon.
@ RECT_CHAMFER_BOTTOM_RIGHT
@ RECT_CHAMFER_BOTTOM_LEFT
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE FULL_CIRCLE
static constexpr EDA_ANGLE ANGLE_360
static constexpr EDA_ANGLE ANGLE_180
a few functions useful in geometry calculations.
int GetCircleToPolyCorrection(int aMaxError)
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
static bool intersect(const SEGMENT_WITH_NORMALS &aSeg, const SFVEC2F &aStart, const SFVEC2F &aEnd)
constexpr double correction
std::optional< VECTOR2I > OPT_VECTOR2I
ROUNDED_CORNER(int x, int y, int radius)
ROUNDED_CORNER(int x, int y)
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double EuclideanNorm(const VECTOR2I &vector)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".