KiCad PCB EDA Suite
Loading...
Searching...
No Matches
shape_collisions.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) 2013 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <cmath>
23#include <limits>
24
25#include <geometry/seg.h> // for SEG
26#include <geometry/shape.h>
27#include <geometry/shape_arc.h>
30#include <geometry/shape_rect.h>
35#include <math/vector2d.h>
36
38
39
40static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
41 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
42{
43 ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
44 ecoord min_dist_sq = min_dist * min_dist;
45
46 const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
47 ecoord dist_sq = delta.SquaredEuclideanNorm();
48
49 if( dist_sq == 0 || dist_sq < min_dist_sq )
50 {
51 if( aActual )
52 *aActual = std::max( 0, (int) sqrt( dist_sq ) - aA.GetRadius() - aB.GetRadius() );
53
54 if( aLocation )
55 *aLocation = ( aA.GetCenter() + aB.GetCenter() ) / 2;
56
57 if( aMTV )
58 *aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error
59
60 return true;
61 }
62
63 return false;
64}
65
66
67static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
68 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
69{
70 if( aA.GetRadius() > 0 )
71 {
72 wxASSERT_MSG( !aMTV, wxT( "MTV not implemented for SHAPE_RECT to SHAPE_CIRCLE collisions when rect "
73 "has rounded corners" ) );
74
75 const SHAPE_LINE_CHAIN& outline = aA.Outline();
76 return outline.SHAPE::Collide( &aB, aClearance, aActual, aLocation );
77 }
78
79 const VECTOR2I c = aB.GetCenter();
80 const VECTOR2I p0 = aA.GetPosition();
81 const VECTOR2I size = aA.GetSize();
82 const int r = aB.GetRadius();
83 const int min_dist = aClearance + r;
84 const ecoord min_dist_sq = SEG::Square( min_dist );
85
86 const VECTOR2I vts[] =
87 {
88 VECTOR2I( p0.x, p0.y ),
89 VECTOR2I( p0.x, p0.y + size.y ),
90 VECTOR2I( p0.x + size.x, p0.y + size.y ),
91 VECTOR2I( p0.x + size.x, p0.y ),
92 VECTOR2I( p0.x, p0.y )
93 };
94
95 ecoord nearest_side_dist_sq = VECTOR2I::ECOORD_MAX;
96 VECTOR2I nearest;
97
98 bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
99 && c.y >= p0.y && c.y <= ( p0.y + size.y );
100
101 // If we're not looking for MTV or actual, short-circuit once we find a hard collision
102 if( inside && !aActual && !aLocation && !aMTV )
103 return true;
104
105 for( int i = 0; i < 4; i++ )
106 {
107 const SEG side( vts[i], vts[ i + 1] );
108
109 VECTOR2I pn = side.NearestPoint( c );
110 ecoord side_dist_sq = ( pn - c ).SquaredEuclideanNorm();
111
112 if( side_dist_sq < nearest_side_dist_sq )
113 {
114 nearest = pn;
115 nearest_side_dist_sq = side_dist_sq;
116
117 if( aMTV )
118 continue;
119
120 if( nearest_side_dist_sq == 0 )
121 break;
122
123 // If we're not looking for aActual then any collision will do
124 if( nearest_side_dist_sq < min_dist_sq && !aActual )
125 break;
126 }
127 }
128
129 if( inside || nearest_side_dist_sq == 0 || nearest_side_dist_sq < min_dist_sq )
130 {
131 if( aLocation )
132 *aLocation = nearest;
133
134 if( aActual )
135 *aActual = std::max( 0, (int) sqrt( nearest_side_dist_sq ) - r );
136
137 if( aMTV )
138 {
139 VECTOR2I delta = c - nearest;
140
141 if( inside )
142 *aMTV = -delta.Resize( abs( min_dist + 1 + sqrt( nearest_side_dist_sq ) ) + 1 );
143 else
144 *aMTV = delta.Resize( abs( min_dist + 1 - sqrt( nearest_side_dist_sq ) ) + 1 );
145 }
146
147 return true;
148 }
149
150 return false;
151}
152
153
154static VECTOR2I pushoutForce( const SHAPE_CIRCLE& aA, const SEG& aB, int aClearance )
155{
156 VECTOR2I f( 0, 0 );
157
158 const VECTOR2I c = aA.GetCenter();
159 const VECTOR2I nearest = aB.NearestPoint( c );
160
161 const int r = aA.GetRadius();
162
163 int dist = ( nearest - c ).EuclideanNorm();
164 int min_dist = aClearance + r;
165
166 if( dist < min_dist )
167 {
168 for( int corr = 0; corr < 5; corr++ )
169 {
170 f = ( aA.GetCenter() - nearest ).Resize( min_dist - dist + corr );
171
172 if( aB.Distance( c + f ) >= min_dist )
173 break;
174 }
175 }
176
177 return f;
178}
179
180
181template <typename SegmentSource, typename Containment>
182static inline bool collideEllipseVsSegments( const SHAPE_ELLIPSE& aA, const SegmentSource& aSegSource, int aClearance,
183 int aHalfWidth, Containment aContainment, int* aActual,
184 VECTOR2I* aLocation )
185{
186 const int effClear = aClearance + aHalfWidth;
187
188 bool found = false;
189 int bestActual = std::numeric_limits<int>::max();
190 VECTOR2I bestLocation;
191
192 const size_t nSegs = aSegSource.GetSegmentCount();
193
194 for( size_t i = 0; i < nSegs; ++i )
195 {
196 const SEG seg = aSegSource.GetSegment( static_cast<int>( i ) );
197 int localActual = 0;
198 VECTOR2I localLoc;
199
200 if( aA.Collide( seg, effClear, aActual ? &localActual : nullptr, aLocation ? &localLoc : nullptr ) )
201 {
202 if( !aActual && !aLocation )
203 return true;
204
205 if( !found || localActual < bestActual )
206 {
207 bestActual = localActual;
208 bestLocation = localLoc;
209 found = true;
210 }
211 }
212 }
213
214 if( found )
215 {
216 if( aActual )
217 *aActual = std::max( 0, bestActual - aHalfWidth );
218 if( aLocation )
219 *aLocation = bestLocation;
220 return true;
221 }
222
223 if( aContainment() )
224 {
225 if( aActual )
226 *aActual = 0;
227 if( aLocation )
228 *aLocation = aA.GetCenter();
229 return true;
230 }
231
232 return false;
233}
234
235
236static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN_BASE& aB,
237 int aClearance, int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
238{
239 int closest_dist = std::numeric_limits<int>::max();
240 int closest_mtv_dist = std::numeric_limits<int>::max();
241 VECTOR2I nearest;
242 int closest_mtv_seg = -1;
243
244 if( aB.IsClosed() && aB.PointInside( aA.GetCenter() ) )
245 {
246 nearest = aA.GetCenter();
247 closest_dist = 0;
248
249 if( aMTV )
250 {
251 for( size_t s = 0; s < aB.GetSegmentCount(); s++ )
252 {
253 int dist = aB.GetSegment(s).Distance( aA.GetCenter() );
254
255 if( dist < closest_mtv_dist )
256 {
257 closest_mtv_dist = dist;
258 closest_mtv_seg = s;
259 }
260 }
261 }
262
263 }
264 else
265 {
266 for( size_t s = 0; s < aB.GetSegmentCount(); s++ )
267 {
268 int collision_dist = 0;
269 VECTOR2I pn;
270
271 if( aA.Collide( aB.GetSegment( s ), aClearance,
272 aActual || aLocation ? &collision_dist : nullptr,
273 aLocation ? &pn : nullptr ) )
274 {
275 if( collision_dist < closest_dist )
276 {
277 nearest = pn;
278 closest_dist = collision_dist;
279 }
280
281 if( closest_dist == 0 )
282 break;
283
284 // If we're not looking for aActual then any collision will do
285 if( !aActual )
286 break;
287 }
288 }
289 }
290
291 if( closest_dist == 0 || closest_dist < aClearance )
292 {
293 if( aLocation )
294 *aLocation = nearest;
295
296 if( aActual )
297 *aActual = closest_dist;
298
299 if( aMTV )
300 {
301 SHAPE_CIRCLE cmoved( aA );
302 VECTOR2I f_total( 0, 0 );
303
304 VECTOR2I f;
305
306 if (closest_mtv_seg >= 0)
307 {
308 SEG cs = aB.GetSegment( closest_mtv_seg );
309 VECTOR2I np = cs.NearestPoint( aA.GetCenter() );
310 f = ( np - aA.GetCenter() ) + ( np - aA.GetCenter() ).Resize( aA.GetRadius() );
311 }
312
313 cmoved.SetCenter( cmoved.GetCenter() + f );
314 f_total += f;
315
316 for( size_t s = 0; s < aB.GetSegmentCount(); s++ )
317 {
318 f = pushoutForce( cmoved, aB.GetSegment( s ), aClearance );
319 cmoved.SetCenter( cmoved.GetCenter() + f );
320 f_total += f;
321 }
322
323 *aMTV = f_total;
324 }
325
326 return true;
327 }
328
329 return false;
330}
331
332
333static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
334 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
335{
336 if( aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, aActual, aLocation ) )
337 {
338 if( aMTV )
339 *aMTV = -pushoutForce( aA, aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2);
340
341 if( aActual )
342 *aActual = std::max( 0, *aActual - aSeg.GetWidth() / 2 );
343
344 return true;
345 }
346
347 return false;
348}
349
350
351static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_LINE_CHAIN_BASE& aB,
352 int aClearance, int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
353{
354 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
355 aA.TypeName(),
356 aB.TypeName() ) );
357
358 int closest_dist = std::numeric_limits<int>::max();
359 VECTOR2I nearest;
360
361 if( aB.IsClosed() && aA.GetPointCount() > 0 && aB.PointInside( aA.GetPoint( 0 ) ) )
362 {
363 closest_dist = 0;
364 nearest = aA.GetPoint( 0 );
365 }
366 else if( aA.IsClosed() && aB.GetPointCount() > 0 && aA.PointInside( aB.GetPoint( 0 ) ) )
367 {
368 closest_dist = 0;
369 nearest = aB.GetPoint( 0 );
370 }
371 else
372 {
373 std::vector<SEG> a_segs;
374 std::vector<SEG> b_segs;
375
376 for( size_t ii = 0; ii < aA.GetSegmentCount(); ii++ )
377 {
378 if( aA.Type() != SH_LINE_CHAIN
379 || !static_cast<const SHAPE_LINE_CHAIN*>( &aA )->IsArcSegment( ii ) )
380 {
381 a_segs.push_back( aA.GetSegment( ii ) );
382 }
383 }
384
385 for( size_t ii = 0; ii < aB.GetSegmentCount(); ii++ )
386 {
387 if( aB.Type() != SH_LINE_CHAIN
388 || !static_cast<const SHAPE_LINE_CHAIN*>( &aB )->IsArcSegment( ii ) )
389 {
390 b_segs.push_back( aB.GetSegment( ii ) );
391 }
392 }
393
394 auto seg_sort = []( const SEG& a, const SEG& b )
395 {
396 return a.A.x < b.A.x || ( a.A.x == b.A.x && a.A.y < b.A.y );
397 };
398
399 std::sort( a_segs.begin(), a_segs.end(), seg_sort );
400 std::sort( b_segs.begin(), b_segs.end(), seg_sort );
401
402 for( const SEG& a_seg : a_segs )
403 {
404 for( const SEG& b_seg : b_segs )
405 {
406 int dist = 0;
407
408 if( a_seg.Collide( b_seg, aClearance, aActual || aLocation ? &dist : nullptr ) )
409 {
410 if( dist < closest_dist )
411 {
412 nearest = a_seg.NearestPoint( b_seg );
413 closest_dist = dist;
414 }
415
416 if( closest_dist == 0 )
417 break;
418
419 // If we're not looking for aActual then any collision will do
420 if( !aActual )
421 break;
422 }
423 }
424 }
425 }
426
427 if( (!aActual && !aLocation ) || closest_dist > 0 )
428 {
429 std::vector<const SHAPE_LINE_CHAIN*> chains = {
430 dynamic_cast<const SHAPE_LINE_CHAIN*>( &aA ),
431 dynamic_cast<const SHAPE_LINE_CHAIN*>( &aB )
432 };
433
434 std::vector<const SHAPE*> shapes = { &aA, &aB };
435
436 for( int ii = 0; ii < 2; ii++ )
437 {
438 const SHAPE_LINE_CHAIN* chain = chains[ii];
439 const SHAPE* other = shapes[( ii + 1 ) % 2];
440
441 if( !chain )
442 continue;
443
444 for( size_t jj = 0; jj < chain->ArcCount(); jj++ )
445 {
446 const SHAPE_ARC& arc = chain->Arc( jj );
447
448 if( arc.Collide( other, aClearance, aActual, aLocation ) )
449 return true;
450 }
451 }
452 }
453
454 if( closest_dist == 0 || closest_dist < aClearance )
455 {
456 if( aLocation )
457 *aLocation = nearest;
458
459 if( aActual )
460 *aActual = closest_dist;
461
462 return true;
463 }
464
465 return false;
466}
467
468
469static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
470 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
471{
472 if( aA.GetRadius() > 0 )
473 return Collide( aA.Outline(), aB, aClearance, aActual, aLocation, aMTV );
474
475 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
476 aA.TypeName(),
477 aB.TypeName() ) );
478
479 int closest_dist = std::numeric_limits<int>::max();
480 VECTOR2I nearest;
481
482 if( aB.IsClosed() && aB.PointInside( aA.Centre() ) )
483 {
484 nearest = aA.Centre();
485 closest_dist = 0;
486 }
487 else
488 {
489 for( size_t s = 0; s < aB.GetSegmentCount(); s++ )
490 {
491 int collision_dist = 0;
492 VECTOR2I pn;
493
494 if( aA.Collide( aB.GetSegment( s ), aClearance,
495 aActual || aLocation ? &collision_dist : nullptr,
496 aLocation ? &pn : nullptr ) )
497 {
498 if( collision_dist < closest_dist )
499 {
500 nearest = pn;
501 closest_dist = collision_dist;
502 }
503
504 if( closest_dist == 0 )
505 break;
506
507 // If we're not looking for aActual then any collision will do
508 if( !aActual )
509 break;
510 }
511 }
512 }
513
514 if( closest_dist == 0 || closest_dist < aClearance )
515 {
516 if( aLocation )
517 *aLocation = nearest;
518
519 if( aActual )
520 *aActual = closest_dist;
521
522 return true;
523 }
524
525 return false;
526}
527
528
529static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, int aClearance,
530 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
531{
532 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
533 aA.TypeName(),
534 aB.TypeName() ) );
535
536 bool rv = aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, aActual, aLocation );
537
538 if( rv && aActual )
539 *aActual = std::max( 0, *aActual - aB.GetWidth() / 2 );
540
541 return rv;
542}
543
544
545static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_SEGMENT& aB,
546 int aClearance, int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
547{
548 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
549 aA.TypeName(),
550 aB.TypeName() ) );
551
552 bool rv = aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, aActual, aLocation );
553
554 if( rv && aActual )
555 *aActual = std::max( 0, *aActual - aB.GetWidth() / 2 );
556
557 return rv;
558}
559
560
561static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aB, int aClearance,
562 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
563{
564 if( aA.GetRadius() > 0 )
565 return Collide( aA.Outline(), aB, aClearance, aActual, aLocation, aMTV );
566
567 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
568 aA.TypeName(),
569 aB.TypeName() ) );
570
571 bool rv = aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, aActual, aLocation );
572
573 if( rv && aActual )
574 *aActual = std::max( 0, *aActual - aB.GetWidth() / 2 );
575
576 return rv;
577}
578
579
580static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_RECT& aB, int aClearance,
581 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
582{
583 if( aClearance || aActual || aLocation || aMTV || aA.GetRadius() > 0 || aB.GetRadius() > 0 )
584 {
585 return Collide( aA.Outline(), aB.Outline(), aClearance, aActual, aLocation, aMTV );
586 }
587 else
588 {
589 BOX2I bboxa = aA.BBox();
590 BOX2I bboxb = aB.BBox();
591
592 return bboxa.Intersects( bboxb );
593 }
594}
595
596
597static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_CIRCLE& aB, int aClearance,
598 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
599{
600 if( aA.IsEffectiveLine() )
601 {
602 SHAPE_SEGMENT tmp( aA.GetP0(), aA.GetP1(), aA.GetWidth() );
603 bool retval = Collide( aB, tmp, aClearance, aActual, aLocation, aMTV );
604
605 if( retval && aMTV )
606 *aMTV = - *aMTV;
607
608 return retval;
609 }
610
611 VECTOR2I ptA, ptB;
612 int64_t dist_sq = std::numeric_limits<int64_t>::max();
613 aA.NearestPoints( aB, ptA, ptB, dist_sq );
614
615 if( dist_sq == 0 || dist_sq < SEG::Square( aClearance ) )
616 {
617 if( aLocation )
618 *aLocation = ( ptA + ptB ) / 2;
619
620 if( aActual )
621 *aActual = std::max( 0, KiROUND( std::sqrt( dist_sq ) ) );
622
623 if( aMTV )
624 {
625 const VECTOR2I delta = ptB - ptA;
626 *aMTV = delta.Resize( aClearance - std::sqrt( dist_sq ) + 3 );
627 }
628
629 return true;
630 }
631
632 return false;
633}
634
635
636static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
637 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
638{
639 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
640 aA.TypeName(),
641 aB.TypeName() ) );
642
643 int closest_dist = std::numeric_limits<int>::max();
644 VECTOR2I nearest;
645
646 if( aB.IsClosed() && aB.PointInside( aA.GetP0() ) )
647 {
648 closest_dist = 0;
649 nearest = aA.GetP0();
650 }
651 else
652 {
653 int collision_dist = 0;
654 VECTOR2I pn;
655
656 for( size_t i = 0; i < aB.GetSegmentCount(); i++ )
657 {
658 // ignore arcs - we will collide these separately
659 if( aB.IsArcSegment( i ) )
660 continue;
661
662 if( aA.Collide( aB.GetSegment( i ), aClearance,
663 aActual || aLocation ? &collision_dist : nullptr,
664 aLocation ? &pn : nullptr ) )
665 {
666 if( collision_dist < closest_dist )
667 {
668 nearest = pn;
669 closest_dist = collision_dist;
670 }
671
672 if( closest_dist == 0 )
673 break;
674
675 // If we're not looking for aActual then any collision will do
676 if( !aActual )
677 break;
678 }
679 }
680
681 for( size_t i = 0; i < aB.ArcCount(); i++ )
682 {
683 const SHAPE_ARC& arc = aB.Arc( i );
684
685 // The arcs in the chain should have zero width
686 wxASSERT_MSG( arc.GetWidth() == 0, wxT( "Invalid arc width - should be zero" ) );
687
688 if( aA.Collide( &arc, aClearance, aActual || aLocation ? &collision_dist : nullptr,
689 aLocation ? &pn : nullptr ) )
690 {
691 if( collision_dist < closest_dist )
692 {
693 nearest = pn;
694 closest_dist = collision_dist;
695 }
696
697 if( closest_dist == 0 )
698 break;
699
700 if( !aActual )
701 break;
702 }
703 }
704 }
705
706 if( closest_dist == 0 || closest_dist < aClearance )
707 {
708 if( aLocation )
709 *aLocation = nearest;
710
711 if( aActual )
712 *aActual = closest_dist;
713
714 return true;
715 }
716
717 return false;
718}
719
720
721static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_RECT& aB, int aClearance,
722 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
723{
724 if( aB.GetRadius() > 0 )
725 return Collide( aA, aB.Outline(), aClearance, aActual, aLocation, aMTV );
726
727 if( aA.IsEffectiveLine() )
728 {
729 SHAPE_SEGMENT tmp( aA.GetP0(), aA.GetP1(), aA.GetWidth() );
730 bool retval = Collide( aB, tmp, aClearance, aActual, aLocation, aMTV );
731
732 if( retval && aMTV )
733 *aMTV = - *aMTV;
734
735 return retval;
736 }
737
738 VECTOR2I ptA, ptB;
739 int64_t dist_sq = std::numeric_limits<int64_t>::max();
740 aA.NearestPoints( aB, ptA, ptB, dist_sq );
741
742 if( dist_sq == 0 || dist_sq < SEG::Square( aClearance ) )
743 {
744 if( aLocation )
745 *aLocation = ( ptA + ptB ) / 2;
746
747 if( aActual )
748 *aActual = std::max( 0, KiROUND( std::sqrt( dist_sq ) ) );
749
750 if( aMTV )
751 {
752 const VECTOR2I delta = ptB - ptA;
753 *aMTV = delta.Resize( aClearance - std::sqrt( dist_sq ) + 3 );
754 }
755
756 return true;
757 }
758
759 return false;
760}
761
762
763static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SEGMENT& aB, int aClearance,
764 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
765{
766 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
767 aA.TypeName(),
768 aB.TypeName() ) );
769
770 // If the arc radius is too large, it is effectively a line segment
771 if( aA.IsEffectiveLine() )
772 {
773 SHAPE_SEGMENT tmp( aA.GetP0(), aA.GetP1(), aA.GetWidth() );
774 return Collide( tmp, aB, aClearance, aActual, aLocation, aMTV );
775 }
776
777 bool rv = aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, aActual, aLocation );
778
779 if( rv && aActual )
780 *aActual = std::max( 0, *aActual - aB.GetWidth() / 2 );
781
782 return rv;
783}
784
785
786static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
787 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
788{
789 // If the arc radius is too large, it is effectively a line segment
790 if( aA.IsEffectiveLine() )
791 {
792 SHAPE_SEGMENT tmp( aA.GetP0(), aA.GetP1(), aA.GetWidth() );
793 return Collide( aB, tmp, aClearance, aActual, aLocation, aMTV );
794 }
795
796 wxASSERT_MSG( !aMTV, wxString::Format( wxT( "MTV not implemented for %s : %s collisions" ),
797 aA.TypeName(),
798 aB.TypeName() ) );
799
800 int closest_dist = std::numeric_limits<int>::max();
801 VECTOR2I nearest;
802
803 if( aB.IsClosed() && aB.PointInside( aA.GetP0() ) )
804 {
805 closest_dist = 0;
806 nearest = aA.GetP0();
807 }
808 else
809 {
810 for( size_t i = 0; i < aB.GetSegmentCount(); i++ )
811 {
812 int collision_dist = 0;
813 VECTOR2I pn;
814
815 if( aA.Collide( aB.GetSegment( i ), aClearance,
816 aActual || aLocation ? &collision_dist : nullptr,
817 aLocation ? &pn : nullptr ) )
818 {
819 if( collision_dist < closest_dist )
820 {
821 nearest = pn;
822 closest_dist = collision_dist;
823 }
824
825 if( closest_dist == 0 )
826 break;
827
828 // If we're not looking for aActual then any collision will do
829 if( !aActual )
830 break;
831 }
832 }
833 }
834
835 if( closest_dist == 0 || closest_dist < aClearance )
836 {
837 if( aLocation )
838 *aLocation = nearest;
839
840 if( aActual )
841 *aActual = closest_dist;
842
843 return true;
844 }
845
846 return false;
847}
848
849
850static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_ARC& aB, int aClearance,
851 int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
852{
853 if( aA.IsEffectiveLine() )
854 {
855 SHAPE_SEGMENT tmp( aA.GetP0(), aA.GetP1(), aA.GetWidth() );
856 bool retval = Collide( aB, tmp, aClearance, aActual, aLocation, aMTV );
857
858 if( retval && aMTV )
859 *aMTV = - *aMTV;
860
861 return retval;
862 }
863
864 if( aB.IsEffectiveLine() )
865 {
866 SHAPE_SEGMENT tmp( aB.GetP0(), aB.GetP1(), aB.GetWidth() );
867 return Collide( aA, tmp, aClearance, aActual, aLocation, aMTV );
868 }
869
870 VECTOR2I ptA, ptB;
871 int64_t dist_sq = std::numeric_limits<int64_t>::max();
872 aA.NearestPoints( aB, ptA, ptB, dist_sq );
873
874 if( dist_sq == 0 || dist_sq < SEG::Square( aClearance ) )
875 {
876 if( aLocation )
877 *aLocation = ( ptA + ptB ) / 2;
878
879 if( aActual )
880 *aActual = std::max( 0, KiROUND( std::sqrt( dist_sq ) ) );
881
882 if( aMTV )
883 {
884 const VECTOR2I delta = ptB - ptA;
885 *aMTV = delta.Resize( aClearance - std::sqrt( dist_sq ) + 3 );
886 }
887
888 return true;
889 }
890
891 return false;
892}
893
894
895template<class T_a, class T_b>
896inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
897 VECTOR2I* aLocation, VECTOR2I* aMTV )
898
899{
900 return Collide( *static_cast<const T_a*>( aA ), *static_cast<const T_b*>( aB ),
901 aClearance, aActual, aLocation, aMTV);
902}
903
904
905template<class T_a, class T_b>
906inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
907 VECTOR2I* aLocation, VECTOR2I* aMTV )
908{
909 bool rv = Collide( *static_cast<const T_b*>( aB ), *static_cast<const T_a*>( aA ),
910 aClearance, aActual, aLocation, aMTV);
911
912 if( rv && aMTV)
913 *aMTV = - *aMTV;
914
915 return rv;
916}
917
918
919static inline bool Collide( const SHAPE_ELLIPSE& aA, const SHAPE_SEGMENT& aSeg, int aClearance, int* aActual,
920 VECTOR2I* aLocation, VECTOR2I* aMTV )
921{
922 wxASSERT_MSG( !aMTV, wxT( "MTV not implemented for SHAPE_ELLIPSE collisions" ) );
923
924 const int halfWidth = aSeg.GetWidth() / 2;
925 const int effClear = aClearance + halfWidth;
926
927 int localActual = 0;
928 VECTOR2I localLoc;
929
930 if( aA.Collide( aSeg.GetSeg(), effClear, aActual ? &localActual : nullptr, aLocation ? &localLoc : nullptr ) )
931 {
932 if( aActual )
933 *aActual = std::max( 0, localActual - halfWidth );
934 if( aLocation )
935 *aLocation = localLoc;
936 return true;
937 }
938
939 return false;
940}
941
942
943static inline bool Collide( const SHAPE_ELLIPSE& aA, const SHAPE_CIRCLE& aB, int aClearance, int* aActual,
944 VECTOR2I* aLocation, VECTOR2I* aMTV )
945{
946 wxASSERT_MSG( !aMTV, wxT( "MTV not implemented for SHAPE_ELLIPSE collisions" ) );
947
948 const VECTOR2I c = aB.GetCenter();
949 const int r = aB.GetRadius();
950 const int effClr = aClearance + r;
951 const SEG::ecoord dSq = aA.SquaredDistance( c, false );
952 const SEG::ecoord effSq = static_cast<SEG::ecoord>( effClr ) * static_cast<SEG::ecoord>( effClr );
953
954 if( dSq == 0 || dSq < effSq )
955 {
956 if( aActual )
957 {
958 const int d = static_cast<int>( std::round( std::sqrt( static_cast<double>( dSq ) ) ) );
959 *aActual = std::max( 0, d - r );
960 }
961 if( aLocation )
962 *aLocation = c;
963 return true;
964 }
965
966 return false;
967}
968
969
970static inline bool Collide( const SHAPE_ELLIPSE& aA, const SHAPE_RECT& aB, int aClearance, int* aActual,
971 VECTOR2I* aLocation, VECTOR2I* aMTV )
972{
973 wxASSERT_MSG( !aMTV, wxT( "MTV not implemented for SHAPE_ELLIPSE collisions" ) );
975 aA, aB.Outline(), aClearance, /*halfWidth*/ 0,
976 [&]
977 {
978 return aB.BBox().Contains( aA.GetCenter() );
979 },
980 aActual, aLocation );
981}
982
983
984static inline bool Collide( const SHAPE_ELLIPSE& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance, int* aActual,
985 VECTOR2I* aLocation, VECTOR2I* aMTV )
986{
987 wxASSERT_MSG( !aMTV, wxT( "MTV not implemented for SHAPE_ELLIPSE collisions" ) );
989 aA, aB, aClearance, /*halfWidth*/ 0,
990 [&]
991 {
992 return aB.IsClosed() && aB.GetSegmentCount() > 0 && aB.PointInside( aA.GetCenter() );
993 },
994 aActual, aLocation );
995}
996
997
998static inline bool Collide( const SHAPE_ELLIPSE& aA, const SHAPE_ARC& aB, int aClearance, int* aActual,
999 VECTOR2I* aLocation, VECTOR2I* aMTV )
1000{
1001 wxASSERT_MSG( !aMTV, wxT( "MTV not implemented for SHAPE_ELLIPSE collisions" ) );
1002
1003 const int halfWidth = aB.GetWidth() / 2;
1004 const int effClear = aClearance + halfWidth;
1005 const int tessError = std::max( 1, effClear / 4 );
1006 const SHAPE_LINE_CHAIN chain = aB.ConvertToPolyline( tessError );
1007
1009 aA, chain, aClearance, halfWidth,
1010 []
1011 {
1012 return false;
1013 },
1014 aActual, aLocation );
1015}
1016
1017
1018static inline bool Collide( const SHAPE_ELLIPSE& aA, const SHAPE_ELLIPSE& aB, int aClearance, int* aActual,
1019 VECTOR2I* aLocation, VECTOR2I* aMTV )
1020{
1021 wxASSERT_MSG( !aMTV, wxT( "MTV not implemented for SHAPE_ELLIPSE collisions" ) );
1022
1023 if( !aA.IsArc() && aA.PointInside( aB.GetCenter() ) )
1024 {
1025 if( aActual )
1026 *aActual = 0;
1027 if( aLocation )
1028 *aLocation = aB.GetCenter();
1029 return true;
1030 }
1031 if( !aB.IsArc() && aB.PointInside( aA.GetCenter() ) )
1032 {
1033 if( aActual )
1034 *aActual = 0;
1035 if( aLocation )
1036 *aLocation = aA.GetCenter();
1037 return true;
1038 }
1039
1040 const int tessError = std::max( 1, aClearance / 4 );
1041 const SHAPE_LINE_CHAIN chainB = aB.ConvertToPolyline( tessError );
1042
1043 return Collide( aA, chainB, aClearance, aActual, aLocation, aMTV );
1044}
1045
1046
1047static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
1048 VECTOR2I* aLocation, VECTOR2I* aMTV )
1049{
1050 if( aA->Type() == SH_POLY_SET )
1051 {
1052 const SHAPE_POLY_SET* polySetA = static_cast<const SHAPE_POLY_SET*>( aA );
1053
1054 wxASSERT( !aMTV );
1055 return polySetA->Collide( aB, aClearance, aActual, aLocation );
1056 }
1057 else if( aB->Type() == SH_POLY_SET )
1058 {
1059 const SHAPE_POLY_SET* polySetB = static_cast<const SHAPE_POLY_SET*>( aB );
1060
1061 wxASSERT( !aMTV );
1062 return polySetB->Collide( aA, aClearance, aActual, aLocation );
1063 }
1064
1065 switch( aA->Type() )
1066 {
1067 case SH_NULL:
1068 return false;
1069
1070 case SH_RECT:
1071 switch( aB->Type() )
1072 {
1073 case SH_RECT:
1074 return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1075
1076 case SH_CIRCLE:
1077 return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1078
1079 case SH_LINE_CHAIN:
1080 return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
1081
1082 case SH_SEGMENT:
1083 return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1084
1085 case SH_SIMPLE:
1087 return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1088
1089 case SH_ARC:
1090 return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
1091
1092 case SH_ELLIPSE:
1093 return CollCaseReversed<SHAPE_RECT, SHAPE_ELLIPSE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1094
1095 case SH_NULL:
1096 return false;
1097
1098 default:
1099 break;
1100 }
1101 break;
1102
1103 case SH_CIRCLE:
1104 switch( aB->Type() )
1105 {
1106 case SH_RECT:
1107 return CollCaseReversed<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1108
1109 case SH_CIRCLE:
1110 return CollCase<SHAPE_CIRCLE, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1111
1112 case SH_LINE_CHAIN:
1113 return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
1114
1115 case SH_SEGMENT:
1116 return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1117
1118 case SH_SIMPLE:
1120 return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1121
1122 case SH_ARC:
1123 return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
1124
1125 case SH_ELLIPSE:
1126 return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ELLIPSE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1127
1128 case SH_NULL:
1129 return false;
1130
1131 default:
1132 break;
1133 }
1134 break;
1135
1136 case SH_LINE_CHAIN:
1137 switch( aB->Type() )
1138 {
1139 case SH_RECT:
1140 return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aLocation, aMTV );
1141
1142 case SH_CIRCLE:
1143 return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aLocation, aMTV );
1144
1145 case SH_LINE_CHAIN:
1146 return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
1147
1148 case SH_SEGMENT:
1149 return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1150
1151 case SH_SIMPLE:
1153 return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1154
1155 case SH_ARC:
1156 return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
1157
1158 case SH_ELLIPSE:
1159 return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ELLIPSE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1160
1161 case SH_NULL:
1162 return false;
1163
1164 default:
1165 break;
1166 }
1167 break;
1168
1169 case SH_SEGMENT:
1170 switch( aB->Type() )
1171 {
1172 case SH_RECT:
1173 return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aLocation, aMTV );
1174
1175 case SH_CIRCLE:
1176 return CollCaseReversed<SHAPE_SEGMENT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1177
1178 case SH_LINE_CHAIN:
1179 return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aLocation, aMTV );
1180
1181 case SH_SEGMENT:
1182 return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1183
1184 case SH_SIMPLE:
1186 return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aLocation, aMTV );
1187
1188 case SH_ARC:
1189 return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
1190
1191 case SH_ELLIPSE:
1192 return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ELLIPSE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1193
1194 case SH_NULL:
1195 return false;
1196
1197 default:
1198 break;
1199 }
1200 break;
1201
1202 case SH_SIMPLE:
1204 switch( aB->Type() )
1205 {
1206 case SH_RECT:
1207 return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aLocation, aMTV );
1208
1209 case SH_CIRCLE:
1210 return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aLocation, aMTV );
1211
1212 case SH_LINE_CHAIN:
1213 return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aLocation, aMTV );
1214
1215 case SH_SEGMENT:
1216 return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1217
1218 case SH_SIMPLE:
1220 return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1221
1222 case SH_ARC:
1223 return CollCaseReversed<SHAPE_LINE_CHAIN_BASE, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
1224
1225 case SH_ELLIPSE:
1226 return CollCaseReversed<SHAPE_LINE_CHAIN_BASE, SHAPE_ELLIPSE>( aA, aB, aClearance, aActual, aLocation,
1227 aMTV );
1228
1229 case SH_NULL:
1230 return false;
1231
1232 default:
1233 break;
1234 }
1235 break;
1236
1237 case SH_ARC:
1238 switch( aB->Type() )
1239 {
1240 case SH_RECT:
1241 return CollCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1242
1243 case SH_CIRCLE:
1244 return CollCase<SHAPE_ARC, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1245
1246 case SH_LINE_CHAIN:
1247 return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
1248
1249 case SH_SEGMENT:
1250 return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1251
1252 case SH_SIMPLE:
1254 return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1255
1256 case SH_ARC:
1257 return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
1258
1259 case SH_ELLIPSE:
1260 return CollCaseReversed<SHAPE_ARC, SHAPE_ELLIPSE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1261
1262 case SH_NULL: return false;
1263
1264 default: break;
1265 }
1266 break;
1267
1268 case SH_ELLIPSE:
1269 switch( aB->Type() )
1270 {
1271 case SH_RECT: return CollCase<SHAPE_ELLIPSE, SHAPE_RECT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1272
1273 case SH_CIRCLE: return CollCase<SHAPE_ELLIPSE, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1274
1275 case SH_LINE_CHAIN:
1276 return CollCase<SHAPE_ELLIPSE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1277
1278 case SH_SEGMENT: return CollCase<SHAPE_ELLIPSE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
1279
1280 case SH_SIMPLE:
1282 return CollCase<SHAPE_ELLIPSE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1283
1284 case SH_ARC: return CollCase<SHAPE_ELLIPSE, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
1285
1286 case SH_ELLIPSE: return CollCase<SHAPE_ELLIPSE, SHAPE_ELLIPSE>( aA, aB, aClearance, aActual, aLocation, aMTV );
1287
1288 case SH_NULL:
1289 return false;
1290
1291 default:
1292 break;
1293 }
1294 break;
1295
1296 default:
1297 break;
1298 }
1299
1300 wxFAIL_MSG( wxString::Format( wxT( "Unsupported collision: %s with %s" ),
1301 SHAPE_TYPE_asString( aA->Type() ),
1302 SHAPE_TYPE_asString( aB->Type() ) ) );
1303
1304 return false;
1305}
1306
1307static bool collideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
1308 VECTOR2I* aLocation, VECTOR2I* aMTV )
1309{
1310 int currentActual = std::numeric_limits<int>::max();
1311 VECTOR2I currentLocation;
1312 VECTOR2I currentMTV(0, 0);
1313 bool colliding = false;
1314
1315 auto canExit =
1316 [&]()
1317 {
1318 if( !colliding )
1319 return false;
1320
1321 if( aActual && currentActual > 0 )
1322 return false;
1323
1324 if( aMTV )
1325 return false;
1326
1327 return true;
1328 };
1329
1330 auto collideCompoundSubshapes =
1331 [&]( const SHAPE* elemA, const SHAPE* elemB, int clearance ) -> bool
1332 {
1333 int actual = 0;
1335 VECTOR2I mtv;
1336
1337 if( collideSingleShapes( elemA, elemB, clearance,
1338 aActual || aLocation ? &actual : nullptr,
1339 aLocation ? &location : nullptr,
1340 aMTV ? &mtv : nullptr ) )
1341 {
1342 if( actual < currentActual )
1343 {
1344 currentActual = actual;
1345 currentLocation = location;
1346 }
1347
1348 if( aMTV && mtv.SquaredEuclideanNorm() > currentMTV.SquaredEuclideanNorm() )
1349 {
1350 currentMTV = mtv;
1351 }
1352
1353 return true;
1354 }
1355
1356 return false;
1357 };
1358
1359 if( aA->Type() == SH_COMPOUND && aB->Type() == SH_COMPOUND )
1360 {
1361 const SHAPE_COMPOUND* cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
1362 const SHAPE_COMPOUND* cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
1363
1364 for( const SHAPE* elemA : cmpA->Shapes() )
1365 {
1366 for( const SHAPE* elemB : cmpB->Shapes() )
1367 {
1368 if( collideCompoundSubshapes( elemA, elemB, aClearance ) )
1369 {
1370 colliding = true;
1371
1372 if( canExit() )
1373 break;
1374 }
1375 }
1376
1377 if( canExit() )
1378 break;
1379 }
1380 }
1381 else if( aA->Type() == SH_COMPOUND )
1382 {
1383 const SHAPE_COMPOUND* cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
1384
1385 for( const SHAPE* elemA : cmpA->Shapes() )
1386 {
1387 if( collideCompoundSubshapes( elemA, aB, aClearance ) )
1388 {
1389 colliding = true;
1390
1391 if( canExit() )
1392 break;
1393 }
1394 }
1395 }
1396 else if( aB->Type() == SH_COMPOUND )
1397 {
1398 const SHAPE_COMPOUND* cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
1399
1400 for( const SHAPE* elemB : cmpB->Shapes() )
1401 {
1402 if( collideCompoundSubshapes( aA, elemB, aClearance ) )
1403 {
1404 colliding = true;
1405
1406 if( canExit() )
1407 break;
1408 }
1409 }
1410 }
1411 else
1412 {
1413 return collideSingleShapes( aA, aB, aClearance, aActual, aLocation, aMTV );
1414 }
1415
1416 if( colliding )
1417 {
1418 if( aLocation )
1419 *aLocation = currentLocation;
1420
1421 if( aActual )
1422 *aActual = currentActual;
1423
1424 if( aMTV )
1425 *aMTV = currentMTV;
1426 }
1427
1428 return colliding;
1429}
1430
1431
1432bool SHAPE::Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const
1433{
1434 return collideShapes( this, aShape, aClearance, nullptr, nullptr, aMTV );
1435}
1436
1437
1438bool SHAPE::Collide( const SHAPE* aShape, int aClearance, int* aActual, VECTOR2I* aLocation ) const
1439{
1440 return collideShapes( this, aShape, aClearance, aActual, aLocation, nullptr );
1441}
1442
1443
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:307
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I::extended_type ecoord
Definition seg.h:40
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition seg.cpp:629
static SEG::ecoord Square(int a)
Definition seg.h:119
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:698
int GetWidth() const override
Definition shape_arc.h:211
const SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError=DefaultAccuracyForPCB(), int *aActualError=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
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,...
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
Definition shape_arc.h:114
wxString TypeName() const
Definition shape.h:101
SHAPE_TYPE Type() const
Return the type of the shape.
Definition shape.h:96
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,...
int GetRadius() const
const VECTOR2I GetCenter() const
void SetCenter(const VECTOR2I &aCenter)
const std::vector< SHAPE * > & Shapes() const
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
const VECTOR2I & GetCenter() const
SEG::ecoord SquaredDistance(const VECTOR2I &aP, bool aOutlineOnly=false) const override
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
bool IsArc() const
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,...
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
virtual size_t GetPointCount() const =0
virtual size_t GetSegmentCount() const =0
virtual const VECTOR2I GetPoint(int aIndex) const =0
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
virtual bool IsClosed() const =0
virtual const SEG GetSegment(int aIndex) const =0
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
virtual const SEG GetSegment(int aIndex) const override
virtual size_t GetSegmentCount() const override
size_t ArcCount() const
bool IsArcSegment(size_t aSegment) const
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
Represent a set of closed polygons.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
bool Collide(const SHAPE *aShape, int aClearance, VECTOR2I *aMTV) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
Definition shape_rect.h:147
const SHAPE_LINE_CHAIN Outline() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Definition shape_rect.h:105
const VECTOR2I & GetPosition() const
Definition shape_rect.h:165
const VECTOR2I GetSize() const
Definition shape_rect.h:173
int GetRadius() const
Definition shape_rect.h:197
const SEG & GetSeg() const
int GetWidth() const override
bool Collide(const SHAPE *aShape, int aClearance, VECTOR2I *aMTV) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
An abstract shape on 2D plane.
Definition shape.h:124
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition shape.h:179
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Definition shape.h:230
SHAPE(SHAPE_TYPE aType)
Create an empty shape of type aType.
Definition shape.h:134
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
Definition vector2d.h:303
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:72
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition vector2d.h:69
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:381
@ SH_POLY_SET
set of polygons (with holes, etc.)
Definition shape.h:48
@ SH_RECT
axis-aligned rectangle
Definition shape.h:43
@ SH_CIRCLE
circle
Definition shape.h:46
@ SH_SIMPLE
simple polygon
Definition shape.h:47
@ SH_ELLIPSE
ellipse or elliptical arc
Definition shape.h:53
@ SH_NULL
empty shape (no shape...),
Definition shape.h:51
@ SH_SEGMENT
line segment
Definition shape.h:44
@ SH_ARC
circular arc
Definition shape.h:50
@ SH_POLY_SET_TRIANGLE
a single triangle belonging to a POLY_SET triangulation
Definition shape.h:52
@ SH_LINE_CHAIN
line chain (polyline)
Definition shape.h:45
@ SH_COMPOUND
compound shape, consisting of multiple simple shapes
Definition shape.h:49
static wxString SHAPE_TYPE_asString(SHAPE_TYPE a)
Definition shape.h:56
static bool collideSingleShapes(const SHAPE *aA, const SHAPE *aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
static bool Collide(const SHAPE_CIRCLE &aA, const SHAPE_CIRCLE &aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
bool CollCaseReversed(const SHAPE *aA, const SHAPE *aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
static bool collideEllipseVsSegments(const SHAPE_ELLIPSE &aA, const SegmentSource &aSegSource, int aClearance, int aHalfWidth, Containment aContainment, int *aActual, VECTOR2I *aLocation)
static VECTOR2I pushoutForce(const SHAPE_CIRCLE &aA, const SEG &aB, int aClearance)
bool CollCase(const SHAPE *aA, const SHAPE *aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
static bool collideShapes(const SHAPE *aA, const SHAPE *aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
VECTOR2I::extended_type ecoord
const SHAPE_LINE_CHAIN chain
int clearance
VECTOR2I location
int actual
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683