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