You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

613 lines
23 KiB

  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. #include <length_delay_calculation/length_delay_calculation.h>
  24. #include <board.h>
  25. #include <board_design_settings.h>
  26. #include <geometry/geometry_utils.h>
  27. void LENGTH_DELAY_CALCULATION::clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aLayer,
  28. bool aForward )
  29. {
  30. const int start = aForward ? 0 : aLine.PointCount() - 1;
  31. const int delta = aForward ? 1 : -1;
  32. // Note: we don't apply the clip-to-pad optimization if an arc ends in a pad
  33. // Room for future improvement.
  34. if( aLine.IsPtOnArc( start ) )
  35. return;
  36. const auto& shape = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
  37. // Skip the "first" (or last) vertex, we already know it's contained in the pad
  38. int clip = start;
  39. for( int vertex = start + delta; aForward ? vertex < aLine.PointCount() : vertex >= 0; vertex += delta )
  40. {
  41. SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( vertex - delta ) );
  42. bool containsA = shape->Contains( seg.A );
  43. bool containsB = shape->Contains( seg.B );
  44. if( containsA && containsB )
  45. {
  46. // Whole segment is inside: clip out this segment
  47. clip = vertex;
  48. }
  49. else if( containsB )
  50. {
  51. // Only one point inside: Find the intersection
  52. VECTOR2I loc;
  53. if( shape->Collide( seg, 0, nullptr, &loc ) )
  54. {
  55. aLine.Replace( vertex - delta, vertex - delta, loc );
  56. }
  57. }
  58. }
  59. if( !aForward && clip < start )
  60. aLine.Remove( clip + 1, start );
  61. else if( clip > start )
  62. aLine.Remove( start, clip - 1 );
  63. // Now connect the dots
  64. aLine.Insert( aForward ? 0 : aLine.PointCount(), aPad->GetPosition() );
  65. }
  66. LENGTH_DELAY_STATS LENGTH_DELAY_CALCULATION::CalculateLengthDetails( std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems,
  67. const PATH_OPTIMISATIONS aOptimisations,
  68. const PAD* aStartPad, const PAD* aEndPad,
  69. const LENGTH_DELAY_LAYER_OPT aLayerOpt,
  70. const LENGTH_DELAY_DOMAIN_OPT aDomain ) const
  71. {
  72. // If this set of items has not been optimised, optimise for shortest electrical path
  73. if( aOptimisations.OptimiseViaLayers || aOptimisations.MergeTracks || aOptimisations.MergeTracks )
  74. {
  75. std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
  76. std::vector<LENGTH_DELAY_CALCULATION_ITEM*> lines;
  77. std::vector<LENGTH_DELAY_CALCULATION_ITEM*> vias;
  78. // Map of line endpoints to line objects
  79. std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> linesPositionMap;
  80. // Map of pad positions to pad objects
  81. std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>> padsPositionMap;
  82. for( LENGTH_DELAY_CALCULATION_ITEM& item : aItems )
  83. {
  84. if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
  85. {
  86. pads.emplace_back( &item );
  87. padsPositionMap[item.GetPad()->GetPosition()].insert( &item );
  88. }
  89. else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA )
  90. {
  91. vias.emplace_back( &item );
  92. }
  93. else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
  94. {
  95. lines.emplace_back( &item );
  96. linesPositionMap[item.GetLine().CPoint( 0 )].insert( &item );
  97. linesPositionMap[item.GetLine().CLastPoint()].insert( &item );
  98. }
  99. }
  100. if( aOptimisations.OptimiseViaLayers )
  101. optimiseViaLayers( vias, lines, linesPositionMap, padsPositionMap );
  102. if( aOptimisations.MergeTracks )
  103. mergeLines( lines, linesPositionMap );
  104. if( aOptimisations.OptimiseTracesInPads )
  105. optimiseTracesInPads( pads, lines );
  106. }
  107. LENGTH_DELAY_STATS details;
  108. // Create the layer detail maps if required
  109. if( aLayerOpt == LENGTH_DELAY_LAYER_OPT::WITH_LAYER_DETAIL )
  110. {
  111. details.LayerLengths = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
  112. if( aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL )
  113. details.LayerDelays = std::make_unique<std::map<PCB_LAYER_ID, int64_t>>();
  114. }
  115. const bool useHeight = m_board->GetDesignSettings().m_UseHeightForLengthCalcs;
  116. // If this is a contiguous set of items, check if we have an inferred fanout via at either end. Note that this
  117. // condition only arises as a result of how PNS assembles tuning paths - for DRC / net inspector calculations these
  118. // fanout vias will be present in the object set and therefore do not need to be inferred
  119. if( aOptimisations.InferViaInPad && useHeight )
  120. {
  121. inferViaInPad( aStartPad, aItems.front(), details );
  122. inferViaInPad( aEndPad, aItems.back(), details );
  123. }
  124. // Add stats for each item
  125. for( const LENGTH_DELAY_CALCULATION_ITEM& item : aItems )
  126. {
  127. // Don't include merged items
  128. if( item.GetMergeStatus() == LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED
  129. || item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
  130. {
  131. continue;
  132. }
  133. // Calculate the space domain statistics
  134. if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
  135. {
  136. const int64_t length = item.GetLine().Length();
  137. details.TrackLength += length;
  138. if( details.LayerLengths )
  139. ( *details.LayerLengths )[item.GetStartLayer()] += length;
  140. }
  141. else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
  142. {
  143. const auto [layerStart, layerEnd] = item.GetLayers();
  144. details.ViaLength += StackupHeight( layerStart, layerEnd );
  145. details.NumVias += 1;
  146. }
  147. else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
  148. {
  149. details.PadToDieLength += item.GetPad()->GetPadToDieLength();
  150. details.NumPads += 1;
  151. }
  152. }
  153. // Calculate the time domain statistics if required
  154. if( aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL && !aItems.empty() )
  155. {
  156. // TODO(JJ): Populate this
  157. TIME_DOMAIN_GEOMETRY_CONTEXT ctx;
  158. ctx.NetClass = aItems.front().GetEffectiveNetClass(); // We don't care if this is merged for net class lookup
  159. const std::vector<int64_t> itemDelays = m_timeDomainParameters->GetPropagationDelays( aItems, ctx );
  160. wxASSERT( itemDelays.size() == aItems.size() );
  161. for( size_t i = 0; i < aItems.size(); ++i )
  162. {
  163. const LENGTH_DELAY_CALCULATION_ITEM& item = aItems[i];
  164. if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
  165. {
  166. details.TrackDelay += itemDelays[i];
  167. if( details.LayerDelays )
  168. ( *details.LayerDelays )[item.GetStartLayer()] += itemDelays[i];
  169. }
  170. else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight )
  171. {
  172. details.ViaDelay += itemDelays[i];
  173. }
  174. else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD )
  175. {
  176. details.PadToDieDelay += itemDelays[i];
  177. }
  178. }
  179. }
  180. return details;
  181. }
  182. void LENGTH_DELAY_CALCULATION::inferViaInPad( const PAD* aPad, const LENGTH_DELAY_CALCULATION_ITEM& aItem,
  183. LENGTH_DELAY_STATS& aDetails ) const
  184. {
  185. if( aPad && aItem.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE )
  186. {
  187. const PCB_LAYER_ID startBottomLayer = aItem.GetStartLayer();
  188. const LSET padLayers = aPad->Padstack().LayerSet();
  189. if( !padLayers.Contains( startBottomLayer ) )
  190. {
  191. // This must be either F_Cu or B_Cu
  192. const PCB_LAYER_ID padLayer = padLayers.Contains( F_Cu ) ? F_Cu : B_Cu;
  193. aDetails.NumVias += 1;
  194. aDetails.ViaLength += StackupHeight( startBottomLayer, padLayer );
  195. }
  196. }
  197. }
  198. int64_t LENGTH_DELAY_CALCULATION::CalculateLength( std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems,
  199. const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad,
  200. const PAD* aEndPad ) const
  201. {
  202. return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad ).TotalLength();
  203. }
  204. int64_t LENGTH_DELAY_CALCULATION::CalculateDelay( std::vector<LENGTH_DELAY_CALCULATION_ITEM>& aItems,
  205. const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad,
  206. const PAD* aEndPad ) const
  207. {
  208. return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL,
  209. LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL )
  210. .TotalDelay();
  211. }
  212. int LENGTH_DELAY_CALCULATION::StackupHeight( const PCB_LAYER_ID aFirstLayer, const PCB_LAYER_ID aSecondLayer ) const
  213. {
  214. if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
  215. return 0;
  216. if( m_board->GetDesignSettings().m_HasStackup )
  217. {
  218. const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
  219. return stackup.GetLayerDistance( aFirstLayer, aSecondLayer );
  220. }
  221. else
  222. {
  223. BOARD_STACKUP stackup;
  224. stackup.BuildDefaultStackupList( &m_board->GetDesignSettings(), m_board->GetCopperLayerCount() );
  225. return stackup.GetLayerDistance( aFirstLayer, aSecondLayer );
  226. }
  227. }
  228. void LENGTH_DELAY_CALCULATION::mergeLines(
  229. std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
  230. std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap )
  231. {
  232. // Vector of pads, and an associated flag to indicate whether they have been visited by the clustering algorithm
  233. std::vector<LENGTH_DELAY_CALCULATION_ITEM*> pads;
  234. auto removeFromPositionMap = [&aLinesPositionMap]( LENGTH_DELAY_CALCULATION_ITEM* line )
  235. {
  236. aLinesPositionMap[line->GetLine().CPoint( 0 )].erase( line );
  237. aLinesPositionMap[line->GetLine().CLastPoint()].erase( line );
  238. };
  239. // Attempts to merge unmerged lines in to aPrimaryLine
  240. auto tryMerge = [&removeFromPositionMap, &aLinesPositionMap]( const MERGE_POINT aMergePoint,
  241. const VECTOR2I& aMergePos,
  242. const LENGTH_DELAY_CALCULATION_ITEM* aPrimaryItem,
  243. SHAPE_LINE_CHAIN& aPrimaryLine, bool* aDidMerge )
  244. {
  245. const auto startItr = aLinesPositionMap.find( aMergePos );
  246. if( startItr == aLinesPositionMap.end() )
  247. return;
  248. std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& startItems = startItr->second;
  249. if( startItems.size() != 1 )
  250. return;
  251. LENGTH_DELAY_CALCULATION_ITEM* lineToMerge = *startItems.begin();
  252. // Don't merge if line is an arc
  253. if( !lineToMerge->GetLine().CArcs().empty() )
  254. return;
  255. // Don't merge if lines are on different layers
  256. if( aPrimaryItem->GetStartLayer() != lineToMerge->GetStartLayer() )
  257. return;
  258. // Merge the lines
  259. lineToMerge->SetMergeStatus( LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED );
  260. mergeShapeLineChains( aPrimaryLine, lineToMerge->GetLine(), aMergePoint );
  261. removeFromPositionMap( lineToMerge );
  262. *aDidMerge = true;
  263. };
  264. // Cluster all lines in to contiguous entities
  265. for( LENGTH_DELAY_CALCULATION_ITEM* primaryItem : aLines )
  266. {
  267. // Don't start with an already merged line
  268. if( primaryItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::UNMERGED )
  269. continue;
  270. // Remove starting line from the position map
  271. removeFromPositionMap( primaryItem );
  272. SHAPE_LINE_CHAIN& primaryLine = primaryItem->GetLine();
  273. // Merge all endpoints
  274. primaryItem->SetMergeStatus( LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE );
  275. bool mergeComplete = false;
  276. while( !mergeComplete )
  277. {
  278. bool startMerged = false;
  279. bool endMerged = false;
  280. VECTOR2I startPos = primaryLine.CPoint( 0 );
  281. VECTOR2I endPos = primaryLine.CLastPoint();
  282. tryMerge( MERGE_POINT::START, startPos, primaryItem, primaryLine, &startMerged );
  283. tryMerge( MERGE_POINT::END, endPos, primaryItem, primaryLine, &endMerged );
  284. mergeComplete = !startMerged && !endMerged;
  285. }
  286. }
  287. }
  288. void LENGTH_DELAY_CALCULATION::mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const SHAPE_LINE_CHAIN& aSecondary,
  289. const MERGE_POINT aMergePoint )
  290. {
  291. if( aMergePoint == MERGE_POINT::START )
  292. {
  293. if( aSecondary.GetPoint( 0 ) == aPrimary.GetPoint( 0 ) )
  294. {
  295. for( auto itr = aSecondary.CPoints().begin() + 1; itr != aSecondary.CPoints().end(); ++itr )
  296. aPrimary.Insert( 0, *itr );
  297. }
  298. else
  299. {
  300. wxASSERT( aSecondary.CLastPoint() == aPrimary.GetPoint( 0 ) );
  301. for( auto itr = aSecondary.CPoints().rbegin() + 1; itr != aSecondary.CPoints().rend(); ++itr )
  302. aPrimary.Insert( 0, *itr );
  303. }
  304. }
  305. else
  306. {
  307. if( aSecondary.GetPoint( 0 ) == aPrimary.CLastPoint() )
  308. {
  309. for( auto itr = aSecondary.CPoints().begin() + 1; itr != aSecondary.CPoints().end(); ++itr )
  310. aPrimary.Append( *itr );
  311. }
  312. else
  313. {
  314. wxASSERT( aSecondary.CLastPoint() == aPrimary.CLastPoint() );
  315. for( auto itr = aSecondary.CPoints().rbegin() + 1; itr != aSecondary.CPoints().rend(); ++itr )
  316. aPrimary.Append( *itr );
  317. }
  318. }
  319. }
  320. void LENGTH_DELAY_CALCULATION::optimiseTracesInPads( const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aPads,
  321. const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines )
  322. {
  323. for( LENGTH_DELAY_CALCULATION_ITEM* padItem : aPads )
  324. {
  325. const PAD* pad = padItem->GetPad();
  326. for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : aLines )
  327. {
  328. // Ignore merged lines
  329. if( lineItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE )
  330. continue;
  331. const PCB_LAYER_ID pcbLayer = lineItem->GetStartLayer();
  332. SHAPE_LINE_CHAIN& line = lineItem->GetLine();
  333. OptimiseTraceInPad( line, pad, pcbLayer );
  334. }
  335. }
  336. }
  337. void LENGTH_DELAY_CALCULATION::optimiseViaLayers(
  338. const std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aVias, std::vector<LENGTH_DELAY_CALCULATION_ITEM*>& aLines,
  339. std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aLinesPositionMap,
  340. const std::map<VECTOR2I, std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>>& aPadsPositionMap )
  341. {
  342. for( LENGTH_DELAY_CALCULATION_ITEM* via : aVias )
  343. {
  344. auto lineItr = aLinesPositionMap.find( via->GetVia()->GetPosition() );
  345. if( lineItr == aLinesPositionMap.end() )
  346. continue;
  347. std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& connectedLines = lineItr->second;
  348. if( connectedLines.empty() )
  349. {
  350. // No connected lines - this via is floating. Set both layers to the same
  351. via->SetLayers( via->GetVia()->GetLayer(), via->GetVia()->GetLayer() );
  352. }
  353. else if( connectedLines.size() == 1 )
  354. {
  355. // This is either a via stub, or a via-in-pad
  356. bool isViaInPad = false;
  357. const PCB_LAYER_ID lineLayer = ( *connectedLines.begin() )->GetStartLayer();
  358. auto padItr = aPadsPositionMap.find( via->GetVia()->GetPosition() );
  359. if( padItr != aPadsPositionMap.end() )
  360. {
  361. // This could be a via-in-pad - check for overlapping pads which are not on the line layer
  362. const std::unordered_set<LENGTH_DELAY_CALCULATION_ITEM*>& pads = padItr->second;
  363. if( pads.size() == 1 )
  364. {
  365. const LENGTH_DELAY_CALCULATION_ITEM* padItem = *pads.begin();
  366. if( !padItem->GetPad()->Padstack().LayerSet().Contains( lineLayer ) )
  367. {
  368. // This is probably a via-in-pad
  369. isViaInPad = true;
  370. via->SetLayers( lineLayer, padItem->GetStartLayer() );
  371. }
  372. }
  373. }
  374. if( !isViaInPad )
  375. {
  376. // This is a via stub - make its electrical length 0
  377. via->SetLayers( lineLayer, lineLayer );
  378. }
  379. }
  380. else
  381. {
  382. // This via has more than one track ending at it. Calculate the connected layer span (which may be shorter
  383. // than the overall via span)
  384. LSET layers;
  385. for( const LENGTH_DELAY_CALCULATION_ITEM* lineItem : connectedLines )
  386. layers.set( lineItem->GetStartLayer() );
  387. LSEQ cuStack = layers.CuStack();
  388. PCB_LAYER_ID firstLayer = UNDEFINED_LAYER;
  389. PCB_LAYER_ID lastLayer = UNDEFINED_LAYER;
  390. for( PCB_LAYER_ID layer : cuStack )
  391. {
  392. if( firstLayer == UNDEFINED_LAYER )
  393. firstLayer = layer;
  394. else
  395. lastLayer = layer;
  396. }
  397. if( lastLayer == UNDEFINED_LAYER )
  398. via->SetLayers( firstLayer, firstLayer );
  399. else
  400. via->SetLayers( firstLayer, lastLayer );
  401. }
  402. }
  403. }
  404. void LENGTH_DELAY_CALCULATION::OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad,
  405. const PCB_LAYER_ID aPcbLayer )
  406. {
  407. // Only consider lines which terminate in the pad
  408. if( aLine.CPoint( 0 ) != aPad->GetPosition() && aLine.CLastPoint() != aPad->GetPosition() )
  409. return;
  410. if( !aPad->FlashLayer( aPcbLayer ) )
  411. return;
  412. const auto& shape = aPad->GetEffectivePolygon( aPcbLayer, ERROR_INSIDE );
  413. if( shape->Contains( aLine.CPoint( 0 ) ) )
  414. clipLineToPad( aLine, aPad, aPcbLayer, true );
  415. else if( shape->Contains( aLine.CPoint( -1 ) ) )
  416. clipLineToPad( aLine, aPad, aPcbLayer, false );
  417. }
  418. LENGTH_DELAY_CALCULATION_ITEM
  419. LENGTH_DELAY_CALCULATION::GetLengthCalculationItem( const BOARD_CONNECTED_ITEM* aBoardItem ) const
  420. {
  421. if( const PCB_TRACK* track = dynamic_cast<const PCB_TRACK*>( aBoardItem ) )
  422. {
  423. if( track->Type() == PCB_VIA_T )
  424. {
  425. const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
  426. LENGTH_DELAY_CALCULATION_ITEM item;
  427. item.SetVia( via );
  428. item.CalculateViaLayers( m_board );
  429. item.SetEffectiveNetClass( via->GetEffectiveNetClass() );
  430. return item;
  431. }
  432. if( track->Type() == PCB_ARC_T )
  433. {
  434. const PCB_ARC* arcParent = static_cast<const PCB_ARC*>( track );
  435. SHAPE_ARC shapeArc( arcParent->GetStart(), arcParent->GetMid(), arcParent->GetEnd(),
  436. arcParent->GetWidth() );
  437. SHAPE_LINE_CHAIN chainArc( shapeArc );
  438. LENGTH_DELAY_CALCULATION_ITEM item;
  439. item.SetLine( chainArc );
  440. item.SetLayers( track->GetLayer() );
  441. item.SetEffectiveNetClass( arcParent->GetEffectiveNetClass() );
  442. return item;
  443. }
  444. if( track->Type() == PCB_TRACE_T )
  445. {
  446. std::vector<VECTOR2I> points{ track->GetStart(), track->GetEnd() };
  447. SHAPE_LINE_CHAIN shape( points );
  448. LENGTH_DELAY_CALCULATION_ITEM item;
  449. item.SetLine( shape );
  450. item.SetLayers( track->GetLayer() );
  451. item.SetEffectiveNetClass( track->GetEffectiveNetClass() );
  452. return item;
  453. }
  454. }
  455. else if( const PAD* pad = dynamic_cast<const PAD*>( aBoardItem ) )
  456. {
  457. LENGTH_DELAY_CALCULATION_ITEM item;
  458. item.SetPad( pad );
  459. const LSET& layers = pad->Padstack().LayerSet();
  460. PCB_LAYER_ID firstLayer = UNDEFINED_LAYER;
  461. PCB_LAYER_ID secondLayer = UNDEFINED_LAYER;
  462. for( auto itr = layers.copper_layers_begin(); itr != layers.copper_layers_end(); ++itr )
  463. {
  464. if( firstLayer == UNDEFINED_LAYER )
  465. firstLayer = *itr;
  466. else
  467. secondLayer = *itr;
  468. }
  469. item.SetLayers( firstLayer, secondLayer );
  470. item.SetEffectiveNetClass( pad->GetEffectiveNetClass() );
  471. return item;
  472. }
  473. return {};
  474. }
  475. void LENGTH_DELAY_CALCULATION::SetTimeDomainParametersProvider(
  476. std::unique_ptr<TIME_DOMAIN_PARAMETERS_IFACE>&& aProvider )
  477. {
  478. m_timeDomainParameters = std::move( aProvider );
  479. }
  480. void LENGTH_DELAY_CALCULATION::SynchronizeTimeDomainProperties() const
  481. {
  482. m_timeDomainParameters->OnSettingsChanged();
  483. }
  484. int64_t LENGTH_DELAY_CALCULATION::CalculateLengthForDelay( const int64_t aDesiredDelay,
  485. const TIME_DOMAIN_GEOMETRY_CONTEXT& aCtx ) const
  486. {
  487. return m_timeDomainParameters->GetTrackLengthForPropagationDelay( aDesiredDelay, aCtx );
  488. }
  489. int64_t
  490. LENGTH_DELAY_CALCULATION::CalculatePropagationDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape,
  491. const TIME_DOMAIN_GEOMETRY_CONTEXT& aCtx ) const
  492. {
  493. return m_timeDomainParameters->CalculatePropagationDelayForShapeLineChain( aShape, aCtx );
  494. }