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
19 * along with this program. If not, see <https://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() );
204
205 walkaround.SetSolidsOnly( aSolidsOnly );
206 walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() );
208
209 SHOVE shove( aNode, Router() );
210 LINE walkP, walkN;
211
212 aWalk = *aCurrent;
213
214 int iter = 0;
215
216 DIFF_PAIR cur( *aCurrent );
217
218 bool currentIsP = aPFirst;
219
220 int mask = aSolidsOnly ? ITEM::SOLID_T : ITEM::ANY_T;
221
222 do
223 {
224 LINE preWalk = ( currentIsP ? cur.PLine() : cur.NLine() );
225 LINE preShove = ( currentIsP ? cur.NLine() : cur.PLine() );
226 LINE postWalk;
227
228 if( !aNode->CheckColliding ( &preWalk, mask ) )
229 {
230 currentIsP = !currentIsP;
231
232 if( !aNode->CheckColliding( &preShove, mask ) )
233 break;
234 else
235 continue;
236 }
237
238 auto wf1 = walkaround.Route( preWalk );
239
240 if( wf1.status[ WALKAROUND::WP_SHORTEST ] != WALKAROUND::ST_DONE )
241 return false;
242
243 postWalk = wf1.lines[ WALKAROUND::WP_SHORTEST ];
244
245 LINE postShove( preShove );
246
247 shove.ForceClearance( true, cur.Gap() - 2 * PNS_HULL_MARGIN );
248
249 bool sh1;
250
251 sh1 = shove.ShoveObstacleLine( postWalk, preShove, postShove );
252
253 if( !sh1 )
254 return false;
255
256 postWalk.Line().Simplify();
257 postShove.Line().Simplify();
258
259 cur.SetShape( postWalk.CLine(), postShove.CLine(), !currentIsP );
260
261 currentIsP = !currentIsP;
262
263 if( !aNode->CheckColliding( &postShove, mask ) )
264 break;
265
266 iter++;
267 }
268 while( iter < 3 );
269
270 if( iter == 3 )
271 return false;
272
273 aWalk.SetShape( cur.CP(), cur.CN() );
274
275 return true;
276}
277
278
279bool DIFF_PAIR_PLACER::tryWalkDp( NODE* aNode, DIFF_PAIR &aPair, bool aSolidsOnly )
280{
281 DIFF_PAIR best;
282 double bestScore = 100000000000000.0;
283
284 for( int attempt = 0; attempt <= 3; attempt++ )
285 {
286 DIFF_PAIR p;
287 NODE *tmp = m_currentNode->Branch();
288
289 bool pfirst = ( attempt & 1 ) ? true : false;
290 bool wind_cw = ( attempt & 2 ) ? true : false;
291
292 if( attemptWalk( tmp, &aPair, p, pfirst, wind_cw, aSolidsOnly ) )
293 {
294 double cl = 1 + p.CoupledLength();
295 double skew = p.Skew();
296
297 double score = cl + fabs( skew ) * 3.0;
298
299 if( score < bestScore )
300 {
301 bestScore = score;
302 best = std::move( p );
303 }
304 }
305
306 delete tmp;
307 }
308
309 if( bestScore > 0.0 )
310 {
311 OPTIMIZER optimizer( m_currentNode );
312
313 aPair.SetShape( best );
314 optimizer.Optimize( &aPair );
315
316 return true;
317 }
318
319 return false;
320}
321
322
324{
325 if( !routeHead ( aP ) )
326 return false;
327
329
330 return m_fitOk;
331}
332
333
335{
336 switch( Settings().Mode() )
337 {
338 case RM_MarkObstacles:
339 return rhMarkObstacles( aP );
340 case RM_Walkaround:
341 return rhWalkOnly( aP );
342 case RM_Shove:
343 return rhShoveOnly( aP );
344 default:
345 break;
346 }
347
348 return false;
349}
350
351
353{
354 m_currentNode = m_shove->CurrentNode();
355
356 bool ok = routeHead( aP );
357
358 m_fitOk = false;
359
360 if( !ok )
361 return false;
362
363 if( !tryWalkDp( m_currentNode, m_currentTrace, true ) )
364 return false;
365
366 LINE pLine( m_currentTrace.PLine() );
367 LINE nLine( m_currentTrace.NLine() );
368 ITEM_SET head;
369
370 m_shove->ClearHeads();
371 m_shove->AddHeads( pLine );
372 m_shove->AddHeads( nLine );
373
374 SHOVE::SHOVE_STATUS status = m_shove->Run();
375
376 m_currentNode = m_shove->CurrentNode();
377
378 if( status == SHOVE::SH_OK )
379 {
380 m_currentNode = m_shove->CurrentNode();
381
382 if( m_shove->HeadsModified( 0 ))
383 pLine = m_shove->GetModifiedHead(0);
384
385 if( m_shove->HeadsModified( 1 ))
386 nLine = m_shove->GetModifiedHead(1);
387
388 // Update m_currentTrace with the shoved shapes so FixRoute() commits correct geometry
389 m_currentTrace.SetShape( pLine.CLine(), nLine.CLine() );
390
391 if( !m_currentNode->CheckColliding( &pLine ) &&
392 !m_currentNode->CheckColliding( &nLine ) )
393 {
394 m_fitOk = true;
395 }
396 }
397 else
398 {
399 // bring back previous state
400 m_currentTrace.SetShape( pLine.CLine(), nLine.CLine() );
401 }
402
403
404 return m_fitOk;
405}
406
407
409{
410 ITEM_SET t;
411
412 t.Add( &m_currentTrace.PLine() );
413 t.Add( &m_currentTrace.NLine() );
414
415 return t;
416}
417
418
420{
422
423 if( !m_idle )
424 Move( m_currentEnd, nullptr );
425}
426
427
428NODE* DIFF_PAIR_PLACER::CurrentNode( bool aLoopsRemoved ) const
429{
430 if( m_lastNode )
431 return m_lastNode;
432
433 return m_currentNode;
434}
435
436
438{
439 if( m_idle )
440 {
441 m_currentLayer = aLayer;
442 return true;
443 }
444 else if( m_chainedPlacement || !m_prevPair )
445 {
446 return false;
447 }
448 else if( !m_prevPair->PrimP() || ( m_prevPair->PrimP()->OfKind( ITEM::VIA_T ) &&
449 m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) )
450 {
451 m_currentLayer = aLayer;
454 Move( m_currentEnd, nullptr );
455 return true;
456 }
457
458 return false;
459}
460
461
463{
464 switch( aItem->Kind() )
465 {
466 case ITEM::LINE_T:
467 {
468 LINE* l = static_cast<LINE*>( aItem );
469
470 if( !l->PointCount() )
471 return OPT_VECTOR2I();
472 else
473 return l->CPoint( 0 );
474 }
475 case ITEM::VIA_T:
476 case ITEM::SOLID_T:
477 return aItem->Anchor( 0 );
478
479 case ITEM::ARC_T:
480 {
481 ARC* a = static_cast<ARC*>( aItem );
482
483 const JOINT* jA = aNode->FindJoint( aItem->Anchor( 0 ), aItem );
484 const JOINT* jB = aNode->FindJoint( aItem->Anchor( 1 ), aItem );
485
486 if( jA && jA->LinkCount() == 1 )
487 return a->Arc().GetP0();
488 else if( jB && jB->LinkCount() == 1 )
489 return a->Arc().GetP1();
490 else
491 return OPT_VECTOR2I();
492 }
493 case ITEM::SEGMENT_T:
494 {
495 SEGMENT* s = static_cast<SEGMENT*>( aItem );
496
497 const JOINT* jA = aNode->FindJoint( aItem->Anchor( 0 ), aItem );
498 const JOINT* jB = aNode->FindJoint( aItem->Anchor( 1 ), aItem );
499
500 if( jA && jA->LinkCount() == 1 )
501 return s->Seg().A;
502 else if( jB && jB->LinkCount() == 1 )
503 return s->Seg().B;
504 else
505 return OPT_VECTOR2I();
506 }
507
508 default:
509 return OPT_VECTOR2I();
510 }
511}
512
513
514
516 DP_PRIMITIVE_PAIR& aPair, wxString* aErrorMsg )
517{
518 NET_HANDLE netP, netN;
519
520 bool result = aWorld->GetRuleResolver()->DpNetPair( aItem, netP, netN );
521
522 if( !result )
523 {
524 if( aErrorMsg )
525 {
526 *aErrorMsg = _( "Unable to find complementary differential pair "
527 "nets. Make sure the names of the nets belonging "
528 "to a differential pair end with either N/P or +/-." );
529 }
530 return false;
531 }
532
533 NET_HANDLE refNet = aItem->Net();
534 NET_HANDLE coupledNet = ( refNet == netP ) ? netN : netP;
535
536 OPT_VECTOR2I refAnchor = getDanglingAnchor( aWorld, aItem );
537 ITEM* primRef = aItem;
538
539 if( !refAnchor )
540 {
541 if( aErrorMsg )
542 {
543 *aErrorMsg = _( "Can't find a suitable starting point. If starting "
544 "from an existing differential pair make sure you are "
545 "at the end." );
546 }
547
548 return false;
549 }
550
551 std::set<ITEM*> coupledItems;
552
553 aWorld->AllItemsInNet( coupledNet, coupledItems );
554 double bestDist = std::numeric_limits<double>::max();
555 bool found = false;
556
557 for( ITEM* item : coupledItems )
558 {
559 if( item->Kind() == aItem->Kind() )
560 {
561 OPT_VECTOR2I anchor = getDanglingAnchor( aWorld, item );
562
563 if( !anchor )
564 continue;
565
566 double dist = ( *anchor - *refAnchor ).EuclideanNorm();
567
568 bool shapeMatches = true;
569
570 if( item->OfKind( ITEM::SOLID_T | ITEM::VIA_T ) && item->Layers() != aItem->Layers() )
571 {
572 shapeMatches = false;
573 }
574
575 if( dist < bestDist && shapeMatches )
576 {
577 found = true;
578 bestDist = dist;
579
580 if( refNet != netP )
581 {
582 aPair = DP_PRIMITIVE_PAIR ( item, primRef );
583 aPair.SetAnchors( *anchor, *refAnchor );
584 }
585 else
586 {
587 aPair = DP_PRIMITIVE_PAIR( primRef, item );
588 aPair.SetAnchors( *refAnchor, *anchor );
589 }
590 }
591 }
592 }
593
594 if( !found )
595 {
596 if( aErrorMsg )
597 {
598 *aErrorMsg = wxString::Format( _( "Can't find a suitable starting point "
599 "for coupled net \"%s\"." ),
600 aWorld->GetRuleResolver()->NetName( coupledNet ) );
601 }
602
603 return false;
604 }
605
606 return true;
607}
608
609
611{
612 return m_sizes.EffectiveDiffPairViaGap();
613}
614
615
617{
618 return m_sizes.DiffPairGap() + m_sizes.DiffPairWidth();
619}
620
621
622bool DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
623{
624 VECTOR2I p( aP );
625
626 setWorld( Router()->GetWorld() );
628
629 wxString err_msg;
630
631 if( !FindDpPrimitivePair( m_currentNode, aP, aStartItem, m_start, &err_msg ) )
632 {
633 Router()->SetFailureReason( err_msg );
634 return false;
635 }
636
637 m_netP = m_start.PrimP()->Net();
638 m_netN = m_start.PrimN()->Net();
639
640 m_currentStart = p;
641 m_currentEnd = p;
642 m_placingVia = false;
643 m_chainedPlacement = false;
644 m_hasFixedAnything = false;
645 m_currentTraceOk = false;
647 m_currentTrace.SetNets( m_netP, m_netN );
648 m_lastFixNode = nullptr;
649
651
652 return true;
653}
654
655
657{
658 m_idle = false;
659 m_orthoMode = false;
660 m_currentEndItem = nullptr;
662
663 NODE* world = Router()->GetWorld();
664
665 world->KillChildren();
666 NODE* rootNode = world->Branch();
667
668 setWorld( rootNode );
669
670 m_lastNode = nullptr;
671 m_currentNode = rootNode;
672
673 m_shove = std::make_unique<SHOVE>( m_currentNode, Router() );
674}
675
676
678{
679 m_fitOk = false;
680
681 DP_GATEWAYS gwsEntry( gap() );
682 DP_GATEWAYS gwsTarget( gap() );
683
684 if( !m_prevPair )
686
688
689 DP_PRIMITIVE_PAIR target;
690
692 {
693 gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal );
694 m_snapOnTarget = true;
695 }
696 else
697 {
698 VECTOR2I fp;
699
700 if( !propagateDpHeadForces( aP, fp ) )
701 return false;
702
703 VECTOR2I midp, dirV;
704 m_prevPair->CursorOrientation( fp, midp, dirV );
705
706 VECTOR2I fpProj = SEG( midp, midp + dirV ).LineProject( fp );
707
708 // compute 'leader point' distance from the cursor (project cursor position
709 // on the extension of the starting segment pair of the DP)
710 int lead_dist = ( fpProj - fp ).EuclideanNorm();
711
712 gwsTarget.SetFitVias( m_placingVia, m_sizes.ViaDiameter(), viaGap() );
713
714 // far from the initial segment extension line -> allow a 45-degree obtuse turn
715 if( lead_dist > ( m_sizes.DiffPairGap() + m_sizes.DiffPairWidth() ) / 2 )
716 {
717 gwsTarget.BuildForCursor( fp );
718 }
719 else
720 {
721 // close to the initial segment extension line -> keep straight part only, project
722 // as close as possible to the cursor.
723 gwsTarget.BuildForCursor( fpProj );
725 DIRECTION_45( dirV ) );
726 }
727
728 m_snapOnTarget = false;
729 }
730
731 m_currentTrace.SetGap( gap() );
732 m_currentTrace.SetLayer( m_currentLayer );
733
734 bool result = gwsEntry.FitGateways( gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace );
735
736 if( result )
737 {
738 m_currentTraceOk = true;
739 m_currentTrace.SetNets( m_netP, m_netN );
740 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
741 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
742
743 if( m_placingVia )
744 {
745 m_currentTrace.AppendVias ( makeVia( m_currentTrace.CP().CLastPoint(), m_netP ),
746 makeVia( m_currentTrace.CN().CLastPoint(), m_netN ) );
747 }
748 else
749 {
750 m_currentTrace.RemoveVias();
751 }
752
753 return true;
754 }
755
756 return m_currentTraceOk;
757}
758
759
760bool DIFF_PAIR_PLACER::Move( const VECTOR2I& aP , ITEM* aEndItem )
761{
762 m_currentEndItem = aEndItem;
763 m_fitOk = false;
764
765 delete m_lastNode;
766 m_lastNode = nullptr;
767
768 bool retval = route( aP );
769
770 NODE* latestNode = m_currentNode;
771 m_lastNode = latestNode->Branch();
772
773 assert( m_lastNode != nullptr );
774 m_currentEnd = aP;
775
777
778 return retval;
779}
780
781
783{
784 int prevDiffPairWidth = m_sizes.DiffPairWidth();
785
786 m_sizes = aSizes;
787
788 if( !m_idle )
789 {
790 // When continuing from an existing track in connected-track-width mode, preserve the
791 // inherited diff pair width rather than reverting to the netclass default. This matches
792 // the guard in LINE_PLACER::UpdateSizes() for single tracks.
793 if( !m_sizes.TrackWidthIsExplicit() && m_hasFixedAnything )
794 m_sizes.SetDiffPairWidth( prevDiffPairWidth );
795
796 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
797 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
798
799 if( m_currentTrace.EndsWithVias() )
800 {
801 m_currentTrace.SetViaDiameter( m_sizes.ViaDiameter() );
802 m_currentTrace.SetViaDrill( m_sizes.ViaDrill() );
803 }
804 }
805}
806
807
808bool DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
809{
810 if( !m_fitOk && !Settings().AllowDRCViolations() )
811 return false;
812
813 if( m_currentTrace.CP().SegmentCount() < 1 || m_currentTrace.CN().SegmentCount() < 1 )
814 return false;
815
816 if( m_currentTrace.CP().SegmentCount() > 1 )
817 m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal();
818
819 TOPOLOGY topo( m_lastNode );
820
821 if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() && !aForceFinish &&
822 !Settings().GetFixAllSegments() )
823 {
824 SHAPE_LINE_CHAIN newP( m_currentTrace.CP() );
825 SHAPE_LINE_CHAIN newN( m_currentTrace.CN() );
826
827 if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 )
828 {
829 newP.Remove( -1, -1 );
830 newN.Remove( -1, -1 );
831 }
832
833 m_currentTrace.SetShape( newP, newN );
834 }
835
836 if( m_currentTrace.EndsWithVias() )
837 {
838 m_lastNode->Add( Clone( m_currentTrace.PLine().Via() ) );
839 m_lastNode->Add( Clone( m_currentTrace.NLine().Via() ) );
840 m_chainedPlacement = false;
841 }
842 else
843 {
844 m_chainedPlacement = !m_snapOnTarget && !aForceFinish;
845 }
846
847 LINE lineP( m_currentTrace.PLine() );
848 LINE lineN( m_currentTrace.NLine() );
849
850 m_lastNode->Add( lineP );
851 m_lastNode->Add( lineN );
852
853 topo.SimplifyLine( &lineP );
854 topo.SimplifyLine( &lineN );
855
856 m_prevPair = m_currentTrace.EndingPrimitives();
858
859 // avoid an use-after-free error (CommitPlacement calls NODE::Commit which will invalidate the shove heads state. Need to rethink the memory management).
860 if( Settings().Mode() == RM_Shove )
861 m_shove = std::make_unique<SHOVE>( m_world, Router() );
862
864 m_placingVia = false;
865 m_lastFixNode = nullptr;
866
867 if( m_snapOnTarget || aForceFinish )
868 {
869 m_idle = true;
870 return true;
871 }
872 else
873 {
874 m_hasFixedAnything = true;
876 return false;
877 }
878}
879
880
882{
883 m_world->KillChildren();
884 m_lastNode = nullptr;
885 return true;
886}
887
888
890{
891 return m_currentTrace.CP().SegmentCount() > 0 || m_currentTrace.CN().SegmentCount() > 0;
892}
893
894
896{
897 if( m_lastFixNode )
899
900 m_lastFixNode = nullptr;
901 m_lastNode = nullptr;
902 m_currentNode = nullptr;
903 return true;
904}
905
906
907void DIFF_PAIR_PLACER::GetModifiedNets( std::vector<NET_HANDLE> &aNets ) const
908{
909 aNets.push_back( m_netP );
910 aNets.push_back( m_netN );
911}
912
913
915{
916 SHAPE_LINE_CHAIN ratLineN, ratLineP;
917 TOPOLOGY topo( m_lastNode );
918
919 if( topo.LeadingRatLine( &m_currentTrace.PLine(), ratLineP ) )
920 m_router->GetInterface()->DisplayRatline( ratLineP, m_netP );
921
922 if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN ) )
923 m_router->GetInterface()->DisplayRatline( ratLineN, m_netN );
924}
925
926
927const std::vector<NET_HANDLE> DIFF_PAIR_PLACER::CurrentNets() const
928{
929 std::vector<NET_HANDLE> rv;
930 rv.push_back( m_netP );
931 rv.push_back( m_netN );
932 return rv;
933}
934
935}
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:83
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:242
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:157
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:492
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:252
RULE_RESOLVER * GetRuleResolver() const
Return the number of joints.
Definition pns_node.h:291
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:235
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:186
virtual bool DpNetPair(const ITEM *aItem, NET_HANDLE &aNetP, NET_HANDLE &aNetN)=0
virtual wxString NetName(NET_HANDLE aNet)=0
const SEG & Seg() const
The actual Push and Shove algorithm.
Definition pns_shove.h:47
void ForceClearance(bool aEnabled, int aClearance)
Definition pns_shove.h:91
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:227
void SetDiameter(int aLayer, int aDiameter)
Definition pns_via.h:234
const VECTOR2I & Pos() const
Definition pns_via.h:206
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_via.h:302
void SetPos(const VECTOR2I &aPos)
Definition pns_via.h:208
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:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
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:681
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
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:303
#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:35
int clearance
wxString result
Test unit parsing edge cases and error handling.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683