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/*
27 * Helper functions that dispatch to the correct intersection function
28 * in one of the geometry classes.
29 */
30namespace
31{
32
33void findIntersections( const SEG& aSegA, const SEG& aSegB, std::vector<VECTOR2I>& aIntersections )
34{
35 const OPT_VECTOR2I intersection = aSegA.Intersect( aSegB );
36
37 if( intersection )
38 {
39 aIntersections.push_back( *intersection );
40 }
41}
42
43void findIntersections( const SEG& aSeg, const LINE& aLine, std::vector<VECTOR2I>& aIntersections )
44{
45 OPT_VECTOR2I intersection = aLine.Intersect( aSeg );
46
47 if( intersection )
48 {
49 aIntersections.push_back( *intersection );
50 }
51}
52
53void findIntersections( const SEG& aSeg, const HALF_LINE& aHalfLine,
54 std::vector<VECTOR2I>& aIntersections )
55{
56 OPT_VECTOR2I intersection = aHalfLine.Intersect( aSeg );
57
58 if( intersection )
59 {
60 aIntersections.push_back( *intersection );
61 }
62}
63
64void findIntersections( const SEG& aSeg, const CIRCLE& aCircle,
65 std::vector<VECTOR2I>& aIntersections )
66{
67 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
68
69 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
70}
71
72void findIntersections( const SEG& aSeg, const SHAPE_ARC& aArc,
73 std::vector<VECTOR2I>& aIntersections )
74{
75 std::vector<VECTOR2I> intersections;
76 aArc.IntersectLine( aSeg, &intersections );
77
78 // Find only the intersections that are within the segment
79 for( const VECTOR2I& intersection : intersections )
80 {
81 if( aSeg.Contains( intersection ) )
82 {
83 aIntersections.emplace_back( intersection );
84 }
85 }
86}
87
88void findIntersections( const LINE& aLineA, const LINE& aLineB,
89 std::vector<VECTOR2I>& aIntersections )
90{
91 OPT_VECTOR2I intersection = aLineA.Intersect( aLineB );
92
93 if( intersection )
94 {
95 aIntersections.push_back( *intersection );
96 }
97}
98
99void findIntersections( const LINE& aLine, const HALF_LINE& aHalfLine,
100 std::vector<VECTOR2I>& aIntersections )
101{
102 // Intersect as two infinite lines
103 OPT_VECTOR2I intersection =
104 aHalfLine.GetContainedSeg().Intersect( aLine.GetContainedSeg(), false, true );
105
106 // No intersection at all (parallel, or passes on the other side of the start point)
107 if( !intersection )
108 {
109 return;
110 }
111
112 if( aHalfLine.Contains( *intersection ) )
113 {
114 aIntersections.push_back( *intersection );
115 }
116}
117
118void findIntersections( const HALF_LINE& aHalfLineA, const HALF_LINE& aHalfLineB,
119 std::vector<VECTOR2I>& aIntersections )
120{
121 OPT_VECTOR2I intersection = aHalfLineA.Intersect( aHalfLineB );
122
123 if( intersection )
124 {
125 aIntersections.push_back( *intersection );
126 }
127}
128
129void findIntersections( const CIRCLE& aCircle, const LINE& aLine,
130 std::vector<VECTOR2I>& aIntersections )
131{
132 std::vector<VECTOR2I> intersections = aCircle.IntersectLine( aLine.GetContainedSeg() );
133
134 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
135}
136
137void findIntersections( const CIRCLE& aCircle, const HALF_LINE& aHalfLine,
138 std::vector<VECTOR2I>& aIntersections )
139{
140 std::vector<VECTOR2I> intersections = aCircle.IntersectLine( aHalfLine.GetContainedSeg() );
141
142 for( const VECTOR2I& intersection : intersections )
143 {
144 if( aHalfLine.Contains( intersection ) )
145 {
146 aIntersections.push_back( intersection );
147 }
148 }
149}
150
151void findIntersections( const CIRCLE& aCircleA, const CIRCLE& aCircleB,
152 std::vector<VECTOR2I>& aIntersections )
153{
154 std::vector<VECTOR2I> intersections = aCircleA.Intersect( aCircleB );
155 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
156}
157
158void findIntersections( const CIRCLE& aCircle, const SHAPE_ARC& aArc,
159 std::vector<VECTOR2I>& aIntersections )
160{
161 aArc.Intersect( aCircle, &aIntersections );
162}
163
164void findIntersections( const SHAPE_ARC& aArcA, const SHAPE_ARC& aArcB,
165 std::vector<VECTOR2I>& aIntersections )
166{
167 aArcA.Intersect( aArcB, &aIntersections );
168}
169
170void findIntersections( const SHAPE_ARC& aArc, const LINE& aLine,
171 std::vector<VECTOR2I>& aIntersections )
172{
173 std::vector<VECTOR2I> intersections;
174 aArc.IntersectLine( aLine.GetContainedSeg(), &intersections );
175
176 aIntersections.insert( aIntersections.end(), intersections.begin(), intersections.end() );
177}
178
179void findIntersections( const SHAPE_ARC& aArc, const HALF_LINE& aHalfLine,
180 std::vector<VECTOR2I>& aIntersections )
181{
182 std::vector<VECTOR2I> intersections;
183 aArc.IntersectLine( aHalfLine.GetContainedSeg(), &intersections );
184
185 for( const VECTOR2I& intersection : intersections )
186 {
187 if( aHalfLine.Contains( intersection ) )
188 {
189 aIntersections.push_back( intersection );
190 }
191 }
192}
193
194} // namespace
195
196
198 std::vector<VECTOR2I>& aIntersections ) :
199 m_otherGeometry( aOtherGeometry ), m_intersections( aIntersections )
200{
201}
202
203/*
204 * The operator() functions are the entry points for the visitor.
205 *
206 * Dispatch to the correct function based on the type of the "otherGeometry"
207 * which is held as state. This is also where the order of the parameters is
208 * determined, which avoids having to define a 'reverse' function for each
209 * intersection type.
210 */
211
212void INTERSECTION_VISITOR::operator()( const SEG& aSeg ) const
213{
214 // Dispatch to the correct function
215 return std::visit(
216 [&]( const auto& otherGeom )
217 {
218 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
219
220 if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
221 {
222 // Seg-Rect via decomposition into segments
223 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
224 {
225 findIntersections( aSeg, aRectSeg, m_intersections );
226 }
227 }
228 else
229 {
230 // In all other segment comparisons, the SEG is the first argument
231 findIntersections( aSeg, otherGeom, m_intersections );
232 }
233 },
235}
236
237void INTERSECTION_VISITOR::operator()( const LINE& aLine ) const
238{
239 // Dispatch to the correct function
240 return std::visit(
241 [&]( const auto& otherGeom )
242 {
243 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
244 // Dispatch in the correct order
245 if constexpr( std::is_same_v<OtherGeomType, SEG>
246 || std::is_same_v<OtherGeomType, LINE>
247 || std::is_same_v<OtherGeomType, CIRCLE>
248 || std::is_same_v<OtherGeomType, SHAPE_ARC> )
249 {
250 // Seg-Line, Line-Line, Circle-Line, Arc-Line
251 findIntersections( otherGeom, aLine, m_intersections );
252 }
253 else if constexpr( std::is_same_v<OtherGeomType, HALF_LINE> )
254 {
255 // Line-HalfLine
256 findIntersections( aLine, otherGeom, m_intersections );
257 }
258 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
259 {
260 // Line-Rect via decomposition into segments
261 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
262 {
263 findIntersections( aRectSeg, aLine, m_intersections );
264 }
265 }
266 else
267 {
269 "Unhandled other geometry type" );
270 }
271 },
273};
274
275void INTERSECTION_VISITOR::operator()( const HALF_LINE& aHalfLine ) const
276{
277 // Dispatch to the correct function
278 return std::visit(
279 [&]( const auto& otherGeom )
280 {
281 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
282 // Dispatch in the correct order
283 if constexpr( std::is_same_v<OtherGeomType, SEG>
284 || std::is_same_v<OtherGeomType, HALF_LINE>
285 || std::is_same_v<OtherGeomType, CIRCLE>
286 || std::is_same_v<OtherGeomType, SHAPE_ARC> )
287 {
288 // Seg-HalfLine, HalfLine-HalfLine, Circle-HalfLine, Arc-HalfLine
289 findIntersections( otherGeom, aHalfLine, m_intersections );
290 }
291 else if constexpr( std::is_same_v<OtherGeomType, LINE> )
292 {
293 // Line-HalfLine
294 findIntersections( otherGeom, aHalfLine, m_intersections );
295 }
296 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
297 {
298 // HalfLine-Rect via decomposition into segments
299 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
300 {
301 findIntersections( aRectSeg, aHalfLine, m_intersections );
302 }
303 }
304 else
305 {
307 "Unhandled other geometry type" );
308 }
309 },
311};
312
313void INTERSECTION_VISITOR::operator()( const CIRCLE& aCircle ) const
314{
315 // Dispatch to the correct function
316 return std::visit(
317 [&]( const auto& otherGeom )
318 {
319 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
320 // Dispatch in the correct order
321 if constexpr( std::is_same_v<OtherGeomType, SEG>
322 || std::is_same_v<OtherGeomType, CIRCLE> )
323 {
324 // Seg-Circle, Circle-Circle
325 findIntersections( otherGeom, aCircle, m_intersections );
326 }
327 else if constexpr( std::is_same_v<OtherGeomType, SHAPE_ARC>
328 || std::is_same_v<OtherGeomType, LINE>
329 || std::is_same_v<OtherGeomType, HALF_LINE> )
330 {
331 // Circle-Arc, Circle-Line, Circle-HalfLine
332 findIntersections( aCircle, otherGeom, m_intersections );
333 }
334 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
335 {
336 // Circle-Rect via decomposition into segments
337 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
338 {
339 findIntersections( aRectSeg, aCircle, m_intersections );
340 }
341 }
342 else
343 {
345 "Unhandled other geometry type" );
346 }
347 },
349}
350
352{
353 // Dispatch to the correct function
354 return std::visit(
355 [&]( const auto& otherGeom )
356 {
357 using OtherGeomType = std::decay_t<decltype( otherGeom )>;
358 // Dispatch in the correct order
359 if constexpr( std::is_same_v<OtherGeomType, SEG>
360 || std::is_same_v<OtherGeomType, CIRCLE>
361 || std::is_same_v<OtherGeomType, SHAPE_ARC> )
362 {
363 // Seg-Arc, Circle-Arc, Arc-Arc
364 findIntersections( otherGeom, aArc, m_intersections );
365 }
366 else if constexpr( std::is_same_v<OtherGeomType, LINE>
367 || std::is_same_v<OtherGeomType, HALF_LINE> )
368 {
369 // Arc-Line, Arc-HalfLine
370 findIntersections( aArc, otherGeom, m_intersections );
371 }
372 else if constexpr( std::is_same_v<OtherGeomType, BOX2I> )
373 {
374 // Arc-Rect via decomposition into segments
375 for( const SEG& aRectSeg : KIGEOM::BoxToSegs( otherGeom ) )
376 {
377 findIntersections( aRectSeg, aArc, m_intersections );
378 }
379 }
380 else
381 {
383 "Unhandled other geometry type" );
384 }
385 },
387};
388
389
390void INTERSECTION_VISITOR::operator()( const BOX2I& aRect ) const
391{
392 // Defer to the SEG visitor repeatedly
393 // Note - in some cases, points can be repeated in the intersection list
394 // if that's an issue, both directions of the visitor can be implemented
395 // to take care of that.
396 const std::array<SEG, 4> segs = KIGEOM::BoxToSegs( aRect );
397
398 for( const SEG& seg : segs )
399 {
400 ( *this )( seg );
401 }
402};
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
Represent basic circle geometry with utility geometry functions.
Definition circle.h:33
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
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 Contains(const SEG &aSeg) const
Definition seg.h:320
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.
std::variant< LINE, HALF_LINE, SEG, CIRCLE, SHAPE_ARC, 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.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:35
Utility functions for working with shapes.
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