KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_utils.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2014 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "pns_utils.h"
23#include "pns_line.h"
24#include "pns_via.h"
25#include "pns_router.h"
26#include "pns_debug_decorator.h"
27#include "pns_arc.h"
28#include "pns_node.h"
29
30#include <core/kicad_algo.h>
31#include <core/minoptmax.h>
32
33#include <geometry/shape_arc.h>
38#include <math/box2.h>
39
40#include <cmath>
41
42namespace PNS {
43
44const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize,
45 int aClearance, int aChamfer )
46{
48
49 s.SetClosed( true );
50
51 s.Append( aP0.x - aClearance, aP0.y - aClearance + aChamfer );
52
53 if( aChamfer )
54 s.Append( aP0.x - aClearance + aChamfer, aP0.y - aClearance );
55
56 s.Append( aP0.x + aSize.x + aClearance - aChamfer, aP0.y - aClearance );
57
58 if( aChamfer )
59 s.Append( aP0.x + aSize.x + aClearance, aP0.y - aClearance + aChamfer );
60
61 s.Append( aP0.x + aSize.x + aClearance, aP0.y + aSize.y + aClearance - aChamfer );
62
63 if( aChamfer )
64 s.Append( aP0.x + aSize.x + aClearance - aChamfer, aP0.y + aSize.y + aClearance );
65
66 s.Append( aP0.x - aClearance + aChamfer, aP0.y + aSize.y + aClearance );
67
68 if( aChamfer )
69 s.Append( aP0.x - aClearance, aP0.y + aSize.y + aClearance - aChamfer );
70
71 return s;
72}
73
74
75const SHAPE_LINE_CHAIN ArcHull( const SHAPE_ARC& aArc, int aClearance, int aWalkaroundThickness )
76{
77 int cl = aClearance + ( aWalkaroundThickness + 1 ) / 2;
78
79 // If we can't route through the arc, we might as well treat it as a circle
80 if( aArc.GetCentralAngle().AsDegrees() > 180.0 && aArc.GetChord().Length() < cl )
81 {
82 int r = aArc.GetRadius();
83 return OctagonalHull( aArc.GetCenter() - VECTOR2I( r, r ),
84 VECTOR2I( 2 * r, 2 * r ),
85 cl,
86 2.0 * ( 1.0 - M_SQRT1_2 ) * ( r + cl ) );
87 }
88
89 int d = aArc.GetWidth() / 2 + cl + SHAPE_ARC::DefaultAccuracyForPCB();
90 int x = (int) ( 2.0 / ( 1.0 + M_SQRT2 ) * d ) / 2;
91
92 auto line = aArc.ConvertToPolyline( ARC_LOW_DEF );
93
95 s.SetClosed( true );
96 std::vector<VECTOR2I> reverse_line;
97
98 auto seg = line.Segment( 0 );
99 VECTOR2I dir = seg.B - seg.A;
100 VECTOR2I p0 = -dir.Perpendicular().Resize( d );
101 VECTOR2I ds = -dir.Perpendicular().Resize( x );
102 VECTOR2I pd = dir.Resize( x );
103 VECTOR2I dp = dir.Resize( d );
104
105 // Append the first curve
106 s.Append( seg.A + p0 - pd );
107 s.Append( seg.A - dp + ds );
108 s.Append( seg.A - dp - ds );
109 s.Append( seg.A - p0 - pd );
110
111 for( int i = 1; i < line.SegmentCount(); i++ )
112 {
113 // calculate a vertex normal (average of segment normals)
114 auto pp =
115 ( line.CSegment( i - 1 ).B - line.CSegment( i - 1 ).A ).Perpendicular().Resize( d );
116 auto pp2 = ( line.CSegment( i ).B - line.CSegment( i ).A ).Perpendicular().Resize( d );
117
118 auto sa_out = line.CSegment( i - 1 ), sa_in = line.CSegment( i - 1 );
119 auto sb_out = line.CSegment( i ), sb_in = line.CSegment( i );
120
121 sa_out.A += pp;
122 sa_out.B += pp;
123 sb_out.A += pp2;
124 sb_out.B += pp2;
125
126 sa_in.A -= pp;
127 sa_in.B -= pp;
128 sb_in.A -= pp2;
129 sb_in.B -= pp2;
130
131 auto ip_out = sa_out.IntersectLines( sb_out );
132 auto ip_in = sa_in.IntersectLines( sb_in );
133
134 seg = line.CSegment( i );
135 s.Append( *ip_out );
136 reverse_line.push_back( *ip_in );
137 }
138
139 seg = line.CSegment( -1 );
140 dir = seg.B - seg.A;
141 p0 = -dir.Perpendicular().Resize( d );
142 ds = -dir.Perpendicular().Resize( x );
143 pd = dir.Resize( x );
144 dp = dir.Resize( d );
145 s.Append( seg.B - p0 + pd );
146 s.Append( seg.B + dp - ds );
147 s.Append( seg.B + dp + ds );
148 s.Append( seg.B + p0 + pd );
149
150 for( int i = reverse_line.size() - 1; i >= 0; i-- )
151 s.Append( reverse_line[i] );
152
153 // make sure the hull outline is always clockwise
154 if( s.CSegment( 0 ).Side( line.Segment( 0 ).A ) < 0 )
155 return s.Reverse();
156 else
157 return s;
158}
159
160
161static bool IsSegment45Degree( const SEG& aS )
162{
163 VECTOR2I dir( aS.B - aS.A );
164
165 if( std::abs( dir.x ) <= 1 )
166 return true;
167
168 if( std::abs( dir.y ) <= 1 )
169 return true;
170
171 int delta = std::abs(dir.x) - std::abs(dir.y);
172
173 if( delta >= -1 && delta <= 1)
174 return true;
175
176 return false;
177}
178
179
180template <typename T> int sgn(T val) {
181 return (T(0) < val) - (val < T(0));
182}
183
184
185const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance,
186 int aWalkaroundThickness )
187{
188 const int kinkThreshold = aClearance / 10;
189
190 int cl = aClearance + aWalkaroundThickness / 2;
191 double d = (double)aSeg.GetWidth() / 2.0 + cl;
192 double x = 2.0 / ( 1.0 + M_SQRT2 ) * d;
193 int dr = KiROUND( d );
194 int xr2 = KiROUND( x / 2.0 );
195
196 const VECTOR2I a = aSeg.GetSeg().A;
197 VECTOR2I b = aSeg.GetSeg().B;
198 int len = aSeg.GetSeg().Length();
199 int w = b.x - a.x;
200 int h = b.y - a.y;
201
202 /*
203 auto dbg = ROUTER::GetInstance()->GetInterface()->GetDebugDecorator();
204
205 if( len < kinkThreshold )
206 {
207 PNS_DBG( dbg, AddShape, &aSeg, CYAN, 10000, wxString::Format( "kinky-seg 45 %d l %d dx %d dy %d", !!IsSegment45Degree( aSeg.GetSeg() ), len, w, h ) );
208 }
209 */
210
211 if( a != b )
212 {
213 if ( !IsSegment45Degree( aSeg.GetSeg() ) )
214 {
215 if ( len <= kinkThreshold && len > 0 )
216 {
217 int ll = std::max( std::abs( w ), std::abs( h ) );
218
219 b = a + VECTOR2I( sgn( w ) * ll, sgn( h ) * ll );
220 }
221 }
222 else
223 {
224 if( len <= kinkThreshold )
225 {
226 int delta45 = std::abs( std::abs(w) - std::abs(h) );
227 if( std::abs(w) <= 1 ) // almost vertical
228 {
229 w = 0;
230 cl ++;
231 }
232 else if ( std::abs(h) <= 1 ) // almost horizontal
233 {
234 h = 0;
235 cl ++;
236 }
237 else if ( delta45 <= 2 ) // almost 45 degree
238 {
239 int newW = sgn( w ) * std::max( std::abs(w), std::abs( h ) );
240 int newH = sgn( h ) * std::max( std::abs(w), std::abs( h ) );
241 w = newW;
242 h = newH;
243 cl += 2;
244 //PNS_DBG( dbg, AddShape, &aSeg, CYAN, 10000, wxString::Format( "almostkinky45 45 %d l %d dx %d dy %d", !!IsSegment45Degree( aSeg.GetSeg() ), len, w, h ) );
245
246 }
247
248 b.x = a.x + w;
249 b.y = a.y + h;
250 }
251 }
252 }
253
254 if( a == b )
255 {
256 int xx2 = KiROUND( 2.0 * ( 1.0 - M_SQRT1_2 ) * d );
257
258 auto ohull = OctagonalHull( a - VECTOR2I( aSeg.GetWidth() / 2, aSeg.GetWidth() / 2 ),
259 VECTOR2I( aSeg.GetWidth(), aSeg.GetWidth() ),
260 cl,
261 xx2 );
262
263 return ohull;
264 }
265
266 VECTOR2I dir = b - a;
267 VECTOR2I p0 = dir.Perpendicular().Resize( dr );
268 VECTOR2I ds = dir.Perpendicular().Resize( xr2 );
269 VECTOR2I pd = dir.Resize( xr2 );
270 VECTOR2I dp = dir.Resize( dr );
271
273
274 s.SetClosed( true );
275
276 s.Append( b + p0 + pd );
277 s.Append( b + dp + ds );
278 s.Append( b + dp - ds );
279 s.Append( b - p0 + pd );
280 s.Append( a - p0 - pd );
281 s.Append( a - dp - ds );
282 s.Append( a - dp + ds );
283 s.Append( a + p0 - pd );
284
285 // make sure the hull outline is always clockwise
286 if( s.CSegment( 0 ).Side( a ) < 0 )
287 return s.Reverse();
288 else
289 return s;
290}
291
292
293static void MoveDiagonal( SEG& aDiagonal, const SHAPE_LINE_CHAIN& aVertices, int aClearance )
294{
295 int dist;
296
297 aVertices.NearestPoint( aDiagonal, dist );
298 VECTOR2I moveBy = ( aDiagonal.A - aDiagonal.B ).Perpendicular().Resize( dist - aClearance );
299 aDiagonal.A += moveBy;
300 aDiagonal.B += moveBy;
301}
302
303
304const SHAPE_LINE_CHAIN ConvexHull( const SHAPE_SIMPLE& aConvex, int aClearance )
305{
306 // this defines the horizontal and vertical lines in the hull octagon
307 BOX2I box = aConvex.BBox( aClearance );
308 box.Normalize();
309
310 SEG topline = SEG( VECTOR2I( box.GetX(), box.GetY() + box.GetHeight() ),
311 VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() + box.GetHeight() ) );
312 SEG rightline = SEG( VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() + box.GetHeight() ),
313 VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() ) );
314 SEG bottomline = SEG( VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() ),
315 box.GetOrigin() );
316 SEG leftline = SEG( box.GetOrigin(), VECTOR2I( box.GetX(), box.GetY() + box.GetHeight() ) );
317
318 const SHAPE_LINE_CHAIN& vertices = aConvex.Vertices();
319
320 // top right diagonal
321 VECTOR2I corner = box.GetOrigin() + box.GetSize();
322 SEG toprightline = SEG( corner,
323 corner + VECTOR2I( box.GetHeight(), -box.GetHeight() ) );
324 MoveDiagonal( toprightline, vertices, aClearance );
325
326 // bottom right diagonal
327 corner = box.GetOrigin() + VECTOR2I( box.GetWidth(), 0 );
328 SEG bottomrightline = SEG( corner + VECTOR2I( box.GetHeight(), box.GetHeight() ),
329 corner );
330 MoveDiagonal( bottomrightline, vertices, aClearance );
331
332 // bottom left diagonal
333 corner = box.GetOrigin();
334 SEG bottomleftline = SEG( corner,
335 corner + VECTOR2I( -box.GetHeight(), box.GetHeight() ) );
336 MoveDiagonal( bottomleftline, vertices, aClearance );
337
338 // top left diagonal
339 corner = box.GetOrigin() + VECTOR2I( 0, box.GetHeight() );
340 SEG topleftline = SEG( corner + VECTOR2I( -box.GetHeight(), -box.GetHeight() ),
341 corner );
342 MoveDiagonal( topleftline, vertices, aClearance );
343
344 SHAPE_LINE_CHAIN octagon;
345 octagon.SetClosed( true );
346
347 octagon.Append( *leftline.IntersectLines( bottomleftline ) );
348 octagon.Append( *bottomline.IntersectLines( bottomleftline ) );
349 octagon.Append( *bottomline.IntersectLines( bottomrightline ) );
350 octagon.Append( *rightline.IntersectLines( bottomrightline ) );
351 octagon.Append( *rightline.IntersectLines( toprightline ) );
352 octagon.Append( *topline.IntersectLines( toprightline ) );
353 octagon.Append( *topline.IntersectLines( topleftline ) );
354 octagon.Append( *leftline.IntersectLines( topleftline ) );
355
356 return octagon;
357}
358
359
361{
362 SHAPE_RECT r;
363
364 VECTOR2I delta( aSeg.GetWidth() / 2, aSeg.GetWidth() / 2 );
365 VECTOR2I p0( aSeg.GetSeg().A - delta );
366 VECTOR2I p1( aSeg.GetSeg().B + delta );
367
368 return SHAPE_RECT( std::min( p0.x, p1.x ), std::min( p0.y, p1.y ),
369 std::abs( p1.x - p0.x ), std::abs( p1.y - p0.y ) );
370}
371
372
373OPT_BOX2I ChangedArea( const ITEM* aItemA, const ITEM* aItemB )
374{
375 if( aItemA->OfKind( ITEM::VIA_T ) && aItemB->OfKind( ITEM::VIA_T ) )
376 {
377 const VIA* va = static_cast<const VIA*>( aItemA );
378 const VIA* vb = static_cast<const VIA*>( aItemB );
379
380 return va->ChangedArea( vb );
381 }
382 else if( aItemA->OfKind( ITEM::LINE_T ) && aItemB->OfKind( ITEM::LINE_T ) )
383 {
384 const LINE* la = static_cast<const LINE*> ( aItemA );
385 const LINE* lb = static_cast<const LINE*> ( aItemB );
386
387 return la->ChangedArea( lb );
388 }
389
390 return OPT_BOX2I();
391}
392
393OPT_BOX2I ChangedArea( const LINE& aLineA, const LINE& aLineB )
394{
395 return aLineA.ChangedArea( &aLineB );
396}
397
398
400 std::vector<SHAPE_LINE_CHAIN::INTERSECTION>& ips )
401{
402 std::vector<SHAPE_LINE_CHAIN::INTERSECTION> ips_raw;
403
404 if( line.PointCount() < 2 )
405 return;
406
407 hull.Intersect( line, ips_raw );
408
409 for( SHAPE_LINE_CHAIN::INTERSECTION& p : ips_raw )
410 {
412
413 SEG d1[2];
414 VECTOR2I d2[2];
415 int d1_idx = 0, d2_idx = 0;
416
417 ipp = p;
418 ipp.valid = false;
419
420 if( !p.is_corner_our && !p.is_corner_their )
421 {
422 ipp.valid = true;
423 ips.push_back( ipp );
424 continue;
425 }
426
427 if( p.index_our >= hull.SegmentCount() )
428 p.index_our -= hull.SegmentCount();
429
430 if( p.is_corner_our )
431 {
432 d1[0] = hull.CSegment( p.index_our );
433 d1[1] = hull.CSegment( p.index_our - 1 );
434 d1_idx = 2;
435 }
436 else
437 {
438 d1[0] = hull.CSegment( p.index_our );
439 d1_idx = 1;
440 }
441
442 if( p.is_corner_their )
443 {
444 if( p.index_their > 0 )
445 {
446 d2[d2_idx++] = line.CSegment( p.index_their - 1 ).A;
447 }
448 if( p.index_their < line.PointCount() - 1 )
449 {
450 d2[d2_idx++] = line.CSegment( p.index_their ).B;
451 }
452 }
453 else
454 {
455 d2[d2_idx++] = line.CSegment( p.index_their ).A;
456 d2[d2_idx++] = line.CSegment( p.index_their ).B;
457 }
458
459 for( int i = 0; i < d1_idx; i++ )
460 {
461 for( int j = 0; j < d2_idx; j++ )
462 {
463 if( d1[i].Side( d2[j] ) > 0 )
464 {
465 ipp.valid = true;
466 }
467 }
468 }
469
470#ifdef TOM_EXTRA_DEBUG
471 printf("p %d %d hi %d their %d co %d ct %d ipv %d\n", p.p.x, p.p.y, p.index_our, p.index_their, p.is_corner_our?1:0, p.is_corner_their?1:0, ipp.valid ?1:0);
472 printf("d1 %d d2 %d\n", d1_idx, d2_idx );
473#endif
474 if( ipp.valid )
475 {
476 ips.push_back( ipp );
477 }
478 }
479}
480
481
482const SHAPE_LINE_CHAIN BuildHullForPrimitiveShape( const SHAPE* aShape, int aClearance,
483 int aWalkaroundThickness )
484{
485 int cl = aClearance + ( aWalkaroundThickness + 1 )/ 2;
486
487 switch( aShape->Type() )
488 {
489 case SH_RECT:
490 {
491 const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( aShape );
492 return OctagonalHull( rect->GetPosition(),
493 rect->GetSize(),
494 cl,
495 0 );
496 }
497
498 case SH_CIRCLE:
499 {
500 const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( aShape );
501 int r = circle->GetRadius();
502 return OctagonalHull( circle->GetCenter() - VECTOR2I( r, r ),
503 VECTOR2I( 2 * r, 2 * r ),
504 cl,
505 2.0 * ( 1.0 - M_SQRT1_2 ) * ( r + cl ) );
506 }
507
508 case SH_SEGMENT:
509 {
510 const SHAPE_SEGMENT* seg = static_cast<const SHAPE_SEGMENT*>( aShape );
511 return SegmentHull( *seg, aClearance, aWalkaroundThickness );
512 }
513
514 case SH_ARC:
515 {
516 const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( aShape );
517 return ArcHull( *arc, aClearance, aWalkaroundThickness );
518 }
519
520 case SH_SIMPLE:
521 {
522 const SHAPE_SIMPLE* convex = static_cast<const SHAPE_SIMPLE*>( aShape );
523
524 return ConvexHull( *convex, cl );
525 }
526
527 case SH_ELLIPSE:
528 {
529 const SHAPE_ELLIPSE* ellipse = static_cast<const SHAPE_ELLIPSE*>( aShape );
530 const BOX2I bbox = ellipse->BBox();
531
532 return OctagonalHull( bbox.GetPosition(), bbox.GetSize(), cl, 0 );
533 }
534
535 default:
536 {
537 wxFAIL_MSG( wxString::Format( wxT( "Unsupported hull shape: %d (%s)." ),
538 aShape->Type(),
539 SHAPE_TYPE_asString( aShape->Type() ) ) );
540 break;
541 }
542 }
543
544 return SHAPE_LINE_CHAIN();
545}
546
547
548void NodeStats( DEBUG_DECORATOR* dbg, wxString label, PNS::NODE *node )
549{
550 NODE::ITEM_VECTOR added, removed;
551 node->GetUpdatedItems( removed, added );
552
553 PNS_DBG( dbg, BeginGroup, wxString::Format( "node:%s this=%p depth=%d added=%d removed=%d",
554 label, node, node->Depth(), (int) added.size(), (int) removed.size() ),
555 0 );
556
557 for( ITEM* item : added )
558 PNS_DBG( dbg, AddItem, item, BLUE, 10000, wxT( "added-item" ) );
559
560 for( ITEM* item : removed )
561 PNS_DBG( dbg, AddItem, item, RED, 10000, wxT( "removed-item" ) );
562
563 PNS_DBGN( dbg, EndGroup );
564}
565
566
567bool SplitAdjacentSegments( NODE* aNode, ITEM* aSeg, const VECTOR2I& aP )
568{
569 if( !aSeg )
570 return false;
571
572 if( !aSeg->OfKind( ITEM::SEGMENT_T ) )
573 return false;
574
575 const JOINT* jt = aNode->FindJoint( aP, aSeg );
576
577 if( jt && jt->LinkCount() >= 1 )
578 {
579 return false;
580 }
581
582 // Shove may have already replaced aSeg in this branch, so splitting it would resurrect it
583 const JOINT* owner = aNode->FindJoint( aSeg->Anchor( 0 ), aSeg );
584
585 if( !owner || !alg::contains( owner->LinkList(), aSeg ) )
586 return false;
587
588 SEGMENT* s_old = static_cast<SEGMENT*>( aSeg );
589
590 if( s_old->Seg().Distance( aP ) > 100 )
591 return false;
592
593 aNode->Remove( s_old );
594
595 if( s_old->Seg().B != aP )
596 {
597 std::unique_ptr<SEGMENT> s_new ( Clone( *s_old ) );
598 s_new->SetEnds( s_old->Seg().A, aP );
599 s_new->Unmark();
600 aNode->Add( std::move( s_new ), true );
601 }
602
603 if( s_old->Seg().A != aP )
604 {
605 std::unique_ptr<SEGMENT> s_new ( Clone( *s_old ) );
606 s_new->SetEnds( aP, s_old->Seg().B );
607 s_new->Unmark();
608 aNode->Add( std::move( s_new ), true );
609 }
610
611 return true;
612}
613
614
615bool SplitAdjacentArcs( NODE* aNode, ITEM* aArc, const VECTOR2I& aP )
616{
617 if( !aArc )
618 return false;
619
620 if( !aArc->OfKind( ITEM::ARC_T ) )
621 return false;
622
623 const JOINT* jt = aNode->FindJoint( aP, aArc );
624
625 if( jt && jt->LinkCount() >= 1 )
626 return false;
627
628 const JOINT* owner = aNode->FindJoint( aArc->Anchor( 0 ), aArc );
629
630 if( !owner || !alg::contains( owner->LinkList(), aArc ) )
631 return false;
632
633 ARC* a_old = static_cast<ARC*>( aArc );
634 const SHAPE_ARC& o_arc = a_old->Arc();
635
636 std::unique_ptr<ARC> a_new[2] = { Clone( *a_old ), Clone( *a_old ) };
637
638 a_new[0]->Arc().ConstructFromStartEndCenter( o_arc.GetP0(), aP, o_arc.GetCenter(),
639 o_arc.IsClockwise(), o_arc.GetWidth() );
640
641 a_new[1]->Arc().ConstructFromStartEndCenter( aP, o_arc.GetP1(), o_arc.GetCenter(),
642 o_arc.IsClockwise(), o_arc.GetWidth() );
643
644 aNode->Remove( a_old );
645 aNode->Add( std::move( a_new[0] ), true );
646 aNode->Add( std::move( a_new[1] ), true );
647
648 return true;
649}
650
651const wxString Format( const MINOPTMAX<int> x )
652{
653 wxString ret;
654
655 ret = wxT( "min:" );
656 if( x.HasMin() )
657 ret.Append( wxString::Format( wxT( "%d" ), x.Min() ) );
658 else
659 ret.Append( wxT( "none" ) );
660
661 ret.Append( wxT( " max:" ) );
662 if( x.HasMax() )
663 ret.Append( wxString::Format( wxT( "%d" ), x.Max() ) );
664 else
665 ret.Append( wxT( "none" ) );
666
667 ret.Append( wxT( " opt:" ) );
668 if( x.HasOpt() )
669 ret.Append( wxString::Format( wxT( "%d" ), x.Opt() ) );
670 else
671 ret.Append( wxT( "none" ) );
672
673 return ret;
674}
675
676
677const SEG LongestCoveringSegment( const SEG& a, const SEG& b )
678{
679 const SEG::ecoord dists[4] =
680 {
681 (a.A - b.A).SquaredEuclideanNorm(),
682 (a.A - b.B).SquaredEuclideanNorm(),
683 (a.B - b.A).SquaredEuclideanNorm(),
684 (a.B - b.B).SquaredEuclideanNorm()
685 };
686
687 SEG::ecoord maxDist = std::numeric_limits<SEG::ecoord>::min();
688 int farthest = -1;
689
690 for( int i = 0; i < 4; i++ )
691 {
692 if ( dists[i] > maxDist )
693 {
694 maxDist = dists[i];
695 farthest = i;
696 }
697 }
698
699 switch(farthest)
700 {
701 case 0: return SEG( a.A, b.A );
702 case 1: return SEG( a.A, b.B );
703 case 2: return SEG( a.B, b.A );
704 case 3: return SEG( a.B, b.B );
705 default: wxASSERT_MSG( false, wxT("failed to find farthest points?")); break;
706 }
707 return SEG();
708}
709
710
711}
constexpr int ARC_LOW_DEF
Definition base_units.h:143
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
constexpr const Vec & GetPosition() const
Definition box2.h:208
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr coord_type GetY() const
Definition box2.h:205
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr coord_type GetX() const
Definition box2.h:204
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr const SizeVec & GetSize() const
Definition box2.h:203
double AsDegrees() const
Definition eda_angle.h:115
T Min() const
Definition minoptmax.h:29
bool HasMax() const
Definition minoptmax.h:38
bool HasMin() const
Definition minoptmax.h:37
T Max() const
Definition minoptmax.h:30
T Opt() const
Definition minoptmax.h:31
bool HasOpt() const
Definition minoptmax.h:39
SHAPE_ARC & Arc()
Definition pns_arc.h:115
Base class for PNS router board items.
Definition pns_item.h:98
bool OfKind(int aKindMask) const
Definition pns_item.h:181
virtual VECTOR2I Anchor(int n) const
Definition pns_item.h:272
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
Definition pns_joint.h:43
const std::vector< ITEM * > & LinkList() const
Definition pns_joint.h:307
int LinkCount(int aMask=-1) const
Definition pns_joint.h:322
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
OPT_BOX2I ChangedArea(const LINE *aOther) const
Keep the router "world" - i.e.
Definition pns_node.h:244
std::vector< ITEM * > ITEM_VECTOR
Definition pns_node.h:255
void GetUpdatedItems(ITEM_VECTOR &aRemoved, ITEM_VECTOR &aAdded)
Return the list of items removed and added in this branch with respect to the root branch.
const JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, NET_HANDLE aNet) const
Search for a joint at a given position, layer and belonging to given net.
int Depth() const
Return the number of nodes in the inheritance chain (wrs to the root node).
Definition pns_node.h:305
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition pns_node.cpp:753
void Remove(ARC *aArc)
Remove an item from this branch.
Definition pns_node.cpp:997
const SEG & Seg() const
OPT_BOX2I ChangedArea(const VIA *aOther) const
Definition pns_via.cpp:307
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I::extended_type ecoord
Definition seg.h:40
VECTOR2I B
Definition seg.h:46
int Length() const
Return the length (this).
Definition seg.h:340
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition seg.h:217
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:668
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition seg.h:139
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
SEG GetChord() const
Definition shape_arc.h:247
bool IsClockwise() const
Definition shape_arc.h:323
int GetWidth() const override
Definition shape_arc.h:215
const SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError=DefaultAccuracyForPCB(), int *aActualError=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
static int DefaultAccuracyForPCB()
Definition shape_arc.h:283
double GetRadius() const
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
const VECTOR2I & GetCenter() const
SHAPE_TYPE Type() const
Return the type of the shape.
Definition shape.h:96
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int Intersect(const SEG &aSeg, std::vector< INTERSECTION > &aIp) const
Find all intersection points between our line chain and the segment aSeg.
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
const VECTOR2I & GetPosition() const
Definition shape_rect.h:164
const VECTOR2I GetSize() const
Definition shape_rect.h:172
const SEG & GetSeg() const
int GetWidth() const override
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
const SHAPE_LINE_CHAIN & Vertices() const
Return the list of vertices defining this simple polygon.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
An abstract shape on 2D plane.
Definition shape.h:124
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
Definition vector2d.h:335
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:406
@ BLUE
Definition color4d.h:52
@ RED
Definition color4d.h:55
Push and Shove diff pair dimensions (gap) settings dialog.
const wxString Format(const MINOPTMAX< int > x)
bool SplitAdjacentSegments(NODE *aNode, ITEM *aSeg, const VECTOR2I &aP)
Snaps the point aP to segment aSeg.
const SHAPE_LINE_CHAIN BuildHullForPrimitiveShape(const SHAPE *aShape, int aClearance, int aWalkaroundThickness)
const SHAPE_LINE_CHAIN OctagonalHull(const VECTOR2I &aP0, const VECTOR2I &aSize, int aClearance, int aChamfer)
Definition pns_utils.cpp:44
SHAPE_RECT ApproximateSegmentAsRect(const SHAPE_SEGMENT &aSeg)
bool SplitAdjacentArcs(NODE *aNode, ITEM *aArc, const VECTOR2I &aP)
Snaps the point aP to arc aArc.
const SHAPE_LINE_CHAIN ArcHull(const SHAPE_ARC &aArc, int aClearance, int aWalkaroundThickness)
Various utility functions.
Definition pns_utils.cpp:75
const SHAPE_LINE_CHAIN ConvexHull(const SHAPE_SIMPLE &aConvex, int aClearance)
Function ConvexHull()
void NodeStats(DEBUG_DECORATOR *dbg, wxString label, PNS::NODE *node)
const SHAPE_LINE_CHAIN SegmentHull(const SHAPE_SEGMENT &aSeg, int aClearance, int aWalkaroundThickness)
static bool IsSegment45Degree(const SEG &aS)
static void MoveDiagonal(SEG &aDiagonal, const SHAPE_LINE_CHAIN &aVertices, int aClearance)
void HullIntersection(const SHAPE_LINE_CHAIN &hull, const SHAPE_LINE_CHAIN &line, std::vector< SHAPE_LINE_CHAIN::INTERSECTION > &ips)
OPT_BOX2I ChangedArea(const ITEM *aItemA, const ITEM *aItemB)
int sgn(T val)
std::unique_ptr< typename std::remove_const< T >::type > Clone(const T &aItem)
Definition pns_item.h:348
const SEG LongestCoveringSegment(const SEG &a, const SEG &b)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
#define PNS_DBG(dbg, method,...)
#define PNS_DBGN(dbg, method)
@ 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_ELLIPSE
ellipse or elliptical arc
Definition shape.h:53
@ SH_SEGMENT
line segment
Definition shape.h:44
@ SH_ARC
circular arc
Definition shape.h:50
static wxString SHAPE_TYPE_asString(SHAPE_TYPE a)
Definition shape.h:56
Represent an intersection between two line segments.
bool valid
Auxiliary flag to avoid copying intersection info to intersection refining code, used by the refining...
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708