KiCad PCB EDA Suite
Loading...
Searching...
No Matches
length_delay_calculation.cpp
Go to the documentation of this file.
1/*
2* This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <wx/log.h>
23
24#include <board.h>
26#include <footprint.h>
29#include <geometry/circle.h>
30#include <pad.h>
31#include <pcb_track.h>
32
33
35 const std::shared_ptr<SHAPE_POLY_SET>& aPadShape,
36 const VECTOR2I& aInsidePoint, VECTOR2I& aIntersection )
37{
38 bool found = false;
39 int64_t bestDistSq = std::numeric_limits<int64_t>::max();
40
41 for( int i = 0; i < aPadShape->OutlineCount(); i++ )
42 {
43 const SHAPE_LINE_CHAIN& outline = aPadShape->Outline( i );
44
45 for( int j = 0; j < outline.SegmentCount(); j++ )
46 {
47 const SEG& seg = outline.CSegment( j );
48 std::vector<VECTOR2I> intersections;
49
50 if( !aArc.IntersectLine( seg, &intersections ) )
51 continue;
52
53 for( const VECTOR2I& pt : intersections )
54 {
55 if( !seg.Contains( pt ) )
56 continue;
57
58 int64_t distSq = ( pt - aInsidePoint ).SquaredEuclideanNorm();
59
60 if( distSq < bestDistSq )
61 {
62 bestDistSq = distSq;
63 aIntersection = pt;
64 found = true;
65 }
66 }
67 }
68 }
69
70 return found;
71}
72
73
75 bool aForward )
76{
77 wxASSERT( aLine.PointCount() >= 2 );
78
79 const int start = aForward ? 0 : aLine.PointCount() - 1;
80 const int delta = aForward ? 1 : -1;
81
82 const auto& shape = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
83
84 // Find the first point OUTSIDE the pad
85 int firstOutside = -1;
86 VECTOR2I intersectionPt;
87 bool hasIntersection = false;
88
89 for( int vertex = start + delta; aForward ? vertex < aLine.PointCount() : vertex >= 0; vertex += delta )
90 {
91 if( !shape->Contains( aLine.GetPoint( vertex ) ) )
92 {
93 firstOutside = vertex;
94 int prevVertex = vertex - delta;
95
96 // Check if the crossing segment is part of an arc
97 ssize_t arcIdx = aLine.ArcIndex( prevVertex );
98
99 if( arcIdx >= 0 && aLine.ArcIndex( vertex ) == arcIdx )
100 {
101 hasIntersection = findArcPadIntersection( aLine.Arc( arcIdx ), shape, aLine.GetPoint( prevVertex ),
102 intersectionPt );
103 }
104
105 // Fallback to segment intersection if arc intersection didn't work
106 if( !hasIntersection )
107 {
108 SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( prevVertex ) );
109 VECTOR2I loc;
110
111 if( shape->Collide( seg, 0, nullptr, &loc ) )
112 {
113 intersectionPt = loc;
114 hasIntersection = true;
115 }
116 }
117
118 break;
119 }
120 }
121
122 if( firstOutside < 0 )
123 return; // All points inside pad, nothing to clip
124
125 // Build new chain using Slice (preserves arcs correctly without index corruption)
126 SHAPE_LINE_CHAIN newChain;
127
128 if( aForward )
129 {
130 // Chain: padCenter -> intersection -> [firstOutside to end]
131 newChain.Append( aPad->GetPosition() );
132 if( hasIntersection )
133 newChain.Append( intersectionPt );
134 newChain.Append( aLine.Slice( firstOutside, -1 ) );
135 }
136 else
137 {
138 // Chain: [0 to firstOutside] -> intersection -> padCenter
139 newChain.Append( aLine.Slice( 0, firstOutside ) );
140 if( hasIntersection )
141 newChain.Append( intersectionPt );
142 newChain.Append( aPad->GetPosition() );
143 }
144
145 aLine = newChain;
146}
147
148
150 std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems, const PATH_OPTIMISATIONS aOptimisations,
151 const PAD* aStartPad, const PAD* aEndPad, const LENGTH_DELAY_LAYER_OPT aLayerOpt,
152 const LENGTH_DELAY_DOMAIN_OPT aDomain, LENGTH_DELAY_ITEM_DETAILS* aPerItemLengthDelays ) const
153{
154 const bool doTrace = wxLog::IsAllowedTraceMask( wxT( "PNS_TUNE" ) );
155
156 if( doTrace )
157 {
158 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "" ) );
159 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "========== CalculateLengthDetails START ==========" ) );
160 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: input has %zu items" ), aItems.size() );
161 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: optimisations - OptimiseVias=%d, MergeTracks=%d, OptimiseTracesInPads=%d, InferViaInPad=%d" ),
162 aOptimisations.OptimiseVias, aOptimisations.MergeTracks,
163 aOptimisations.OptimiseTracesInPads, aOptimisations.InferViaInPad );
164
165 // Count initial items by type
166 int initialPads = 0, initialVias = 0, initialLines = 0, initialUnknown = 0;
167
168 for( const LENGTH_DELAY_CALCULATION_ITEM& item : aItems )
169 {
170 switch( item.Type() )
171 {
172 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD: initialPads++; break;
173 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA: initialVias++; break;
174 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE: initialLines++; break;
175 default: initialUnknown++; break;
176 }
177 }
178
179 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: initial items - PADs=%d, VIAs=%d, LINEs=%d, UNKNOWN=%d" ),
180 initialPads, initialVias, initialLines, initialUnknown );
181 }
182
183 // If this set of items has not been optimised, optimise for shortest electrical path
184 if( aOptimisations.OptimiseVias || aOptimisations.MergeTracks || aOptimisations.MergeTracks )
185 {
186 if( doTrace )
187 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: performing optimisations..." ) );
188
189 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
190 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> lines;
191 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> vias;
192
193 // Map of line endpoints to line objects
194 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> linesPositionMap;
195
196 // Map of pad positions to pad objects
197 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> padsPositionMap;
198
199 for( LENGTH_DELAY_CALCULATION_ITEM& item : aItems )
200 {
201 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
202 {
203 pads.emplace_back( &item );
204 padsPositionMap[item.GetPad()->GetPosition()].insert( &item );
205 }
206 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA )
207 {
208 vias.emplace_back( &item );
209 }
210 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
211 {
212 lines.emplace_back( &item );
213 linesPositionMap[item.GetLine().CPoint( 0 )].insert( &item );
214 linesPositionMap[item.GetLine().CLastPoint()].insert( &item );
215 }
216 }
217
218 if( aOptimisations.OptimiseVias )
219 {
220 if( doTrace )
221 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: optimising via layers (%zu vias)" ), vias.size() );
222
223 optimiseVias( vias, lines, linesPositionMap, padsPositionMap );
224 }
225
226 if( aOptimisations.MergeTracks )
227 {
228 if( doTrace )
229 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: merging tracks (%zu lines)" ), lines.size() );
230
231 mergeLines( lines, linesPositionMap );
232 }
233
234 // Clip traces inside VIA pads after merging
235 if( aOptimisations.OptimiseVias )
236 {
238 {
239 const PCB_VIA* pcbVia = via->GetVia();
240
241 for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : lines )
242 {
243 if( lineItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE )
244 {
245 continue;
246 }
247
248 OptimiseTraceInVia( lineItem->GetLine(), pcbVia, lineItem->GetStartLayer() );
249 }
250 }
251 }
252
253 if( aOptimisations.OptimiseTracesInPads )
254 {
255 if( doTrace )
256 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: optimising traces in pads" ) );
257
258 optimiseTracesInPads( pads, lines );
259 }
260 }
261
262 LENGTH_DELAY_STATS details;
263
264 // Create the layer detail maps if required
266 {
267 if( doTrace )
268 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: creating layer detail maps" ) );
269
270 details.LayerLengths = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
271
273 details.LayerDelays = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
274 }
275
276 const bool useHeight = m_board->GetDesignSettings().m_UseHeightForLengthCalcs;
277
278 if( doTrace )
279 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: useHeight=%d" ), useHeight );
280
281 // If this is a contiguous set of items, check if we have an inferred fanout via at either end. Note that this
282 // condition only arises as a result of how PNS assembles tuning paths - for DRC / net inspector calculations these
283 // fanout vias will be present in the object set and therefore do not need to be inferred
284 if( aOptimisations.InferViaInPad && useHeight )
285 {
286 if( doTrace )
287 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: inferring vias in pads" ) );
288
289 std::pair<int64_t, int64_t> inferredStartPadViaDetails{ 0, 0 };
290 std::pair<int64_t, int64_t> inferredEndPadViaDetails{ 0, 0 };
291
292 const bool withDelay = aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL;
293 inferViaInPad( aStartPad, aItems.front(), details, inferredStartPadViaDetails, withDelay );
294 inferViaInPad( aEndPad, aItems.back(), details, inferredEndPadViaDetails, withDelay );
295
296 if( aPerItemLengthDelays )
297 {
298 aPerItemLengthDelays->InferredStartViaLength = inferredStartPadViaDetails.first;
299 aPerItemLengthDelays->InferredStartViaDelay = inferredStartPadViaDetails.second;
300 aPerItemLengthDelays->InferredEndViaLength = inferredEndPadViaDetails.first;
301 aPerItemLengthDelays->InferredEndViaDelay = inferredEndPadViaDetails.second;
302 }
303 }
304
305 // Add stats for each item
306 int processedPads = 0, processedVias = 0, processedLines = 0;
307 int mergedRetired = 0, unknownType = 0;
308
309 // Output per-item details if required
310 if( aPerItemLengthDelays )
311 {
312 aPerItemLengthDelays->LengthsAndDelays.clear();
313 aPerItemLengthDelays->LengthsAndDelays.resize( aItems.size(), { 0, 0 } );
314 }
315
316 auto setPerItemLengthDetail = [aPerItemLengthDelays]( const size_t idx, const int64_t value )
317 {
318 if( !aPerItemLengthDelays )
319 return;
320
321 aPerItemLengthDelays->LengthsAndDelays[idx].first = value;
322 };
323
324 auto setPerItemDelayDetail = [aPerItemLengthDelays]( const size_t idx, const int64_t value )
325 {
326 if( !aPerItemLengthDelays )
327 return;
328
329 aPerItemLengthDelays->LengthsAndDelays[idx].second = value;
330 };
331
332 if( doTrace )
333 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: processing %zu items..." ), aItems.size() );
334
335 for( size_t i = 0; i < aItems.size(); ++i )
336 {
337 const LENGTH_DELAY_CALCULATION_ITEM& item = aItems[i];
338
339 // Don't include merged items
341 || item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
342 {
344 mergedRetired++;
345 else
346 unknownType++;
347 continue;
348 }
349
350 // Calculate the space domain statistics
351 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
352 {
353 const int64_t length = item.GetLine().Length();
354
355 setPerItemLengthDetail( i, length );
356 details.TrackLength += length;
357 processedLines++;
358
359 if( details.LayerLengths )
360 ( *details.LayerLengths )[item.GetStartLayer()] += length;
361 }
362 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
363 {
364 const auto [layerStart, layerEnd] = item.GetLayers();
365 int64_t viaHeight = StackupHeight( layerStart, layerEnd );
366 setPerItemLengthDetail( i, viaHeight );
367 details.ViaLength += static_cast<int>( viaHeight );
368 details.NumVias += 1;
369 processedVias++;
370
371 if( doTrace )
372 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: via from layer %d to %d, height=%lld" ),
373 layerStart, layerEnd, viaHeight );
374 }
375 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
376 {
377 int64_t padToDie = item.GetPad()->GetPadToDieLength();
378 setPerItemLengthDetail( i, padToDie );
379 details.PadToDieLength += static_cast<int>( padToDie );
380 details.NumPads += 1;
381 processedPads++;
382
383 if( doTrace && padToDie > 0 )
384 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: pad with pad-to-die length=%lld" ), padToDie );
385 }
386 }
387
388 if( doTrace )
389 {
390 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: processed items - PADs=%d, VIAs=%d, LINEs=%d" ),
391 processedPads, processedVias, processedLines );
392 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: skipped items - merged/retired=%d, unknown=%d" ),
393 mergedRetired, unknownType );
394 }
395
396 // Calculate the time domain statistics if required
397 if( aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL && !aItems.empty() )
398 {
399 if( doTrace )
400 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: calculating time domain statistics" ) );
401
402 // TODO(JJ): Populate this
404 ctx.NetClass = aItems.front().GetEffectiveNetClass(); // We don't care if this is merged for net class lookup
405
406 const std::vector<int64_t> itemDelays = m_tuningProfileParameters->GetPropagationDelays( aItems, ctx );
407
408 wxASSERT( itemDelays.size() == aItems.size() );
409
410 for( size_t i = 0; i < aItems.size(); ++i )
411 {
412 const LENGTH_DELAY_CALCULATION_ITEM& item = aItems[i];
413
415 || item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
416 {
417 continue;
418 }
419
420 setPerItemDelayDetail( i, itemDelays[i] );
421
422 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
423 {
424 details.TrackDelay += itemDelays[i];
425
426 if( details.LayerDelays )
427 ( *details.LayerDelays )[item.GetStartLayer()] += itemDelays[i];
428 }
429 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
430 {
431 details.ViaDelay += itemDelays[i];
432 }
433 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
434 {
435 details.PadToDieDelay += itemDelays[i];
436 }
437 }
438
439 if( doTrace )
440 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: total delays - Track=%lld, Via=%lld, PadToDie=%lld" ),
441 details.TrackDelay, details.ViaDelay, details.PadToDieDelay );
442 }
443
444 if( doTrace )
445 {
446 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: RESULTS:" ) );
447 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " Track length: %lld" ), details.TrackLength );
448 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " Via length: %d (from %d vias)" ), details.ViaLength, details.NumVias );
449 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " Pad-to-die length: %d (from %d pads)" ), details.PadToDieLength, details.NumPads );
450 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " TOTAL LENGTH: %lld" ), details.TotalLength() );
451 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "========== CalculateLengthDetails END ==========" ) );
452 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "" ) );
453 }
454
455 return details;
456}
457
458
460 LENGTH_DELAY_STATS& aDetails,
461 std::pair<int64_t, int64_t>& aInferredViaLengthDelay,
462 const bool aWithDelayDetail ) const
463{
464 if( aPad && aItem.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
465 {
466 const PCB_LAYER_ID startBottomLayer = aItem.GetStartLayer();
467 const LSET padLayers = aPad->Padstack().LayerSet();
468
469 if( !padLayers.Contains( startBottomLayer ) )
470 {
471 // This must be either F_Cu or B_Cu
472 const PCB_LAYER_ID padLayer = padLayers.Contains( F_Cu ) ? F_Cu : B_Cu;
473
474 aDetails.NumVias += 1;
475 const int64_t height = StackupHeight( startBottomLayer, padLayer );
476 aDetails.ViaLength += height;
477 aInferredViaLengthDelay.first = height;
478
479 // Look up via delay details if required
480 if( aWithDelayDetail )
481 {
483 ctx.NetClass = aItem.GetEffectiveNetClass();
484 const int64_t delay = m_tuningProfileParameters->GetViaPropagationDelay( startBottomLayer, padLayer,
485 F_Cu, B_Cu, ctx );
486 aDetails.ViaDelay += delay;
487 aInferredViaLengthDelay.second = delay;
488 }
489 }
490 }
491}
492
493
494int64_t LENGTH_DELAY_CALCULATION::CalculateLength( std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems,
495 const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad,
496 const PAD* aEndPad ) const
497{
498 return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad ).TotalLength();
499}
500
501
502int64_t LENGTH_DELAY_CALCULATION::CalculateDelay( std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems,
503 const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad,
504 const PAD* aEndPad ) const
505{
506 return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL,
508 .TotalDelay();
509}
510
511
512int LENGTH_DELAY_CALCULATION::StackupHeight( const PCB_LAYER_ID aFirstLayer, const PCB_LAYER_ID aSecondLayer ) const
513{
514 if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
515 return 0;
516
517 if( m_board->GetDesignSettings().m_HasStackup )
518 {
519 const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
520 return stackup.GetLayerDistance( aFirstLayer, aSecondLayer );
521 }
522 else
523 {
524 BOARD_STACKUP stackup;
525 stackup.BuildDefaultStackupList( &m_board->GetDesignSettings(), m_board->GetCopperLayerCount() );
526 return stackup.GetLayerDistance( aFirstLayer, aSecondLayer );
527 }
528}
529
530
532 std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
533 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap )
534{
535 // Vector of pads, and an associated flag to indicate whether they have been visited by the clustering algorithm
536 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
537
538 auto removeFromPositionMap = [&aLinesPositionMap]( LENGTH_DELAY_CALCULATION_ITEM* line )
539 {
540 aLinesPositionMap[line->GetLine().CPoint( 0 )].erase( line );
541 aLinesPositionMap[line->GetLine().CLastPoint()].erase( line );
542 };
543
544 // Attempts to merge unmerged lines in to aPrimaryLine
545 auto tryMerge = [&removeFromPositionMap, &aLinesPositionMap]( const MERGE_POINT aMergePoint,
546 const VECTOR2I& aMergePos,
547 const LENGTH_DELAY_CALCULATION_ITEM* aPrimaryItem,
548 SHAPE_LINE_CHAIN& aPrimaryLine, bool* aDidMerge )
549 {
550 const auto startItr = aLinesPositionMap.find( aMergePos );
551
552 if( startItr == aLinesPositionMap.end() )
553 return;
554
555 std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& startItems = startItr->second;
556
557 if( startItems.size() != 1 )
558 return;
559
560 LENGTH_DELAY_CALCULATION_ITEM* lineToMerge = *startItems.begin();
561
562 // Don't merge if lines are on different layers
563 if( aPrimaryItem->GetStartLayer() != lineToMerge->GetStartLayer() )
564 return;
565
566 // Merge the lines
568 mergeShapeLineChains( aPrimaryLine, lineToMerge->GetLine(), aMergePoint );
569 removeFromPositionMap( lineToMerge );
570 *aDidMerge = true;
571 };
572
573 // Cluster all lines in to contiguous entities
574 for( LENGTH_DELAY_CALCULATION_ITEM* primaryItem : aLines )
575 {
576 // Don't start with an already merged line
577 if( primaryItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::UNMERGED )
578 continue;
579
580 // Remove starting line from the position map
581 removeFromPositionMap( primaryItem );
582
583 SHAPE_LINE_CHAIN& primaryLine = primaryItem->GetLine();
584
585 // Merge all endpoints
587 bool mergeComplete = false;
588
589 while( !mergeComplete )
590 {
591 bool startMerged = false;
592 bool endMerged = false;
593
594 VECTOR2I startPos = primaryLine.CPoint( 0 );
595 VECTOR2I endPos = primaryLine.CLastPoint();
596
597 tryMerge( MERGE_POINT::START, startPos, primaryItem, primaryLine, &startMerged );
598 tryMerge( MERGE_POINT::END, endPos, primaryItem, primaryLine, &endMerged );
599
600 mergeComplete = !startMerged && !endMerged;
601 }
602 }
603}
604
605
607 const MERGE_POINT aMergePoint )
608{
609 // Append carries the arcs across and drops the shared point. Orient the
610 // secondary so its joining end meets the primary.
611 if( aMergePoint == MERGE_POINT::START )
612 {
613 // Secondary joins the primary's start, so build secondary + primary.
614 SHAPE_LINE_CHAIN merged =
615 ( aSecondary.GetPoint( 0 ) == aPrimary.GetPoint( 0 ) ) ? aSecondary.Reverse() : aSecondary;
616
617 wxASSERT( merged.CLastPoint() == aPrimary.GetPoint( 0 ) );
618
619 merged.Append( aPrimary );
620 aPrimary = merged;
621 }
622 else
623 {
624 if( aSecondary.GetPoint( 0 ) == aPrimary.CLastPoint() )
625 {
626 aPrimary.Append( aSecondary );
627 }
628 else
629 {
630 wxASSERT( aSecondary.CLastPoint() == aPrimary.CLastPoint() );
631 aPrimary.Append( aSecondary.Reverse() );
632 }
633 }
634}
635
636
637void LENGTH_DELAY_CALCULATION::optimiseTracesInPads( const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aPads,
638 const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines )
639{
640 for( LENGTH_DELAY_CALCULATION_ITEM* padItem : aPads )
641 {
642 const PAD* pad = padItem->GetPad();
643
644 for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : aLines )
645 {
646 // Ignore merged lines
647 if( lineItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE )
648 continue;
649
650 const PCB_LAYER_ID pcbLayer = lineItem->GetStartLayer();
651 SHAPE_LINE_CHAIN& line = lineItem->GetLine();
652
653 OptimiseTraceInPad( line, pad, pcbLayer );
654 }
655 }
656}
657
658
660 const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aVias, std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
661 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap,
662 const std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aPadsPositionMap ) const
663{
664 for( LENGTH_DELAY_CALCULATION_ITEM* via : aVias )
665 {
666 const PCB_VIA* pcbVia = via->GetVia();
667
668 std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*> connectedLines;
669
670 const VECTOR2I viaPos = pcbVia->GetPosition();
671
672 auto exactMatch = aLinesPositionMap.find( viaPos );
673
674 if( exactMatch != aLinesPositionMap.end() )
675 connectedLines.insert( exactMatch->second.begin(), exactMatch->second.end() );
676
677 int maxRadius = 0;
678
680 [&]( PCB_LAYER_ID layer )
681 {
682 maxRadius = std::max( maxRadius, pcbVia->GetWidth( layer ) / 2 );
683 } );
684
685 const int64_t maxRadiusSq = static_cast<int64_t>( maxRadius ) * maxRadius;
686
687 for( const auto& [pos, lineSet] : aLinesPositionMap )
688 {
689 if( pos == viaPos )
690 continue;
691
692 if( ( pos - viaPos ).SquaredEuclideanNorm() > maxRadiusSq )
693 continue;
694
695 for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : lineSet )
696 {
697 PCB_LAYER_ID layer = lineItem->GetStartLayer();
698 std::shared_ptr<SHAPE> shape = pcbVia->GetEffectiveShape( layer, FLASHING::ALWAYS_FLASHED );
699
700 if( shape && shape->Collide( pos, 0 ) )
701 connectedLines.insert( lineItem );
702 }
703 }
704
705 const PAD* coincidentPad = nullptr;
706
707 for( PAD* pad : m_board->GetConnectivity()->GetConnectedPads( pcbVia ) )
708 {
709 coincidentPad = pad;
710 break;
711 }
712
713 LSET spanLayers;
714
715 for( const LENGTH_DELAY_CALCULATION_ITEM* lineItem : connectedLines )
716 spanLayers.set( lineItem->GetStartLayer() );
717
718 if( coincidentPad )
719 {
720 PCB_LAYER_ID padSideLayer;
721
722 if( coincidentPad->GetAttribute() == PAD_ATTRIB::SMD || coincidentPad->GetAttribute() == PAD_ATTRIB::CONN )
723 {
724 padSideLayer = *coincidentPad->Padstack().LayerSet().CuStack().begin();
725 }
726 else
727 {
728 padSideLayer = coincidentPad->GetParentFootprint()->GetLayer();
729 }
730
731 spanLayers.set( padSideLayer );
732 }
733
734 wxLogTrace( wxT( "PNS_TUNE" ),
735 wxT( "optimiseVias: via@(%d,%d) connectedLines=%zu coincidentPad=%d "
736 "spanLayerCount=%d" ),
737 viaPos.x, viaPos.y, connectedLines.size(), coincidentPad ? 1 : 0,
738 static_cast<int>( spanLayers.count() ) );
739
740 const LSEQ cuStack = spanLayers.CuStack();
741
742 if( cuStack.empty() )
743 {
744 // Nothing connects to this via
745 via->SetLayers( pcbVia->GetLayer(), pcbVia->GetLayer() );
746 }
747 else if( cuStack.size() == 1 )
748 {
749 // Stub via
750 via->SetLayers( cuStack.front(), cuStack.front() );
751 }
752 else
753 {
754 // Signal transitions layers
755 via->SetLayers( cuStack.front(), cuStack.back() );
756 }
757 }
758}
759
760
762 const PCB_LAYER_ID aPcbLayer )
763{
764 // Only consider lines which terminate in the pad
765 if( aLine.CPoint( 0 ) != aPad->GetPosition() && aLine.CLastPoint() != aPad->GetPosition() )
766 return;
767
768 if( !aPad->FlashLayer( aPcbLayer ) )
769 return;
770
771 const auto& shape = aPad->GetEffectivePolygon( aPcbLayer, ERROR_INSIDE );
772
773 if( shape->Contains( aLine.CPoint( 0 ) ) )
774 clipLineToPad( aLine, aPad, aPcbLayer, true );
775 else if( shape->Contains( aLine.CLastPoint() ) )
776 clipLineToPad( aLine, aPad, aPcbLayer, false );
777}
778
779
781 bool aForward )
782{
783 wxASSERT( aLine.PointCount() >= 2 );
784
785 const int start = aForward ? 0 : aLine.PointCount() - 1;
786 const int delta = aForward ? 1 : -1;
787
788 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
789
790 if( !viaShape )
791 return;
792
793 const SHAPE_CIRCLE* viaCircle = dynamic_cast<const SHAPE_CIRCLE*>( viaShape.get() );
794
795 if( !viaCircle )
796 return;
797
798 // Find the first point OUTSIDE the via pad
799 int firstOutside = -1;
800 VECTOR2I intersectionPt;
801 bool hasIntersection = false;
802
803 for( int vertex = start + delta; aForward ? vertex < aLine.PointCount() : vertex >= 0; vertex += delta )
804 {
805 if( !viaShape->Collide( aLine.GetPoint( vertex ), 0 ) )
806 {
807 firstOutside = vertex;
808 int prevVertex = vertex - delta;
809
810 SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( prevVertex ) );
811
812 CIRCLE circle( viaCircle->GetCenter(), viaCircle->GetRadius() );
813
814 std::vector<VECTOR2I> pts = circle.Intersect( seg );
815
816 if( !pts.empty() )
817 {
818 // Pick the intersection closest to the outside vertex
819 VECTOR2I outside = aLine.GetPoint( vertex );
820 intersectionPt = pts[0];
821
822 for( size_t i = 1; i < pts.size(); i++ )
823 {
824 if( ( pts[i] - outside ).SquaredEuclideanNorm()
825 < ( intersectionPt - outside ).SquaredEuclideanNorm() )
826 {
827 intersectionPt = pts[i];
828 }
829 }
830
831 hasIntersection = true;
832 }
833
834 break;
835 }
836 }
837
838 if( firstOutside < 0 )
839 return;
840
841 SHAPE_LINE_CHAIN newChain;
842
843 if( aForward )
844 {
845 // viaCenter -> intersection -> [firstOutside to end]
846 newChain.Append( aVia->GetPosition() );
847
848 if( hasIntersection )
849 newChain.Append( intersectionPt );
850
851 newChain.Append( aLine.Slice( firstOutside, -1 ) );
852 }
853 else
854 {
855 // [0 to firstOutside] -> intersection -> viaCenter
856 newChain.Append( aLine.Slice( 0, firstOutside ) );
857
858 if( hasIntersection )
859 newChain.Append( intersectionPt );
860
861 newChain.Append( aVia->GetPosition() );
862 }
863
864 aLine = newChain;
865}
866
867
869{
870 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
871
872 if( !viaShape )
873 return;
874
875 if( viaShape->Collide( aLine.CPoint( 0 ), 0 ) )
876 clipLineToVia( aLine, aVia, aLayer, true );
877 else if( viaShape->Collide( aLine.CLastPoint(), 0 ) )
878 clipLineToVia( aLine, aVia, aLayer, false );
879}
880
881
883{
884 std::shared_ptr<SHAPE> shape = aVia->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
885 return shape && shape->Collide( aPoint, 0 );
886}
887
888
891{
892 if( const PCB_TRACK* track = dynamic_cast<const PCB_TRACK*>( aBoardItem ) )
893 {
894 if( track->Type() == PCB_VIA_T )
895 {
896 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
897
899 item.SetVia( via );
901 item.SetEffectiveNetClass( via->GetEffectiveNetClass() );
902
903 return item;
904 }
905
906 if( track->Type() == PCB_ARC_T )
907 {
908 const PCB_ARC* arcParent = static_cast<const PCB_ARC*>( track );
909 SHAPE_ARC shapeArc( arcParent->GetStart(), arcParent->GetMid(), arcParent->GetEnd(),
910 arcParent->GetWidth() );
911 SHAPE_LINE_CHAIN chainArc( shapeArc );
912
914 item.SetLine( chainArc );
915 item.SetLayers( track->GetLayer() );
916 item.SetEffectiveNetClass( arcParent->GetEffectiveNetClass() );
917
918 return item;
919 }
920
921 if( track->Type() == PCB_TRACE_T )
922 {
923 std::vector<VECTOR2I> points{ track->GetStart(), track->GetEnd() };
924 SHAPE_LINE_CHAIN shape( points );
925
927 item.SetLine( shape );
928 item.SetLayers( track->GetLayer() );
929 item.SetEffectiveNetClass( track->GetEffectiveNetClass() );
930
931 return item;
932 }
933 }
934 else if( const PAD* pad = dynamic_cast<const PAD*>( aBoardItem ) )
935 {
937 item.SetPad( pad );
938
939 const LSET& layers = pad->Padstack().LayerSet();
940 PCB_LAYER_ID firstLayer = UNDEFINED_LAYER;
941 PCB_LAYER_ID secondLayer = UNDEFINED_LAYER;
942
943 for( auto itr = layers.copper_layers_begin(); itr != layers.copper_layers_end(); ++itr )
944 {
945 if( firstLayer == UNDEFINED_LAYER )
946 firstLayer = *itr;
947 else
948 secondLayer = *itr;
949 }
950
951 item.SetLayers( firstLayer, secondLayer );
952 item.SetEffectiveNetClass( pad->GetEffectiveNetClass() );
953
954 return item;
955 }
956
957 return {};
958}
959
960
962 std::unique_ptr<TUNING_PROFILE_PARAMETERS_IFACE>&& aProvider )
963{
964 m_tuningProfileParameters = std::move( aProvider );
965}
966
967
972
973
974int64_t LENGTH_DELAY_CALCULATION::CalculateLengthForDelay( const int64_t aDesiredDelay,
975 const TUNING_PROFILE_GEOMETRY_CONTEXT& aCtx ) const
976{
977 return m_tuningProfileParameters->GetTrackLengthForPropagationDelay( aDesiredDelay, aCtx );
978}
979
980
982 const SHAPE_LINE_CHAIN& aShape, const TUNING_PROFILE_GEOMETRY_CONTEXT& aCtx ) const
983{
984 return m_tuningProfileParameters->CalculatePropagationDelayForShapeLineChain( aShape, aCtx );
985}
@ ERROR_INSIDE
BASE_SET & set(size_t pos)
Definition base_set.h:116
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.
FOOTPRINT * GetParentFootprint() const
Manage layers needed to make a physical board.
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Represent basic circle geometry with utility geometry functions.
Definition circle.h:33
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:417
Lightweight class which holds a pad, via, or a routed trace outline.
MERGE_STATUS GetMergeStatus() const
Gets the MERGE_STATUS of this item.
void SetLine(const SHAPE_LINE_CHAIN &aLine)
Sets the source SHAPE_LINE_CHAIN of this item.
void SetVia(const PCB_VIA *aVia)
Sets the VIA associated with this item.
TYPE Type() const
Gets the routing item type.
std::tuple< PCB_LAYER_ID, PCB_LAYER_ID > GetLayers() const
Gets the upper and lower layers for the proxied item.
void SetPad(const PAD *aPad)
Sets the parent PAD associated with this item.
void SetMergeStatus(const MERGE_STATUS aStatus)
Sets the MERGE_STATUS of this item.
const NETCLASS * GetEffectiveNetClass() const
Returns the effective net class for the item.
SHAPE_LINE_CHAIN & GetLine() const
Gets the SHAPE_LINE_CHAIN associated with this item.
const PAD * GetPad() const
Gets the parent PAD associated with this item.
PCB_LAYER_ID GetStartLayer() const
Gets the start board layer for the proxied item.
void SetEffectiveNetClass(const NETCLASS *aNetClass)
Sets the effective net class for the item.
void CalculateViaLayers(const BOARD *aBoard)
Calculates active via payers for a proxied VIA object.
void SetLayers(const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd=PCB_LAYER_ID::UNDEFINED_LAYER)
Sets the first and last layers associated with this item.
std::unique_ptr< TUNING_PROFILE_PARAMETERS_IFACE > m_tuningProfileParameters
The active provider of tuning profile parameters.
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Calculates the length of track required for the given delay in a specific geometry context.
void inferViaInPad(const PAD *aPad, const LENGTH_DELAY_CALCULATION_ITEM &aItem, LENGTH_DELAY_STATS &aDetails, std::pair< int64_t, int64_t > &aInferredViaLengthDelay, bool aWithDelayDetail) const
Infers if there is a via in the given pad.
int64_t CalculatePropagationDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Gets the propagation delay for the given shape line chain.
static void clipLineToPad(SHAPE_LINE_CHAIN &aLine, const PAD *aPad, PCB_LAYER_ID aLayer, bool aForward=true)
Clips the given line to the minimal direct electrical length within the pad.
MERGE_POINT
Enum to describe whether track merging is attempted from the start or end of a track segment.
static void optimiseTracesInPads(const std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aPads, const std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aLines)
Optimises the given set of items to minimise the electrical path length.
static void mergeLines(std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aLines, std::map< VECTOR2I, std::unordered_set< LENGTH_DELAY_CALCULATION_ITEM * > > &aLinesPositionMap)
Merges any lines (traces) that are contiguous, on one layer, and with no junctions.
int64_t CalculateDelay(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical propagation delay of the given items.
int64_t CalculateLength(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical length of the given items.
int StackupHeight(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Returns the stackup distance between the two given layers.
void SynchronizeTuningProfileProperties() const
Ensure time domain properties provider is synced with board / project settings if required.
LENGTH_DELAY_STATS CalculateLengthDetails(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr, LENGTH_DELAY_LAYER_OPT aLayerOpt=LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, LENGTH_DELAY_DOMAIN_OPT aDomain=LENGTH_DELAY_DOMAIN_OPT::NO_DELAY_DETAIL, LENGTH_DELAY_ITEM_DETAILS *aPerItemLengthDelays=nullptr) const
Calculates the electrical length of the given items.
static void OptimiseTraceInVia(SHAPE_LINE_CHAIN &aLine, const PCB_VIA *aVia, PCB_LAYER_ID aLayer)
Clips trace portions inside a VIA pad and replaces them with a straight-line segment from the VIA edg...
static void clipLineToVia(SHAPE_LINE_CHAIN &aLine, const PCB_VIA *aVia, PCB_LAYER_ID aLayer, bool aForward)
Clips the given line to the minimal direct electrical length within the via.
BOARD * m_board
The parent board for all items.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
void SetTuningProfileParametersProvider(std::unique_ptr< TUNING_PROFILE_PARAMETERS_IFACE > &&aProvider)
Sets the provider for tuning profile parameter resolution.
static void mergeShapeLineChains(SHAPE_LINE_CHAIN &aPrimary, const SHAPE_LINE_CHAIN &aSecondary, MERGE_POINT aMergePoint)
Merges two SHAPE_LINE_CHAINs where there is a shared endpoing.
static bool findArcPadIntersection(const SHAPE_ARC &aArc, const std::shared_ptr< SHAPE_POLY_SET > &aPadShape, const VECTOR2I &aInsidePoint, VECTOR2I &aIntersection)
Finds the intersection point between an arc and a pad shape.
void optimiseVias(const std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aVias, std::vector< LENGTH_DELAY_CALCULATION_ITEM * > &aLines, std::map< VECTOR2I, std::unordered_set< LENGTH_DELAY_CALCULATION_ITEM * > > &aLinesPositionMap, const std::map< VECTOR2I, std::unordered_set< LENGTH_DELAY_CALCULATION_ITEM * > > &aPadsPositionMap) const
Optimises the via layers.
static bool IsPointInsideViaPad(const PCB_VIA *aVia, const VECTOR2I &aPoint, PCB_LAYER_ID aLayer)
Returns true if the given point falls inside VIA pad shape on the given layer.
static void OptimiseTraceInPad(SHAPE_LINE_CHAIN &aLine, const PAD *aPad, PCB_LAYER_ID aPcbLayer)
Optimises the given trace / line to minimise the electrical path length within the given pad.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
copper_layers_iterator copper_layers_end() const
Definition lset.cpp:919
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:259
copper_layers_iterator copper_layers_begin() const
Definition lset.cpp:913
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
const LSET & LayerSet() const
Definition padstack.h:322
Definition pad.h:61
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition pad.cpp:650
PAD_ATTRIB GetAttribute() const
Definition pad.h:555
VECTOR2I GetPosition() const override
Definition pad.cpp:245
const PADSTACK & Padstack() const
Definition pad.h:326
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1194
int GetPadToDieLength() const
Definition pad.h:573
const VECTOR2I & GetMid() const
Definition pcb_track.h:286
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
const VECTOR2I & GetEnd() const
Definition pcb_track.h:90
virtual int GetWidth() const
Definition pcb_track.h:87
VECTOR2I GetPosition() const override
Definition pcb_track.h:553
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
const PADSTACK & Padstack() const
Definition pcb_track.h:402
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
int GetWidth() const override
Definition seg.h:38
bool Contains(const SEG &aSeg) const
Definition seg.h:320
int IntersectLine(const SEG &aSeg, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and aSeg, treating aSeg as an infinite line.
int GetRadius() const
const VECTOR2I GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
const SHAPE_ARC & Arc(size_t aArc) const
virtual const VECTOR2I GetPoint(int aIndex) const override
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 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.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
int SegmentCount() const
Return the number of segments in this line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
long long int Length() const
Return length of the line chain in Euclidean metric.
a few functions useful in geometry calculations.
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:182
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
LENGTH_DELAY_DOMAIN_OPT
Enum which controls the calculation domain of the length / delay calculation methods.
LENGTH_DELAY_LAYER_OPT
Enum which controls the level of detail returned by the length / delay calculation methods.
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:100
Used to represent the results of a call to CalculateLengthDetails, including inferred via-in-pad deta...
int64_t InferredEndViaLength
The length of an inferred end via-in-pad.
int64_t InferredStartViaLength
The length of an inferred start via-in-pad.
int64_t InferredEndViaDelay
The delay of an inferred end via-in-pad.
std::vector< std::pair< int64_t, int64_t > > LengthsAndDelays
Per-item lengths and delays.
int64_t InferredStartViaDelay
The delay of an inferred start via-in-pad.
Holds length measurement result details and statistics.
std::unique_ptr< std::map< PCB_LAYER_ID, int64_t > > LayerDelays
int64_t TotalLength() const
Calculates the total electrical length for this set of statistics.
std::unique_ptr< std::map< PCB_LAYER_ID, int64_t > > LayerLengths
int64_t TotalDelay() const
Calculates the total electrical propagation delay for this set of statistics.
Struct to control which optimisations the length calculation code runs on the given path objects.
bool InferViaInPad
Determines if there is a via-in-pad present on the board but not in the item set.
bool OptimiseVias
Optimise vias for electrical length calculations, including effective via span and trace clipping ins...
bool MergeTracks
Merges all contiguous (end-to-end, same layer) tracks.
bool OptimiseTracesInPads
Optimises the electrical length of tracks within pads.
A data structure to contain basic geometry data which can affect signal propagation calculations.
const NETCLASS * NetClass
The net class this track belongs to.
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
int delta
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:91
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:89
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683