KiCad PCB EDA Suite
pns_meander.cpp
Go to the documentation of this file.
1 /*
2  * KiRouter - a push-and-(sometimes-)shove PCB router
3  *
4  * Copyright (C) 2013-2014 CERN
5  * Copyright (C) 2016-2021 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 <base_units.h> // God forgive me doing this...
23 
24 #include "pns_node.h"
25 #include "pns_itemset.h"
26 #include "pns_meander.h"
28 #include "pns_router.h"
29 #include "pns_debug_decorator.h"
30 
31 namespace PNS {
32 
34 {
35  return m_placer->MeanderSettings();
36 }
37 
38 
40 {
41  return m_placer->MeanderSettings();
42 }
43 
44 
45 void MEANDERED_LINE::MeanderSegment( const SEG& aBase, bool aSide, int aBaseIndex )
46 {
47  double base_len = aBase.Length();
48 
50 
51  bool side = aSide;
52  VECTOR2D dir( aBase.B - aBase.A );
53 
54  if( !m_dual )
55  AddCorner( aBase.A );
56 
57  bool turning = false;
58  bool started = false;
59 
60  m_last = aBase.A;
61 
62  do
63  {
65 
67  m.SetBaseIndex( aBaseIndex );
68 
69  double thr = (double) m.spacing();
70 
71  bool fail = false;
72  double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm();
73 
74  auto addSingleIfFits = [&]()
75  {
76  fail = true;
77 
78  for( int i = 0; i < 2; i++ )
79  {
80  bool checkSide = ( i == 0 ) ? side : !side;
81 
82  if( m.Fit( MT_SINGLE, aBase, m_last, checkSide ) )
83  {
84  AddMeander( new MEANDER_SHAPE( m ) );
85  fail = false;
86  started = false;
87  side = !checkSide;
88  break;
89  }
90  }
91  };
92 
93  if( remaining < Settings( ).m_step )
94  break;
95 
96  if( remaining > 3.0 * thr )
97  {
98  if( !turning )
99  {
100  for( int i = 0; i < 2; i++ )
101  {
102  bool checkSide = ( i == 0 ) ? side : !side;
103 
104  if( m.Fit( MT_CHECK_START, aBase, m_last, checkSide ) )
105  {
106  turning = true;
107  AddMeander( new MEANDER_SHAPE( m ) );
108  side = !checkSide;
109  started = true;
110  break;
111  }
112  }
113 
114  if( !turning )
115  addSingleIfFits();
116  }
117  else
118  {
119  bool rv = m.Fit( MT_CHECK_FINISH, aBase, m_last, side );
120 
121  if( rv )
122  {
123  m.Fit( MT_TURN, aBase, m_last, side );
124  AddMeander( new MEANDER_SHAPE( m ) );
125  started = true;
126  }
127  else
128  {
129  m.Fit( MT_FINISH, aBase, m_last, side );
130  started = false;
131  AddMeander( new MEANDER_SHAPE( m ) );
132  turning = false;
133  }
134 
135  side = !side;
136  }
137  }
138  else if( started )
139  {
140  bool rv = m.Fit( MT_FINISH, aBase, m_last, side );
141 
142  if( rv )
143  AddMeander( new MEANDER_SHAPE( m ) );
144 
145  break;
146 
147  }
148  else if( !turning && remaining > thr * 2.0 )
149  {
150  addSingleIfFits();
151  }
152  else
153  {
154  fail = true;
155  }
156 
157  remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( );
158 
159  if( remaining < Settings( ).m_step )
160  break;
161 
162  if( fail )
163  {
166  tmp.SetBaseIndex( aBaseIndex );
167 
168  int nextP = tmp.spacing() - 2 * tmp.cornerRadius() + Settings().m_step;
169  VECTOR2I pn = m_last + dir.Resize( nextP );
170 
171  if( aBase.Contains( pn ) && !m_dual )
172  {
173  AddCorner( pn );
174  } else
175  break;
176  }
177 
178 
179  } while( true );
180 
181  if( !m_dual )
182  AddCorner( aBase.B );
183 }
184 
185 
187 {
188  // TODO: fix diff-pair meandering so we can use non-100% radii
189  int rPercent = m_dual ? 100 : Settings().m_cornerRadiusPercentage;
190 
191  return (int64_t) spacing() * rPercent / 200;
192 }
193 
194 
196 {
197  if( !m_dual )
198  {
199  return std::max( m_width + m_placer->Clearance(), Settings().m_spacing );
200  }
201  else
202  {
203  int sp = m_width + m_placer->Clearance() + ( 2 * std::abs( m_baselineOffset ) );
204  return std::max( sp, Settings().m_spacing );
205  }
206 }
207 
208 
210  bool aSide )
211 {
212  SHAPE_LINE_CHAIN lc;
213 
214  if( aDir.EuclideanNorm( ) == 0.0f )
215  {
216  lc.Append( aP );
217  return lc;
218  }
219 
220  VECTOR2D dir_u( aDir );
221  VECTOR2D dir_v( aDir.Perpendicular( ) );
222  VECTOR2D p = aP;
223  lc.Append( ( int ) p.x, ( int ) p.y );
224 
225  // fixme: refactor
227  {
228  case MEANDER_STYLE_ROUND:
229  {
230  VECTOR2D center = aP + dir_v * ( aSide ? -1.0 : 1.0 );
231 
232  lc.Append( SHAPE_ARC( center, aP, ( aSide ? -90 : 90 ) ) );
233  }
234  break;
235 
237  {
238  double radius = (double) aDir.EuclideanNorm();
239  double correction = 0;
240 
241  if( m_dual && radius > m_meanCornerRadius )
242  correction = (double)( -2 * abs(m_baselineOffset) ) * tan( 22.5 * M_PI / 180.0 );
243 
244  VECTOR2D dir_cu = dir_u.Resize( correction );
245  VECTOR2D dir_cv = dir_v.Resize( correction );
246 
247  p = aP - dir_cu;
248  lc.Append( ( int ) p.x, ( int ) p.y );
249  p = aP + dir_u + (dir_v + dir_cv) * ( aSide ? -1.0 : 1.0 );
250  lc.Append( ( int ) p.x, ( int ) p.y );
251  }
252  break;
253  }
254 
255  p = aP + dir_u + dir_v * ( aSide ? -1.0 : 1.0 );
256  lc.Append( ( int ) p.x, ( int ) p.y );
257 
258  return lc;
259 }
260 
261 
262 void MEANDER_SHAPE::start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir )
263 {
264  m_currentTarget = aTarget;
266  m_currentTarget->Append( aWhere );
267  m_currentDir = aDir;
268  m_currentPos = aWhere;
269 }
270 
271 
272 void MEANDER_SHAPE::forward( int aLength )
273 {
274  m_currentPos += m_currentDir.Resize( aLength );
276 }
277 
278 
279 void MEANDER_SHAPE::turn( int aAngle )
280 {
281  m_currentDir = m_currentDir.Rotate( (double) aAngle * M_PI / 180.0 );
282 }
283 
284 
285 void MEANDER_SHAPE::miter( int aRadius, bool aSide )
286 {
287  if( aRadius <= 0 )
288  {
289  turn( aSide ? -90 : 90 );
290  return;
291  }
292 
293  VECTOR2D dir = m_currentDir.Resize( (double) aRadius );
294  SHAPE_LINE_CHAIN lc = makeMiterShape( m_currentPos, dir, aSide );
295 
296  m_currentPos = lc.CPoint( -1 );
297  m_currentDir = dir.Rotate( aSide ? -M_PI / 2.0 : M_PI / 2.0 );
298 
299  m_currentTarget->Append( lc );
300 }
301 
302 
303 void MEANDER_SHAPE::uShape( int aSides, int aCorner, int aTop )
304 {
305  forward( aSides );
306  miter( aCorner, true );
307  forward( aTop );
308  miter( aCorner, true );
309  forward( aSides );
310 }
311 
312 
314  bool aSide, MEANDER_TYPE aType, int aAmpl,
315  int aBaselineOffset )
316 {
317  int cr = cornerRadius();
318  int offset = aBaselineOffset;
319  int spc = spacing();
320 
321  if( aSide )
322  offset *= -1;
323 
324  VECTOR2D dir_u_b( aDir.Resize( offset ) );
325  VECTOR2D dir_v_b( dir_u_b.Perpendicular() );
326 
327  if( 2 * cr > aAmpl )
328  {
329  cr = aAmpl / 2;
330  }
331 
332  if( 2 * cr > spc )
333  {
334  cr = spc / 2;
335  }
336 
337  m_meanCornerRadius = cr;
338 
339  SHAPE_LINE_CHAIN lc;
340 
341  start( &lc, aP + dir_v_b, aDir );
342 
343  switch( aType )
344  {
345  case MT_EMPTY:
346  {
347  lc.Append( aP + dir_v_b + aDir );
348  break;
349  }
350  case MT_START:
351  {
352  miter( cr - offset, false );
353  uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr );
354  forward( std::min( cr - offset, cr + offset ) );
355  forward( std::abs( offset ) );
356  break;
357  }
358 
359  case MT_FINISH:
360  {
361  start( &lc, aP - dir_u_b, aDir );
362  turn( 90 );
363  forward( std::min( cr - offset, cr + offset ) );
364  forward( std::abs( offset ) );
365  uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr );
366  miter( cr - offset, false );
367  break;
368  }
369 
370  case MT_TURN:
371  {
372  start( &lc, aP - dir_u_b, aDir );
373  turn( 90 );
374  forward( std::abs( offset ) );
375  uShape( aAmpl - cr, cr + offset, spc - 2 * cr );
376  forward( std::abs( offset ) );
377  break;
378  }
379 
380  case MT_SINGLE:
381  {
382  miter( cr - offset, false );
383  uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr );
384  miter( cr - offset, false );
385  lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc ) );
386  break;
387  }
388 
389  default:
390  break;
391  }
392 
393  if( aSide )
394  {
395  SEG axis( aP, aP + aDir );
396 
397  lc.Mirror( axis );
398  }
399 
400  return lc;
401 }
402 
403 
405 {
406  for( int i = m_meanders.size() - 1; i >= 0; i-- )
407  {
408  MEANDER_SHAPE* m = m_meanders[i];
409 
410  if( m->Type() == MT_EMPTY || m->Type() == MT_CORNER )
411  continue;
412 
413  const SEG& b1 = aShape->BaseSegment();
414  const SEG& b2 = m->BaseSegment();
415 
416  if( b1.ApproxParallel( b2 ) )
417  continue;
418 
419  int n = m->CLine( 0 ).SegmentCount();
420 
421  for( int j = n - 1; j >= 0; j-- )
422  {
423  if( aShape->CLine( 0 ).Collide( m->CLine( 0 ) .CSegment( j ), aClearance ) )
424  return false;
425  }
426  }
427 
428  return true;
429 }
430 
431 
432 bool MEANDER_SHAPE::Fit( MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide )
433 {
434  const MEANDER_SETTINGS& st = Settings();
435 
436  bool checkMode = false;
437  MEANDER_TYPE prim1, prim2;
438 
439  if( aType == MT_CHECK_START )
440  {
441  prim1 = MT_START;
442  prim2 = MT_TURN;
443  checkMode = true;
444  }
445  else if( aType == MT_CHECK_FINISH )
446  {
447  prim1 = MT_TURN;
448  prim2 = MT_FINISH;
449  checkMode = true;
450  }
451 
452  if( checkMode )
453  {
456 
459 
460  bool c1 = m1.Fit( prim1, aSeg, aP, aSide );
461  bool c2 = false;
462 
463  if( c1 )
464  c2 = m2.Fit( prim2, aSeg, m1.End(), !aSide );
465 
466  if( c1 && c2 )
467  {
468  m_type = prim1;
469  m_shapes[0] = m1.m_shapes[0];
470  m_shapes[1] = m1.m_shapes[1];
471  m_baseSeg =aSeg;
472  m_p0 = aP;
473  m_side = aSide;
474  m_amplitude = m1.Amplitude();
475  m_dual = m1.m_dual;
476  m_baseSeg = m1.m_baseSeg;
480  return true;
481  }
482  else
483  {
484  return false;
485  }
486  }
487 
488  int minAmpl = st.m_minAmplitude;
489  int maxAmpl = st.m_maxAmplitude;
490 
491  if( m_dual )
492  {
493  minAmpl = std::max( minAmpl, 2 * std::abs( m_baselineOffset ) );
494  maxAmpl = std::max( maxAmpl, 2 * std::abs( m_baselineOffset ) );
495  }
496 
497  for( int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step )
498  {
499  if( m_dual )
500  {
501  m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, ampl,
503  m_shapes[1] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, ampl,
504  -m_baselineOffset );
505  }
506  else
507  {
508  m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, ampl, 0 );
509  }
510 
511  m_type = aType;
512  m_baseSeg = aSeg;
513  m_p0 = aP;
514  m_side = aSide;
515  m_amplitude = ampl;
516 
518 
519  if( m_placer->CheckFit( this ) )
520  return true;
521  }
522 
523  return false;
524 }
525 
526 
528 {
530  m_dual ? m_baselineOffset : 0 );
531 
532  if( m_dual )
535 
537 }
538 
539 
540 void MEANDER_SHAPE::Resize( int aAmpl )
541 {
542  if( aAmpl < 0 )
543  return;
544 
545  m_amplitude = aAmpl;
546 
547  Recalculate();
548 }
549 
550 
552 {
554 
556 
557  m_type = MT_EMPTY;
558 
560 
561  if( m_dual )
563 }
564 
565 
566 void MEANDERED_LINE::AddCorner( const VECTOR2I& aA, const VECTOR2I& aB )
567 {
569 
570  m->MakeCorner( aA, aB );
571  m_last = aA;
572 
573  m_meanders.push_back( m );
574 }
575 
576 
577 void MEANDERED_LINE::AddArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
578 {
580 
581  m->MakeArc( aArc1, aArc2 );
582  m_last = aArc1.GetP1();
583 
584  m_meanders.push_back( m );
585 }
586 
587 
588 void MEANDERED_LINE::AddArcAndPt( const SHAPE_ARC& aArc1, const VECTOR2I& aPt2 )
589 {
590  SHAPE_ARC arc2( aPt2, aPt2, aPt2, 0 );
591 
592  AddArc( aArc1, arc2 );
593 }
594 
595 
596 void MEANDERED_LINE::AddPtAndArc( const VECTOR2I& aPt1, const SHAPE_ARC& aArc2 )
597 {
598  SHAPE_ARC arc1( aPt1, aPt1, aPt1, 0 );
599 
600  AddArc( arc1, aArc2 );
601 }
602 
603 
604 void MEANDER_SHAPE::MakeCorner( const VECTOR2I& aP1, const VECTOR2I& aP2 )
605 {
606  SetType( MT_CORNER );
607  m_shapes[0].Clear();
608  m_shapes[1].Clear();
609  m_shapes[0].Append( aP1 );
610  m_shapes[1].Append( aP2 );
611  m_clippedBaseSeg.A = aP1;
612  m_clippedBaseSeg.B = aP1;
613 }
614 
615 
616 void MEANDER_SHAPE::MakeArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
617 {
618  SetType( MT_CORNER );
619  m_shapes[0].Clear();
620  m_shapes[1].Clear();
621  m_shapes[0].Append( aArc1 );
622  m_shapes[1].Append( aArc2 );
623  m_clippedBaseSeg.A = aArc1.GetP1();
624  m_clippedBaseSeg.B = aArc1.GetP1();
625 }
626 
627 
629 {
630  m_last = aShape->BaseSegment().B;
631  m_meanders.push_back( aShape );
632 }
633 
634 
636 {
637  for( MEANDER_SHAPE* m : m_meanders )
638  {
639  delete m;
640  }
641 
642  m_meanders.clear( );
643 }
644 
645 
647 {
648  return m_clippedBaseSeg.Length();
649 }
650 
651 
653 {
654  return CLine( 0 ).Length();
655 }
656 
657 
659 {
660  if( m_dual )
661  {
662  VECTOR2I midpA = ( CLine( 0 ).CPoint( 0 ) + CLine( 1 ).CPoint( 0 ) ) / 2;
663  VECTOR2I midpB = ( CLine( 0 ).CPoint( -1 ) + CLine( 1 ).CPoint( -1 ) ) / 2;
664 
667  }
668  else
669  {
670  m_clippedBaseSeg.A = m_baseSeg.LineProject( CLine( 0 ).CPoint( 0 ) );
671  m_clippedBaseSeg.B = m_baseSeg.LineProject( CLine( 0 ).CPoint( -1 ) );
672  }
673 }
674 
675 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
int Length() const
Return the length (this).
Definition: seg.h:350
long long int Length() const
Return length of the line chain in Euclidean metric.
int m_minAmplitude
Maximum meandering amplitude.
Definition: pns_meander.h:77
void uShape(int aSides, int aCorner, int aTop)
Generate a 90-degree circular arc.
void SetBaselineOffset(int aOffset)
Set the parallel offset between the base segment and the meandered line.
Definition: pns_meander.h:293
bool CheckSelfIntersections(MEANDER_SHAPE *aShape, int aClearance)
Check if the given shape is intersecting with any other meander in the current line.
int BaselineLength() const
bool m_side
The actual shapes (0 used for single, both for dual).
Definition: pns_meander.h:363
The geometry of a single meander.
Definition: pns_meander.h:110
SHAPE_LINE_CHAIN makeMiterShape(const VECTOR2D &aP, const VECTOR2D &aDir, bool aSide)
Produce a meander shape of given type.
VECTOR2I End() const
Definition: pns_meander.h:224
Implementation of conversion functions that require both schematic and board internal units.
MEANDER_PLACER_BASE * m_placer
Definition: pns_meander.h:511
VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
Definition: vector2d.h:314
MEANDER_TYPE
Shapes of available meanders.
Definition: pns_meander.h:37
VECTOR2I m_p0
Base segment (unclipped).
Definition: pns_meander.h:354
void AddCorner(const VECTOR2I &aA, const VECTOR2I &aB=VECTOR2I(0, 0))
Create a dummy meander shape representing a line corner.
void MakeArc(const SHAPE_ARC &aArc1, const SHAPE_ARC &aArc2=SHAPE_ARC())
Create a dummy meander shape representing an arc corner.
void AddPtAndArc(const VECTOR2I &aPt1, const SHAPE_ARC &aArc2)
Create a dummy meander shape representing an arc corner.
virtual int Clearance()
Return the clearance of the track(s) being length tuned.
SHAPE_LINE_CHAIN * m_currentTarget
Definition: pns_meander.h:378
std::vector< MEANDER_SHAPE * > m_meanders
Definition: pns_meander.h:512
void Clear()
Clear the line geometry, removing all corners and meanders.
int m_baseIndex
The current turtle direction.
Definition: pns_meander.h:369
MEANDER_TYPE Type() const
Definition: pns_meander.h:145
Dimensions for the meandering algorithm.
Definition: pns_meander.h:58
SHAPE_LINE_CHAIN genMeanderShape(const VECTOR2D &aP, const VECTOR2D &aDir, bool aSide, MEANDER_TYPE aType, int aAmpl, int aBaselineOffset=0)
Recalculate the clipped baseline after the parameters of the meander have been changed.
void Recalculate()
Recalculate the line chain representing the meander's shape.
virtual bool CheckFit(MEANDER_SHAPE *aShape)
Checks if it's OK to place the shape aShape (i.e.
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
Definition: pns_meander.h:95
void AddArcAndPt(const SHAPE_ARC &aArc1, const VECTOR2I &aPt2)
Create a dummy meander shape representing an arc corner.
const MEANDER_SETTINGS & Settings() const
Definition: pns_meander.cpp:39
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
void Resize(int aAmpl)
Change the amplitude of the meander shape to aAmpl and recalculates the resulting line chain.
void miter(int aRadius, bool aSide)
Tell the turtle to draw an U-like shape.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int m_step
Length PadToDie.
Definition: pns_meander.h:86
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Definition: seg.cpp:268
bool ApproxParallel(const SEG &aSeg) const
Definition: seg.h:290
void start(SHAPE_LINE_CHAIN *aTarget, const VECTOR2D &aWhere, const VECTOR2D &aDir)
Move turtle forward by aLength.
void AddArc(const SHAPE_ARC &aArc1, const SHAPE_ARC &aArc2=SHAPE_ARC())
Create a dummy meander shape representing an arc corner.
void AddMeander(MEANDER_SHAPE *aShape)
Add a new meander shape to the meandered line.
MEANDER_TYPE m_type
The placer that placed this meander.
Definition: pns_meander.h:333
const SHAPE_LINE_CHAIN & CLine(int aShape) const
Definition: pns_meander.h:232
int m_cornerRadiusPercentage
Allowable tuning error.
Definition: pns_meander.h:98
int m_meanCornerRadius
First point of the meandered line.
Definition: pns_meander.h:351
const SEG & BaseSegment() const
Return the base segment the meander was fitted to.
Definition: pns_meander.h:259
void turn(int aAngle)
Tell the turtle to draw a mitered corner of given radius and turn direction.
MEANDER_PLACER_BASE * m_placer
Dual or single line.
Definition: pns_meander.h:336
void MakeCorner(const VECTOR2I &aP1, const VECTOR2I &aP2=VECTOR2I(0, 0))
Create a dummy meander shape representing a line corner.
int m_width
Amplitude of the meander.
Definition: pns_meander.h:342
SHAPE_LINE_CHAIN m_shapes[2]
Index of the meandered segment in the base line.
Definition: pns_meander.h:366
int MaxTunableLength() const
int SegmentCount() const
Return the number of segments in this line chain.
void forward(int aLength)
Turn the turtle by aAngle.
int m_baselineOffset
Average radius of meander corners (for correction of DP meanders).
Definition: pns_meander.h:348
const MEANDER_SETTINGS & Settings() const
Definition: pns_meander.cpp:33
int m_amplitude
Offset wrs the base segment (dual only).
Definition: pns_meander.h:345
bool Fit(MEANDER_TYPE aType, const SEG &aSeg, const VECTOR2I &aP, bool aSide)
Attempt to fit a meander of a given type onto a segment, avoiding collisions with other board feature...
Definition: seg.h:40
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:404
void MakeEmpty()
Replace the meander with straight bypass line(s), effectively clearing it.
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
Definition: vector2d.h:371
void MeanderSegment(const SEG &aSeg, bool aSide, int aBaseIndex=0)
Fit maximum amplitude meanders on a given segment and adds to the current line.
Definition: pns_meander.cpp:45
void SetBaseIndex(int aIndex)
Set an auxiliary index of the segment being meandered in its original LINE.
Definition: pns_meander.h:153
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
Represent a polyline (an zero-thickness chain of connected line segments).
int cornerRadius() const
Return sanitized spacing value.
VECTOR2I A
Definition: seg.h:48
SEG m_baseSeg
Base segment (clipped).
Definition: pns_meander.h:357
void Clear()
Remove all points from the line chain.
void updateBaseSegment()
Return sanitized corner radius value.
bool m_dual
Width of the line.
Definition: pns_meander.h:339
int m_spacing
Amplitude/spacing adjustment step.
Definition: pns_meander.h:83
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
int spacing() const
The type of meander.
Push and Shove diff pair dimensions (gap) settings dialog.
VECTOR2D m_currentPos
The line the turtle is drawing on.
Definition: pns_meander.h:375
virtual const MEANDER_SETTINGS & MeanderSettings() const
Return the current meandering configuration.
const VECTOR2I & GetP1() const
Definition: shape_arc.h:112
void SetType(MEANDER_TYPE aType)
Set the type of the meander.
Definition: pns_meander.h:137
int Amplitude() const
Definition: pns_meander.h:169
SEG m_clippedBaseSeg
Side (true = right).
Definition: pns_meander.h:360
VECTOR2D m_currentDir
The current turtle position.
Definition: pns_meander.h:372
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both).
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition: pns_meander.h:80
bool Contains(const SEG &aSeg) const
Definition: seg.h:331
VECTOR2I B
Definition: seg.h:49