37constexpr double OVERLAP_EPSILON = 1e-7;
41concept LINE_LIKE = std::same_as<T, SEG> || std::same_as<T, LINE> || std::same_as<T, HALF_LINE>;
45concept CIRCULAR = std::same_as<T, CIRCLE> || std::same_as<T, SHAPE_ARC>;
51template <
typename GEOM>
53bool extentContains(
const GEOM& aGeom,
const VECTOR2I& aPoint )
55 if constexpr( std::same_as<GEOM, LINE> || std::same_as<GEOM, CIRCLE> )
57 else if constexpr( std::same_as<GEOM, SHAPE_ARC> )
58 return aGeom.Collide( aPoint );
60 return aGeom.Contains( aPoint );
63template <LINE_LIKE GEOM>
64const SEG& carrierSeg(
const GEOM& aGeom )
66 if constexpr( std::same_as<GEOM, SEG> )
69 return aGeom.GetContainedSeg();
72template <CIRCULAR GEOM>
73CIRCLE carrierCircle(
const GEOM& aGeom )
75 if constexpr( std::same_as<GEOM, CIRCLE> )
78 return CIRCLE( aGeom.GetCenter(),
KiROUND( aGeom.GetRadius() ) );
82std::pair<double, double> extentAlong(
const SEG& aSeg,
const SEG& aRef )
87std::pair<double, double> extentAlong(
const LINE&,
const SEG& )
89 return { -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity() };
92std::pair<double, double> extentAlong(
const HALF_LINE& aHalfLine,
const SEG& aRef )
98 return { start, std::numeric_limits<double>::infinity() };
100 return { -std::numeric_limits<double>::infinity(), start };
104template <LINE_LIKE GEOM_A, LINE_LIKE GEOM_B>
110 const SEG& refSeg = carrierSeg( aA );
112 if( !refSeg.
Collinear( carrierSeg( aB ) ) )
115 const auto [aLow, aHigh] = extentAlong( aA, refSeg );
116 const auto [bLow, bHigh] = extentAlong( aB, refSeg );
118 if( std::min( aHigh, bHigh ) - std::max( aLow, bLow ) > OVERLAP_EPSILON )
123template <LINE_LIKE LINE_GEOM, CIRCULAR CIRCULAR_GEOM>
124void checkLineTangency(
const LINE_GEOM& aLine,
const CIRCULAR_GEOM& aCircular,
INTERSECTION_CONTACT* aContact )
129 std::vector<VECTOR2I> touches = carrierCircle( aCircular ).IntersectLine( carrierSeg( aLine ) );
131 if( touches.size() == 1 && extentContains( aLine, touches.front() )
132 && extentContains( aCircular, touches.front() ) )
139template <CIRCULAR GEOM_A, CIRCULAR GEOM_B>
140bool sharesArcExtent(
const GEOM_A&,
const GEOM_B& )
151template <CIRCULAR GEOM_A, CIRCULAR GEOM_B>
157 const CIRCLE circleA = carrierCircle( aA );
158 const CIRCLE circleB = carrierCircle( aB );
171 std::vector<VECTOR2I> touches = circleA.
Intersect( circleB );
173 if( touches.size() == 1 && extentContains( aA, touches.front() ) && extentContains( aB, touches.front() ) )
177void findIntersections(
const SEG& aSegA,
const SEG& aSegB, std::vector<VECTOR2I>& aIntersections,
180 checkCollinearOverlap( aSegA, aSegB, aContact );
186 aIntersections.push_back( *intersection );
190void findIntersections(
const SEG& aSeg,
const LINE& aLine, std::vector<VECTOR2I>& aIntersections,
193 checkCollinearOverlap( aSeg, aLine, aContact );
199 aIntersections.push_back( *intersection );
203void findIntersections(
const SEG& aSeg,
const HALF_LINE& aHalfLine,
206 checkCollinearOverlap( aSeg, aHalfLine, aContact );
212 aIntersections.push_back( *intersection );
216void findIntersections(
const SEG& aSeg,
const CIRCLE& aCircle,
219 checkLineTangency( aSeg, aCircle, aContact );
221 std::vector<VECTOR2I> intersections = aCircle.
Intersect( aSeg );
223 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
226void findIntersections(
const SEG& aSeg,
const SHAPE_ARC& aArc,
229 checkLineTangency( aSeg, aArc, aContact );
231 std::vector<VECTOR2I> intersections;
235 for(
const VECTOR2I& intersection : intersections )
239 aIntersections.emplace_back( intersection );
244void findIntersections(
const LINE& aLineA,
const LINE& aLineB,
247 checkCollinearOverlap( aLineA, aLineB, aContact );
253 aIntersections.push_back( *intersection );
257void findIntersections(
const LINE& aLine,
const HALF_LINE& aHalfLine,
260 checkCollinearOverlap( aLine, aHalfLine, aContact );
272 if( aHalfLine.
Contains( *intersection ) )
274 aIntersections.push_back( *intersection );
281 checkCollinearOverlap( aHalfLineA, aHalfLineB, aContact );
287 aIntersections.push_back( *intersection );
291void findIntersections(
const CIRCLE& aCircle,
const LINE& aLine,
294 checkLineTangency( aLine, aCircle, aContact );
298 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
301void findIntersections(
const CIRCLE& aCircle,
const HALF_LINE& aHalfLine,
304 checkLineTangency( aHalfLine, aCircle, aContact );
308 for(
const VECTOR2I& intersection : intersections )
310 if( aHalfLine.
Contains( intersection ) )
312 aIntersections.push_back( intersection );
317void findIntersections(
const CIRCLE& aCircleA,
const CIRCLE& aCircleB,
320 checkCircularContact( aCircleA, aCircleB, aContact );
322 std::vector<VECTOR2I> intersections = aCircleA.
Intersect( aCircleB );
323 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
329 checkCircularContact( aCircle, aArc, aContact );
331 aArc.
Intersect( aCircle, &aIntersections );
337 checkCircularContact( aArcA, aArcB, aContact );
339 aArcA.
Intersect( aArcB, &aIntersections );
342void findIntersections(
const SHAPE_ARC& aArc,
const LINE& aLine,
345 checkLineTangency( aLine, aArc, aContact );
347 std::vector<VECTOR2I> intersections;
350 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
356 checkLineTangency( aHalfLine, aArc, aContact );
358 std::vector<VECTOR2I> intersections;
361 for(
const VECTOR2I& intersection : intersections )
363 if( aHalfLine.
Contains( intersection ) )
365 aIntersections.push_back( intersection );
374void findIntersections(
const SHAPE_ELLIPSE& aEllipse,
const SEG& aSeg, std::vector<VECTOR2I>& aIntersections,
377 std::vector<VECTOR2I> intersections = aEllipse.
Intersect( aSeg );
379 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
382void findIntersections(
const SHAPE_ELLIPSE& aEllipse,
const LINE& aLine, std::vector<VECTOR2I>& aIntersections,
387 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
395 for(
const VECTOR2I& intersection : intersections )
397 if( aHalfLine.
Contains( intersection ) )
399 aIntersections.push_back( intersection );
404void findIntersections(
const SHAPE_ELLIPSE& aEllipse,
const CIRCLE& aCircle, std::vector<VECTOR2I>& aIntersections,
407 std::vector<VECTOR2I> intersections = aEllipse.
Intersect( aCircle );
409 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
412void findIntersections(
const SHAPE_ELLIPSE& aEllipse,
const SHAPE_ARC& aArc, std::vector<VECTOR2I>& aIntersections,
415 std::vector<VECTOR2I> intersections = aEllipse.
Intersect( aArc );
417 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
423 std::vector<VECTOR2I> intersections = aEllipseA.
Intersect( aEllipseB );
425 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
432 std::vector<VECTOR2I>& aIntersections ) :
439 std::vector<VECTOR2I>& aIntersections,
458 [&](
const auto& otherGeom )
460 using OtherGeomType = std::decay_t<
decltype( otherGeom )>;
462 if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
470 else if constexpr( std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
488 [&](
const auto& otherGeom )
490 using OtherGeomType = std::decay_t<
decltype( otherGeom )>;
492 if constexpr( std::is_same_v<OtherGeomType, SEG> || std::is_same_v<OtherGeomType, LINE>
493 || std::is_same_v<OtherGeomType, CIRCLE> || std::is_same_v<OtherGeomType, SHAPE_ARC>
494 || std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
499 else if constexpr( std::is_same_v<OtherGeomType, HALF_LINE> )
504 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
515 "Unhandled other geometry type" );
525 [&](
const auto& otherGeom )
527 using OtherGeomType = std::decay_t<
decltype( otherGeom )>;
529 if constexpr( std::is_same_v<OtherGeomType, SEG> || std::is_same_v<OtherGeomType, HALF_LINE>
530 || std::is_same_v<OtherGeomType, CIRCLE> || std::is_same_v<OtherGeomType, SHAPE_ARC>
531 || std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
537 else if constexpr( std::is_same_v<OtherGeomType, LINE> )
542 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
553 "Unhandled other geometry type" );
563 [&](
const auto& otherGeom )
565 using OtherGeomType = std::decay_t<
decltype( otherGeom )>;
567 if constexpr( std::is_same_v<OtherGeomType, SEG> || std::is_same_v<OtherGeomType, CIRCLE>
568 || std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
573 else if constexpr( std::is_same_v<OtherGeomType, SHAPE_ARC>
574 || std::is_same_v<OtherGeomType, LINE>
575 || std::is_same_v<OtherGeomType, HALF_LINE> )
580 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
591 "Unhandled other geometry type" );
601 [&](
const auto& otherGeom )
603 using OtherGeomType = std::decay_t<
decltype( otherGeom )>;
605 if constexpr( std::is_same_v<OtherGeomType, SEG> || std::is_same_v<OtherGeomType, CIRCLE>
606 || std::is_same_v<OtherGeomType, SHAPE_ARC>
607 || std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
612 else if constexpr( std::is_same_v<OtherGeomType, LINE>
613 || std::is_same_v<OtherGeomType, HALF_LINE> )
618 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
629 "Unhandled other geometry type" );
640 [&](
const auto& otherGeom )
642 using OtherGeomType = std::decay_t<
decltype( otherGeom )>;
644 if constexpr( std::is_same_v<OtherGeomType, SEG> || std::is_same_v<OtherGeomType, LINE>
645 || std::is_same_v<OtherGeomType, HALF_LINE> || std::is_same_v<OtherGeomType, CIRCLE>
646 || std::is_same_v<OtherGeomType, SHAPE_ARC>
647 || std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
651 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
676 for(
const SEG& seg : segs )
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Represent basic circle geometry with utility geometry functions.
VECTOR2I Center
Public to make access simpler.
int Radius
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.
OPT_VECTOR2I Intersect(const SEG &aSeg) const
const SEG & GetContainedSeg() const
Gets the (one of the infinite number of) segments that the ray passes through.
bool Contains(const VECTOR2I &aPoint) const
const SEG & GetContainedSeg() const
Gets the (one of the infinite number of) segments that the line passes through.
OPT_VECTOR2I Intersect(const SEG &aOther) const
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
bool Collinear(const SEG &aSeg) const
Check if segment aSeg lies on the same line as (this).
bool Contains(const SEG &aSeg) const
const VECTOR2I & GetArcMid() const
int Intersect(const CIRCLE &aArc, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and a CIRCLE.
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,...
std::vector< VECTOR2I > Intersect(const SHAPE_ELLIPSE &aOther) const
Find the points where this curve crosses another one.
Carries a circle. CIRCLE is its own.
Carries a seg. SEG is its own.
std::variant< LINE, HALF_LINE, SEG, CIRCLE, SHAPE_ARC, SHAPE_ELLIPSE, BOX2I > INTERSECTABLE_GEOM
A variant type that can hold any of the supported geometry types for intersection calculations.
std::array< SEG, 4 > BoxToSegs(const BOX2I &aBox)
Decompose a BOX2 into four segments.
double ParameterAlong(const SEG &aSeg, const VECTOR2I &aPoint)
Position of a point along a segment.
std::optional< VECTOR2I > OPT_VECTOR2I
Utility functions for working with shapes.
INTERSECTION_CONTACT * m_contact
const INTERSECTABLE_GEOM & m_otherGeometry
INTERSECTION_VISITOR(const INTERSECTABLE_GEOM &aOtherGeometry, std::vector< VECTOR2I > &aIntersections)
std::vector< VECTOR2I > & m_intersections
void operator()(const SEG &aSeg) const
A type that is always false.
VECTOR2< int32_t > VECTOR2I