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
31const long long int MEANDER_SETTINGS::DEFAULT_TOLERANCE( pcbIUScale.mmToIU( 0.1 ) );
32const long long int MEANDER_SETTINGS::LENGTH_UNCONSTRAINED( 1000000 * pcbIUScale.IU_PER_MM );
33
34
36{
37 m_minAmplitude = 200000;
38 m_maxAmplitude = 1000000;
39 m_step = 50000;
40 m_lenPadToDie = 0;
41 m_spacing = 600000;
43 SetTargetSkew( 0 );
47 m_singleSided = false;
50 m_keepEndpoints = false;
51}
52
53
54void MEANDER_SETTINGS::SetTargetLength( long long int aOpt )
55{
56 m_targetLength.SetOpt( aOpt );
57
58 if( aOpt == std::numeric_limits<long long int>::max() )
59 {
61 m_targetLength.SetMax( aOpt );
62 }
63 else
64 {
67 }
68}
69
70
72{
73 SetTargetLength( aConstraint.Opt() );
74
75 if( aConstraint.HasMin() )
76 m_targetLength.SetMin( aConstraint.Min() );
77
78 if( aConstraint.HasMax() )
79 m_targetLength.SetMax( aConstraint.Max() );
80}
81
82
84{
85 m_targetSkew.SetOpt( aOpt );
86
87 if( aOpt == std::numeric_limits<int>::max() )
88 {
90 m_targetSkew.SetMax( aOpt );
91 }
92 else
93 {
96 }
97}
98
99
101{
102 SetTargetSkew( aConstraint.Opt() );
103
104 if( aConstraint.HasMin() )
105 m_targetSkew.SetMin( aConstraint.Min() );
106
107 if( aConstraint.HasMax() )
108 m_targetSkew.SetMax( aConstraint.Max() );
109}
110
111
113{
114 return m_placer->MeanderSettings();
115}
116
117
119{
120 return m_placer->MeanderSettings();
121}
122
123
124void MEANDERED_LINE::MeanderSegment( const SEG& aBase, bool aSide, int aBaseIndex )
125{
126 double base_len = aBase.Length();
127
129
130 bool singleSided = Settings().m_singleSided;
131 bool side = aSide;
132 VECTOR2D dir( aBase.B - aBase.A );
133
134 if( !m_dual )
135 AddCorner( aBase.A );
136
137 bool turning = false;
138 bool started = false;
139
140 m_last = aBase.A;
141
142 do
143 {
145
147 m.SetBaseIndex( aBaseIndex );
148
149 double thr = (double) m.spacing();
150
151 bool fail = false;
152 double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm();
153
154 auto flipInitialSide =
155 [&]()
156 {
158 settings.m_initialSide = (PNS::MEANDER_SIDE) -settings.m_initialSide;
159 m_placer->UpdateSettings( settings );
160 };
161
162 auto addSingleIfFits =
163 [&]()
164 {
165 fail = true;
166
167 if( m.Fit( MT_SINGLE, aBase, m_last, side ) )
168 {
169 AddMeander( new MEANDER_SHAPE( m ) );
170 fail = false;
171 started = false;
172 }
173
174 if( fail && !singleSided )
175 {
176 if( m.Fit( MT_SINGLE, aBase, m_last, !side ) )
177 {
178 if( !started )
179 flipInitialSide();
180
181 AddMeander( new MEANDER_SHAPE( m ) );
182 fail = false;
183 started = false;
184 side = !side;
185 }
186 }
187 };
188
189 if( remaining < Settings( ).m_step )
190 break;
191
192 if( !singleSided && remaining > 3.0 * thr )
193 {
194 if( !turning )
195 {
196 for( int i = 0; i < 2; i++ )
197 {
198 bool checkSide = ( i == 0 ) ? side : !side;
199
200 if( m.Fit( MT_CHECK_START, aBase, m_last, checkSide ) )
201 {
202 if( !started && checkSide != side )
203 flipInitialSide();
204
205 turning = true;
206 AddMeander( new MEANDER_SHAPE( m ) );
207 side = !checkSide;
208 started = true;
209 break;
210 }
211 }
212
213 if( !turning )
214 addSingleIfFits();
215 }
216 else
217 {
218 bool rv = m.Fit( MT_CHECK_FINISH, aBase, m_last, side );
219
220 if( rv )
221 {
222 m.Fit( MT_TURN, aBase, m_last, side );
223 AddMeander( new MEANDER_SHAPE( m ) );
224 side = !side;
225 started = true;
226 }
227 else
228 {
229 m.Fit( MT_FINISH, aBase, m_last, side );
230 started = false;
231 AddMeander( new MEANDER_SHAPE( m ) );
232 turning = false;
233 }
234 }
235 }
236 else if( !singleSided && started )
237 {
238 bool rv = m.Fit( MT_FINISH, aBase, m_last, side );
239
240 if( rv )
241 AddMeander( new MEANDER_SHAPE( m ) );
242
243 break;
244
245 }
246 else if( !turning && remaining > thr * 2.0 )
247 {
248 addSingleIfFits();
249 }
250 else
251 {
252 fail = true;
253 }
254
255 remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( );
256
257 if( remaining < Settings( ).m_step )
258 break;
259
260 if( fail )
261 {
264 tmp.SetBaseIndex( aBaseIndex );
265
266 int nextP = tmp.spacing() - 2 * tmp.cornerRadius() + Settings().m_step;
267 VECTOR2I pn = m_last + dir.Resize( nextP );
268
269 if( aBase.Contains( pn ) && !m_dual )
270 AddCorner( pn );
271 else
272 break;
273 }
274
275
276 } while( true );
277
278 if( !m_dual )
279 AddCorner( aBase.B );
280}
281
282
284{
285 int minAmplitude = Settings().m_minAmplitude;
286
288 {
289 minAmplitude = std::max( minAmplitude, std::abs( m_baselineOffset ) + m_width );
290 }
291 else
292 {
293 int correction = m_width * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
294 minAmplitude = std::max( minAmplitude, std::abs( m_baselineOffset ) + correction );
295 }
296
297 return minAmplitude;
298}
299
300
302{
303 if( m_amplitude == 0 )
304 return 0;
305
306 int minCr = 0;
307
309 minCr = std::abs( m_baselineOffset ) + m_width / 2;
310 else
311 minCr = std::abs( m_baselineOffset ) + m_width / 2 * ( 1 - tan( DEG2RAD( 22.5 ) ) );
312
313 int maxCr1 = ( m_amplitude + std::abs( m_baselineOffset ) ) / 2;
314 int maxCr2 = spacing() / 2;
315 int maxCr = std::min( maxCr1, maxCr2 );
316
317 wxCHECK2_MSG( maxCr >= minCr, return maxCr,
318 wxString::Format( "cornerRadius %d < %d amp %d spc %d w %d off %d", maxCr, minCr,
320
321 int rPercent = Settings().m_cornerRadiusPercentage;
322 int optCr = static_cast<int>( static_cast<SEG::ecoord>( spacing() ) * rPercent / 200 );
323
324 return std::clamp( optCr, minCr, maxCr );
325}
326
327
329{
330 if( !m_dual )
331 {
332 return std::max( m_width + m_placer->Clearance(), Settings().m_spacing );
333 }
334 else
335 {
336 int sp = m_width + m_placer->Clearance() + ( 2 * std::abs( m_baselineOffset ) );
337 return std::max( sp, Settings().m_spacing );
338 }
339}
340
341
343 bool aSide )
344{
346
347 if( aDir.EuclideanNorm( ) == 0.0f )
348 {
349 lc.Append( aP );
350 return lc;
351 }
352
353 VECTOR2D dir_u( aDir );
354 VECTOR2D dir_v( aDir.Perpendicular() );
355
356 VECTOR2D endPoint = aP + dir_u + dir_v * ( aSide ? -1.0 : 1.0 );
357 VECTOR2D p = aP;
358 lc.Append( ( int ) p.x, ( int ) p.y );
359
360 // fixme: refactor
362 {
364 {
365 VECTOR2I arcEnd( (int) endPoint.x, (int) endPoint.y );
366
367 SHAPE_ARC arc;
368 arc.ConstructFromStartEndAngle( aP, arcEnd, ( aSide ? -ANGLE_90 : ANGLE_90 ) );
369 lc.Append( arc );
370 break;
371 }
372
374 {
375 double radius = (double) aDir.EuclideanNorm();
376 double correction = 0;
377
378 if( m_dual && radius > m_meanCornerRadius )
379 correction = (double) ( -2 * abs( m_baselineOffset ) ) * tan( DEG2RAD( 22.5 ) );
380
381 VECTOR2D dir_cu = dir_u.Resize( correction );
382 VECTOR2D dir_cv = dir_v.Resize( correction );
383
384 p = aP - dir_cu;
385 lc.Append( ( int ) p.x, ( int ) p.y );
386 p = aP + dir_u + (dir_v + dir_cv) * ( aSide ? -1.0 : 1.0 );
387 lc.Append( ( int ) p.x, ( int ) p.y );
388
389 p = endPoint;
390 lc.Append( (int) p.x, (int) p.y );
391 break;
392 }
393
394 default:
395 break;
396 }
397
398 return lc;
399}
400
401
402void MEANDER_SHAPE::start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir )
403{
404 m_currentTarget = aTarget;
406 m_currentTarget->Append( aWhere );
407 m_currentDir = aDir;
408 m_currentPos = aWhere;
409}
410
411
412void MEANDER_SHAPE::forward( int aLength )
413{
414 // Very small segments cause problems.
415 if( aLength < 5 )
416 return;
417
418 m_currentPos += m_currentDir.Resize( aLength );
420}
421
422
423void MEANDER_SHAPE::turn( const EDA_ANGLE& aAngle )
424{
425 RotatePoint( m_currentDir, aAngle );
426}
427
428
429void MEANDER_SHAPE::miter( int aRadius, bool aSide )
430{
431 if( aRadius <= 0 )
432 {
433 turn( aSide ? ANGLE_90 : -ANGLE_90 );
434 return;
435 }
436
437 VECTOR2D dir = m_currentDir.Resize( (double) aRadius );
438 SHAPE_LINE_CHAIN lc = makeMiterShape( m_currentPos, dir, aSide );
439
440 m_currentPos = lc.CPoint( -1 );
441 turn( aSide ? ANGLE_90 : -ANGLE_90 );
442
443 m_currentTarget->Append( lc );
444}
445
446
447void MEANDER_SHAPE::uShape( int aSides, int aCorner, int aTop )
448{
449 forward( aSides );
450 miter( aCorner, true );
451 forward( aTop );
452 miter( aCorner, true );
453 forward( aSides );
454}
455
456
458 bool aSide, MEANDER_TYPE aType,
459 int aBaselineOffset )
460{
461 int cr = cornerRadius();
462 int offset = aBaselineOffset;
463 int spc = spacing();
464 int amplitude = m_amplitude;
465 int targetBaseLen = m_targetBaseLen;
466
467 if( aSide )
468 offset *= -1;
469
470 VECTOR2D dir_u_b( aDir.Resize( offset ) );
471 VECTOR2D dir_v_b( dir_u_b.Perpendicular() );
472
473 if( 2 * cr > amplitude + std::abs( offset ) )
474 cr = ( amplitude + std::abs( offset ) ) / 2;
475
476 if( 2 * cr > spc )
477 cr = spc / 2;
478
479 if( cr - offset < 0 )
480 cr = offset;
481
483
484 int sCorner = cr - offset;
485 int uCorner = cr + offset;
486 int startSide = amplitude - 2 * cr + std::abs( offset );
487 int turnSide = amplitude - cr;
488 int top = spc - 2 * cr;
489
491
492 start( &lc, aP + dir_v_b, aDir );
493
494 switch( aType )
495 {
496 case MT_EMPTY:
497 {
498 lc.Append( aP + dir_v_b + aDir );
499 break;
500 }
501 case MT_START:
502 {
503 if( targetBaseLen )
504 top = std::max( top, targetBaseLen - sCorner - uCorner * 2 + offset );
505
506 miter( sCorner, false );
507 uShape( startSide, uCorner, top );
508 forward( std::min( sCorner, uCorner ) );
509 forward( std::abs( offset ) );
510 break;
511 }
512
513 case MT_FINISH:
514 {
515 if( targetBaseLen )
516 top = std::max( top, targetBaseLen - cr - spc );
517
518 start( &lc, aP - dir_u_b, aDir );
519 turn( -ANGLE_90 );
520 forward( std::min( sCorner, uCorner ) );
521 forward( std::abs( offset ) );
522 uShape( startSide, uCorner, top );
523 miter( sCorner, false );
524
525 if( targetBaseLen >= spc + cr )
526 lc.Append( aP + dir_v_b + aDir.Resize( targetBaseLen ) );
527 else
528 lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc - cr ) );
529
530 break;
531 }
532
533 case MT_TURN:
534 {
535 if( targetBaseLen )
536 top = std::max( top, targetBaseLen - uCorner * 2 + offset * 2 );
537
538 start( &lc, aP - dir_u_b, aDir );
539 turn( -ANGLE_90 );
540 forward( std::abs( offset ) );
541 uShape( turnSide, uCorner, top );
542 forward( std::abs( offset ) );
543 break;
544 }
545
546 case MT_SINGLE:
547 {
548 if( targetBaseLen )
549 top = std::max( top, ( targetBaseLen - sCorner * 2 - uCorner * 2 ) / 2 );
550
551 miter( sCorner, false );
552 uShape( startSide, uCorner, top );
553 miter( sCorner, false );
554 lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc ) );
555 break;
556 }
557
558 default:
559 break;
560 }
561
562 if( aSide )
563 {
564 SEG axis( aP, aP + aDir );
565
566 lc.Mirror( axis );
567 }
568
569 return lc;
570}
571
572
574{
575 for( int i = m_meanders.size() - 1; i >= 0; i-- )
576 {
578
579 if( m->Type() == MT_EMPTY || m->Type() == MT_CORNER )
580 continue;
581
582 const SEG& b1 = aShape->BaseSegment();
583 const SEG& b2 = m->BaseSegment();
584
585 if( b1.ApproxParallel( b2 ) )
586 continue;
587
588 int n = m->CLine( 0 ).SegmentCount();
589
590 for( int j = n - 1; j >= 0; j-- )
591 {
592 if( aShape->CLine( 0 ).Collide( m->CLine( 0 ) .CSegment( j ), aClearance ) )
593 return false;
594 }
595 }
596
597 return true;
598}
599
600
601bool MEANDER_SHAPE::Fit( MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide )
602{
603 const MEANDER_SETTINGS& st = Settings();
604
605 bool checkMode = false;
606 MEANDER_TYPE prim1, prim2;
607
608 if( aType == MT_CHECK_START )
609 {
610 prim1 = MT_START;
611 prim2 = MT_TURN;
612 checkMode = true;
613 }
614 else if( aType == MT_CHECK_FINISH )
615 {
616 prim1 = MT_TURN;
617 prim2 = MT_FINISH;
618 checkMode = true;
619 }
620
621 if( checkMode )
622 {
625
627 m2.SetBaselineOffset( m_baselineOffset );
628
629 bool c1 = m1.Fit( prim1, aSeg, aP, aSide );
630 bool c2 = false;
631
632 if( c1 )
633 c2 = m2.Fit( prim2, aSeg, m1.End(), !aSide );
634
635 if( c1 && c2 )
636 {
637 m_type = prim1;
638 m_shapes[0] = m1.m_shapes[0];
639 m_shapes[1] = m1.m_shapes[1];
640 m_baseSeg =aSeg;
641 m_p0 = aP;
642 m_side = aSide;
643 m_amplitude = m1.Amplitude();
644 m_dual = m1.m_dual;
645 m_baseSeg = m1.m_baseSeg;
649 return true;
650 }
651 else
652 {
653 return false;
654 }
655 }
656
657 int minAmpl = MinAmplitude();
658 int maxAmpl = std::max( st.m_maxAmplitude, minAmpl );
659
660 for( int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step )
661 {
662 m_amplitude = ampl;
663
664 if( m_dual )
665 {
666 m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, m_baselineOffset );
667 m_shapes[1] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, -m_baselineOffset );
668 }
669 else
670 {
671 m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, 0 );
672 }
673
674 m_type = aType;
675 m_baseSeg = aSeg;
676 m_p0 = aP;
677 m_side = aSide;
678
680
681 if( m_placer->CheckFit( this ) )
682 return true;
683 }
684
685 return false;
686}
687
688
690{
692 m_dual ? m_baselineOffset : 0 );
693
694 if( m_dual )
697
699}
700
701
702void MEANDER_SHAPE::Resize( int aAmpl )
703{
704 if( aAmpl < 0 )
705 return;
706
707 m_amplitude = aAmpl;
708
709 Recalculate();
710}
711
712
714{
716
718
720 m_amplitude = 0;
721
723
724 if( m_dual )
726}
727
728
729void MEANDERED_LINE::AddCorner( const VECTOR2I& aA, const VECTOR2I& aB )
730{
732
733 m->MakeCorner( aA, aB );
734 m_last = aA;
735
736 m_meanders.push_back( m );
737}
738
739
740void MEANDERED_LINE::AddArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
741{
743
744 m->MakeArc( aArc1, aArc2 );
745 m_last = aArc1.GetP1();
746
747 m_meanders.push_back( m );
748}
749
750
751void MEANDERED_LINE::AddArcAndPt( const SHAPE_ARC& aArc1, const VECTOR2I& aPt2 )
752{
753 SHAPE_ARC arc2( aPt2, aPt2, aPt2, 0 );
754
755 AddArc( aArc1, arc2 );
756}
757
758
759void MEANDERED_LINE::AddPtAndArc( const VECTOR2I& aPt1, const SHAPE_ARC& aArc2 )
760{
761 SHAPE_ARC arc1( aPt1, aPt1, aPt1, 0 );
762
763 AddArc( arc1, aArc2 );
764}
765
766
767void MEANDER_SHAPE::MakeCorner( const VECTOR2I& aP1, const VECTOR2I& aP2 )
768{
770 m_shapes[0].Clear();
771 m_shapes[1].Clear();
772 m_shapes[0].Append( aP1 );
773 m_shapes[1].Append( aP2 );
774 m_clippedBaseSeg.A = aP1;
775 m_clippedBaseSeg.B = aP1;
776}
777
778
779void MEANDER_SHAPE::MakeArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
780{
782 m_shapes[0].Clear();
783 m_shapes[1].Clear();
784 m_shapes[0].Append( aArc1 );
785 m_shapes[1].Append( aArc2 );
786 m_clippedBaseSeg.A = aArc1.GetP1();
787 m_clippedBaseSeg.B = aArc1.GetP1();
788}
789
790
792{
793 m_last = aShape->BaseSegment().B;
794 m_meanders.push_back( aShape );
795}
796
797
799{
800 for( MEANDER_SHAPE* m : m_meanders )
801 delete m;
802
803 m_meanders.clear( );
804}
805
806
808{
809 return m_clippedBaseSeg.Length();
810}
811
812
813long long int MEANDER_SHAPE::CurrentLength() const
814{
815 return CLine( 0 ).Length();
816}
817
818
820{
821 MEANDER_SHAPE copy = *this;
822
823 copy.SetTargetBaselineLength( BaselineLength() );
824 copy.Resize( copy.MinAmplitude() );
825
826 return copy.CurrentLength();
827}
828
829
831{
832 if( m_dual )
833 {
834 VECTOR2I midpA = ( CLine( 0 ).CPoint( 0 ) + CLine( 1 ).CPoint( 0 ) ) / 2;
835 VECTOR2I midpB = ( CLine( 0 ).CPoint( -1 ) + CLine( 1 ).CPoint( -1 ) ) / 2;
836
839 }
840 else
841 {
844 }
845}
846
847}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
T Min() const
Definition: minoptmax.h:33
void SetMin(T v)
Definition: minoptmax.h:41
bool HasMax() const
Definition: minoptmax.h:38
void SetOpt(T v)
Definition: minoptmax.h:43
bool HasMin() const
Definition: minoptmax.h:37
void SetMax(T v)
Definition: minoptmax.h:42
T Max() const
Definition: minoptmax.h:34
T Opt() const
Definition: minoptmax.h:35
void AddMeander(MEANDER_SHAPE *aShape)
Add a new meander shape to the meandered line.
MEANDER_PLACER_BASE * m_placer
Definition: pns_meander.h:549
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:550
void MeanderSegment(const SEG &aSeg, bool aSide, int aBaseIndex=0)
Fit maximum amplitude meanders on a given segment and adds to the current line.
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
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:82
void SetTargetLength(long long int aOpt)
Definition: pns_meander.cpp:54
static const long long int LENGTH_UNCONSTRAINED
Definition: pns_meander.h:71
int m_cornerRadiusPercentage
Place meanders on one side.
Definition: pns_meander.h:108
MEANDER_SIDE m_initialSide
Allowable tuning error.
Definition: pns_meander.h:114
bool m_singleSided
Initial side when placing meanders at segment.
Definition: pns_meander.h:111
MINOPTMAX< long long int > m_targetLength
Target skew value for diff pair de-skewing.
Definition: pns_meander.h:97
void SetTargetSkew(int aOpt)
Definition: pns_meander.cpp:83
int m_lengthTolerance
Keep vertices between pre, tuned and post parts of the line.
Definition: pns_meander.h:117
int m_step
Length PadToDie.
Definition: pns_meander.h:91
MINOPTMAX< int > m_targetSkew
Definition: pns_meander.h:100
static const long long int DEFAULT_TOLERANCE
Definition: pns_meander.h:70
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
Definition: pns_meander.h:105
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition: pns_meander.h:85
bool m_overrideCustomRules
Type of corners for the meandered line.
Definition: pns_meander.h:102
int m_lenPadToDie
Desired length of the tuned line/diff pair (this is in nm, so allow more than board width).
Definition: pns_meander.h:94
int m_spacing
Amplitude/spacing adjustment step.
Definition: pns_meander.h:88
The geometry of a single meander.
Definition: pns_meander.h:127
MEANDER_TYPE m_type
The placer that placed this meander.
Definition: pns_meander.h:368
int MinAmplitude() const
MEANDER_PLACER_BASE * m_placer
Dual or single line.
Definition: pns_meander.h:371
SEG m_baseSeg
Base segment (clipped).
Definition: pns_meander.h:395
SEG m_clippedBaseSeg
Side (true = right).
Definition: pns_meander.h:398
int Amplitude() const
Definition: pns_meander.h:186
void SetType(MEANDER_TYPE aType)
Set the type of the meander.
Definition: pns_meander.h:154
int m_targetBaseLen
First point of the meandered line.
Definition: pns_meander.h:389
VECTOR2I End() const
Definition: pns_meander.h:241
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:170
int m_baselineOffset
Average radius of meander corners (for correction of DP meanders).
Definition: pns_meander.h:383
VECTOR2D m_currentDir
The current turtle position.
Definition: pns_meander.h:410
int m_width
Amplitude of the meander.
Definition: pns_meander.h:377
VECTOR2D m_currentPos
The line the turtle is drawing on.
Definition: pns_meander.h:413
SHAPE_LINE_CHAIN m_shapes[2]
Index of the meandered segment in the base line.
Definition: pns_meander.h:404
long long int CurrentLength() const
bool m_side
The actual shapes (0 used for single, both for dual).
Definition: pns_meander.h:401
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:407
SHAPE_LINE_CHAIN * m_currentTarget
Definition: pns_meander.h:416
bool m_dual
Width of the line.
Definition: pns_meander.h:374
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:386
int spacing() const
The type of meander.
int m_amplitude
Offset wrs the base segment (dual only).
Definition: pns_meander.h:380
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:320
void forward(int aLength)
Turn the turtle by aAngle.
MEANDER_TYPE Type() const
Definition: pns_meander.h:162
VECTOR2I m_p0
Base segment (unclipped).
Definition: pns_meander.h:392
const MEANDER_SETTINGS & Settings() const
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:249
int BaselineLength() const
const SEG & BaseSegment() const
Return the base segment the meander was fitted to.
Definition: pns_meander.h:276
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:402
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
SHAPE_ARC & ConstructFromStartEndAngle(const VECTOR2I &aStart, const VECTOR2I &aEnd, const EDA_ANGLE &aAngle, double aWidth=0)
Construct this arc from the given start, end and angle.
Definition: shape_arc.cpp:194
const VECTOR2I & GetP1() const
Definition: shape_arc.h:114
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:437
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_SIDE_LEFT
Definition: pns_meander.h:59
@ 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:424
constexpr double correction
const double IU_PER_MM
Definition: base_units.h:76
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
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 DEG2RAD(double deg)
Definition: trigo.h:200
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:128