39 int aError,
ERROR_LOC aErrorLoc,
int aMinSegCount )
43 numSegs = std::max( aMinSegCount, numSegs );
46 numSegs = ( numSegs + 7 ) / 8 * 8;
62 corner_position.
x = radius;
63 corner_position.
y = 0;
65 corner_position += aCenter;
66 aBuffer.
Append( corner_position.
x, corner_position.
y );
74 int aError,
ERROR_LOC aErrorLoc,
int aMinSegCount )
78 numSegs = std::max( aMinSegCount, numSegs );
81 numSegs = ( numSegs + 7 ) / 8 * 8;
99 corner_position.
x = radius;
100 corner_position.
y = 0;
102 corner_position += aCenter;
103 aBuffer.
Append( corner_position.
x, corner_position.
y );
107 corner_position.
x = radius;
108 corner_position.
y = 0;
110 corner_position += aCenter;
111 aBuffer.
Append( corner_position.
x, corner_position.
y );
116 int aWidth,
int aError,
ERROR_LOC aErrorLoc,
int aMinSegCount )
123 int radius = aWidth / 2;
125 numSegs = std::max( aMinSegCount, numSegs );
128 numSegs = ( numSegs + 7 ) / 8 * 8;
154 endp = aStart - aEnd;
168 corner =
VECTOR2I( seg_len, radius );
169 polyshape.
Append( corner.
x, corner.
y );
176 polyshape.
Append( corner.
x, corner.
y );
180 corner =
VECTOR2I( seg_len, -radius );
181 polyshape.
Append( corner.
x, corner.
y );
185 polyshape.
Append( corner.
x, corner.
y );
192 polyshape.
Append( corner.
x, corner.
y );
197 polyshape.
Append( corner.
x, corner.
y );
204 int halfwidth = aWidth / 2;
205 corner.
x = -radius - 2;
207 corner.
y = halfwidth;
209 corner.
y = -halfwidth;
211 corner.
x = radius + seg_len + 2;
213 corner.
y = halfwidth;
222 polyshape.
Rotate( -delta_angle );
223 polyshape.
Move( startp );
225 aBuffer.
Append( polyshape);
240 int aInflate,
int aError,
ERROR_LOC aErrorLoc )
242 assert( aInflate >= 0 );
244 VECTOR2I incoming = aCorners[0].m_position - aCorners.back().m_position;
246 for(
int n = 0, count = aCorners.size(); n < count; n++ )
263 if( ( incoming.
x == 0 && outgoing.y == 0 ) || ( incoming.
y == 0 && outgoing.x == 0 ) )
270 double cosNum = (double) incoming.
x * outgoing.x + (
double) incoming.
y * outgoing.y;
271 double cosDen = (double) incoming.
EuclideanNorm() * outgoing.EuclideanNorm();
272 double angle = acos( cosNum / cosDen );
273 tanAngle2 = tan( ( M_PI - angle ) / 2 );
277 if( aInflate && tanAngle2 )
280 cornerPosition += incoming.
Resize( aInflate / tanAngle2 )
291 while( lastSeg > angDelta )
296 while( lastSeg < -angDelta )
300 EDA_ANGLE angPos = lastSeg.
IsZero() ? angDelta : ( angDelta + lastSeg ) / 2;
302 double arcTransitionDistance = ( tanAngle2 > 0 ) ? ( radius / tanAngle2 ) : 0;
303 VECTOR2I arcStart = cornerPosition - incoming.
Resize( arcTransitionDistance );
310 arcStartOrigin = arcStart - arcCenter;
311 outline.
Append( arcStart );
319 arcStartOrigin = arcStart - arcCenter;
323 SEG outlineIn( cornerPosition - incoming, cornerPosition );
325 arcEnd = cornerPosition;
327 while( angPos < endAngle )
334 if( outlineIn.
Side( pt ) > 0 )
338 wxCHECK_RET(
intersect, wxT(
"No solutions exist!" ) );
345 endAngle -= angDelta;
350 for( ; angPos < endAngle; angPos += angDelta )
354 outline.
Append( pt + arcCenter );
367 VECTOR2I prev = aCorners[0].m_position;
369 for(
int pos = aCorners.size() - 1; pos >= 0; pos-- )
371 if( aCorners[pos].m_position == prev )
372 aCorners.erase( aCorners.begin() + pos );
374 prev = aCorners[pos].m_position;
381 int aDeltaY,
int aInflate,
int aError,
ERROR_LOC aErrorLoc )
385 std::vector<ROUNDED_CORNER> corners;
389 if( !aDeltaX && !aDeltaY )
391 size.
x = std::max( 1, size.
x + aInflate );
392 size.
y = std::max( 1, size.
y + aInflate );
396 double slope = (double) aDeltaX / size.
x;
397 int yShrink =
KiROUND( ( std::hypot( size.
x, aDeltaX ) * aInflate ) / size.
x );
398 size.
y = std::max( 1, size.
y + yShrink );
399 size.
x = std::max( 1, size.
x + aInflate );
400 aDeltaX =
KiROUND( size.
x * slope );
402 if( aDeltaX > size.
y )
404 corners.reserve( 3 );
405 corners.emplace_back( -size.
x, -size.
y - aDeltaX );
406 corners.emplace_back(
KiROUND( size.
y / slope ), 0 );
407 corners.emplace_back( -size.
x, size.
y + aDeltaX );
412 double slope = (double) aDeltaY / size.
y;
413 int xShrink =
KiROUND( ( std::hypot( size.
y, aDeltaY ) * aInflate ) / size.
y );
414 size.
x = std::max( 1, size.
x + xShrink );
415 size.
y = std::max( 1, size.
y + aInflate );
416 aDeltaY =
KiROUND( size.
y * slope );
418 if( aDeltaY > size.
x )
420 corners.reserve( 3 );
421 corners.emplace_back( 0, -
KiROUND( size.
x / slope ) );
422 corners.emplace_back( size.
x + aDeltaY, size.
y );
423 corners.emplace_back( -size.
x - aDeltaY, size.
y );
430 if( corners.empty() )
432 corners.reserve( 4 );
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 );
436 corners.emplace_back( -size.
x - aDeltaY, size.
y + aDeltaX );
445 outline.
Rotate( aRotation );
448 aBuffer.
Append( outline );
454 int aCornerRadius,
double aChamferRatio,
455 int aChamferCorners,
int aInflate,
int aError,
460 int chamferCnt = std::bitset<8>( aChamferCorners ).count();
461 double chamferDeduct = 0;
465 size.
x = std::max( 1, size.
x + aInflate );
466 size.
y = std::max( 1, size.
y + aInflate );
467 chamferDeduct = aInflate * ( 2.0 - M_SQRT2 );
468 aCornerRadius = std::max( 0, aCornerRadius + aInflate );
472 std::vector<ROUNDED_CORNER> corners;
473 corners.reserve( 4 + chamferCnt );
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 );
477 corners.emplace_back( -size.
x, size.
y, aCornerRadius );
479 if( aChamferCorners )
481 int shorterSide = std::min( aSize.
x, aSize.
y );
482 int chamfer = std::max( 0,
KiROUND( aChamferRatio * shorterSide + chamferDeduct ) );
485 int sign[8] = { 0, 1, -1, 0, 0, -1, 1, 0 };
487 for(
int cc = 0, pos = 0; cc < 4; cc++, pos++ )
489 if( !( aChamferCorners & chamId[cc] ) )
492 corners[pos].m_radius = 0;
497 corners.insert( corners.begin() + pos + 1, corners[pos] );
498 corners[pos].m_position.x +=
sign[( 2 * cc ) & 7] *
chamfer;
499 corners[pos].m_position.y +=
sign[( 2 * cc - 2 ) & 7] *
chamfer;
500 corners[pos + 1].m_position.x +=
sign[( 2 * cc + 1 ) & 7] *
chamfer;
501 corners[pos + 1].m_position.y +=
sign[( 2 * cc - 1 ) & 7] *
chamfer;
505 if( chamferCnt > 1 && 2 *
chamfer >= shorterSide )
512 outline.
Rotate( aRotation );
514 outline.
Move( aPosition );
515 aBuffer.
Append( outline );
525 if( aRadius >= aAccuracy )
537 for(
int i = 0; i <= n; i++, rot +=
delta )
539 double x = aCenter.
x + aRadius * rot.
Cos();
540 double y = aCenter.
y + aRadius * rot.
Sin();
553 int errorRadius = aRadius + actual_delta_radius;
555 double x = aCenter.
x + aRadius * aStartAngle.
Cos();
556 double y = aCenter.
y + aRadius * aStartAngle.
Sin();
562 for(
int i = 0; i < n; i++, rot +=
delta )
564 x = aCenter.
x + errorRadius * rot.
Cos();
565 y = aCenter.
y + errorRadius * rot.
Sin();
570 x = aCenter.
x + aRadius * ( aStartAngle + aArcAngle ).Cos();
571 y = aCenter.
y + aRadius * ( aStartAngle + aArcAngle ).Sin();
583 SEG startToEnd( aStart, aEnd );
584 int distanceToMid = startToEnd.
Distance( aMid );
586 if( distanceToMid <= 1 )
596 SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
599 EDA_ANGLE arc_angle_end = arc_angle_start + arc_angle;
603 std::swap( arc_angle_start, arc_angle_end );
604 arc =
SHAPE_ARC( aEnd, aMid, aStart, aWidth );
605 arc_angle = -arc_angle;
608 int radial_offset = arc.
GetWidth() / 2;
609 int arc_outer_radius = arc.
GetRadius() + radial_offset;
610 int arc_inner_radius = arc.
GetRadius() - radial_offset;
625 aError, errorLocOuter );
632 if( arc_inner_radius > 0 )
635 -arc_angle, aError, errorLocInner );
638 aBuffer.
Append( polyshape );
643 int aWidth,
int aError,
ERROR_LOC aErrorLoc )
645 int inner_radius = aRadius - ( aWidth / 2 );
646 int outer_radius = inner_radius + aWidth;
648 if( inner_radius <= 0 )
664 aError, inner_err_loc );
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
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).
constexpr 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)
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 int sign(T val)
VECTOR2< int32_t > VECTOR2I