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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <wx/log.h>
27
28#include <board.h>
30#include <footprint.h>
33#include <geometry/circle.h>
34#include <pad.h>
35#include <pcb_track.h>
36
37
39 const std::shared_ptr<SHAPE_POLY_SET>& aPadShape,
40 const VECTOR2I& aInsidePoint, VECTOR2I& aIntersection )
41{
42 bool found = false;
43 int64_t bestDistSq = std::numeric_limits<int64_t>::max();
44
45 for( int i = 0; i < aPadShape->OutlineCount(); i++ )
46 {
47 const SHAPE_LINE_CHAIN& outline = aPadShape->Outline( i );
48
49 for( int j = 0; j < outline.SegmentCount(); j++ )
50 {
51 const SEG& seg = outline.CSegment( j );
52 std::vector<VECTOR2I> intersections;
53
54 if( !aArc.IntersectLine( seg, &intersections ) )
55 continue;
56
57 for( const VECTOR2I& pt : intersections )
58 {
59 if( !seg.Contains( pt ) )
60 continue;
61
62 int64_t distSq = ( pt - aInsidePoint ).SquaredEuclideanNorm();
63
64 if( distSq < bestDistSq )
65 {
66 bestDistSq = distSq;
67 aIntersection = pt;
68 found = true;
69 }
70 }
71 }
72 }
73
74 return found;
75}
76
77
79 bool aForward )
80{
81 wxASSERT( aLine.PointCount() >= 2 );
82
83 const int start = aForward ? 0 : aLine.PointCount() - 1;
84 const int delta = aForward ? 1 : -1;
85
86 const auto& shape = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
87
88 // Find the first point OUTSIDE the pad
89 int firstOutside = -1;
90 VECTOR2I intersectionPt;
91 bool hasIntersection = false;
92
93 for( int vertex = start + delta; aForward ? vertex < aLine.PointCount() : vertex >= 0; vertex += delta )
94 {
95 if( !shape->Contains( aLine.GetPoint( vertex ) ) )
96 {
97 firstOutside = vertex;
98 int prevVertex = vertex - delta;
99
100 // Check if the crossing segment is part of an arc
101 ssize_t arcIdx = aLine.ArcIndex( prevVertex );
102
103 if( arcIdx >= 0 && aLine.ArcIndex( vertex ) == arcIdx )
104 {
105 hasIntersection = findArcPadIntersection( aLine.Arc( arcIdx ), shape, aLine.GetPoint( prevVertex ),
106 intersectionPt );
107 }
108
109 // Fallback to segment intersection if arc intersection didn't work
110 if( !hasIntersection )
111 {
112 SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( prevVertex ) );
113 VECTOR2I loc;
114
115 if( shape->Collide( seg, 0, nullptr, &loc ) )
116 {
117 intersectionPt = loc;
118 hasIntersection = true;
119 }
120 }
121
122 break;
123 }
124 }
125
126 if( firstOutside < 0 )
127 return; // All points inside pad, nothing to clip
128
129 // Build new chain using Slice (preserves arcs correctly without index corruption)
130 SHAPE_LINE_CHAIN newChain;
131
132 if( aForward )
133 {
134 // Chain: padCenter -> intersection -> [firstOutside to end]
135 newChain.Append( aPad->GetPosition() );
136 if( hasIntersection )
137 newChain.Append( intersectionPt );
138 newChain.Append( aLine.Slice( firstOutside, -1 ) );
139 }
140 else
141 {
142 // Chain: [0 to firstOutside] -> intersection -> padCenter
143 newChain.Append( aLine.Slice( 0, firstOutside ) );
144 if( hasIntersection )
145 newChain.Append( intersectionPt );
146 newChain.Append( aPad->GetPosition() );
147 }
148
149 aLine = newChain;
150}
151
152
154 std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems, const PATH_OPTIMISATIONS aOptimisations,
155 const PAD* aStartPad, const PAD* aEndPad, const LENGTH_DELAY_LAYER_OPT aLayerOpt,
156 const LENGTH_DELAY_DOMAIN_OPT aDomain, LENGTH_DELAY_ITEM_DETAILS* aPerItemLengthDelays ) const
157{
158 const bool doTrace = wxLog::IsAllowedTraceMask( wxT( "PNS_TUNE" ) );
159
160 if( doTrace )
161 {
162 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "" ) );
163 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "========== CalculateLengthDetails START ==========" ) );
164 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: input has %zu items" ), aItems.size() );
165 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: optimisations - OptimiseVias=%d, MergeTracks=%d, OptimiseTracesInPads=%d, InferViaInPad=%d" ),
166 aOptimisations.OptimiseVias, aOptimisations.MergeTracks,
167 aOptimisations.OptimiseTracesInPads, aOptimisations.InferViaInPad );
168
169 // Count initial items by type
170 int initialPads = 0, initialVias = 0, initialLines = 0, initialUnknown = 0;
171
172 for( const LENGTH_DELAY_CALCULATION_ITEM& item : aItems )
173 {
174 switch( item.Type() )
175 {
176 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD: initialPads++; break;
177 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA: initialVias++; break;
178 case LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE: initialLines++; break;
179 default: initialUnknown++; break;
180 }
181 }
182
183 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: initial items - PADs=%d, VIAs=%d, LINEs=%d, UNKNOWN=%d" ),
184 initialPads, initialVias, initialLines, initialUnknown );
185 }
186
187 // If this set of items has not been optimised, optimise for shortest electrical path
188 if( aOptimisations.OptimiseVias || aOptimisations.MergeTracks || aOptimisations.MergeTracks )
189 {
190 if( doTrace )
191 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: performing optimisations..." ) );
192
193 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
194 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> lines;
195 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> vias;
196
197 // Map of line endpoints to line objects
198 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> linesPositionMap;
199
200 // Map of pad positions to pad objects
201 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> padsPositionMap;
202
203 for( LENGTH_DELAY_CALCULATION_ITEM& item : aItems )
204 {
205 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
206 {
207 pads.emplace_back( &item );
208 padsPositionMap[item.GetPad()->GetPosition()].insert( &item );
209 }
210 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA )
211 {
212 vias.emplace_back( &item );
213 }
214 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
215 {
216 lines.emplace_back( &item );
217 linesPositionMap[item.GetLine().CPoint( 0 )].insert( &item );
218 linesPositionMap[item.GetLine().CLastPoint()].insert( &item );
219 }
220 }
221
222 if( aOptimisations.OptimiseVias )
223 {
224 if( doTrace )
225 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: optimising via layers (%zu vias)" ), vias.size() );
226
227 optimiseVias( vias, lines, linesPositionMap, padsPositionMap );
228 }
229
230 if( aOptimisations.MergeTracks )
231 {
232 if( doTrace )
233 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: merging tracks (%zu lines)" ), lines.size() );
234
235 mergeLines( lines, linesPositionMap );
236 }
237
238 // Clip traces inside VIA pads after merging
239 if( aOptimisations.OptimiseVias )
240 {
242 {
243 const PCB_VIA* pcbVia = via->GetVia();
244
245 for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : lines )
246 {
247 if( lineItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE )
248 {
249 continue;
250 }
251
252 OptimiseTraceInVia( lineItem->GetLine(), pcbVia, lineItem->GetStartLayer() );
253 }
254 }
255 }
256
257 if( aOptimisations.OptimiseTracesInPads )
258 {
259 if( doTrace )
260 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: optimising traces in pads" ) );
261
262 optimiseTracesInPads( pads, lines );
263 }
264 }
265
266 LENGTH_DELAY_STATS details;
267
268 // Create the layer detail maps if required
270 {
271 if( doTrace )
272 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: creating layer detail maps" ) );
273
274 details.LayerLengths = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
275
277 details.LayerDelays = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
278 }
279
280 const bool useHeight = m_board->GetDesignSettings().m_UseHeightForLengthCalcs;
281
282 if( doTrace )
283 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: useHeight=%d" ), useHeight );
284
285 // If this is a contiguous set of items, check if we have an inferred fanout via at either end. Note that this
286 // condition only arises as a result of how PNS assembles tuning paths - for DRC / net inspector calculations these
287 // fanout vias will be present in the object set and therefore do not need to be inferred
288 if( aOptimisations.InferViaInPad && useHeight )
289 {
290 if( doTrace )
291 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: inferring vias in pads" ) );
292
293 std::pair<int64_t, int64_t> inferredStartPadViaDetails{ 0, 0 };
294 std::pair<int64_t, int64_t> inferredEndPadViaDetails{ 0, 0 };
295
296 const bool withDelay = aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL;
297 inferViaInPad( aStartPad, aItems.front(), details, inferredStartPadViaDetails, withDelay );
298 inferViaInPad( aEndPad, aItems.back(), details, inferredEndPadViaDetails, withDelay );
299
300 if( aPerItemLengthDelays )
301 {
302 aPerItemLengthDelays->InferredStartViaLength = inferredStartPadViaDetails.first;
303 aPerItemLengthDelays->InferredStartViaDelay = inferredStartPadViaDetails.second;
304 aPerItemLengthDelays->InferredEndViaLength = inferredEndPadViaDetails.first;
305 aPerItemLengthDelays->InferredEndViaDelay = inferredEndPadViaDetails.second;
306 }
307 }
308
309 // Add stats for each item
310 int processedPads = 0, processedVias = 0, processedLines = 0;
311 int mergedRetired = 0, unknownType = 0;
312
313 // Output per-item details if required
314 if( aPerItemLengthDelays )
315 {
316 aPerItemLengthDelays->LengthsAndDelays.clear();
317 aPerItemLengthDelays->LengthsAndDelays.resize( aItems.size(), { 0, 0 } );
318 }
319
320 auto setPerItemLengthDetail = [aPerItemLengthDelays]( const size_t idx, const int64_t value )
321 {
322 if( !aPerItemLengthDelays )
323 return;
324
325 aPerItemLengthDelays->LengthsAndDelays[idx].first = value;
326 };
327
328 auto setPerItemDelayDetail = [aPerItemLengthDelays]( const size_t idx, const int64_t value )
329 {
330 if( !aPerItemLengthDelays )
331 return;
332
333 aPerItemLengthDelays->LengthsAndDelays[idx].second = value;
334 };
335
336 if( doTrace )
337 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: processing %zu items..." ), aItems.size() );
338
339 for( size_t i = 0; i < aItems.size(); ++i )
340 {
341 const LENGTH_DELAY_CALCULATION_ITEM& item = aItems[i];
342
343 // Don't include merged items
345 || item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
346 {
348 mergedRetired++;
349 else
350 unknownType++;
351 continue;
352 }
353
354 // Calculate the space domain statistics
355 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
356 {
357 const int64_t length = item.GetLine().Length();
358
359 setPerItemLengthDetail( i, length );
360 details.TrackLength += length;
361 processedLines++;
362
363 if( details.LayerLengths )
364 ( *details.LayerLengths )[item.GetStartLayer()] += length;
365 }
366 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
367 {
368 const auto [layerStart, layerEnd] = item.GetLayers();
369 int64_t viaHeight = StackupHeight( layerStart, layerEnd );
370 setPerItemLengthDetail( i, viaHeight );
371 details.ViaLength += static_cast<int>( viaHeight );
372 details.NumVias += 1;
373 processedVias++;
374
375 if( doTrace )
376 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: via from layer %d to %d, height=%lld" ),
377 layerStart, layerEnd, viaHeight );
378 }
379 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
380 {
381 int64_t padToDie = item.GetPad()->GetPadToDieLength();
382 setPerItemLengthDetail( i, padToDie );
383 details.PadToDieLength += static_cast<int>( padToDie );
384 details.NumPads += 1;
385 processedPads++;
386
387 if( doTrace && padToDie > 0 )
388 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: pad with pad-to-die length=%lld" ), padToDie );
389 }
390 }
391
392 if( doTrace )
393 {
394 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: processed items - PADs=%d, VIAs=%d, LINEs=%d" ),
395 processedPads, processedVias, processedLines );
396 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: skipped items - merged/retired=%d, unknown=%d" ),
397 mergedRetired, unknownType );
398 }
399
400 // Calculate the time domain statistics if required
401 if( aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL && !aItems.empty() )
402 {
403 if( doTrace )
404 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: calculating time domain statistics" ) );
405
406 // TODO(JJ): Populate this
408 ctx.NetClass = aItems.front().GetEffectiveNetClass(); // We don't care if this is merged for net class lookup
409
410 const std::vector<int64_t> itemDelays = m_tuningProfileParameters->GetPropagationDelays( aItems, ctx );
411
412 wxASSERT( itemDelays.size() == aItems.size() );
413
414 for( size_t i = 0; i < aItems.size(); ++i )
415 {
416 const LENGTH_DELAY_CALCULATION_ITEM& item = aItems[i];
417
419 || item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
420 {
421 continue;
422 }
423
424 setPerItemDelayDetail( i, itemDelays[i] );
425
426 if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
427 {
428 details.TrackDelay += itemDelays[i];
429
430 if( details.LayerDelays )
431 ( *details.LayerDelays )[item.GetStartLayer()] += itemDelays[i];
432 }
433 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
434 {
435 details.ViaDelay += itemDelays[i];
436 }
437 else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
438 {
439 details.PadToDieDelay += itemDelays[i];
440 }
441 }
442
443 if( doTrace )
444 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: total delays - Track=%lld, Via=%lld, PadToDie=%lld" ),
445 details.TrackDelay, details.ViaDelay, details.PadToDieDelay );
446 }
447
448 if( doTrace )
449 {
450 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "CalculateLengthDetails: RESULTS:" ) );
451 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " Track length: %lld" ), details.TrackLength );
452 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " Via length: %d (from %d vias)" ), details.ViaLength, details.NumVias );
453 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " Pad-to-die length: %d (from %d pads)" ), details.PadToDieLength, details.NumPads );
454 wxLogTrace( wxT( "PNS_TUNE" ), wxT( " TOTAL LENGTH: %lld" ), details.TotalLength() );
455 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "========== CalculateLengthDetails END ==========" ) );
456 wxLogTrace( wxT( "PNS_TUNE" ), wxT( "" ) );
457 }
458
459 return details;
460}
461
462
464 LENGTH_DELAY_STATS& aDetails,
465 std::pair<int64_t, int64_t>& aInferredViaLengthDelay,
466 const bool aWithDelayDetail ) const
467{
468 if( aPad && aItem.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
469 {
470 const PCB_LAYER_ID startBottomLayer = aItem.GetStartLayer();
471 const LSET padLayers = aPad->Padstack().LayerSet();
472
473 if( !padLayers.Contains( startBottomLayer ) )
474 {
475 // This must be either F_Cu or B_Cu
476 const PCB_LAYER_ID padLayer = padLayers.Contains( F_Cu ) ? F_Cu : B_Cu;
477
478 aDetails.NumVias += 1;
479 const int64_t height = StackupHeight( startBottomLayer, padLayer );
480 aDetails.ViaLength += height;
481 aInferredViaLengthDelay.first = height;
482
483 // Look up via delay details if required
484 if( aWithDelayDetail )
485 {
487 ctx.NetClass = aItem.GetEffectiveNetClass();
488 const int64_t delay = m_tuningProfileParameters->GetViaPropagationDelay( startBottomLayer, padLayer,
489 F_Cu, B_Cu, ctx );
490 aDetails.ViaDelay += delay;
491 aInferredViaLengthDelay.second = delay;
492 }
493 }
494 }
495}
496
497
498int64_t LENGTH_DELAY_CALCULATION::CalculateLength( std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems,
499 const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad,
500 const PAD* aEndPad ) const
501{
502 return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad ).TotalLength();
503}
504
505
506int64_t LENGTH_DELAY_CALCULATION::CalculateDelay( std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems,
507 const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad,
508 const PAD* aEndPad ) const
509{
510 return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL,
512 .TotalDelay();
513}
514
515
516int LENGTH_DELAY_CALCULATION::StackupHeight( const PCB_LAYER_ID aFirstLayer, const PCB_LAYER_ID aSecondLayer ) const
517{
518 if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
519 return 0;
520
521 if( m_board->GetDesignSettings().m_HasStackup )
522 {
523 const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
524 return stackup.GetLayerDistance( aFirstLayer, aSecondLayer );
525 }
526 else
527 {
528 BOARD_STACKUP stackup;
529 stackup.BuildDefaultStackupList( &m_board->GetDesignSettings(), m_board->GetCopperLayerCount() );
530 return stackup.GetLayerDistance( aFirstLayer, aSecondLayer );
531 }
532}
533
534
536 std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
537 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap )
538{
539 // Vector of pads, and an associated flag to indicate whether they have been visited by the clustering algorithm
540 std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
541
542 auto removeFromPositionMap = [&aLinesPositionMap]( LENGTH_DELAY_CALCULATION_ITEM* line )
543 {
544 aLinesPositionMap[line->GetLine().CPoint( 0 )].erase( line );
545 aLinesPositionMap[line->GetLine().CLastPoint()].erase( line );
546 };
547
548 // Attempts to merge unmerged lines in to aPrimaryLine
549 auto tryMerge = [&removeFromPositionMap, &aLinesPositionMap]( const MERGE_POINT aMergePoint,
550 const VECTOR2I& aMergePos,
551 const LENGTH_DELAY_CALCULATION_ITEM* aPrimaryItem,
552 SHAPE_LINE_CHAIN& aPrimaryLine, bool* aDidMerge )
553 {
554 const auto startItr = aLinesPositionMap.find( aMergePos );
555
556 if( startItr == aLinesPositionMap.end() )
557 return;
558
559 std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& startItems = startItr->second;
560
561 if( startItems.size() != 1 )
562 return;
563
564 LENGTH_DELAY_CALCULATION_ITEM* lineToMerge = *startItems.begin();
565
566 // Don't merge if line is an arc
567 if( !lineToMerge->GetLine().CArcs().empty() )
568 return;
569
570 // Don't merge if lines are on different layers
571 if( aPrimaryItem->GetStartLayer() != lineToMerge->GetStartLayer() )
572 return;
573
574 // Merge the lines
576 mergeShapeLineChains( aPrimaryLine, lineToMerge->GetLine(), aMergePoint );
577 removeFromPositionMap( lineToMerge );
578 *aDidMerge = true;
579 };
580
581 // Cluster all lines in to contiguous entities
582 for( LENGTH_DELAY_CALCULATION_ITEM* primaryItem : aLines )
583 {
584 // Don't start with an already merged line
585 if( primaryItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::UNMERGED )
586 continue;
587
588 // Remove starting line from the position map
589 removeFromPositionMap( primaryItem );
590
591 SHAPE_LINE_CHAIN& primaryLine = primaryItem->GetLine();
592
593 // Merge all endpoints
595 bool mergeComplete = false;
596
597 while( !mergeComplete )
598 {
599 bool startMerged = false;
600 bool endMerged = false;
601
602 VECTOR2I startPos = primaryLine.CPoint( 0 );
603 VECTOR2I endPos = primaryLine.CLastPoint();
604
605 tryMerge( MERGE_POINT::START, startPos, primaryItem, primaryLine, &startMerged );
606 tryMerge( MERGE_POINT::END, endPos, primaryItem, primaryLine, &endMerged );
607
608 mergeComplete = !startMerged && !endMerged;
609 }
610 }
611}
612
613
615 const MERGE_POINT aMergePoint )
616{
617 if( aMergePoint == MERGE_POINT::START )
618 {
619 if( aSecondary.GetPoint( 0 ) == aPrimary.GetPoint( 0 ) )
620 {
621 for( auto itr = aSecondary.CPoints().begin() + 1; itr != aSecondary.CPoints().end(); ++itr )
622 aPrimary.Insert( 0, *itr );
623 }
624 else
625 {
626 wxASSERT( aSecondary.CLastPoint() == aPrimary.GetPoint( 0 ) );
627
628 for( auto itr = aSecondary.CPoints().rbegin() + 1; itr != aSecondary.CPoints().rend(); ++itr )
629 aPrimary.Insert( 0, *itr );
630 }
631 }
632 else
633 {
634 if( aSecondary.GetPoint( 0 ) == aPrimary.CLastPoint() )
635 {
636 for( auto itr = aSecondary.CPoints().begin() + 1; itr != aSecondary.CPoints().end(); ++itr )
637 aPrimary.Append( *itr );
638 }
639 else
640 {
641 wxASSERT( aSecondary.CLastPoint() == aPrimary.CLastPoint() );
642
643 for( auto itr = aSecondary.CPoints().rbegin() + 1; itr != aSecondary.CPoints().rend(); ++itr )
644 aPrimary.Append( *itr );
645 }
646 }
647}
648
649
650void LENGTH_DELAY_CALCULATION::optimiseTracesInPads( const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aPads,
651 const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines )
652{
653 for( LENGTH_DELAY_CALCULATION_ITEM* padItem : aPads )
654 {
655 const PAD* pad = padItem->GetPad();
656
657 for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : aLines )
658 {
659 // Ignore merged lines
660 if( lineItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE )
661 continue;
662
663 const PCB_LAYER_ID pcbLayer = lineItem->GetStartLayer();
664 SHAPE_LINE_CHAIN& line = lineItem->GetLine();
665
666 OptimiseTraceInPad( line, pad, pcbLayer );
667 }
668 }
669}
670
671
673 const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aVias, std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
674 std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap,
675 const std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aPadsPositionMap ) const
676{
677 for( LENGTH_DELAY_CALCULATION_ITEM* via : aVias )
678 {
679 const PCB_VIA* pcbVia = via->GetVia();
680
681 std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*> connectedLines;
682
683 const VECTOR2I viaPos = pcbVia->GetPosition();
684
685 auto exactMatch = aLinesPositionMap.find( viaPos );
686
687 if( exactMatch != aLinesPositionMap.end() )
688 connectedLines.insert( exactMatch->second.begin(), exactMatch->second.end() );
689
690 int maxRadius = 0;
691
693 [&]( PCB_LAYER_ID layer )
694 {
695 maxRadius = std::max( maxRadius, pcbVia->GetWidth( layer ) / 2 );
696 } );
697
698 const int64_t maxRadiusSq = static_cast<int64_t>( maxRadius ) * maxRadius;
699
700 for( const auto& [pos, lineSet] : aLinesPositionMap )
701 {
702 if( pos == viaPos )
703 continue;
704
705 if( ( pos - viaPos ).SquaredEuclideanNorm() > maxRadiusSq )
706 continue;
707
708 for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : lineSet )
709 {
710 PCB_LAYER_ID layer = lineItem->GetStartLayer();
711 std::shared_ptr<SHAPE> shape = pcbVia->GetEffectiveShape( layer, FLASHING::ALWAYS_FLASHED );
712
713 if( shape && shape->Collide( pos, 0 ) )
714 connectedLines.insert( lineItem );
715 }
716 }
717
718 const PAD* coincidentPad = nullptr;
719
720 for( PAD* pad : m_board->GetConnectivity()->GetConnectedPads( pcbVia ) )
721 {
722 coincidentPad = pad;
723 break;
724 }
725
726 LSET spanLayers;
727
728 for( const LENGTH_DELAY_CALCULATION_ITEM* lineItem : connectedLines )
729 spanLayers.set( lineItem->GetStartLayer() );
730
731 if( coincidentPad )
732 {
733 PCB_LAYER_ID padSideLayer;
734
735 if( coincidentPad->GetAttribute() == PAD_ATTRIB::SMD || coincidentPad->GetAttribute() == PAD_ATTRIB::CONN )
736 {
737 padSideLayer = *coincidentPad->Padstack().LayerSet().CuStack().begin();
738 }
739 else
740 {
741 padSideLayer = coincidentPad->GetParentFootprint()->GetLayer();
742 }
743
744 spanLayers.set( padSideLayer );
745 }
746
747 wxLogTrace( wxT( "PNS_TUNE" ),
748 wxT( "optimiseVias: via@(%d,%d) connectedLines=%zu coincidentPad=%d "
749 "spanLayerCount=%d" ),
750 viaPos.x, viaPos.y, connectedLines.size(), coincidentPad ? 1 : 0,
751 static_cast<int>( spanLayers.count() ) );
752
753 const LSEQ cuStack = spanLayers.CuStack();
754
755 if( cuStack.empty() )
756 {
757 // Nothing connects to this via
758 via->SetLayers( pcbVia->GetLayer(), pcbVia->GetLayer() );
759 }
760 else if( cuStack.size() == 1 )
761 {
762 // Stub via
763 via->SetLayers( cuStack.front(), cuStack.front() );
764 }
765 else
766 {
767 // Signal transitions layers
768 via->SetLayers( cuStack.front(), cuStack.back() );
769 }
770 }
771}
772
773
775 const PCB_LAYER_ID aPcbLayer )
776{
777 // Only consider lines which terminate in the pad
778 if( aLine.CPoint( 0 ) != aPad->GetPosition() && aLine.CLastPoint() != aPad->GetPosition() )
779 return;
780
781 if( !aPad->FlashLayer( aPcbLayer ) )
782 return;
783
784 const auto& shape = aPad->GetEffectivePolygon( aPcbLayer, ERROR_INSIDE );
785
786 if( shape->Contains( aLine.CPoint( 0 ) ) )
787 clipLineToPad( aLine, aPad, aPcbLayer, true );
788 else if( shape->Contains( aLine.CLastPoint() ) )
789 clipLineToPad( aLine, aPad, aPcbLayer, false );
790}
791
792
794 bool aForward )
795{
796 wxASSERT( aLine.PointCount() >= 2 );
797
798 const int start = aForward ? 0 : aLine.PointCount() - 1;
799 const int delta = aForward ? 1 : -1;
800
801 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
802
803 if( !viaShape )
804 return;
805
806 const SHAPE_CIRCLE* viaCircle = dynamic_cast<const SHAPE_CIRCLE*>( viaShape.get() );
807
808 if( !viaCircle )
809 return;
810
811 // Find the first point OUTSIDE the via pad
812 int firstOutside = -1;
813 VECTOR2I intersectionPt;
814 bool hasIntersection = false;
815
816 for( int vertex = start + delta; aForward ? vertex < aLine.PointCount() : vertex >= 0; vertex += delta )
817 {
818 if( !viaShape->Collide( aLine.GetPoint( vertex ), 0 ) )
819 {
820 firstOutside = vertex;
821 int prevVertex = vertex - delta;
822
823 SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( prevVertex ) );
824
825 CIRCLE circle( viaCircle->GetCenter(), viaCircle->GetRadius() );
826
827 std::vector<VECTOR2I> pts = circle.Intersect( seg );
828
829 if( !pts.empty() )
830 {
831 // Pick the intersection closest to the outside vertex
832 VECTOR2I outside = aLine.GetPoint( vertex );
833 intersectionPt = pts[0];
834
835 for( size_t i = 1; i < pts.size(); i++ )
836 {
837 if( ( pts[i] - outside ).SquaredEuclideanNorm()
838 < ( intersectionPt - outside ).SquaredEuclideanNorm() )
839 {
840 intersectionPt = pts[i];
841 }
842 }
843
844 hasIntersection = true;
845 }
846
847 break;
848 }
849 }
850
851 if( firstOutside < 0 )
852 return;
853
854 SHAPE_LINE_CHAIN newChain;
855
856 if( aForward )
857 {
858 // viaCenter -> intersection -> [firstOutside to end]
859 newChain.Append( aVia->GetPosition() );
860
861 if( hasIntersection )
862 newChain.Append( intersectionPt );
863
864 newChain.Append( aLine.Slice( firstOutside, -1 ) );
865 }
866 else
867 {
868 // [0 to firstOutside] -> intersection -> viaCenter
869 newChain.Append( aLine.Slice( 0, firstOutside ) );
870
871 if( hasIntersection )
872 newChain.Append( intersectionPt );
873
874 newChain.Append( aVia->GetPosition() );
875 }
876
877 aLine = newChain;
878}
879
880
882{
883 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
884
885 if( !viaShape )
886 return;
887
888 if( viaShape->Collide( aLine.CPoint( 0 ), 0 ) )
889 clipLineToVia( aLine, aVia, aLayer, true );
890 else if( viaShape->Collide( aLine.CLastPoint(), 0 ) )
891 clipLineToVia( aLine, aVia, aLayer, false );
892}
893
894
896{
897 std::shared_ptr<SHAPE> shape = aVia->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
898 return shape && shape->Collide( aPoint, 0 );
899}
900
901
904{
905 if( const PCB_TRACK* track = dynamic_cast<const PCB_TRACK*>( aBoardItem ) )
906 {
907 if( track->Type() == PCB_VIA_T )
908 {
909 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
910
912 item.SetVia( via );
914 item.SetEffectiveNetClass( via->GetEffectiveNetClass() );
915
916 return item;
917 }
918
919 if( track->Type() == PCB_ARC_T )
920 {
921 const PCB_ARC* arcParent = static_cast<const PCB_ARC*>( track );
922 SHAPE_ARC shapeArc( arcParent->GetStart(), arcParent->GetMid(), arcParent->GetEnd(),
923 arcParent->GetWidth() );
924 SHAPE_LINE_CHAIN chainArc( shapeArc );
925
927 item.SetLine( chainArc );
928 item.SetLayers( track->GetLayer() );
929 item.SetEffectiveNetClass( arcParent->GetEffectiveNetClass() );
930
931 return item;
932 }
933
934 if( track->Type() == PCB_TRACE_T )
935 {
936 std::vector<VECTOR2I> points{ track->GetStart(), track->GetEnd() };
937 SHAPE_LINE_CHAIN shape( points );
938
940 item.SetLine( shape );
941 item.SetLayers( track->GetLayer() );
942 item.SetEffectiveNetClass( track->GetEffectiveNetClass() );
943
944 return item;
945 }
946 }
947 else if( const PAD* pad = dynamic_cast<const PAD*>( aBoardItem ) )
948 {
950 item.SetPad( pad );
951
952 const LSET& layers = pad->Padstack().LayerSet();
953 PCB_LAYER_ID firstLayer = UNDEFINED_LAYER;
954 PCB_LAYER_ID secondLayer = UNDEFINED_LAYER;
955
956 for( auto itr = layers.copper_layers_begin(); itr != layers.copper_layers_end(); ++itr )
957 {
958 if( firstLayer == UNDEFINED_LAYER )
959 firstLayer = *itr;
960 else
961 secondLayer = *itr;
962 }
963
964 item.SetLayers( firstLayer, secondLayer );
965 item.SetEffectiveNetClass( pad->GetEffectiveNetClass() );
966
967 return item;
968 }
969
970 return {};
971}
972
973
975 std::unique_ptr<TUNING_PROFILE_PARAMETERS_IFACE>&& aProvider )
976{
977 m_tuningProfileParameters = std::move( aProvider );
978}
979
980
985
986
987int64_t LENGTH_DELAY_CALCULATION::CalculateLengthForDelay( const int64_t aDesiredDelay,
988 const TUNING_PROFILE_GEOMETRY_CONTEXT& aCtx ) const
989{
990 return m_tuningProfileParameters->GetTrackLengthForPropagationDelay( aDesiredDelay, aCtx );
991}
992
993
995 const SHAPE_LINE_CHAIN& aShape, const TUNING_PROFILE_GEOMETRY_CONTEXT& aCtx ) const
996{
997 return m_tuningProfileParameters->CalculatePropagationDelayForShapeLineChain( aShape, aCtx );
998}
@ 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:923
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:263
copper_layers_iterator copper_layers_begin() const
Definition lset.cpp:917
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:65
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition pad.cpp:443
PAD_ATTRIB GetAttribute() const
Definition pad.h:583
VECTOR2I GetPosition() const override
Definition pad.h:219
const PADSTACK & Padstack() const
Definition pad.h:353
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:952
int GetPadToDieLength() const
Definition pad.h:601
const VECTOR2I & GetMid() const
Definition pcb_track.h:290
const VECTOR2I & GetStart() const
Definition pcb_track.h:97
const VECTOR2I & GetEnd() const
Definition pcb_track.h:94
virtual int GetWidth() const
Definition pcb_track.h:91
VECTOR2I GetPosition() const override
Definition pcb_track.h:557
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:406
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
int GetWidth() const override
Definition seg.h:42
bool Contains(const SEG &aSeg) const
Definition seg.h:324
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_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.
const std::vector< SHAPE_ARC > & CArcs() const
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.
void Insert(size_t aVertex, const VECTOR2I &aP)
long long int Length() const
Return length of the line chain in Euclidean metric.
const std::vector< VECTOR2I > & CPoints() const
a few functions useful in geometry calculations.
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:186
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ B_Cu
Definition layer_ids.h:65
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:64
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:94
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:95
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:93
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687