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;
175 corner =
VECTOR2I( seg_len, radius );
176 polyshape.
Append( corner.
x, corner.
y );
183 polyshape.
Append( corner.
x, corner.
y );
187 corner =
VECTOR2I( seg_len, -radius );
188 polyshape.
Append( corner.
x, corner.
y );
192 polyshape.
Append( corner.
x, corner.
y );
199 polyshape.
Append( corner.
x, corner.
y );
204 polyshape.
Append( corner.
x, corner.
y );
211 int halfwidth = aWidth / 2;
212 corner.
x = -radius - 2;
214 corner.
y = halfwidth;
216 corner.
y = -halfwidth;
218 corner.
x = radius + seg_len + 2;
220 corner.
y = halfwidth;
229 polyshape.
Rotate( -delta_angle );
230 polyshape.
Move( startp );
232 aBuffer.
Append( polyshape);
247 int aInflate,
int aError,
ERROR_LOC aErrorLoc )
249 assert( aInflate >= 0 );
251 VECTOR2I incoming = aCorners[0].m_position - aCorners.back().m_position;
253 for(
int n = 0, count = aCorners.size(); n < count; n++ )
270 if( ( incoming.
x == 0 && outgoing.y == 0 ) || ( incoming.
y == 0 && outgoing.x == 0 ) )
277 double cosNum = (double) incoming.
x * outgoing.x + (
double) incoming.
y * outgoing.y;
278 double cosDen = (double) incoming.
EuclideanNorm() * outgoing.EuclideanNorm();
279 double angle = acos( cosNum / cosDen );
280 tanAngle2 = tan( ( M_PI - angle ) / 2 );
284 if( aInflate && tanAngle2 )
287 cornerPosition += incoming.
Resize( aInflate / tanAngle2 )
298 while( lastSeg > angDelta )
303 while( lastSeg < -angDelta )
307 EDA_ANGLE angPos = lastSeg.
IsZero() ? angDelta : ( angDelta + lastSeg ) / 2;
309 double arcTransitionDistance = ( tanAngle2 > 0 ) ? ( radius / tanAngle2 ) : 0;
310 VECTOR2I arcStart = cornerPosition - incoming.
Resize( arcTransitionDistance );
317 arcStartOrigin = arcStart - arcCenter;
318 outline.
Append( arcStart );
326 arcStartOrigin = arcStart - arcCenter;
330 SEG outlineIn( cornerPosition - incoming, cornerPosition );
332 arcEnd = cornerPosition;
334 while( angPos < endAngle )
341 if( outlineIn.
Side( pt ) > 0 )
345 wxCHECK_RET(
intersect, wxT(
"No solutions exist!" ) );
352 endAngle -= angDelta;
357 for( ; angPos < endAngle; angPos += angDelta )
361 outline.
Append( pt + arcCenter );
374 VECTOR2I prev = aCorners[0].m_position;
376 for(
int pos = aCorners.size() - 1; pos >= 0; pos-- )
378 if( aCorners[pos].m_position == prev )
379 aCorners.erase( aCorners.begin() + pos );
381 prev = aCorners[pos].m_position;
388 int aDeltaY,
int aInflate,
int aError,
ERROR_LOC aErrorLoc )
392 std::vector<ROUNDED_CORNER> corners;
396 if( !aDeltaX && !aDeltaY )
398 size.
x = std::max( 1, size.
x + aInflate );
399 size.
y = std::max( 1, size.
y + aInflate );
403 double slope = (double) aDeltaX / size.
x;
404 int yShrink =
KiROUND( ( std::hypot( size.
x, aDeltaX ) * aInflate ) / size.
x );
405 size.
y = std::max( 1, size.
y + yShrink );
406 size.
x = std::max( 1, size.
x + aInflate );
407 aDeltaX =
KiROUND( size.
x * slope );
409 if( aDeltaX > size.
y )
411 corners.reserve( 3 );
412 corners.emplace_back( -size.
x, -size.
y - aDeltaX );
413 corners.emplace_back(
KiROUND( size.
y / slope ), 0 );
414 corners.emplace_back( -size.
x, size.
y + aDeltaX );
419 double slope = (double) aDeltaY / size.
y;
420 int xShrink =
KiROUND( ( std::hypot( size.
y, aDeltaY ) * aInflate ) / size.
y );
421 size.
x = std::max( 1, size.
x + xShrink );
422 size.
y = std::max( 1, size.
y + aInflate );
423 aDeltaY =
KiROUND( size.
y * slope );
425 if( aDeltaY > size.
x )
427 corners.reserve( 3 );
428 corners.emplace_back( 0, -
KiROUND( size.
x / slope ) );
429 corners.emplace_back( size.
x + aDeltaY, size.
y );
430 corners.emplace_back( -size.
x - aDeltaY, size.
y );
437 if( corners.empty() )
439 corners.reserve( 4 );
440 corners.emplace_back( -size.
x + aDeltaY, -size.
y - aDeltaX );
441 corners.emplace_back( size.
x - aDeltaY, -size.
y + aDeltaX );
442 corners.emplace_back( size.
x + aDeltaY, size.
y - aDeltaX );
443 corners.emplace_back( -size.
x - aDeltaY, size.
y + aDeltaX );
452 outline.
Rotate( aRotation );
455 aBuffer.
Append( outline );
461 int aCornerRadius,
double aChamferRatio,
462 int aChamferCorners,
int aInflate,
int aError,
467 int chamferCnt = std::bitset<8>( aChamferCorners ).count();
468 double chamferDeduct = 0;
472 size.
x = std::max( 1, size.
x + aInflate );
473 size.
y = std::max( 1, size.
y + aInflate );
474 chamferDeduct = aInflate * ( 2.0 - M_SQRT2 );
475 aCornerRadius = std::max( 0, aCornerRadius + aInflate );
479 std::vector<ROUNDED_CORNER> corners;
480 corners.reserve( 4 + chamferCnt );
481 corners.emplace_back( -size.
x, -size.
y, aCornerRadius );
482 corners.emplace_back( size.
x, -size.
y, aCornerRadius );
483 corners.emplace_back( size.
x, size.
y, aCornerRadius );
484 corners.emplace_back( -size.
x, size.
y, aCornerRadius );
486 if( aChamferCorners )
488 int shorterSide = std::min( aSize.
x, aSize.
y );
489 int chamfer = std::max( 0,
KiROUND( aChamferRatio * shorterSide + chamferDeduct ) );
492 int sign[8] = { 0, 1, -1, 0, 0, -1, 1, 0 };
494 for(
int cc = 0, pos = 0; cc < 4; cc++, pos++ )
496 if( !( aChamferCorners & chamId[cc] ) )
499 corners[pos].m_radius = 0;
504 corners.insert( corners.begin() + pos + 1, corners[pos] );
505 corners[pos].m_position.x +=
sign[( 2 * cc ) & 7] *
chamfer;
506 corners[pos].m_position.y +=
sign[( 2 * cc - 2 ) & 7] *
chamfer;
507 corners[pos + 1].m_position.x +=
sign[( 2 * cc + 1 ) & 7] *
chamfer;
508 corners[pos + 1].m_position.y +=
sign[( 2 * cc - 1 ) & 7] *
chamfer;
512 if( chamferCnt > 1 && 2 *
chamfer >= shorterSide )
519 outline.
Rotate( aRotation );
521 outline.
Move( aPosition );
522 aBuffer.
Append( outline );
532 if( aRadius >= aAccuracy )
544 for(
int i = 0; i <= n; i++, rot +=
delta )
546 double x = aCenter.
x + aRadius * rot.
Cos();
547 double y = aCenter.
y + aRadius * rot.
Sin();
560 int errorRadius = aRadius + actual_delta_radius;
562 double x = aCenter.
x + aRadius * aStartAngle.
Cos();
563 double y = aCenter.
y + aRadius * aStartAngle.
Sin();
569 for(
int i = 0; i < n; i++, rot +=
delta )
571 x = aCenter.
x + errorRadius * rot.
Cos();
572 y = aCenter.
y + errorRadius * rot.
Sin();
577 x = aCenter.
x + aRadius * ( aStartAngle + aArcAngle ).Cos();
578 y = aCenter.
y + aRadius * ( aStartAngle + aArcAngle ).Sin();
590 SEG startToEnd( aStart, aEnd );
591 int distanceToMid = startToEnd.
Distance( aMid );
593 if( distanceToMid <= 1 )
603 SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
606 EDA_ANGLE arc_angle_end = arc_angle_start + arc_angle;
610 std::swap( arc_angle_start, arc_angle_end );
611 arc =
SHAPE_ARC( aEnd, aMid, aStart, aWidth );
612 arc_angle = -arc_angle;
615 int radial_offset = arc.
GetWidth() / 2;
616 int arc_outer_radius = arc.
GetRadius() + radial_offset;
617 int arc_inner_radius = arc.
GetRadius() - radial_offset;
632 aError, errorLocOuter );
639 if( arc_inner_radius > 0 )
642 -arc_angle, aError, errorLocInner );
645 aBuffer.
Append( polyshape );
650 int aWidth,
int aError,
ERROR_LOC aErrorLoc )
652 int inner_radius = aRadius - ( aWidth / 2 );
653 int outer_radius = inner_radius + aWidth;
655 if( inner_radius <= 0 )
671 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
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() 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.
constexpr ret_type KiROUND(fp_type v, bool aQuiet=false)
Round a floating point number to an integer using "round halfway cases away from zero".
VECTOR2< int32_t > VECTOR2I