KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_diff_pair_placer.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2015 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 along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "pns_walkaround.h"
23#include "pns_shove.h"
24#include "pns_router.h"
26#include "pns_solid.h"
27#include "pns_topology.h"
28#include "pns_debug_decorator.h"
29#include "pns_arc.h"
30#include "pns_utils.h"
31
32namespace PNS {
33
35 PLACEMENT_ALGO( aRouter )
36{
38 m_chainedPlacement = false;
39 m_initialDiagonal = false;
40 m_startDiagonal = false;
41 m_fitOk = false;
42 m_netP = nullptr;
43 m_netN = nullptr;
44 m_iteration = 0;
45 m_world = nullptr;
46 m_shove = nullptr;
47 m_currentNode = nullptr;
48 m_lastNode = nullptr;
49 m_lastFixNode = nullptr;
50 m_placingVia = false;
51 m_viaDiameter = 0;
52 m_viaDrill = 0;
55 m_startsOnVia = false;
56 m_orthoMode = false;
57 m_snapOnTarget = false;
58 m_currentEndItem = nullptr;
59 m_currentTraceOk = false;
60 m_idle = true;
61 m_hasFixedAnything = false;
62}
63
66
67
69{
70 m_world = aWorld;
71}
72
73
75{
76 const PNS_LAYER_RANGE layers( m_sizes.GetLayerTop(), m_sizes.GetLayerBottom() );
77
78 VIA v( aP, layers, m_sizes.ViaDiameter(), m_sizes.ViaDrill(), aNet, m_sizes.ViaType() );
79
80 return v;
81}
82
83
84void DIFF_PAIR_PLACER::SetOrthoMode ( bool aOrthoMode )
85{
86 m_orthoMode = aOrthoMode;
87
88 if( !m_idle )
89 Move( m_currentEnd, nullptr );
90}
91
92
93bool DIFF_PAIR_PLACER::ToggleVia( bool aEnabled )
94{
95 m_placingVia = aEnabled;
96
97 if( !m_idle )
98 Move( m_currentEnd, nullptr );
99
100 return true;
101}
102
103
105{
106 if( !routeHead( aP ) )
107 return false;
108
109 bool collP = static_cast<bool>( m_currentNode->CheckColliding( &m_currentTrace.PLine() ) );
110 bool collN = static_cast<bool>( m_currentNode->CheckColliding( &m_currentTrace.NLine() ) );
111
112 m_fitOk = !( collP || collN ) ;
113
114 return m_fitOk;
115}
116
117
119{
120 VIA virtHead = makeVia( aP, nullptr );
121
122 if( m_placingVia )
123 {
124 virtHead.SetDiameter( 0, viaGap() + 2 * virtHead.Diameter( 0 ) );
125 }
126 else
127 {
128 virtHead.SetLayer( m_currentLayer );
129 virtHead.SetDiameter( 0, m_sizes.DiffPairGap() + 2 * m_sizes.DiffPairWidth() );
130 }
131
132 bool solidsOnly = true;
133
134 if( Settings().Mode() == RM_MarkObstacles )
135 {
136 aNewP = aP;
137 return true;
138 }
139 else if( Settings().Mode() == RM_Walkaround )
140 {
141 solidsOnly = false;
142 }
143
144 // fixme: I'm too lazy to do it well. Circular approximaton will do for the moment.
145
146 // Note: this code is lifted from VIA::PushoutForce and then optimized for this use case and to
147 // check proper clearances to the diff pair line. It can be removed if some specialized
148 // pushout for traces / diff pairs is implemented. Just calling VIA::PushoutForce does not work
149 // as the via may have different resolved clearance to items than the diff pair should.
150 int maxIter = 40;
151 int iter = 0;
152 bool collided = false;
153 VECTOR2I force, totalForce;
154 std::set<const ITEM*> handled;
155
156 while( iter < maxIter )
157 {
158 NODE::OPT_OBSTACLE obs = m_currentNode->CheckColliding( &virtHead, solidsOnly ?
160 ITEM::ANY_T );
161 if( !obs || handled.count( obs->m_item ) )
162 break;
163
164 int clearance = m_currentNode->GetClearance( obs->m_item, &m_currentTrace.PLine(), false );
165 VECTOR2I layerForce;
166 collided = false;
167
168 for( int viaLayer : virtHead.RelevantShapeLayers( obs->m_item ) )
169 {
170 collided |= obs->m_item->Shape( viaLayer )->Collide( virtHead.Shape( viaLayer ),
171 clearance, &layerForce );
172
173 if( layerForce.SquaredEuclideanNorm() > force.SquaredEuclideanNorm() )
174 force = layerForce;
175 }
176
177 if( collided )
178 {
179 totalForce += force;
180 virtHead.SetPos( virtHead.Pos() + force );
181 }
182
183 handled.insert( obs->m_item );
184
185 iter++;
186 }
187
188 bool succeeded = ( !collided || iter != maxIter );
189
190 if( succeeded )
191 {
192 aNewP = aP + force;
193 return true;
194 }
195
196 return false;
197}
198
199
201 bool aPFirst, bool aWindCw, bool aSolidsOnly )
202{
203 WALKAROUND walkaround( aNode, Router() );
205
206 walkaround.SetSolidsOnly( aSolidsOnly );
207 walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() );
209
210 SHOVE shove( aNode, Router() );
211 LINE walkP, walkN;
212
213 aWalk = *aCurrent;
214
215 int iter = 0;
216
217 DIFF_PAIR cur( *aCurrent );
218
219 bool currentIsP = aPFirst;
220
221 int mask = aSolidsOnly ? ITEM::SOLID_T : ITEM::ANY_T;
222
223 do
224 {
225 LINE preWalk = ( currentIsP ? cur.PLine() : cur.NLine() );
226 LINE preShove = ( currentIsP ? cur.NLine() : cur.PLine() );
227 LINE postWalk;
228
229 if( !aNode->CheckColliding ( &preWalk, mask ) )
230 {
231 currentIsP = !currentIsP;
232
233 if( !aNode->CheckColliding( &preShove, mask ) )
234 break;
235 else
236 continue;
237 }
238
239 auto wf1 = walkaround.Route( preWalk );
240
241 if( wf1.status[ WALKAROUND::WP_SHORTEST ] != WALKAROUND::ST_DONE )
242 return false;
243
244 postWalk = wf1.lines[ WALKAROUND::WP_SHORTEST ];
245
246 LINE postShove( preShove );
247
248 shove.ForceClearance( true, cur.Gap() - 2 * PNS_HULL_MARGIN );
249
250 bool sh1;
251
252 sh1 = shove.ShoveObstacleLine( postWalk, preShove, postShove );
253
254 if( !sh1 )
255 return false;
256
257 postWalk.Line().Simplify();
258 postShove.Line().Simplify();
259
260 cur.SetShape( postWalk.CLine(), postShove.CLine(), !currentIsP );
261
262 currentIsP = !currentIsP;
263
264 if( !aNode->CheckColliding( &postShove, mask ) )
265 break;
266
267 iter++;
268 }
269 while( iter < 3 );
270
271 if( iter == 3 )
272 return false;
273
274 aWalk.SetShape( cur.CP(), cur.CN() );
275
276 return true;
277}
278
279
280bool DIFF_PAIR_PLACER::tryWalkDp( NODE* aNode, DIFF_PAIR &aPair, bool aSolidsOnly )
281{
282 DIFF_PAIR best;
283 double bestScore = 100000000000000.0;
284
285 for( int attempt = 0; attempt <= 3; attempt++ )
286 {
287 DIFF_PAIR p;
288 NODE *tmp = m_currentNode->Branch();
289
290 bool pfirst = ( attempt & 1 ) ? true : false;
291 bool wind_cw = ( attempt & 2 ) ? true : false;
292
293 if( attemptWalk( tmp, &aPair, p, pfirst, wind_cw, aSolidsOnly ) )
294 {
295 double cl = 1 + p.CoupledLength();
296 double skew = p.Skew();
297
298 double score = cl + fabs( skew ) * 3.0;
299
300 if( score < bestScore )
301 {
302 bestScore = score;
303 best = std::move( p );
304 }
305 }
306
307 delete tmp;
308 }
309
310 if( bestScore > 0.0 )
311 {
312 OPTIMIZER optimizer( m_currentNode );
313
314 aPair.SetShape( best );
315 optimizer.Optimize( &aPair );
316
317 return true;
318 }
319
320 return false;
321}
322
323
325{
326 if( !routeHead ( aP ) )
327 return false;
328
330
331 return m_fitOk;
332}
333
334
336{
337 switch( Settings().Mode() )
338 {
339 case RM_MarkObstacles:
340 return rhMarkObstacles( aP );
341 case RM_Walkaround:
342 return rhWalkOnly( aP );
343 case RM_Shove:
344 return rhShoveOnly( aP );
345 default:
346 break;
347 }
348
349 return false;
350}
351
352
354{
355 m_currentNode = m_shove->CurrentNode();
356
357 bool ok = routeHead( aP );
358
359 m_fitOk = false;
360
361 if( !ok )
362 return false;
363
364 if( !tryWalkDp( m_currentNode, m_currentTrace, true ) )
365 return false;
366
367 LINE pLine( m_currentTrace.PLine() );
368 LINE nLine( m_currentTrace.NLine() );
369 ITEM_SET head;
370
371 m_shove->ClearHeads();
372 m_shove->AddHeads( pLine );
373 m_shove->AddHeads( nLine );
374
375 SHOVE::SHOVE_STATUS status = m_shove->Run();
376
377 m_currentNode = m_shove->CurrentNode();
378
379 if( status == SHOVE::SH_OK )
380 {
381 m_currentNode = m_shove->CurrentNode();
382
383 if( m_shove->HeadsModified( 0 ))
384 pLine = m_shove->GetModifiedHead(0);
385
386 if( m_shove->HeadsModified( 1 ))
387 nLine = m_shove->GetModifiedHead(1);
388
389 // Update m_currentTrace with the shoved shapes so FixRoute() commits correct geometry
390 m_currentTrace.SetShape( pLine.CLine(), nLine.CLine() );
391
392 if( !m_currentNode->CheckColliding( &pLine ) &&
393 !m_currentNode->CheckColliding( &nLine ) )
394 {
395 m_fitOk = true;
396 }
397 }
398 else
399 {
400 // bring back previous state
401 m_currentTrace.SetShape( pLine.CLine(), nLine.CLine() );
402 }
403
404
405 return m_fitOk;
406}
407
408
410{
411 ITEM_SET t;
412
413 t.Add( &m_currentTrace.PLine() );
414 t.Add( &m_currentTrace.NLine() );
415
416 return t;
417}
418
419
421{
423
424 if( !m_idle )
425 Move( m_currentEnd, nullptr );
426}
427
428
429NODE* DIFF_PAIR_PLACER::CurrentNode( bool aLoopsRemoved ) const
430{
431 if( m_lastNode )
432 return m_lastNode;
433
434 return m_currentNode;
435}
436
437
439{
440 if( m_idle )
441 {
442 m_currentLayer = aLayer;
443 return true;
444 }
445 else if( m_chainedPlacement || !m_prevPair )
446 {
447 return false;
448 }
449 else if( !m_prevPair->PrimP() || ( m_prevPair->PrimP()->OfKind( ITEM::VIA_T ) &&
450 m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) )
451 {
452 m_currentLayer = aLayer;
455 Move( m_currentEnd, nullptr );
456 return true;
457 }
458
459 return false;
460}
461
462
464{
465 switch( aItem->Kind() )
466 {
467 case ITEM::LINE_T:
468 {
469 LINE* l = static_cast<LINE*>( aItem );
470
471 if( !l->PointCount() )
472 return OPT_VECTOR2I();
473 else
474 return l->CPoint( 0 );
475 }
476 case ITEM::VIA_T:
477 case ITEM::SOLID_T:
478 return aItem->Anchor( 0 );
479
480 case ITEM::ARC_T:
481 {
482 ARC* a = static_cast<ARC*>( aItem );
483
484 const JOINT* jA = aNode->FindJoint( aItem->Anchor( 0 ), aItem );
485 const JOINT* jB = aNode->FindJoint( aItem->Anchor( 1 ), aItem );
486
487 if( jA && jA->LinkCount() == 1 )
488 return a->Arc().GetP0();
489 else if( jB && jB->LinkCount() == 1 )
490 return a->Arc().GetP1();
491 else
492 return OPT_VECTOR2I();
493 }
494 case ITEM::SEGMENT_T:
495 {
496 SEGMENT* s = static_cast<SEGMENT*>( aItem );
497
498 const JOINT* jA = aNode->FindJoint( aItem->Anchor( 0 ), aItem );
499 const JOINT* jB = aNode->FindJoint( aItem->Anchor( 1 ), aItem );
500
501 if( jA && jA->LinkCount() == 1 )
502 return s->Seg().A;
503 else if( jB && jB->LinkCount() == 1 )
504 return s->Seg().B;
505 else
506 return OPT_VECTOR2I();
507 }
508
509 default:
510 return OPT_VECTOR2I();
511 }
512}
513
514
515
517 DP_PRIMITIVE_PAIR& aPair, wxString* aErrorMsg )
518{
519 NET_HANDLE netP, netN;
520
521 bool result = aWorld->GetRuleResolver()->DpNetPair( aItem, netP, netN );
522
523 if( !result )
524 {
525 if( aErrorMsg )
526 {
527 *aErrorMsg = _( "Unable to find complementary differential pair "
528 "nets. Make sure the names of the nets belonging "
529 "to a differential pair end with either N/P or +/-." );
530 }
531 return false;
532 }
533
534 NET_HANDLE refNet = aItem->Net();
535 NET_HANDLE coupledNet = ( refNet == netP ) ? netN : netP;
536
537 OPT_VECTOR2I refAnchor = getDanglingAnchor( aWorld, aItem );
538 ITEM* primRef = aItem;
539
540 if( !refAnchor )
541 {
542 if( aErrorMsg )
543 {
544 *aErrorMsg = _( "Can't find a suitable starting point. If starting "
545 "from an existing differential pair make sure you are "
546 "at the end." );
547 }
548
549 return false;
550 }
551
552 std::set<ITEM*> coupledItems;
553
554 aWorld->AllItemsInNet( coupledNet, coupledItems );
555 double bestDist = std::numeric_limits<double>::max();
556 bool found = false;
557
558 for( ITEM* item : coupledItems )
559 {
560 if( item->Kind() == aItem->Kind() )
561 {
562 OPT_VECTOR2I anchor = getDanglingAnchor( aWorld, item );
563
564 if( !anchor )
565 continue;
566
567 double dist = ( *anchor - *refAnchor ).EuclideanNorm();
568
569 bool shapeMatches = true;
570
571 if( item->OfKind( ITEM::SOLID_T | ITEM::VIA_T ) && item->Layers() != aItem->Layers() )
572 {
573 shapeMatches = false;
574 }
575
576 if( dist < bestDist && shapeMatches )
577 {
578 found = true;
579 bestDist = dist;
580
581 if( refNet != netP )
582 {
583 aPair = DP_PRIMITIVE_PAIR ( item, primRef );
584 aPair.SetAnchors( *anchor, *refAnchor );
585 }
586 else
587 {
588 aPair = DP_PRIMITIVE_PAIR( primRef, item );
589 aPair.SetAnchors( *refAnchor, *anchor );
590 }
591 }
592 }
593 }
594
595 if( !found )
596 {
597 if( aErrorMsg )
598 {
599 *aErrorMsg = wxString::Format( _( "Can't find a suitable starting point "
600 "for coupled net \"%s\"." ),
601 aWorld->GetRuleResolver()->NetName( coupledNet ) );
602 }
603
604 return false;
605 }
606
607 return true;
608}
609
610
612{
613 return std::max( m_sizes.DiffPairViaGap(),
614 m_sizes.GetDiffPairHoleToHole() + m_sizes.ViaDrill() - m_sizes.ViaDiameter() );
615}
616
617
619{
620 return m_sizes.DiffPairGap() + m_sizes.DiffPairWidth();
621}
622
623
624bool DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
625{
626 VECTOR2I p( aP );
627
628 setWorld( Router()->GetWorld() );
630
631 wxString err_msg;
632
633 if( !FindDpPrimitivePair( m_currentNode, aP, aStartItem, m_start, &err_msg ) )
634 {
635 Router()->SetFailureReason( err_msg );
636 return false;
637 }
638
639 m_netP = m_start.PrimP()->Net();
640 m_netN = m_start.PrimN()->Net();
641
642 m_currentStart = p;
643 m_currentEnd = p;
644 m_placingVia = false;
645 m_chainedPlacement = false;
646 m_currentTraceOk = false;
648 m_currentTrace.SetNets( m_netP, m_netN );
649 m_lastFixNode = nullptr;
650
652
653 return true;
654}
655
656
658{
659 m_idle = false;
660 m_orthoMode = false;
661 m_currentEndItem = nullptr;
663
664 NODE* world = Router()->GetWorld();
665
666 world->KillChildren();
667 NODE* rootNode = world->Branch();
668
669 setWorld( rootNode );
670
671 m_lastNode = nullptr;
672 m_currentNode = rootNode;
673
674 m_shove = std::make_unique<SHOVE>( m_currentNode, Router() );
675}
676
677
679{
680 m_fitOk = false;
681
682 DP_GATEWAYS gwsEntry( gap() );
683 DP_GATEWAYS gwsTarget( gap() );
684
685 if( !m_prevPair )
687
689
690 DP_PRIMITIVE_PAIR target;
691
693 {
694 gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal );
695 m_snapOnTarget = true;
696 }
697 else
698 {
699 VECTOR2I fp;
700
701 if( !propagateDpHeadForces( aP, fp ) )
702 return false;
703
704 VECTOR2I midp, dirV;
705 m_prevPair->CursorOrientation( fp, midp, dirV );
706
707 VECTOR2I fpProj = SEG( midp, midp + dirV ).LineProject( fp );
708
709 // compute 'leader point' distance from the cursor (project cursor position
710 // on the extension of the starting segment pair of the DP)
711 int lead_dist = ( fpProj - fp ).EuclideanNorm();
712
713 gwsTarget.SetFitVias( m_placingVia, m_sizes.ViaDiameter(), viaGap() );
714
715 // far from the initial segment extension line -> allow a 45-degree obtuse turn
716 if( lead_dist > ( m_sizes.DiffPairGap() + m_sizes.DiffPairWidth() ) / 2 )
717 {
718 gwsTarget.BuildForCursor( fp );
719 }
720 else
721 {
722 // close to the initial segment extension line -> keep straight part only, project
723 // as close as possible to the cursor.
724 gwsTarget.BuildForCursor( fpProj );
726 DIRECTION_45( dirV ) );
727 }
728
729 m_snapOnTarget = false;
730 }
731
732 m_currentTrace.SetGap( gap() );
733 m_currentTrace.SetLayer( m_currentLayer );
734
735 bool result = gwsEntry.FitGateways( gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace );
736
737 if( result )
738 {
739 m_currentTraceOk = true;
740 m_currentTrace.SetNets( m_netP, m_netN );
741 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
742 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
743
744 if( m_placingVia )
745 {
746 m_currentTrace.AppendVias ( makeVia( m_currentTrace.CP().CLastPoint(), m_netP ),
747 makeVia( m_currentTrace.CN().CLastPoint(), m_netN ) );
748 }
749 else
750 {
751 m_currentTrace.RemoveVias();
752 }
753
754 return true;
755 }
756
757 return m_currentTraceOk;
758}
759
760
761bool DIFF_PAIR_PLACER::Move( const VECTOR2I& aP , ITEM* aEndItem )
762{
763 m_currentEndItem = aEndItem;
764 m_fitOk = false;
765
766 delete m_lastNode;
767 m_lastNode = nullptr;
768
769 bool retval = route( aP );
770
771 NODE* latestNode = m_currentNode;
772 m_lastNode = latestNode->Branch();
773
774 assert( m_lastNode != nullptr );
775 m_currentEnd = aP;
776
778
779 return retval;
780}
781
782
784{
785 m_sizes = aSizes;
786
787 if( !m_idle )
788 {
789 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
790 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
791
792 if( m_currentTrace.EndsWithVias() )
793 {
794 m_currentTrace.SetViaDiameter( m_sizes.ViaDiameter() );
795 m_currentTrace.SetViaDrill( m_sizes.ViaDrill() );
796 }
797 }
798}
799
800
801bool DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
802{
803 if( !m_fitOk && !Settings().AllowDRCViolations() )
804 return false;
805
806 if( m_currentTrace.CP().SegmentCount() < 1 || m_currentTrace.CN().SegmentCount() < 1 )
807 return false;
808
809 if( m_currentTrace.CP().SegmentCount() > 1 )
810 m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal();
811
812 TOPOLOGY topo( m_lastNode );
813
814 if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() && !aForceFinish &&
815 !Settings().GetFixAllSegments() )
816 {
817 SHAPE_LINE_CHAIN newP( m_currentTrace.CP() );
818 SHAPE_LINE_CHAIN newN( m_currentTrace.CN() );
819
820 if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 )
821 {
822 newP.Remove( -1, -1 );
823 newN.Remove( -1, -1 );
824 }
825
826 m_currentTrace.SetShape( newP, newN );
827 }
828
829 if( m_currentTrace.EndsWithVias() )
830 {
831 m_lastNode->Add( Clone( m_currentTrace.PLine().Via() ) );
832 m_lastNode->Add( Clone( m_currentTrace.NLine().Via() ) );
833 m_chainedPlacement = false;
834 }
835 else
836 {
837 m_chainedPlacement = !m_snapOnTarget && !aForceFinish;
838 }
839
840 LINE lineP( m_currentTrace.PLine() );
841 LINE lineN( m_currentTrace.NLine() );
842
843 m_lastNode->Add( lineP );
844 m_lastNode->Add( lineN );
845
846 topo.SimplifyLine( &lineP );
847 topo.SimplifyLine( &lineN );
848
849 m_prevPair = m_currentTrace.EndingPrimitives();
851
852 // avoid an use-after-free error (CommitPlacement calls NODE::Commit which will invalidate the shove heads state. Need to rethink the memory management).
853 if( Settings().Mode() == RM_Shove )
854 m_shove = std::make_unique<SHOVE>( m_world, Router() );
855
857 m_placingVia = false;
858 m_lastFixNode = nullptr;
859
860 if( m_snapOnTarget || aForceFinish )
861 {
862 m_idle = true;
863 return true;
864 }
865 else
866 {
868 return false;
869 }
870}
871
872
874{
875 m_world->KillChildren();
876 m_lastNode = nullptr;
877 return true;
878}
879
880
882{
883 return m_currentTrace.CP().SegmentCount() > 0 || m_currentTrace.CN().SegmentCount() > 0;
884}
885
886
888{
889 if( m_lastFixNode )
891
892 m_lastFixNode = nullptr;
893 m_lastNode = nullptr;
894 m_currentNode = nullptr;
895 return true;
896}
897
898
899void DIFF_PAIR_PLACER::GetModifiedNets( std::vector<NET_HANDLE> &aNets ) const
900{
901 aNets.push_back( m_netP );
902 aNets.push_back( m_netN );
903}
904
905
907{
908 SHAPE_LINE_CHAIN ratLineN, ratLineP;
909 TOPOLOGY topo( m_lastNode );
910
911 if( topo.LeadingRatLine( &m_currentTrace.PLine(), ratLineP ) )
912 m_router->GetInterface()->DisplayRatline( ratLineP, m_netP );
913
914 if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN ) )
915 m_router->GetInterface()->DisplayRatline( ratLineN, m_netN );
916}
917
918
919const std::vector<NET_HANDLE> DIFF_PAIR_PLACER::CurrentNets() const
920{
921 std::vector<NET_HANDLE> rv;
922 rv.push_back( m_netP );
923 rv.push_back( m_netN );
924 return rv;
925}
926
927}
Represent route directions & corner angles in a 45-degree metric.
Definition direction45.h:37
bool IsDiagonal() const
Returns true if the direction is diagonal (e.g.
ROUTER * Router() const
Return current router settings.
ROUTER * m_router
ROUTING_SETTINGS & Settings() const
Return the logger object, allowing to dump geometry to a file.
SHAPE_ARC & Arc()
Definition pns_arc.h:115
NODE * CurrentNode(bool aLoopsRemoved=false) const override
Return the most recent world state.
void SetOrthoMode(bool aOrthoMode) override
Function SetOrthoMode()
bool HasPlacedAnything() const override
NODE * m_world
current routing start point (end of tail, beginning of head)
bool tryWalkDp(NODE *aNode, DIFF_PAIR &aPair, bool aSolidsOnly)
route step, walk around mode
bool propagateDpHeadForces(const VECTOR2I &aP, VECTOR2I &aNewP)
bool rhMarkObstacles(const VECTOR2I &aP)
int m_viaDiameter
current via drill
std::optional< DP_PRIMITIVE_PAIR > m_prevPair
current algorithm iteration
bool ToggleVia(bool aEnabled) override
Enable/disable a via at the end of currently routed trace.
bool route(const VECTOR2I &aP)
Re-route the current track to point aP.
int m_iteration
pointer to world to search colliding items
bool rhShoveOnly(const VECTOR2I &aP)
route step, mark obstacles mode
bool Start(const VECTOR2I &aP, ITEM *aStartItem) override
Start routing a single track at point aP, taking item aStartItem as anchor (unless NULL).
const ITEM_SET Traces() override
Return the complete routed line, as a single-member ITEM_SET.
void GetModifiedNets(std::vector< NET_HANDLE > &aNets) const override
Function GetModifiedNets.
int m_viaDrill
current track width
void FlipPosture() override
Toggle the current posture (straight/diagonal) of the trace head.
DIFF_PAIR_PLACER(ROUTER *aRouter)
bool attemptWalk(NODE *aNode, DIFF_PAIR *aCurrent, DIFF_PAIR &aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly)
void setWorld(NODE *aWorld)
Set the board to route.
NODE * m_currentNode
Postprocessed world state (including marked collisions & removed loops)
void initPlacement()
Initialize placement of a new line with given parameters.
const std::vector< NET_HANDLE > CurrentNets() const override
Return the net of currently routed track.
bool routeHead(const VECTOR2I &aP)
void UpdateSizes(const SIZES_SETTINGS &aSizes) override
Perform on-the-fly update of the width, via diameter & drill size from a settings class.
static bool FindDpPrimitivePair(NODE *aWorld, const VECTOR2I &aP, ITEM *aItem, DP_PRIMITIVE_PAIR &aPair, wxString *aErrorMsg=nullptr)
bool rhWalkOnly(const VECTOR2I &aP)
route step, shove mode
bool Move(const VECTOR2I &aP, ITEM *aEndItem) override
Move the end of the currently routed trace to the point aP, taking aEndItem as anchor (if not NULL).
bool FixRoute(const VECTOR2I &aP, ITEM *aEndItem, bool aForceFinish) override
Commit the currently routed track to the parent node, taking aP as the final end point and aEndItem a...
bool m_placingVia
current via diameter
void updateLeadingRatLine()
Draw the "leading" ratsnest line, which connects the end of currently routed track and the nearest ye...
const VIA makeVia(const VECTOR2I &aP, NET_HANDLE aNet)
SIZES_SETTINGS m_sizes
Are we placing a via?
bool SetLayer(int aLayer) override
Set the current routing layer.
std::unique_ptr< SHOVE > m_shove
Current world state.
Basic class for a differential pair.
const SHAPE_LINE_CHAIN & CN() const
double CoupledLength() const
double Skew() const
void SetShape(const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN &aN, bool aSwapLanes=false)
int Gap() const
const SHAPE_LINE_CHAIN & CP() const
A set of gateways calculated for the cursor or starting/ending primitive pair.
void SetFitVias(bool aEnable, int aDiameter=0, int aViaGap=-1)
void BuildFromPrimitivePair(const DP_PRIMITIVE_PAIR &aPair, bool aPreferDiagonal)
bool FitGateways(DP_GATEWAYS &aEntry, DP_GATEWAYS &aTarget, bool aPrefDiagonal, DIFF_PAIR &aDp)
void FilterByOrientation(int aAngleMask, DIRECTION_45 aRefOrientation)
void BuildForCursor(const VECTOR2I &aCursorPos)
Store starting/ending primitives (pads, vias or segments) for a differential pair.
void SetAnchors(const VECTOR2I &aAnchorP, const VECTOR2I &aAnchorN)
void Add(const LINE &aLine)
Base class for PNS router board items.
Definition pns_item.h:98
const PNS_LAYER_RANGE & Layers() const
Definition pns_item.h:212
virtual NET_HANDLE Net() const
Definition pns_item.h:210
PnsKind Kind() const
Return the type (kind) of the item.
Definition pns_item.h:173
std::set< int > RelevantShapeLayers(const ITEM *aOther) const
Returns the set of layers on which either this or the other item can have a unique shape.
Definition pns_item.cpp:94
void SetLayer(int aLayer)
Definition pns_item.h:215
virtual VECTOR2I Anchor(int n) const
Definition pns_item.h:268
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
int LinkCount(int aMask=-1) const
Definition pns_joint.h:318
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
const VECTOR2I & CPoint(int aIdx) const
Definition pns_line.h:150
const SHAPE_LINE_CHAIN & CLine() const
Definition pns_line.h:142
SHAPE_LINE_CHAIN & Line()
Definition pns_line.h:141
int PointCount() const
Definition pns_line.h:145
Keep the router "world" - i.e.
Definition pns_node.h:232
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:143
OPT_OBSTACLE CheckColliding(const ITEM *aItem, int aKindMask=ITEM::ANY_T)
Check if the item collides with anything else in the world, and if found, returns the obstacle.
Definition pns_node.cpp:410
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.
std::optional< OBSTACLE > OPT_OBSTACLE
Definition pns_node.h:242
RULE_RESOLVER * GetRuleResolver() const
Return the number of joints.
Definition pns_node.h:270
void AllItemsInNet(NET_HANDLE aNet, std::set< ITEM * > &aItems, int aKindMask=-1)
void KillChildren()
Perform various optimizations of the lines being routed, attempting to make the lines shorter and les...
static bool Optimize(LINE *aLine, int aEffortLevel, NODE *aWorld, const VECTOR2I &aV=VECTOR2I(0, 0))
PLACEMENT_ALGO(ROUTER *aRouter)
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:227
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:178
virtual bool DpNetPair(const ITEM *aItem, NET_HANDLE &aNetP, NET_HANDLE &aNetN)=0
virtual wxString NetName(NET_HANDLE aNet)=0
const SEG & Seg() const
Definition pns_segment.h:93
The actual Push and Shove algorithm.
Definition pns_shove.h:46
void ForceClearance(bool aEnabled, int aClearance)
Definition pns_shove.h:89
bool ShoveObstacleLine(const LINE &aCurLine, const LINE &aObstacleLine, LINE &aResultLine)
bool LeadingRatLine(const LINE *aTrack, SHAPE_LINE_CHAIN &aRatLine)
bool SimplifyLine(LINE *aLine)
int Diameter(int aLayer) const
Definition pns_via.h:226
void SetDiameter(int aLayer, int aDiameter)
Definition pns_via.h:233
const VECTOR2I & Pos() const
Definition pns_via.h:205
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_via.h:301
void SetPos(const VECTOR2I &aPos)
Definition pns_via.h:207
void SetIterationLimit(const int aIterLimit)
void SetSolidsOnly(bool aSolidsOnly)
STATUS Route(const LINE &aInitialPath, LINE &aWalkPath, bool aOptimize=true)
void SetAllowedPolicies(std::vector< WALK_POLICY > aPolicies)
Represent a contiguous set of PCB layers.
Definition seg.h:42
VECTOR2I A
Definition seg.h:49
VECTOR2I B
Definition seg.h:50
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Definition seg.cpp:685
const VECTOR2I & GetP1() const
Definition shape_arc.h:119
const VECTOR2I & GetP0() const
Definition shape_arc.h:118
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
int SegmentCount() const
Return the number of segments in this line chain.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
Definition vector2d.h:307
#define _(s)
Push and Shove diff pair dimensions (gap) settings dialog.
OPT_VECTOR2I getDanglingAnchor(NODE *aNode, ITEM *aItem)
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
@ RM_Walkaround
Only walk around.
@ RM_Shove
Only shove.
void * NET_HANDLE
Definition pns_item.h:55
std::unique_ptr< typename std::remove_const< T >::type > Clone(const T &aItem)
Definition pns_item.h:344
@ DIFF_PAIR
#define PNS_HULL_MARGIN
Definition pns_line.h:45
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:39
int clearance
wxString result
Test unit parsing edge cases and error handling.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695