KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_dp_meander_placer.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2014 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <optional>
23
24#include <core/typeinfo.h>
25
27
28#include "pns_node.h"
29#include "pns_itemset.h"
30#include "pns_topology.h"
32#include "pns_diff_pair.h"
33#include "pns_router.h"
34#include "pns_solid.h"
35
36
37namespace PNS {
38
40 MEANDER_PLACER_BASE( aRouter )
41{
42 m_world = nullptr;
43 m_currentNode = nullptr;
44
47
50
51 // Init temporary variables (do not leave uninitialized members)
52 m_initialSegment = nullptr;
53 m_lastLength = 0;
54 m_lastDelay = 0;
56
57 m_netClass = nullptr;
58}
59
60
64
65
67{
68 return m_currentTraceP;
69}
70
71
76
77
78NODE* DP_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const
79{
80 if( !m_currentNode )
81 return m_world;
82
83 return m_currentNode;
84}
85
86
87bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
88{
89 if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
90 {
91 Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) );
92 return false;
93 }
94
95 m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
96 m_currentNode = nullptr;
98
99 m_world = Router()->GetWorld()->Branch();
100
101 TOPOLOGY topo( m_world );
102
104 {
105 Router()->SetFailureReason( _( "Unable to find complementary differential pair "
106 "net for length tuning. Make sure the names of the nets "
107 "belonging to a differential pair end with either _N/_P "
108 "or +/-." ) );
109 return false;
110 }
111
112 if( m_originPair.Gap() < 0 )
113 m_originPair.SetGap( Router()->Sizes().DiffPairGap() );
114
115 if( !m_originPair.PLine().SegmentCount() || !m_originPair.NLine().SegmentCount() )
116 return false;
117
118 m_tunedPathP = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.PLine().GetLink( 0 ), &m_startPad_p,
119 &m_endPad_p );
120
123
124 if( m_startPad_p )
125 {
126 m_padToDieLengthP += m_startPad_p->GetPadToDie();
127 m_padToDieDelayP += m_startPad_p->GetPadToDieDelay();
128 }
129
130 if( m_endPad_p )
131 {
132 m_padToDieLengthP += m_endPad_p->GetPadToDie();
133 m_padToDieDelayP += m_endPad_p->GetPadToDieDelay();
134 }
135
136 m_tunedPathN = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.NLine().GetLink( 0 ), &m_startPad_n,
137 &m_endPad_n );
138
141
142 if( m_startPad_n )
143 {
144 m_padToDieLengthN += m_startPad_n->GetPadToDie();
145 m_padToDieDelayN += m_startPad_n->GetPadToDieDelay();
146 }
147
148 if( m_endPad_n )
149 {
150 m_padToDieLengthN += m_endPad_n->GetPadToDie();
151 m_padToDieDelayN += m_endPad_n->GetPadToDieDelay();
152 }
153
154 m_world->Remove( m_originPair.PLine() );
155 m_world->Remove( m_originPair.NLine() );
156
158
159 const BOARD_CONNECTED_ITEM* conItem = static_cast<BOARD_CONNECTED_ITEM*>( aStartItem->GetSourceItem() );
160 m_netClass = conItem->GetEffectiveNetClass();
161
163
164 return true;
165}
166
167
171
172
174{
177 return std::max( totalP, totalN );
178}
179
180
182{
183 const int64_t totalP = m_padToDieDelayP + lineDelay( m_tunedPathP, m_startPad_p, m_endPad_p );
184 const int64_t totalN = m_padToDieDelayP + lineDelay( m_tunedPathN, m_startPad_n, m_endPad_n );
185 return std::max( totalP, totalN );
186}
187
188
190{
191 const VECTOR2I a( ( aCoupledSegs.coupledP.A + aCoupledSegs.coupledN.A ) / 2 );
192 const VECTOR2I b( ( aCoupledSegs.coupledP.B + aCoupledSegs.coupledN.B ) / 2 );
193
194 return SEG( a, b );
195}
196
197
199{
200 VECTOR2I midp = ( aPair.coupledP.A + aPair.coupledN.A ) / 2;
201
202 //DrawDebugPoint(midp, 6);
203
204 return aPair.coupledP.Side( midp ) > 0;
205}
206
207
208bool DP_MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
209{
211
212 if( m_currentStart == aP )
213 return false;
214
215 DIFF_PAIR::COUPLED_SEGMENTS_VEC coupledSegments;
216
217 if( m_currentNode )
218 delete m_currentNode;
219
220 m_currentNode = m_world->Branch();
221
222 SHAPE_LINE_CHAIN preP, tunedP, postP;
223 SHAPE_LINE_CHAIN preN, tunedN, postN;
224
225 m_originPair.CP().Split( m_currentStart, aP, preP, tunedP, postP );
226 m_originPair.CN().Split( m_currentStart, aP, preN, tunedN, postN );
227
228 tunedP.Simplify();
229 tunedN.Simplify();
230
231 // Bail out early if the tuned sections are empty (issue #22041). This can happen when the
232 // split points are too close together or outside the line chain.
233 if( tunedP.PointCount() == 0 || tunedN.PointCount() == 0 )
234 {
239
240 return false;
241 }
242
243 auto updateStatus =
244 [&]()
245 {
246 if( m_lastLength > m_settings.m_targetLength.Max() )
248 else if( m_lastLength < m_settings.m_targetLength.Min() )
250 else
252 };
253
254 DIFF_PAIR tuned( m_originPair );
255
256 tuned.SetShape( tunedP, tunedN );
257
258 tuned.CoupledSegmentPairs( coupledSegments );
259
260 if( coupledSegments.size() == 0 )
261 {
262 // Tuning started at an uncoupled area of the DP; we won't get a valid result until the
263 // cursor is moved far enough along a coupled area. Prevent the track from disappearing and
264 // the length from being zero by just using the original.
268 updateStatus();
269
270 return false;
271 }
272
273 m_result = MEANDERED_LINE( this, true );
274 m_result.SetWidth( tuned.Width() );
275
276 int offset = ( tuned.Gap() + tuned.Width() ) / 2;
277
278 if( pairOrientation( coupledSegments[0] ) )
279 offset *= -1;
280
281 m_result.SetBaselineOffset( offset );
282
283 for( const ITEM* item : m_tunedPathP.CItems() )
284 {
285 if( const LINE* l = dyn_cast<const LINE*>( item ) )
286 {
287 PNS_DBG( Dbg(), AddShape, &l->CLine(), YELLOW, 10000, wxT( "tuned-path-p" ) );
288
289 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
290 }
291 }
292
293 for( const ITEM* item : m_tunedPathN.CItems() )
294 {
295 if( const LINE* l = dyn_cast<const LINE*>( item ) )
296 {
297 PNS_DBG( Dbg(), AddShape, &l->CLine(), YELLOW, 10000, wxT( "tuned-path-n" ) );
298
299 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
300 }
301 }
302
303 struct GET_ITEM_RET
304 {
305 std::optional<SHAPE_ARC> arc;
306 VECTOR2I startPt;
307 VECTOR2I endPt;
308 };
309
310 auto getItem = [&]( const SHAPE_LINE_CHAIN& aChain, int aIndex, int aLastIndex )
311 {
312 std::optional<SHAPE_ARC> optArc;
313 VECTOR2I startPt;
314 VECTOR2I endPt;
315
316 if( aChain.IsArcSegment( aIndex ) )
317 {
318 SHAPE_ARC arc = aChain.Arc( aChain.ArcIndex( aIndex ) );
319 optArc = arc;
320 startPt = arc.GetStart();
321 endPt = arc.GetEnd();
322 }
323 else
324 {
325 SEG seg = aChain.GetSegment( aIndex );
326 startPt = seg.A;
327 endPt = seg.B;
328 }
329
330 return GET_ITEM_RET{ optArc, startPt, endPt };
331 };
332
333 auto checkIndex = [&]( bool& aOk, int aCurIndex, int aLastIndex ) -> bool
334 {
335 aOk = aCurIndex <= aLastIndex && aCurIndex != -1;
336 return aOk;
337 };
338
339 int curIndexP = 0, curIndexN = 0;
340
341 auto addCornersUntilIndex = [&]( int aLastIndexP, int aLastIndexN )
342 {
343 while( true )
344 {
345 bool p_ok, n_ok;
346 checkIndex( p_ok, curIndexP, aLastIndexP );
347 checkIndex( n_ok, curIndexN, aLastIndexN );
348
349 if( !p_ok && !n_ok )
350 break;
351
352 auto p_item = getItem( tunedP, curIndexP, aLastIndexP );
353 auto n_item = getItem( tunedN, curIndexN, aLastIndexN );
354
355 if( !p_item.arc && !n_item.arc )
356 {
357 m_result.AddCorner( p_item.startPt, n_item.startPt );
358 }
359 else if( p_item.arc && n_item.arc )
360 {
361 m_result.AddArc( *p_item.arc, *n_item.arc );
362 }
363 else if( p_item.arc && !n_item.arc )
364 {
365 m_result.AddCorner( p_item.startPt, n_item.startPt );
366
367 // Find arc in N
368 while( checkIndex( n_ok, curIndexN, aLastIndexN ) )
369 {
370 curIndexN = tunedN.NextShape( curIndexN );
371 n_item = getItem( tunedN, curIndexN, aLastIndexN );
372
373 if( n_item.arc )
374 {
375 m_result.AddArc( *p_item.arc, *n_item.arc );
376 break;
377 }
378 else
379 {
380 m_result.AddCorner( p_item.startPt, n_item.startPt );
381 }
382 }
383 }
384 else if( !p_item.arc && n_item.arc )
385 {
386 m_result.AddCorner( p_item.startPt, n_item.startPt );
387
388 // Find arc in P
389 while( checkIndex( p_ok, curIndexP, aLastIndexP ) )
390 {
391 curIndexP = tunedP.NextShape( curIndexP );
392 p_item = getItem( tunedP, curIndexP, aLastIndexP );
393
394 if( p_item.arc )
395 {
396 m_result.AddArc( *p_item.arc, *n_item.arc );
397 break;
398 }
399 else
400 {
401 m_result.AddCorner( p_item.startPt, n_item.startPt );
402 }
403 }
404 }
405
406 if( p_ok )
407 curIndexP = tunedP.NextShape( curIndexP );
408
409 if( n_ok )
410 curIndexN = tunedN.NextShape( curIndexN );
411 }
412 };
413
414 for( const DIFF_PAIR::COUPLED_SEGMENTS& sp : coupledSegments )
415 {
416 SEG base = baselineSegment( sp );
417 bool side = false;
418
419 if( m_settings.m_initialSide == 0 )
420 side = base.Side( aP ) < 0;
421 else
422 side = m_settings.m_initialSide < 0;
423
424 PNS_DBG( Dbg(), AddShape, base, GREEN, 10000, wxT( "dp-baseline" ) );
425
426 addCornersUntilIndex( sp.indexP, sp.indexN );
427
428 m_result.MeanderSegment( base, side );
429 }
430
431 addCornersUntilIndex( tunedP.PointCount() - 1, tunedN.PointCount() - 1 );
432
433 m_result.AddCorner( tunedP.CLastPoint(), tunedN.CLastPoint() );
434
435 long long int dpLen = origPathLength();
436 int64_t dpDelay = origPathDelay();
437
439
440 if( dpLen > m_settings.m_targetLength.Max() )
441 {
443 m_lastLength = dpLen;
444 m_lastDelay = dpDelay;
445 }
446 else
447 {
448 m_lastLength = dpLen - std::max( tunedP.Length(), tunedN.Length() );
449
450 if( m_settings.m_isTimeDomain )
451 {
452 int64_t tunedPDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
453 tunedP, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(),
454 m_netClass );
455 int64_t tunedNDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
456 tunedN, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(),
457 m_netClass );
458
459 m_lastDelay = dpDelay - std::max( tunedPDelay, tunedNDelay );
460 }
461
462 tuneLineLength( m_result, m_settings.m_targetLength.Opt() - dpLen );
463 }
464
465 if( m_lastStatus != TOO_LONG )
466 {
467 tunedP.Clear();
468 tunedN.Clear();
469
470 for( MEANDER_SHAPE* m : m_result.Meanders() )
471 {
472 if( m->Type() != MT_EMPTY )
473 {
474 tunedP.Append( m->CLine( 0 ) );
475 tunedN.Append( m->CLine( 1 ) );
476 }
477 }
478
479 m_lastLength += std::max( tunedP.Length(), tunedN.Length() );
480
481 if( m_settings.m_isTimeDomain )
482 {
483 int64_t tunedPDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
484 tunedP, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(),
485 m_netClass );
486 int64_t tunedNDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain(
487 tunedN, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(),
488 m_netClass );
489
490 m_lastDelay += std::max( tunedPDelay, tunedNDelay );
491 }
492
493 updateStatus();
494 }
495
496 m_finalShapeP.Clear();
497 m_finalShapeN.Clear();
498
499 if( m_settings.m_keepEndpoints )
500 {
501 preP.Simplify();
502 tunedP.Simplify();
503 postP.Simplify();
504
505 m_finalShapeP.Append( preP );
506 m_finalShapeP.Append( tunedP );
507 m_finalShapeP.Append( postP );
508
509 preN.Simplify();
510 tunedN.Simplify();
511 postN.Simplify();
512
513 m_finalShapeN.Append( preN );
514 m_finalShapeN.Append( tunedN );
515 m_finalShapeN.Append( postN );
516 }
517 else
518 {
519 m_finalShapeP.Append( preP );
520 m_finalShapeP.Append( tunedP );
521 m_finalShapeP.Append( postP );
522 m_finalShapeP.Simplify();
523
524 m_finalShapeN.Append( preN );
525 m_finalShapeN.Append( tunedN );
526 m_finalShapeN.Append( postN );
527 m_finalShapeN.Simplify();
528 }
529
530 return true;
531}
532
533
534bool DP_MEANDER_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
535{
536 LINE lP( m_originPair.PLine(), m_finalShapeP );
537 LINE lN( m_originPair.NLine(), m_finalShapeN );
538
539 m_currentNode->Add( lP );
540 m_currentNode->Add( lN );
541
543
544 return true;
545}
546
547
549{
550 m_world->KillChildren();
551 return true;
552}
553
554
556{
557 return m_originPair.CP().SegmentCount() > 0 || m_originPair.CN().SegmentCount() > 0;
558}
559
560
562{
563 if( m_currentNode )
565
566 m_currentNode = nullptr;
567 return true;
568}
569
570
572{
573 LINE l1( m_originPair.PLine(), aShape->CLine( 0 ) );
574 LINE l2( m_originPair.NLine(), aShape->CLine( 1 ) );
575
576 if( m_currentNode->CheckColliding( &l1 ) )
577 return false;
578
579 if( m_currentNode->CheckColliding( &l2 ) )
580 return false;
581
582 int w = aShape->Width();
583 int clearance = w + w * 3;
584
585 return m_result.CheckSelfIntersections( aShape, clearance );
586}
587
588
590{
593
594 ITEM_SET traces;
595
596 traces.Add( &m_currentTraceP );
597 traces.Add( &m_currentTraceN );
598
599 return traces;
600}
601
602
604{
605 ITEM_SET lines;
606
607 for( ITEM* item : m_tunedPathN )
608 lines.Add( item );
609
610 for( ITEM* item : m_tunedPathP )
611 lines.Add( item );
612
613 return lines;
614}
615
616
618{
619 return m_currentStart;
620}
621
622
624{
625 return m_currentEnd;
626}
627
628
630{
631 return m_initialSegment->Layers().Start();
632}
633
634
636{
637 if( m_lastLength )
638 return m_lastLength;
639 else
640 return origPathLength();
641}
642
643
645{
646 if( m_lastDelay )
647 return m_lastDelay;
648 else
649 return origPathDelay();
650}
651
652
657
658
659const std::vector<NET_HANDLE> DP_MEANDER_PLACER::CurrentNets() const
660{
661 std::vector<NET_HANDLE> rv;
662 rv.push_back( m_originPair.NetP() );
663 rv.push_back( m_originPair.NetN() );
664 return rv;
665}
666
667
669{
670 // If this is a time domain tuning, calculate the target length for the desired total delay
671 if( m_settings.m_isTimeDomain )
672 {
673 const int64_t curDelay = origPathDelay();
674
675 const int64_t desiredDelayMin = m_settings.m_targetLengthDelay.Min();
676 const int64_t desiredDelayOpt = m_settings.m_targetLengthDelay.Opt();
677 const int64_t desiredDelayMax = m_settings.m_targetLengthDelay.Max();
678
679 const int64_t delayDifferenceOpt = desiredDelayOpt - curDelay;
680
681 const int64_t curLength = origPathLength();
682 const int64_t lengthDiffMin = m_router->GetInterface()->CalculateLengthForDelay(
683 desiredDelayOpt - desiredDelayMin, GetOriginPair().Width(), true, GetOriginPair().Gap(),
684 m_router->GetCurrentLayer(), m_netClass );
685 int64_t lengthDiffOpt = m_router->GetInterface()->CalculateLengthForDelay(
686 std::abs( delayDifferenceOpt ), GetOriginPair().Width(), true, GetOriginPair().Gap(),
687 m_router->GetCurrentLayer(), m_netClass );
688 const int64_t lengthDiffMax = m_router->GetInterface()->CalculateLengthForDelay(
689 desiredDelayMax - desiredDelayOpt, GetOriginPair().Width(), true, GetOriginPair().Gap(),
690 m_router->GetCurrentLayer(), m_netClass );
691
692 lengthDiffOpt = delayDifferenceOpt > 0 ? lengthDiffOpt : -lengthDiffOpt;
693
694 m_settings.m_targetLength.SetMin( curLength + lengthDiffOpt - lengthDiffMin );
695 m_settings.m_targetLength.SetOpt( curLength + lengthDiffOpt );
696 m_settings.m_targetLength.SetMax( curLength + lengthDiffOpt + lengthDiffMax );
697 }
698}
699}
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.
ROUTER * Router() const
Return current router settings.
ROUTER * m_router
DEBUG_DECORATOR * Dbg() const
Basic class for a differential pair.
int Width() const
std::vector< COUPLED_SEGMENTS > COUPLED_SEGMENTS_VEC
void SetShape(const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN &aN, bool aSwapLanes=false)
int Gap() const
void CoupledSegmentPairs(COUPLED_SEGMENTS_VEC &aPairs) const
bool Start(const VECTOR2I &aP, ITEM *aStartItem) override
Start routing a single track at point aP, taking item aStartItem as anchor (unless NULL).
bool CheckFit(MEANDER_SHAPE *aShape) override
Checks if it's OK to place the shape aShape (i.e.
const ITEM_SET Traces() override
Function Traces()
bool pairOrientation(const DIFF_PAIR::COUPLED_SEGMENTS &aPair)
void calculateTimeDomainTargets()
Current routing start point (end of tail, beginning of head).
VECTOR2I m_currentStart
Current world state.
bool FixRoute(const VECTOR2I &aP, ITEM *aEndItem, bool aForceFinish=false) override
Commit the currently routed track to the parent node, taking aP as the final end point and aEndItem a...
int CurrentLayer() const override
Function CurrentLayer()
TUNING_STATUS TuningStatus() const override
Return the tuning status (too short, too long, etc.) of the trace(s) being tuned.
long long int TuningLengthResult() const override
Return the resultant length or skew of the tuned traces.
const SEG baselineSegment(const DIFF_PAIR::COUPLED_SEGMENTS &aCoupledSegs)
const DIFF_PAIR & GetOriginPair()
const ITEM_SET TunedPath() override
bool HasPlacedAnything() const override
bool Move(const VECTOR2I &aP, ITEM *aEndItem) override
Move the end of the currently routed trace to the point aP, taking aEndItem as anchor (if not NULL).
const VECTOR2I & CurrentEnd() const override
Function CurrentEnd()
const VECTOR2I & CurrentStart() const override
Function CurrentStart()
int64_t TuningDelayResult() const override
Return the resultant delay or skew of the tuned traces.
long long int origPathLength() const
const std::vector< NET_HANDLE > CurrentNets() const override
Function CurrentNets()
NODE * CurrentNode(bool aLoopsRemoved=false) const override
Return the most recent world state.
void Add(const LINE &aLine)
Base class for PNS router board items.
Definition pns_item.h:98
BOARD_ITEM * GetSourceItem() const
Definition pns_item.h:202
bool OfKind(int aKindMask) const
Definition pns_item.h:181
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
Represent a set of meanders fitted over a single or two lines.
void tuneLineLength(MEANDERED_LINE &aTuned, long long int aElongation)
Take a set of meanders in aTuned and tunes their length to extend the original line length by aElonga...
TUNING_STATUS
< Result of the length tuning operation
int m_currentWidth
Meander settings.
MEANDER_SETTINGS m_settings
The current end point.
int64_t lineDelay(const ITEM_SET &aLine, const SOLID *aStartPad, const SOLID *aEndPad) const
Calculate the total delay of the line represented by an item set (tracks and vias)
NODE * m_world
Width of the meandered trace(s).
VECTOR2I getSnappedStartPoint(LINKED_ITEM *aStartItem, VECTOR2I aStartPoint)
long long int lineLength(const ITEM_SET &aLine, const SOLID *aStartPad, const SOLID *aEndPad) const
Calculate the total length of the line represented by an item set (tracks and vias)
int Width() const
const SHAPE_LINE_CHAIN & CLine(int aShape) const
Keep the router "world" - i.e.
Definition pns_node.h:240
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:157
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:231
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:182
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
const ITEM_SET AssembleTuningPath(ROUTER_IFACE *aRouterIface, ITEM *aStart, SOLID **aStartPad=nullptr, SOLID **aEndPad=nullptr)
Like AssembleTrivialPath, but follows the track length algorithm, which discards segments that are fu...
Definition seg.h:42
VECTOR2I A
Definition seg.h:49
VECTOR2I B
Definition seg.h:50
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition seg.h:143
VECTOR2I GetEnd() const override
Definition shape_arc.h:208
VECTOR2I GetStart() const override
Definition shape_arc.h:207
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
virtual const SEG GetSegment(int aIndex) const override
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
bool IsArcSegment(size_t aSegment) const
long long int Length() const
Return length of the line chain in Euclidean metric.
@ GREEN
Definition color4d.h:57
@ YELLOW
Definition color4d.h:67
#define _(s)
Push and Shove diff pair dimensions (gap) settings dialog.
@ MT_EMPTY
Definition pns_meander.h:49
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
#define PNS_DBG(dbg, method,...)
int clearance
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:60
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687