KiCad PCB EDA Suite
Loading...
Searching...
No Matches
shape_nearest_points.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
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 * https://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the https://www.gnu.org website for the version 3 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
24#include <cmath>
25#include <limits>
26
27#include <geometry/seg.h>
28#include <geometry/shape.h>
29#include <geometry/shape_arc.h>
32#include <geometry/shape_rect.h>
37#include <math/vector2d.h>
38
40
41
42static bool NearestPoints( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_LINE_CHAIN_BASE& aB,
43 VECTOR2I& aPtA, VECTOR2I& aPtB );
44
45static bool NearestPoints( const SEG& aSeg, const SHAPE_LINE_CHAIN_BASE& aChain,
46 VECTOR2I& aPtA, VECTOR2I& aPtB );
47
57static bool NearestPoints( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB,
58 VECTOR2I& aPtA, VECTOR2I& aPtB )
59{
60 const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
61 const int dist = delta.EuclideanNorm();
62
63 if( dist == 0 )
64 {
65 // Circles are concentric - pick arbitrary points
66 aPtA = aA.GetCenter() + VECTOR2I( aA.GetRadius(), 0 );
67 aPtB = aB.GetCenter() + VECTOR2I( aB.GetRadius(), 0 );
68 }
69 else
70 {
71 // Points lie on line between centers
72 aPtA = aA.GetCenter() + delta.Resize( aA.GetRadius() );
73 aPtB = aB.GetCenter() - delta.Resize( aB.GetRadius() );
74 }
75
76 return true;
77}
78
79
89static bool NearestPoints( const SHAPE_CIRCLE& aCircle, const SHAPE_RECT& aRect,
90 VECTOR2I& aPtA, VECTOR2I& aPtB )
91{
92 const VECTOR2I c = aCircle.GetCenter();
93 const VECTOR2I p0 = aRect.GetPosition();
94 const VECTOR2I size = aRect.GetSize();
95
96 // Clamp circle center to rectangle bounds to find nearest point on rect
97 aPtB.x = std::max( p0.x, std::min( c.x, p0.x + size.x ) );
98 aPtB.y = std::max( p0.y, std::min( c.y, p0.y + size.y ) );
99
100 // Find nearest point on circle
101 if( aPtB == c )
102 {
103 // Center is inside rectangle - find nearest edge
104 int distToLeft = c.x - p0.x;
105 int distToRight = p0.x + size.x - c.x;
106 int distToTop = c.y - p0.y;
107 int distToBottom = p0.y + size.y - c.y;
108
109 int minDist = std::min( { distToLeft, distToRight, distToTop, distToBottom } );
110
111 if( minDist == distToLeft )
112 {
113 aPtB = VECTOR2I( p0.x, c.y );
114 aPtA = c - VECTOR2I( aCircle.GetRadius(), 0 );
115 }
116 else if( minDist == distToRight )
117 {
118 aPtB = VECTOR2I( p0.x + size.x, c.y );
119 aPtA = c + VECTOR2I( aCircle.GetRadius(), 0 );
120 }
121 else if( minDist == distToTop )
122 {
123 aPtB = VECTOR2I( c.x, p0.y );
124 aPtA = c - VECTOR2I( 0, aCircle.GetRadius() );
125 }
126 else
127 {
128 aPtB = VECTOR2I( c.x, p0.y + size.y );
129 aPtA = c + VECTOR2I( 0, aCircle.GetRadius() );
130 }
131 }
132 else
133 {
134 VECTOR2I dir = ( aPtB - c ).Resize( aCircle.GetRadius() );
135 aPtA = c + dir;
136 }
137
138 return true;
139}
140
141
151static bool NearestPoints( const SHAPE_CIRCLE& aCircle, const SEG& aSeg,
152 VECTOR2I& aPtA, VECTOR2I& aPtB )
153{
154 aPtB = aSeg.NearestPoint( aCircle.GetCenter() );
155
156 if( aPtB == aCircle.GetCenter() )
157 {
158 // Center is on segment - pick perpendicular direction
159 VECTOR2I dir = ( aSeg.B - aSeg.A ).Perpendicular().Resize( aCircle.GetRadius() );
160 aPtA = aCircle.GetCenter() + dir;
161 }
162 else
163 {
164 VECTOR2I dir = ( aPtB - aCircle.GetCenter() ).Resize( aCircle.GetRadius() );
165 aPtA = aCircle.GetCenter() + dir;
166 }
167
168 return true;
169}
170
171
175static bool NearestPoints( const SHAPE_CIRCLE& aCircle, const SHAPE_LINE_CHAIN_BASE& aChain,
176 VECTOR2I& aPtA, VECTOR2I& aPtB )
177{
178 const SHAPE_LINE_CHAIN* chain = dynamic_cast<const SHAPE_LINE_CHAIN*>( &aChain );
179 int64_t minDistSq = std::numeric_limits<int64_t>::max();
180
181 for( size_t i = 0; i < aChain.GetSegmentCount(); i++ )
182 {
183 if( chain && chain->IsArcSegment( i ) )
184 continue;
185
186 VECTOR2I ptA, ptB;
187 if( NearestPoints( aCircle, aChain.GetSegment( i ), ptA, ptB ) )
188 {
189 int64_t distSq = ( ptB - ptA ).SquaredEuclideanNorm();
190 if( distSq < minDistSq )
191 {
192 minDistSq = distSq;
193 aPtA = ptA;
194 aPtB = ptB;
195 }
196 }
197 }
198
199 // Also handle arcs if this is a SHAPE_LINE_CHAIN
200 if( chain )
201 {
202 for( size_t j = 0; j < chain->ArcCount(); j++ )
203 {
204 const SHAPE_ARC& arc = chain->Arc( j );
205
206 VECTOR2I ptA, ptB;
207 int64_t distSq;
208
209 // Reverse the output points to match the arc_from_chain/circle order
210 if( arc.NearestPoints( aCircle, ptB, ptA, distSq ) )
211 {
212 if( distSq < minDistSq )
213 {
214 minDistSq = distSq;
215 aPtA = ptA;
216 aPtB = ptB;
217 }
218 }
219 }
220 }
221
222 return minDistSq < std::numeric_limits<int64_t>::max();
223}
224
225
229static bool NearestPoints( const SHAPE_RECT& aA, const SHAPE_RECT& aB,
230 VECTOR2I& aPtA, VECTOR2I& aPtB )
231{
232 // Convert rectangles to line chains and use that algorithm
233 const SHAPE_LINE_CHAIN outlineA = aA.Outline();
234 const SHAPE_LINE_CHAIN outlineB = aB.Outline();
235
236 return NearestPoints( outlineA, outlineB, aPtA, aPtB );
237}
238
239
243static bool NearestPoints( const SHAPE_RECT& aRect, const SEG& aSeg, VECTOR2I& aPtA, VECTOR2I& aPtB )
244{
245 const SHAPE_LINE_CHAIN outline = aRect.Outline();
246
247 // Reverse the output points to match the seg/rect_outline order
248 return NearestPoints( aSeg, outline, aPtB, aPtA );
249}
250
251
255static bool NearestPoints( const SHAPE_RECT& aRect, const SHAPE_LINE_CHAIN_BASE& aChain,
256 VECTOR2I& aPtA, VECTOR2I& aPtB )
257{
258 const SHAPE_LINE_CHAIN outline = aRect.Outline();
259
260 return NearestPoints( outline, aChain, aPtA, aPtB );
261}
262
263
267static bool NearestPoints( const SEG& aA, const SEG& aB,
268 VECTOR2I& aPtA, VECTOR2I& aPtB )
269{
270 aPtA = aA.NearestPoint( aB );
271 aPtB = aB.NearestPoint( aPtA );
272
273 return true;
274}
275
276
280static bool NearestPoints( const SEG& aSeg, const SHAPE_LINE_CHAIN_BASE& aChain,
281 VECTOR2I& aPtA, VECTOR2I& aPtB )
282{
283 const SHAPE_LINE_CHAIN* chain = dynamic_cast<const SHAPE_LINE_CHAIN*>( &aChain );
284 int64_t minDistSq = std::numeric_limits<int64_t>::max();
285
286 for( size_t i = 0; i < aChain.GetSegmentCount(); i++ )
287 {
288 if( chain && chain->IsArcSegment( i ) )
289 continue;
290
291 VECTOR2I ptA, ptB;
292
293 if( NearestPoints( aSeg, aChain.GetSegment( i ), ptA, ptB ) )
294 {
295 int64_t distSq = ( ptB - ptA ).SquaredEuclideanNorm();
296 if( distSq < minDistSq )
297 {
298 minDistSq = distSq;
299 aPtA = ptA;
300 aPtB = ptB;
301 }
302 }
303 }
304
305 // Also handle arcs if this is a SHAPE_LINE_CHAIN
306 if( chain )
307 {
308 for( size_t j = 0; j < chain->ArcCount(); j++ )
309 {
310 const SHAPE_ARC& arc = chain->Arc( j );
311
312 VECTOR2I ptA, ptB;
313 int64_t distSq;
314
315 // Reverse the output points to match the arc_from_chain/seg order
316 if( arc.NearestPoints( aSeg, ptB, ptA, distSq ) )
317 {
318 if( distSq < minDistSq )
319 {
320 minDistSq = distSq;
321 aPtA = ptA;
322 aPtB = ptB;
323 }
324 }
325 }
326 }
327
328 return minDistSq < std::numeric_limits<int64_t>::max();
329}
330
331
336 VECTOR2I& aPtA, VECTOR2I& aPtB )
337{
338 const SHAPE_LINE_CHAIN* chainA = dynamic_cast<const SHAPE_LINE_CHAIN*>( &aA );
339 const SHAPE_LINE_CHAIN* chainB = dynamic_cast<const SHAPE_LINE_CHAIN*>( &aB );
340 int64_t minDistSq = std::numeric_limits<int64_t>::max();
341
342 // Check all segment pairs
343 for( size_t i = 0; i < aA.GetSegmentCount(); i++ )
344 {
345 if( chainA && chainA->IsArcSegment( i ) )
346 continue;
347
348 for( size_t j = 0; j < aB.GetSegmentCount(); j++ )
349 {
350 if( chainB && chainB->IsArcSegment( j ) )
351 continue;
352
353 VECTOR2I ptA, ptB;
354 if( NearestPoints( aA.GetSegment( i ), aB.GetSegment( j ), ptA, ptB ) )
355 {
356 int64_t distSq = ( ptB - ptA ).SquaredEuclideanNorm();
357 if( distSq < minDistSq )
358 {
359 minDistSq = distSq;
360 aPtA = ptA;
361 aPtB = ptB;
362 }
363 }
364 }
365 }
366
367 // Also handle arcs if this is a SHAPE_LINE_CHAIN
368 if( chainA )
369 {
370 for( size_t i = 0; i < chainA->ArcCount(); i++ )
371 {
372 const SHAPE_ARC& arcA = chainA->Arc( i );
373
374 if( chainB )
375 {
376 // Arc to arc
377 for( size_t j = 0; j < chainB->ArcCount(); j++ )
378 {
379 VECTOR2I ptA, ptB;
380 int64_t distSq;
381 if( arcA.NearestPoints( chainB->Arc( j ), ptA, ptB, distSq ) )
382 {
383 if( distSq < minDistSq )
384 {
385 minDistSq = distSq;
386 aPtA = ptA;
387 aPtB = ptB;
388 }
389 }
390 }
391 }
392
393 // Arc to segments
394 for( size_t j = 0; j < aB.GetSegmentCount(); j++ )
395 {
396 VECTOR2I ptA, ptB;
397 int64_t distSq;
398 if( arcA.NearestPoints( aB.GetSegment( j ), ptA, ptB, distSq ) )
399 {
400 if( distSq < minDistSq )
401 {
402 minDistSq = distSq;
403 aPtA = ptA;
404 aPtB = ptB;
405 }
406 }
407 }
408 }
409 }
410
411 if( chainB && !chainA )
412 {
413 // Handle arcs in chainB vs segments in aA
414 for( size_t j = 0; j < chainB->ArcCount(); j++ )
415 {
416 const SHAPE_ARC& arcB = chainB->Arc( j );
417
418 for( size_t i = 0; i < aA.GetSegmentCount(); i++ )
419 {
420 VECTOR2I ptA, ptB;
421 int64_t distSq;
422 if( arcB.NearestPoints( aA.GetSegment( i ), ptB, ptA, distSq ) )
423 {
424 if( distSq < minDistSq )
425 {
426 minDistSq = distSq;
427 aPtA = ptA;
428 aPtB = ptB;
429 }
430 }
431 }
432 }
433 }
434
435 return minDistSq < std::numeric_limits<int64_t>::max();
436}
437
438
443static bool NearestPoints( const SHAPE_ARC& aArc, const SHAPE_CIRCLE& aCircle, VECTOR2I& aPtA, VECTOR2I& aPtB )
444{
445 int64_t distSq;
446 return aArc.NearestPoints( aCircle, aPtA, aPtB, distSq );
447}
448
449static bool NearestPoints( const SHAPE_ARC& aArc, const SHAPE_RECT& aRect, VECTOR2I& aPtA, VECTOR2I& aPtB )
450{
451 int64_t distSq;
452 return aArc.NearestPoints( aRect, aPtA, aPtB, distSq );
453}
454
455static bool NearestPoints( const SHAPE_ARC& aArc, const SHAPE_SEGMENT& aSeg, VECTOR2I& aPtA, VECTOR2I& aPtB )
456{
457 int64_t distSq;
458 bool retVal = aArc.NearestPoints( aSeg.GetSeg(), aPtA, aPtB, distSq );
459
460 // Adjust point B by half the seg width towards point A
461 VECTOR2I dir = ( aPtA - aPtB ).Resize( aSeg.GetWidth() / 2 );
462 aPtB += dir;
463
464 return retVal;
465}
466
467static bool NearestPoints( const SHAPE_ARC& aArcA, const SHAPE_ARC& aArcB, VECTOR2I& aPtA, VECTOR2I& aPtB )
468{
469 int64_t distSq;
470 return aArcA.NearestPoints( aArcB, aPtA, aPtB, distSq );
471}
472
473static bool NearestPoints( const SHAPE_ARC& aArc, const SHAPE_LINE_CHAIN_BASE& aChain, VECTOR2I& aPtA, VECTOR2I& aPtB )
474{
475 const SHAPE_LINE_CHAIN* chain = dynamic_cast<const SHAPE_LINE_CHAIN*>( &aChain );
476 int64_t distSq;
477 int64_t minDistSq = std::numeric_limits<int64_t>::max();
478 VECTOR2I tmp_ptA, tmp_ptB;
479
480 for( size_t i = 0; i < aChain.GetSegmentCount(); i++ )
481 {
482 if( chain && chain->IsArcSegment( i ) )
483 continue;
484
485 if( aArc.NearestPoints( aChain.GetSegment( i ), tmp_ptA, tmp_ptB, distSq ) )
486 {
487 if( distSq < minDistSq )
488 {
489 aPtA = tmp_ptA;
490 aPtB = tmp_ptB;
491 minDistSq = distSq;
492 }
493 }
494 }
495
496 // Also handle arcs if this is a SHAPE_LINE_CHAIN
497 if( chain )
498 {
499 for( size_t j = 0; j < chain->ArcCount(); j++ )
500 {
501 const SHAPE_ARC& arc = chain->Arc( j );
502
503 if( aArc.NearestPoints( arc, tmp_ptA, tmp_ptB, distSq ) )
504 {
505 if( distSq < minDistSq )
506 {
507 minDistSq = distSq;
508 aPtA = tmp_ptA;
509 aPtB = tmp_ptB;
510 }
511 }
512 }
513 }
514
515 return true;
516}
517
518
522static bool NearestPoints( const SHAPE_SEGMENT& aSeg, const SHAPE_CIRCLE& aCircle, VECTOR2I& aPtA, VECTOR2I& aPtB )
523{
524 if( NearestPoints( aCircle, aSeg.GetSeg(), aPtB, aPtA ) )
525 {
526 // Adjust point A by half the segment width towards point B
527 VECTOR2I dir = ( aPtB - aPtA ).Resize( aSeg.GetWidth() / 2 );
528 aPtA += dir;
529 return true;
530 }
531
532 return false;
533}
534
535static bool NearestPoints( const SHAPE_SEGMENT& aSeg, const SHAPE_RECT& aRect, VECTOR2I& aPtA, VECTOR2I& aPtB )
536{
537 if( NearestPoints( aRect, aSeg.GetSeg(), aPtB, aPtA ) )
538 {
539 // Adjust point A by half the segment width towards point B
540 VECTOR2I dir = ( aPtB - aPtA ).Resize( aSeg.GetWidth() / 2 );
541 aPtA += dir;
542 return true;
543 }
544
545 return false;
546}
547
548static bool NearestPoints( const SHAPE_SEGMENT& aSegA, const SHAPE_SEGMENT& aSegB, VECTOR2I& aPtA, VECTOR2I& aPtB )
549{
550 // Find nearest points between two segments
551 if( NearestPoints( aSegA.GetSeg(), aSegB.GetSeg(), aPtA, aPtB ) )
552 {
553 // Adjust point A by half the segment width towards point B
554 VECTOR2I dir = ( aPtB - aPtA ).Resize( aSegA.GetWidth() / 2 );
555 aPtA += dir;
556 // Adjust point B by half the segment width towards point A
557 dir = ( aPtA - aPtB ).Resize( aSegB.GetWidth() / 2 );
558 aPtB += dir;
559 return true;
560 }
561
562 return false;
563}
564
565static bool NearestPoints( const SHAPE_SEGMENT& aSeg, const SHAPE_LINE_CHAIN_BASE& aChain, VECTOR2I& aPtA,
566 VECTOR2I& aPtB )
567{
568 if( NearestPoints( aSeg.GetSeg(), aChain, aPtA, aPtB ) )
569 {
570 // Adjust point A by half the segment width towards point B
571 VECTOR2I dir = ( aPtB - aPtA ).Resize( aSeg.GetWidth() / 2 );
572 aPtA += dir;
573 return true;
574 }
575
576 return false;
577}
578
579
583template<class T_a, class T_b>
584inline bool NearestPointsCase( const SHAPE* aA, const SHAPE* aB, VECTOR2I& aPtA, VECTOR2I& aPtB )
585{
586 return NearestPoints( *static_cast<const T_a*>( aA ), *static_cast<const T_b*>( aB ),
587 aPtA, aPtB );
588}
589
590template<class T_a, class T_b>
591inline bool NearestPointsCaseReversed( const SHAPE* aA, const SHAPE* aB, VECTOR2I& aPtA, VECTOR2I& aPtB )
592{
593 return NearestPoints( *static_cast<const T_b*>( aB ), *static_cast<const T_a*>( aA ),
594 aPtB, aPtA );
595}
596
597
601static bool nearestPointsSingleShapes( const SHAPE* aA, const SHAPE* aB, VECTOR2I& aPtA, VECTOR2I& aPtB )
602{
603 switch( aA->Type() )
604 {
605 case SH_RECT:
606 switch( aB->Type() )
607 {
608 case SH_RECT:
609 return NearestPointsCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aPtA, aPtB );
610 case SH_CIRCLE:
611 return NearestPointsCaseReversed<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aPtA, aPtB );
612 case SH_LINE_CHAIN:
613 return NearestPointsCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aPtA, aPtB );
614 case SH_SEGMENT:
615 return NearestPointsCaseReversed<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aPtA, aPtB );
616 case SH_SIMPLE:
618 return NearestPointsCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aA, aB, aPtA, aPtB );
619 case SH_ARC:
620 return NearestPointsCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aPtA, aPtB );
621 default:
622 break;
623 }
624 break;
625
626 case SH_CIRCLE:
627 switch( aB->Type() )
628 {
629 case SH_RECT:
630 return NearestPointsCase<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aPtA, aPtB );
631 case SH_CIRCLE:
632 return NearestPointsCase<SHAPE_CIRCLE, SHAPE_CIRCLE>( aA, aB, aPtA, aPtB );
633 case SH_LINE_CHAIN:
634 return NearestPointsCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aA, aB, aPtA, aPtB );
635 case SH_SEGMENT:
637 case SH_SIMPLE:
640 case SH_ARC:
641 return NearestPointsCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aPtA, aPtB );
642 default:
643 break;
644 }
645 break;
646
647 case SH_LINE_CHAIN:
648 switch( aB->Type() )
649 {
650 case SH_RECT:
652 case SH_CIRCLE:
654 case SH_LINE_CHAIN:
656 case SH_SEGMENT:
658 case SH_SIMPLE:
661 case SH_ARC:
662 // Special handling for arc
663 {
664 const SHAPE_LINE_CHAIN* chain = static_cast<const SHAPE_LINE_CHAIN*>( aA );
665 const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( aB );
666 int64_t minDistSq = std::numeric_limits<int64_t>::max();
667
668 // Check segments
669 for( int i = 0; i < chain->SegmentCount(); i++ )
670 {
671 VECTOR2I ptA, ptB;
672 int64_t distSq;
673
674 // Reverse the output points to match the arc/segment_from_rect order
675 if( arc->NearestPoints( chain->CSegment( i ), ptB, ptA, distSq ) )
676 {
677 if( distSq < minDistSq )
678 {
679 minDistSq = distSq;
680 aPtA = ptA;
681 aPtB = ptB;
682 }
683 }
684 }
685
686 // Check arcs
687 for( size_t i = 0; i < chain->ArcCount(); i++ )
688 {
689 VECTOR2I ptA, ptB;
690 int64_t distSq;
691 if( chain->Arc( i ).NearestPoints( *arc, ptA, ptB, distSq ) )
692 {
693 if( distSq < minDistSq )
694 {
695 minDistSq = distSq;
696 aPtA = ptA;
697 aPtB = ptB;
698 }
699 }
700 }
701
702 return minDistSq < std::numeric_limits<int64_t>::max();
703 }
704 default:
705 break;
706 }
707 break;
708
709 case SH_SEGMENT:
710 switch( aB->Type() )
711 {
712 case SH_RECT:
713 return NearestPointsCase<SHAPE_SEGMENT, SHAPE_RECT>( aA, aB, aPtA, aPtB );
714 case SH_CIRCLE:
715 return NearestPointsCase<SHAPE_SEGMENT, SHAPE_CIRCLE>( aA, aB, aPtA, aPtB );
716 case SH_LINE_CHAIN:
717 return NearestPointsCase<SHAPE_SEGMENT, SHAPE_LINE_CHAIN>( aA, aB, aPtA, aPtB );
718 case SH_SEGMENT:
719 return NearestPointsCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aPtA, aPtB );
720 case SH_SIMPLE:
723 case SH_ARC:
724 return NearestPointsCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aPtA, aPtB );
725 default:
726 break;
727 }
728 break;
729
730 case SH_SIMPLE:
732 switch( aB->Type() )
733 {
734 case SH_RECT:
736 case SH_CIRCLE:
738 case SH_LINE_CHAIN:
740 case SH_SEGMENT:
742 case SH_SIMPLE:
745 case SH_ARC:
746 // Handle arc specially
747 {
748 const SHAPE_LINE_CHAIN_BASE* chain = static_cast<const SHAPE_LINE_CHAIN_BASE*>( aA );
749 const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( aB );
750 int64_t minDistSq = std::numeric_limits<int64_t>::max();
751
752 for( size_t i = 0; i < chain->GetSegmentCount(); i++ )
753 {
754 VECTOR2I ptA, ptB;
755 int64_t distSq;
756
757 // Reverse the output points to match the arc/segment_from_line_chain order
758 if( arc->NearestPoints( chain->GetSegment( i ), ptB, ptA, distSq ) )
759 {
760 if( distSq < minDistSq )
761 {
762 minDistSq = distSq;
763 aPtA = ptA;
764 aPtB = ptB;
765 }
766 }
767 }
768
769 return minDistSq < std::numeric_limits<int64_t>::max();
770 }
771 default:
772 break;
773 }
774 break;
775
776 case SH_ARC:
777 switch( aB->Type() )
778 {
779 case SH_RECT:
780 return NearestPointsCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aPtA, aPtB );
781 case SH_CIRCLE:
782 return NearestPointsCase<SHAPE_ARC, SHAPE_CIRCLE>( aA, aB, aPtA, aPtB );
783 case SH_LINE_CHAIN:
784 return NearestPointsCase<SHAPE_ARC, SHAPE_LINE_CHAIN>( aA, aB, aPtA, aPtB );
785 case SH_SEGMENT:
786 return NearestPointsCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aPtA, aPtB );
787 case SH_SIMPLE:
789 return NearestPointsCase<SHAPE_ARC, SHAPE_LINE_CHAIN_BASE>( aA, aB, aPtA, aPtB );
790 case SH_ARC:
791 return NearestPointsCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aPtA, aPtB );
792 default:
793 break;
794 }
795 break;
796
797 case SH_POLY_SET:
798 // For polygon sets, find nearest points to all edges
799 {
800 const SHAPE_POLY_SET* polySet = static_cast<const SHAPE_POLY_SET*>( aA );
801 int64_t minDistSq = std::numeric_limits<int64_t>::max();
802
803 for( auto it = polySet->CIterateSegmentsWithHoles(); it; ++it )
804 {
805 SHAPE_SEGMENT seg( *it );
806 VECTOR2I ptA, ptB;
807
808 if( nearestPointsSingleShapes( &seg, aB, ptA, ptB ) )
809 {
810 int64_t distSq = ( ptB - ptA ).SquaredEuclideanNorm();
811 if( distSq < minDistSq )
812 {
813 minDistSq = distSq;
814 aPtA = ptA;
815 aPtB = ptB;
816 }
817 }
818 }
819
820 return minDistSq < std::numeric_limits<int64_t>::max();
821 }
822 break;
823
824 default:
825 break;
826 }
827
828 // Handle SHAPE_POLY_SET as second shape
829 if( aB->Type() == SH_POLY_SET )
830 {
831 const SHAPE_POLY_SET* polySet = static_cast<const SHAPE_POLY_SET*>( aB );
832 int64_t minDistSq = std::numeric_limits<int64_t>::max();
833
834 for( auto it = polySet->CIterateSegments(); it; ++it )
835 {
836 SHAPE_SEGMENT seg( *it );
837 VECTOR2I ptA, ptB;
838
839 if( nearestPointsSingleShapes( aA, &seg, ptA, ptB ) )
840 {
841 int64_t distSq = ( ptB - ptA ).SquaredEuclideanNorm();
842 if( distSq < minDistSq )
843 {
844 minDistSq = distSq;
845 aPtA = ptA;
846 aPtB = ptB;
847 }
848 }
849 }
850
851 return minDistSq < std::numeric_limits<int64_t>::max();
852 }
853
854 return false;
855}
856
857
861static bool nearestPoints( const SHAPE* aA, const SHAPE* aB, VECTOR2I& aPtA, VECTOR2I& aPtB )
862{
863 int64_t minDistSq = std::numeric_limits<int64_t>::max();
864 bool found = false;
865
866 auto checkNearestPoints =
867 [&]( const SHAPE* shapeA, const SHAPE* shapeB ) -> bool
868 {
869 VECTOR2I ptA, ptB;
870
871 if( nearestPointsSingleShapes( shapeA, shapeB, ptA, ptB ) )
872 {
873 int64_t distSq = ( ptB - ptA ).SquaredEuclideanNorm();
874
875 if( distSq < minDistSq )
876 {
877 minDistSq = distSq;
878 aPtA = ptA;
879 aPtB = ptB;
880 found = true;
881 }
882
883 return true;
884 }
885
886 return false;
887 };
888
889 if( aA->Type() == SH_COMPOUND && aB->Type() == SH_COMPOUND )
890 {
891 const SHAPE_COMPOUND* cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
892 const SHAPE_COMPOUND* cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
893
894 for( const SHAPE* elemA : cmpA->Shapes() )
895 {
896 for( const SHAPE* elemB : cmpB->Shapes() )
897 {
898 checkNearestPoints( elemA, elemB );
899 }
900 }
901 }
902 else if( aA->Type() == SH_COMPOUND )
903 {
904 const SHAPE_COMPOUND* cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
905
906 for( const SHAPE* elemA : cmpA->Shapes() )
907 {
908 checkNearestPoints( elemA, aB );
909 }
910 }
911 else if( aB->Type() == SH_COMPOUND )
912 {
913 const SHAPE_COMPOUND* cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
914
915 for( const SHAPE* elemB : cmpB->Shapes() )
916 {
917 checkNearestPoints( aA, elemB );
918 }
919 }
920 else
921 {
922 return nearestPointsSingleShapes( aA, aB, aPtA, aPtB );
923 }
924
925 return found;
926}
927
928
938bool SHAPE::NearestPoints( const SHAPE* aOther, VECTOR2I& aPtThis, VECTOR2I& aPtOther ) const
939{
940 return nearestPoints( this, aOther, aPtThis, aPtOther );
941}
Definition seg.h:42
VECTOR2I A
Definition seg.h:49
VECTOR2I B
Definition seg.h:50
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition seg.cpp:604
bool NearestPoints(const SHAPE_ARC &aArc, VECTOR2I &aPtA, VECTOR2I &aPtB, int64_t &aDistSq) const
Compute closest points between this arc and aArc.
SHAPE_TYPE Type() const
Return the type of the shape.
Definition shape.h:98
int GetRadius() const
const VECTOR2I GetCenter() const
const std::vector< SHAPE * > & Shapes() const
virtual size_t GetSegmentCount() 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
size_t ArcCount() const
bool IsArcSegment(size_t aSegment) const
Represent a set of closed polygons.
CONST_SEGMENT_ITERATOR CIterateSegmentsWithHoles() const
Return an iterator object, for the aOutline-th outline in the set (with holes).
CONST_SEGMENT_ITERATOR CIterateSegments(int aFirst, int aLast, bool aIterateHoles=false) const
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
const SHAPE_LINE_CHAIN Outline() const
const VECTOR2I & GetPosition() const
Definition shape_rect.h:169
const VECTOR2I GetSize() const
Definition shape_rect.h:177
const SEG & GetSeg() const
int GetWidth() const override
An abstract shape on 2D plane.
Definition shape.h:126
SHAPE(SHAPE_TYPE aType)
Create an empty shape of type aType.
Definition shape.h:136
bool NearestPoints(const SHAPE *aOther, VECTOR2I &aPtThis, VECTOR2I &aPtOther) const
Return the two points that mark the closest distance between this shape and aOther.
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition vector2d.h:73
@ 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_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
VECTOR2I::extended_type ecoord
static bool NearestPoints(const SHAPE_LINE_CHAIN_BASE &aA, const SHAPE_LINE_CHAIN_BASE &aB, VECTOR2I &aPtA, VECTOR2I &aPtB)
Find the nearest points between two line chains.
bool NearestPointsCase(const SHAPE *aA, const SHAPE *aB, VECTOR2I &aPtA, VECTOR2I &aPtB)
Template functions to handle shape conversions and reversals.
static bool nearestPointsSingleShapes(const SHAPE *aA, const SHAPE *aB, VECTOR2I &aPtA, VECTOR2I &aPtB)
Main dispatcher for finding nearest points between arbitrary shapes.
static bool nearestPoints(const SHAPE *aA, const SHAPE *aB, VECTOR2I &aPtA, VECTOR2I &aPtB)
Handle compound shapes by finding nearest points between all sub-shape pairs.
bool NearestPointsCaseReversed(const SHAPE *aA, const SHAPE *aB, VECTOR2I &aPtA, VECTOR2I &aPtB)
const SHAPE_LINE_CHAIN chain
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695