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