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 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 "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
32const long long int MEANDER_SETTINGS::LENGTH_UNCONSTRAINED( 1000000 * pcbIUScale.IU_PER_MM );
33
35const long long int MEANDER_SETTINGS::DELAY_UNCONSTRAINED( 1000000 * pcbIUScale.IU_PER_PS );
36
37const int MEANDER_SETTINGS::SKEW_UNCONSTRAINED( std::numeric_limits<int>::max() );
38
39
65
66
67void MEANDER_SETTINGS::SetTargetLength( long long int aOpt )
68{
69 m_targetLength.SetOpt( aOpt );
70
72 {
73 m_targetLength.SetMin( 0 );
74 m_targetLength.SetMax( aOpt );
75 }
76 else
77 {
80 }
81}
82
83
85{
86 SetTargetLength( aConstraint.Opt() );
87
88 if( aConstraint.HasMin() )
89 m_targetLength.SetMin( aConstraint.Min() );
90
91 if( aConstraint.HasMax() )
92 m_targetLength.SetMax( aConstraint.Max() );
93}
94
95
97{
98 m_targetLengthDelay.SetOpt( aOpt );
99
101 {
102 m_targetLengthDelay.SetMin( 0 );
103 m_targetLengthDelay.SetMax( aOpt );
104 }
105 else
106 {
109 }
110}
111
112
114{
115 SetTargetLengthDelay( aConstraint.Opt() );
116
117 if( aConstraint.HasMin() )
118 m_targetLengthDelay.SetMin( aConstraint.Min() );
119
120 if( aConstraint.HasMax() )
121 m_targetLengthDelay.SetMax( aConstraint.Max() );
122}
123
125{
126 m_targetSignalLengthDelay.SetOpt( aOpt );
127
129 {
130 m_targetSignalLengthDelay.SetMin( 0 );
131 m_targetSignalLengthDelay.SetMax( aOpt );
132 }
133 else
134 {
137 }
138}
139
140
142{
143 m_targetSignalLength.SetOpt( aOpt );
144
146 {
147 m_targetSignalLength.SetMin( 0 );
148 m_targetSignalLength.SetMax( aOpt );
149 }
150 else
151 {
154 }
155}
156
157
159{
160 SetTargetSignalLength( aConstraint.Opt() );
161
162 if( aConstraint.HasMin() )
163 m_targetSignalLength.SetMin( aConstraint.Min() );
164
165 if( aConstraint.HasMax() )
166 m_targetSignalLength.SetMax( aConstraint.Max() );
167}
168
169
171{
172 SetTargetSignalLengthDelay( aConstraint.Opt() );
173
174 if( aConstraint.HasMin() )
175 m_targetSignalLengthDelay.SetMin( aConstraint.Min() );
176
177 if( aConstraint.HasMax() )
178 m_targetSignalLengthDelay.SetMax( aConstraint.Max() );
179}
180
181
183{
184 m_targetSkew.SetOpt( aOpt );
185
187 {
188 m_targetSkew.SetMin( 0 );
189 m_targetSkew.SetMax( aOpt );
190 }
191 else
192 {
193 m_targetSkew.SetMin( aOpt - DEFAULT_LENGTH_TOLERANCE );
194 m_targetSkew.SetMax( aOpt + DEFAULT_LENGTH_TOLERANCE );
195 }
196}
197
198
200{
201 SetTargetSkew( aConstraint.Opt() );
202
203 if( aConstraint.HasMin() )
204 m_targetSkew.SetMin( aConstraint.Min() );
205
206 if( aConstraint.HasMax() )
207 m_targetSkew.SetMax( aConstraint.Max() );
208}
209
210
212{
213 m_targetSkewDelay.SetOpt( aOpt );
214
216 {
217 m_targetSkewDelay.SetMin( 0 );
218 m_targetSkewDelay.SetMax( aOpt );
219 }
220 else
221 {
224 }
225}
226
227
229{
230 SetTargetSkewDelay( aConstraint.Opt() );
231
232 if( aConstraint.HasMin() )
233 m_targetSkewDelay.SetMin( aConstraint.Min() );
234
235 if( aConstraint.HasMax() )
236 m_targetSkewDelay.SetMax( aConstraint.Max() );
237}
238
239
241{
242 return m_placer->MeanderSettings();
243}
244
245
247{
248 return m_placer->MeanderSettings();
249}
250
251
252void MEANDERED_LINE::MeanderSegment( const SEG& aBase, bool aSide, int aBaseIndex )
253{
254 double base_len = aBase.Length();
255
257
258 bool singleSided = Settings().m_singleSided;
259 bool side = aSide;
260 VECTOR2D dir( aBase.B - aBase.A );
261
262 if( !m_dual )
263 AddCorner( aBase.A );
264
265 bool turning = false;
266 bool started = false;
267
268 m_last = aBase.A;
269
270 do
271 {
273
275 m.SetBaseIndex( aBaseIndex );
276
277 double thr = (double) m.spacing();
278
279 bool fail = false;
280 double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm();
281
282 auto flipInitialSide =
283 [&]()
284 {
285 MEANDER_SETTINGS settings = m_placer->MeanderSettings();
286 settings.m_initialSide = (PNS::MEANDER_SIDE) -settings.m_initialSide;
287 m_placer->UpdateSettings( settings );
288 };
289
290 auto addSingleIfFits =
291 [&]()
292 {
293 fail = true;
294
295 if( m.Fit( MT_SINGLE, aBase, m_last, side ) )
296 {
297 AddMeander( new MEANDER_SHAPE( m ) );
298 fail = false;
299 started = false;
300 }
301
302 if( fail && !singleSided )
303 {
304 if( m.Fit( MT_SINGLE, aBase, m_last, !side ) )
305 {
306 if( !started )
307 flipInitialSide();
308
309 AddMeander( new MEANDER_SHAPE( m ) );
310 fail = false;
311 started = false;
312 side = !side;
313 }
314 }
315 };
316
317 if( remaining < Settings( ).m_step )
318 break;
319
320 if( !singleSided && remaining > 3.0 * thr )
321 {
322 if( !turning )
323 {
324 for( int i = 0; i < 2; i++ )
325 {
326 bool checkSide = ( i == 0 ) ? side : !side;
327
328 if( m.Fit( MT_CHECK_START, aBase, m_last, checkSide ) )
329 {
330 if( !started && checkSide != side )
331 flipInitialSide();
332
333 turning = true;
334 AddMeander( new MEANDER_SHAPE( m ) );
335 side = !checkSide;
336 started = true;
337 break;
338 }
339 }
340
341 if( !turning )
342 addSingleIfFits();
343 }
344 else
345 {
346 bool rv = m.Fit( MT_CHECK_FINISH, aBase, m_last, side );
347
348 if( rv )
349 {
350 m.Fit( MT_TURN, aBase, m_last, side );
351 AddMeander( new MEANDER_SHAPE( m ) );
352 side = !side;
353 started = true;
354 }
355 else
356 {
357 m.Fit( MT_FINISH, aBase, m_last, side );
358 started = false;
359 AddMeander( new MEANDER_SHAPE( m ) );
360 turning = false;
361 }
362 }
363 }
364 else if( !singleSided && started )
365 {
366 bool rv = m.Fit( MT_FINISH, aBase, m_last, side );
367
368 if( rv )
369 AddMeander( new MEANDER_SHAPE( m ) );
370
371 break;
372
373 }
374 else if( !turning && remaining > thr * 2.0 )
375 {
376 addSingleIfFits();
377 }
378 else
379 {
380 fail = true;
381 }
382
383 remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( );
384
385 if( remaining < Settings( ).m_step )
386 break;
387
388 if( fail )
389 {
392 tmp.SetBaseIndex( aBaseIndex );
393
394 int nextP = tmp.spacing() - 2 * tmp.cornerRadius() + Settings().m_step;
395 VECTOR2I pn = m_last + dir.Resize( nextP );
396
397 if( aBase.Contains( pn ) && !m_dual )
398 AddCorner( pn );
399 else
400 break;
401 }
402
403
404 } while( true );
405
406 if( !m_dual )
407 AddCorner( aBase.B );
408}
409
410
412{
413 int minAmplitude = Settings().m_minAmplitude;
414
415 if( m_placer->MeanderSettings().m_cornerStyle == MEANDER_STYLE_ROUND )
416 {
417 minAmplitude = std::max( minAmplitude, std::abs( m_baselineOffset ) + m_width );
418 }
419 else
420 {
421 int correction = m_width * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
422 minAmplitude = std::max( minAmplitude, std::abs( m_baselineOffset ) + correction );
423 }
424
425 return minAmplitude;
426}
427
428
430{
431 if( m_amplitude == 0 )
432 return 0;
433
434 int minCr = 0;
435
436 if( m_placer->MeanderSettings().m_cornerStyle == MEANDER_STYLE_ROUND )
437 minCr = std::abs( m_baselineOffset ) + m_width / 2;
438 else
439 minCr = std::abs( m_baselineOffset ) + m_width / 2 * ( 1 - tan( DEG2RAD( 22.5 ) ) );
440
441 int maxCr1 = ( m_amplitude + std::abs( m_baselineOffset ) ) / 2;
442 int maxCr2 = spacing() / 2;
443 int maxCr = std::min( maxCr1, maxCr2 );
444
445 wxCHECK2_MSG( maxCr >= minCr, return maxCr,
446 wxString::Format( "cornerRadius %d < %d amp %d spc %d w %d off %d", maxCr, minCr,
448
449 int rPercent = Settings().m_cornerRadiusPercentage;
450 int optCr = static_cast<int>( static_cast<SEG::ecoord>( spacing() ) * rPercent / 200 );
451
452 return std::clamp( optCr, minCr, maxCr );
453}
454
455
457{
458 if( !m_dual )
459 {
460 return std::max( m_width + m_placer->Clearance(), Settings().m_spacing );
461 }
462 else
463 {
464 int sp = m_width + m_placer->Clearance() + ( 2 * std::abs( m_baselineOffset ) );
465 return std::max( sp, Settings().m_spacing );
466 }
467}
468
469
471 bool aSide )
472{
474
475 if( aDir.EuclideanNorm( ) == 0.0f )
476 {
477 lc.Append( aP );
478 return lc;
479 }
480
481 VECTOR2D dir_u( aDir );
482 VECTOR2D dir_v( aDir.Perpendicular() );
483
484 VECTOR2D endPoint = aP + dir_u + dir_v * ( aSide ? -1.0 : 1.0 );
485 VECTOR2D p = aP;
486 lc.Append( ( int ) p.x, ( int ) p.y );
487
488 // fixme: refactor
489 switch( m_placer->MeanderSettings().m_cornerStyle )
490 {
492 {
493 VECTOR2I arcEnd( (int) endPoint.x, (int) endPoint.y );
494
495 SHAPE_ARC arc;
496 arc.ConstructFromStartEndAngle( aP, arcEnd, ( aSide ? -ANGLE_90 : ANGLE_90 ) );
497 lc.Append( arc );
498 break;
499 }
500
502 {
503 double radius = (double) aDir.EuclideanNorm();
504 double correction = 0;
505
507 correction = (double) ( -2 * abs( m_baselineOffset ) ) * tan( DEG2RAD( 22.5 ) );
508
509 VECTOR2D dir_cu = dir_u.Resize( correction );
510 VECTOR2D dir_cv = dir_v.Resize( correction );
511
512 p = aP - dir_cu;
513 lc.Append( ( int ) p.x, ( int ) p.y );
514 p = aP + dir_u + (dir_v + dir_cv) * ( aSide ? -1.0 : 1.0 );
515 lc.Append( ( int ) p.x, ( int ) p.y );
516
517 p = endPoint;
518 lc.Append( (int) p.x, (int) p.y );
519 break;
520 }
521
522 default:
523 break;
524 }
525
526 return lc;
527}
528
529
530void MEANDER_SHAPE::start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir )
531{
532 m_currentTarget = aTarget;
533 m_currentTarget->Clear();
534 m_currentTarget->Append( aWhere );
535 m_currentDir = aDir;
536 m_currentPos = aWhere;
537}
538
539
540void MEANDER_SHAPE::forward( int aLength )
541{
542 // Very small segments cause problems.
543 if( aLength < 5 )
544 return;
545
546 m_currentPos += m_currentDir.Resize( aLength );
547 m_currentTarget->Append( m_currentPos );
548}
549
550
551void MEANDER_SHAPE::turn( const EDA_ANGLE& aAngle )
552{
553 RotatePoint( m_currentDir, aAngle );
554}
555
556
557void MEANDER_SHAPE::miter( int aRadius, bool aSide )
558{
559 if( aRadius <= 0 )
560 {
561 turn( aSide ? ANGLE_90 : -ANGLE_90 );
562 return;
563 }
564
565 VECTOR2D dir = m_currentDir.Resize( (double) aRadius );
566 SHAPE_LINE_CHAIN lc = makeMiterShape( m_currentPos, dir, aSide );
567
569 turn( aSide ? ANGLE_90 : -ANGLE_90 );
570
571 m_currentTarget->Append( lc );
572}
573
574
575void MEANDER_SHAPE::uShape( int aSides, int aCorner, int aTop )
576{
577 forward( aSides );
578 miter( aCorner, true );
579 forward( aTop );
580 miter( aCorner, true );
581 forward( aSides );
582}
583
584
586 bool aSide, MEANDER_TYPE aType,
587 int aBaselineOffset )
588{
589 int cr = cornerRadius();
590 int offset = aBaselineOffset;
591 int spc = spacing();
592 int amplitude = m_amplitude;
593 int targetBaseLen = m_targetBaseLen;
594
595 if( aSide )
596 offset *= -1;
597
598 VECTOR2D dir_u_b( aDir.Resize( offset ) );
599 VECTOR2D dir_v_b( dir_u_b.Perpendicular() );
600
601 if( 2 * cr > amplitude + std::abs( offset ) )
602 cr = ( amplitude + std::abs( offset ) ) / 2;
603
604 if( 2 * cr > spc )
605 cr = spc / 2;
606
607 if( cr - offset < 0 )
608 cr = offset;
609
611
612 int sCorner = cr - offset;
613 int uCorner = cr + offset;
614 int startSide = amplitude - 2 * cr + std::abs( offset );
615 int turnSide = amplitude - cr;
616 int top = spc - 2 * cr;
617
619
620 start( &lc, aP + dir_v_b, aDir );
621
622 switch( aType )
623 {
624 case MT_EMPTY:
625 lc.Append( aP + dir_v_b + aDir );
626 break;
627
628 case MT_START:
629 if( targetBaseLen )
630 top = std::max( top, targetBaseLen - sCorner - uCorner * 2 + offset );
631
632 miter( sCorner, false );
633 uShape( startSide, uCorner, top );
634 forward( std::min( sCorner, uCorner ) );
635 forward( std::abs( offset ) );
636 break;
637
638 case MT_FINISH:
639 if( targetBaseLen )
640 top = std::max( top, targetBaseLen - cr - spc );
641
642 start( &lc, aP - dir_u_b, aDir );
643 turn( -ANGLE_90 );
644 forward( std::min( sCorner, uCorner ) );
645 forward( std::abs( offset ) );
646 uShape( startSide, uCorner, top );
647 miter( sCorner, false );
648
649 if( targetBaseLen >= spc + cr )
650 lc.Append( aP + dir_v_b + aDir.Resize( targetBaseLen ) );
651 else
652 lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc - cr ) );
653
654 break;
655
656 case MT_TURN:
657 if( targetBaseLen )
658 top = std::max( top, targetBaseLen - uCorner * 2 + offset * 2 );
659
660 start( &lc, aP - dir_u_b, aDir );
661 turn( -ANGLE_90 );
662 forward( std::abs( offset ) );
663 uShape( turnSide, uCorner, top );
664 forward( std::abs( offset ) );
665 break;
666
667 case MT_SINGLE:
668 if( targetBaseLen )
669 top = std::max( top, ( targetBaseLen - sCorner * 2 - uCorner * 2 ) / 2 );
670
671 miter( sCorner, false );
672 uShape( startSide, uCorner, top );
673 miter( sCorner, false );
674 lc.Append( aP + dir_v_b + aDir.Resize( 2 * spc ) );
675 break;
676
677 default:
678 break;
679 }
680
681 if( aSide )
682 {
683 SEG axis( aP, aP + aDir );
684
685 lc.Mirror( axis );
686 }
687
688 // Clear the current target pointer to avoid dangling pointer after lc goes out of scope
689 m_currentTarget = nullptr;
690
691 return lc;
692}
693
694
696{
697 for( int i = m_meanders.size() - 1; i >= 0; i-- )
698 {
700
701 if( m->Type() == MT_EMPTY || m->Type() == MT_CORNER )
702 continue;
703
704 const SEG& b1 = aShape->BaseSegment();
705 const SEG& b2 = m->BaseSegment();
706
707 if( b1.ApproxParallel( b2 ) )
708 continue;
709
710 int n = m->CLine( 0 ).SegmentCount();
711
712 for( int j = n - 1; j >= 0; j-- )
713 {
714 if( aShape->CLine( 0 ).Collide( m->CLine( 0 ) .CSegment( j ), aClearance ) )
715 return false;
716 }
717 }
718
719 return true;
720}
721
722
723bool MEANDER_SHAPE::Fit( MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide )
724{
725 const MEANDER_SETTINGS& st = Settings();
726
727 bool checkMode = false;
728 MEANDER_TYPE prim1 = MT_EMPTY;
729 MEANDER_TYPE prim2 = MT_EMPTY;
730
731 if( aType == MT_CHECK_START )
732 {
733 prim1 = MT_START;
734 prim2 = MT_TURN;
735 checkMode = true;
736 }
737 else if( aType == MT_CHECK_FINISH )
738 {
739 prim1 = MT_TURN;
740 prim2 = MT_FINISH;
741 checkMode = true;
742 }
743
744 if( checkMode )
745 {
748
750 m2.SetBaselineOffset( m_baselineOffset );
751
752 bool c1 = m1.Fit( prim1, aSeg, aP, aSide );
753 bool c2 = false;
754
755 if( c1 )
756 c2 = m2.Fit( prim2, aSeg, m1.End(), !aSide );
757
758 if( c1 && c2 )
759 {
760 m_type = prim1;
761 m_shapes[0] = m1.m_shapes[0];
762 m_shapes[1] = m1.m_shapes[1];
763 m_baseSeg =aSeg;
764 m_p0 = aP;
765 m_side = aSide;
766 m_amplitude = m1.Amplitude();
767 m_dual = m1.m_dual;
768 m_baseSeg = m1.m_baseSeg;
772 return true;
773 }
774 else
775 {
776 return false;
777 }
778 }
779
780 int minAmpl = MinAmplitude();
781 int maxAmpl = std::max( st.m_maxAmplitude, minAmpl );
782
783 // Calculate minimum acceptable corner radius for visible rounding.
784 // Use at least half the track width to ensure curves are noticeably rounded.
785 // Smaller values lead to corners that appear nearly square, which is problematic
786 // for high-speed nets (e.g., DDR4) where 90-degree corners cause reflections.
787 int minCornerRadius = m_width / 2;
788
789 for( int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step )
790 {
791 m_amplitude = ampl;
792
793 if( m_dual )
794 {
795 m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, m_baselineOffset );
796 m_shapes[1] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, -m_baselineOffset );
797 }
798 else
799 {
800 m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, 0 );
801 }
802
803 m_type = aType;
804 m_baseSeg = aSeg;
805 m_p0 = aP;
806 m_side = aSide;
807
809
810 // Reject configurations that would result in nearly-square corners (issue #8629).
811 // m_meanCornerRadius is set by genMeanderShape() to the actual corner radius used.
812 if( m_meanCornerRadius < minCornerRadius )
813 continue;
814
815 if( m_placer->CheckFit( this ) )
816 return true;
817 }
818
819 return false;
820}
821
822
834
835
836void MEANDER_SHAPE::Resize( int aAmpl )
837{
838 if( aAmpl < 0 )
839 return;
840
841 // Ensure amplitude doesn't go below minimum needed for proper corner radii (issue #8629)
842 int minAmpl = MinAmplitude();
843
844 m_amplitude = std::max( aAmpl, minAmpl );
845
846 Recalculate();
847}
848
849
864
865
866void MEANDERED_LINE::AddCorner( const VECTOR2I& aA, const VECTOR2I& aB )
867{
869
870 m->MakeCorner( aA, aB );
871 m_last = aA;
872
873 m_meanders.push_back( m );
874}
875
876
877void MEANDERED_LINE::AddArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
878{
880
881 m->MakeArc( aArc1, aArc2 );
882 m_last = aArc1.GetP1();
883
884 m_meanders.push_back( m );
885}
886
887
888void MEANDERED_LINE::AddArcAndPt( const SHAPE_ARC& aArc1, const VECTOR2I& aPt2 )
889{
890 SHAPE_ARC arc2( aPt2, aPt2, aPt2, 0 );
891
892 AddArc( aArc1, arc2 );
893}
894
895
896void MEANDERED_LINE::AddPtAndArc( const VECTOR2I& aPt1, const SHAPE_ARC& aArc2 )
897{
898 SHAPE_ARC arc1( aPt1, aPt1, aPt1, 0 );
899
900 AddArc( arc1, aArc2 );
901}
902
903
904void MEANDER_SHAPE::MakeCorner( const VECTOR2I& aP1, const VECTOR2I& aP2 )
905{
907 m_shapes[0].Clear();
908 m_shapes[1].Clear();
909 m_shapes[0].Append( aP1 );
910 m_shapes[1].Append( aP2 );
911 m_clippedBaseSeg.A = aP1;
912 m_clippedBaseSeg.B = aP1;
913}
914
915
916void MEANDER_SHAPE::MakeArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 )
917{
919 m_shapes[0].Clear();
920 m_shapes[1].Clear();
921 m_shapes[0].Append( aArc1 );
922 m_shapes[1].Append( aArc2 );
923 m_clippedBaseSeg.A = aArc1.GetP1();
924 m_clippedBaseSeg.B = aArc1.GetP1();
925}
926
927
929{
930 m_last = aShape->BaseSegment().B;
931 m_meanders.push_back( aShape );
932}
933
934
936{
937 for( MEANDER_SHAPE* m : m_meanders )
938 delete m;
939
940 m_meanders.clear( );
941}
942
943
945{
946 return m_clippedBaseSeg.Length();
947}
948
949
950long long int MEANDER_SHAPE::CurrentLength() const
951{
952 return CLine( 0 ).Length();
953}
954
955
957{
958 MEANDER_SHAPE copy = *this;
959
960 copy.SetTargetBaselineLength( BaselineLength() );
961 copy.Resize( copy.MinAmplitude() );
962
963 return copy.CurrentLength();
964}
965
966
968{
969 if( m_dual )
970 {
971 VECTOR2I midpA = ( CLine( 0 ).CPoint( 0 ) + CLine( 1 ).CPoint( 0 ) ) / 2;
972 VECTOR2I midpB = ( CLine( 0 ).CLastPoint() + CLine( 1 ).CLastPoint() ) / 2;
973
974 m_clippedBaseSeg.A = m_baseSeg.LineProject( midpA );
975 m_clippedBaseSeg.B = m_baseSeg.LineProject( midpB );
976 }
977 else
978 {
979 m_clippedBaseSeg.A = m_baseSeg.LineProject( CLine( 0 ).CPoint( 0 ) );
980 m_clippedBaseSeg.B = m_baseSeg.LineProject( CLine( 0 ).CLastPoint() );
981 }
982}
983
984}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
T Min() const
Definition minoptmax.h:33
bool HasMax() const
Definition minoptmax.h:38
bool HasMin() const
Definition minoptmax.h:37
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
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
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.
Dimensions for the meandering algorithm.
Definition pns_meander.h:70
int m_minAmplitude
Maximum meandering amplitude.
void SetTargetLength(long long int aOpt)
bool m_isTimeDomain
The net class this meander pattern belongs to.
static const long long int LENGTH_UNCONSTRAINED
Definition pns_meander.h:73
int m_cornerRadiusPercentage
Place meanders on one side.
MEANDER_SIDE m_initialSide
Allowable tuning error.
bool m_singleSided
Initial side when placing meanders at segment.
void SetTargetLengthDelay(long long int aOpt)
static const int SKEW_UNCONSTRAINED
Definition pns_meander.h:78
static const long long int DEFAULT_DELAY_TOLERANCE
Definition pns_meander.h:75
MINOPTMAX< long long int > m_targetLength
Desired propagation delay of the tuned line.
void SetTargetSignalLengthDelay(long long int aOpt)
void SetTargetSkew(int aOpt)
void SetTargetSignalLength(long long int aOpt)
static const long long int DEFAULT_LENGTH_TOLERANCE
Definition pns_meander.h:72
int m_lengthTolerance
Keep vertices between pre, tuned and post parts of the line.
int m_step
Length PadToDie.
MINOPTMAX< int > m_targetSkew
Target skew value for diff pair de-skewing.
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
MINOPTMAX< long long int > m_targetSignalLengthDelay
Target skew value for diff pair de-skewing.
bool m_keepEndpoints
Calculate tuning in the time domain.
MINOPTMAX< int > m_targetSkewDelay
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
long long int m_signalExtraDelay
Desired length of the tuned line/diff pair (this is in nm, so allow more than board width).
bool m_overrideCustomRules
Type of corners for the meandered line.
MINOPTMAX< long long int > m_targetLengthDelay
Desired chain length (copper-only, bridging subtracted).
void SetTargetSkewDelay(int aOpt)
static const long long int DELAY_UNCONSTRAINED
Definition pns_meander.h:76
int m_lenPadToDie
Additional pre-existing length contributed by other nets in the same logical chain (used when chain-l...
long long int m_signalExtraLength
Additional pre-existing delay contributed by other nets in the same logical chain (used when chain-le...
int m_spacing
Amplitude/spacing adjustment step.
MINOPTMAX< long long int > m_targetSignalLength
Desired overall chain propagation delay.
The geometry of a single meander.
MEANDER_TYPE m_type
The placer that placed this meander.
int MinAmplitude() const
MEANDER_PLACER_BASE * m_placer
Dual or single line.
SEG m_baseSeg
Base segment (clipped).
MEANDER_SHAPE(MEANDER_PLACER_BASE *aPlacer, int aWidth, bool aIsDual=false)
SEG m_clippedBaseSeg
Side (true = right).
int Amplitude() const
void SetType(MEANDER_TYPE aType)
Set the type of the meander.
int m_targetBaseLen
First point of the meandered line.
VECTOR2I End() const
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.
int m_baselineOffset
Average radius of meander corners (for correction of DP meanders).
VECTOR2D m_currentDir
The current turtle position.
int m_width
Amplitude of the meander.
VECTOR2D m_currentPos
The line the turtle is drawing on.
SHAPE_LINE_CHAIN m_shapes[2]
Index of the meandered segment in the base line.
long long int CurrentLength() const
bool m_side
The actual shapes (0 used for single, both for dual).
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.
SHAPE_LINE_CHAIN * m_currentTarget
bool m_dual
Width of the line.
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.
int spacing() const
The type of meander.
int m_amplitude
Offset wrs the base segment (dual only).
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.
void forward(int aLength)
Turn the turtle by aAngle.
MEANDER_TYPE Type() const
VECTOR2I m_p0
Base segment (unclipped).
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
int BaselineLength() const
const SEG & BaseSegment() const
Return the base segment the meander was fitted to.
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:343
bool ApproxParallel(const SEG &aSeg, int aDistanceThreshold=1) const
Definition seg.cpp:807
bool Contains(const SEG &aSeg) const
Definition seg.h:324
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.
const VECTOR2I & GetP1() const
Definition shape_arc.h:119
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 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 VECTOR2I & CLastPoint() const
Return the last point in the line chain.
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the line points about y or x (or both).
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:283
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
Definition vector2d.h:314
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:385
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
Push and Shove diff pair dimensions (gap) settings dialog.
MEANDER_TYPE
Shapes of available meanders.
Definition pns_meander.h:40
@ MT_TURN
Definition pns_meander.h:44
@ MT_CHECK_START
Definition pns_meander.h:45
@ MT_CHECK_FINISH
Definition pns_meander.h:46
@ MT_START
Definition pns_meander.h:42
@ MT_FINISH
Definition pns_meander.h:43
@ MT_EMPTY
Definition pns_meander.h:49
@ MT_CORNER
Definition pns_meander.h:47
@ MT_SINGLE
Definition pns_meander.h:41
MEANDER_SIDE
Definition pns_meander.h:60
@ MEANDER_SIDE_LEFT
Definition pns_meander.h:61
@ MEANDER_STYLE_ROUND
Definition pns_meander.h:54
@ MEANDER_STYLE_CHAMFER
Definition pns_meander.h:55
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
constexpr double correction
const double IU_PER_PS
Internal time units are attoseconds.
Definition base_units.h:80
const double IU_PER_MM
Definition base_units.h:78
constexpr int mmToIU(double mm) const
Definition base_units.h:94
KIBIS top(path, &reporter)
MATRIX3x3D m2(VECTOR3I{ 6, 6, 6 }, { 1, 1, 1 }, { 3, 3, 3 })
Test suite for KiCad math code.
SHAPE_ARC arc2(c.m_arc2.GenerateArc())
int radius
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:229
double DEG2RAD(double deg)
Definition trigo.h:166
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686