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 if( !m_currentNode->CheckColliding( &m_currentTrace.PLine() ) &&
390 !m_currentNode->CheckColliding( &m_currentTrace.NLine() ) )
391 {
392 m_fitOk = true;
393 }
394 }
395 else
396 {
397 // bring back previous state
398 m_currentTrace.SetShape( pLine.CLine(), nLine.CLine() );
399 }
400
401
402 return m_fitOk;
403}
404
405
407{
408 ITEM_SET t;
409
410 t.Add( &m_currentTrace.PLine() );
411 t.Add( &m_currentTrace.NLine() );
412
413 return t;
414}
415
416
418{
420
421 if( !m_idle )
422 Move( m_currentEnd, nullptr );
423}
424
425
426NODE* DIFF_PAIR_PLACER::CurrentNode( bool aLoopsRemoved ) const
427{
428 if( m_lastNode )
429 return m_lastNode;
430
431 return m_currentNode;
432}
433
434
436{
437 if( m_idle )
438 {
439 m_currentLayer = aLayer;
440 return true;
441 }
442 else if( m_chainedPlacement || !m_prevPair )
443 {
444 return false;
445 }
446 else if( !m_prevPair->PrimP() || ( m_prevPair->PrimP()->OfKind( ITEM::VIA_T ) &&
447 m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) )
448 {
449 m_currentLayer = aLayer;
452 Move( m_currentEnd, nullptr );
453 return true;
454 }
455
456 return false;
457}
458
459
461{
462 switch( aItem->Kind() )
463 {
464 case ITEM::LINE_T:
465 {
466 LINE* l = static_cast<LINE*>( aItem );
467
468 if( !l->PointCount() )
469 return OPT_VECTOR2I();
470 else
471 return l->CPoint( 0 );
472 }
473 case ITEM::VIA_T:
474 case ITEM::SOLID_T:
475 return aItem->Anchor( 0 );
476
477 case ITEM::ARC_T:
478 {
479 ARC* a = static_cast<ARC*>( aItem );
480
481 const JOINT* jA = aNode->FindJoint( aItem->Anchor( 0 ), aItem );
482 const JOINT* jB = aNode->FindJoint( aItem->Anchor( 1 ), aItem );
483
484 if( jA && jA->LinkCount() == 1 )
485 return a->Arc().GetP0();
486 else if( jB && jB->LinkCount() == 1 )
487 return a->Arc().GetP1();
488 else
489 return OPT_VECTOR2I();
490 }
491 case ITEM::SEGMENT_T:
492 {
493 SEGMENT* s = static_cast<SEGMENT*>( aItem );
494
495 const JOINT* jA = aNode->FindJoint( aItem->Anchor( 0 ), aItem );
496 const JOINT* jB = aNode->FindJoint( aItem->Anchor( 1 ), aItem );
497
498 if( jA && jA->LinkCount() == 1 )
499 return s->Seg().A;
500 else if( jB && jB->LinkCount() == 1 )
501 return s->Seg().B;
502 else
503 return OPT_VECTOR2I();
504 }
505
506 default:
507 return OPT_VECTOR2I();
508 }
509}
510
511
512
514 DP_PRIMITIVE_PAIR& aPair, wxString* aErrorMsg )
515{
516 NET_HANDLE netP, netN;
517
518 bool result = aWorld->GetRuleResolver()->DpNetPair( aItem, netP, netN );
519
520 if( !result )
521 {
522 if( aErrorMsg )
523 {
524 *aErrorMsg = _( "Unable to find complementary differential pair "
525 "nets. Make sure the names of the nets belonging "
526 "to a differential pair end with either N/P or +/-." );
527 }
528 return false;
529 }
530
531 NET_HANDLE refNet = aItem->Net();
532 NET_HANDLE coupledNet = ( refNet == netP ) ? netN : netP;
533
534 OPT_VECTOR2I refAnchor = getDanglingAnchor( aWorld, aItem );
535 ITEM* primRef = aItem;
536
537 if( !refAnchor )
538 {
539 if( aErrorMsg )
540 {
541 *aErrorMsg = _( "Can't find a suitable starting point. If starting "
542 "from an existing differential pair make sure you are "
543 "at the end." );
544 }
545
546 return false;
547 }
548
549 std::set<ITEM*> coupledItems;
550
551 aWorld->AllItemsInNet( coupledNet, coupledItems );
552 double bestDist = std::numeric_limits<double>::max();
553 bool found = false;
554
555 for( ITEM* item : coupledItems )
556 {
557 if( item->Kind() == aItem->Kind() )
558 {
559 OPT_VECTOR2I anchor = getDanglingAnchor( aWorld, item );
560
561 if( !anchor )
562 continue;
563
564 double dist = ( *anchor - *refAnchor ).EuclideanNorm();
565
566 bool shapeMatches = true;
567
568 if( item->OfKind( ITEM::SOLID_T | ITEM::VIA_T ) && item->Layers() != aItem->Layers() )
569 {
570 shapeMatches = false;
571 }
572
573 if( dist < bestDist && shapeMatches )
574 {
575 found = true;
576 bestDist = dist;
577
578 if( refNet != netP )
579 {
580 aPair = DP_PRIMITIVE_PAIR ( item, primRef );
581 aPair.SetAnchors( *anchor, *refAnchor );
582 }
583 else
584 {
585 aPair = DP_PRIMITIVE_PAIR( primRef, item );
586 aPair.SetAnchors( *refAnchor, *anchor );
587 }
588 }
589 }
590 }
591
592 if( !found )
593 {
594 if( aErrorMsg )
595 {
596 *aErrorMsg = wxString::Format( _( "Can't find a suitable starting point "
597 "for coupled net \"%s\"." ),
598 aWorld->GetRuleResolver()->NetName( coupledNet ) );
599 }
600
601 return false;
602 }
603
604 return true;
605}
606
607
609{
610 return std::max( m_sizes.DiffPairViaGap(),
611 m_sizes.GetDiffPairHoleToHole() + m_sizes.ViaDrill() - m_sizes.ViaDiameter() );
612}
613
614
616{
617 return m_sizes.DiffPairGap() + m_sizes.DiffPairWidth();
618}
619
620
621bool DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
622{
623 VECTOR2I p( aP );
624
625 setWorld( Router()->GetWorld() );
627
628 wxString err_msg;
629
630 if( !FindDpPrimitivePair( m_currentNode, aP, aStartItem, m_start, &err_msg ) )
631 {
632 Router()->SetFailureReason( err_msg );
633 return false;
634 }
635
636 m_netP = m_start.PrimP()->Net();
637 m_netN = m_start.PrimN()->Net();
638
639 m_currentStart = p;
640 m_currentEnd = p;
641 m_placingVia = false;
642 m_chainedPlacement = false;
643 m_currentTraceOk = false;
645 m_currentTrace.SetNets( m_netP, m_netN );
646 m_lastFixNode = nullptr;
647
649
650 return true;
651}
652
653
655{
656 m_idle = false;
657 m_orthoMode = false;
658 m_currentEndItem = nullptr;
660
661 NODE* world = Router()->GetWorld();
662
663 world->KillChildren();
664 NODE* rootNode = world->Branch();
665
666 setWorld( rootNode );
667
668 m_lastNode = nullptr;
669 m_currentNode = rootNode;
670
671 m_shove = std::make_unique<SHOVE>( m_currentNode, Router() );
672}
673
674
676{
677 m_fitOk = false;
678
679 DP_GATEWAYS gwsEntry( gap() );
680 DP_GATEWAYS gwsTarget( gap() );
681
682 if( !m_prevPair )
684
686
687 DP_PRIMITIVE_PAIR target;
688
690 {
691 gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal );
692 m_snapOnTarget = true;
693 }
694 else
695 {
696 VECTOR2I fp;
697
698 if( !propagateDpHeadForces( aP, fp ) )
699 return false;
700
701 VECTOR2I midp, dirV;
702 m_prevPair->CursorOrientation( fp, midp, dirV );
703
704 VECTOR2I fpProj = SEG( midp, midp + dirV ).LineProject( fp );
705
706 // compute 'leader point' distance from the cursor (project cursor position
707 // on the extension of the starting segment pair of the DP)
708 int lead_dist = ( fpProj - fp ).EuclideanNorm();
709
710 gwsTarget.SetFitVias( m_placingVia, m_sizes.ViaDiameter(), viaGap() );
711
712 // far from the initial segment extension line -> allow a 45-degree obtuse turn
713 if( lead_dist > ( m_sizes.DiffPairGap() + m_sizes.DiffPairWidth() ) / 2 )
714 {
715 gwsTarget.BuildForCursor( fp );
716 }
717 else
718 {
719 // close to the initial segment extension line -> keep straight part only, project
720 // as close as possible to the cursor.
721 gwsTarget.BuildForCursor( fpProj );
723 DIRECTION_45( dirV ) );
724 }
725
726 m_snapOnTarget = false;
727 }
728
729 m_currentTrace.SetGap( gap() );
730 m_currentTrace.SetLayer( m_currentLayer );
731
732 bool result = gwsEntry.FitGateways( gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace );
733
734 if( result )
735 {
736 m_currentTraceOk = true;
737 m_currentTrace.SetNets( m_netP, m_netN );
738 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
739 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
740
741 if( m_placingVia )
742 {
743 m_currentTrace.AppendVias ( makeVia( m_currentTrace.CP().CLastPoint(), m_netP ),
744 makeVia( m_currentTrace.CN().CLastPoint(), m_netN ) );
745 }
746 else
747 {
748 m_currentTrace.RemoveVias();
749 }
750
751 return true;
752 }
753
754 return m_currentTraceOk;
755}
756
757
758bool DIFF_PAIR_PLACER::Move( const VECTOR2I& aP , ITEM* aEndItem )
759{
760 m_currentEndItem = aEndItem;
761 m_fitOk = false;
762
763 delete m_lastNode;
764 m_lastNode = nullptr;
765
766 bool retval = route( aP );
767
768 NODE* latestNode = m_currentNode;
769 m_lastNode = latestNode->Branch();
770
771 assert( m_lastNode != nullptr );
772 m_currentEnd = aP;
773
775
776 return retval;
777}
778
779
781{
782 m_sizes = aSizes;
783
784 if( !m_idle )
785 {
786 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
787 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
788
789 if( m_currentTrace.EndsWithVias() )
790 {
791 m_currentTrace.SetViaDiameter( m_sizes.ViaDiameter() );
792 m_currentTrace.SetViaDrill( m_sizes.ViaDrill() );
793 }
794 }
795}
796
797
798bool DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
799{
800 if( !m_fitOk && !Settings().AllowDRCViolations() )
801 return false;
802
803 if( m_currentTrace.CP().SegmentCount() < 1 || m_currentTrace.CN().SegmentCount() < 1 )
804 return false;
805
806 if( m_currentTrace.CP().SegmentCount() > 1 )
807 m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal();
808
809 TOPOLOGY topo( m_lastNode );
810
811 if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() && !aForceFinish &&
812 !Settings().GetFixAllSegments() )
813 {
814 SHAPE_LINE_CHAIN newP( m_currentTrace.CP() );
815 SHAPE_LINE_CHAIN newN( m_currentTrace.CN() );
816
817 if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 )
818 {
819 newP.Remove( -1, -1 );
820 newN.Remove( -1, -1 );
821 }
822
823 m_currentTrace.SetShape( newP, newN );
824 }
825
826 if( m_currentTrace.EndsWithVias() )
827 {
828 m_lastNode->Add( Clone( m_currentTrace.PLine().Via() ) );
829 m_lastNode->Add( Clone( m_currentTrace.NLine().Via() ) );
830 m_chainedPlacement = false;
831 }
832 else
833 {
834 m_chainedPlacement = !m_snapOnTarget && !aForceFinish;
835 }
836
837 LINE lineP( m_currentTrace.PLine() );
838 LINE lineN( m_currentTrace.NLine() );
839
840 m_lastNode->Add( lineP );
841 m_lastNode->Add( lineN );
842
843 topo.SimplifyLine( &lineP );
844 topo.SimplifyLine( &lineN );
845
846 m_prevPair = m_currentTrace.EndingPrimitives();
848
849 // avoid an use-after-free error (CommitPlacement calls NODE::Commit which will invalidate the shove heads state. Need to rethink the memory management).
850 if( Settings().Mode() == RM_Shove )
851 m_shove = std::make_unique<SHOVE>( m_world, Router() );
852
854 m_placingVia = false;
855 m_lastFixNode = nullptr;
856
857 if( m_snapOnTarget || aForceFinish )
858 {
859 m_idle = true;
860 return true;
861 }
862 else
863 {
865 return false;
866 }
867}
868
869
871{
872 m_world->KillChildren();
873 m_lastNode = nullptr;
874 return true;
875}
876
877
879{
880 return m_currentTrace.CP().SegmentCount() > 0 || m_currentTrace.CN().SegmentCount() > 0;
881}
882
883
885{
886 if( m_lastFixNode )
888
889 m_lastFixNode = nullptr;
890 m_lastNode = nullptr;
891 m_currentNode = nullptr;
892 return true;
893}
894
895
896void DIFF_PAIR_PLACER::GetModifiedNets( std::vector<NET_HANDLE> &aNets ) const
897{
898 aNets.push_back( m_netP );
899 aNets.push_back( m_netN );
900}
901
902
904{
905 SHAPE_LINE_CHAIN ratLineN, ratLineP;
906 TOPOLOGY topo( m_lastNode );
907
908 if( topo.LeadingRatLine( &m_currentTrace.PLine(), ratLineP ) )
909 m_router->GetInterface()->DisplayRatline( ratLineP, m_netP );
910
911 if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN ) )
912 m_router->GetInterface()->DisplayRatline( ratLineN, m_netN );
913}
914
915
916const std::vector<NET_HANDLE> DIFF_PAIR_PLACER::CurrentNets() const
917{
918 std::vector<NET_HANDLE> rv;
919 rv.push_back( m_netP );
920 rv.push_back( m_netN );
921 return rv;
922}
923
924}
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:146
const SHAPE_LINE_CHAIN & CLine() const
Definition pns_line.h:138
SHAPE_LINE_CHAIN & Line()
Definition pns_line.h:137
int PointCount() const
Definition pns_line.h:141
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:208
void SetDiameter(int aLayer, int aDiameter)
Definition pns_via.h:215
const VECTOR2I & Pos() const
Definition pns_via.h:184
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_via.h:246
void SetPos(const VECTOR2I &aPos)
Definition pns_via.h:186
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:656
const VECTOR2I & GetP1() const
Definition shape_arc.h:117
const VECTOR2I & GetP0() const
Definition shape_arc.h:116
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