KiCad PCB EDA Suite
Loading...
Searching...
No Matches
intersection.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <core/type_helpers.h>
23
25
26#include <algorithm>
27#include <concepts>
28#include <limits>
29
30/*
31 * Helper functions that dispatch to the correct intersection function
32 * in one of the geometry classes.
33 */
34namespace
35{
36
37constexpr double OVERLAP_EPSILON = 1e-7;
38
40template <typename T>
41concept LINE_LIKE = std::same_as<T, SEG> || std::same_as<T, LINE> || std::same_as<T, HALF_LINE>;
42
44template <typename T>
45concept CIRCULAR = std::same_as<T, CIRCLE> || std::same_as<T, SHAPE_ARC>;
46
47/*
48 * A contact counts only where it lies on both geometries, so each shape answers for its own
49 * extent. LINE and CIRCLE are unbounded carriers. Any point off them is on them.
50 */
51template <typename GEOM>
53bool extentContains( const GEOM& aGeom, const VECTOR2I& aPoint )
54{
55 if constexpr( std::same_as<GEOM, LINE> || std::same_as<GEOM, CIRCLE> )
56 return true;
57 else if constexpr( std::same_as<GEOM, SHAPE_ARC> )
58 return aGeom.Collide( aPoint );
59 else
60 return aGeom.Contains( aPoint );
61}
62
63template <LINE_LIKE GEOM>
64const SEG& carrierSeg( const GEOM& aGeom )
65{
66 if constexpr( std::same_as<GEOM, SEG> )
67 return aGeom;
68 else
69 return aGeom.GetContainedSeg();
70}
71
72template <CIRCULAR GEOM>
73CIRCLE carrierCircle( const GEOM& aGeom )
74{
75 if constexpr( std::same_as<GEOM, CIRCLE> )
76 return aGeom;
77 else
78 return CIRCLE( aGeom.GetCenter(), KiROUND( aGeom.GetRadius() ) );
79}
80
82std::pair<double, double> extentAlong( const SEG& aSeg, const SEG& aRef )
83{
84 return std::minmax( KIGEOM::ParameterAlong( aRef, aSeg.A ), KIGEOM::ParameterAlong( aRef, aSeg.B ) );
85}
86
87std::pair<double, double> extentAlong( const LINE&, const SEG& )
88{
89 return { -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity() };
90}
91
92std::pair<double, double> extentAlong( const HALF_LINE& aHalfLine, const SEG& aRef )
93{
94 const SEG& ray = aHalfLine.GetContainedSeg();
95 double start = KIGEOM::ParameterAlong( aRef, ray.A );
96
97 if( KIGEOM::ParameterAlong( aRef, ray.B ) > start )
98 return { start, std::numeric_limits<double>::infinity() };
99
100 return { -std::numeric_limits<double>::infinity(), start };
101}
102
104template <LINE_LIKE GEOM_A, LINE_LIKE GEOM_B>
105void checkCollinearOverlap( const GEOM_A& aA, const GEOM_B& aB, INTERSECTION_CONTACT* aContact )
106{
107 if( !aContact || aContact->m_Overlapping )
108 return;
109
110 const SEG& refSeg = carrierSeg( aA );
111
112 if( !refSeg.Collinear( carrierSeg( aB ) ) )
113 return;
114
115 const auto [aLow, aHigh] = extentAlong( aA, refSeg );
116 const auto [bLow, bHigh] = extentAlong( aB, refSeg );
117
118 if( std::min( aHigh, bHigh ) - std::max( aLow, bLow ) > OVERLAP_EPSILON )
119 aContact->m_Overlapping = true;
120}
121
123template <LINE_LIKE LINE_GEOM, CIRCULAR CIRCULAR_GEOM>
124void checkLineTangency( const LINE_GEOM& aLine, const CIRCULAR_GEOM& aCircular, INTERSECTION_CONTACT* aContact )
125{
126 if( !aContact || aContact->m_Tangent )
127 return;
128
129 std::vector<VECTOR2I> touches = carrierCircle( aCircular ).IntersectLine( carrierSeg( aLine ) );
130
131 if( touches.size() == 1 && extentContains( aLine, touches.front() )
132 && extentContains( aCircular, touches.front() ) )
133 {
134 aContact->m_Tangent = true;
135 }
136}
137
139template <CIRCULAR GEOM_A, CIRCULAR GEOM_B>
140bool sharesArcExtent( const GEOM_A&, const GEOM_B& )
141{
142 return true;
143}
144
145bool sharesArcExtent( const SHAPE_ARC& aA, const SHAPE_ARC& aB )
146{
147 return aA.Collide( aB.GetArcMid() ) || aB.Collide( aA.GetArcMid() );
148}
149
151template <CIRCULAR GEOM_A, CIRCULAR GEOM_B>
152void checkCircularContact( const GEOM_A& aA, const GEOM_B& aB, INTERSECTION_CONTACT* aContact )
153{
154 if( !aContact )
155 return;
156
157 const CIRCLE circleA = carrierCircle( aA );
158 const CIRCLE circleB = carrierCircle( aB );
159
160 if( circleA.Center == circleB.Center && circleA.Radius == circleB.Radius )
161 {
162 if( !aContact->m_Overlapping && sharesArcExtent( aA, aB ) )
163 aContact->m_Overlapping = true;
164
165 return;
166 }
167
168 if( aContact->m_Tangent )
169 return;
170
171 std::vector<VECTOR2I> touches = circleA.Intersect( circleB );
172
173 if( touches.size() == 1 && extentContains( aA, touches.front() ) && extentContains( aB, touches.front() ) )
174 aContact->m_Tangent = true;
175}
176
177void findIntersections( const SEG& aSegA, const SEG& aSegB, std::vector<VECTOR2I>& aIntersections,
178 INTERSECTION_CONTACT* aContact )
179{
180 checkCollinearOverlap( aSegA, aSegB, aContact );
181
182 const OPT_VECTOR2I intersection = aSegA.Intersect( aSegB );
183
184 if( intersection )
185 {
186 aIntersections.push_back( *intersection );
187 }
188}
189
190void findIntersections( const SEG& aSeg, const LINE& aLine, std::vector<VECTOR2I>& aIntersections,
191 INTERSECTION_CONTACT* aContact )
192{
193 checkCollinearOverlap( aSeg, aLine, aContact );
194
195 OPT_VECTOR2I intersection = aLine.Intersect( aSeg );
196
197 if( intersection )
198 {
199 aIntersections.push_back( *intersection );
200 }
201}
202
203void findIntersections( const SEG& aSeg, const HALF_LINE& aHalfLine,
204 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
205{
206 checkCollinearOverlap( aSeg, aHalfLine, aContact );
207
208 OPT_VECTOR2I intersection = aHalfLine.Intersect( aSeg );
209
210 if( intersection )
211 {
212 aIntersections.push_back( *intersection );
213 }
214}
215
216void findIntersections( const SEG& aSeg, const CIRCLE& aCircle,
217 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
218{
219 checkLineTangency( aSeg, aCircle, aContact );
220
221 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
222
223 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
224}
225
226void findIntersections( const SEG& aSeg, const SHAPE_ARC& aArc,
227 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
228{
229 checkLineTangency( aSeg, aArc, aContact );
230
231 std::vector<VECTOR2I> intersections;
232 aArc.IntersectLine( aSeg, &intersections );
233
234 // Find only the intersections that are within the segment
235 for( const VECTOR2I& intersection : intersections )
236 {
237 if( aSeg.Contains( intersection ) )
238 {
239 aIntersections.emplace_back( intersection );
240 }
241 }
242}
243
244void findIntersections( const LINE& aLineA, const LINE& aLineB,
245 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
246{
247 checkCollinearOverlap( aLineA, aLineB, aContact );
248
249 OPT_VECTOR2I intersection = aLineA.Intersect( aLineB );
250
251 if( intersection )
252 {
253 aIntersections.push_back( *intersection );
254 }
255}
256
257void findIntersections( const LINE& aLine, const HALF_LINE& aHalfLine,
258 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
259{
260 checkCollinearOverlap( aLine, aHalfLine, aContact );
261
262 // Intersect as two infinite lines
263 OPT_VECTOR2I intersection =
264 aHalfLine.GetContainedSeg().Intersect( aLine.GetContainedSeg(), false, true );
265
266 // No intersection at all (parallel, or passes on the other side of the start point)
267 if( !intersection )
268 {
269 return;
270 }
271
272 if( aHalfLine.Contains( *intersection ) )
273 {
274 aIntersections.push_back( *intersection );
275 }
276}
277
278void findIntersections( const HALF_LINE& aHalfLineA, const HALF_LINE& aHalfLineB,
279 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
280{
281 checkCollinearOverlap( aHalfLineA, aHalfLineB, aContact );
282
283 OPT_VECTOR2I intersection = aHalfLineA.Intersect( aHalfLineB );
284
285 if( intersection )
286 {
287 aIntersections.push_back( *intersection );
288 }
289}
290
291void findIntersections( const CIRCLE& aCircle, const LINE& aLine,
292 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
293{
294 checkLineTangency( aLine, aCircle, aContact );
295
296 std::vector<VECTOR2I> intersections = aCircle.IntersectLine( aLine.GetContainedSeg() );
297
298 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
299}
300
301void findIntersections( const CIRCLE& aCircle, const HALF_LINE& aHalfLine,
302 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
303{
304 checkLineTangency( aHalfLine, aCircle, aContact );
305
306 std::vector<VECTOR2I> intersections = aCircle.IntersectLine( aHalfLine.GetContainedSeg() );
307
308 for( const VECTOR2I& intersection : intersections )
309 {
310 if( aHalfLine.Contains( intersection ) )
311 {
312 aIntersections.push_back( intersection );
313 }
314 }
315}
316
317void findIntersections( const CIRCLE& aCircleA, const CIRCLE& aCircleB,
318 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
319{
320 checkCircularContact( aCircleA, aCircleB, aContact );
321
322 std::vector<VECTOR2I> intersections = aCircleA.Intersect( aCircleB );
323 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
324}
325
326void findIntersections( const CIRCLE& aCircle, const SHAPE_ARC& aArc,
327 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
328{
329 checkCircularContact( aCircle, aArc, aContact );
330
331 aArc.Intersect( aCircle, &aIntersections );
332}
333
334void findIntersections( const SHAPE_ARC& aArcA, const SHAPE_ARC& aArcB,
335 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
336{
337 checkCircularContact( aArcA, aArcB, aContact );
338
339 aArcA.Intersect( aArcB, &aIntersections );
340}
341
342void findIntersections( const SHAPE_ARC& aArc, const LINE& aLine,
343 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
344{
345 checkLineTangency( aLine, aArc, aContact );
346
347 std::vector<VECTOR2I> intersections;
348 aArc.IntersectLine( aLine.GetContainedSeg(), &intersections );
349
350 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
351}
352
353void findIntersections( const SHAPE_ARC& aArc, const HALF_LINE& aHalfLine,
354 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* aContact )
355{
356 checkLineTangency( aHalfLine, aArc, aContact );
357
358 std::vector<VECTOR2I> intersections;
359 aArc.IntersectLine( aHalfLine.GetContainedSeg(), &intersections );
360
361 for( const VECTOR2I& intersection : intersections )
362 {
363 if( aHalfLine.Contains( intersection ) )
364 {
365 aIntersections.push_back( intersection );
366 }
367 }
368}
369
370/*
371 * Ellipse overloads take a contact but never set one. An ellipse has no carrier seg or circle to
372 * reduce to. A caller that refuses ambiguity accepts a grazing ellipse as a clean crossing.
373 */
374void findIntersections( const SHAPE_ELLIPSE& aEllipse, const SEG& aSeg, std::vector<VECTOR2I>& aIntersections,
376{
377 std::vector<VECTOR2I> intersections = aEllipse.Intersect( aSeg );
378
379 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
380}
381
382void findIntersections( const SHAPE_ELLIPSE& aEllipse, const LINE& aLine, std::vector<VECTOR2I>& aIntersections,
384{
385 std::vector<VECTOR2I> intersections = aEllipse.Intersect( aLine.GetContainedSeg(), true );
386
387 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
388}
389
390void findIntersections( const SHAPE_ELLIPSE& aEllipse, const HALF_LINE& aHalfLine,
391 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* )
392{
393 std::vector<VECTOR2I> intersections = aEllipse.Intersect( aHalfLine.GetContainedSeg(), true );
394
395 for( const VECTOR2I& intersection : intersections )
396 {
397 if( aHalfLine.Contains( intersection ) )
398 {
399 aIntersections.push_back( intersection );
400 }
401 }
402}
403
404void findIntersections( const SHAPE_ELLIPSE& aEllipse, const CIRCLE& aCircle, std::vector<VECTOR2I>& aIntersections,
406{
407 std::vector<VECTOR2I> intersections = aEllipse.Intersect( aCircle );
408
409 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
410}
411
412void findIntersections( const SHAPE_ELLIPSE& aEllipse, const SHAPE_ARC& aArc, std::vector<VECTOR2I>& aIntersections,
414{
415 std::vector<VECTOR2I> intersections = aEllipse.Intersect( aArc );
416
417 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
418}
419
420void findIntersections( const SHAPE_ELLIPSE& aEllipseA, const SHAPE_ELLIPSE& aEllipseB,
421 std::vector<VECTOR2I>& aIntersections, INTERSECTION_CONTACT* )
422{
423 std::vector<VECTOR2I> intersections = aEllipseA.Intersect( aEllipseB );
424
425 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
426}
427
428} // namespace
429
430
432 std::vector<VECTOR2I>& aIntersections ) :
433 m_otherGeometry( aOtherGeometry ), m_intersections( aIntersections )
434{
435}
436
437
439 std::vector<VECTOR2I>& aIntersections,
440 INTERSECTION_CONTACT& aContact ) :
441 m_otherGeometry( aOtherGeometry ), m_intersections( aIntersections ), m_contact( &aContact )
442{
443}
444
445/*
446 * The operator() functions are the entry points for the visitor.
447 *
448 * Dispatch to the correct function based on the type of the "otherGeometry"
449 * which is held as state. This is also where the order of the parameters is
450 * determined, which avoids having to define a 'reverse' function for each
451 * intersection type.
452 */
453
454void INTERSECTION_VISITOR::operator()( const SEG& aSeg ) const
455{
456 // Dispatch to the correct function
457 return std::visit(
458 [&]( const auto& otherGeom )
459 {
460 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
461
462 if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
463 {
464 // Seg-Rect via decomposition into segments
465 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
466 {
467 findIntersections( aSeg, aRectSeg, m_intersections, m_contact );
468 }
469 }
470 else if constexpr( std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
471 {
472 // Ellipse-Seg
473 findIntersections( otherGeom, aSeg, m_intersections, m_contact );
474 }
475 else
476 {
477 // In all other segment comparisons, the SEG is the first argument
478 findIntersections( aSeg, otherGeom, m_intersections, m_contact );
479 }
480 },
482}
483
484void INTERSECTION_VISITOR::operator()( const LINE& aLine ) const
485{
486 // Dispatch to the correct function
487 return std::visit(
488 [&]( const auto& otherGeom )
489 {
490 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
491 // Dispatch in the correct order
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> )
495 {
496 // Seg-Line, Line-Line, Circle-Line, Arc-Line, Ellipse-Line
497 findIntersections( otherGeom, aLine, m_intersections, m_contact );
498 }
499 else if constexpr( std::is_same_v<OtherGeomType, HALF_LINE> )
500 {
501 // Line-HalfLine
502 findIntersections( aLine, otherGeom, m_intersections, m_contact );
503 }
504 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
505 {
506 // Line-Rect via decomposition into segments
507 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
508 {
509 findIntersections( aRectSeg, aLine, m_intersections, m_contact );
510 }
511 }
512 else
513 {
515 "Unhandled other geometry type" );
516 }
517 },
519};
520
521void INTERSECTION_VISITOR::operator()( const HALF_LINE& aHalfLine ) const
522{
523 // Dispatch to the correct function
524 return std::visit(
525 [&]( const auto& otherGeom )
526 {
527 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
528 // Dispatch in the correct order
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> )
532 {
533 // Seg-HalfLine, HalfLine-HalfLine, Circle-HalfLine, Arc-HalfLine,
534 // Ellipse-HalfLine
535 findIntersections( otherGeom, aHalfLine, m_intersections, m_contact );
536 }
537 else if constexpr( std::is_same_v<OtherGeomType, LINE> )
538 {
539 // Line-HalfLine
540 findIntersections( otherGeom, aHalfLine, m_intersections, m_contact );
541 }
542 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
543 {
544 // HalfLine-Rect via decomposition into segments
545 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
546 {
547 findIntersections( aRectSeg, aHalfLine, m_intersections, m_contact );
548 }
549 }
550 else
551 {
553 "Unhandled other geometry type" );
554 }
555 },
557};
558
559void INTERSECTION_VISITOR::operator()( const CIRCLE& aCircle ) const
560{
561 // Dispatch to the correct function
562 return std::visit(
563 [&]( const auto& otherGeom )
564 {
565 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
566 // Dispatch in the correct order
567 if constexpr( std::is_same_v<OtherGeomType, SEG> || std::is_same_v<OtherGeomType, CIRCLE>
568 || std::is_same_v<OtherGeomType, SHAPE_ELLIPSE> )
569 {
570 // Seg-Circle, Circle-Circle, Ellipse-Circle
571 findIntersections( otherGeom, aCircle, m_intersections, m_contact );
572 }
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> )
576 {
577 // Circle-Arc, Circle-Line, Circle-HalfLine
578 findIntersections( aCircle, otherGeom, m_intersections, m_contact );
579 }
580 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
581 {
582 // Circle-Rect via decomposition into segments
583 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
584 {
585 findIntersections( aRectSeg, aCircle, m_intersections, m_contact );
586 }
587 }
588 else
589 {
591 "Unhandled other geometry type" );
592 }
593 },
595}
596
598{
599 // Dispatch to the correct function
600 return std::visit(
601 [&]( const auto& otherGeom )
602 {
603 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
604 // Dispatch in the correct order
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> )
608 {
609 // Seg-Arc, Circle-Arc, Arc-Arc, Ellipse-Arc
610 findIntersections( otherGeom, aArc, m_intersections, m_contact );
611 }
612 else if constexpr( std::is_same_v<OtherGeomType, LINE>
613 || std::is_same_v<OtherGeomType, HALF_LINE> )
614 {
615 // Arc-Line, Arc-HalfLine
616 findIntersections( aArc, otherGeom, m_intersections, m_contact );
617 }
618 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
619 {
620 // Arc-Rect via decomposition into segments
621 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
622 {
623 findIntersections( aRectSeg, aArc, m_intersections, m_contact );
624 }
625 }
626 else
627 {
629 "Unhandled other geometry type" );
630 }
631 },
633};
634
635
637{
638 // Dispatch to the correct function
639 return std::visit(
640 [&]( const auto& otherGeom )
641 {
642 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
643 // The ellipse is always the first argument
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> )
648 {
649 findIntersections( aEllipse, otherGeom, m_intersections, m_contact );
650 }
651 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
652 {
653 // Ellipse-Rect via decomposition into segments
654 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
655 {
656 findIntersections( aEllipse, aRectSeg, m_intersections, m_contact );
657 }
658 }
659 else
660 {
661 static_assert( always_false<OtherGeomType>::value, "Unhandled other geometry type" );
662 }
663 },
665};
666
667
668void INTERSECTION_VISITOR::operator()( const BOX2I& aRect ) const
669{
670 // Defer to the SEG visitor repeatedly
671 // Note - in some cases, points can be repeated in the intersection list
672 // if that's an issue, both directions of the visitor can be implemented
673 // to take care of that.
674 const std::array<SEG, 4> segs = KIGEOM::BoxToSegs( aRect );
675
676 for( const SEG& seg : segs )
677 {
678 ( *this )( seg );
679 }
680};
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
Represent basic circle geometry with utility geometry functions.
Definition circle.h:33
VECTOR2I Center
Public to make access simpler.
Definition circle.h:150
int Radius
Public to make access simpler.
Definition circle.h:149
std::vector< VECTOR2I > Intersect(const CIRCLE &aCircle) const
Compute the intersection points between this circle and aCircle.
Definition circle.cpp:243
std::vector< VECTOR2I > IntersectLine(const SEG &aLine) const
Compute the intersection points between this circle and aLine.
Definition circle.cpp:322
OPT_VECTOR2I Intersect(const SEG &aSeg) const
Definition half_line.cpp:53
const SEG & GetContainedSeg() const
Gets the (one of the infinite number of) segments that the ray passes through.
Definition half_line.h:83
bool Contains(const VECTOR2I &aPoint) const
Definition half_line.cpp:37
Definition line.h:32
const SEG & GetContainedSeg() const
Gets the (one of the infinite number of) segments that the line passes through.
Definition line.h:45
OPT_VECTOR2I Intersect(const SEG &aOther) const
Definition line.cpp:22
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition seg.cpp:442
bool Collinear(const SEG &aSeg) const
Check if segment aSeg lies on the same line as (this).
Definition seg.h:282
bool Contains(const SEG &aSeg) const
Definition seg.h:320
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:116
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.
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
Definition seg.h:35
Utility functions for working with shapes.
How two geometries meet, beyond where they cross.
bool m_Tangent
Touch at one point, no crossing.
bool m_Overlapping
Collinear or concentric, more than one point shared.
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
Definition vector2d.h:683