39 aStream <<
"Arc( P0=" << aArc.
GetP0() <<
" P1=" << aArc.
GetP1() <<
" Mid=" << aArc.
GetArcMid()
40 <<
" Width=" << aArc.
GetWidth() <<
" )";
46 const EDA_ANGLE& aCenterAngle,
int aWidth ) :
67 const VECTOR2I& aArcEnd,
int aWidth ) :
125 if( !p || aSegmentA.
Length() == 0 || aSegmentB.
Length() == 0 )
128 wxASSERT_MSG( false,
"The input segments do not intersect or one is zero length." );
131 m_start = aSegmentA.A;
135 VECTOR2I arcCenter = aSegmentA.Center();
136 RotatePoint( m_mid, arcCenter, ANGLE_90 );
140 VECTOR2I pToA = aSegmentA.B - *p;
141 VECTOR2I pToB = aSegmentB.B - *p;
143 if( pToA.EuclideanNorm() == 0 )
144 pToA = aSegmentA.A - *p;
146 if( pToB.EuclideanNorm() == 0 )
147 pToB = aSegmentB.A - *p;
149 EDA_ANGLE pToAangle( pToA );
150 EDA_ANGLE pToBangle( pToB );
152 EDA_ANGLE alpha = ( pToAangle - pToBangle ).Normalize180();
154 double distPC = (double) aRadius / abs( sin( alpha.AsRadians() / 2 ) );
155 EDA_ANGLE angPC = pToAangle - alpha / 2;
158 arcCenter.x = p->x + KiROUND( distPC * angPC.Cos() );
159 arcCenter.y = p->y + KiROUND( distPC * angPC.Sin() );
163 m_start = aSegmentA.LineProject( arcCenter );
164 m_end = aSegmentB.LineProject( arcCenter );
167 VECTOR2I startVector = m_start - arcCenter;
168 VECTOR2I endVector = m_end - arcCenter;
170 EDA_ANGLE startAngle( startVector );
171 EDA_ANGLE endAngle( endVector );
172 EDA_ANGLE midPointRotAngle = ( startAngle - endAngle ).Normalize180() / 2;
175 RotatePoint( m_mid, arcCenter, midPointRotAngle );
221 const VECTOR2I& aCenter,
bool aClockwise,
224 VECTOR2I startLine = aStart - aCenter;
257 return v1.ApproxCollinear(
v2 ) && (
v1.B -
v1.A).Dot(
v2.B -
v2.A) > 0;
268 if(
radius >= (
double) std::numeric_limits<int>::max() / 2.0 )
273 std::vector<VECTOR2I> candidatePts;
281 candidatePts.push_back( aSeg.
A );
282 candidatePts.push_back( aSeg.
B );
284 bool any_collides =
false;
286 for(
const VECTOR2I& candidate : candidatePts )
288 bool collides =
Collide( candidate, aClearance, aActual, aLocation );
289 any_collides |= collides;
291 if( collides && ( !aActual || *aActual == 0 ) )
303 && (
m_start -
m_end ).SquaredEuclideanNorm() < clearance_sq )
305 ecoord a_dist_sq = ( aSeg.
A -
center ).SquaredEuclideanNorm();
306 ecoord b_dist_sq = ( aSeg.
B -
center ).SquaredEuclideanNorm();
309 if( a_dist_sq < radius_sq && b_dist_sq < radius_sq )
313 return circle.Collide( aSeg, aClearance, aActual, aLocation );
322 std::vector<VECTOR2I> candidatePts =
circle.GetCircle().Intersect( aSeg );
327 candidatePts.push_back( aSeg.
A );
328 candidatePts.push_back( aSeg.
B );
330 bool any_collides =
false;
332 for(
const VECTOR2I& candidate : candidatePts )
334 bool collides =
Collide( candidate, aClearance, aActual, aLocation );
335 any_collides |= collides;
337 if( collides && ( !aActual || *aActual == 0 ) )
347 if( aSeg.
A == aSeg.
B )
350 if(
GetRadius() >= (
double) std::numeric_limits<int>::max() / 2.0 )
355 std::vector<VECTOR2I> intersections = circ.
IntersectLine( aSeg );
357 const size_t originalSize = aIpsBuffer->size();
359 for(
const VECTOR2I& intersection : intersections )
362 aIpsBuffer->push_back( intersection );
365 return aIpsBuffer->size() - originalSize;
371 if(
GetRadius() >= (
double) std::numeric_limits<int>::max() / 2.0 )
376 std::vector<VECTOR2I> intersections = thiscirc.
Intersect( aCircle );
378 const size_t originalSize = aIpsBuffer->size();
380 for(
const VECTOR2I& intersection : intersections )
383 aIpsBuffer->push_back( intersection );
386 return aIpsBuffer->size() - originalSize;
392 if(
GetRadius() >= (
double) std::numeric_limits<int>::max() / 2.0
393 || aArc.
GetRadius() >= (
double) std::numeric_limits<int>::max() / 2.0 )
401 std::vector<VECTOR2I> intersections = thiscirc.
Intersect( othercirc );
403 const size_t originalSize = aIpsBuffer->size();
405 for(
const VECTOR2I& intersection : intersections )
408 aIpsBuffer->push_back( intersection );
411 return aIpsBuffer->size() - originalSize;
420 std::vector<VECTOR2I> points;
423 points.push_back(
m_mid );
424 points.push_back(
m_end );
430 if( start_angle > end_angle )
431 std::swap( start_angle, end_angle );
433 int quad_angle_start = std::ceil( start_angle.
AsDegrees() / 90.0 );
434 int quad_angle_end = std::floor( end_angle.
AsDegrees() / 90.0 );
439 if(
m_radius < (
double)INT_MAX/2.0 )
444 for(
int quad_angle = quad_angle_start; quad_angle <= quad_angle_end; ++quad_angle )
448 switch( quad_angle % 4 )
450 case 0: quad_pt += {
radius, 0 };
break;
451 case 1:
case -3: quad_pt += { 0,
radius };
break;
452 case 2:
case -2: quad_pt += { -
radius, 0 };
break;
453 case 3:
case -1: quad_pt += { 0, -
radius };
break;
458 points.push_back( quad_pt );
473 if( aClearance != 0 )
482 const static int s_epsilon = 8;
487 if( ( nearestPt -
m_start ).SquaredEuclideanNorm() <= s_epsilon )
490 if( ( nearestPt -
m_end ).SquaredEuclideanNorm() <= s_epsilon )
496 if( ( aP -
m_start ).SquaredEuclideanNorm() <= ( aP -
m_end ).SquaredEuclideanNorm() )
504 int64_t& aDistSq )
const
508 aPtA = aPtB =
GetP0();
513 aDistSq = std::numeric_limits<int64_t>::max();
517 std::vector<VECTOR2I> intersections = circle1.
Intersect( circle2 );
519 for(
const VECTOR2I& pt : intersections )
538 if( distSq < aDistSq )
561 int64_t& aDistSq )
const
563 aDistSq = std::numeric_limits<int64_t>::max();
567 std::vector<VECTOR2I> intersections =
circle.Intersect( aSeg );
569 for(
const VECTOR2I& pt : intersections )
580 for(
const VECTOR2I& pt : { aSeg.
A, aSeg.
B } )
585 int64_t distSq = pt.SquaredDistance( nearestPt );
587 if( distSq < aDistSq )
602 if( distSq < aDistSq )
618 if( distSq < aDistSq )
622 aPtB = circleNearestPt;
640 int64_t& aDistSq )
const
642 aDistSq = std::numeric_limits<int64_t>::max();
654 int64_t& aDistSq )
const
656 auto adjustForArcWidths =
664 dir = ( aPtA - aPtB ).Resize( aArc.
GetWidth() / 2 );
673 aDistSq = std::numeric_limits<int64_t>::max();
681 bool colocated = center_dist_sq < center_epsilon * center_epsilon;
685 std::vector<VECTOR2I> pts2 = { aArc.
GetP0(), aArc.
GetP1() };
691 int64_t distSq = pt1.SquaredDistance( pt2 );
693 if( distSq < aDistSq )
711 aPtB =
circle.NearestPoint( pt );
714 if( colocated || aDistSq == 0 )
717 adjustForArcWidths();
729 aPtA =
circle.NearestPoint( pt );
733 if( colocated || aDistSq == 0 )
736 adjustForArcWidths();
751 std::vector<VECTOR2I> intersections = circle1.
Intersect( circle2 );
753 for(
const VECTOR2I& pt : intersections )
770 if( pt1InSlice && pt2InSlice )
774 if( distSq < aDistSq )
781 adjustForArcWidths();
790 int64_t distSq = pt.SquaredDistance( pt2 );
792 if( distSq < aDistSq )
806 int64_t distSq = pt.SquaredDistance( pt1 );
808 if( distSq < aDistSq )
817 adjustForArcWidths();
825 int minDist = aClearance +
m_width / 2;
826 auto bbox =
BBox( minDist );
829 if( !bbox.Contains( aP ) )
837 if(
radius >= (
double) std::numeric_limits<int>::max() / 2.0 )
843 int dist = std::min( dist1, dist2 );
845 if( dist <= minDist )
848 *aActual = std::max( 0, dist -
m_width / 2 );
880 if( ( ccw && rotatedPtAngle > rotatedEndAngle )
881 || ( !ccw && rotatedPtAngle < rotatedEndAngle ) )
883 int distStartpt = ( aP -
m_start ).EuclideanNorm();
884 int distEndpt = ( aP -
m_end ).EuclideanNorm();
886 if( distStartpt < distEndpt )
899 if( dist <= minDist )
902 *aLocation = nearestPt;
905 *aActual = std::max( 0, dist -
m_width / 2 );
990 double halfMaxError = std::max( 1.0, aMaxError / 2.0 );
996 double external_radius = r + (
m_width / 2.0 );
997 double effectiveError;
999 if( external_radius < halfMaxError
1005 effectiveError = external_radius;
1012 int seg360 = n * 360.0 / fabs( ca.
AsDegrees() );
1019 r += effectiveError / 2;
1024 for(
int i = 1; i < n ; i += 2 )
1029 a += ( ca * i ) / n;
1031 double x = c.
x + r * a.
Cos();
1032 double y = c.
y + r * a.
Sin();
1040 *aActualError =
KiROUND( effectiveError );
1120 return phi >= sa && phi <= ea;
1127 return phi <= sa && phi >= ea;
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)
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Represent basic circle geometry with utility geometry functions.
VECTOR2I Center
Public to make access simpler.
std::vector< VECTOR2I > Intersect(const CIRCLE &aCircle) const
Compute the intersection points between this circle and aCircle.
std::vector< VECTOR2I > IntersectLine(const SEG &aLine) const
Compute the intersection points between this circle and aLine.
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute the point on the circumference of the circle that is the closest to aP.
const VECTOR2I ReflectPoint(const VECTOR2I &aP) const
Reflect a point using this segment as axis.
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
int Length() const
Return the length (this).
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
static SEG::ecoord Square(int a)
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
const VECTOR2I & GetArcMid() const
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aMaxError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
void Move(const VECTOR2I &aVector) override
SHAPE_ARC & ConstructFromStartEndAngle(const VECTOR2I &aStart, const VECTOR2I &aEnd, const EDA_ANGLE &aAngle, double aWidth=0)
Construct this arc from the given start, end and angle.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
int GetWidth() const override
EDA_ANGLE GetEndAngle() const
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter) override
Rotate the arc by a given angle about a point.
bool sliceContainsPoint(const VECTOR2I &p) const
const SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError=DefaultAccuracyForPCB(), int *aActualError=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
VECTOR2I NearestPoint(const VECTOR2I &aP) const
int Intersect(const CIRCLE &aArc, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and a CIRCLE.
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
SHAPE_ARC Reversed() const
const VECTOR2I & GetP1() const
int IntersectLine(const SEG &aSeg, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and aSeg, treating aSeg as an infinite line.
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
EDA_ANGLE GetStartAngle() const
bool IsEffectiveLine() const
bool NearestPoints(const SHAPE_ARC &aArc, VECTOR2I &aPtA, VECTOR2I &aPtB, int64_t &aDistSq) const
Compute closest points between this arc and aArc.
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
const CIRCLE GetCircle() 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 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.
const SHAPE_LINE_CHAIN Outline() const
VECTOR2I::extended_type ecoord
SHAPE(SHAPE_TYPE aType)
Create an empty shape of type aType.
bool NearestPoints(const SHAPE *aOther, VECTOR2I &aPtThis, VECTOR2I &aPtOther) const
Return the two points that mark the closest distance between this shape and aOther.
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
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.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_360
a few functions useful in geometry calculations.
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
@ LEFT_RIGHT
Flip left to right (around the Y axis)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::optional< VECTOR2I > OPT_VECTOR2I
std::ostream & operator<<(std::ostream &aStream, const SHAPE_ARC &aArc)
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
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.
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR2< int64_t > VECTOR2L