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