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>
35#include <kiplatform/ui.h>
37#include <collectors.h>
38#include <scoped_set_reset.h>
39#include <core/mirror.h>
40
42#include <drc/drc_engine.h>
43#include <pcb_track.h>
44#include <pcb_shape.h>
45#include <pcb_group.h>
46
47#include <tool/edit_points.h>
48#include <tool/tool_manager.h>
49#include <tools/drawing_tool.h>
54
57#include <view/view.h>
58#include <view/view_controls.h>
59
62#include <router/pns_meander.h>
64#include <router/pns_segment.h>
65#include <router/pns_arc.h>
66#include <router/pns_solid.h>
67#include <router/pns_topology.h>
69
71
72#include <wx/log.h>
73
74
76{
80};
81
82
84{
85public:
87 EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
88 m_frame( aFrame ), m_min( 0.0 ), m_max( 0.0 ), m_current( 0.0 ), m_isTimeDomain( false )
89 { }
90
91 wxString GetClass() const override { return wxT( "TUNING_STATUS" ); }
92
93#if defined(DEBUG)
94 void Show( int nestLevel, std::ostream& os ) const override {}
95#endif
96
97 VECTOR2I GetPosition() const override { return m_pos; }
98 void SetPosition( const VECTOR2I& aPos ) override { m_pos = aPos; };
99
100 void SetMinMax( const double aMin, const double aMax )
101 {
102 const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
103
104 m_min = aMin;
105 m_minText = m_frame->MessageTextFromValue( m_min, false, unitType );
106 m_max = aMax;
107 m_maxText = m_frame->MessageTextFromValue( m_max, false, unitType );
108 }
109
111 {
112 m_min = 0.0;
113 m_minText = wxT( "---" );
114 m_max = std::numeric_limits<double>::max();
115 m_maxText = wxT( "---" );
116 }
117
118 void SetCurrent( const double aCurrent, const wxString& aLabel )
119 {
120 const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
121
122 m_current = aCurrent;
123 m_currentText = m_frame->MessageTextFromValue( aCurrent, true, unitType );
124 m_currentLabel = aLabel;
125 }
126
127 void SetIsTimeDomain( const bool aIsTimeDomain ) { m_isTimeDomain = aIsTimeDomain; }
128
129 const BOX2I ViewBBox() const override
130 {
131 BOX2I tmp;
132
133 // this is an edit-time artefact; no reason to try and be smart with the bounding box
134 // (besides, we can't tell the text extents without a view to know what the scale is)
135 tmp.SetMaximum();
136 return tmp;
137 }
138
139 std::vector<int> ViewGetLayers() const override
140 {
141 return { LAYER_UI_START, LAYER_UI_START + 1 };
142 }
143
144 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override
145 {
146 KIGFX::GAL* gal = aView->GetGAL();
147 bool viewFlipped = gal->IsFlippedX();
148 bool drawingDropShadows = ( aLayer == LAYER_UI_START );
149
150 gal->Save();
151 gal->Scale( { 1., 1. } );
152
156 const KIFONT::METRICS& fontMetrics = KIFONT::METRICS::Default();
157 TEXT_ATTRIBUTES textAttrs;
158
159 int glyphWidth = textDims.GlyphSize.x;
160 VECTOR2I margin( KiROUND( glyphWidth * 0.4 ), KiROUND( glyphWidth ) );
161 VECTOR2I size( glyphWidth * 25 + margin.x * 2, headerDims.GlyphSize.y + textDims.GlyphSize.y );
162 VECTOR2I offset( margin.x * 2, -( size.y + margin.y * 2 ) );
163
164 if( drawingDropShadows )
165 {
166 gal->SetIsFill( true );
167 gal->SetIsStroke( true );
168 gal->SetLineWidth( gal->GetScreenWorldMatrix().GetScale().x * 2 );
169 gal->SetStrokeColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) );
170 KIGFX::COLOR4D bgColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
171 gal->SetFillColor( bgColor.WithAlpha( 0.9 ) );
172
173 gal->DrawRectangle( GetPosition() + offset - margin,
174 GetPosition() + offset + size + margin );
175 gal->Restore();
176 return;
177 }
178
179 COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
180 COLOR4D normal = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
181 COLOR4D red;
182
183 // Choose a red with reasonable contrasting with the background
184 double bg_h, bg_s, bg_l;
185 bg.ToHSL( bg_h, bg_s, bg_l );
186 red.FromHSL( 0, 1.0, bg_l < 0.5 ? 0.7 : 0.3 );
187
188 if( viewFlipped )
190 else
191 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
192
193 gal->SetIsFill( false );
194 gal->SetIsStroke( true );
195 gal->SetStrokeColor( normal );
196 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
197
198 // Prevent text flipping when view is flipped
199 if( gal->IsFlippedX() )
200 {
201 textAttrs.m_Mirrored = true;
203 }
204
205 textAttrs.m_Size = headerDims.GlyphSize;
206 textAttrs.m_StrokeWidth = headerDims.StrokeWidth;
207
208 VECTOR2I textPos = GetPosition() + offset;
209 font->Draw( gal, m_currentLabel, textPos, textAttrs, KIFONT::METRICS::Default() );
210
211 textPos.x += glyphWidth * 11 + margin.x;
212 font->Draw( gal, _( "min" ), textPos, textAttrs, fontMetrics );
213
214 textPos.x += glyphWidth * 7 + margin.x;
215 font->Draw( gal, _( "max" ), textPos, textAttrs, fontMetrics );
216
217 textAttrs.m_Size = textDims.GlyphSize;
218 textAttrs.m_StrokeWidth = textDims.StrokeWidth;
219
220 textPos = GetPosition() + offset;
221 textPos.y += KiROUND( headerDims.LinePitch * 1.3 );
222 font->Draw( gal, m_currentText, textPos, textAttrs, KIFONT::METRICS::Default() );
223
224 textPos.x += glyphWidth * 11 + margin.x;
226 font->Draw( gal, m_minText, textPos, textAttrs, fontMetrics );
227
228 textPos.x += glyphWidth * 7 + margin.x;
230 font->Draw( gal, m_maxText, textPos, textAttrs, fontMetrics );
231
232 gal->Restore();
233 }
234
235protected:
238 double m_min;
239 double m_max;
240 double m_current;
243 wxString m_minText;
244 wxString m_maxText;
246};
247
248
250{
251public:
252 static const wxString GENERATOR_TYPE;
253 static const wxString DISPLAY_NAME;
254
255 PCB_TUNING_PATTERN( BOARD_ITEM* aParent = nullptr, PCB_LAYER_ID aLayer = F_Cu,
256 LENGTH_TUNING_MODE aMode = LENGTH_TUNING_MODE::SINGLE );
257
258 wxString GetGeneratorType() const override { return wxS( "tuning_pattern" ); }
259
260 wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override
261 {
262 return wxString( _( "Tuning Pattern" ) );
263 }
264
265 wxString GetFriendlyName() const override
266 {
267 return wxString( _( "Tuning Pattern" ) );
268 }
269
270 wxString GetPluralName() const override
271 {
272 return wxString( _( "Tuning Patterns" ) );
273 }
274
275 BITMAPS GetMenuImage() const override
276 {
277 switch( m_tuningMode )
278 {
279 case SINGLE: return BITMAPS::ps_tune_length; break;
280 case DIFF_PAIR: return BITMAPS::ps_diff_pair_tune_length; break;
281 case DIFF_PAIR_SKEW: return BITMAPS::ps_diff_pair_tune_phase; break;
282 }
283
284 return BITMAPS::unknown;
285 }
286
288 BOARD_CONNECTED_ITEM* aStartItem,
289 LENGTH_TUNING_MODE aMode );
290
291 void EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
292
293 bool Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
294
295 void EditPush( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit,
296 const wxString& aCommitMsg = wxEmptyString, int aCommitFlags = 0 ) override;
297
298 void EditRevert( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
299
300 void Remove( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
301
302 bool MakeEditPoints( EDIT_POINTS& points ) const override;
303
304 bool UpdateFromEditPoints( EDIT_POINTS& aEditPoints ) override;
305
306 bool UpdateEditPoints( EDIT_POINTS& aEditPoints ) override;
307
308 void Move( const VECTOR2I& aMoveVector ) override
309 {
310 m_origin += aMoveVector;
311 m_end += aMoveVector;
312
313 if( !this->HasFlag( IN_EDIT ) )
314 {
315 PCB_GROUP::Move( aMoveVector );
316
317 if( m_baseLine )
318 m_baseLine->Move( aMoveVector );
319
321 m_baseLineCoupled->Move( aMoveVector );
322 }
323 }
324
325 void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override
326 {
327 if( !this->HasFlag( IN_EDIT ) )
328 {
329 PCB_GENERATOR::Rotate( aRotCentre, aAngle );
330 RotatePoint( m_end, aRotCentre, aAngle );
331
332 if( m_baseLine )
333 m_baseLine->Rotate( aAngle, aRotCentre );
334
336 m_baseLineCoupled->Rotate( aAngle, aRotCentre );
337 }
338 }
339
340 void Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
341 {
342 if( !this->HasFlag( IN_EDIT ) )
343 {
344 PCB_GENERATOR::Flip( aCentre, aFlipDirection );
345
346 baseMirror( aCentre, aFlipDirection );
347 }
348 }
349
350 void Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
351 {
352 if( !this->HasFlag( IN_EDIT ) )
353 {
354 PCB_GENERATOR::Mirror( aCentre, aFlipDirection );
355
356 baseMirror( aCentre, aFlipDirection );
357 }
358 }
359
360 const BOX2I GetBoundingBox() const override
361 {
362 return getOutline().BBox();
363 }
364
365 std::vector<int> ViewGetLayers() const override
366 {
367 return { LAYER_ANCHOR, GetLayer() };
368 }
369
370 bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
371 {
372 return getOutline().Collide( aPosition, aAccuracy );
373 }
374
375 bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
376 {
377 BOX2I sel = aRect;
378
379 if ( aAccuracy )
380 sel.Inflate( aAccuracy );
381
382 if( aContained )
383 return sel.Contains( GetBoundingBox() );
384
385 return sel.Intersects( GetBoundingBox() );
386 }
387
388 bool HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const override
389 {
390 return KIGEOM::ShapeHitTest( aPoly, getOutline(), aContained );
391 }
392
393 const BOX2I ViewBBox() const override { return GetBoundingBox(); }
394
395 EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
396
397 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
398
399 const VECTOR2I& GetEnd() const { return m_end; }
400 void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
401
402 int GetEndX() const { return m_end.x; }
403 void SetEndX( int aValue ) { m_end.x = aValue; }
404
405 int GetEndY() const { return m_end.y; }
406 void SetEndY( int aValue ) { m_end.y = aValue; }
407
409
411 {
412 switch( m_tuningMode )
413 {
414 case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
415 case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
416 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
417 default: return PNS::PNS_MODE_TUNE_SINGLE;
418 }
419 }
420
422
424 void SetMinAmplitude( int aValue )
425 {
426 aValue = std::max( aValue, 0 );
427
428 m_settings.m_minAmplitude = aValue;
429
432 }
433
435 void SetMaxAmplitude( int aValue )
436 {
437 aValue = std::max( aValue, 0 );
438
439 m_settings.m_maxAmplitude = aValue;
440
443 }
444
445 // Update the initial side one time at EditStart based on m_end.
447
450
451 int GetSpacing() const { return m_settings.m_spacing; }
452 void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
453
454 std::optional<int> GetTargetLength() const
455 {
457 return std::optional<int>();
458 else
460 }
461
462 void SetTargetLength( std::optional<int> aValue )
463 {
465
466 if( aValue.has_value() )
467 m_settings.SetTargetLength( aValue.value() );
468 else
470 }
471
472 std::optional<int> GetTargetDelay() const
473 {
475 return std::optional<int>();
476 else
478 }
479
480 void SetTargetDelay( std::optional<int> aValue )
481 {
483
484 if( aValue.has_value() )
485 m_settings.SetTargetLengthDelay( aValue.value() );
486 else
488 }
489
490 int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
491 void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
492
494 void SetTargetSkewDelay( int aValue ) { m_settings.SetTargetSkewDelay( aValue ); }
495
497 void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
498
501
502 bool IsSingleSided() const { return m_settings.m_singleSided; }
503 void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
504
508
509 std::vector<std::pair<wxString, wxVariant>> GetRowData() override
510 {
511 std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
512 data.emplace_back( _HKI( "Net" ), m_lastNetName );
513 data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
514 return data;
515 }
516
517 const STRING_ANY_MAP GetProperties() const override;
518 void SetProperties( const STRING_ANY_MAP& aProps ) override;
519
520 void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
521
522 std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
523 bool aStatusItemsOnly = false ) override;
524
525 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
526
527protected:
528 void swapData( BOARD_ITEM* aImage ) override
529 {
530 wxASSERT( aImage->Type() == PCB_GENERATOR_T );
531
532 std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
533 }
534
535 bool recoverBaseline( PNS::ROUTER* aRouter );
536
537 bool baselineValid();
538
539 bool initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard, VECTOR2I& aStart,
540 VECTOR2I& aEnd, NETINFO_ITEM* aNet,
541 std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
542
543 bool initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard );
544
545 bool removeToBaseline( PNS::ROUTER* aRouter, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine );
546
547 bool resetToBaseline( GENERATOR_TOOL* aTool, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine,
548 bool aPrimary );
549
551
552 void baseMirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
553 {
554 PCB_GENERATOR::baseMirror( aCentre, aFlipDirection );
555
556 if( m_baseLine )
557 {
558 m_baseLine->Mirror( aCentre, aFlipDirection );
559 m_origin = m_baseLine->CPoint( 0 );
560 m_end = m_baseLine->CLastPoint();
561 }
562
564 m_baseLineCoupled->Mirror( aCentre, aFlipDirection );
565
568 else
570 }
571
572protected:
574
576
577 std::optional<SHAPE_LINE_CHAIN> m_baseLine;
578 std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
579
582
584
586 wxString m_tuningInfo;
587
589
591};
592
593
594static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
595{
596 if( aStr == "single" )
598 else if( aStr == "diff_pair" )
600 else if( aStr == "diff_pair_skew" )
602 else
603 {
604 wxFAIL_MSG( wxS( "Unknown length tuning token" ) );
606 }
607}
608
609
610static std::string tuningToString( const LENGTH_TUNING_MODE aTuning )
611{
612 switch( aTuning )
613 {
614 case LENGTH_TUNING_MODE::SINGLE: return "single";
615 case LENGTH_TUNING_MODE::DIFF_PAIR: return "diff_pair";
616 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return "diff_pair_skew";
617 default: wxFAIL; return "";
618 }
619}
620
621
623{
624 switch( aRouterMode )
625 {
629 default: return LENGTH_TUNING_MODE::SINGLE;
630 }
631}
632
633
634static PNS::MEANDER_SIDE sideFromString( const std::string& aStr )
635{
636 if( aStr == "default" )
638 else if( aStr == "left" )
640 else if( aStr == "right" )
642 else
643 {
644 wxFAIL_MSG( wxS( "Unknown length-tuning side token" ) );
646 }
647}
648
649
651{
652 switch( aStatus )
653 {
654 case PNS::MEANDER_PLACER_BASE::TOO_LONG: return "too_long";
655 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: return "too_short";
656 case PNS::MEANDER_PLACER_BASE::TUNED: return "tuned";
657 default: wxFAIL; return "";
658 }
659}
660
661
663{
664 if( aStr == "too_long" )
666 else if( aStr == "too_short" )
668 else if( aStr == "tuned" )
670 else
671 {
672 wxFAIL_MSG( wxS( "Unknown tuning status token" ) );
674 }
675}
676
677
678static std::string sideToString( const PNS::MEANDER_SIDE aValue )
679{
680 switch( aValue )
681 {
682 case PNS::MEANDER_SIDE_DEFAULT: return "default";
683 case PNS::MEANDER_SIDE_LEFT: return "left";
684 case PNS::MEANDER_SIDE_RIGHT: return "right";
685 default: wxFAIL; return "";
686 }
687}
688
689
691 LENGTH_TUNING_MODE aMode ) :
692 PCB_GENERATOR( aParent, aLayer ),
693 m_trackWidth( 0 ),
694 m_diffPairGap( 0 ),
695 m_tuningMode( aMode ),
696 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED ),
697 m_updateSideFromEnd(false)
698{
701 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
703}
704
705
706static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
707 PCB_TRACK** aNearestTrack )
708{
710 VECTOR2I closestPt = aP;
711
712 for( PCB_TRACK *track : aBoard->Tracks() )
713 {
714 if( aNet && track->GetNet() != aNet )
715 continue;
716
717 VECTOR2I nearest;
718
719 if( track->Type() == PCB_ARC_T )
720 {
721 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
722 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
723 pcbArc->GetWidth() );
724
725 nearest = arc.NearestPoint( aP );
726 }
727 else
728 {
729 SEG seg( track->GetStart(), track->GetEnd() );
730 nearest = seg.NearestPoint( aP );
731 }
732
733 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
734
735 if( dist_sq < minDist_sq )
736 {
737 minDist_sq = dist_sq;
738 closestPt = nearest;
739
740 if( aNearestTrack )
741 *aNearestTrack = track;
742 }
743 }
744
745 return closestPt;
746}
747
748
750{
752 {
753 return( m_baseLine && m_baseLine->PointCount() > 1
754 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
755 }
756 else
757 {
758 return( m_baseLine && m_baseLine->PointCount() > 1 );
759 }
760}
761
762
764 PCB_BASE_EDIT_FRAME* aFrame,
765 BOARD_CONNECTED_ITEM* aStartItem,
766 LENGTH_TUNING_MODE aMode )
767{
768 BOARD* board = aStartItem->GetBoard();
770 DRC_CONSTRAINT constraint;
771 PCB_LAYER_ID layer = aStartItem->GetLayer();
772
773 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
774
775 switch( aMode )
776 {
777 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
778 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
779 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
780 }
781
782 if( aMode == SINGLE || aMode == DIFF_PAIR )
783 {
784 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
785
786 if( !constraint.IsNull() )
787 {
789 {
790 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
792 pattern->m_settings.m_isTimeDomain = true;
793 }
794 else
795 {
797 pattern->m_settings.SetTargetLength( constraint.GetValue() );
798 pattern->m_settings.m_isTimeDomain = false;
799 }
800 }
801 }
802 else
803 {
804 constraint = bds.m_DRCEngine->EvalRules( SKEW_CONSTRAINT, aStartItem, nullptr, layer );
805
806 if( !constraint.IsNull() )
807 {
809 {
811 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
812 pattern->m_settings.m_isTimeDomain = true;
813 }
814 else
815 {
816 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
818 pattern->m_settings.m_isTimeDomain = true;
819 }
820 }
821 }
822
823 pattern->SetFlags( IS_NEW );
824 pattern->m_settings.m_netClass = aStartItem->GetEffectiveNetClass();
825
826 return pattern;
827}
828
830{
831 if( aCommit )
832 {
833 if( IsNew() )
834 aCommit->Add( this );
835 else
836 aCommit->Modify( this );
837 }
838
839 SetFlags( IN_EDIT );
840
841 PNS::ROUTER* router = aTool->Router();
842 int layer = router->GetInterface()->GetPNSLayerFromBoardLayer( GetLayer() );
843
844 aTool->ClearRouterChanges();
845 router->SyncWorld();
846
848 PNS::CONSTRAINT constraint;
849
850 if( !baselineValid() )
851 initBaseLines( router, layer, aBoard );
852
854 {
855 VECTOR2I centerlineOffsetEnd;
856
858 && m_baseLineCoupled->SegmentCount() > 0 )
859 {
860 centerlineOffsetEnd =
861 ( m_baseLineCoupled->CLastPoint() - m_baseLine->CLastPoint() ) / 2;
862 }
863
864 SEG baseEnd = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( -1 )
865 : SEG( m_origin, m_end );
866
867 baseEnd.A += centerlineOffsetEnd;
868 baseEnd.B += centerlineOffsetEnd;
869
870 if( baseEnd.A != baseEnd.B )
871 {
872 int side = baseEnd.Side( m_end );
873
874 if( side < 0 )
876 else
878 }
879
880 m_updateSideFromEnd = false;
881 }
882
883 PCB_TRACK* track = nullptr;
884 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
885 wxCHECK( track, /* void */ );
886
888
890 {
891 PNS::SEGMENT pnsItem;
892 NETINFO_ITEM* net = track->GetNet();
893
894 pnsItem.SetParent( track );
895 pnsItem.SetNet( net );
896
897 if( m_tuningMode == SINGLE )
898 {
899 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
900 &pnsItem, nullptr, layer, &constraint ) )
901 {
902 if( constraint.m_IsTimeDomain )
903 {
906 }
907 else
908 {
910 m_settings.SetTargetLength( constraint.m_Value );
911 }
912
915 }
916 }
917 else
918 {
919 PCB_TRACK* coupledTrack = nullptr;
920 PNS::SEGMENT pnsCoupledItem;
921 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
922
923 if( coupledNet )
924 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
925
926 pnsCoupledItem.SetParent( coupledTrack );
927 pnsCoupledItem.SetNet( coupledNet );
928
929 if( m_tuningMode == DIFF_PAIR )
930 {
931 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
932 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
933 {
934 if( constraint.m_IsTimeDomain )
935 {
938 }
939 else
940 {
942 m_settings.SetTargetLength( constraint.m_Value );
943 }
944
947 }
948 }
949 else
950 {
952 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
953 {
954 if( constraint.m_IsTimeDomain )
955 {
958 }
959 else
960 {
962 m_settings.SetTargetSkew( constraint.m_Value );
963 }
964
967 }
968 }
969 }
970 }
971}
972
973
974static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
975 VECTOR2I& aPointOut,
976 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
977{
978 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
979
980 static const int candidateCount = 2;
981 PNS::LINKED_ITEM* prioritized[candidateCount];
982 SEG::ecoord dist[candidateCount];
983 SEG::ecoord distBaseline[candidateCount];
984 VECTOR2I point[candidateCount];
985
986 for( int i = 0; i < candidateCount; i++ )
987 {
988 prioritized[i] = nullptr;
989 dist[i] = VECTOR2I::ECOORD_MAX;
990 distBaseline[i] = VECTOR2I::ECOORD_MAX;
991 }
992
993 for( int slopRadius : { 0, maxSlopRadius } )
994 {
995 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
996
997 for( PNS::ITEM* item : candidates.Items() )
998 {
999 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
1000 continue;
1001
1002 if( !item->IsRoutable() )
1003 continue;
1004
1005 if( !item->Layers().Overlaps( aLayer ) )
1006 continue;
1007
1008 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
1009
1010 if( item->Kind() & PNS::ITEM::ARC_T )
1011 {
1012 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
1013
1014 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
1015 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
1016
1017 if( d0 > dist[1] )
1018 continue;
1019
1020 if( aBaseline.PointCount() > 0 )
1021 {
1022 SEG::ecoord dcBaseline;
1023 VECTOR2I target = pnsArc->Arc().GetArcMid();
1024
1025 if( aBaseline.SegmentCount() > 0 )
1026 dcBaseline = aBaseline.SquaredDistance( target );
1027 else
1028 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
1029
1030 if( dcBaseline > distBaseline[1] )
1031 continue;
1032
1033 distBaseline[1] = dcBaseline;
1034 }
1035
1036 prioritized[1] = linked;
1037 dist[1] = d0;
1038 point[1] = nearest;
1039 }
1040 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
1041 {
1042 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
1043
1044 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
1045 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
1046
1047 if( dd > dist[1] )
1048 continue;
1049
1050 if( aBaseline.PointCount() > 0 )
1051 {
1052 SEG::ecoord dcBaseline;
1053 VECTOR2I target = segm->Shape( -1 )->Centre();
1054
1055 if( aBaseline.SegmentCount() > 0 )
1056 dcBaseline = aBaseline.SquaredDistance( target );
1057 else
1058 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
1059
1060 if( dcBaseline > distBaseline[1] )
1061 continue;
1062
1063 distBaseline[1] = dcBaseline;
1064 }
1065
1066 prioritized[1] = segm;
1067 dist[1] = dd;
1068 point[1] = nearest;
1069 }
1070 }
1071 }
1072
1073 PNS::LINKED_ITEM* rv = nullptr;
1074
1075 for( int i = 0; i < candidateCount; i++ )
1076 {
1077 PNS::LINKED_ITEM* item = prioritized[i];
1078
1079 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
1080 {
1081 rv = item;
1082 aPointOut = point[i];
1083 break;
1084 }
1085 }
1086
1087 return rv;
1088}
1089
1090
1091static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
1092 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
1093 VECTOR2I& aEndOut )
1094{
1095 PNS::NODE* world = router->GetWorld();
1096
1097 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
1098 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
1099
1100 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
1101 {
1102 if( !testItem )
1103 continue;
1104
1105 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
1106 SHAPE_LINE_CHAIN oldChain = line.CLine();
1107
1108 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
1109 return line;
1110 }
1111
1112 return std::nullopt;
1113}
1114
1115
1116bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard,
1117 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
1118 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
1119{
1120 PNS::NODE* world = aRouter->GetWorld();
1121
1122 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
1123 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
1124
1125 VECTOR2I startSnapPoint, endSnapPoint;
1126
1127 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aPNSLayer, startSnapPoint );
1128 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aPNSLayer, endSnapPoint );
1129
1130 wxASSERT( startItem );
1131 wxASSERT( endItem );
1132
1133 if( !startItem || !endItem )
1134 return false;
1135
1136 PNS::LINE line = world->AssembleLine( startItem );
1137 const SHAPE_LINE_CHAIN& chain = line.CLine();
1138
1139 wxASSERT( line.ContainsLink( endItem ) );
1140
1141 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
1142 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
1143
1144 SHAPE_LINE_CHAIN pre;
1145 SHAPE_LINE_CHAIN mid;
1146 SHAPE_LINE_CHAIN post;
1147
1148 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
1149
1150 aBaseLine = mid;
1151
1152 return true;
1153}
1154
1155
1156bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard )
1157{
1158 m_baseLineCoupled.reset();
1159
1160 PCB_TRACK* track = nullptr;
1161
1162 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
1163 wxCHECK( track, false );
1164
1165 NETINFO_ITEM* net = track->GetNet();
1166
1167 if( !initBaseLine( aRouter, aPNSLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
1168 return false;
1169
1170 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
1171 // DRC rules against.
1173 {
1174 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
1175 {
1176 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
1177 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
1178
1179 return initBaseLine( aRouter, aPNSLayer, aBoard, coupledStart, coupledEnd, coupledNet,
1181 }
1182
1183 return false;
1184 }
1185
1186 return true;
1187}
1188
1190 SHAPE_LINE_CHAIN& aBaseLine )
1191{
1192 VECTOR2I startSnapPoint, endSnapPoint;
1193
1194 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CLastPoint(),
1195 aRouter, aPNSLayer, startSnapPoint, endSnapPoint );
1196
1197 wxCHECK( pnsLine, false );
1198
1199 SHAPE_LINE_CHAIN pre;
1200 SHAPE_LINE_CHAIN mid;
1201 SHAPE_LINE_CHAIN post;
1202 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1203
1204 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
1205 aRouter->GetInterface()->RemoveItem( li );
1206
1207 aRouter->GetWorld()->Remove( *pnsLine );
1208
1209 SHAPE_LINE_CHAIN straightChain;
1210 straightChain.Append( pre );
1211 straightChain.Append( aBaseLine );
1212 straightChain.Append( post );
1213 straightChain.Simplify();
1214
1215 PNS::LINE straightLine( *pnsLine, straightChain );
1216
1217 aRouter->GetWorld()->Add( straightLine, false );
1218
1219 for( PNS::LINKED_ITEM* li : straightLine.Links() )
1220 aRouter->GetInterface()->AddItem( li );
1221
1222 return true;
1223}
1224
1225
1227{
1228 SetFlags( IN_EDIT );
1229
1230 aTool->Router()->SyncWorld();
1231
1232 PNS::ROUTER* router = aTool->Router();
1233 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1234
1235 aCommit->Remove( this );
1236
1237 aTool->ClearRouterChanges();
1238
1239 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1240 int pnslayer = iface->GetPNSLayerFromBoardLayer( GetLayer() );
1241
1242 if( baselineValid() )
1243 {
1244 bool success = true;
1245
1246 success &= removeToBaseline( router, pnslayer, *m_baseLine );
1247
1248 if( m_tuningMode == DIFF_PAIR )
1249 success &= removeToBaseline( router, pnslayer, *m_baseLineCoupled );
1250
1251 if( !success )
1252 recoverBaseline( router );
1253 }
1254
1255 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
1256
1257 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
1258 {
1259 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
1260 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
1261
1262 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1263 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1264 << " m_removedItems " << m_removedItems.size() << std::endl;*/
1265
1266 for( BOARD_ITEM* item : routerRemovedItems )
1267 {
1268 item->ClearSelected();
1269 aCommit->Remove( item );
1270 }
1271
1272 for( BOARD_ITEM* item : routerAddedItems )
1273 aCommit->Add( item );
1274 }
1275
1276 aCommit->Push( "Remove Tuning Pattern" );
1277}
1278
1279
1281{
1282 PNS::SOLID queryItem;
1283
1284 SHAPE_LINE_CHAIN* chain = static_cast<SHAPE_LINE_CHAIN*>( getOutline().Clone() );
1285 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
1286 queryItem.SetLayer( m_layer );
1287
1288 int lineWidth = 0;
1289
1290 PNS::NODE::OBSTACLES obstacles;
1292 opts.m_useClearanceEpsilon = false;
1293
1294 PNS::NODE* world = aRouter->GetWorld();
1295 PNS::NODE* branch = world->Branch();
1296
1297 branch->QueryColliding( &queryItem, obstacles, opts );
1298
1299 for( const PNS::OBSTACLE& obs : obstacles )
1300 {
1301 PNS::ITEM* item = obs.m_item;
1302
1304 continue;
1305
1306 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
1307 {
1308 if( lineWidth == 0 || li->Width() < lineWidth )
1309 lineWidth = li->Width();
1310 }
1311
1312 if( chain->PointInside( item->Anchor( 0 ), 10 )
1313 && chain->PointInside( item->Anchor( 1 ), 10 ) )
1314 {
1315 branch->Remove( item );
1316 }
1317 }
1318
1319 if( lineWidth == 0 )
1320 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1321
1322 if( baselineValid() )
1323 {
1324 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1325 PNS::LINE recoverLine;
1326
1327 recoverLine.SetLayer( m_layer );
1328 recoverLine.SetWidth( lineWidth );
1329 recoverLine.Line() = *m_baseLine;
1330 recoverLine.SetNet( recoverNet );
1331 branch->Add( recoverLine, false );
1332
1334 {
1335 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1336 PNS::LINE recoverLineCoupled;
1337
1338 recoverLineCoupled.SetLayer( m_layer );
1339 recoverLineCoupled.SetWidth( lineWidth );
1340 recoverLineCoupled.Line() = *m_baseLineCoupled;
1341 recoverLineCoupled.SetNet( recoverCoupledNet );
1342 branch->Add( recoverLineCoupled, false );
1343 }
1344 }
1345
1346 aRouter->CommitRouting( branch );
1347
1348 //wxLogWarning( "PNS baseline recovered" );
1349
1350 return true;
1351}
1352
1353
1355 SHAPE_LINE_CHAIN& aBaseLine, bool aPrimary )
1356{
1357 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1358 PNS::ROUTER* router = aTool->Router();
1359 PNS::NODE* world = router->GetWorld();
1360 VECTOR2I startSnapPoint, endSnapPoint;
1361
1362 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CLastPoint(),
1363 router, aPNSLayer, startSnapPoint, endSnapPoint );
1364
1365 if( !pnsLine )
1366 {
1367 // TODO
1368 //recoverBaseline( aRouter );
1369 return true;
1370 }
1371
1372 PNS::NODE* branch = world->Branch();
1373
1374 SHAPE_LINE_CHAIN straightChain;
1375 {
1376 SHAPE_LINE_CHAIN pre, mid, post;
1377 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1378
1379 straightChain.Append( pre );
1380 straightChain.Append( aBaseLine );
1381 straightChain.Append( post );
1382 straightChain.Simplify();
1383 }
1384
1385 branch->Remove( *pnsLine );
1386
1387 SHAPE_LINE_CHAIN newLineChain;
1388
1389 if( aPrimary )
1390 {
1391 m_origin = straightChain.NearestPoint( m_origin );
1392 m_end = straightChain.NearestPoint( m_end );
1393
1394 // Don't allow points too close
1395 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1396 {
1397 m_origin = startSnapPoint;
1398 m_end = endSnapPoint;
1399 }
1400
1401 {
1402 SHAPE_LINE_CHAIN pre, mid, post;
1403 straightChain.Split( m_origin, m_end, pre, mid, post );
1404
1405 newLineChain.Append( pre );
1406 newLineChain.Append( mid );
1407 newLineChain.Append( post );
1408
1409 m_baseLine = mid;
1410 }
1411 }
1412 else
1413 {
1414 VECTOR2I start = straightChain.NearestPoint( m_origin );
1415 VECTOR2I end = straightChain.NearestPoint( m_end );
1416
1417 {
1418 SHAPE_LINE_CHAIN pre, mid, post;
1419 straightChain.Split( start, end, pre, mid, post );
1420
1421 newLineChain.Append( pre );
1422 newLineChain.Append( mid );
1423 newLineChain.Append( post );
1424
1425 m_baseLineCoupled = mid;
1426 }
1427 }
1428
1429 PNS::LINE newLine( *pnsLine, newLineChain );
1430
1431 branch->Add( newLine, false );
1432 router->CommitRouting( branch );
1433
1434 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1435
1436 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1437
1438 return true;
1439}
1440
1441
1443{
1444 if( !( GetFlags() & IN_EDIT ) )
1445 return false;
1446
1447 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1448 PNS::ROUTER* router = aTool->Router();
1449 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1450 PCB_LAYER_ID pcblayer = GetLayer();
1451
1452 auto hideRemovedItems = [&]( bool aHide )
1453 {
1454 if( view )
1455 {
1456 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1457 {
1458 for( BOARD_ITEM* item : pnsCommit.removedItems )
1459 {
1460 if( view )
1461 view->Hide( item, aHide, aHide );
1462 }
1463 }
1464 }
1465 };
1466
1467 iface->SetStartLayerFromPCBNew( pcblayer );
1468
1469 if( router->RoutingInProgress() )
1470 {
1471 router->StopRouting();
1472 }
1473
1474 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1475 int pnslayer = iface->GetPNSLayerFromBoardLayer( pcblayer );
1476
1477 if( !baselineValid() )
1478 {
1479 initBaseLines( router, pnslayer, aBoard );
1480 }
1481 else
1482 {
1483 if( resetToBaseline( aTool, pnslayer, *m_baseLine, true ) )
1484 {
1485 m_origin = m_baseLine->CPoint( 0 );
1486 m_end = m_baseLine->CLastPoint();
1487 }
1488 else
1489 {
1490 //initBaseLines( router, layer, aBoard );
1491 return false;
1492 }
1493
1494 if( m_tuningMode == DIFF_PAIR )
1495 {
1496 if( !resetToBaseline( aTool, pnslayer, *m_baseLineCoupled, false ) )
1497 {
1498 initBaseLines( router, pnslayer, aBoard );
1499 return false;
1500 }
1501 }
1502 }
1503
1504 hideRemovedItems( true );
1505 // Snap points
1506 VECTOR2I startSnapPoint, endSnapPoint;
1507
1508 wxCHECK( m_baseLine, false );
1509
1510 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, pnslayer, startSnapPoint, *m_baseLine);
1511 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, pnslayer, endSnapPoint, *m_baseLine );
1512
1513 wxASSERT( startItem );
1514 wxASSERT( endItem );
1515
1516 if( !startItem || !endItem )
1517 return false;
1518
1519 router->SetMode( GetPNSMode() );
1520
1521 if( !router->StartRouting( startSnapPoint, startItem, pnslayer ) )
1522 {
1523 //recoverBaseline( router );
1524 return false;
1525 }
1526
1527 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1528
1529 m_settings.m_keepEndpoints = true; // Required for re-grouping
1530 placer->UpdateSettings( m_settings );
1531
1532 router->Move( m_end, nullptr );
1533
1534 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1535 {
1536 m_trackWidth = dpPlacer->GetOriginPair().Width();
1537 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1538 }
1539 else
1540 {
1541 m_trackWidth = startItem->Width();
1542 m_diffPairGap = router->Sizes().DiffPairGap();
1543 }
1544
1545 m_settings = placer->MeanderSettings();
1546 m_lastNetName = iface->GetNetName( startItem->Net() );
1547 m_tuningStatus = placer->TuningStatus();
1548
1549 wxString statusMessage;
1550
1551 switch ( m_tuningStatus )
1552 {
1553 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1554 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1555 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1556 default: statusMessage = _( "unknown" ); break;
1557 }
1558
1559 wxString result;
1560 EDA_UNITS userUnits = EDA_UNITS::MM;
1561
1562 if( aTool->GetManager()->GetSettings() )
1563 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1564
1566 {
1568 (double) placer->TuningLengthResult() );
1569 }
1570 else
1571 {
1573 (double) placer->TuningLengthResult() );
1574 }
1575
1576 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1577
1578 return true;
1579}
1580
1581
1583 const wxString& aCommitMsg, int aCommitFlags )
1584{
1585 if( !( GetFlags() & IN_EDIT ) )
1586 return;
1587
1589
1590 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1591 PNS::ROUTER* router = aTool->Router();
1592 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1593 SHAPE_LINE_CHAIN bounds = getOutline();
1594 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1595
1596 iface->EraseView();
1597
1598 if( router->RoutingInProgress() )
1599 {
1600 bool forceFinish = true;
1601 bool forceCommit = false;
1602
1603 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1604 router->StopRouting();
1605 }
1606
1607 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1608
1609 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1610 {
1611 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1612 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1613
1614 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1615 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1616 // << " m_removedItems " << m_removedItems.size() << std::endl;
1617
1618 for( BOARD_ITEM* item : routerRemovedItems )
1619 {
1620 if( view )
1621 view->Hide( item, false );
1622
1623 aCommit->Remove( item );
1624 }
1625
1626 for( BOARD_ITEM* item : routerAddedItems )
1627 {
1628 aCommit->Add( item );
1629
1630 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1631 {
1632 if( bounds.PointInside( track->GetStart(), epsilon )
1633 && bounds.PointInside( track->GetEnd(), epsilon ) )
1634 {
1635 AddItem( item );
1636 }
1637 }
1638 }
1639 }
1640
1641 if( aCommitMsg.IsEmpty() )
1642 aCommit->Push( _( "Edit Tuning Pattern" ), aCommitFlags );
1643 else
1644 aCommit->Push( aCommitMsg, aCommitFlags );
1645}
1646
1647
1649{
1650 if( !( GetFlags() & IN_EDIT ) )
1651 return;
1652
1654
1655 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1656
1657 iface->EraseView();
1658
1659 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1660 {
1661 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1662 {
1663 for( BOARD_ITEM* item : pnsCommit.removedItems )
1664 view->Hide( item, false );
1665 }
1666 }
1667
1668 aTool->Router()->StopRouting();
1669
1670 if( aCommit )
1671 aCommit->Revert();
1672}
1673
1674
1676{
1677 VECTOR2I centerlineOffset;
1678 VECTOR2I centerlineOffsetEnd;
1679
1680 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1681 {
1682 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1683 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1684 }
1685
1686 aPoints.AddPoint( m_origin + centerlineOffset );
1687 aPoints.AddPoint( m_end + centerlineOffsetEnd );
1688
1689 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1690 : SEG( m_origin, m_end );
1691
1692 base.A += centerlineOffset;
1693 base.B += centerlineOffset;
1694
1695 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1696
1697 if( m_tuningMode == DIFF_PAIR )
1698 amplitude += m_trackWidth + m_diffPairGap;
1699
1700 if( m_settings.m_initialSide == -1 )
1701 amplitude *= -1;
1702
1703 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1704
1705 aPoints.AddPoint( base.A + widthHandleOffset );
1706 aPoints.Point( 2 ).SetGridConstraint( IGNORE_GRID );
1707
1708 VECTOR2I spacingHandleOffset =
1709 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1710
1711 aPoints.AddPoint( base.A + spacingHandleOffset );
1712 aPoints.Point( 3 ).SetGridConstraint( IGNORE_GRID );
1713
1714 return true;
1715}
1716
1717
1719{
1720 VECTOR2I centerlineOffset;
1721 VECTOR2I centerlineOffsetEnd;
1722
1723 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1724 {
1725 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1726 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1727 }
1728
1729 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1730 : SEG( m_origin, m_end );
1731
1732 base.A += centerlineOffset;
1733 base.B += centerlineOffset;
1734
1735 m_origin = aEditPoints.Point( 0 ).GetPosition() - centerlineOffset;
1736 m_end = aEditPoints.Point( 1 ).GetPosition() - centerlineOffsetEnd;
1737
1738 if( aEditPoints.Point( 2 ).IsActive() )
1739 {
1740 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1741
1742 int value = base.LineDistance( wHandle );
1743
1744 value -= KiROUND( m_trackWidth / 2.0 );
1745
1746 if( m_tuningMode == DIFF_PAIR )
1747 value -= m_trackWidth + m_diffPairGap;
1748
1749 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1750
1751 int side = base.Side( wHandle );
1752
1753 if( side < 0 )
1755 else
1757 }
1758
1759 if( aEditPoints.Point( 3 ).IsActive() )
1760 {
1761 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1762 VECTOR2I sHandle = aEditPoints.Point( 3 ).GetPosition();
1763
1764 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1765
1766 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1767 }
1768
1769 return true;
1770}
1771
1772
1774{
1775 VECTOR2I centerlineOffset;
1776 VECTOR2I centerlineOffsetEnd;
1777
1778 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1779 {
1780 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1781 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1782 }
1783
1784 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1785 : SEG( m_origin, m_end );
1786
1787 base.A += centerlineOffset;
1788 base.B += centerlineOffset;
1789
1790 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1791
1792 if( m_tuningMode == DIFF_PAIR )
1793 amplitude += m_trackWidth + m_diffPairGap;
1794
1795 if( m_settings.m_initialSide == -1 )
1796 amplitude *= -1;
1797
1798 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1799
1800 aEditPoints.Point( 0 ).SetPosition( m_origin + centerlineOffset );
1801 aEditPoints.Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1802
1803 aEditPoints.Point( 2 ).SetPosition( base.A + widthHandleOffset );
1804
1805 VECTOR2I spacingHandleOffset =
1806 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1807
1808 aEditPoints.Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1809
1810 return true;
1811}
1812
1813
1815{
1816 if( m_baseLine )
1817 {
1818 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1819 int minAllowedAmplitude = 0;
1820 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1821
1823 {
1824 minAllowedAmplitude = baselineOffset + m_trackWidth;
1825 }
1826 else
1827 {
1828 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1829 minAllowedAmplitude = baselineOffset + correction;
1830 }
1831
1832 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1833
1835 {
1836 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1838
1839 if( m_tuningMode != DIFF_PAIR )
1840 {
1841 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1842
1844
1845 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left, right,
1846 true ) )
1847 {
1849 chain.Append( clBase.Reverse() );
1850 chain.SetClosed( true );
1851
1852 return chain;
1853 }
1854 }
1856 {
1857 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1858
1860 SHAPE_LINE_CHAIN chain1, chain2;
1861
1862 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left, right,
1863 true ) )
1864 {
1865 if( m_settings.m_initialSide >= 0 )
1866 chain1.Append( right );
1867 else
1868 chain1.Append( left );
1869
1870 if( clBase.OffsetLine( KiROUND( m_trackWidth / 2.0 ), CORNER_STRATEGY::ROUND_ALL_CORNERS,
1871 ARC_LOW_DEF, left, right, true ) )
1872 {
1873 if( m_settings.m_initialSide >= 0 )
1874 chain1.Append( left.Reverse() );
1875 else
1876 chain1.Append( right.Reverse() );
1877 }
1878
1879 chain1.SetClosed( true );
1880 }
1881
1882 if( clCoupled.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left, right,
1883 true ) )
1884 {
1885 if( m_settings.m_initialSide >= 0 )
1886 chain2.Append( right );
1887 else
1888 chain2.Append( left );
1889
1890 if( clCoupled.OffsetLine( KiROUND( m_trackWidth / 2.0 ), CORNER_STRATEGY::ROUND_ALL_CORNERS,
1891 ARC_LOW_DEF, left, right, true ) )
1892 {
1893 if( m_settings.m_initialSide >= 0 )
1894 chain2.Append( left.Reverse() );
1895 else
1896 chain2.Append( right.Reverse() );
1897 }
1898
1899 chain2.SetClosed( true );
1900 }
1901
1902 SHAPE_POLY_SET merged;
1903 merged.BooleanAdd( chain1, chain2 );
1904
1905 if( merged.OutlineCount() > 0 )
1906 return merged.Outline( 0 );
1907 }
1908 }
1909
1910 // Not single-sided / fallback
1911 SHAPE_POLY_SET poly;
1913
1914 int amplitude = 0;
1915
1916 if( m_tuningMode == DIFF_PAIR )
1917 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1918 else
1919 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1920
1921 poly.OffsetLineChain( *m_baseLine, amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, false );
1922
1924 {
1925 SHAPE_POLY_SET polyCoupled;
1926 polyCoupled.OffsetLineChain( *m_baseLineCoupled, amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1927 ARC_LOW_DEF, false );
1928
1929 poly.ClearArcs();
1930 polyCoupled.ClearArcs();
1931
1932 SHAPE_POLY_SET merged;
1933 merged.BooleanAdd( poly, polyCoupled );
1934
1935 if( merged.OutlineCount() > 0 )
1936 return merged.Outline( 0 );
1937 }
1938
1939 if( poly.OutlineCount() > 0 )
1940 return poly.Outline( 0 );
1941 }
1942
1943 return SHAPE_LINE_CHAIN();
1944}
1945
1946
1947void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1948{
1949 if( !IsSelected() && !IsNew() )
1950 return;
1951
1952 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1953
1954 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1955 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1956
1957 if( !HasFlag( IN_EDIT ) )
1958 {
1959 if( m_baseLine )
1960 {
1961 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1962 {
1963 SEG seg = m_baseLine->CSegment( i );
1964 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1965 }
1966 }
1967 else
1968 {
1969 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1970 }
1971
1973 {
1974 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1975 {
1976 SEG seg = m_baseLineCoupled->CSegment( i );
1977 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1978 }
1979 }
1980 }
1981
1983
1984 for( int i = 0; i < chain.SegmentCount(); i++ )
1985 {
1986 SEG seg = chain.Segment( i );
1987 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1988 }
1989}
1990
1991
1993{
1995
1996 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
1997 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
1998 props.set( "last_status", statusToString( m_tuningStatus ) );
1999 props.set( "is_time_domain", m_settings.m_isTimeDomain );
2000
2001 props.set( "end", m_end );
2002 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
2003 props.set( "single_sided", m_settings.m_singleSided );
2005
2006 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
2007 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
2008 props.set_iu( "min_spacing", m_settings.m_spacing );
2009 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
2010 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
2011 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
2012 props.set_iu( "target_delay_min", m_settings.m_targetLengthDelay.Min() );
2013 props.set_iu( "target_delay", m_settings.m_targetLengthDelay.Opt() );
2014 props.set_iu( "target_delay_max", m_settings.m_targetLengthDelay.Max() );
2015 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
2016 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
2017 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
2018 props.set_iu( "last_track_width", m_trackWidth );
2019 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
2020
2021 props.set( "last_netname", m_lastNetName );
2022 props.set( "last_tuning", m_tuningInfo );
2023 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
2024
2025 if( m_baseLine )
2026 props.set( "base_line", wxAny( *m_baseLine ) );
2027
2028 if( m_baseLineCoupled )
2029 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
2030
2031 return props;
2032}
2033
2034
2036{
2038
2039 wxString tuningMode;
2040 aProps.get_to( "tuning_mode", tuningMode );
2041 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
2042
2043 wxString side;
2044 aProps.get_to( "initial_side", side );
2045 m_settings.m_initialSide = sideFromString( side.utf8_string() );
2046
2047 wxString status;
2048 aProps.get_to( "last_status", status );
2049 m_tuningStatus = statusFromString( status.utf8_string() );
2050
2051 aProps.get_to( "is_time_domain", m_settings.m_isTimeDomain );
2052
2053 aProps.get_to( "end", m_end );
2054 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
2055 aProps.get_to( "single_sided", m_settings.m_singleSided );
2056 aProps.get_to( "side", m_settings.m_initialSide );
2057
2058 bool rounded = false;
2059 aProps.get_to( "rounded", rounded );
2061
2062 long long int val;
2063
2064 aProps.get_to_iu( "target_length", val );
2066
2067 if( aProps.get_to_iu( "target_length_min", val ) )
2069
2070 if( aProps.get_to_iu( "target_length_max", val ) )
2072
2073 aProps.get_to_iu( "target_delay", val );
2075
2076 if( aProps.get_to_iu( "target_delay_min", val ) )
2078
2079 if( aProps.get_to_iu( "target_delay_max", val ) )
2081
2082 int int_val;
2083
2084 aProps.get_to_iu( "target_skew", int_val );
2085 m_settings.SetTargetSkew( int_val );
2086
2087 if( aProps.get_to_iu( "target_skew_min", int_val ) )
2088 m_settings.m_targetSkew.SetMin( int_val );
2089
2090 if( aProps.get_to_iu( "target_skew_max", int_val ) )
2091 m_settings.m_targetSkew.SetMax( int_val );
2092
2093 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
2094 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
2095 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
2096 aProps.get_to_iu( "last_track_width", m_trackWidth );
2097 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
2098 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
2099
2100 aProps.get_to( "last_netname", m_lastNetName );
2101 aProps.get_to( "last_tuning", m_tuningInfo );
2102
2103 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
2104 m_baseLine = *baseLine;
2105
2106 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
2107 m_baseLineCoupled = *baseLineCoupled;
2108}
2109
2110
2112{
2114 DRC_CONSTRAINT constraint;
2115
2116 if( !m_items.empty() )
2117 {
2118 BOARD_ITEM* startItem = static_cast<BOARD_ITEM*>( *m_items.begin() );
2119 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
2120
2122 {
2123 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, startItem, nullptr, GetLayer() );
2124
2125 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
2126 {
2128 {
2129 settings.SetTargetLengthDelay( constraint.GetValue() );
2130 settings.SetTargetLength( MINOPTMAX<int>() );
2131 settings.m_isTimeDomain = true;
2132 }
2133 else
2134 {
2136 settings.SetTargetLength( constraint.GetValue() );
2137 settings.m_isTimeDomain = false;
2138 }
2139 }
2140 }
2141 else
2142 {
2143 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
2144
2145 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
2146 {
2148 {
2149 settings.SetTargetLengthDelay( constraint.GetValue() );
2150 settings.SetTargetLength( MINOPTMAX<int>() );
2151 settings.m_isTimeDomain = true;
2152 }
2153 else
2154 {
2156 settings.SetTargetLength( constraint.GetValue() );
2157 settings.m_isTimeDomain = false;
2158 }
2159 }
2160 }
2161 }
2162
2163 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
2164
2165 if( dlg.ShowModal() == wxID_OK )
2166 {
2167 BOARD_COMMIT commit( aEditFrame );
2168 commit.Modify( this );
2169 m_settings = settings;
2170
2171 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
2172 EditStart( generatorTool, GetBoard(), &commit );
2173 Update( generatorTool, GetBoard(), &commit );
2174 EditPush( generatorTool, GetBoard(), &commit );
2175 }
2176}
2177
2178
2180 PCB_BASE_EDIT_FRAME* aFrame,
2181 bool aStatusItemsOnly )
2182{
2183 std::vector<EDA_ITEM*> previewItems;
2184 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
2185
2186 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
2187 {
2188 if( !aStatusItemsOnly )
2189 {
2190 PNS::ITEM_SET items = placer->TunedPath();
2191
2192 for( PNS::ITEM* item : items )
2193 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item,
2194 aTool->Router()->GetInterface(),
2195 view, PNS_HOVER_ITEM ) );
2196 }
2197
2198 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
2199
2201 {
2204 else
2206 }
2207 else
2208 {
2210 {
2212 {
2213 statusItem->ClearMinMax();
2214 }
2215 else
2216 {
2217 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLengthDelay.Min() ),
2218 static_cast<double>( m_settings.m_targetLengthDelay.Max() ) );
2219 }
2220 }
2221 else
2222 {
2224 {
2225 statusItem->ClearMinMax();
2226 }
2227 else
2228 {
2229 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLength.Min() ),
2230 static_cast<double>( m_settings.m_targetLength.Max() ) );
2231 }
2232 }
2233 }
2234
2236
2238 {
2240 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current skew" ) );
2241 else
2242 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current skew" ) );
2243 }
2244 else
2245 {
2247 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current delay" ) );
2248 else
2249 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current length" ) );
2250 }
2251
2252 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
2253 previewItems.push_back( statusItem );
2254 }
2255
2256 return previewItems;
2257}
2258
2259
2261 std::vector<MSG_PANEL_ITEM>& aList )
2262{
2263 wxString msg;
2264 NETINFO_ITEM* primaryNet = nullptr;
2265 NETINFO_ITEM* coupledNet = nullptr;
2266 PCB_TRACK* primaryItem = nullptr;
2267 PCB_TRACK* coupledItem = nullptr;
2268 NETCLASS* netclass = nullptr;
2269 int width = 0;
2270 bool mixedWidth = false;
2271
2272 EDA_DATA_TYPE unitType = m_settings.m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
2273
2274 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2275
2276 for( EDA_ITEM* member : GetItems() )
2277 {
2278 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
2279 {
2280 if( !primaryNet )
2281 {
2282 primaryItem = track;
2283 primaryNet = track->GetNet();
2284 }
2285 else if( !coupledNet && track->GetNet() != primaryNet )
2286 {
2287 coupledItem = track;
2288 coupledNet = track->GetNet();
2289 }
2290
2291 if( !netclass )
2292 netclass = track->GetEffectiveNetClass();
2293
2294 if( !width )
2295 width = track->GetWidth();
2296 else if( width != track->GetWidth() )
2297 mixedWidth = true;
2298 }
2299 }
2300
2301 if( coupledNet )
2302 {
2303 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2304 + wxS( ", " )
2305 + UnescapeString( coupledNet->GetNetname() ) );
2306 }
2307 else if( primaryNet )
2308 {
2309 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2310 }
2311
2312 if( netclass )
2313 aList.emplace_back( _( "Resolved Netclass" ),
2314 UnescapeString( netclass->GetHumanReadableName() ) );
2315
2316 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
2317
2318 if( width && !mixedWidth )
2319 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2320
2321 BOARD* board = GetBoard();
2322 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2323 DRC_CONSTRAINT constraint;
2324
2325 // Display full track length (in Pcbnew)
2326 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2327 {
2328 int count = 0;
2329 double trackLen = 0.0;
2330 double lenPadToDie = 0.0;
2331 double trackDelay = 0.0;
2332 double delayPadToDie = 0.0;
2333
2334 std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *primaryItem );
2335
2336 if( coupledItem && coupledItem->GetNetCode() > 0 )
2337 {
2338 double coupledLen = 0.0;
2339 double coupledLenPadToDie = 0.0;
2340 double coupledTrackDelay = 0.0;
2341 double doubledDelayPadToDie = 0.0;
2342
2343 std::tie( count, coupledLen, coupledLenPadToDie, coupledTrackDelay, doubledDelayPadToDie ) =
2344 board->GetTrackLength( *coupledItem );
2345
2346 if( trackDelay == 0.0 || coupledTrackDelay == 0.0 )
2347 {
2348 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen ) + wxS( ", " )
2349 + aFrame->MessageTextFromValue( coupledLen ) );
2350 }
2351 else
2352 {
2353 aList.emplace_back(
2354 _( "Routed Delays" ),
2355 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) + wxS( ", " )
2356 + aFrame->MessageTextFromValue( coupledTrackDelay, true, EDA_DATA_TYPE::TIME ) );
2357 }
2358 }
2359 else
2360 {
2361 if( trackDelay == 0.0 )
2362 {
2363 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2364 }
2365 else
2366 {
2367 aList.emplace_back( _( "Routed Delay" ),
2368 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) );
2369 }
2370 }
2371
2372 if( lenPadToDie != 0 && delayPadToDie == 0.0 )
2373 {
2374 msg = aFrame->MessageTextFromValue( lenPadToDie );
2375 aList.emplace_back( _( "Pad To Die Length" ), msg );
2376
2377 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2378 aList.emplace_back( _( "Full Length" ), msg );
2379 }
2380 else if( delayPadToDie > 0.0 )
2381 {
2382 msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME );
2383 aList.emplace_back( _( "Pad To Die Delay" ), msg );
2384
2385 msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME );
2386 aList.emplace_back( _( "Full Delay" ), msg );
2387 }
2388 }
2389
2391 {
2392 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2393
2394 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2395 {
2397
2398 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2399 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2400 }
2401 else
2402 {
2403 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2404
2405 if( !msg.IsEmpty() )
2406 {
2407 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2408 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2409 }
2410 }
2411 }
2412 else
2413 {
2414 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2415
2416 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2417 {
2418 wxString caption;
2419
2421 {
2422 caption = _( "Target Delay: %s" );
2423 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLengthDelay.Opt() ), true,
2424 EDA_DATA_TYPE::TIME );
2425 }
2426 else
2427 {
2428 caption = _( "Target Length: %s" );
2429 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLength.Opt() ) );
2430 }
2431
2432 aList.emplace_back( wxString::Format( caption, msg ),
2433 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2434 }
2435 else
2436 {
2437 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue(), unitType );
2438
2439 wxString caption = m_settings.m_isTimeDomain ? _( "Delay Constraints: %s" ) : _( "Length Constraints: %s" );
2440
2441 if( !msg.IsEmpty() )
2442 {
2443 aList.emplace_back( wxString::Format( caption, msg ),
2444 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2445 }
2446 }
2447 }
2448}
2449
2450
2451const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2452const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2453
2454
2456
2457
2458#define HITTEST_THRESHOLD_PIXELS 5
2459
2460
2462{
2463 // TODO: (JJ) Reserving before v9 string freeze
2464 wxLogDebug( _( "Tune Skew" ) );
2465
2467 return 0;
2468
2469 if( m_inDrawingTool )
2470 return 0;
2471
2473
2475
2476 m_frame->PushTool( aEvent );
2477 Activate();
2478
2481 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
2482 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2483 PNS::ROUTER* router = generatorTool->Router();
2484 PNS::ROUTER_MODE routerMode = aEvent.Parameter<PNS::ROUTER_MODE>();
2485 LENGTH_TUNING_MODE mode = fromPNSMode( routerMode );
2486 PNS::MEANDER_SETTINGS meanderSettings;
2487
2488 switch( mode )
2489 {
2490 case LENGTH_TUNING_MODE::SINGLE: meanderSettings = bds.m_SingleTrackMeanderSettings; break;
2491 case DIFF_PAIR: meanderSettings = bds.m_DiffPairMeanderSettings; break;
2492 case DIFF_PAIR_SKEW: meanderSettings = bds.m_SkewMeanderSettings; break;
2493 }
2494
2498 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2499
2500 m_pickerItem = nullptr;
2501 m_tuningPattern = nullptr;
2502
2503 // Add a VIEW_GROUP that serves as a preview for the new item
2504 m_preview.Clear();
2505 m_view->Add( &m_preview );
2506
2507 auto setCursor =
2508 [&]()
2509 {
2510 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
2511 controls->ShowCursor( true );
2512 };
2513
2514 auto applyCommonSettings =
2515 [&]( PCB_TUNING_PATTERN* aPattern )
2516 {
2517 const auto& origTargetLength = aPattern->GetSettings().m_targetLength;
2518 const auto& origTargetSkew = aPattern->GetSettings().m_targetSkew;
2519
2520 aPattern->GetSettings() = meanderSettings;
2521
2522 if( meanderSettings.m_targetLength.IsNull() )
2523 aPattern->GetSettings().m_targetLength = origTargetLength;
2524
2525 if( meanderSettings.m_targetSkew.IsNull() )
2526 aPattern->GetSettings().m_targetSkew = origTargetSkew;
2527 };
2528
2529 auto updateHoverStatus =
2530 [&]()
2531 {
2532 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2533
2534 if( m_pickerItem )
2535 {
2536 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2537 m_pickerItem, mode ) );
2538 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2539 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2540 }
2541
2542 if( dummyPattern )
2543 {
2544 applyCommonSettings( dummyPattern.get() );
2545
2546 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2547 dummyPattern->Update( generatorTool, m_board, nullptr );
2548
2550
2551 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2552 m_preview.Add( item );
2553
2554 generatorTool->Router()->StopRouting();
2555
2556 m_view->Update( &m_preview );
2557 }
2558 else
2559 {
2560
2562 m_view->Update( &m_preview );
2563 }
2564 };
2565
2566 auto updateTuningPattern =
2567 [&]()
2568 {
2570 {
2571 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2572 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2573
2575
2576 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame, true ) )
2577 m_preview.Add( item );
2578
2579 m_view->Update( &m_preview );
2580 }
2581 };
2582
2583 // Set initial cursor
2584 setCursor();
2585
2586 while( TOOL_EVENT* evt = Wait() )
2587 {
2588 setCursor();
2589 VECTOR2D cursorPos = controls->GetMousePosition();
2590
2591 if( evt->IsCancelInteractive() || evt->IsActivate()
2592 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2593 {
2594 if( m_tuningPattern )
2595 {
2596 // First click already made; clean up tuning pattern preview
2597 m_tuningPattern->EditRevert( generatorTool, m_board, nullptr );
2598
2599 delete m_tuningPattern;
2600 m_tuningPattern = nullptr;
2601 }
2602 else
2603 {
2604 break;
2605 }
2606 }
2607 else if( evt->IsMotion() )
2608 {
2609 if( !m_tuningPattern )
2610 {
2611 // First click not yet made; we're in highlight-net-under-cursor mode
2612
2613 GENERAL_COLLECTOR collector;
2614 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2615
2616 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2617 guide.SetIncludeSecondary( false );
2618 else
2619 guide.SetIncludeSecondary( true );
2620
2621 guide.SetPreferredLayer( m_frame->GetActiveLayer() );
2622
2623 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2624
2625 if( collector.GetCount() > 1 )
2626 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2627
2628 m_pickerItem = nullptr;
2629
2630 if( collector.GetCount() > 0 )
2631 {
2632 double min_dist_sq = std::numeric_limits<double>::max();
2633
2634 for( EDA_ITEM* candidate : collector )
2635 {
2636 VECTOR2I candidatePos;
2637
2638 if( candidate->Type() == PCB_TRACE_T )
2639 {
2640 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2641 }
2642 else if( candidate->Type() == PCB_ARC_T )
2643 {
2644 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2645 }
2646
2647 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2648
2649 if( dist_sq < min_dist_sq )
2650 {
2651 min_dist_sq = dist_sq;
2652 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2653 }
2654 }
2655 }
2656
2657 updateHoverStatus();
2658 }
2659 else
2660 {
2661 // First click already made; we're in preview-tuning-pattern mode
2662
2663 m_tuningPattern->SetEnd( cursorPos );
2665
2666 updateTuningPattern();
2667 }
2668 }
2669 else if( evt->IsClick( BUT_LEFT ) )
2670 {
2672 {
2673 // First click; create a tuning pattern
2674
2675 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2676 {
2677 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2678 "tuning patterns." ) );
2679 }
2680 else
2681 {
2683
2686 m_pickerItem, mode );
2687
2688 applyCommonSettings( m_tuningPattern );
2689
2690 int dummyDist;
2691 int dummyClearance = std::numeric_limits<int>::max() / 2;
2692 VECTOR2I closestPt;
2693
2694 // With an artificially-large clearance this can't *not* collide, but the
2695 // if stmt keeps Coverity happy....
2696 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2697 &dummyDist, &closestPt ) )
2698 {
2699 m_tuningPattern->SetPosition( closestPt );
2700 m_tuningPattern->SetEnd( closestPt );
2701 }
2702
2704 }
2705 }
2706 else if( m_pickerItem && m_tuningPattern )
2707 {
2708 // Second click; we're done
2709 BOARD_COMMIT commit( m_frame );
2710
2711 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2712 m_tuningPattern->Update( generatorTool, m_board, &commit );
2713 m_tuningPattern->EditPush( generatorTool, m_board, &commit, _( "Tune" ) );
2714
2715 m_tuningPattern = nullptr;
2716 m_pickerItem = nullptr;
2717 }
2718 }
2719 else if( evt->IsClick( BUT_RIGHT ) )
2720 {
2722 m_menu->ShowContextMenu( dummy );
2723 }
2724 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2725 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2726 {
2727 if( m_tuningPattern )
2728 {
2729 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2730
2731 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2732 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2733 meanderSettings.m_spacing = placer->MeanderSettings().m_spacing;
2734
2735 updateTuningPattern();
2736 }
2737 else
2738 {
2739 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2740 }
2741 }
2742 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2743 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2744 {
2745 if( m_tuningPattern )
2746 {
2747 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2748
2749 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2750 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2751 meanderSettings.m_maxAmplitude = placer->MeanderSettings().m_maxAmplitude;
2752
2753 updateTuningPattern();
2754 }
2755 else
2756 {
2757 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2758 }
2759 }
2760 else if( evt->IsAction( &PCB_ACTIONS::properties )
2761 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2762 {
2763 DRC_CONSTRAINT constraint;
2764
2765 if( m_tuningPattern )
2766 {
2767 if( !m_tuningPattern->GetItems().empty() )
2768 {
2769 BOARD_ITEM* startItem = *m_tuningPattern->GetBoardItems().begin();
2770
2771 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2772 startItem->GetLayer() );
2773 }
2774 }
2775
2776 DIALOG_TUNING_PATTERN_PROPERTIES dlg( m_frame, meanderSettings, routerMode, constraint );
2777
2778 if( dlg.ShowModal() == wxID_OK )
2779 {
2780 if( m_tuningPattern )
2781 applyCommonSettings( m_tuningPattern );
2782
2783 updateTuningPattern();
2784 }
2785 }
2786 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2787 // but we don't at present have that, so we just knock out some of the egregious ones.
2788 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2789 {
2790 wxBell();
2791 }
2792 else
2793 {
2794 evt->SetPassEvent();
2795 }
2796
2797 controls->CaptureCursor( m_tuningPattern != nullptr );
2798 controls->SetAutoPan( m_tuningPattern != nullptr );
2799 }
2800
2801 controls->CaptureCursor( false );
2802 controls->SetAutoPan( false );
2803 controls->ForceCursorPosition( false );
2804 controls->ShowCursor( false );
2805 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2806
2808 m_view->Remove( &m_preview );
2809
2811
2812 if( m_tuningPattern )
2813 selectionTool->AddItemToSel( m_tuningPattern );
2814
2815 m_frame->PopTool( aEvent );
2816 return 0;
2817}
2818
2819
2821{
2823 {
2825 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2826 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2827 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2828
2830 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2831 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2832 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2833
2840
2841 const wxString groupTab = _HKI( "Pattern Properties" );
2842
2844 _HKI( "End X" ), &PCB_TUNING_PATTERN::SetEndX,
2845 &PCB_TUNING_PATTERN::GetEndX, PROPERTY_DISPLAY::PT_SIZE,
2847 groupTab );
2848
2850 _HKI( "End Y" ), &PCB_TUNING_PATTERN::SetEndY,
2851 &PCB_TUNING_PATTERN::GetEndY, PROPERTY_DISPLAY::PT_SIZE,
2853 groupTab );
2854
2856 _HKI( "Tuning Mode" ),
2859 groupTab );
2860
2862 _HKI( "Min Amplitude" ),
2865 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2866 groupTab );
2867
2869 _HKI( "Max Amplitude" ),
2872 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2873 groupTab );
2874
2876 _HKI( "Initial Side" ),
2879 groupTab );
2880
2882 _HKI( "Min Spacing" ), &PCB_TUNING_PATTERN::SetSpacing,
2883 &PCB_TUNING_PATTERN::GetSpacing, PROPERTY_DISPLAY::PT_SIZE,
2885 groupTab );
2886
2888 _HKI( "Corner Radius %" ),
2891 PROPERTY_DISPLAY::PT_DEFAULT, ORIGIN_TRANSFORMS::NOT_A_COORD ),
2892 groupTab );
2893
2894 auto isSkew =
2895 []( INSPECTABLE* aItem ) -> bool
2896 {
2897 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2898 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2899
2900 return false;
2901 };
2902
2903 auto isTimeDomain = []( INSPECTABLE* aItem ) -> bool
2904 {
2905 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2906 return pattern->GetSettings().m_isTimeDomain;
2907
2908 return false;
2909 };
2910
2911 auto isLengthIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2912 {
2913 return !isSkew( aItem ) && !isTimeDomain( aItem );
2914 };
2915
2916 auto isLengthIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2917 {
2918 return !isSkew( aItem ) && isTimeDomain( aItem );
2919 };
2920
2921 auto isSkewIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2922 {
2923 return isSkew( aItem ) && !isTimeDomain( aItem );
2924 };
2925
2926 auto isSkewIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2927 {
2928 return isSkew( aItem ) && isTimeDomain( aItem );
2929 };
2930
2931 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2932 _HKI( "Target Length" ), &PCB_TUNING_PATTERN::SetTargetLength,
2933 &PCB_TUNING_PATTERN::GetTargetLength, PROPERTY_DISPLAY::PT_SIZE,
2935 groupTab )
2936 .SetAvailableFunc( isLengthIsSpaceDomain );
2937
2938 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2939 _HKI( "Target Delay" ), &PCB_TUNING_PATTERN::SetTargetDelay,
2940 &PCB_TUNING_PATTERN::GetTargetDelay, PROPERTY_DISPLAY::PT_TIME,
2942 groupTab )
2943 .SetAvailableFunc( isLengthIsTimeDomain );
2944
2946 _HKI( "Target Skew" ), &PCB_TUNING_PATTERN::SetTargetSkew,
2947 &PCB_TUNING_PATTERN::GetTargetSkew, PROPERTY_DISPLAY::PT_SIZE,
2949 groupTab )
2950 .SetAvailableFunc( isSkewIsSpaceDomain );
2951
2953 _HKI( "Target Skew Delay" ), &PCB_TUNING_PATTERN::SetTargetSkewDelay,
2954 &PCB_TUNING_PATTERN::GetTargetSkewDelay, PROPERTY_DISPLAY::PT_TIME,
2956 groupTab )
2957 .SetAvailableFunc( isSkewIsTimeDomain );
2958
2960 _HKI( "Override Custom Rules" ),
2963 groupTab );
2964
2966 _HKI( "Single-sided" ),
2969 groupTab );
2970
2972 _HKI( "Rounded" ), &PCB_TUNING_PATTERN::SetRounded,
2974 groupTab );
2975 }
2977
2980
2982
2983// Also register under the 7.99 name
2984template <typename T>
2986{
2988 {
2989 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2990 []()
2991 {
2992 return new T;
2993 } );
2994 }
2995};
2996
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
constexpr int ARC_LOW_DEF
Definition: base_units.h:128
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:221
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:232
PCB_LAYER_ID m_layer
Definition: board_item.h:453
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:326
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:79
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:207
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition: board.cpp:2168
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:2470
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:2099
const TRACKS & Tracks() const
Definition: board.h:356
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1024
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:83
int m_Threshold
Definition: collector.h:236
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:91
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition: commit.h:107
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:79
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:168
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:160
bool GetOption(OPTIONS option) const
Definition: drc_rule.h:193
bool IsNull() const
Definition: drc_rule.h:155
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:77
std::unordered_set< EDA_ITEM * > m_items
Definition: eda_group.h:76
std::unordered_set< EDA_ITEM * > & GetItems()
Definition: eda_group.h:54
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition: eda_group.cpp:27
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
virtual const VECTOR2I GetFocusPosition() const
Similar to GetPosition() but allows items to return their visual center rather than their anchor.
Definition: eda_item.h:279
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:142
virtual EDA_GROUP * GetParentGroup() const
Definition: eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:144
bool IsSelected() const
Definition: eda_item.h:127
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:146
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:145
bool IsNew() const
Definition: eda_item.h:124
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:697
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:349
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:324
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:207
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:505
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:218
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:66
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:341
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:1685
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:202
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:467
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1633
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:168
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:200
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:201
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:202
static TOOL_ACTION lengthTunerSettings
Definition: pcb_actions.h:203
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:199
const VECTOR2I & GetMid() const
Definition: pcb_track.h:345
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...
virtual PCB_LAYER_ID GetActiveLayer() const
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:350
std::unordered_set< BOARD_ITEM * > GetBoardItems() const
Definition: pcb_group.cpp:98
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.
bool HitTest(const SHAPE_LINE_CHAIN &aPoly, bool aContained) const override
Test if aPoly intersects this item.
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:151
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:74
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:76
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:719
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:606
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:98
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 VECTOR2I & CLastPoint() const
Return the last point in the 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.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
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)
#define _HKI(x)
@ LENGTH_CONSTRAINT
Definition: drc_rule.h:71
@ SKEW_CONSTRAINT
Definition: drc_rule.h:72
#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
a few functions useful in geometry calculations.
@ LAYER_UI_START
Definition: layer_ids.h:348
@ 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
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
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:808
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:799
#define REGISTER_TYPE(x)
Definition: property_mgr.h:351
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:92
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