KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_dp_meander_placer.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2014 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 <optional>
23#include <algorithm>
24
25#include <core/typeinfo.h>
26
28
29#include "pns_node.h"
30#include "pns_itemset.h"
31#include "pns_topology.h"
33#include "pns_diff_pair.h"
34#include "pns_helpers.h"
35#include "pns_router.h"
36#include "pns_solid.h"
37
38
39namespace PNS {
40
42 MEANDER_PLACER_BASE( aRouter )
43{
44 m_world = nullptr;
45 m_currentNode = nullptr;
46
49
52
53 // Init temporary variables (do not leave uninitialized members)
54 m_initialSegment = nullptr;
55 m_lastLength = 0;
56 m_lastDelay = 0;
58
59 m_netClass = nullptr;
60}
61
62
66
67
69{
70 return m_currentTraceP;
71}
72
73
78
79
80NODE* DP_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const
81{
82 if( !m_currentNode )
83 return m_world;
84
85 return m_currentNode;
86}
87
88
89bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
90{
91 if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
92 {
93 Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) );
94 return false;
95 }
96
97 m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
98 m_currentNode = nullptr;
100
101 m_world = Router()->GetWorld()->Branch();
102
103 TOPOLOGY topo( m_world );
104
106 {
107 Router()->SetFailureReason( _( "Unable to find complementary differential pair "
108 "net for length tuning. Make sure the names of the nets "
109 "belonging to a differential pair end with either _N/_P "
110 "or +/-." ) );
111 return false;
112 }
113
114 if( m_originPair.Dimensions().Gap() < 0 )
115 m_originPair.SetGap( Router()->Sizes().DiffPairGap() );
116
117 if( !m_originPair.PLine().SegmentCount() || !m_originPair.NLine().SegmentCount() )
118 return false;
119
120 m_tunedPathP = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.PLine().GetLink( 0 ), &m_startPad_p,
121 &m_endPad_p );
122
125
126 if( m_startPad_p )
127 {
128 m_padToDieLengthP += m_startPad_p->GetPadToDie();
129 m_padToDieDelayP += m_startPad_p->GetPadToDieDelay();
130 }
131
132 if( m_endPad_p )
133 {
134 m_padToDieLengthP += m_endPad_p->GetPadToDie();
135 m_padToDieDelayP += m_endPad_p->GetPadToDieDelay();
136 }
137
138 m_tunedPathN = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.NLine().GetLink( 0 ), &m_startPad_n,
139 &m_endPad_n );
140
143
144 if( m_startPad_n )
145 {
146 m_padToDieLengthN += m_startPad_n->GetPadToDie();
147 m_padToDieDelayN += m_startPad_n->GetPadToDieDelay();
148 }
149
150 if( m_endPad_n )
151 {
152 m_padToDieLengthN += m_endPad_n->GetPadToDie();
153 m_padToDieDelayN += m_endPad_n->GetPadToDieDelay();
154 }
155
156 m_world->Remove( m_originPair.PLine() );
157 m_world->Remove( m_originPair.NLine() );
158
159 m_currentWidth = m_originPair.Dimensions().Width();
160
161 const BOARD_CONNECTED_ITEM* conItem = static_cast<BOARD_CONNECTED_ITEM*>( aStartItem->GetSourceItem() );
162 m_netClass = conItem->GetEffectiveNetClass();
163
166 m_baselineDelay = m_settings.m_isTimeDomain ? origPathDelay() : 0;
167 m_hasBaseline = true;
168
170
172
173 return true;
174}
175
176
180
181
183{
186 return std::max( totalP, totalN );
187}
188
189
191{
192 const int64_t totalP = m_padToDieDelayP + lineDelay( m_tunedPathP, m_startPad_p, m_endPad_p );
193 const int64_t totalN = m_padToDieDelayN + lineDelay( m_tunedPathN, m_startPad_n, m_endPad_n );
194 return std::max( totalP, totalN );
195}
196
197
199{
200 const VECTOR2I a( ( aCoupledSegs.coupledP.A + aCoupledSegs.coupledN.A ) / 2 );
201 const VECTOR2I b( ( aCoupledSegs.coupledP.B + aCoupledSegs.coupledN.B ) / 2 );
202
203 return SEG( a, b );
204}
205
206
208{
209 VECTOR2I midp = ( aPair.coupledP.A + aPair.coupledN.A ) / 2;
210
211 //DrawDebugPoint(midp, 6);
212
213 return aPair.coupledP.Side( midp ) > 0;
214}
215
216
217bool DP_MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
218{
219 m_hasMeanders = false;
220
221 // Reuse the chain-extras aggregate captured at Start(). Other nets in the chain are
222 // not edited during a tuning session, so we don't need to walk the BOARD again.
223 const long long extraDelay = m_chainExtrasValid ? m_chainExtrasDelay : 0;
224
225 m_settings.m_signalExtraDelay = extraDelay;
226
227 // Derive per-net budget from chain target, accounting for stubs not in the PNS path.
228 // Take the tighter of chain budget and existing per-net constraint.
229 if( m_settings.m_targetSignalLength.Opt() != MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
230 {
231 const long long otherLen = chainNarrowingOffset();
232
233 long long budgetMin = std::max( 0LL, m_settings.m_targetSignalLength.Min() - otherLen );
234 long long budgetOpt = std::max( 0LL, m_settings.m_targetSignalLength.Opt() - otherLen );
235 long long budgetMax = std::max( budgetOpt, m_settings.m_targetSignalLength.Max() - otherLen );
236
237 if( m_settings.m_targetLength.Opt() == MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
238 {
239 m_settings.m_targetLength.SetMin( budgetMin );
240 m_settings.m_targetLength.SetOpt( budgetOpt );
241 m_settings.m_targetLength.SetMax( budgetMax );
242 }
243 else
244 {
245 m_settings.m_targetLength.SetMin( std::max( m_settings.m_targetLength.Min(), budgetMin ) );
246 m_settings.m_targetLength.SetOpt( std::min( m_settings.m_targetLength.Opt(), budgetOpt ) );
247 m_settings.m_targetLength.SetMax( std::min( m_settings.m_targetLength.Max(), budgetMax ) );
248 }
249 }
250
252
253 if( m_currentStart == aP )
254 return false;
255
256 DIFF_PAIR::COUPLED_SEGMENTS_VEC coupledSegments;
257
258 if( m_currentNode )
259 delete m_currentNode;
260
261 m_currentNode = m_world->Branch();
262
263 SHAPE_LINE_CHAIN preP, tunedP, postP;
264 SHAPE_LINE_CHAIN preN, tunedN, postN;
265
266 m_originPair.CP().Split( m_currentStart, aP, preP, tunedP, postP );
267 m_originPair.CN().Split( m_currentStart, aP, preN, tunedN, postN );
268
269 tunedP.Simplify();
270 tunedN.Simplify();
271
272 // Bail out early if the tuned sections are empty (issue #22041). This can happen when the
273 // split points are too close together or outside the line chain.
274 if( tunedP.PointCount() == 0 || tunedN.PointCount() == 0 )
275 {
280
281 return false;
282 }
283
284 auto updateStatus =
285 [&]()
286 {
287 if( m_lastLength > m_settings.m_targetLength.Max() )
289 else if( m_lastLength < m_settings.m_targetLength.Min() )
291 else
293 };
294
295 DIFF_PAIR tuned( m_originPair );
296
297 tuned.SetShape( tunedP, tunedN );
298
299 tuned.CoupledSegmentPairs( coupledSegments );
300
301 if( coupledSegments.size() == 0 )
302 {
303 // Tuning started at an uncoupled area of the DP; we won't get a valid result until the
304 // cursor is moved far enough along a coupled area. Prevent the track from disappearing and
305 // the length from being zero by just using the original.
309 updateStatus();
310
311 return false;
312 }
313
314 m_result = MEANDERED_LINE( this, true );
315 m_result.SetWidth( tuned.Dimensions().Width() );
316
317 int offset = ( tuned.Dimensions().Gap() + tuned.Dimensions().Width() ) / 2;
318
319 if( pairOrientation( coupledSegments[0] ) )
320 offset *= -1;
321
322 m_result.SetBaselineOffset( offset );
323
324 for( const ITEM* item : m_tunedPathP.CItems() )
325 {
326 if( const LINE* l = dyn_cast<const LINE*>( item ) )
327 {
328 PNS_DBG( Dbg(), AddShape, &l->CLine(), YELLOW, 10000, wxT( "tuned-path-p" ) );
329
330 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
331 }
332 }
333
334 for( const ITEM* item : m_tunedPathN.CItems() )
335 {
336 if( const LINE* l = dyn_cast<const LINE*>( item ) )
337 {
338 PNS_DBG( Dbg(), AddShape, &l->CLine(), YELLOW, 10000, wxT( "tuned-path-n" ) );
339
340 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
341 }
342 }
343
344 struct GET_ITEM_RET
345 {
346 std::optional<SHAPE_ARC> arc;
347 VECTOR2I startPt;
348 VECTOR2I endPt;
349 };
350
351 auto getItem = [&]( const SHAPE_LINE_CHAIN& aChain, int aIndex, int aLastIndex )
352 {
353 std::optional<SHAPE_ARC> optArc;
354 VECTOR2I startPt;
355 VECTOR2I endPt;
356
357 if( aChain.IsArcSegment( aIndex ) )
358 {
359 SHAPE_ARC arc = aChain.Arc( aChain.ArcIndex( aIndex ) );
360 optArc = arc;
361 startPt = arc.GetStart();
362 endPt = arc.GetEnd();
363 }
364 else
365 {
366 SEG seg = aChain.GetSegment( aIndex );
367 startPt = seg.A;
368 endPt = seg.B;
369 }
370
371 return GET_ITEM_RET{ optArc, startPt, endPt };
372 };
373
374 auto checkIndex = [&]( bool& aOk, int aCurIndex, int aLastIndex ) -> bool
375 {
376 aOk = aCurIndex <= aLastIndex && aCurIndex != -1;
377 return aOk;
378 };
379
380 int curIndexP = 0, curIndexN = 0;
381
382 auto addCornersUntilIndex = [&]( int aLastIndexP, int aLastIndexN )
383 {
384 while( true )
385 {
386 bool p_ok, n_ok;
387 checkIndex( p_ok, curIndexP, aLastIndexP );
388 checkIndex( n_ok, curIndexN, aLastIndexN );
389
390 if( !p_ok && !n_ok )
391 break;
392
393 auto p_item = getItem( tunedP, curIndexP, aLastIndexP );
394 auto n_item = getItem( tunedN, curIndexN, aLastIndexN );
395
396 if( !p_item.arc && !n_item.arc )
397 {
398 m_result.AddCorner( p_item.startPt, n_item.startPt );
399 }
400 else if( p_item.arc && n_item.arc )
401 {
402 m_result.AddArc( *p_item.arc, *n_item.arc );
403 }
404 else if( p_item.arc && !n_item.arc )
405 {
406 m_result.AddCorner( p_item.startPt, n_item.startPt );
407
408 // Find arc in N
409 while( checkIndex( n_ok, curIndexN, aLastIndexN ) )
410 {
411 curIndexN = tunedN.NextShape( curIndexN );
412 n_item = getItem( tunedN, curIndexN, aLastIndexN );
413
414 if( n_item.arc )
415 {
416 m_result.AddArc( *p_item.arc, *n_item.arc );
417 break;
418 }
419 else
420 {
421 m_result.AddCorner( p_item.startPt, n_item.startPt );
422 }
423 }
424 }
425 else if( !p_item.arc && n_item.arc )
426 {
427 m_result.AddCorner( p_item.startPt, n_item.startPt );
428
429 // Find arc in P
430 while( checkIndex( p_ok, curIndexP, aLastIndexP ) )
431 {
432 curIndexP = tunedP.NextShape( curIndexP );
433 p_item = getItem( tunedP, curIndexP, aLastIndexP );
434
435 if( p_item.arc )
436 {
437 m_result.AddArc( *p_item.arc, *n_item.arc );
438 break;
439 }
440 else
441 {
442 m_result.AddCorner( p_item.startPt, n_item.startPt );
443 }
444 }
445 }
446
447 if( p_ok )
448 curIndexP = tunedP.NextShape( curIndexP );
449
450 if( n_ok )
451 curIndexN = tunedN.NextShape( curIndexN );
452 }
453 };
454
455 for( const DIFF_PAIR::COUPLED_SEGMENTS& sp : coupledSegments )
456 {
457 SEG base = baselineSegment( sp );
458 bool side = false;
459
460 if( m_settings.m_initialSide == 0 )
461 side = base.Side( aP ) < 0;
462 else
463 side = m_settings.m_initialSide < 0;
464
465 PNS_DBG( Dbg(), AddShape, base, GREEN, 10000, wxT( "dp-baseline" ) );
466
467 addCornersUntilIndex( sp.indexP, sp.indexN );
468
469 m_result.MeanderSegment( base, side );
470 }
471
472 addCornersUntilIndex( tunedP.PointCount() - 1, tunedN.PointCount() - 1 );
473
474 m_result.AddCorner( tunedP.CLastPoint(), tunedN.CLastPoint() );
475
476 long long int dpLen = origPathLength();
477 int64_t dpDelay = origPathDelay();
478
480
481 if( dpLen > m_settings.m_targetLength.Max() )
482 {
484 m_lastLength = dpLen;
485 m_lastDelay = dpDelay;
486 }
487 else
488 {
489 m_lastLength = dpLen - std::max( tunedP.Length(), tunedN.Length() );
490
491 if( m_settings.m_isTimeDomain )
492 {
493 int64_t tunedPDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
494 tunedP, GetOriginPair().Dimensions().Width(), true, GetOriginPair().Dimensions().Gap(), m_router->GetCurrentLayer(),
495 m_netClass );
496 int64_t tunedNDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
497 tunedN, GetOriginPair().Dimensions().Width(), true, GetOriginPair().Dimensions().Gap(), m_router->GetCurrentLayer(),
498 m_netClass );
499
500 m_lastDelay = dpDelay - std::max( tunedPDelay, tunedNDelay );
501 }
502
503 tuneLineLength( m_result, m_settings.m_targetLength.Opt() - dpLen );
504 }
505
506 if( m_lastStatus != TOO_LONG )
507 {
508 tunedP.Clear();
509 tunedN.Clear();
510
511 for( MEANDER_SHAPE* m : m_result.Meanders() )
512 {
513 if( m->Type() != MT_EMPTY )
514 {
515 tunedP.Append( m->CLine( 0 ) );
516 tunedN.Append( m->CLine( 1 ) );
517 m_hasMeanders |= m->IsMeander();
518 }
519 }
520
521 m_lastLength += std::max( tunedP.Length(), tunedN.Length() );
522
523 if( m_settings.m_isTimeDomain )
524 {
525 int64_t tunedPDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
526 tunedP, GetOriginPair().Dimensions().Width(), true, GetOriginPair().Dimensions().Gap(), m_router->GetCurrentLayer(),
527 m_netClass );
528 int64_t tunedNDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
529 tunedN, GetOriginPair().Dimensions().Width(), true, GetOriginPair().Dimensions().Gap(), m_router->GetCurrentLayer(),
530 m_netClass );
531
532 m_lastDelay += std::max( tunedPDelay, tunedNDelay );
533 }
534
535 updateStatus();
536 }
537
538 m_finalShapeP.Clear();
539 m_finalShapeN.Clear();
540
541 if( m_settings.m_keepEndpoints )
542 {
543 preP.Simplify();
544 tunedP.Simplify();
545 postP.Simplify();
546
547 m_finalShapeP.Append( preP );
548 m_finalShapeP.Append( tunedP );
549 m_finalShapeP.Append( postP );
550
551 preN.Simplify();
552 tunedN.Simplify();
553 postN.Simplify();
554
555 m_finalShapeN.Append( preN );
556 m_finalShapeN.Append( tunedN );
557 m_finalShapeN.Append( postN );
558 }
559 else
560 {
561 m_finalShapeP.Append( preP );
562 m_finalShapeP.Append( tunedP );
563 m_finalShapeP.Append( postP );
564 m_finalShapeP.Simplify();
565
566 m_finalShapeN.Append( preN );
567 m_finalShapeN.Append( tunedN );
568 m_finalShapeN.Append( postN );
569 m_finalShapeN.Simplify();
570 }
571
572 return true;
573}
574
575
576bool DP_MEANDER_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
577{
578 LINE lP( m_originPair.PLine(), m_finalShapeP );
579 LINE lN( m_originPair.NLine(), m_finalShapeN );
580
581 m_currentNode->Add( lP );
582 m_currentNode->Add( lN );
583
585
586 return true;
587}
588
589
591{
592 m_world->KillChildren();
593 return true;
594}
595
596
598{
599 return m_originPair.CP().SegmentCount() > 0 || m_originPair.CN().SegmentCount() > 0;
600}
601
602
604{
605 if( m_currentNode )
607
608 m_currentNode = nullptr;
609 return true;
610}
611
612
614{
615 LINE l1( m_originPair.PLine(), aShape->CLine( 0 ) );
616 LINE l2( m_originPair.NLine(), aShape->CLine( 1 ) );
617
618 if( m_currentNode->CheckColliding( &l1 ) )
619 return false;
620
621 if( m_currentNode->CheckColliding( &l2 ) )
622 return false;
623
624 int w = aShape->Width();
625 int clearance = w + w * 3;
626
627 return m_result.CheckSelfIntersections( aShape, clearance );
628}
629
630
632{
635
636 ITEM_SET traces;
637
638 traces.Add( &m_currentTraceP );
639 traces.Add( &m_currentTraceN );
640
641 return traces;
642}
643
644
646{
647 ITEM_SET lines;
648
649 for( ITEM* item : m_tunedPathN )
650 lines.Add( item );
651
652 for( ITEM* item : m_tunedPathP )
653 lines.Add( item );
654
655 return lines;
656}
657
658
660{
661 return m_currentStart;
662}
663
664
666{
667 return m_currentEnd;
668}
669
670
672{
673 return m_initialSegment->Layers().Start();
674}
675
676
678{
679 if( m_lastLength )
680 return m_lastLength;
681 else
682 return origPathLength();
683}
684
685
687{
688 if( m_lastDelay )
689 return m_lastDelay;
690 else
691 return origPathDelay();
692}
693
694
699
700
701const std::vector<NET_HANDLE> DP_MEANDER_PLACER::CurrentNets() const
702{
703 std::vector<NET_HANDLE> rv;
704 rv.push_back( m_originPair.NetP() );
705 rv.push_back( m_originPair.NetN() );
706 return rv;
707}
708
709
711{
712 // If this is a time domain tuning, calculate the target length for the desired total delay
713 if( m_settings.m_isTimeDomain )
714 {
715 const int64_t curDelayChain = origPathDelay();
716 const int64_t curDelayPair = curDelayChain - m_settings.m_signalExtraDelay; // subtract other nets
717
718 bool useSignalTarget = ( m_settings.m_targetSignalLengthDelay.Opt() != MEANDER_SETTINGS::DELAY_UNCONSTRAINED );
719 const MINOPTMAX<long long int>& targetDelaySet = useSignalTarget ? m_settings.m_targetSignalLengthDelay
720 : m_settings.m_targetLengthDelay;
721
722 int64_t desiredDelayMin = targetDelaySet.Min();
723 int64_t desiredDelayOpt = targetDelaySet.Opt();
724 int64_t desiredDelayMax = targetDelaySet.Max();
725
726 if( useSignalTarget )
727 {
728 desiredDelayMin = std::max<int64_t>( 0, desiredDelayMin - m_settings.m_signalExtraDelay );
729 desiredDelayOpt = std::max<int64_t>( 0, desiredDelayOpt - m_settings.m_signalExtraDelay );
730 desiredDelayMax = std::max<int64_t>( desiredDelayOpt, desiredDelayMax - m_settings.m_signalExtraDelay );
731 }
732
733 const int64_t curDelay = useSignalTarget ? curDelayPair : curDelayChain;
734
735 const int64_t delayDifferenceOpt = desiredDelayOpt - curDelay;
736
737 const int64_t curLength = origPathLength();
738 const int64_t lengthDiffMin = m_router->GetInterface()->CalculateLengthForDelay(
739 desiredDelayOpt - desiredDelayMin, GetOriginPair().Dimensions().Width(), true, GetOriginPair().Dimensions().Gap(),
740 m_router->GetCurrentLayer(), m_netClass );
741 int64_t lengthDiffOpt = m_router->GetInterface()->CalculateLengthForDelay(
742 std::abs( delayDifferenceOpt ), GetOriginPair().Dimensions().Width(), true, GetOriginPair().Dimensions().Gap(),
743 m_router->GetCurrentLayer(), m_netClass );
744 const int64_t lengthDiffMax = m_router->GetInterface()->CalculateLengthForDelay(
745 desiredDelayMax - desiredDelayOpt, GetOriginPair().Dimensions().Width(), true, GetOriginPair().Dimensions().Gap(),
746 m_router->GetCurrentLayer(), m_netClass );
747
748 lengthDiffOpt = delayDifferenceOpt > 0 ? lengthDiffOpt : -lengthDiffOpt;
749
750 m_settings.m_targetLength.SetMin( curLength + lengthDiffOpt - lengthDiffMin );
751 m_settings.m_targetLength.SetOpt( curLength + lengthDiffOpt );
752 m_settings.m_targetLength.SetMax( curLength + lengthDiffOpt + lengthDiffMax );
753 }
754}
755}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
T Min() const
Definition minoptmax.h:29
T Max() const
Definition minoptmax.h:30
T Opt() const
Definition minoptmax.h:31
ROUTER * Router() const
Return the instance of our router.
ROUTER * m_router
DEBUG_DECORATOR * Dbg() const
Basic class for a differential pair.
std::vector< COUPLED_SEGMENTS > COUPLED_SEGMENTS_VEC
const DP_DIMENSIONS & Dimensions() const
void SetShape(const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN &aN, bool aSwapLanes=false)
void CoupledSegmentPairs(COUPLED_SEGMENTS_VEC &aPairs, bool aUseGapConstraint=true, const std::optional< DP_GAP_CONSTRAINT > &aOverrideGapConstraint=std::optional< DP_GAP_CONSTRAINT >()) const
bool Start(const VECTOR2I &aP, ITEM *aStartItem) override
Start routing a single track at point aP, taking item aStartItem as anchor (unless NULL).
bool CheckFit(MEANDER_SHAPE *aShape) override
Checks if it's OK to place the shape aShape (i.e.
const ITEM_SET Traces() override
Return all routed/tuned traces.
bool pairOrientation(const DIFF_PAIR::COUPLED_SEGMENTS &aPair)
VECTOR2I m_currentStart
Current routing start point (end of tail, beginning of head).
bool FixRoute(const VECTOR2I &aP, ITEM *aEndItem, bool aForceFinish=false) override
Commit the currently routed track to the parent node, taking aP as the final end point and aEndItem a...
int CurrentLayer() const override
Return the layer of currently routed track.
TUNING_STATUS TuningStatus() const override
Return the tuning status (too short, too long, etc.) of the trace(s) being tuned.
long long int TuningLengthResult() const override
Return the resultant length or skew of the tuned traces.
const SEG baselineSegment(const DIFF_PAIR::COUPLED_SEGMENTS &aCoupledSegs)
const DIFF_PAIR & GetOriginPair()
const ITEM_SET TunedPath() override
bool HasPlacedAnything() const override
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).
const VECTOR2I & CurrentEnd() const override
Return the current end of the line(s) being placed/tuned.
const VECTOR2I & CurrentStart() const override
Return the current start of the line(s) being placed/tuned.
NODE * m_currentNode
Current world state.
int64_t TuningDelayResult() const override
Return the resultant delay or skew of the tuned traces.
long long int origPathLength() const
const std::vector< NET_HANDLE > CurrentNets() const override
Returns the net(s) of currently routed track(s).
NODE * CurrentNode(bool aLoopsRemoved=false) const override
Return the most recent world state.
void Add(const LINE &aLine)
Base class for PNS router board items.
Definition pns_item.h:98
BOARD_ITEM * GetSourceItem() const
Definition pns_item.h:202
bool OfKind(int aKindMask) const
Definition pns_item.h:181
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
Represent a set of meanders fitted over a single or two lines.
long long int chainNarrowingOffset() const
Return the length offset to subtract when converting a user-facing total signal length target into a ...
void tuneLineLength(MEANDERED_LINE &aTuned, long long int aElongation)
Take a set of meanders in aTuned and tunes their length to extend the original line length by aElonga...
TUNING_STATUS
Result of the length tuning operation.
int m_currentWidth
Width of the meandered trace(s).
long long int m_startPathLength
Active path length at Start().
VECTOR2I m_currentEnd
The current end point.
void initChainExtras()
Cache the per-session chain-extras length/delay (other nets in the same chain) so per-Move use does n...
MEANDER_SETTINGS m_settings
Meander settings.
int64_t lineDelay(const ITEM_SET &aLine, const SOLID *aStartPad, const SOLID *aEndPad) const
Calculate the total delay of the line represented by an item set (tracks and vias)
NODE * m_world
Pointer to world to search colliding items.
long long int lineLength(const ITEM_SET &aLine, const SOLID *aStartPad, const SOLID *aEndPad) const
Calculate the total length of the line represented by an item set (tracks and vias)
long long int m_baselineLength
The tuning results as they were at Start(). The deltas measure change from these.
static const long long int LENGTH_UNCONSTRAINED
Definition pns_meander.h:73
static const long long int DELAY_UNCONSTRAINED
Definition pns_meander.h:76
int Width() const
const SHAPE_LINE_CHAIN & CLine(int aShape) const
Keep the router "world" - i.e.
Definition pns_node.h:244
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:163
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:260
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:211
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
const ITEM_SET AssembleTuningPath(ROUTER_IFACE *aRouterIface, ITEM *aStart, SOLID **aStartPad=nullptr, SOLID **aEndPad=nullptr)
Like AssembleTrivialPath, but follows the track length algorithm, which discards segments that are fu...
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition seg.h:139
VECTOR2I GetEnd() const override
Definition shape_arc.h:208
VECTOR2I GetStart() const override
Definition shape_arc.h:207
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
virtual const SEG GetSegment(int aIndex) const override
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
bool IsArcSegment(size_t aSegment) const
long long int Length() const
Return length of the line chain in Euclidean metric.
@ GREEN
Definition color4d.h:53
@ YELLOW
Definition color4d.h:63
#define _(s)
Push and Shove diff pair dimensions (gap) settings dialog.
@ MT_EMPTY
Definition pns_meander.h:49
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
#define PNS_DBG(dbg, method,...)
static VECTOR2I GetSnappedStartPoint(LINKED_ITEM *aStartItem, VECTOR2I aStartPoint)
int clearance
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:55
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708