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_hasFixedAnything = false;
647 m_currentTraceOk = false;
649 m_currentTrace.SetNets( m_netP, m_netN );
650 m_lastFixNode = nullptr;
651
653
654 return true;
655}
656
657
659{
660 m_idle = false;
661 m_orthoMode = false;
662 m_currentEndItem = nullptr;
664
665 NODE* world = Router()->GetWorld();
666
667 world->KillChildren();
668 NODE* rootNode = world->Branch();
669
670 setWorld( rootNode );
671
672 m_lastNode = nullptr;
673 m_currentNode = rootNode;
674
675 m_shove = std::make_unique<SHOVE>( m_currentNode, Router() );
676}
677
678
680{
681 m_fitOk = false;
682
683 DP_GATEWAYS gwsEntry( gap() );
684 DP_GATEWAYS gwsTarget( gap() );
685
686 if( !m_prevPair )
688
690
691 DP_PRIMITIVE_PAIR target;
692
694 {
695 gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal );
696 m_snapOnTarget = true;
697 }
698 else
699 {
700 VECTOR2I fp;
701
702 if( !propagateDpHeadForces( aP, fp ) )
703 return false;
704
705 VECTOR2I midp, dirV;
706 m_prevPair->CursorOrientation( fp, midp, dirV );
707
708 VECTOR2I fpProj = SEG( midp, midp + dirV ).LineProject( fp );
709
710 // compute 'leader point' distance from the cursor (project cursor position
711 // on the extension of the starting segment pair of the DP)
712 int lead_dist = ( fpProj - fp ).EuclideanNorm();
713
714 gwsTarget.SetFitVias( m_placingVia, m_sizes.ViaDiameter(), viaGap() );
715
716 // far from the initial segment extension line -> allow a 45-degree obtuse turn
717 if( lead_dist > ( m_sizes.DiffPairGap() + m_sizes.DiffPairWidth() ) / 2 )
718 {
719 gwsTarget.BuildForCursor( fp );
720 }
721 else
722 {
723 // close to the initial segment extension line -> keep straight part only, project
724 // as close as possible to the cursor.
725 gwsTarget.BuildForCursor( fpProj );
727 DIRECTION_45( dirV ) );
728 }
729
730 m_snapOnTarget = false;
731 }
732
733 m_currentTrace.SetGap( gap() );
734 m_currentTrace.SetLayer( m_currentLayer );
735
736 bool result = gwsEntry.FitGateways( gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace );
737
738 if( result )
739 {
740 m_currentTraceOk = true;
741 m_currentTrace.SetNets( m_netP, m_netN );
742 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
743 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
744
745 if( m_placingVia )
746 {
747 m_currentTrace.AppendVias ( makeVia( m_currentTrace.CP().CLastPoint(), m_netP ),
748 makeVia( m_currentTrace.CN().CLastPoint(), m_netN ) );
749 }
750 else
751 {
752 m_currentTrace.RemoveVias();
753 }
754
755 return true;
756 }
757
758 return m_currentTraceOk;
759}
760
761
762bool DIFF_PAIR_PLACER::Move( const VECTOR2I& aP , ITEM* aEndItem )
763{
764 m_currentEndItem = aEndItem;
765 m_fitOk = false;
766
767 delete m_lastNode;
768 m_lastNode = nullptr;
769
770 bool retval = route( aP );
771
772 NODE* latestNode = m_currentNode;
773 m_lastNode = latestNode->Branch();
774
775 assert( m_lastNode != nullptr );
776 m_currentEnd = aP;
777
779
780 return retval;
781}
782
783
785{
786 int prevDiffPairWidth = m_sizes.DiffPairWidth();
787
788 m_sizes = aSizes;
789
790 if( !m_idle )
791 {
792 // When continuing from an existing track in connected-track-width mode, preserve the
793 // inherited diff pair width rather than reverting to the netclass default. This matches
794 // the guard in LINE_PLACER::UpdateSizes() for single tracks.
795 if( !m_sizes.TrackWidthIsExplicit() && m_hasFixedAnything )
796 m_sizes.SetDiffPairWidth( prevDiffPairWidth );
797
798 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
799 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
800
801 if( m_currentTrace.EndsWithVias() )
802 {
803 m_currentTrace.SetViaDiameter( m_sizes.ViaDiameter() );
804 m_currentTrace.SetViaDrill( m_sizes.ViaDrill() );
805 }
806 }
807}
808
809
810bool DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
811{
812 if( !m_fitOk && !Settings().AllowDRCViolations() )
813 return false;
814
815 if( m_currentTrace.CP().SegmentCount() < 1 || m_currentTrace.CN().SegmentCount() < 1 )
816 return false;
817
818 if( m_currentTrace.CP().SegmentCount() > 1 )
819 m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal();
820
821 TOPOLOGY topo( m_lastNode );
822
823 if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() && !aForceFinish &&
824 !Settings().GetFixAllSegments() )
825 {
826 SHAPE_LINE_CHAIN newP( m_currentTrace.CP() );
827 SHAPE_LINE_CHAIN newN( m_currentTrace.CN() );
828
829 if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 )
830 {
831 newP.Remove( -1, -1 );
832 newN.Remove( -1, -1 );
833 }
834
835 m_currentTrace.SetShape( newP, newN );
836 }
837
838 if( m_currentTrace.EndsWithVias() )
839 {
840 m_lastNode->Add( Clone( m_currentTrace.PLine().Via() ) );
841 m_lastNode->Add( Clone( m_currentTrace.NLine().Via() ) );
842 m_chainedPlacement = false;
843 }
844 else
845 {
846 m_chainedPlacement = !m_snapOnTarget && !aForceFinish;
847 }
848
849 LINE lineP( m_currentTrace.PLine() );
850 LINE lineN( m_currentTrace.NLine() );
851
852 m_lastNode->Add( lineP );
853 m_lastNode->Add( lineN );
854
855 topo.SimplifyLine( &lineP );
856 topo.SimplifyLine( &lineN );
857
858 m_prevPair = m_currentTrace.EndingPrimitives();
860
861 // avoid an use-after-free error (CommitPlacement calls NODE::Commit which will invalidate the shove heads state. Need to rethink the memory management).
862 if( Settings().Mode() == RM_Shove )
863 m_shove = std::make_unique<SHOVE>( m_world, Router() );
864
866 m_placingVia = false;
867 m_lastFixNode = nullptr;
868
869 if( m_snapOnTarget || aForceFinish )
870 {
871 m_idle = true;
872 return true;
873 }
874 else
875 {
876 m_hasFixedAnything = true;
878 return false;
879 }
880}
881
882
884{
885 m_world->KillChildren();
886 m_lastNode = nullptr;
887 return true;
888}
889
890
892{
893 return m_currentTrace.CP().SegmentCount() > 0 || m_currentTrace.CN().SegmentCount() > 0;
894}
895
896
898{
899 if( m_lastFixNode )
901
902 m_lastFixNode = nullptr;
903 m_lastNode = nullptr;
904 m_currentNode = nullptr;
905 return true;
906}
907
908
909void DIFF_PAIR_PLACER::GetModifiedNets( std::vector<NET_HANDLE> &aNets ) const
910{
911 aNets.push_back( m_netP );
912 aNets.push_back( m_netN );
913}
914
915
917{
918 SHAPE_LINE_CHAIN ratLineN, ratLineP;
919 TOPOLOGY topo( m_lastNode );
920
921 if( topo.LeadingRatLine( &m_currentTrace.PLine(), ratLineP ) )
922 m_router->GetInterface()->DisplayRatline( ratLineP, m_netP );
923
924 if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN ) )
925 m_router->GetInterface()->DisplayRatline( ratLineN, m_netN );
926}
927
928
929const std::vector<NET_HANDLE> DIFF_PAIR_PLACER::CurrentNets() const
930{
931 std::vector<NET_HANDLE> rv;
932 rv.push_back( m_netP );
933 rv.push_back( m_netN );
934 return rv;
935}
936
937}
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:240
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:155
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:440
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:226
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:177
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