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