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 );
158 endp = aStart - aEnd;
176 polyshape.
Append( corner.
x, corner.
y );
180 corner =
VECTOR2I( seg_len, -radius );
181 polyshape.
Append( corner.
x, corner.
y );
188 polyshape.
Append( corner.
x, corner.
y );
193 polyshape.
Append( corner.
x, corner.
y );
200 int halfwidth = aWidth / 2;
201 corner.
x = -radius - 2;
203 corner.
y = halfwidth;
205 corner.
y = -halfwidth;
207 corner.
x = radius + seg_len + 2;
209 corner.
y = halfwidth;
218 polyshape.
Rotate( -delta_angle );
219 polyshape.
Move( startp );
221 aBuffer.
Append( polyshape);
236 int aInflate,
int aError,
ERROR_LOC aErrorLoc )
238 assert( aInflate >= 0 );
240 VECTOR2I incoming = aCorners[0].m_position - aCorners.back().m_position;
242 for(
int n = 0, count = aCorners.size(); n < count; n++ )
259 if( ( incoming.
x == 0 && outgoing.y == 0 ) || ( incoming.
y == 0 && outgoing.x == 0 ) )
266 double cosNum = (double) incoming.
x * outgoing.x + (
double) incoming.
y * outgoing.y;
267 double cosDen = (double) incoming.
EuclideanNorm() * outgoing.EuclideanNorm();
268 double angle = acos( cosNum / cosDen );
269 tanAngle2 = tan( ( M_PI - angle ) / 2 );
273 if( aInflate && tanAngle2 )
276 cornerPosition += incoming.
Resize( aInflate / tanAngle2 )
287 while( lastSeg > angDelta )
292 while( lastSeg < -angDelta )
296 EDA_ANGLE angPos = lastSeg.
IsZero() ? angDelta : ( angDelta + lastSeg ) / 2;
298 double arcTransitionDistance = ( tanAngle2 > 0 ) ? ( radius / tanAngle2 ) : 0;
299 VECTOR2I arcStart = cornerPosition - incoming.
Resize( arcTransitionDistance );
306 arcStartOrigin = arcStart - arcCenter;
307 outline.
Append( arcStart );
315 arcStartOrigin = arcStart - arcCenter;
319 SEG outlineIn( cornerPosition - incoming, cornerPosition );
321 arcEnd = cornerPosition;
323 while( angPos < endAngle )
330 if( outlineIn.
Side( pt ) > 0 )
334 wxCHECK_RET(
intersect, wxT(
"No solutions exist!" ) );
341 endAngle -= angDelta;
346 for( ; angPos < endAngle; angPos += angDelta )
350 outline.
Append( pt + arcCenter );
363 VECTOR2I prev = aCorners[0].m_position;
365 for(
int pos = aCorners.size() - 1; pos >= 0; pos-- )
367 if( aCorners[pos].m_position == prev )
368 aCorners.erase( aCorners.begin() + pos );
370 prev = aCorners[pos].m_position;
377 int aDeltaY,
int aInflate,
int aError,
ERROR_LOC aErrorLoc )
381 std::vector<ROUNDED_CORNER> corners;
385 if( !aDeltaX && !aDeltaY )
387 size.
x = std::max( 1, size.
x + aInflate );
388 size.
y = std::max( 1, size.
y + aInflate );
392 double slope = (double) aDeltaX / size.
x;
393 int yShrink =
KiROUND( ( std::hypot( size.
x, aDeltaX ) * aInflate ) / size.
x );
394 size.
y = std::max( 1, size.
y + yShrink );
395 size.
x = std::max( 1, size.
x + aInflate );
396 aDeltaX =
KiROUND( size.
x * slope );
398 if( aDeltaX > size.
y )
400 corners.reserve( 3 );
401 corners.emplace_back( -size.
x, -size.
y - aDeltaX );
402 corners.emplace_back(
KiROUND( size.
y / slope ), 0 );
403 corners.emplace_back( -size.
x, size.
y + aDeltaX );
408 double slope = (double) aDeltaY / size.
y;
409 int xShrink =
KiROUND( ( std::hypot( size.
y, aDeltaY ) * aInflate ) / size.
y );
410 size.
x = std::max( 1, size.
x + xShrink );
411 size.
y = std::max( 1, size.
y + aInflate );
412 aDeltaY =
KiROUND( size.
y * slope );
414 if( aDeltaY > size.
x )
416 corners.reserve( 3 );
417 corners.emplace_back( 0, -
KiROUND( size.
x / slope ) );
418 corners.emplace_back( size.
x + aDeltaY, size.
y );
419 corners.emplace_back( -size.
x - aDeltaY, size.
y );
426 if( corners.empty() )
428 corners.reserve( 4 );
429 corners.emplace_back( -size.
x + aDeltaY, -size.
y - aDeltaX );
430 corners.emplace_back( size.
x - aDeltaY, -size.
y + aDeltaX );
431 corners.emplace_back( size.
x + aDeltaY, size.
y - aDeltaX );
432 corners.emplace_back( -size.
x - aDeltaY, size.
y + aDeltaX );
441 outline.
Rotate( aRotation );
444 aBuffer.
Append( outline );
450 int aCornerRadius,
double aChamferRatio,
451 int aChamferCorners,
int aInflate,
int aError,
456 int chamferCnt = std::bitset<8>( aChamferCorners ).count();
457 double chamferDeduct = 0;
461 size.
x = std::max( 1, size.
x + aInflate );
462 size.
y = std::max( 1, size.
y + aInflate );
463 chamferDeduct = aInflate * ( 2.0 - M_SQRT2 );
464 aCornerRadius = std::max( 0, aCornerRadius + aInflate );
468 std::vector<ROUNDED_CORNER> corners;
469 corners.reserve( 4 + chamferCnt );
470 corners.emplace_back( -size.
x, -size.
y, aCornerRadius );
471 corners.emplace_back( size.
x, -size.
y, aCornerRadius );
472 corners.emplace_back( size.
x, size.
y, aCornerRadius );
473 corners.emplace_back( -size.
x, size.
y, aCornerRadius );
475 if( aChamferCorners )
477 int shorterSide = std::min( aSize.
x, aSize.
y );
478 int chamfer = std::max( 0,
KiROUND( aChamferRatio * shorterSide + chamferDeduct ) );
481 int sign[8] = { 0, 1, -1, 0, 0, -1, 1, 0 };
483 for(
int cc = 0, pos = 0; cc < 4; cc++, pos++ )
485 if( !( aChamferCorners & chamId[cc] ) )
488 corners[pos].m_radius = 0;
493 corners.insert( corners.begin() + pos + 1, corners[pos] );
494 corners[pos].m_position.x +=
sign[( 2 * cc ) & 7] *
chamfer;
495 corners[pos].m_position.y +=
sign[( 2 * cc - 2 ) & 7] *
chamfer;
496 corners[pos + 1].m_position.x +=
sign[( 2 * cc + 1 ) & 7] *
chamfer;
497 corners[pos + 1].m_position.y +=
sign[( 2 * cc - 1 ) & 7] *
chamfer;
501 if( chamferCnt > 1 && 2 *
chamfer >= shorterSide )
508 outline.
Rotate( aRotation );
510 outline.
Move( aPosition );
511 aBuffer.
Append( outline );
521 if( aRadius >= aAccuracy )
533 for(
int i = 0; i <= n; i++, rot +=
delta )
535 double x = aCenter.
x + aRadius * rot.
Cos();
536 double y = aCenter.
y + aRadius * rot.
Sin();
549 int errorRadius = aRadius + actual_delta_radius;
551 double x = aCenter.
x + aRadius * aStartAngle.
Cos();
552 double y = aCenter.
y + aRadius * aStartAngle.
Sin();
558 for(
int i = 0; i < n; i++, rot +=
delta )
560 x = aCenter.
x + errorRadius * rot.
Cos();
561 y = aCenter.
y + errorRadius * rot.
Sin();
566 x = aCenter.
x + aRadius * ( aStartAngle + aArcAngle ).Cos();
567 y = aCenter.
y + aRadius * ( aStartAngle + aArcAngle ).Sin();
579 SEG startToEnd( aStart, aEnd );
580 int distanceToMid = startToEnd.
Distance( aMid );
582 if( distanceToMid <= 1 )
592 SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
595 EDA_ANGLE arc_angle_end = arc_angle_start + arc_angle;
599 std::swap( arc_angle_start, arc_angle_end );
600 arc =
SHAPE_ARC( aEnd, aMid, aStart, aWidth );
601 arc_angle = -arc_angle;
604 int radial_offset = arc.
GetWidth() / 2;
605 int arc_outer_radius = arc.
GetRadius() + radial_offset;
606 int arc_inner_radius = arc.
GetRadius() - radial_offset;
621 aError, errorLocOuter );
628 if( arc_inner_radius > 0 )
631 -arc_angle, aError, errorLocInner );
634 aBuffer.
Append( polyshape );
639 int aWidth,
int aError,
ERROR_LOC aErrorLoc )
641 int inner_radius = aRadius - ( aWidth / 2 );
642 int outer_radius = inner_radius + aWidth;
644 if( inner_radius <= 0 )
660 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_180
static constexpr EDA_ANGLE & ANGLE_360
static constexpr EDA_ANGLE & FULL_CIRCLE
static constexpr EDA_ANGLE & ANGLE_90
static constexpr EDA_ANGLE & ANGLE_0
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)
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".