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