KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 "pns_node.h"
23#include "pns_itemset.h"
24#include "pns_meander.h"
26#include "pns_router.h"
27#include "pns_debug_decorator.h"
28
29namespace PNS {
30
32{
33 return m_placer->MeanderSettings();
34}
35
36
38{
39 return m_placer->MeanderSettings();
40}
41
42
43void MEANDERED_LINE::MeanderSegment( const SEG& aBase, bool aSide, int aBaseIndex )
44{
45 double base_len = aBase.Length();
46
48
49 bool singleSided = Settings().m_singleSided;
50 bool side = aSide;
51 VECTOR2D dir( aBase.B - aBase.A );
52
53 if( !m_dual )
54 AddCorner( aBase.A );
55
56 bool turning = false;
57 bool started = false;
58
59 m_last = aBase.A;
60
61 do
62 {
64
66 m.SetBaseIndex( aBaseIndex );
67
68 double thr = (double) m.spacing();
69
70 bool fail = false;
71 double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm();
72
73 auto flipInitialSide =
74 [&]()
75 {
77 settings.m_initialSide = (PNS::MEANDER_SIDE) -settings.m_initialSide;
78 m_placer->UpdateSettings( settings );
79 };
80
81 auto addSingleIfFits =
82 [&]()
83 {
84 fail = true;
85
86 if( m.Fit( MT_SINGLE, aBase, m_last, side ) )
87 {
88 AddMeander( new MEANDER_SHAPE( m ) );
89 fail = false;
90 started = false;
91 }
92
93 if( fail && !singleSided )
94 {
95 if( m.Fit( MT_SINGLE, aBase, m_last, !side ) )
96 {
97 if( !started )
98 flipInitialSide();
99
100 AddMeander( new MEANDER_SHAPE( m ) );
101 fail = false;
102 started = false;
103 side = !side;
104 }
105 }
106 };
107
108 if( remaining < Settings( ).m_step )
109 break;
110
111 if( !singleSided && remaining > 3.0 * thr )
112 {
113 if( !turning )
114 {
115 for( int i = 0; i < 2; i++ )
116 {
117 bool checkSide = ( i == 0 ) ? side : !side;
118
119 if( m.Fit( MT_CHECK_START, aBase, m_last, checkSide ) )
120 {
121 if( !started && checkSide != side )
122 flipInitialSide();
123
124 turning = true;
125 AddMeander( new MEANDER_SHAPE( m ) );
126 side = !checkSide;
127 started = true;
128 break;
129 }
130 }
131
132 if( !turning )
133 addSingleIfFits();
134 }
135 else
136 {
137 bool rv = m.Fit( MT_CHECK_FINISH, aBase, m_last, side );
138
139 if( rv )
140 {
141 m.Fit( MT_TURN, aBase, m_last, side );
142 AddMeander( new MEANDER_SHAPE( m ) );
143 side = !side;
144 started = true;
145 }
146 else
147 {
148 m.Fit( MT_FINISH, aBase, m_last, side );
149 started = false;
150 AddMeander( new MEANDER_SHAPE( m ) );
151 turning = false;
152 }
153 }
154 }
155 else if( !singleSided && started )
156 {
157 bool rv = m.Fit( MT_FINISH, aBase, m_last, side );
158
159 if( rv )
160 AddMeander( new MEANDER_SHAPE( m ) );
161
162 break;
163
164 }
165 else if( !turning && remaining > thr * 2.0 )
166 {
167 addSingleIfFits();
168 }
169 else
170 {
171 fail = true;
172 }
173
174 remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( );
175
176 if( remaining < Settings( ).m_step )
177 break;
178
179 if( fail )
180 {
183 tmp.SetBaseIndex( aBaseIndex );
184
185 int nextP = tmp.spacing() - 2 * tmp.cornerRadius() + Settings().m_step;
186 VECTOR2I pn = m_last + dir.Resize( nextP );
187
188 if( aBase.Contains( pn ) && !m_dual )
189 AddCorner( pn );
190 else
191 break;
192 }
193
194
195 } while( true );
196
197 if( !m_dual )
198 AddCorner( aBase.B );
199}
200
201
203{
204 int minAmplitude = Settings().m_minAmplitude;
205
206 // DP meanders don't really support smaller amplitudes
207 minAmplitude = std::max( minAmplitude, std::abs( m_baselineOffset ) * 2 );
208
209 // The path length won't be correct with very small arcs
211 minAmplitude = std::max( minAmplitude, m_width + std::abs( m_baselineOffset ) * 2 );
212
213 return minAmplitude;
214}
215
216
218{
219 int rPercent = Settings().m_cornerRadiusPercentage;
220 int optCr = static_cast<int>( static_cast<SEG::ecoord>( spacing() ) * rPercent / 200 );
221 int minCr = std::abs( m_baselineOffset );
222 int maxCr = std::min( m_amplitude / 2, spacing() / 2 );
223
224 if( maxCr > minCr )
225 return std::clamp( optCr, minCr, maxCr );
226 else
227 return maxCr;
228}
229
230
232{
233 if( !m_dual )
234 {
235 return std::max( m_width + m_placer->Clearance(), Settings().m_spacing );
236 }
237 else
238 {
239 int sp = m_width + m_placer->Clearance() + ( 2 * std::abs( m_baselineOffset ) );
240 return std::max( sp, Settings().m_spacing );
241 }
242}
243
244
246 bool aSide )
247{
249
250 if( aDir.EuclideanNorm( ) == 0.0f )
251 {
252 lc.Append( aP );
253 return lc;
254 }
255
256 VECTOR2D dir_u( aDir );
257 VECTOR2D dir_v( aDir.Perpendicular( ) );
258 VECTOR2D p = aP;
259 lc.Append( ( int ) p.x, ( int ) p.y );
260
261 // fixme: refactor
263 {
265 {
266 VECTOR2D center = aP + dir_v * ( aSide ? -1.0 : 1.0 );
267
268 lc.Append( SHAPE_ARC( center, aP, ( aSide ? -ANGLE_90 : ANGLE_90 ) ) );
269 break;
270 }
271
273 {
274 double radius = (double) aDir.EuclideanNorm();
275 double correction = 0;
276
277 if( m_dual && radius > m_meanCornerRadius )
278 correction = (double)( -2 * abs(m_baselineOffset) ) * tan( 22.5 * M_PI / 180.0 );
279
280 VECTOR2D dir_cu = dir_u.Resize( correction );
281 VECTOR2D dir_cv = dir_v.Resize( correction );
282
283 p = aP - dir_cu;
284 lc.Append( ( int ) p.x, ( int ) p.y );
285 p = aP + dir_u + (dir_v + dir_cv) * ( aSide ? -1.0 : 1.0 );
286 lc.Append( ( int ) p.x, ( int ) p.y );
287 break;
288 }
289
290 default:
291 break;
292 }
293
294 p = aP + dir_u + dir_v * ( aSide ? -1.0 : 1.0 );
295 lc.Append( ( int ) p.x, ( int ) p.y );
296
297 return lc;
298}
299
300
301void MEANDER_SHAPE::start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir )
302{
303 m_currentTarget = aTarget;
305 m_currentTarget->Append( aWhere );
306 m_currentDir = aDir;
307 m_currentPos = aWhere;
308}
309
310
311void MEANDER_SHAPE::forward( int aLength )
312{
313 // Very small segments cause problems.
314 if( aLength < 5 )
315 return;
316
317 m_currentPos += m_currentDir.Resize( aLength );
319}
320
321
322void MEANDER_SHAPE::turn( const EDA_ANGLE& aAngle )
323{
324 RotatePoint( m_currentDir, aAngle );
325}
326
327
328void MEANDER_SHAPE::miter( int aRadius, bool aSide )
329{
330 if( aRadius <= 0 )
331 {
332 turn( aSide ? ANGLE_90 : -ANGLE_90 );
333 return;
334 }
335
336 VECTOR2D dir = m_currentDir.Resize( (double) aRadius );
337 SHAPE_LINE_CHAIN lc = makeMiterShape( m_currentPos, dir, aSide );
338
339 m_currentPos = lc.CPoint( -1 );
340 turn( aSide ? ANGLE_90 : -ANGLE_90 );
341
342 m_currentTarget->Append( lc );
343}
344
345
346void MEANDER_SHAPE::uShape( int aSides, int aCorner, int aTop )
347{
348 forward( aSides );
349 miter( aCorner, true );
350 forward( aTop );
351 miter( aCorner, true );
352 forward( aSides );
353}
354
355
357 bool aSide, MEANDER_TYPE aType,
358 int aBaselineOffset )
359{
360 int cr = cornerRadius();
361 int offset = aBaselineOffset;
362 int spc = spacing();
363 int amplitude = m_amplitude;
364 int targetBaseLen = m_targetBaseLen;
365
366 if( aSide )
367 offset *= -1;
368
369 VECTOR2D dir_u_b( aDir.Resize( offset ) );
370 VECTOR2D dir_v_b( dir_u_b.Perpendicular() );
371
372 if( 2 * cr > amplitude )
373 cr = amplitude / 2;
374
375 if( 2 * cr > spc )
376 cr = spc / 2;
377
378 if( cr - offset < 0 )
379 cr = offset;
380
382
383 int sCorner = cr - offset;
384 int uCorner = cr + offset;
385 int startSide = amplitude - 2 * cr + std::abs( offset );
386 int turnSide = amplitude - cr;
387 int top = spc - 2 * cr;
388
390
391 start( &lc, aP + dir_v_b, aDir );
392
393 switch( aType )
394 {
395 case MT_EMPTY:
396 {
397 lc.Append( aP + dir_v_b + aDir );
398 break;
399 }
400 case MT_START:
401 {
402 if( targetBaseLen )
403 top = std::max( top, targetBaseLen - sCorner - uCorner * 2 + offset );
404
405 miter( sCorner, false );
406 uShape( startSide, uCorner, top );
407 forward( std::min( sCorner, uCorner ) );
408 forward( std::abs( offset ) );
409 break;
410 }
411
412 case MT_FINISH:
413 {
414 if( targetBaseLen )
415 top = std::max( top, targetBaseLen - cr - spc );
416
417 start( &lc, aP - dir_u_b, aDir );
418 turn( -ANGLE_90 );
419 forward( std::min( sCorner, uCorner ) );
420 forward( std::abs( offset ) );
421 uShape( startSide, uCorner, top );
422 miter( sCorner, false );
423
424 if( targetBaseLen >= spc + cr )
425 lc.Append( aP + dir_v_b + aDir.Resize( targetBaseLen ) );
426 else
427 lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc - cr ) );
428
429 break;
430 }
431
432 case MT_TURN:
433 {
434 if( targetBaseLen )
435 top = std::max( top, targetBaseLen - uCorner * 2 + offset * 2 );
436
437 start( &lc, aP - dir_u_b, aDir );
438 turn( -ANGLE_90 );
439 forward( std::abs( offset ) );
440 uShape( turnSide, uCorner, top );
441 forward( std::abs( offset ) );
442 break;
443 }
444
445 case MT_SINGLE:
446 {
447 if( targetBaseLen )
448 top = std::max( top, ( targetBaseLen - sCorner * 2 - uCorner * 2 ) / 2 );
449
450 miter( sCorner, false );
451 uShape( startSide, uCorner, top );
452 miter( sCorner, false );
453 lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc ) );
454 break;
455 }
456
457 default:
458 break;
459 }
460
461 if( aSide )
462 {
463 SEG axis( aP, aP + aDir );
464
465 lc.Mirror( axis );
466 }
467
468 return lc;
469}
470
471
473{
474 for( int i = m_meanders.size() - 1; i >= 0; i-- )
475 {
477
478 if( m->Type() == MT_EMPTY || m->Type() == MT_CORNER )
479 continue;
480
481 const SEG& b1 = aShape->BaseSegment();
482 const SEG& b2 = m->BaseSegment();
483
484 if( b1.ApproxParallel( b2 ) )
485 continue;
486
487 int n = m->CLine( 0 ).SegmentCount();
488
489 for( int j = n - 1; j >= 0; j-- )
490 {
491 if( aShape->CLine( 0 ).Collide( m->CLine( 0 ) .CSegment( j ), aClearance ) )
492 return false;
493 }
494 }
495
496 return true;
497}
498
499
500bool MEANDER_SHAPE::Fit( MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide )
501{
502 const MEANDER_SETTINGS& st = Settings();
503
504 bool checkMode = false;
505 MEANDER_TYPE prim1, prim2;
506
507 if( aType == MT_CHECK_START )
508 {
509 prim1 = MT_START;
510 prim2 = MT_TURN;
511 checkMode = true;
512 }
513 else if( aType == MT_CHECK_FINISH )
514 {
515 prim1 = MT_TURN;
516 prim2 = MT_FINISH;
517 checkMode = true;
518 }
519
520 if( checkMode )
521 {
524
526 m2.SetBaselineOffset( m_baselineOffset );
527
528 bool c1 = m1.Fit( prim1, aSeg, aP, aSide );
529 bool c2 = false;
530
531 if( c1 )
532 c2 = m2.Fit( prim2, aSeg, m1.End(), !aSide );
533
534 if( c1 && c2 )
535 {
536 m_type = prim1;
537 m_shapes[0] = m1.m_shapes[0];
538 m_shapes[1] = m1.m_shapes[1];
539 m_baseSeg =aSeg;
540 m_p0 = aP;
541 m_side = aSide;
542 m_amplitude = m1.Amplitude();
543 m_dual = m1.m_dual;
544 m_baseSeg = m1.m_baseSeg;
548 return true;
549 }
550 else
551 {
552 return false;
553 }
554 }
555
556 int minAmpl = MinAmplitude();
557 int maxAmpl = std::max( st.m_maxAmplitude, minAmpl );
558
559 for( int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step )
560 {
561 m_amplitude = ampl;
562
563 if( m_dual )
564 {
565 m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, m_baselineOffset );
566 m_shapes[1] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, -m_baselineOffset );
567 }
568 else
569 {
570 m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, 0 );
571 }
572
573 m_type = aType;
574 m_baseSeg = aSeg;
575 m_p0 = aP;
576 m_side = aSide;
577
579
580 if( m_placer->CheckFit( this ) )
581 return true;
582 }
583
584 return false;
585}
586
587
589{
591 m_dual ? m_baselineOffset : 0 );
592
593 if( m_dual )
596
598}
599
600
601void MEANDER_SHAPE::Resize( int aAmpl )
602{
603 if( aAmpl < 0 )
604 return;
605
606 m_amplitude = aAmpl;
607
608 Recalculate();
609}
610
611
613{
615
617
619 m_amplitude = 0;
620
622
623 if( m_dual )
625}
626
627
628void MEANDERED_LINE::AddCorner( const VECTOR2I& aA, const VECTOR2I& aB )
629{
631
632 m->MakeCorner( aA, aB );
633 m_last = aA;
634
635 m_meanders.push_back( m );
636}
637
638
639void MEANDERED_LINE::AddArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
640{
642
643 m->MakeArc( aArc1, aArc2 );
644 m_last = aArc1.GetP1();
645
646 m_meanders.push_back( m );
647}
648
649
650void MEANDERED_LINE::AddArcAndPt( const SHAPE_ARC& aArc1, const VECTOR2I& aPt2 )
651{
652 SHAPE_ARC arc2( aPt2, aPt2, aPt2, 0 );
653
654 AddArc( aArc1, arc2 );
655}
656
657
658void MEANDERED_LINE::AddPtAndArc( const VECTOR2I& aPt1, const SHAPE_ARC& aArc2 )
659{
660 SHAPE_ARC arc1( aPt1, aPt1, aPt1, 0 );
661
662 AddArc( arc1, aArc2 );
663}
664
665
666void MEANDER_SHAPE::MakeCorner( const VECTOR2I& aP1, const VECTOR2I& aP2 )
667{
669 m_shapes[0].Clear();
670 m_shapes[1].Clear();
671 m_shapes[0].Append( aP1 );
672 m_shapes[1].Append( aP2 );
673 m_clippedBaseSeg.A = aP1;
674 m_clippedBaseSeg.B = aP1;
675}
676
677
678void MEANDER_SHAPE::MakeArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
679{
681 m_shapes[0].Clear();
682 m_shapes[1].Clear();
683 m_shapes[0].Append( aArc1 );
684 m_shapes[1].Append( aArc2 );
685 m_clippedBaseSeg.A = aArc1.GetP1();
686 m_clippedBaseSeg.B = aArc1.GetP1();
687}
688
689
691{
692 m_last = aShape->BaseSegment().B;
693 m_meanders.push_back( aShape );
694}
695
696
698{
699 for( MEANDER_SHAPE* m : m_meanders )
700 delete m;
701
702 m_meanders.clear( );
703}
704
705
707{
708 return m_clippedBaseSeg.Length();
709}
710
711
712long long int MEANDER_SHAPE::CurrentLength() const
713{
714 return CLine( 0 ).Length();
715}
716
717
719{
720 MEANDER_SHAPE copy = *this;
721
722 copy.SetTargetBaselineLength( BaselineLength() );
723 copy.Resize( copy.MinAmplitude() );
724
725 return copy.CurrentLength();
726}
727
728
730{
731 if( m_dual )
732 {
733 VECTOR2I midpA = ( CLine( 0 ).CPoint( 0 ) + CLine( 1 ).CPoint( 0 ) ) / 2;
734 VECTOR2I midpB = ( CLine( 0 ).CPoint( -1 ) + CLine( 1 ).CPoint( -1 ) ) / 2;
735
738 }
739 else
740 {
743 }
744}
745
746}
void AddMeander(MEANDER_SHAPE *aShape)
Add a new meander shape to the meandered line.
MEANDER_PLACER_BASE * m_placer
Definition: pns_meander.h:595
void AddCorner(const VECTOR2I &aA, const VECTOR2I &aB=VECTOR2I(0, 0))
Create a dummy meander shape representing a line corner.
void Clear()
Clear the line geometry, removing all corners and meanders.
std::vector< MEANDER_SHAPE * > m_meanders
Definition: pns_meander.h:596
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:43
void AddArc(const SHAPE_ARC &aArc1, const SHAPE_ARC &aArc2=SHAPE_ARC())
Create a dummy meander shape representing an arc corner.
void AddArcAndPt(const SHAPE_ARC &aArc1, const VECTOR2I &aPt2)
Create a dummy meander shape representing an arc corner.
bool CheckSelfIntersections(MEANDER_SHAPE *aShape, int aClearance)
Check if the given shape is intersecting with any other meander in the current line.
const MEANDER_SETTINGS & Settings() const
Definition: pns_meander.cpp:37
void AddPtAndArc(const VECTOR2I &aPt1, const SHAPE_ARC &aArc2)
Create a dummy meander shape representing an arc corner.
virtual void UpdateSettings(const MEANDER_SETTINGS &aSettings)
virtual bool CheckFit(MEANDER_SHAPE *aShape)
Checks if it's OK to place the shape aShape (i.e.
virtual int Clearance()
Return the clearance of the track(s) being length tuned.
virtual const MEANDER_SETTINGS & MeanderSettings() const
Return the current meandering configuration.
Dimensions for the meandering algorithm.
Definition: pns_meander.h:68
int m_minAmplitude
Maximum meandering amplitude.
Definition: pns_meander.h:128
int m_cornerRadiusPercentage
Place meanders on one side.
Definition: pns_meander.h:154
MEANDER_SIDE m_initialSide
Allowable tuning error.
Definition: pns_meander.h:160
bool m_singleSided
Initial side when placing meanders at segment.
Definition: pns_meander.h:157
int m_step
Length PadToDie.
Definition: pns_meander.h:137
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
Definition: pns_meander.h:151
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition: pns_meander.h:131
The geometry of a single meander.
Definition: pns_meander.h:173
MEANDER_TYPE m_type
The placer that placed this meander.
Definition: pns_meander.h:414
int MinAmplitude() const
MEANDER_PLACER_BASE * m_placer
Dual or single line.
Definition: pns_meander.h:417
SEG m_baseSeg
Base segment (clipped).
Definition: pns_meander.h:441
SEG m_clippedBaseSeg
Side (true = right).
Definition: pns_meander.h:444
int Amplitude() const
Definition: pns_meander.h:232
void SetType(MEANDER_TYPE aType)
Set the type of the meander.
Definition: pns_meander.h:200
int m_targetBaseLen
First point of the meandered line.
Definition: pns_meander.h:435
VECTOR2I End() const
Definition: pns_meander.h:287
SHAPE_LINE_CHAIN genMeanderShape(const VECTOR2D &aP, const VECTOR2D &aDir, bool aSide, MEANDER_TYPE aType, int aBaselineOffset=0)
Recalculate the clipped baseline after the parameters of the meander have been changed.
void start(SHAPE_LINE_CHAIN *aTarget, const VECTOR2D &aWhere, const VECTOR2D &aDir)
Move turtle forward by aLength.
void SetBaseIndex(int aIndex)
Set an auxiliary index of the segment being meandered in its original LINE.
Definition: pns_meander.h:216
int m_baselineOffset
Average radius of meander corners (for correction of DP meanders).
Definition: pns_meander.h:429
VECTOR2D m_currentDir
The current turtle position.
Definition: pns_meander.h:456
int m_width
Amplitude of the meander.
Definition: pns_meander.h:423
VECTOR2D m_currentPos
The line the turtle is drawing on.
Definition: pns_meander.h:459
SHAPE_LINE_CHAIN m_shapes[2]
Index of the meandered segment in the base line.
Definition: pns_meander.h:450
long long int CurrentLength() const
bool m_side
The actual shapes (0 used for single, both for dual).
Definition: pns_meander.h:447
void updateBaseSegment()
Return sanitized corner radius value.
SHAPE_LINE_CHAIN makeMiterShape(const VECTOR2D &aP, const VECTOR2D &aDir, bool aSide)
Produce a meander shape of given type.
void MakeArc(const SHAPE_ARC &aArc1, const SHAPE_ARC &aArc2=SHAPE_ARC())
Create a dummy meander shape representing an arc corner.
int m_baseIndex
The current turtle direction.
Definition: pns_meander.h:453
SHAPE_LINE_CHAIN * m_currentTarget
Definition: pns_meander.h:462
bool m_dual
Width of the line.
Definition: pns_meander.h:420
void Recalculate()
Recalculate the line chain representing the meander's shape.
void miter(int aRadius, bool aSide)
Tell the turtle to draw an U-like shape.
long long int MinTunableLength() const
void Resize(int aAmpl)
Change the amplitude of the meander shape to aAmpl and recalculates the resulting line chain.
int m_meanCornerRadius
Minimum length of the base segment to target when resizing.
Definition: pns_meander.h:432
int spacing() const
The type of meander.
int m_amplitude
Offset wrs the base segment (dual only).
Definition: pns_meander.h:426
int cornerRadius() const
Return sanitized spacing value.
void turn(const EDA_ANGLE &aAngle)
Tell the turtle to draw a mitered corner of given radius and turn direction.
void SetBaselineOffset(int aOffset)
Set the parallel offset between the base segment and the meandered line.
Definition: pns_meander.h:366
void forward(int aLength)
Turn the turtle by aAngle.
MEANDER_TYPE Type() const
Definition: pns_meander.h:208
VECTOR2I m_p0
Base segment (unclipped).
Definition: pns_meander.h:438
const MEANDER_SETTINGS & Settings() const
Definition: pns_meander.cpp:31
void MakeEmpty()
Replace the meander with straight bypass line(s), effectively clearing it.
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...
void uShape(int aSides, int aCorner, int aTop)
Generate a 90-degree circular arc.
const SHAPE_LINE_CHAIN & CLine(int aShape) const
Definition: pns_meander.h:295
int BaselineLength() const
const SEG & BaseSegment() const
Return the base segment the meander was fitted to.
Definition: pns_meander.h:322
void MakeCorner(const VECTOR2I &aP1, const VECTOR2I &aP2=VECTOR2I(0, 0))
Create a dummy meander shape representing a line corner.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I::extended_type ecoord
Definition: seg.h:44
VECTOR2I B
Definition: seg.h:50
int Length() const
Return the length (this).
Definition: seg.h:326
bool ApproxParallel(const SEG &aSeg, int aDistanceThreshold=1) const
Definition: seg.cpp:403
bool Contains(const SEG &aSeg) const
Definition: seg.h:307
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:312
const VECTOR2I & GetP1() const
Definition: shape_arc.h:113
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
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 Clear()
Remove all points from the line chain.
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both).
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.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
long long int Length() const
Return length of the line chain in Euclidean metric.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:265
VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
Definition: vector2d.h:279
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:350
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:439
Push and Shove diff pair dimensions (gap) settings dialog.
MEANDER_TYPE
Shapes of available meanders.
Definition: pns_meander.h:38
@ MT_TURN
Definition: pns_meander.h:42
@ MT_CHECK_START
Definition: pns_meander.h:43
@ MT_CHECK_FINISH
Definition: pns_meander.h:44
@ MT_START
Definition: pns_meander.h:40
@ MT_FINISH
Definition: pns_meander.h:41
@ MT_EMPTY
Definition: pns_meander.h:47
@ MT_CORNER
Definition: pns_meander.h:45
@ MT_SINGLE
Definition: pns_meander.h:39
MEANDER_SIDE
Definition: pns_meander.h:58
@ MEANDER_STYLE_ROUND
Definition: pns_meander.h:52
@ MEANDER_STYLE_CHAMFER
Definition: pns_meander.h:53
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:426
constexpr double correction
MATRIX3x3D m2(VECTOR3I{ 6, 6, 6 }, { 1, 1, 1 }, { 3, 3, 3 })
Test suite for KiCad math code.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:128