KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_tuning_pattern.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 Alex Shvartzkop <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <pcb_generator.h>
26#include <generators_mgr.h>
27
28#include <optional>
29#include <magic_enum.hpp>
30
31#include <wx/debug.h>
34#include <kiplatform/ui.h>
36#include <collectors.h>
37#include <scoped_set_reset.h>
38#include <core/mirror.h>
39
41#include <drc/drc_engine.h>
42#include <pcb_track.h>
43#include <pcb_shape.h>
44#include <pcb_group.h>
45
46#include <tool/edit_points.h>
47#include <tools/drawing_tool.h>
52
55#include <view/view.h>
56#include <view/view_controls.h>
57
60#include <router/pns_meander.h>
62#include <router/pns_segment.h>
63#include <router/pns_arc.h>
64#include <router/pns_solid.h>
65#include <router/pns_topology.h>
67
69
70#include <wx/log.h>
71
72
74{
78};
79
80
82{
83public:
85 EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
86 m_frame( aFrame ), m_min( 0.0 ), m_max( 0.0 ), m_current( 0.0 ), m_isTimeDomain( false )
87 { }
88
89 wxString GetClass() const override { return wxT( "TUNING_STATUS" ); }
90
91#if defined(DEBUG)
92 void Show( int nestLevel, std::ostream& os ) const override {}
93#endif
94
95 VECTOR2I GetPosition() const override { return m_pos; }
96 void SetPosition( const VECTOR2I& aPos ) override { m_pos = aPos; };
97
98 void SetMinMax( const double aMin, const double aMax )
99 {
100 const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
101
102 m_min = aMin;
103 m_minText = m_frame->MessageTextFromValue( m_min, false, unitType );
104 m_max = aMax;
105 m_maxText = m_frame->MessageTextFromValue( m_max, false, unitType );
106 }
107
109 {
110 m_min = 0.0;
111 m_minText = wxT( "---" );
112 m_max = std::numeric_limits<double>::max();
113 m_maxText = wxT( "---" );
114 }
115
116 void SetCurrent( const double aCurrent, const wxString& aLabel )
117 {
118 const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
119
120 m_current = aCurrent;
121 m_currentText = m_frame->MessageTextFromValue( aCurrent, true, unitType );
122 m_currentLabel = aLabel;
123 }
124
125 void SetIsTimeDomain( const bool aIsTimeDomain ) { m_isTimeDomain = aIsTimeDomain; }
126
127 const BOX2I ViewBBox() const override
128 {
129 BOX2I tmp;
130
131 // this is an edit-time artefact; no reason to try and be smart with the bounding box
132 // (besides, we can't tell the text extents without a view to know what the scale is)
133 tmp.SetMaximum();
134 return tmp;
135 }
136
137 std::vector<int> ViewGetLayers() const override
138 {
139 return { LAYER_UI_START, LAYER_UI_START + 1 };
140 }
141
142 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override
143 {
144 KIGFX::GAL* gal = aView->GetGAL();
145 bool viewFlipped = gal->IsFlippedX();
146 bool drawingDropShadows = ( aLayer == LAYER_UI_START );
147
148 gal->Save();
149 gal->Scale( { 1., 1. } );
150
154 const KIFONT::METRICS& fontMetrics = KIFONT::METRICS::Default();
155 TEXT_ATTRIBUTES textAttrs;
156
157 int glyphWidth = textDims.GlyphSize.x;
158 VECTOR2I margin( KiROUND( glyphWidth * 0.4 ), KiROUND( glyphWidth ) );
159 VECTOR2I size( glyphWidth * 25 + margin.x * 2, headerDims.GlyphSize.y + textDims.GlyphSize.y );
160 VECTOR2I offset( margin.x * 2, -( size.y + margin.y * 2 ) );
161
162 if( drawingDropShadows )
163 {
164 gal->SetIsFill( true );
165 gal->SetIsStroke( true );
166 gal->SetLineWidth( gal->GetScreenWorldMatrix().GetScale().x * 2 );
167 gal->SetStrokeColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) );
168 KIGFX::COLOR4D bgColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
169 gal->SetFillColor( bgColor.WithAlpha( 0.9 ) );
170
171 gal->DrawRectangle( GetPosition() + offset - margin,
172 GetPosition() + offset + size + margin );
173 gal->Restore();
174 return;
175 }
176
177 COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
178 COLOR4D normal = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
179 COLOR4D red;
180
181 // Choose a red with reasonable contrasting with the background
182 double bg_h, bg_s, bg_l;
183 bg.ToHSL( bg_h, bg_s, bg_l );
184 red.FromHSL( 0, 1.0, bg_l < 0.5 ? 0.7 : 0.3 );
185
186 if( viewFlipped )
188 else
189 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
190
191 gal->SetIsFill( false );
192 gal->SetIsStroke( true );
193 gal->SetStrokeColor( normal );
194 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
195
196 // Prevent text flipping when view is flipped
197 if( gal->IsFlippedX() )
198 {
199 textAttrs.m_Mirrored = true;
201 }
202
203 textAttrs.m_Size = headerDims.GlyphSize;
204 textAttrs.m_StrokeWidth = headerDims.StrokeWidth;
205
206 VECTOR2I textPos = GetPosition() + offset;
207 font->Draw( gal, m_currentLabel, textPos, textAttrs, KIFONT::METRICS::Default() );
208
209 textPos.x += glyphWidth * 11 + margin.x;
210 font->Draw( gal, _( "min" ), textPos, textAttrs, fontMetrics );
211
212 textPos.x += glyphWidth * 7 + margin.x;
213 font->Draw( gal, _( "max" ), textPos, textAttrs, fontMetrics );
214
215 textAttrs.m_Size = textDims.GlyphSize;
216 textAttrs.m_StrokeWidth = textDims.StrokeWidth;
217
218 textPos = GetPosition() + offset;
219 textPos.y += KiROUND( headerDims.LinePitch * 1.3 );
220 font->Draw( gal, m_currentText, textPos, textAttrs, KIFONT::METRICS::Default() );
221
222 textPos.x += glyphWidth * 11 + margin.x;
224 font->Draw( gal, m_minText, textPos, textAttrs, fontMetrics );
225
226 textPos.x += glyphWidth * 7 + margin.x;
228 font->Draw( gal, m_maxText, textPos, textAttrs, fontMetrics );
229
230 gal->Restore();
231 }
232
233protected:
236 double m_min;
237 double m_max;
238 double m_current;
241 wxString m_minText;
242 wxString m_maxText;
244};
245
246
248{
249public:
250 static const wxString GENERATOR_TYPE;
251 static const wxString DISPLAY_NAME;
252
253 PCB_TUNING_PATTERN( BOARD_ITEM* aParent = nullptr, PCB_LAYER_ID aLayer = F_Cu,
254 LENGTH_TUNING_MODE aMode = LENGTH_TUNING_MODE::SINGLE );
255
256 wxString GetGeneratorType() const override { return wxS( "tuning_pattern" ); }
257
258 wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override
259 {
260 return wxString( _( "Tuning Pattern" ) );
261 }
262
263 wxString GetFriendlyName() const override
264 {
265 return wxString( _( "Tuning Pattern" ) );
266 }
267
268 wxString GetPluralName() const override
269 {
270 return wxString( _( "Tuning Patterns" ) );
271 }
272
273 BITMAPS GetMenuImage() const override
274 {
275 switch( m_tuningMode )
276 {
277 case SINGLE: return BITMAPS::ps_tune_length; break;
278 case DIFF_PAIR: return BITMAPS::ps_diff_pair_tune_length; break;
279 case DIFF_PAIR_SKEW: return BITMAPS::ps_diff_pair_tune_phase; break;
280 }
281
282 return BITMAPS::unknown;
283 }
284
286 BOARD_CONNECTED_ITEM* aStartItem,
287 LENGTH_TUNING_MODE aMode );
288
289 void EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
290
291 bool Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
292
293 void EditPush( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit,
294 const wxString& aCommitMsg = wxEmptyString, int aCommitFlags = 0 ) override;
295
296 void EditRevert( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
297
298 void Remove( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
299
300 bool MakeEditPoints( EDIT_POINTS& points ) const override;
301
302 bool UpdateFromEditPoints( EDIT_POINTS& aEditPoints ) override;
303
304 bool UpdateEditPoints( EDIT_POINTS& aEditPoints ) override;
305
306 void Move( const VECTOR2I& aMoveVector ) override
307 {
308 m_origin += aMoveVector;
309 m_end += aMoveVector;
310
311 if( !this->HasFlag( IN_EDIT ) )
312 {
313 PCB_GROUP::Move( aMoveVector );
314
315 if( m_baseLine )
316 m_baseLine->Move( aMoveVector );
317
319 m_baseLineCoupled->Move( aMoveVector );
320 }
321 }
322
323 void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override
324 {
325 if( !this->HasFlag( IN_EDIT ) )
326 {
327 PCB_GENERATOR::Rotate( aRotCentre, aAngle );
328 RotatePoint( m_end, aRotCentre, aAngle );
329
330 if( m_baseLine )
331 m_baseLine->Rotate( aAngle, aRotCentre );
332
334 m_baseLineCoupled->Rotate( aAngle, aRotCentre );
335 }
336 }
337
338 void Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
339 {
340 if( !this->HasFlag( IN_EDIT ) )
341 {
342 PCB_GENERATOR::Flip( aCentre, aFlipDirection );
343
344 baseMirror( aCentre, aFlipDirection );
345 }
346 }
347
348 void Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
349 {
350 if( !this->HasFlag( IN_EDIT ) )
351 {
352 PCB_GENERATOR::Mirror( aCentre, aFlipDirection );
353
354 baseMirror( aCentre, aFlipDirection );
355 }
356 }
357
358 const BOX2I GetBoundingBox() const override
359 {
360 return getOutline().BBox();
361 }
362
363 std::vector<int> ViewGetLayers() const override
364 {
365 return { LAYER_ANCHOR, GetLayer() };
366 }
367
368 bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
369 {
370 return getOutline().Collide( aPosition, aAccuracy );
371 }
372
373 bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
374 {
375 BOX2I sel = aRect;
376
377 if ( aAccuracy )
378 sel.Inflate( aAccuracy );
379
380 if( aContained )
381 return sel.Contains( GetBoundingBox() );
382
383 return sel.Intersects( GetBoundingBox() );
384 }
385
386 const BOX2I ViewBBox() const override { return GetBoundingBox(); }
387
388 EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
389
390 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
391
392 const VECTOR2I& GetEnd() const { return m_end; }
393 void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
394
395 int GetEndX() const { return m_end.x; }
396 void SetEndX( int aValue ) { m_end.x = aValue; }
397
398 int GetEndY() const { return m_end.y; }
399 void SetEndY( int aValue ) { m_end.y = aValue; }
400
402
404 {
405 switch( m_tuningMode )
406 {
407 case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
408 case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
409 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
410 default: return PNS::PNS_MODE_TUNE_SINGLE;
411 }
412 }
413
415
417 void SetMinAmplitude( int aValue )
418 {
419 aValue = std::max( aValue, 0 );
420
421 m_settings.m_minAmplitude = aValue;
422
425 }
426
428 void SetMaxAmplitude( int aValue )
429 {
430 aValue = std::max( aValue, 0 );
431
432 m_settings.m_maxAmplitude = aValue;
433
436 }
437
438 // Update the initial side one time at EditStart based on m_end.
440
443
444 int GetSpacing() const { return m_settings.m_spacing; }
445 void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
446
447 std::optional<int> GetTargetLength() const
448 {
450 return std::optional<int>();
451 else
453 }
454
455 void SetTargetLength( std::optional<int> aValue )
456 {
458
459 if( aValue.has_value() )
460 m_settings.SetTargetLength( aValue.value() );
461 else
463 }
464
465 std::optional<int> GetTargetDelay() const
466 {
468 return std::optional<int>();
469 else
471 }
472
473 void SetTargetDelay( std::optional<int> aValue )
474 {
476
477 if( aValue.has_value() )
478 m_settings.SetTargetLengthDelay( aValue.value() );
479 else
481 }
482
483 int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
484 void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
485
487 void SetTargetSkewDelay( int aValue ) { m_settings.SetTargetSkewDelay( aValue ); }
488
490 void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
491
494
495 bool IsSingleSided() const { return m_settings.m_singleSided; }
496 void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
497
501
502 std::vector<std::pair<wxString, wxVariant>> GetRowData() override
503 {
504 std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
505 data.emplace_back( _HKI( "Net" ), m_lastNetName );
506 data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
507 return data;
508 }
509
510 const STRING_ANY_MAP GetProperties() const override;
511 void SetProperties( const STRING_ANY_MAP& aProps ) override;
512
513 void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
514
515 std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
516 bool aStatusItemsOnly = false ) override;
517
518 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
519
520protected:
521 void swapData( BOARD_ITEM* aImage ) override
522 {
523 wxASSERT( aImage->Type() == PCB_GENERATOR_T );
524
525 std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
526 }
527
528 bool recoverBaseline( PNS::ROUTER* aRouter );
529
530 bool baselineValid();
531
532 bool initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard, VECTOR2I& aStart,
533 VECTOR2I& aEnd, NETINFO_ITEM* aNet,
534 std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
535
536 bool initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard );
537
538 bool removeToBaseline( PNS::ROUTER* aRouter, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine );
539
540 bool resetToBaseline( GENERATOR_TOOL* aTool, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine,
541 bool aPrimary );
542
544
545 void baseMirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
546 {
547 PCB_GENERATOR::baseMirror( aCentre, aFlipDirection );
548
549 if( m_baseLine )
550 {
551 m_baseLine->Mirror( aCentre, aFlipDirection );
552 m_origin = m_baseLine->CPoint( 0 );
553 m_end = m_baseLine->CPoint( -1 );
554 }
555
557 m_baseLineCoupled->Mirror( aCentre, aFlipDirection );
558
561 else
563 }
564
565protected:
567
569
570 std::optional<SHAPE_LINE_CHAIN> m_baseLine;
571 std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
572
575
577
579 wxString m_tuningInfo;
580
582
584};
585
586
587static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
588{
589 if( aStr == "single" )
591 else if( aStr == "diff_pair" )
593 else if( aStr == "diff_pair_skew" )
595 else
596 {
597 wxFAIL_MSG( wxS( "Unknown length tuning token" ) );
599 }
600}
601
602
603static std::string tuningToString( const LENGTH_TUNING_MODE aTuning )
604{
605 switch( aTuning )
606 {
607 case LENGTH_TUNING_MODE::SINGLE: return "single";
608 case LENGTH_TUNING_MODE::DIFF_PAIR: return "diff_pair";
609 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return "diff_pair_skew";
610 default: wxFAIL; return "";
611 }
612}
613
614
616{
617 switch( aRouterMode )
618 {
622 default: return LENGTH_TUNING_MODE::SINGLE;
623 }
624}
625
626
627static PNS::MEANDER_SIDE sideFromString( const std::string& aStr )
628{
629 if( aStr == "default" )
631 else if( aStr == "left" )
633 else if( aStr == "right" )
635 else
636 {
637 wxFAIL_MSG( wxS( "Unknown length-tuning side token" ) );
639 }
640}
641
642
644{
645 switch( aStatus )
646 {
647 case PNS::MEANDER_PLACER_BASE::TOO_LONG: return "too_long";
648 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: return "too_short";
649 case PNS::MEANDER_PLACER_BASE::TUNED: return "tuned";
650 default: wxFAIL; return "";
651 }
652}
653
654
656{
657 if( aStr == "too_long" )
659 else if( aStr == "too_short" )
661 else if( aStr == "tuned" )
663 else
664 {
665 wxFAIL_MSG( wxS( "Unknown tuning status token" ) );
667 }
668}
669
670
671static std::string sideToString( const PNS::MEANDER_SIDE aValue )
672{
673 switch( aValue )
674 {
675 case PNS::MEANDER_SIDE_DEFAULT: return "default";
676 case PNS::MEANDER_SIDE_LEFT: return "left";
677 case PNS::MEANDER_SIDE_RIGHT: return "right";
678 default: wxFAIL; return "";
679 }
680}
681
682
684 LENGTH_TUNING_MODE aMode ) :
685 PCB_GENERATOR( aParent, aLayer ),
686 m_trackWidth( 0 ),
687 m_diffPairGap( 0 ),
688 m_tuningMode( aMode ),
689 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED ),
690 m_updateSideFromEnd(false)
691{
694 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
696}
697
698
699static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
700 PCB_TRACK** aNearestTrack )
701{
703 VECTOR2I closestPt = aP;
704
705 for( PCB_TRACK *track : aBoard->Tracks() )
706 {
707 if( aNet && track->GetNet() != aNet )
708 continue;
709
710 VECTOR2I nearest;
711
712 if( track->Type() == PCB_ARC_T )
713 {
714 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
715 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
716 pcbArc->GetWidth() );
717
718 nearest = arc.NearestPoint( aP );
719 }
720 else
721 {
722 SEG seg( track->GetStart(), track->GetEnd() );
723 nearest = seg.NearestPoint( aP );
724 }
725
726 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
727
728 if( dist_sq < minDist_sq )
729 {
730 minDist_sq = dist_sq;
731 closestPt = nearest;
732
733 if( aNearestTrack )
734 *aNearestTrack = track;
735 }
736 }
737
738 return closestPt;
739}
740
741
743{
745 {
746 return( m_baseLine && m_baseLine->PointCount() > 1
747 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
748 }
749 else
750 {
751 return( m_baseLine && m_baseLine->PointCount() > 1 );
752 }
753}
754
755
757 PCB_BASE_EDIT_FRAME* aFrame,
758 BOARD_CONNECTED_ITEM* aStartItem,
759 LENGTH_TUNING_MODE aMode )
760{
761 BOARD* board = aStartItem->GetBoard();
763 DRC_CONSTRAINT constraint;
764 PCB_LAYER_ID layer = aStartItem->GetLayer();
765
766 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
767
768 switch( aMode )
769 {
770 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
771 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
772 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
773 }
774
775 if( aMode == SINGLE || aMode == DIFF_PAIR )
776 {
777 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
778
779 if( !constraint.IsNull() )
780 {
782 {
783 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
785 pattern->m_settings.m_isTimeDomain = true;
786 }
787 else
788 {
790 pattern->m_settings.SetTargetLength( constraint.GetValue() );
791 pattern->m_settings.m_isTimeDomain = false;
792 }
793 }
794 }
795 else
796 {
797 constraint = bds.m_DRCEngine->EvalRules( SKEW_CONSTRAINT, aStartItem, nullptr, layer );
798
799 if( !constraint.IsNull() )
800 {
802 {
804 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
805 pattern->m_settings.m_isTimeDomain = true;
806 }
807 else
808 {
809 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
811 pattern->m_settings.m_isTimeDomain = true;
812 }
813 }
814 }
815
816 pattern->SetFlags( IS_NEW );
817 pattern->m_settings.m_netClass = aStartItem->GetEffectiveNetClass();
818
819 return pattern;
820}
821
823{
824 if( aCommit )
825 {
826 if( IsNew() )
827 aCommit->Add( this );
828 else
829 aCommit->Modify( this );
830 }
831
832 SetFlags( IN_EDIT );
833
834 PNS::ROUTER* router = aTool->Router();
835 int layer = router->GetInterface()->GetPNSLayerFromBoardLayer( GetLayer() );
836
837 aTool->ClearRouterChanges();
838 router->SyncWorld();
839
841 PNS::CONSTRAINT constraint;
842
843 if( !baselineValid() )
844 initBaseLines( router, layer, aBoard );
845
847 {
848 VECTOR2I centerlineOffsetEnd;
849
851 && m_baseLineCoupled->SegmentCount() > 0 )
852 {
853 centerlineOffsetEnd =
854 ( m_baseLineCoupled->CPoint( -1 ) - m_baseLine->CPoint( -1 ) ) / 2;
855 }
856
857 SEG baseEnd = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( -1 )
858 : SEG( m_origin, m_end );
859
860 baseEnd.A += centerlineOffsetEnd;
861 baseEnd.B += centerlineOffsetEnd;
862
863 if( baseEnd.A != baseEnd.B )
864 {
865 int side = baseEnd.Side( m_end );
866
867 if( side < 0 )
869 else
871 }
872
873 m_updateSideFromEnd = false;
874 }
875
876 PCB_TRACK* track = nullptr;
877 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
878 wxCHECK( track, /* void */ );
879
881
883 {
884 PNS::SEGMENT pnsItem;
885 NETINFO_ITEM* net = track->GetNet();
886
887 pnsItem.SetParent( track );
888 pnsItem.SetNet( net );
889
890 if( m_tuningMode == SINGLE )
891 {
892 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
893 &pnsItem, nullptr, layer, &constraint ) )
894 {
895 if( constraint.m_IsTimeDomain )
896 {
899 }
900 else
901 {
903 m_settings.SetTargetLength( constraint.m_Value );
904 }
905
908 }
909 }
910 else
911 {
912 PCB_TRACK* coupledTrack = nullptr;
913 PNS::SEGMENT pnsCoupledItem;
914 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
915
916 if( coupledNet )
917 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
918
919 pnsCoupledItem.SetParent( coupledTrack );
920 pnsCoupledItem.SetNet( coupledNet );
921
922 if( m_tuningMode == DIFF_PAIR )
923 {
924 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
925 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
926 {
927 if( constraint.m_IsTimeDomain )
928 {
931 }
932 else
933 {
935 m_settings.SetTargetLength( constraint.m_Value );
936 }
937
940 }
941 }
942 else
943 {
945 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
946 {
947 if( constraint.m_IsTimeDomain )
948 {
951 }
952 else
953 {
955 m_settings.SetTargetSkew( constraint.m_Value );
956 }
957
960 }
961 }
962 }
963 }
964}
965
966
967static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
968 VECTOR2I& aPointOut,
969 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
970{
971 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
972
973 static const int candidateCount = 2;
974 PNS::LINKED_ITEM* prioritized[candidateCount];
975 SEG::ecoord dist[candidateCount];
976 SEG::ecoord distBaseline[candidateCount];
977 VECTOR2I point[candidateCount];
978
979 for( int i = 0; i < candidateCount; i++ )
980 {
981 prioritized[i] = nullptr;
982 dist[i] = VECTOR2I::ECOORD_MAX;
983 distBaseline[i] = VECTOR2I::ECOORD_MAX;
984 }
985
986 for( int slopRadius : { 0, maxSlopRadius } )
987 {
988 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
989
990 for( PNS::ITEM* item : candidates.Items() )
991 {
992 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
993 continue;
994
995 if( !item->IsRoutable() )
996 continue;
997
998 if( !item->Layers().Overlaps( aLayer ) )
999 continue;
1000
1001 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
1002
1003 if( item->Kind() & PNS::ITEM::ARC_T )
1004 {
1005 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
1006
1007 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
1008 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
1009
1010 if( d0 > dist[1] )
1011 continue;
1012
1013 if( aBaseline.PointCount() > 0 )
1014 {
1015 SEG::ecoord dcBaseline;
1016 VECTOR2I target = pnsArc->Arc().GetArcMid();
1017
1018 if( aBaseline.SegmentCount() > 0 )
1019 dcBaseline = aBaseline.SquaredDistance( target );
1020 else
1021 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
1022
1023 if( dcBaseline > distBaseline[1] )
1024 continue;
1025
1026 distBaseline[1] = dcBaseline;
1027 }
1028
1029 prioritized[1] = linked;
1030 dist[1] = d0;
1031 point[1] = nearest;
1032 }
1033 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
1034 {
1035 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
1036
1037 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
1038 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
1039
1040 if( dd > dist[1] )
1041 continue;
1042
1043 if( aBaseline.PointCount() > 0 )
1044 {
1045 SEG::ecoord dcBaseline;
1046 VECTOR2I target = segm->Shape( -1 )->Centre();
1047
1048 if( aBaseline.SegmentCount() > 0 )
1049 dcBaseline = aBaseline.SquaredDistance( target );
1050 else
1051 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
1052
1053 if( dcBaseline > distBaseline[1] )
1054 continue;
1055
1056 distBaseline[1] = dcBaseline;
1057 }
1058
1059 prioritized[1] = segm;
1060 dist[1] = dd;
1061 point[1] = nearest;
1062 }
1063 }
1064 }
1065
1066 PNS::LINKED_ITEM* rv = nullptr;
1067
1068 for( int i = 0; i < candidateCount; i++ )
1069 {
1070 PNS::LINKED_ITEM* item = prioritized[i];
1071
1072 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
1073 {
1074 rv = item;
1075 aPointOut = point[i];
1076 break;
1077 }
1078 }
1079
1080 return rv;
1081}
1082
1083
1084static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
1085 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
1086 VECTOR2I& aEndOut )
1087{
1088 PNS::NODE* world = router->GetWorld();
1089
1090 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
1091 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
1092
1093 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
1094 {
1095 if( !testItem )
1096 continue;
1097
1098 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
1099 SHAPE_LINE_CHAIN oldChain = line.CLine();
1100
1101 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
1102 return line;
1103 }
1104
1105 return std::nullopt;
1106}
1107
1108
1109bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard,
1110 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
1111 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
1112{
1113 PNS::NODE* world = aRouter->GetWorld();
1114
1115 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
1116 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
1117
1118 VECTOR2I startSnapPoint, endSnapPoint;
1119
1120 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aPNSLayer, startSnapPoint );
1121 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aPNSLayer, endSnapPoint );
1122
1123 wxASSERT( startItem );
1124 wxASSERT( endItem );
1125
1126 if( !startItem || !endItem )
1127 return false;
1128
1129 PNS::LINE line = world->AssembleLine( startItem );
1130 const SHAPE_LINE_CHAIN& chain = line.CLine();
1131
1132 wxASSERT( line.ContainsLink( endItem ) );
1133
1134 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
1135 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
1136
1137 SHAPE_LINE_CHAIN pre;
1138 SHAPE_LINE_CHAIN mid;
1139 SHAPE_LINE_CHAIN post;
1140
1141 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
1142
1143 aBaseLine = mid;
1144
1145 return true;
1146}
1147
1148
1149bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard )
1150{
1151 m_baseLineCoupled.reset();
1152
1153 PCB_TRACK* track = nullptr;
1154
1155 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
1156 wxCHECK( track, false );
1157
1158 NETINFO_ITEM* net = track->GetNet();
1159
1160 if( !initBaseLine( aRouter, aPNSLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
1161 return false;
1162
1163 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
1164 // DRC rules against.
1166 {
1167 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
1168 {
1169 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
1170 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
1171
1172 return initBaseLine( aRouter, aPNSLayer, aBoard, coupledStart, coupledEnd, coupledNet,
1174 }
1175
1176 return false;
1177 }
1178
1179 return true;
1180}
1181
1183 SHAPE_LINE_CHAIN& aBaseLine )
1184{
1185 VECTOR2I startSnapPoint, endSnapPoint;
1186
1187 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1188 aRouter, aPNSLayer, startSnapPoint, endSnapPoint );
1189
1190 wxCHECK( pnsLine, false );
1191
1192 SHAPE_LINE_CHAIN pre;
1193 SHAPE_LINE_CHAIN mid;
1194 SHAPE_LINE_CHAIN post;
1195 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1196
1197 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
1198 aRouter->GetInterface()->RemoveItem( li );
1199
1200 aRouter->GetWorld()->Remove( *pnsLine );
1201
1202 SHAPE_LINE_CHAIN straightChain;
1203 straightChain.Append( pre );
1204 straightChain.Append( aBaseLine );
1205 straightChain.Append( post );
1206 straightChain.Simplify();
1207
1208 PNS::LINE straightLine( *pnsLine, straightChain );
1209
1210 aRouter->GetWorld()->Add( straightLine, false );
1211
1212 for( PNS::LINKED_ITEM* li : straightLine.Links() )
1213 aRouter->GetInterface()->AddItem( li );
1214
1215 return true;
1216}
1217
1218
1220{
1221 SetFlags( IN_EDIT );
1222
1223 aTool->Router()->SyncWorld();
1224
1225 PNS::ROUTER* router = aTool->Router();
1226 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1227
1228 // Ungroup first so that undo works
1229 if( !GetItems().empty() )
1230 {
1231 PCB_GENERATOR* group = this;
1232
1233 for( EDA_ITEM* member : group->GetItems() )
1234 aCommit->Stage( member, CHT_UNGROUP );
1235
1236 group->GetItems().clear();
1237 }
1238
1239 aCommit->Remove( this );
1240
1241 aTool->ClearRouterChanges();
1242
1243 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1244 int pnslayer = iface->GetPNSLayerFromBoardLayer( GetLayer() );
1245
1246 if( baselineValid() )
1247 {
1248 bool success = true;
1249
1250 success &= removeToBaseline( router, pnslayer, *m_baseLine );
1251
1252 if( m_tuningMode == DIFF_PAIR )
1253 success &= removeToBaseline( router, pnslayer, *m_baseLineCoupled );
1254
1255 if( !success )
1256 recoverBaseline( router );
1257 }
1258
1259 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
1260
1261 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
1262 {
1263 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
1264 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
1265
1266 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1267 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1268 << " m_removedItems " << m_removedItems.size() << std::endl;*/
1269
1270 for( BOARD_ITEM* item : routerRemovedItems )
1271 {
1272 item->ClearSelected();
1273 aCommit->Remove( item );
1274 }
1275
1276 for( BOARD_ITEM* item : routerAddedItems )
1277 aCommit->Add( item );
1278 }
1279
1280 aCommit->Push( "Remove Tuning Pattern" );
1281}
1282
1283
1285{
1286 PNS::SOLID queryItem;
1287
1288 SHAPE_LINE_CHAIN* chain = static_cast<SHAPE_LINE_CHAIN*>( getOutline().Clone() );
1289 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
1290 queryItem.SetLayer( m_layer );
1291
1292 int lineWidth = 0;
1293
1294 PNS::NODE::OBSTACLES obstacles;
1296 opts.m_useClearanceEpsilon = false;
1297
1298 PNS::NODE* world = aRouter->GetWorld();
1299 PNS::NODE* branch = world->Branch();
1300
1301 branch->QueryColliding( &queryItem, obstacles, opts );
1302
1303 for( const PNS::OBSTACLE& obs : obstacles )
1304 {
1305 PNS::ITEM* item = obs.m_item;
1306
1308 continue;
1309
1310 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
1311 {
1312 if( lineWidth == 0 || li->Width() < lineWidth )
1313 lineWidth = li->Width();
1314 }
1315
1316 if( chain->PointInside( item->Anchor( 0 ), 10 )
1317 && chain->PointInside( item->Anchor( 1 ), 10 ) )
1318 {
1319 branch->Remove( item );
1320 }
1321 }
1322
1323 if( lineWidth == 0 )
1324 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1325
1326 if( baselineValid() )
1327 {
1328 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1329 PNS::LINE recoverLine;
1330
1331 recoverLine.SetLayer( m_layer );
1332 recoverLine.SetWidth( lineWidth );
1333 recoverLine.Line() = *m_baseLine;
1334 recoverLine.SetNet( recoverNet );
1335 branch->Add( recoverLine, false );
1336
1338 {
1339 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1340 PNS::LINE recoverLineCoupled;
1341
1342 recoverLineCoupled.SetLayer( m_layer );
1343 recoverLineCoupled.SetWidth( lineWidth );
1344 recoverLineCoupled.Line() = *m_baseLineCoupled;
1345 recoverLineCoupled.SetNet( recoverCoupledNet );
1346 branch->Add( recoverLineCoupled, false );
1347 }
1348 }
1349
1350 aRouter->CommitRouting( branch );
1351
1352 //wxLogWarning( "PNS baseline recovered" );
1353
1354 return true;
1355}
1356
1357
1359 SHAPE_LINE_CHAIN& aBaseLine, bool aPrimary )
1360{
1361 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1362 PNS::ROUTER* router = aTool->Router();
1363 PNS::NODE* world = router->GetWorld();
1364 VECTOR2I startSnapPoint, endSnapPoint;
1365
1366 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1367 router, aPNSLayer, startSnapPoint, endSnapPoint );
1368
1369 if( !pnsLine )
1370 {
1371 // TODO
1372 //recoverBaseline( aRouter );
1373 return true;
1374 }
1375
1376 PNS::NODE* branch = world->Branch();
1377
1378 SHAPE_LINE_CHAIN straightChain;
1379 {
1380 SHAPE_LINE_CHAIN pre, mid, post;
1381 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1382
1383 straightChain.Append( pre );
1384 straightChain.Append( aBaseLine );
1385 straightChain.Append( post );
1386 straightChain.Simplify();
1387 }
1388
1389 branch->Remove( *pnsLine );
1390
1391 SHAPE_LINE_CHAIN newLineChain;
1392
1393 if( aPrimary )
1394 {
1395 m_origin = straightChain.NearestPoint( m_origin );
1396 m_end = straightChain.NearestPoint( m_end );
1397
1398 // Don't allow points too close
1399 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1400 {
1401 m_origin = startSnapPoint;
1402 m_end = endSnapPoint;
1403 }
1404
1405 {
1406 SHAPE_LINE_CHAIN pre, mid, post;
1407 straightChain.Split( m_origin, m_end, pre, mid, post );
1408
1409 newLineChain.Append( pre );
1410 newLineChain.Append( mid );
1411 newLineChain.Append( post );
1412
1413 m_baseLine = mid;
1414 }
1415 }
1416 else
1417 {
1418 VECTOR2I start = straightChain.NearestPoint( m_origin );
1419 VECTOR2I end = straightChain.NearestPoint( m_end );
1420
1421 {
1422 SHAPE_LINE_CHAIN pre, mid, post;
1423 straightChain.Split( start, end, pre, mid, post );
1424
1425 newLineChain.Append( pre );
1426 newLineChain.Append( mid );
1427 newLineChain.Append( post );
1428
1429 m_baseLineCoupled = mid;
1430 }
1431 }
1432
1433 PNS::LINE newLine( *pnsLine, newLineChain );
1434
1435 branch->Add( newLine, false );
1436 router->CommitRouting( branch );
1437
1438 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1439
1440 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1441
1442 return true;
1443}
1444
1445
1447{
1448 if( !( GetFlags() & IN_EDIT ) )
1449 return false;
1450
1451 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1452 PNS::ROUTER* router = aTool->Router();
1453 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1454 PCB_LAYER_ID pcblayer = GetLayer();
1455
1456 auto hideRemovedItems = [&]( bool aHide )
1457 {
1458 if( view )
1459 {
1460 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1461 {
1462 for( BOARD_ITEM* item : pnsCommit.removedItems )
1463 {
1464 if( view )
1465 view->Hide( item, aHide, aHide );
1466 }
1467 }
1468 }
1469 };
1470
1471 iface->SetStartLayerFromPCBNew( pcblayer );
1472
1473 if( router->RoutingInProgress() )
1474 {
1475 router->StopRouting();
1476 }
1477
1478 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1479 int pnslayer = iface->GetPNSLayerFromBoardLayer( pcblayer );
1480
1481 if( !baselineValid() )
1482 {
1483 initBaseLines( router, pnslayer, aBoard );
1484 }
1485 else
1486 {
1487 if( resetToBaseline( aTool, pnslayer, *m_baseLine, true ) )
1488 {
1489 m_origin = m_baseLine->CPoint( 0 );
1490 m_end = m_baseLine->CPoint( -1 );
1491 }
1492 else
1493 {
1494 //initBaseLines( router, layer, aBoard );
1495 return false;
1496 }
1497
1498 if( m_tuningMode == DIFF_PAIR )
1499 {
1500 if( !resetToBaseline( aTool, pnslayer, *m_baseLineCoupled, false ) )
1501 {
1502 initBaseLines( router, pnslayer, aBoard );
1503 return false;
1504 }
1505 }
1506 }
1507
1508 hideRemovedItems( true );
1509 // Snap points
1510 VECTOR2I startSnapPoint, endSnapPoint;
1511
1512 wxCHECK( m_baseLine, false );
1513
1514 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, pnslayer, startSnapPoint, *m_baseLine);
1515 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, pnslayer, endSnapPoint, *m_baseLine );
1516
1517 wxASSERT( startItem );
1518 wxASSERT( endItem );
1519
1520 if( !startItem || !endItem )
1521 return false;
1522
1523 router->SetMode( GetPNSMode() );
1524
1525 if( !router->StartRouting( startSnapPoint, startItem, pnslayer ) )
1526 {
1527 //recoverBaseline( router );
1528 return false;
1529 }
1530
1531 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1532
1533 m_settings.m_keepEndpoints = true; // Required for re-grouping
1534 placer->UpdateSettings( m_settings );
1535
1536 router->Move( m_end, nullptr );
1537
1538 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1539 {
1540 m_trackWidth = dpPlacer->GetOriginPair().Width();
1541 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1542 }
1543 else
1544 {
1545 m_trackWidth = startItem->Width();
1546 m_diffPairGap = router->Sizes().DiffPairGap();
1547 }
1548
1549 m_settings = placer->MeanderSettings();
1550 m_lastNetName = iface->GetNetName( startItem->Net() );
1551 m_tuningStatus = placer->TuningStatus();
1552
1553 wxString statusMessage;
1554
1555 switch ( m_tuningStatus )
1556 {
1557 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1558 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1559 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1560 default: statusMessage = _( "unknown" ); break;
1561 }
1562
1563 wxString result;
1564 EDA_UNITS userUnits = EDA_UNITS::MM;
1565
1566 if( aTool->GetManager()->GetSettings() )
1567 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1568
1570 {
1572 (double) placer->TuningLengthResult() );
1573 }
1574 else
1575 {
1577 (double) placer->TuningLengthResult() );
1578 }
1579
1580 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1581
1582 return true;
1583}
1584
1585
1587 const wxString& aCommitMsg, int aCommitFlags )
1588{
1589 if( !( GetFlags() & IN_EDIT ) )
1590 return;
1591
1593
1594 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1595 PNS::ROUTER* router = aTool->Router();
1596 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1597 SHAPE_LINE_CHAIN bounds = getOutline();
1598 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1599
1600 iface->EraseView();
1601
1602 if( router->RoutingInProgress() )
1603 {
1604 bool forceFinish = true;
1605 bool forceCommit = false;
1606
1607 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1608 router->StopRouting();
1609 }
1610
1611 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1612
1613 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1614 {
1615 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1616 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1617
1618 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1619 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1620 // << " m_removedItems " << m_removedItems.size() << std::endl;
1621
1622 for( BOARD_ITEM* item : routerRemovedItems )
1623 {
1624 if( view )
1625 view->Hide( item, false );
1626
1627 aCommit->Remove( item );
1628 }
1629
1630 for( BOARD_ITEM* item : routerAddedItems )
1631 {
1632 aCommit->Add( item );
1633
1634 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1635 {
1636 if( bounds.PointInside( track->GetStart(), epsilon )
1637 && bounds.PointInside( track->GetEnd(), epsilon ) )
1638 {
1639 AddItem( item );
1640 aCommit->Stage( item, CHT_GROUP );
1641 }
1642 }
1643 }
1644 }
1645
1646 if( aCommitMsg.IsEmpty() )
1647 aCommit->Push( _( "Edit Tuning Pattern" ), aCommitFlags );
1648 else
1649 aCommit->Push( aCommitMsg, aCommitFlags );
1650}
1651
1652
1654{
1655 if( !( GetFlags() & IN_EDIT ) )
1656 return;
1657
1659
1660 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1661
1662 iface->EraseView();
1663
1664 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1665 {
1666 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1667 {
1668 for( BOARD_ITEM* item : pnsCommit.removedItems )
1669 view->Hide( item, false );
1670 }
1671 }
1672
1673 aTool->Router()->StopRouting();
1674
1675 if( aCommit )
1676 aCommit->Revert();
1677}
1678
1679
1681{
1682 VECTOR2I centerlineOffset;
1683 VECTOR2I centerlineOffsetEnd;
1684
1685 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1686 {
1687 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1688 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1689 }
1690
1691 aPoints.AddPoint( m_origin + centerlineOffset );
1692 aPoints.AddPoint( m_end + centerlineOffsetEnd );
1693
1694 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1695 : SEG( m_origin, m_end );
1696
1697 base.A += centerlineOffset;
1698 base.B += centerlineOffset;
1699
1700 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1701
1702 if( m_tuningMode == DIFF_PAIR )
1703 amplitude += m_trackWidth + m_diffPairGap;
1704
1705 if( m_settings.m_initialSide == -1 )
1706 amplitude *= -1;
1707
1708 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1709
1710 aPoints.AddPoint( base.A + widthHandleOffset );
1711 aPoints.Point( 2 ).SetGridConstraint( IGNORE_GRID );
1712
1713 VECTOR2I spacingHandleOffset =
1714 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1715
1716 aPoints.AddPoint( base.A + spacingHandleOffset );
1717 aPoints.Point( 3 ).SetGridConstraint( IGNORE_GRID );
1718
1719 return true;
1720}
1721
1722
1724{
1725 VECTOR2I centerlineOffset;
1726 VECTOR2I centerlineOffsetEnd;
1727
1728 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1729 {
1730 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1731 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1732 }
1733
1734 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1735 : SEG( m_origin, m_end );
1736
1737 base.A += centerlineOffset;
1738 base.B += centerlineOffset;
1739
1740 m_origin = aEditPoints.Point( 0 ).GetPosition() - centerlineOffset;
1741 m_end = aEditPoints.Point( 1 ).GetPosition() - centerlineOffsetEnd;
1742
1743 if( aEditPoints.Point( 2 ).IsActive() )
1744 {
1745 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1746
1747 int value = base.LineDistance( wHandle );
1748
1749 value -= KiROUND( m_trackWidth / 2.0 );
1750
1751 if( m_tuningMode == DIFF_PAIR )
1752 value -= m_trackWidth + m_diffPairGap;
1753
1754 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1755
1756 int side = base.Side( wHandle );
1757
1758 if( side < 0 )
1760 else
1762 }
1763
1764 if( aEditPoints.Point( 3 ).IsActive() )
1765 {
1766 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1767 VECTOR2I sHandle = aEditPoints.Point( 3 ).GetPosition();
1768
1769 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1770
1771 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1772 }
1773
1774 return true;
1775}
1776
1777
1779{
1780 VECTOR2I centerlineOffset;
1781 VECTOR2I centerlineOffsetEnd;
1782
1783 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1784 {
1785 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1786 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1787 }
1788
1789 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1790 : SEG( m_origin, m_end );
1791
1792 base.A += centerlineOffset;
1793 base.B += centerlineOffset;
1794
1795 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1796
1797 if( m_tuningMode == DIFF_PAIR )
1798 amplitude += m_trackWidth + m_diffPairGap;
1799
1800 if( m_settings.m_initialSide == -1 )
1801 amplitude *= -1;
1802
1803 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1804
1805 aEditPoints.Point( 0 ).SetPosition( m_origin + centerlineOffset );
1806 aEditPoints.Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1807
1808 aEditPoints.Point( 2 ).SetPosition( base.A + widthHandleOffset );
1809
1810 VECTOR2I spacingHandleOffset =
1811 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1812
1813 aEditPoints.Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1814
1815 return true;
1816}
1817
1818
1820{
1821 if( m_baseLine )
1822 {
1823 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1824 int minAllowedAmplitude = 0;
1825 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1826
1828 {
1829 minAllowedAmplitude = baselineOffset + m_trackWidth;
1830 }
1831 else
1832 {
1833 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1834 minAllowedAmplitude = baselineOffset + correction;
1835 }
1836
1837 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1838
1840 {
1841 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1843
1844 if( m_tuningMode != DIFF_PAIR )
1845 {
1846 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1847
1849
1850 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1851 left, right, true ) )
1852 {
1854 chain.Append( clBase.Reverse() );
1855 chain.SetClosed( true );
1856
1857 return chain;
1858 }
1859 }
1861 {
1862 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1863
1865 SHAPE_LINE_CHAIN chain1, chain2;
1866
1867 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1868 left, right, true ) )
1869 {
1870 if( m_settings.m_initialSide >= 0 )
1871 chain1.Append( right );
1872 else
1873 chain1.Append( left );
1874
1875 if( clBase.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1876 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1877 right, true ) )
1878 {
1879 if( m_settings.m_initialSide >= 0 )
1880 chain1.Append( left.Reverse() );
1881 else
1882 chain1.Append( right.Reverse() );
1883 }
1884
1885 chain1.SetClosed( true );
1886 }
1887
1888 if( clCoupled.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1889 ARC_LOW_DEF, left, right, true ) )
1890 {
1891 if( m_settings.m_initialSide >= 0 )
1892 chain2.Append( right );
1893 else
1894 chain2.Append( left );
1895
1896 if( clCoupled.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1897 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1898 right, true ) )
1899 {
1900 if( m_settings.m_initialSide >= 0 )
1901 chain2.Append( left.Reverse() );
1902 else
1903 chain2.Append( right.Reverse() );
1904 }
1905
1906 chain2.SetClosed( true );
1907 }
1908
1909 SHAPE_POLY_SET merged;
1910 merged.BooleanAdd( chain1, chain2 );
1911
1912 if( merged.OutlineCount() > 0 )
1913 return merged.Outline( 0 );
1914 }
1915 }
1916
1917 // Not single-sided / fallback
1918 SHAPE_POLY_SET poly;
1920
1921 int amplitude = 0;
1922
1923 if( m_tuningMode == DIFF_PAIR )
1924 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1925 else
1926 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1927
1928 poly.OffsetLineChain( *m_baseLine, amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1929 ARC_LOW_DEF, false );
1930
1932 {
1933 SHAPE_POLY_SET polyCoupled;
1934 polyCoupled.OffsetLineChain( *m_baseLineCoupled, amplitude,
1935 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, false );
1936
1937 SHAPE_POLY_SET merged;
1938 merged.BooleanAdd( poly, polyCoupled );
1939
1940 if( merged.OutlineCount() > 0 )
1941 return merged.Outline( 0 );
1942 }
1943
1944 if( poly.OutlineCount() > 0 )
1945 return poly.Outline( 0 );
1946 }
1947
1948 return SHAPE_LINE_CHAIN();
1949}
1950
1951
1952void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1953{
1954 if( !IsSelected() && !IsNew() )
1955 return;
1956
1957 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1958
1959 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1960 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1961
1962 if( !HasFlag( IN_EDIT ) )
1963 {
1964 if( m_baseLine )
1965 {
1966 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1967 {
1968 SEG seg = m_baseLine->CSegment( i );
1969 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1970 }
1971 }
1972 else
1973 {
1974 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1975 }
1976
1978 {
1979 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1980 {
1981 SEG seg = m_baseLineCoupled->CSegment( i );
1982 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1983 }
1984 }
1985 }
1986
1988
1989 for( int i = 0; i < chain.SegmentCount(); i++ )
1990 {
1991 SEG seg = chain.Segment( i );
1992 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1993 }
1994}
1995
1996
1998{
2000
2001 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
2002 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
2003 props.set( "last_status", statusToString( m_tuningStatus ) );
2004 props.set( "is_time_domain", m_settings.m_isTimeDomain );
2005
2006 props.set( "end", m_end );
2007 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
2008 props.set( "single_sided", m_settings.m_singleSided );
2010
2011 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
2012 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
2013 props.set_iu( "min_spacing", m_settings.m_spacing );
2014 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
2015 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
2016 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
2017 props.set_iu( "target_delay_min", m_settings.m_targetLengthDelay.Min() );
2018 props.set_iu( "target_delay", m_settings.m_targetLengthDelay.Opt() );
2019 props.set_iu( "target_delay_max", m_settings.m_targetLengthDelay.Max() );
2020 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
2021 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
2022 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
2023 props.set_iu( "last_track_width", m_trackWidth );
2024 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
2025
2026 props.set( "last_netname", m_lastNetName );
2027 props.set( "last_tuning", m_tuningInfo );
2028 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
2029
2030 if( m_baseLine )
2031 props.set( "base_line", wxAny( *m_baseLine ) );
2032
2033 if( m_baseLineCoupled )
2034 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
2035
2036 return props;
2037}
2038
2039
2041{
2043
2044 wxString tuningMode;
2045 aProps.get_to( "tuning_mode", tuningMode );
2046 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
2047
2048 wxString side;
2049 aProps.get_to( "initial_side", side );
2050 m_settings.m_initialSide = sideFromString( side.utf8_string() );
2051
2052 wxString status;
2053 aProps.get_to( "last_status", status );
2054 m_tuningStatus = statusFromString( status.utf8_string() );
2055
2056 aProps.get_to( "is_time_domain", m_settings.m_isTimeDomain );
2057
2058 aProps.get_to( "end", m_end );
2059 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
2060 aProps.get_to( "single_sided", m_settings.m_singleSided );
2061 aProps.get_to( "side", m_settings.m_initialSide );
2062
2063 bool rounded = false;
2064 aProps.get_to( "rounded", rounded );
2066
2067 long long int val;
2068
2069 aProps.get_to_iu( "target_length", val );
2071
2072 if( aProps.get_to_iu( "target_length_min", val ) )
2074
2075 if( aProps.get_to_iu( "target_length_max", val ) )
2077
2078 aProps.get_to_iu( "target_delay", val );
2080
2081 if( aProps.get_to_iu( "target_delay_min", val ) )
2083
2084 if( aProps.get_to_iu( "target_delay_max", val ) )
2086
2087 int int_val;
2088
2089 aProps.get_to_iu( "target_skew", int_val );
2090 m_settings.SetTargetSkew( int_val );
2091
2092 if( aProps.get_to_iu( "target_skew_min", int_val ) )
2093 m_settings.m_targetSkew.SetMin( int_val );
2094
2095 if( aProps.get_to_iu( "target_skew_max", int_val ) )
2096 m_settings.m_targetSkew.SetMax( int_val );
2097
2098 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
2099 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
2100 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
2101 aProps.get_to_iu( "last_track_width", m_trackWidth );
2102 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
2103 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
2104
2105 aProps.get_to( "last_netname", m_lastNetName );
2106 aProps.get_to( "last_tuning", m_tuningInfo );
2107
2108 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
2109 m_baseLine = *baseLine;
2110
2111 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
2112 m_baseLineCoupled = *baseLineCoupled;
2113}
2114
2115
2117{
2119 DRC_CONSTRAINT constraint;
2120
2121 if( !m_items.empty() )
2122 {
2123 BOARD_ITEM* startItem = static_cast<BOARD_ITEM*>( *m_items.begin() );
2124 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
2125
2127 {
2128 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, startItem, nullptr, GetLayer() );
2129
2130 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
2131 {
2133 {
2134 settings.SetTargetLengthDelay( constraint.GetValue() );
2135 settings.SetTargetLength( MINOPTMAX<int>() );
2136 settings.m_isTimeDomain = true;
2137 }
2138 else
2139 {
2141 settings.SetTargetLength( constraint.GetValue() );
2142 settings.m_isTimeDomain = false;
2143 }
2144 }
2145 }
2146 else
2147 {
2148 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
2149
2150 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
2151 {
2153 {
2154 settings.SetTargetLengthDelay( constraint.GetValue() );
2155 settings.SetTargetLength( MINOPTMAX<int>() );
2156 settings.m_isTimeDomain = true;
2157 }
2158 else
2159 {
2161 settings.SetTargetLength( constraint.GetValue() );
2162 settings.m_isTimeDomain = false;
2163 }
2164 }
2165 }
2166 }
2167
2168 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
2169
2170 if( dlg.ShowModal() == wxID_OK )
2171 {
2172 BOARD_COMMIT commit( aEditFrame );
2173 commit.Modify( this );
2174 m_settings = settings;
2175
2176 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
2177 EditStart( generatorTool, GetBoard(), &commit );
2178 Update( generatorTool, GetBoard(), &commit );
2179 EditPush( generatorTool, GetBoard(), &commit );
2180 }
2181}
2182
2183
2185 PCB_BASE_EDIT_FRAME* aFrame,
2186 bool aStatusItemsOnly )
2187{
2188 std::vector<EDA_ITEM*> previewItems;
2189 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
2190
2191 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
2192 {
2193 if( !aStatusItemsOnly )
2194 {
2195 PNS::ITEM_SET items = placer->TunedPath();
2196
2197 for( PNS::ITEM* item : items )
2198 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item,
2199 aTool->Router()->GetInterface(),
2200 view, PNS_HOVER_ITEM ) );
2201 }
2202
2203 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
2204
2206 {
2209 else
2211 }
2212 else
2213 {
2215 {
2217 {
2218 statusItem->ClearMinMax();
2219 }
2220 else
2221 {
2222 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLengthDelay.Min() ),
2223 static_cast<double>( m_settings.m_targetLengthDelay.Max() ) );
2224 }
2225 }
2226 else
2227 {
2229 {
2230 statusItem->ClearMinMax();
2231 }
2232 else
2233 {
2234 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLength.Min() ),
2235 static_cast<double>( m_settings.m_targetLength.Max() ) );
2236 }
2237 }
2238 }
2239
2241
2243 {
2245 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current skew" ) );
2246 else
2247 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current skew" ) );
2248 }
2249 else
2250 {
2252 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current delay" ) );
2253 else
2254 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current length" ) );
2255 }
2256
2257 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
2258 previewItems.push_back( statusItem );
2259 }
2260
2261 return previewItems;
2262}
2263
2264
2266 std::vector<MSG_PANEL_ITEM>& aList )
2267{
2268 wxString msg;
2269 NETINFO_ITEM* primaryNet = nullptr;
2270 NETINFO_ITEM* coupledNet = nullptr;
2271 PCB_TRACK* primaryItem = nullptr;
2272 PCB_TRACK* coupledItem = nullptr;
2273 NETCLASS* netclass = nullptr;
2274 int width = 0;
2275 bool mixedWidth = false;
2276
2277 EDA_DATA_TYPE unitType = m_settings.m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
2278
2279 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2280
2281 for( EDA_ITEM* member : GetItems() )
2282 {
2283 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
2284 {
2285 if( !primaryNet )
2286 {
2287 primaryItem = track;
2288 primaryNet = track->GetNet();
2289 }
2290 else if( !coupledNet && track->GetNet() != primaryNet )
2291 {
2292 coupledItem = track;
2293 coupledNet = track->GetNet();
2294 }
2295
2296 if( !netclass )
2297 netclass = track->GetEffectiveNetClass();
2298
2299 if( !width )
2300 width = track->GetWidth();
2301 else if( width != track->GetWidth() )
2302 mixedWidth = true;
2303 }
2304 }
2305
2306 if( coupledNet )
2307 {
2308 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2309 + wxS( ", " )
2310 + UnescapeString( coupledNet->GetNetname() ) );
2311 }
2312 else if( primaryNet )
2313 {
2314 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2315 }
2316
2317 if( netclass )
2318 aList.emplace_back( _( "Resolved Netclass" ),
2319 UnescapeString( netclass->GetHumanReadableName() ) );
2320
2321 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
2322
2323 if( width && !mixedWidth )
2324 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2325
2326 BOARD* board = GetBoard();
2327 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2328 DRC_CONSTRAINT constraint;
2329
2330 // Display full track length (in Pcbnew)
2331 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2332 {
2333 int count = 0;
2334 double trackLen = 0.0;
2335 double lenPadToDie = 0.0;
2336 double trackDelay = 0.0;
2337 double delayPadToDie = 0.0;
2338
2339 std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *primaryItem );
2340
2341 if( coupledItem && coupledItem->GetNetCode() > 0 )
2342 {
2343 double coupledLen = 0.0;
2344 double coupledLenPadToDie = 0.0;
2345 double coupledTrackDelay = 0.0;
2346 double doubledDelayPadToDie = 0.0;
2347
2348 std::tie( count, coupledLen, coupledLenPadToDie, coupledTrackDelay, doubledDelayPadToDie ) =
2349 board->GetTrackLength( *coupledItem );
2350
2351 if( trackDelay == 0.0 || coupledTrackDelay == 0.0 )
2352 {
2353 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen ) + wxS( ", " )
2354 + aFrame->MessageTextFromValue( coupledLen ) );
2355 }
2356 else
2357 {
2358 aList.emplace_back(
2359 _( "Routed Delays" ),
2360 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) + wxS( ", " )
2361 + aFrame->MessageTextFromValue( coupledTrackDelay, true, EDA_DATA_TYPE::TIME ) );
2362 }
2363 }
2364 else
2365 {
2366 if( trackDelay == 0.0 )
2367 {
2368 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2369 }
2370 else
2371 {
2372 aList.emplace_back( _( "Routed Delay" ),
2373 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) );
2374 }
2375 }
2376
2377 if( lenPadToDie != 0 && delayPadToDie == 0.0 )
2378 {
2379 msg = aFrame->MessageTextFromValue( lenPadToDie );
2380 aList.emplace_back( _( "Pad To Die Length" ), msg );
2381
2382 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2383 aList.emplace_back( _( "Full Length" ), msg );
2384 }
2385 else if( delayPadToDie > 0.0 )
2386 {
2387 msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME );
2388 aList.emplace_back( _( "Pad To Die Delay" ), msg );
2389
2390 msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME );
2391 aList.emplace_back( _( "Full Delay" ), msg );
2392 }
2393 }
2394
2396 {
2397 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2398
2399 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2400 {
2402
2403 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2404 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2405 }
2406 else
2407 {
2408 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2409
2410 if( !msg.IsEmpty() )
2411 {
2412 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2413 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2414 }
2415 }
2416 }
2417 else
2418 {
2419 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2420
2421 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2422 {
2423 wxString caption;
2424
2426 {
2427 caption = _( "Target Delay: %s" );
2428 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLengthDelay.Opt() ), true,
2429 EDA_DATA_TYPE::TIME );
2430 }
2431 else
2432 {
2433 caption = _( "Target Length: %s" );
2434 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLength.Opt() ) );
2435 }
2436
2437 aList.emplace_back( wxString::Format( caption, msg ),
2438 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2439 }
2440 else
2441 {
2442 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue(), unitType );
2443
2444 wxString caption = m_settings.m_isTimeDomain ? _( "Delay Constraints: %s" ) : _( "Length Constraints: %s" );
2445
2446 if( !msg.IsEmpty() )
2447 {
2448 aList.emplace_back( wxString::Format( caption, msg ),
2449 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2450 }
2451 }
2452 }
2453}
2454
2455
2456const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2457const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2458
2459
2461
2462
2463#define HITTEST_THRESHOLD_PIXELS 5
2464
2465
2467{
2468 // TODO: (JJ) Reserving before v9 string freeze
2469 wxLogDebug( _( "Tune Skew" ) );
2470
2472 return 0;
2473
2474 if( m_inDrawingTool )
2475 return 0;
2476
2478
2480
2481 m_frame->PushTool( aEvent );
2482 Activate();
2483
2486 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
2487 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2488 PNS::ROUTER* router = generatorTool->Router();
2489 PNS::ROUTER_MODE routerMode = aEvent.Parameter<PNS::ROUTER_MODE>();
2490 LENGTH_TUNING_MODE mode = fromPNSMode( routerMode );
2491 PNS::MEANDER_SETTINGS meanderSettings;
2492
2493 switch( mode )
2494 {
2495 case LENGTH_TUNING_MODE::SINGLE: meanderSettings = bds.m_SingleTrackMeanderSettings; break;
2496 case DIFF_PAIR: meanderSettings = bds.m_DiffPairMeanderSettings; break;
2497 case DIFF_PAIR_SKEW: meanderSettings = bds.m_SkewMeanderSettings; break;
2498 }
2499
2503 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2504
2505 m_pickerItem = nullptr;
2506 m_tuningPattern = nullptr;
2507
2508 // Add a VIEW_GROUP that serves as a preview for the new item
2509 m_preview.Clear();
2510 m_view->Add( &m_preview );
2511
2512 auto setCursor =
2513 [&]()
2514 {
2515 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
2516 controls->ShowCursor( true );
2517 };
2518
2519 auto applyCommonSettings =
2520 [&]( PCB_TUNING_PATTERN* aPattern )
2521 {
2522 const auto& origTargetLength = aPattern->GetSettings().m_targetLength;
2523 const auto& origTargetSkew = aPattern->GetSettings().m_targetSkew;
2524
2525 aPattern->GetSettings() = meanderSettings;
2526
2527 if( meanderSettings.m_targetLength.IsNull() )
2528 aPattern->GetSettings().m_targetLength = origTargetLength;
2529
2530 if( meanderSettings.m_targetSkew.IsNull() )
2531 aPattern->GetSettings().m_targetSkew = origTargetSkew;
2532 };
2533
2534 auto updateHoverStatus =
2535 [&]()
2536 {
2537 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2538
2539 if( m_pickerItem )
2540 {
2541 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2542 m_pickerItem, mode ) );
2543 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2544 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2545 }
2546
2547 if( dummyPattern )
2548 {
2549 applyCommonSettings( dummyPattern.get() );
2550
2551 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2552 dummyPattern->Update( generatorTool, m_board, nullptr );
2553
2555
2556 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2557 m_preview.Add( item );
2558
2559 generatorTool->Router()->StopRouting();
2560
2561 m_view->Update( &m_preview );
2562 }
2563 else
2564 {
2565
2567 m_view->Update( &m_preview );
2568 }
2569 };
2570
2571 auto updateTuningPattern =
2572 [&]()
2573 {
2575 {
2576 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2577 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2578
2580
2581 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame, true ) )
2582 m_preview.Add( item );
2583
2584 m_view->Update( &m_preview );
2585 }
2586 };
2587
2588 // Set initial cursor
2589 setCursor();
2590
2591 while( TOOL_EVENT* evt = Wait() )
2592 {
2593 setCursor();
2594 VECTOR2D cursorPos = controls->GetMousePosition();
2595
2596 if( evt->IsCancelInteractive() || evt->IsActivate()
2597 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2598 {
2599 if( m_tuningPattern )
2600 {
2601 // First click already made; clean up tuning pattern preview
2602 m_tuningPattern->EditRevert( generatorTool, m_board, nullptr );
2603
2604 delete m_tuningPattern;
2605 m_tuningPattern = nullptr;
2606 }
2607 else
2608 {
2609 break;
2610 }
2611 }
2612 else if( evt->IsMotion() )
2613 {
2614 if( !m_tuningPattern )
2615 {
2616 // First click not yet made; we're in highlight-net-under-cursor mode
2617
2618 GENERAL_COLLECTOR collector;
2619 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2620
2621 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2622 guide.SetIncludeSecondary( false );
2623 else
2624 guide.SetIncludeSecondary( true );
2625
2626 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2627
2628 if( collector.GetCount() > 1 )
2629 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2630
2631 m_pickerItem = nullptr;
2632
2633 if( collector.GetCount() > 0 )
2634 {
2635 double min_dist_sq = std::numeric_limits<double>::max();
2636
2637 for( EDA_ITEM* candidate : collector )
2638 {
2639 VECTOR2I candidatePos;
2640
2641 if( candidate->Type() == PCB_TRACE_T )
2642 {
2643 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2644 }
2645 else if( candidate->Type() == PCB_ARC_T )
2646 {
2647 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2648 }
2649
2650 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2651
2652 if( dist_sq < min_dist_sq )
2653 {
2654 min_dist_sq = dist_sq;
2655 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2656 }
2657 }
2658 }
2659
2660 updateHoverStatus();
2661 }
2662 else
2663 {
2664 // First click already made; we're in preview-tuning-pattern mode
2665
2666 m_tuningPattern->SetEnd( cursorPos );
2668
2669 updateTuningPattern();
2670 }
2671 }
2672 else if( evt->IsClick( BUT_LEFT ) )
2673 {
2675 {
2676 // First click; create a tuning pattern
2677
2678 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2679 {
2680 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2681 "tuning patterns." ) );
2682 }
2683 else
2684 {
2686
2689 m_pickerItem, mode );
2690
2691 applyCommonSettings( m_tuningPattern );
2692
2693 int dummyDist;
2694 int dummyClearance = std::numeric_limits<int>::max() / 2;
2695 VECTOR2I closestPt;
2696
2697 // With an artificially-large clearance this can't *not* collide, but the
2698 // if stmt keeps Coverity happy....
2699 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2700 &dummyDist, &closestPt ) )
2701 {
2702 m_tuningPattern->SetPosition( closestPt );
2703 m_tuningPattern->SetEnd( closestPt );
2704 }
2705
2707 }
2708 }
2709 else if( m_pickerItem && m_tuningPattern )
2710 {
2711 // Second click; we're done
2712 BOARD_COMMIT commit( m_frame );
2713
2714 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2715 m_tuningPattern->Update( generatorTool, m_board, &commit );
2716 m_tuningPattern->EditPush( generatorTool, m_board, &commit, _( "Tune" ) );
2717
2718 m_tuningPattern = nullptr;
2719 m_pickerItem = nullptr;
2720 }
2721 }
2722 else if( evt->IsClick( BUT_RIGHT ) )
2723 {
2725 m_menu->ShowContextMenu( dummy );
2726 }
2727 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2728 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2729 {
2730 if( m_tuningPattern )
2731 {
2732 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2733
2734 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2735 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2736 meanderSettings.m_spacing = placer->MeanderSettings().m_spacing;
2737
2738 updateTuningPattern();
2739 }
2740 else
2741 {
2742 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2743 }
2744 }
2745 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2746 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2747 {
2748 if( m_tuningPattern )
2749 {
2750 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2751
2752 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2753 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2754 meanderSettings.m_maxAmplitude = placer->MeanderSettings().m_maxAmplitude;
2755
2756 updateTuningPattern();
2757 }
2758 else
2759 {
2760 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2761 }
2762 }
2763 else if( evt->IsAction( &PCB_ACTIONS::properties )
2764 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2765 {
2766 DRC_CONSTRAINT constraint;
2767
2768 if( m_tuningPattern )
2769 {
2770 if( !m_tuningPattern->GetItems().empty() )
2771 {
2772 BOARD_ITEM* startItem = *m_tuningPattern->GetBoardItems().begin();
2773
2774 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2775 startItem->GetLayer() );
2776 }
2777 }
2778
2779 DIALOG_TUNING_PATTERN_PROPERTIES dlg( m_frame, meanderSettings, routerMode, constraint );
2780
2781 if( dlg.ShowModal() == wxID_OK )
2782 {
2783 if( m_tuningPattern )
2784 applyCommonSettings( m_tuningPattern );
2785
2786 updateTuningPattern();
2787 }
2788 }
2789 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2790 // but we don't at present have that, so we just knock out some of the egregious ones.
2791 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2792 {
2793 wxBell();
2794 }
2795 else
2796 {
2797 evt->SetPassEvent();
2798 }
2799
2800 controls->CaptureCursor( m_tuningPattern != nullptr );
2801 controls->SetAutoPan( m_tuningPattern != nullptr );
2802 }
2803
2804 controls->CaptureCursor( false );
2805 controls->SetAutoPan( false );
2806 controls->ForceCursorPosition( false );
2807 controls->ShowCursor( false );
2808 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2809
2811 m_view->Remove( &m_preview );
2812
2814
2815 if( m_tuningPattern )
2816 selectionTool->AddItemToSel( m_tuningPattern );
2817
2818 m_frame->PopTool( aEvent );
2819 return 0;
2820}
2821
2822
2824{
2826 {
2828 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2829 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2830 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2831
2833 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2834 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2835 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2836
2843
2844 const wxString groupTab = _HKI( "Pattern Properties" );
2845
2847 _HKI( "End X" ), &PCB_TUNING_PATTERN::SetEndX,
2848 &PCB_TUNING_PATTERN::GetEndX, PROPERTY_DISPLAY::PT_SIZE,
2850 groupTab );
2851
2853 _HKI( "End Y" ), &PCB_TUNING_PATTERN::SetEndY,
2854 &PCB_TUNING_PATTERN::GetEndY, PROPERTY_DISPLAY::PT_SIZE,
2856 groupTab );
2857
2859 _HKI( "Tuning Mode" ),
2862 groupTab );
2863
2865 _HKI( "Min Amplitude" ),
2868 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2869 groupTab );
2870
2872 _HKI( "Max Amplitude" ),
2875 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2876 groupTab );
2877
2879 _HKI( "Initial Side" ),
2882 groupTab );
2883
2885 _HKI( "Min Spacing" ), &PCB_TUNING_PATTERN::SetSpacing,
2886 &PCB_TUNING_PATTERN::GetSpacing, PROPERTY_DISPLAY::PT_SIZE,
2888 groupTab );
2889
2891 _HKI( "Corner Radius %" ),
2894 PROPERTY_DISPLAY::PT_DEFAULT, ORIGIN_TRANSFORMS::NOT_A_COORD ),
2895 groupTab );
2896
2897 auto isSkew =
2898 []( INSPECTABLE* aItem ) -> bool
2899 {
2900 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2901 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2902
2903 return false;
2904 };
2905
2906 auto isTimeDomain = []( INSPECTABLE* aItem ) -> bool
2907 {
2908 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2909 return pattern->GetSettings().m_isTimeDomain;
2910
2911 return false;
2912 };
2913
2914 auto isLengthIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2915 {
2916 return !isSkew( aItem ) && !isTimeDomain( aItem );
2917 };
2918
2919 auto isLengthIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2920 {
2921 return !isSkew( aItem ) && isTimeDomain( aItem );
2922 };
2923
2924 auto isSkewIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2925 {
2926 return isSkew( aItem ) && !isTimeDomain( aItem );
2927 };
2928
2929 auto isSkewIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2930 {
2931 return isSkew( aItem ) && isTimeDomain( aItem );
2932 };
2933
2934 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2935 _HKI( "Target Length" ), &PCB_TUNING_PATTERN::SetTargetLength,
2936 &PCB_TUNING_PATTERN::GetTargetLength, PROPERTY_DISPLAY::PT_SIZE,
2938 groupTab )
2939 .SetAvailableFunc( isLengthIsSpaceDomain );
2940
2941 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2942 _HKI( "Target Delay" ), &PCB_TUNING_PATTERN::SetTargetDelay,
2943 &PCB_TUNING_PATTERN::GetTargetDelay, PROPERTY_DISPLAY::PT_TIME,
2945 groupTab )
2946 .SetAvailableFunc( isLengthIsTimeDomain );
2947
2949 _HKI( "Target Skew" ), &PCB_TUNING_PATTERN::SetTargetSkew,
2950 &PCB_TUNING_PATTERN::GetTargetSkew, PROPERTY_DISPLAY::PT_SIZE,
2952 groupTab )
2953 .SetAvailableFunc( isSkewIsSpaceDomain );
2954
2956 _HKI( "Target Skew Delay" ), &PCB_TUNING_PATTERN::SetTargetSkewDelay,
2957 &PCB_TUNING_PATTERN::GetTargetSkewDelay, PROPERTY_DISPLAY::PT_TIME,
2959 groupTab )
2960 .SetAvailableFunc( isSkewIsTimeDomain );
2961
2963 _HKI( "Override Custom Rules" ),
2966 groupTab );
2967
2969 _HKI( "Single-sided" ),
2972 groupTab );
2973
2975 _HKI( "Rounded" ), &PCB_TUNING_PATTERN::SetRounded,
2977 groupTab );
2978 }
2980
2983
2985
2986// Also register under the 7.99 name
2987template <typename T>
2989{
2991 {
2992 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2993 []()
2994 {
2995 return new T;
2996 } );
2997 }
2998};
2999
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:110
constexpr int ARC_LOW_DEF
Definition: base_units.h:121
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static TOOL_ACTION undo
Definition: actions.h:75
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:220
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
Add a change of the item aItem of type aChangeType to the change list.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int GetDRCEpsilon() const
Return an epsilon which accounts for rounding errors, etc.
PNS::MEANDER_SETTINGS m_DiffPairMeanderSettings
PNS::MEANDER_SETTINGS m_SingleTrackMeanderSettings
PNS::MEANDER_SETTINGS m_SkewMeanderSettings
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:78
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:229
PCB_LAYER_ID m_layer
Definition: board_item.h:445
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:279
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:48
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:167
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:297
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition: board.cpp:2091
std::tuple< int, double, double, double, double > GetTrackLength(const PCB_TRACK &aTrack) const
Return data on the length and number of track segments connected to a given track.
Definition: board.cpp:2395
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:2020
const TRACKS & Tracks() const
Definition: board.h:336
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:955
constexpr void SetMaximum()
Definition: box2.h:80
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:311
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:82
int m_Threshold
Definition: collector.h:235
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:92
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Definition: commit.h:108
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:80
int ShowModal() override
PCB_SELECTION m_preview
Definition: drawing_tool.h:395
KIGFX::VIEW * m_view
Definition: drawing_tool.h:384
BOARD_CONNECTED_ITEM * m_pickerItem
Definition: drawing_tool.h:396
bool m_inDrawingTool
Definition: drawing_tool.h:389
int PlaceTuningPattern(const TOOL_EVENT &aEvent)
BOARD * m_board
Definition: drawing_tool.h:386
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:387
PCB_TUNING_PATTERN * m_tuningPattern
Definition: drawing_tool.h:397
wxString GetName() const
Definition: drc_rule.h:165
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:157
bool GetOption(OPTIONS option) const
Definition: drc_rule.h:190
bool IsNull() const
Definition: drc_rule.h:152
void ShowInfoBarWarning(const wxString &aWarningMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and a warning icon on the left ...
The base class for create windows for drawing purpose.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
wxString m_name
Definition: eda_group.h:92
std::unordered_set< EDA_ITEM * > m_items
Definition: eda_group.h:91
std::unordered_set< EDA_ITEM * > & GetItems()
Definition: eda_group.h:54
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:96
virtual const VECTOR2I GetFocusPosition() const
Similar to GetPosition() but allows items to return their visual center rather than their anchor.
Definition: eda_item.h:263
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:138
virtual EDA_GROUP * GetParentGroup() const
Definition: eda_item.h:114
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:108
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:140
bool IsSelected() const
Definition: eda_item.h:123
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:142
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:141
bool IsNew() const
Definition: eda_item.h:120
EDIT_POINTS is a VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them.
Definition: edit_points.h:353
void AddPoint(const EDIT_POINT &aPoint)
Add an EDIT_POINT.
Definition: edit_points.h:390
EDIT_POINT & Point(unsigned int aIndex)
Definition: edit_points.h:511
void SetGridConstraint(GRID_CONSTRAINT_TYPE aConstraint)
Definition: edit_points.h:179
bool IsActive() const
Definition: edit_points.h:172
static const int POINT_SIZE
Single point size in pixels.
Definition: edit_points.h:190
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
Definition: edit_points.h:107
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:71
static ENUM_MAP< T > & Instance()
Definition: property.h:681
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:348
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:319
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:202
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:482
A factory which returns an instance of a PCB_GENERATOR.
void Register(const wxString &aTypeStr, const wxString &aName, std::function< PCB_GENERATOR *(void)> aCreateFunc)
Associate a type string to display name and create function.
static GENERATORS_MGR & Instance()
const std::vector< GENERATOR_PNS_CHANGES > & GetRouterChanges()
Handle actions specific to filling copper zones.
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:37
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:131
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition: font.cpp:147
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics) const
Draw a string.
Definition: font.cpp:250
static const METRICS & Default()
Definition: font.cpp:52
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:311
void ToHSL(double &aOutHue, double &aOutSaturation, double &aOutLightness) const
Converts current color (stored in RGB) to HSL format.
Definition: color4d.cpp:296
Abstract interface for drawing on a 2D-surface.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
virtual void Restore()
Restore the context.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
virtual void Scale(const VECTOR2D &aScale)
Scale the context.
virtual void Save()
Save the context.
A KIGFX::PREVIEW::DRAW_CONTEXT is a wrapper around a GAL and some other settings that makes it easy t...
Definition: draw_context.h:45
void DrawLineDashed(const VECTOR2I &aStart, const VECTOR2I &aEn, int aDashStep, int aDashFill, bool aDeEmphasised)
Draw a dashed line on the current layer.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
void FreeItems()
Free all the items that were added to the group.
Definition: view_group.cpp:211
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:297
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:332
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1673
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:198
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:457
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1621
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition: matrix3x3.h:295
T Min() const
Definition: minoptmax.h:33
void SetMin(T v)
Definition: minoptmax.h:41
void SetMax(T v)
Definition: minoptmax.h:42
T Max() const
Definition: minoptmax.h:34
bool IsNull() const
Definition: minoptmax.h:45
T Opt() const
Definition: minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:45
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition: netclass.cpp:288
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:163
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:195
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:196
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:197
static TOOL_ACTION lengthTunerSettings
Definition: pcb_actions.h:198
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:194
const VECTOR2I & GetMid() const
Definition: pcb_track.h:344
Common, abstract interface for edit frames.
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
virtual void SetProperties(const STRING_ANY_MAP &aProps)
void baseMirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
wxString m_generatorType
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aMirrorDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
VECTOR2I m_origin
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_generator.h:82
VECTOR2I GetPosition() const override
Definition: pcb_generator.h:81
virtual std::vector< std::pair< wxString, wxVariant > > GetRowData()
virtual const STRING_ANY_MAP GetProperties() const
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_group.cpp:390
std::unordered_set< BOARD_ITEM * > GetBoardItems() const
Definition: pcb_group.cpp:122
bool AddItem(EDA_ITEM *aItem) override
Add item to group.
Definition: pcb_group.cpp:81
The selection tool: currently supports:
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
bool m_isFootprintEditor
const VECTOR2I & GetStart() const
Definition: pcb_track.h:152
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:149
virtual int GetWidth() const
Definition: pcb_track.h:146
void SetTargetSkew(int aValue)
void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
bool initBaseLines(PNS::ROUTER *aRouter, int aPNSLayer, BOARD *aBoard)
const STRING_ANY_MAP GetProperties() const override
bool HitTest(const BOX2I &aRect, bool aContained, int aAccuracy) const override
Test if aRect intersects this item.
void SetEnd(const VECTOR2I &aValue)
void SetMinAmplitude(int aValue)
void SetSpacing(int aValue)
wxString GetGeneratorType() const override
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
static const wxString DISPLAY_NAME
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
PNS::ROUTER_MODE GetPNSMode()
bool initBaseLine(PNS::ROUTER *aRouter, int aPNSLayer, BOARD *aBoard, VECTOR2I &aStart, VECTOR2I &aEnd, NETINFO_ITEM *aNet, std::optional< SHAPE_LINE_CHAIN > &aBaseLine)
void SetTargetSkewDelay(int aValue)
PCB_TUNING_PATTERN(BOARD_ITEM *aParent=nullptr, PCB_LAYER_ID aLayer=F_Cu, LENGTH_TUNING_MODE aMode=LENGTH_TUNING_MODE::SINGLE)
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
void swapData(BOARD_ITEM *aImage) override
bool recoverBaseline(PNS::ROUTER *aRouter)
void EditRevert(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
PNS::MEANDER_SIDE GetInitialSide() const
const VECTOR2I & GetEnd() const
void SetInitialSide(PNS::MEANDER_SIDE aValue)
wxString GetFriendlyName() const override
void SetTargetDelay(std::optional< int > aValue)
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
LENGTH_TUNING_MODE GetTuningMode() const
std::optional< int > GetTargetDelay() const
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
std::vector< EDA_ITEM * > GetPreviewItems(GENERATOR_TOOL *aTool, PCB_BASE_EDIT_FRAME *aFrame, bool aStatusItemsOnly=false) override
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void EditStart(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
void baseMirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void SetOverrideCustomRules(bool aOverride)
void SetRounded(bool aFlag)
LENGTH_TUNING_MODE m_tuningMode
std::vector< std::pair< wxString, wxVariant > > GetRowData() override
static const wxString GENERATOR_TYPE
bool resetToBaseline(GENERATOR_TOOL *aTool, int aPNSLayer, SHAPE_LINE_CHAIN &aBaseLine, bool aPrimary)
bool MakeEditPoints(EDIT_POINTS &points) const override
void SetCornerRadiusPercentage(int aValue)
PNS::MEANDER_PLACER_BASE::TUNING_STATUS m_tuningStatus
std::optional< SHAPE_LINE_CHAIN > m_baseLineCoupled
void SetProperties(const STRING_ANY_MAP &aProps) override
wxString GetPluralName() const override
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override final
Draw the parts of the object belonging to layer aLayer.
void Remove(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool UpdateFromEditPoints(EDIT_POINTS &aEditPoints) override
std::optional< SHAPE_LINE_CHAIN > m_baseLine
PNS::MEANDER_SETTINGS m_settings
void SetEndX(int aValue)
void ShowPropertiesDialog(PCB_BASE_EDIT_FRAME *aEditFrame) override
bool Update(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool UpdateEditPoints(EDIT_POINTS &aEditPoints) override
bool GetOverrideCustomRules() const
void SetMaxAmplitude(int aValue)
void EditPush(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit, const wxString &aCommitMsg=wxEmptyString, int aCommitFlags=0) override
PNS::MEANDER_SETTINGS & GetSettings()
void SetSingleSided(bool aValue)
bool removeToBaseline(PNS::ROUTER *aRouter, int aPNSLayer, SHAPE_LINE_CHAIN &aBaseLine)
std::optional< int > GetTargetLength() const
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
int GetCornerRadiusPercentage() const
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
SHAPE_LINE_CHAIN getOutline() const
void SetEndY(int aValue)
void SetTargetLength(std::optional< int > aValue)
static PCB_TUNING_PATTERN * CreateNew(GENERATOR_TOOL *aTool, PCB_BASE_EDIT_FRAME *aFrame, BOARD_CONNECTED_ITEM *aStartItem, LENGTH_TUNING_MODE aMode)
SHAPE_ARC & Arc()
Definition: pns_arc.h:115
Differential Pair length-matching/meandering tool.
std::vector< ITEM * > & Items()
Definition: pns_itemset.h:87
Base class for PNS router board items.
Definition: pns_item.h:98
virtual NET_HANDLE Net() const
Definition: pns_item.h:210
void SetNet(NET_HANDLE aNet)
Definition: pns_item.h:209
void SetLayer(int aLayer)
Definition: pns_item.h:215
@ SEGMENT_T
Definition: pns_item.h:107
void SetParent(BOARD_ITEM *aParent)
Definition: pns_item.h:191
bool OfKind(int aKindMask) const
Definition: pns_item.h:181
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:268
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition: pns_line.h:62
const SHAPE_LINE_CHAIN & CLine() const
Definition: pns_line.h:138
SHAPE_LINE_CHAIN & Line()
Definition: pns_line.h:137
void SetWidth(int aWidth)
Return line width.
Definition: pns_line.h:150
virtual int Width() const
Base class for Single trace & Differential pair meandering tools, as both of them share a lot of code...
virtual void UpdateSettings(const MEANDER_SETTINGS &aSettings)
TUNING_STATUS
< Result of the length tuning operation
virtual void SpacingStep(int aSign)
Increase/decrease the current meandering spacing by one step.
virtual TUNING_STATUS TuningStatus() const =0
Return the tuning status (too short, too long, etc.) of the trace(s) being tuned.
virtual const MEANDER_SETTINGS & MeanderSettings() const
Return the current meandering configuration.
virtual void AmplitudeStep(int aSign)
Increase/decreases the current meandering amplitude by one step.
virtual long long int TuningLengthResult() const =0
Return the resultant length or skew of the tuned traces.
Dimensions for the meandering algorithm.
Definition: pns_meander.h:68
int m_minAmplitude
Maximum meandering amplitude.
Definition: pns_meander.h:93
void SetTargetLength(long long int aOpt)
Definition: pns_meander.cpp:63
bool m_isTimeDomain
The net class this meander pattern belongs to.
Definition: pns_meander.h:140
static const long long int LENGTH_UNCONSTRAINED
Definition: pns_meander.h:71
int m_cornerRadiusPercentage
Place meanders on one side.
Definition: pns_meander.h:125
MEANDER_SIDE m_initialSide
Allowable tuning error.
Definition: pns_meander.h:131
bool m_singleSided
Initial side when placing meanders at segment.
Definition: pns_meander.h:128
void SetTargetLengthDelay(long long int aOpt)
Definition: pns_meander.cpp:92
MINOPTMAX< long long int > m_targetLength
Desired propagation delay of the tuned line.
Definition: pns_meander.h:108
void SetTargetSkew(int aOpt)
MINOPTMAX< int > m_targetSkew
Target skew value for diff pair de-skewing.
Definition: pns_meander.h:114
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
Definition: pns_meander.h:122
bool m_keepEndpoints
Calculate tuning in the time domain.
Definition: pns_meander.h:137
MINOPTMAX< int > m_targetSkewDelay
Definition: pns_meander.h:117
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition: pns_meander.h:96
bool m_overrideCustomRules
Type of corners for the meandered line.
Definition: pns_meander.h:119
MINOPTMAX< long long int > m_targetLengthDelay
Target skew value for diff pair de-skewing.
Definition: pns_meander.h:111
void SetTargetSkewDelay(int aOpt)
static const long long int DELAY_UNCONSTRAINED
Definition: pns_meander.h:74
int m_spacing
Amplitude/spacing adjustment step.
Definition: pns_meander.h:99
Keep the router "world" - i.e.
Definition: pns_node.h:232
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition: pns_node.cpp:143
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition: pns_node.cpp:665
std::set< OBSTACLE > OBSTACLES
Definition: pns_node.h:244
const LINE AssembleLine(LINKED_ITEM *aSeg, int *aOriginSegmentIndex=nullptr, bool aStopAtLockedJoints=false, bool aFollowLockedSegments=false, bool aAllowSegmentSizeMismatch=true)
Follow the joint map to assemble a line connecting two non-trivial joints starting from segment aSeg.
Definition: pns_node.cpp:1047
int QueryColliding(const ITEM *aItem, OBSTACLES &aObstacles, const COLLISION_SEARCH_OPTIONS &aOpts=COLLISION_SEARCH_OPTIONS()) const
Find items colliding (closer than clearance) with the item aItem.
Definition: pns_node.cpp:255
void Remove(ARC *aArc)
Remove an item from this branch.
Definition: pns_node.cpp:909
virtual int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const =0
virtual void RemoveItem(ITEM *aItem)=0
virtual void AddItem(ITEM *aItem)=0
void SetMode(ROUTER_MODE aMode)
void StopRouting()
Definition: pns_router.cpp:930
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:230
ROUTER_IFACE * GetInterface() const
Definition: pns_router.h:232
void CommitRouting()
Definition: pns_router.cpp:921
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, int aSlopRadius=0)
Definition: pns_router.cpp:124
void SyncWorld()
Definition: pns_router.cpp:95
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:194
bool RoutingInProgress() const
Definition: pns_router.cpp:118
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:408
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:225
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
Definition: pns_router.cpp:878
NODE * GetWorld() const
Definition: pns_router.h:178
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:468
virtual int Clearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
const SHAPE_LINE_CHAIN CLine() const
Definition: pns_segment.h:98
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition: pns_segment.h:78
void SetShape(SHAPE *shape)
Definition: pns_solid.h:111
ROUTER * Router() const
PNS_KICAD_IFACE * GetInterface() const
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
void EraseView() override
wxString GetNetName(PNS::NET_HANDLE aNet) const override
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:258
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:87
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
RAII class that sets an value at construction and resets it to the original value at destruction.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Return the closest Euclidean distance between point aP and the line defined by the ends of segment (t...
Definition: seg.cpp:484
VECTOR2I::extended_type ecoord
Definition: seg.h:44
VECTOR2I B
Definition: seg.h:50
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:365
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition: seg.h:143
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:93
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Definition: shape_arc.cpp:427
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of the line chain.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
int Split(const VECTOR2I &aP, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
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 Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
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.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
int SegmentCount() const
Return the number of segments in this line chain.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
bool OffsetLine(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, SHAPE_LINE_CHAIN &aLeft, SHAPE_LINE_CHAIN &aRight, bool aSimplify=false) const
Creates line chains aLeft and aRight offset to this line chain.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void OffsetLineChain(const SHAPE_LINE_CHAIN &aLine, int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify)
Perform offsetting of a line chain.
int OutlineCount() const
Return the number of outlines in the set.
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Definition: shape.h:232
A name/value tuple with unique names and wxAny values.
void set_iu(const std::string &aKey, const T &aVar)
bool get_to(const std::string &aKey, T &aVar) const
std::optional< T > get_opt(const std::string &aKey) const
void set(const std::string &aKey, const T &aVar)
bool get_to_iu(const std::string &aKey, T &aVar) const
GR_TEXT_H_ALIGN_T m_Halign
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:146
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:38
Generic, UI-independent tool event.
Definition: tool_event.h:168
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
VECTOR2D GetMousePosition() const
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:404
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:395
void SetIsTimeDomain(const bool aIsTimeDomain)
void SetCurrent(const double aCurrent, const wxString &aLabel)
wxString GetClass() const override
Return the class name.
VECTOR2I GetPosition() const override
void SetMinMax(const double aMin, const double aMax)
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
TUNING_STATUS_VIEW_ITEM(PCB_BASE_EDIT_FRAME *aFrame)
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
void SetPosition(const VECTOR2I &aPos) override
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString MessageTextFromMinOptMax(const MINOPTMAX< int > &aValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
Definition: vector2d.h:569
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:76
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:385
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
@ CHT_GROUP
Definition: commit.h:45
@ CHT_UNGROUP
Definition: commit.h:46
#define _HKI(x)
static bool empty(const wxTextEntryBase *aCtrl)
@ LENGTH_CONSTRAINT
Definition: drc_rule.h:68
@ SKEW_CONSTRAINT
Definition: drc_rule.h:69
#define _(s)
#define IS_NEW
New item, just created.
#define IN_EDIT
Item currently edited.
EDA_DATA_TYPE
The type of unit.
Definition: eda_units.h:38
EDA_UNITS
Definition: eda_units.h:48
@ IGNORE_GRID
static FILENAME_RESOLVER * resolver
Definition: export_idf.cpp:53
@ LAYER_UI_START
Definition: layer_ids.h:347
@ LAYER_ANCHOR
Anchor of items having an anchor point (texts, footprints).
Definition: layer_ids.h:247
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_Cu
Definition: layer_ids.h:64
FLIP_DIRECTION
Definition: mirror.h:27
KICOMMON_API wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
Definition: eda_units.cpp:404
TEXT_DIMS GetConstantGlyphHeight(KIGFX::GAL *aGal, int aRelativeSize=0)
Set the GAL glyph height to a constant scaled value, so that it always looks the same on screen.
Push and Shove diff pair dimensions (gap) settings dialog.
MEANDER_SIDE
Definition: pns_meander.h:58
@ MEANDER_SIDE_RIGHT
Definition: pns_meander.h:61
@ MEANDER_SIDE_DEFAULT
Definition: pns_meander.h:60
@ MEANDER_SIDE_LEFT
Definition: pns_meander.h:59
@ MEANDER_STYLE_ROUND
Definition: pns_meander.h:52
@ MEANDER_STYLE_CHAMFER
Definition: pns_meander.h:53
ROUTER_MODE
Definition: pns_router.h:62
@ PNS_MODE_TUNE_DIFF_PAIR
Definition: pns_router.h:66
@ PNS_MODE_TUNE_SINGLE
Definition: pns_router.h:65
@ PNS_MODE_TUNE_DIFF_PAIR_SKEW
Definition: pns_router.h:67
Class to handle a set of BOARD_ITEMs.
static PNS::MEANDER_SIDE sideFromString(const std::string &aStr)
static LENGTH_TUNING_MODE tuningFromString(const std::string &aStr)
static std::string tuningToString(const LENGTH_TUNING_MODE aTuning)
static struct PCB_TUNING_PATTERN_DESC _PCB_TUNING_PATTERN_DESC
static LENGTH_TUNING_MODE fromPNSMode(PNS::ROUTER_MODE aRouterMode)
static PNS::MEANDER_PLACER_BASE::TUNING_STATUS statusFromString(const std::string &aStr)
static std::string sideToString(const PNS::MEANDER_SIDE aValue)
static std::string statusToString(const PNS::MEANDER_PLACER_BASE::TUNING_STATUS aStatus)
static GENERATORS_MGR::REGISTER< PCB_TUNING_PATTERN > registerMe
static PNS::LINKED_ITEM * pickSegment(PNS::ROUTER *aRouter, const VECTOR2I &aWhere, int aLayer, VECTOR2I &aPointOut, const SHAPE_LINE_CHAIN &aBaseline=SHAPE_LINE_CHAIN())
static std::optional< PNS::LINE > getPNSLine(const VECTOR2I &aStart, const VECTOR2I &aEnd, PNS::ROUTER *router, int layer, VECTOR2I &aStartOut, VECTOR2I &aEndOut)
LENGTH_TUNING_MODE
@ DIFF_PAIR
@ DIFF_PAIR_SKEW
static VECTOR2I snapToNearestTrack(const VECTOR2I &aP, BOARD *aBoard, NETINFO_ITEM *aNet, PCB_TRACK **aNearestTrack)
static REGISTER_LEGACY_TUNING_PATTERN< PCB_TUNING_PATTERN > registerMeToo
#define TYPE_HASH(x)
Definition: property.h:72
#define NO_SETTER(owner, type)
Definition: property.h:792
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:783
#define REGISTER_TYPE(x)
Definition: property_mgr.h:371
constexpr double correction
const double epsilon
#define PNS_HOVER_ITEM
#define PNS_COLLISION
#define HITTEST_THRESHOLD_PIXELS
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
constexpr int mmToIU(double mm) const
Definition: base_units.h:90
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition: pns_node.h:73
bool m_IsTimeDomain
Definition: pns_node.h:80
MINOPTMAX< int > m_Value
Definition: pns_node.h:75
Hold an object colliding with another object, along with some useful data about the collision.
Definition: pns_node.h:88
const SHAPE_LINE_CHAIN chain
VECTOR2I end
int clearance
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ BUT_LEFT
Definition: tool_event.h:132
@ BUT_RIGHT
Definition: tool_event.h:133
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
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition: typeinfo.h:91
@ NOT_USED
the 3d code uses this value
Definition: typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695