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() );
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 std::max( m_sizes.DiffPairViaGap(),
613 m_sizes.GetDiffPairHoleToHole() + m_sizes.ViaDrill() - m_sizes.ViaDiameter() );
614}
615
616
618{
619 return m_sizes.DiffPairGap() + m_sizes.DiffPairWidth();
620}
621
622
623bool DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
624{
625 VECTOR2I p( aP );
626
627 setWorld( Router()->GetWorld() );
629
630 wxString err_msg;
631
632 if( !FindDpPrimitivePair( m_currentNode, aP, aStartItem, m_start, &err_msg ) )
633 {
634 Router()->SetFailureReason( err_msg );
635 return false;
636 }
637
638 m_netP = m_start.PrimP()->Net();
639 m_netN = m_start.PrimN()->Net();
640
641 m_currentStart = p;
642 m_currentEnd = p;
643 m_placingVia = false;
644 m_chainedPlacement = false;
645 m_hasFixedAnything = 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 int prevDiffPairWidth = m_sizes.DiffPairWidth();
786
787 m_sizes = aSizes;
788
789 if( !m_idle )
790 {
791 // When continuing from an existing track in connected-track-width mode, preserve the
792 // inherited diff pair width rather than reverting to the netclass default. This matches
793 // the guard in LINE_PLACER::UpdateSizes() for single tracks.
794 if( !m_sizes.TrackWidthIsExplicit() && m_hasFixedAnything )
795 m_sizes.SetDiffPairWidth( prevDiffPairWidth );
796
797 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
798 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
799
800 if( m_currentTrace.EndsWithVias() )
801 {
802 m_currentTrace.SetViaDiameter( m_sizes.ViaDiameter() );
803 m_currentTrace.SetViaDrill( m_sizes.ViaDrill() );
804 }
805 }
806}
807
808
809bool DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
810{
811 if( !m_fitOk && !Settings().AllowDRCViolations() )
812 return false;
813
814 if( m_currentTrace.CP().SegmentCount() < 1 || m_currentTrace.CN().SegmentCount() < 1 )
815 return false;
816
817 if( m_currentTrace.CP().SegmentCount() > 1 )
818 m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal();
819
820 TOPOLOGY topo( m_lastNode );
821
822 if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() && !aForceFinish &&
823 !Settings().GetFixAllSegments() )
824 {
825 SHAPE_LINE_CHAIN newP( m_currentTrace.CP() );
826 SHAPE_LINE_CHAIN newN( m_currentTrace.CN() );
827
828 if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 )
829 {
830 newP.Remove( -1, -1 );
831 newN.Remove( -1, -1 );
832 }
833
834 m_currentTrace.SetShape( newP, newN );
835 }
836
837 if( m_currentTrace.EndsWithVias() )
838 {
839 m_lastNode->Add( Clone( m_currentTrace.PLine().Via() ) );
840 m_lastNode->Add( Clone( m_currentTrace.NLine().Via() ) );
841 m_chainedPlacement = false;
842 }
843 else
844 {
845 m_chainedPlacement = !m_snapOnTarget && !aForceFinish;
846 }
847
848 LINE lineP( m_currentTrace.PLine() );
849 LINE lineN( m_currentTrace.NLine() );
850
851 m_lastNode->Add( lineP );
852 m_lastNode->Add( lineN );
853
854 topo.SimplifyLine( &lineP );
855 topo.SimplifyLine( &lineN );
856
857 m_prevPair = m_currentTrace.EndingPrimitives();
859
860 // avoid an use-after-free error (CommitPlacement calls NODE::Commit which will invalidate the shove heads state. Need to rethink the memory management).
861 if( Settings().Mode() == RM_Shove )
862 m_shove = std::make_unique<SHOVE>( m_world, Router() );
863
865 m_placingVia = false;
866 m_lastFixNode = nullptr;
867
868 if( m_snapOnTarget || aForceFinish )
869 {
870 m_idle = true;
871 return true;
872 }
873 else
874 {
875 m_hasFixedAnything = true;
877 return false;
878 }
879}
880
881
883{
884 m_world->KillChildren();
885 m_lastNode = nullptr;
886 return true;
887}
888
889
891{
892 return m_currentTrace.CP().SegmentCount() > 0 || m_currentTrace.CN().SegmentCount() > 0;
893}
894
895
897{
898 if( m_lastFixNode )
900
901 m_lastFixNode = nullptr;
902 m_lastNode = nullptr;
903 m_currentNode = nullptr;
904 return true;
905}
906
907
908void DIFF_PAIR_PLACER::GetModifiedNets( std::vector<NET_HANDLE> &aNets ) const
909{
910 aNets.push_back( m_netP );
911 aNets.push_back( m_netN );
912}
913
914
916{
917 SHAPE_LINE_CHAIN ratLineN, ratLineP;
918 TOPOLOGY topo( m_lastNode );
919
920 if( topo.LeadingRatLine( &m_currentTrace.PLine(), ratLineP ) )
921 m_router->GetInterface()->DisplayRatline( ratLineP, m_netP );
922
923 if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN ) )
924 m_router->GetInterface()->DisplayRatline( ratLineN, m_netN );
925}
926
927
928const std::vector<NET_HANDLE> DIFF_PAIR_PLACER::CurrentNets() const
929{
930 std::vector<NET_HANDLE> rv;
931 rv.push_back( m_netP );
932 rv.push_back( m_netN );
933 return rv;
934}
935
936}
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:240
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:494
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:250
RULE_RESOLVER * GetRuleResolver() const
Return the number of joints.
Definition pns_node.h:278
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:231
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:182
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:90
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: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