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 (C) 2016-2023 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 <optional>
23
24#include "pns_node.h"
25#include "pns_itemset.h"
26#include "pns_topology.h"
28#include "pns_diff_pair.h"
29#include "pns_router.h"
30#include "pns_solid.h"
31
32namespace PNS {
33
35 MEANDER_PLACER_BASE( aRouter )
36{
37 m_world = nullptr;
38 m_currentNode = nullptr;
39
40 m_padToDieP = 0;
41 m_padToDieN = 0;
42
43 // Init temporary variables (do not leave uninitialized members)
44 m_initialSegment = nullptr;
45 m_lastLength = 0;
47}
48
49
51{
52}
53
54
56{
57 return m_currentTraceP;
58}
59
60
62{
63 return m_originPair;
64}
65
66
67NODE* DP_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const
68{
69 if( !m_currentNode )
70 return m_world;
71
72 return m_currentNode;
73}
74
75
76bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
77{
78 if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
79 {
80 Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) );
81 return false;
82 }
83
84 m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
85 m_currentNode = nullptr;
87
88 m_world = Router()->GetWorld()->Branch();
89
90 TOPOLOGY topo( m_world );
91
93 {
94 Router()->SetFailureReason( _( "Unable to find complementary differential pair "
95 "net for length tuning. Make sure the names of the nets "
96 "belonging to a differential pair end with either _N/_P "
97 "or +/-." ) );
98 return false;
99 }
100
101 if( m_originPair.Gap() < 0 )
102 m_originPair.SetGap( Router()->Sizes().DiffPairGap() );
103
105 return false;
106
108
109 m_padToDieP = 0;
110
111 if( m_startPad_p )
113
114 if( m_endPad_p )
116
118
119 m_padToDieN = 0;
120
121 if( m_startPad_n )
123
124 if( m_endPad_n )
126
129
131
132 return true;
133}
134
135
137{
138}
139
140
142{
143 long long int totalP = m_padToDieP + lineLength( m_tunedPathP, m_startPad_p, m_endPad_p );
144 long long int totalN = m_padToDieN + lineLength( m_tunedPathN, m_startPad_n, m_endPad_n );
145 return std::max( totalP, totalN );
146}
147
148
150{
151 const VECTOR2I a( ( aCoupledSegs.coupledP.A + aCoupledSegs.coupledN.A ) / 2 );
152 const VECTOR2I b( ( aCoupledSegs.coupledP.B + aCoupledSegs.coupledN.B ) / 2 );
153
154 return SEG( a, b );
155}
156
157
159{
160 VECTOR2I midp = ( aPair.coupledP.A + aPair.coupledN.A ) / 2;
161
162 //DrawDebugPoint(midp, 6);
163
164 return aPair.coupledP.Side( midp ) > 0;
165}
166
167
168bool DP_MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
169{
170 if( m_currentStart == aP )
171 return false;
172
173 DIFF_PAIR::COUPLED_SEGMENTS_VEC coupledSegments;
174
175 if( m_currentNode )
176 delete m_currentNode;
177
179
180 SHAPE_LINE_CHAIN preP, tunedP, postP;
181 SHAPE_LINE_CHAIN preN, tunedN, postN;
182
183 m_originPair.CP().Split( m_currentStart, aP, preP, tunedP, postP );
184 m_originPair.CN().Split( m_currentStart, aP, preN, tunedN, postN );
185
186 auto updateStatus =
187 [&]()
188 {
193 else
195 };
196
197 DIFF_PAIR tuned( m_originPair );
198
199 tuned.SetShape( tunedP, tunedN );
200
201 tuned.CoupledSegmentPairs( coupledSegments );
202
203 if( coupledSegments.size() == 0 )
204 {
205 // Tuning started at an uncoupled area of the DP; we won't get a valid result until the
206 // cursor is moved far enough along a coupled area. Prevent the track from disappearing and
207 // the length from being zero by just using the original.
211 updateStatus();
212
213 return false;
214 }
215
216 m_result = MEANDERED_LINE( this, true );
217 m_result.SetWidth( tuned.Width() );
218
219 int offset = ( tuned.Gap() + tuned.Width() ) / 2;
220
221 if( pairOrientation( coupledSegments[0] ) )
222 offset *= -1;
223
224 m_result.SetBaselineOffset( offset );
225
226 for( const ITEM* item : m_tunedPathP.CItems() )
227 {
228 if( const LINE* l = dyn_cast<const LINE*>( item ) )
229 {
230 PNS_DBG( Dbg(), AddShape, &l->CLine(), YELLOW, 10000, wxT( "tuned-path-p" ) );
231
232 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
233 }
234 }
235
236 for( const ITEM* item : m_tunedPathN.CItems() )
237 {
238 if( const LINE* l = dyn_cast<const LINE*>( item ) )
239 {
240 PNS_DBG( Dbg(), AddShape, &l->CLine(), YELLOW, 10000, wxT( "tuned-path-n" ) );
241
242 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
243 }
244 }
245
246 int curIndexP = 0, curIndexN = 0;
247
248 for( const DIFF_PAIR::COUPLED_SEGMENTS& sp : coupledSegments )
249 {
250 SEG base = baselineSegment( sp );
251 bool side = false;
252
253 if( m_settings.m_initialSide == 0 )
254 side = base.Side( aP ) < 0;
255 else
256 side = m_settings.m_initialSide < 0;
257
258 PNS_DBG( Dbg(), AddShape, base, GREEN, 10000, wxT( "dp-baseline" ) );
259
260 while( sp.indexP >= curIndexP && curIndexP != -1 )
261 {
262 if( tunedP.IsArcSegment( curIndexP ) )
263 {
264 ssize_t arcIndex = tunedP.ArcIndex( curIndexP );
265
266 m_result.AddArcAndPt( tunedP.Arc( arcIndex ), tunedN.CPoint( curIndexN ) );
267 }
268 else
269 {
270 m_result.AddCorner( tunedP.CPoint( curIndexP ), tunedN.CPoint( curIndexN ) );
271 }
272
273 curIndexP = tunedP.NextShape( curIndexP );
274 }
275
276 while( sp.indexN >= curIndexN && curIndexN != -1 )
277 {
278 if( tunedN.IsArcSegment( curIndexN ) )
279 {
280 ssize_t arcIndex = tunedN.ArcIndex( curIndexN );
281
282 m_result.AddPtAndArc( tunedP.CPoint( sp.indexP ), tunedN.Arc( arcIndex ) );
283 }
284 else
285 {
286 m_result.AddCorner( tunedP.CPoint( sp.indexP ), tunedN.CPoint( curIndexN ) );
287 }
288
289 curIndexN = tunedN.NextShape( curIndexN );
290 }
291
292 m_result.MeanderSegment( base, side );
293 }
294
295 while( curIndexP < tunedP.PointCount() && curIndexP != -1 )
296 {
297 if( tunedP.IsArcSegment( curIndexP ) )
298 {
299 ssize_t arcIndex = tunedP.ArcIndex( curIndexP );
300
301 m_result.AddArcAndPt( tunedP.Arc( arcIndex ), tunedN.CPoint( curIndexN ) );
302 }
303 else
304 {
305 m_result.AddCorner( tunedP.CPoint( curIndexP ), tunedN.CPoint( curIndexN ) );
306 }
307
308 curIndexP = tunedP.NextShape( curIndexP );
309 }
310
311 while( curIndexN < tunedN.PointCount() && curIndexN != -1 )
312 {
313 if( tunedN.IsArcSegment( curIndexN ) )
314 {
315 ssize_t arcIndex = tunedN.ArcIndex( curIndexN );
316
317 m_result.AddPtAndArc( tunedP.CPoint( -1 ), tunedN.Arc( arcIndex ) );
318 }
319 else
320 {
321 m_result.AddCorner( tunedP.CPoint( -1 ), tunedN.CPoint( curIndexN ) );
322 }
323
324 curIndexN = tunedN.NextShape( curIndexN );
325 }
326
327 m_result.AddCorner( tunedP.CPoint( -1 ), tunedN.CPoint( -1 ) );
328
329 long long int dpLen = origPathLength();
330
332
333 if( dpLen > m_settings.m_targetLength.Max() )
334 {
336 m_lastLength = dpLen;
337 }
338 else
339 {
340 m_lastLength = dpLen - std::max( tunedP.Length(), tunedN.Length() );
342 }
343
344 if( m_lastStatus != TOO_LONG )
345 {
346 tunedP.Clear();
347 tunedN.Clear();
348
349 for( MEANDER_SHAPE* m : m_result.Meanders() )
350 {
351 if( m->Type() != MT_EMPTY )
352 {
353 tunedP.Append( m->CLine( 0 ) );
354 tunedN.Append( m->CLine( 1 ) );
355 }
356 }
357
358 m_lastLength += std::max( tunedP.Length(), tunedN.Length() );
359 updateStatus();
360 }
361
364
366 {
367 preP.Simplify();
368 tunedP.Simplify();
369 postP.Simplify();
370
371 m_finalShapeP.Append( preP );
372 m_finalShapeP.Append( tunedP );
373 m_finalShapeP.Append( postP );
374
375 preN.Simplify();
376 tunedN.Simplify();
377 postN.Simplify();
378
379 m_finalShapeN.Append( preN );
380 m_finalShapeN.Append( tunedN );
381 m_finalShapeN.Append( postN );
382 }
383 else
384 {
385 m_finalShapeP.Append( preP );
386 m_finalShapeP.Append( tunedP );
387 m_finalShapeP.Append( postP );
389
390 m_finalShapeN.Append( preN );
391 m_finalShapeN.Append( tunedN );
392 m_finalShapeN.Append( postN );
394 }
395
396 return true;
397}
398
399
400bool DP_MEANDER_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
401{
404
405 m_currentNode->Add( lP );
406 m_currentNode->Add( lN );
407
409
410 return true;
411}
412
413
415{
417 return true;
418}
419
420
422{
423 return m_originPair.CP().SegmentCount() > 0 || m_originPair.CN().SegmentCount() > 0;
424}
425
426
428{
429 if( m_currentNode )
431
432 m_currentNode = nullptr;
433 return true;
434}
435
436
438{
439 LINE l1( m_originPair.PLine(), aShape->CLine( 0 ) );
440 LINE l2( m_originPair.NLine(), aShape->CLine( 1 ) );
441
442 if( m_currentNode->CheckColliding( &l1 ) )
443 return false;
444
445 if( m_currentNode->CheckColliding( &l2 ) )
446 return false;
447
448 int w = aShape->Width();
449 int clearance = w + w * 3;
450
451 return m_result.CheckSelfIntersections( aShape, clearance );
452}
453
454
456{
459
460 ITEM_SET traces;
461
462 traces.Add( &m_currentTraceP );
463 traces.Add( &m_currentTraceN );
464
465 return traces;
466}
467
468
470{
471 ITEM_SET lines;
472
473 for( ITEM* item : m_tunedPathN )
474 lines.Add( item );
475
476 for( ITEM* item : m_tunedPathP )
477 lines.Add( item );
478
479 return lines;
480}
481
482
484{
485 return m_currentStart;
486}
487
488
490{
491 return m_currentEnd;
492}
493
494
496{
497 return m_initialSegment->Layers().Start();
498}
499
500
502{
503 if( m_lastLength )
504 return m_lastLength;
505 else
506 return origPathLength();
507}
508
509
511{
512 return m_lastStatus;
513}
514
515
516const std::vector<NET_HANDLE> DP_MEANDER_PLACER::CurrentNets() const
517{
518 std::vector<NET_HANDLE> rv;
519 rv.push_back( m_originPair.NetP() );
520 rv.push_back( m_originPair.NetN() );
521 return rv;
522}
523
524}
int Start() const
Definition: pns_layerset.h:82
T Min() const
Definition: minoptmax.h:33
T Max() const
Definition: minoptmax.h:34
T Opt() const
Definition: minoptmax.h:35
ROUTER * Router() const
Return current router settings.
Definition: pns_algo_base.h:54
ROUTER * m_router
Definition: pns_algo_base.h:87
DEBUG_DECORATOR * Dbg() const
Definition: pns_algo_base.h:78
Basic class for a differential pair.
const SHAPE_LINE_CHAIN & CN() const
int Width() const
std::vector< COUPLED_SEGMENTS > COUPLED_SEGMENTS_VEC
void SetShape(const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN &aN, bool aSwapLanes=false)
int Gap() const
NET_HANDLE NetP() const
void SetGap(int aGap)
const SHAPE_LINE_CHAIN & CP() const
void CoupledSegmentPairs(COUPLED_SEGMENTS_VEC &aPairs) const
NET_HANDLE NetN() 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
Function Traces()
bool pairOrientation(const DIFF_PAIR::COUPLED_SEGMENTS &aPair)
long long int TuningResult() const override
Return the resultant length or skew of the tuned traces.
DP_MEANDER_PLACER(ROUTER *aRouter)
VECTOR2I m_currentStart
Current world state.
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
Function CurrentLayer()
TUNING_STATUS TuningStatus() const override
Return the tuning status (too short, too long, etc.) of the trace(s) being tuned.
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
Function CurrentEnd()
const VECTOR2I & CurrentStart() const override
Function CurrentStart()
long long int origPathLength() const
Current routing start point (end of tail, beginning of head).
const std::vector< NET_HANDLE > CurrentNets() const override
Function CurrentNets()
NODE * CurrentNode(bool aLoopsRemoved=false) const override
Return the most recent world state.
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
const std::vector< ITEM * > & CItems() const
Definition: pns_itemset.h:88
Base class for PNS router board items.
Definition: pns_item.h:97
@ SEGMENT_T
Definition: pns_item.h:105
const LAYER_RANGE & Layers() const
Definition: pns_item.h:195
bool OfKind(int aKindMask) const
Definition: pns_item.h:174
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition: pns_line.h:61
int SegmentCount() const
Definition: pns_line.h:138
Represent a set of meanders fitted over a single or two lines.
Definition: pns_meander.h:424
void SetBaselineOffset(int aOffset)
Set the parallel offset between the base segment and the meandered line.
Definition: pns_meander.h:519
void SetWidth(int aWidth)
Set the line width.
Definition: pns_meander.h:504
void AddCorner(const VECTOR2I &aA, const VECTOR2I &aB=VECTOR2I(0, 0))
Create a dummy meander shape representing a line corner.
void MeanderSegment(const SEG &aSeg, bool aSide, int aBaseIndex=0)
Fit maximum amplitude meanders on a given segment and adds to the current line.
void AddArcAndPt(const SHAPE_ARC &aArc1, const VECTOR2I &aPt2)
Create a dummy meander shape representing an arc corner.
bool CheckSelfIntersections(MEANDER_SHAPE *aShape, int aClearance)
Check if the given shape is intersecting with any other meander in the current line.
std::vector< MEANDER_SHAPE * > & Meanders()
Definition: pns_meander.h:527
void AddPtAndArc(const VECTOR2I &aPt1, const SHAPE_ARC &aArc2)
Create a dummy meander shape representing an arc corner.
Base class for Single trace & Differential pair meandering tools, as both of them share a lot of code...
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
Meander settings.
MEANDER_SETTINGS m_settings
The current end point.
NODE * m_world
Width of the meandered trace(s).
VECTOR2I getSnappedStartPoint(LINKED_ITEM *aStartItem, VECTOR2I aStartPoint)
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)
MEANDER_SIDE m_initialSide
Allowable tuning error.
Definition: pns_meander.h:114
MINOPTMAX< long long int > m_targetLength
Target skew value for diff pair de-skewing.
Definition: pns_meander.h:97
The geometry of a single meander.
Definition: pns_meander.h:127
int Width() const
Definition: pns_meander.h:309
const SHAPE_LINE_CHAIN & CLine(int aShape) const
Definition: pns_meander.h:249
Keep the router "world" - i.e.
Definition: pns_node.h:207
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition: pns_node.cpp:143
OPT_OBSTACLE CheckColliding(const ITEM *aItem, int aKindMask=ITEM::ANY_T)
Check if the item collides with anything else in the world, and if found, returns the obstacle.
Definition: pns_node.cpp:410
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition: pns_node.cpp:663
void KillChildren()
Definition: pns_node.cpp:1496
void Remove(ARC *aArc)
Remove an item from this branch.
Definition: pns_node.cpp:884
virtual void DisplayPathLine(const SHAPE_LINE_CHAIN &aLine, int aImportance)=0
ROUTER_IFACE * GetInterface() const
Definition: pns_router.h:218
void SetFailureReason(const wxString &aReason)
Definition: pns_router.h:213
void CommitRouting()
Definition: pns_router.cpp:896
NODE * GetWorld() const
Definition: pns_router.h:164
int GetPadToDie() const
Definition: pns_solid.h:107
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
const ITEM_SET AssembleTuningPath(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:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition: seg.h:143
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 Split(const VECTOR2I &aP, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
void Simplify(int aMaxError=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
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.
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.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this 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:57
@ YELLOW
Definition: color4d.h:67
#define _(s)
Push and Shove diff pair dimensions (gap) settings dialog.
@ MT_EMPTY
Definition: pns_meander.h:47
#define PNS_DBG(dbg, method,...)