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 (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <pcb_generator.h>
26#include <generators_mgr.h>
27
28#include <optional>
29#include <magic_enum.hpp>
30
31#include <wx/debug.h>
34#include <kiplatform/ui.h>
36#include <collectors.h>
37#include <scoped_set_reset.h>
38#include <core/mirror.h>
39
41#include <drc/drc_engine.h>
42#include <pcb_track.h>
43#include <pcb_shape.h>
44#include <pcb_group.h>
45
46#include <tool/edit_points.h>
47#include <tools/drawing_tool.h>
52
55#include <view/view.h>
56#include <view/view_controls.h>
57
60#include <router/pns_meander.h>
62#include <router/pns_segment.h>
63#include <router/pns_arc.h>
64#include <router/pns_solid.h>
65#include <router/pns_topology.h>
67
69
70
72{
76};
77
78
80{
81public:
83 EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
84 m_frame( aFrame ),
85 m_min( 0.0 ),
86 m_max( 0.0 ),
87 m_current( 0.0 )
88 { }
89
90 wxString GetClass() const override { return wxT( "TUNING_STATUS" ); }
91
92#if defined(DEBUG)
93 void Show( int nestLevel, std::ostream& os ) const override {}
94#endif
95
96 VECTOR2I GetPosition() const override { return m_pos; }
97 void SetPosition( const VECTOR2I& aPos ) override { m_pos = aPos; };
98
99 void SetMinMax( double aMin, double aMax )
100 {
101 m_min = aMin;
103 m_max = aMax;
105 }
106
108 {
109 m_min = 0.0;
110 m_minText = wxT( "---" );
111 m_max = std::numeric_limits<double>::max();
112 m_maxText = wxT( "---" );
113 }
114
115 void SetCurrent( double aCurrent, const wxString& aLabel )
116 {
117 m_current = aCurrent;
119 m_currentLabel = aLabel;
120 }
121
122 const BOX2I ViewBBox() const override
123 {
124 BOX2I tmp;
125
126 // this is an edit-time artefact; no reason to try and be smart with the bounding box
127 // (besides, we can't tell the text extents without a view to know what the scale is)
128 tmp.SetMaximum();
129 return tmp;
130 }
131
132 void ViewGetLayers( int aLayers[], int& aCount ) const override
133 {
134 aLayers[0] = LAYER_UI_START;
135 aLayers[1] = LAYER_UI_START + 1;
136 aCount = 2;
137 }
138
139 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override
140 {
141 KIGFX::GAL* gal = aView->GetGAL();
142 bool viewFlipped = gal->IsFlippedX();
143 bool drawingDropShadows = ( aLayer == LAYER_UI_START );
144
145 gal->Save();
146 gal->Scale( { 1., 1. } );
147
151 const KIFONT::METRICS& fontMetrics = KIFONT::METRICS::Default();
152 TEXT_ATTRIBUTES textAttrs;
153
154 int glyphWidth = textDims.GlyphSize.x;
155 VECTOR2I margin( KiROUND( glyphWidth * 0.4 ), KiROUND( glyphWidth ) );
156 VECTOR2I size( glyphWidth * 25 + margin.x * 2, headerDims.GlyphSize.y + textDims.GlyphSize.y );
157 VECTOR2I offset( margin.x * 2, -( size.y + margin.y * 2 ) );
158
159 if( drawingDropShadows )
160 {
161 gal->SetIsFill( true );
162 gal->SetIsStroke( true );
163 gal->SetLineWidth( gal->GetScreenWorldMatrix().GetScale().x * 2 );
164 gal->SetStrokeColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) );
165 KIGFX::COLOR4D bgColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
166 gal->SetFillColor( bgColor.WithAlpha( 0.9 ) );
167
168 gal->DrawRectangle( GetPosition() + offset - margin,
169 GetPosition() + offset + size + margin );
170 gal->Restore();
171 return;
172 }
173
174 COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
175 COLOR4D normal = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
176 COLOR4D red;
177
178 // Choose a red with reasonable contrasting with the background
179 double bg_h, bg_s, bg_l;
180 bg.ToHSL( bg_h, bg_s, bg_l );
181 red.FromHSL( 0, 1.0, bg_l < 0.5 ? 0.7 : 0.3 );
182
183 if( viewFlipped )
185 else
186 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
187
188 gal->SetIsFill( false );
189 gal->SetIsStroke( true );
190 gal->SetStrokeColor( normal );
191 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
192
193 // Prevent text flipping when view is flipped
194 if( gal->IsFlippedX() )
195 {
196 textAttrs.m_Mirrored = true;
198 }
199
200 textAttrs.m_Size = headerDims.GlyphSize;
201 textAttrs.m_StrokeWidth = headerDims.StrokeWidth;
202
203 VECTOR2I textPos = GetPosition() + offset;
204 font->Draw( gal, m_currentLabel, textPos, textAttrs, KIFONT::METRICS::Default() );
205
206 textPos.x += glyphWidth * 11 + margin.x;
207 font->Draw( gal, _( "min" ), textPos, textAttrs, fontMetrics );
208
209 textPos.x += glyphWidth * 7 + margin.x;
210 font->Draw( gal, _( "max" ), textPos, textAttrs, fontMetrics );
211
212 textAttrs.m_Size = textDims.GlyphSize;
213 textAttrs.m_StrokeWidth = textDims.StrokeWidth;
214
215 textPos = GetPosition() + offset;
216 textPos.y += KiROUND( headerDims.LinePitch * 1.3 );
217 font->Draw( gal, m_currentText, textPos, textAttrs, KIFONT::METRICS::Default() );
218
219 textPos.x += glyphWidth * 11 + margin.x;
221 font->Draw( gal, m_minText, textPos, textAttrs, fontMetrics );
222
223 textPos.x += glyphWidth * 7 + margin.x;
225 font->Draw( gal, m_maxText, textPos, textAttrs, fontMetrics );
226
227 gal->Restore();
228 }
229
230protected:
233 double m_min;
234 double m_max;
235 double m_current;
238 wxString m_minText;
239 wxString m_maxText;
240};
241
242
244{
245public:
246 static const wxString GENERATOR_TYPE;
247 static const wxString DISPLAY_NAME;
248
249 PCB_TUNING_PATTERN( BOARD_ITEM* aParent = nullptr, PCB_LAYER_ID aLayer = F_Cu,
250 LENGTH_TUNING_MODE aMode = LENGTH_TUNING_MODE::SINGLE );
251
252 wxString GetGeneratorType() const override { return wxS( "tuning_pattern" ); }
253
254 wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override
255 {
256 return wxString( _( "Tuning Pattern" ) );
257 }
258
259 wxString GetFriendlyName() const override
260 {
261 return wxString( _( "Tuning Pattern" ) );
262 }
263
264 wxString GetPluralName() const override
265 {
266 return wxString( _( "Tuning Patterns" ) );
267 }
268
270 BOARD_CONNECTED_ITEM* aStartItem,
271 LENGTH_TUNING_MODE aMode );
272
273 void EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
274
275 bool Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
276
277 void EditPush( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit,
278 const wxString& aCommitMsg = wxEmptyString, int aCommitFlags = 0 ) override;
279
280 void EditRevert( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
281
282 void Remove( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
283
284 bool MakeEditPoints( std::shared_ptr<EDIT_POINTS> points ) const override;
285
286 bool UpdateFromEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints,
287 BOARD_COMMIT* aCommit ) override;
288
289 bool UpdateEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints ) override;
290
291 void Move( const VECTOR2I& aMoveVector ) override
292 {
293 if( !this->HasFlag( IN_EDIT ) )
294 {
295 PCB_GENERATOR::Move( aMoveVector );
296 m_end += aMoveVector;
297
298 if( m_baseLine )
299 m_baseLine->Move( aMoveVector );
300
302 m_baseLineCoupled->Move( aMoveVector );
303 }
304 }
305
306 void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override
307 {
308 if( !this->HasFlag( IN_EDIT ) )
309 {
310 PCB_GENERATOR::Rotate( aRotCentre, aAngle );
311 RotatePoint( m_end, aRotCentre, aAngle );
312
313 if( m_baseLine )
314 m_baseLine->Rotate( aAngle, aRotCentre );
315
317 m_baseLineCoupled->Rotate( aAngle, aRotCentre );
318 }
319 }
320
321 void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override
322 {
323 if( !this->HasFlag( IN_EDIT ) )
324 {
325 PCB_GENERATOR::Flip( aCentre, aFlipLeftRight );
326
327 if( aFlipLeftRight )
328 MIRROR( m_end.x, aCentre.x );
329 else
330 MIRROR( m_end.y, aCentre.y );
331
332 if( m_baseLine )
333 m_baseLine->Mirror( aFlipLeftRight, !aFlipLeftRight, aCentre );
334
336 m_baseLineCoupled->Mirror( aFlipLeftRight, !aFlipLeftRight, aCentre );
337 }
338 }
339
340 const BOX2I GetBoundingBox() const override
341 {
342 return getOutline().BBox();
343 }
344
345 void ViewGetLayers( int aLayers[], int& aCount ) const override
346 {
347 aCount = 0;
348 aLayers[aCount++] = LAYER_ANCHOR;
349 aLayers[aCount++] = GetLayer();
350 }
351
352 bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
353 {
354 return getOutline().Collide( aPosition, aAccuracy );
355 }
356
357 bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
358 {
359 BOX2I sel = aRect;
360
361 if ( aAccuracy )
362 sel.Inflate( aAccuracy );
363
364 if( aContained )
365 return sel.Contains( GetBoundingBox() );
366
367 return sel.Intersects( GetBoundingBox() );
368 }
369
370 const BOX2I ViewBBox() const override { return GetBoundingBox(); }
371
372 EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
373
374 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
375
376 const VECTOR2I& GetEnd() const { return m_end; }
377 void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
378
379 int GetEndX() const { return m_end.x; }
380 void SetEndX( int aValue ) { m_end.x = aValue; }
381
382 int GetEndY() const { return m_end.y; }
383 void SetEndY( int aValue ) { m_end.y = aValue; }
384
386
388 {
389 switch( m_tuningMode )
390 {
391 case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
392 case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
393 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
394 default: return PNS::PNS_MODE_TUNE_SINGLE;
395 }
396 }
397
399
401 void SetMinAmplitude( int aValue )
402 {
403 aValue = std::max( aValue, 0 );
404
405 m_settings.m_minAmplitude = aValue;
406
409 }
410
412 void SetMaxAmplitude( int aValue )
413 {
414 aValue = std::max( aValue, 0 );
415
416 m_settings.m_maxAmplitude = aValue;
417
420 }
421
424
425 int GetSpacing() const { return m_settings.m_spacing; }
426 void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
427
428 std::optional<int> GetTargetLength() const
429 {
431 return std::optional<int>();
432 else
434 }
435
436 void SetTargetLength( std::optional<int> aValue )
437 {
438 if( aValue.has_value() )
439 m_settings.SetTargetLength( aValue.value() );
440 else
442 }
443
444 int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
445 void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
446
448 void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
449
452
453 bool IsSingleSided() const { return m_settings.m_singleSided; }
454 void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
455
459
460 std::vector<std::pair<wxString, wxVariant>> GetRowData() override
461 {
462 std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
463 data.emplace_back( _HKI( "Net" ), m_lastNetName );
464 data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
465 return data;
466 }
467
468 const STRING_ANY_MAP GetProperties() const override;
469 void SetProperties( const STRING_ANY_MAP& aProps ) override;
470
471 void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
472
473 std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
474 bool aStatusItemsOnly = false ) override;
475
476 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
477
478protected:
479 void swapData( BOARD_ITEM* aImage ) override
480 {
481 wxASSERT( aImage->Type() == PCB_GENERATOR_T );
482
483 std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
484 }
485
486 bool recoverBaseline( PNS::ROUTER* aRouter );
487
488 bool baselineValid();
489
490 bool initBaseLine( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard, VECTOR2I& aStart,
491 VECTOR2I& aEnd, NETINFO_ITEM* aNet,
492 std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
493
494 bool initBaseLines( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard );
495
496 bool removeToBaseline( PNS::ROUTER* aRouter, int aLayer, SHAPE_LINE_CHAIN& aBaseLine );
497
498 bool resetToBaseline( GENERATOR_TOOL* aTool, int aLayer, SHAPE_LINE_CHAIN& aBaseLine,
499 bool aPrimary );
500
502
503protected:
505
507
508 std::optional<SHAPE_LINE_CHAIN> m_baseLine;
509 std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
510
513
515
517 wxString m_tuningInfo;
518
520};
521
522
523static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
524{
525 if( aStr == "single" )
527 else if( aStr == "diff_pair" )
529 else if( aStr == "diff_pair_skew" )
531 else
532 {
533 wxFAIL_MSG( wxS( "Unknown length tuning token" ) );
535 }
536}
537
538
539static std::string tuningToString( const LENGTH_TUNING_MODE aTuning )
540{
541 switch( aTuning )
542 {
543 case LENGTH_TUNING_MODE::SINGLE: return "single";
544 case LENGTH_TUNING_MODE::DIFF_PAIR: return "diff_pair";
545 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return "diff_pair_skew";
546 default: wxFAIL; return "";
547 }
548}
549
550
552{
553 switch( aRouterMode )
554 {
558 default: return LENGTH_TUNING_MODE::SINGLE;
559 }
560}
561
562
563static PNS::MEANDER_SIDE sideFromString( const std::string& aStr )
564{
565 if( aStr == "default" )
567 else if( aStr == "left" )
569 else if( aStr == "right" )
571 else
572 {
573 wxFAIL_MSG( wxS( "Unknown length-tuning side token" ) );
575 }
576}
577
578
580{
581 switch( aStatus )
582 {
583 case PNS::MEANDER_PLACER_BASE::TOO_LONG: return "too_long";
584 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: return "too_short";
585 case PNS::MEANDER_PLACER_BASE::TUNED: return "tuned";
586 default: wxFAIL; return "";
587 }
588}
589
590
592{
593 if( aStr == "too_long" )
595 else if( aStr == "too_short" )
597 else if( aStr == "tuned" )
599 else
600 {
601 wxFAIL_MSG( wxS( "Unknown tuning status token" ) );
603 }
604}
605
606
607static std::string sideToString( const PNS::MEANDER_SIDE aValue )
608{
609 switch( aValue )
610 {
611 case PNS::MEANDER_SIDE_DEFAULT: return "default";
612 case PNS::MEANDER_SIDE_LEFT: return "left";
613 case PNS::MEANDER_SIDE_RIGHT: return "right";
614 default: wxFAIL; return "";
615 }
616}
617
618
620 LENGTH_TUNING_MODE aMode ) :
621 PCB_GENERATOR( aParent, aLayer ),
622 m_trackWidth( 0 ),
623 m_diffPairGap( 0 ),
624 m_tuningMode( aMode ),
625 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED )
626{
629 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
631}
632
633
634static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
635 PCB_TRACK** aNearestTrack )
636{
638 VECTOR2I closestPt = aP;
639
640 for( PCB_TRACK *track : aBoard->Tracks() )
641 {
642 if( aNet && track->GetNet() != aNet )
643 continue;
644
645 VECTOR2I nearest;
646
647 if( track->Type() == PCB_ARC_T )
648 {
649 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
650 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
651 pcbArc->GetWidth() );
652
653 nearest = arc.NearestPoint( aP );
654 }
655 else
656 {
657 SEG seg( track->GetStart(), track->GetEnd() );
658 nearest = seg.NearestPoint( aP );
659 }
660
661 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
662
663 if( dist_sq < minDist_sq )
664 {
665 minDist_sq = dist_sq;
666 closestPt = nearest;
667
668 if( aNearestTrack )
669 *aNearestTrack = track;
670 }
671 }
672
673 return closestPt;
674}
675
676
678{
680 {
681 return( m_baseLine && m_baseLine->PointCount() > 1
682 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
683 }
684 else
685 {
686 return( m_baseLine && m_baseLine->PointCount() > 1 );
687 }
688}
689
690
692 PCB_BASE_EDIT_FRAME* aFrame,
693 BOARD_CONNECTED_ITEM* aStartItem,
694 LENGTH_TUNING_MODE aMode )
695{
696 BOARD* board = aStartItem->GetBoard();
698 DRC_CONSTRAINT constraint;
699 PCB_LAYER_ID layer = aStartItem->GetLayer();
700
701 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
702
703 switch( aMode )
704 {
705 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
706 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
707 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
708 }
709
710 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
711
712 if( !constraint.IsNull() )
713 {
714 if( aMode == DIFF_PAIR_SKEW )
715 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
716 else
717 pattern->m_settings.SetTargetLength( constraint.GetValue() );
718 }
719
720 pattern->SetFlags( IS_NEW );
721
722 return pattern;
723}
724
726{
727 if( aCommit )
728 {
729 if( IsNew() )
730 aCommit->Add( this );
731 else
732 aCommit->Modify( this );
733 }
734
735 SetFlags( IN_EDIT );
736
737 int layer = GetLayer();
738 PNS::ROUTER* router = aTool->Router();
739
740 aTool->ClearRouterChanges();
741 router->SyncWorld();
742
744 PNS::CONSTRAINT constraint;
745
746 if( !baselineValid() )
747 initBaseLines( router, layer, aBoard );
748
750 {
751 PCB_TRACK* track = nullptr;
752 PNS::SEGMENT pnsItem;
753
754 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
755 wxCHECK( track, /* void */ );
756
757 NETINFO_ITEM* net = track->GetNet();
758
759 pnsItem.SetParent( track );
760 pnsItem.SetNet( net );
761
762 if( m_tuningMode == SINGLE )
763 {
764 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
765 &pnsItem, nullptr, layer, &constraint ) )
766 {
767 m_settings.SetTargetLength( constraint.m_Value );
769 }
770 }
771 else
772 {
773 PCB_TRACK* coupledTrack = nullptr;
774 PNS::SEGMENT pnsCoupledItem;
775 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
776
777 if( coupledNet )
778 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
779
780 pnsCoupledItem.SetParent( coupledTrack );
781 pnsCoupledItem.SetNet( coupledNet );
782
783 if( m_tuningMode == DIFF_PAIR )
784 {
785 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
786 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
787 {
788 m_settings.SetTargetLength( constraint.m_Value );
790 }
791 }
792 else
793 {
795 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
796 {
797 m_settings.m_targetSkew = constraint.m_Value;
799 }
800 }
801 }
802 }
803}
804
805
806static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
807 VECTOR2I& aPointOut,
808 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
809{
810 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
811
812 static const int candidateCount = 2;
813 PNS::LINKED_ITEM* prioritized[candidateCount];
814 SEG::ecoord dist[candidateCount];
815 SEG::ecoord distBaseline[candidateCount];
816 VECTOR2I point[candidateCount];
817
818 for( int i = 0; i < candidateCount; i++ )
819 {
820 prioritized[i] = nullptr;
821 dist[i] = VECTOR2I::ECOORD_MAX;
822 distBaseline[i] = VECTOR2I::ECOORD_MAX;
823 }
824
825 for( int slopRadius : { 0, maxSlopRadius } )
826 {
827 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
828
829 for( PNS::ITEM* item : candidates.Items() )
830 {
831 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
832 continue;
833
834 if( !item->IsRoutable() )
835 continue;
836
837 if( !item->Layers().Overlaps( aLayer ) )
838 continue;
839
840 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
841
842 if( item->Kind() & PNS::ITEM::ARC_T )
843 {
844 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
845
846 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
847 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
848
849 if( d0 > dist[1] )
850 continue;
851
852 if( aBaseline.PointCount() > 0 )
853 {
854 SEG::ecoord dcBaseline;
855 VECTOR2I target = pnsArc->Arc().GetArcMid();
856
857 if( aBaseline.SegmentCount() > 0 )
858 dcBaseline = aBaseline.SquaredDistance( target );
859 else
860 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
861
862 if( dcBaseline > distBaseline[1] )
863 continue;
864
865 distBaseline[1] = dcBaseline;
866 }
867
868 prioritized[1] = linked;
869 dist[1] = d0;
870 point[1] = nearest;
871 }
872 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
873 {
874 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
875
876 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
877 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
878
879 if( dd > dist[1] )
880 continue;
881
882 if( aBaseline.PointCount() > 0 )
883 {
884 SEG::ecoord dcBaseline;
885 VECTOR2I target = segm->Shape()->Centre();
886
887 if( aBaseline.SegmentCount() > 0 )
888 dcBaseline = aBaseline.SquaredDistance( target );
889 else
890 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
891
892 if( dcBaseline > distBaseline[1] )
893 continue;
894
895 distBaseline[1] = dcBaseline;
896 }
897
898 prioritized[1] = segm;
899 dist[1] = dd;
900 point[1] = nearest;
901 }
902 }
903 }
904
905 PNS::LINKED_ITEM* rv = nullptr;
906
907 for( int i = 0; i < candidateCount; i++ )
908 {
909 PNS::LINKED_ITEM* item = prioritized[i];
910
911 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
912 {
913 rv = item;
914 aPointOut = point[i];
915 break;
916 }
917 }
918
919 return rv;
920}
921
922
923static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
924 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
925 VECTOR2I& aEndOut )
926{
927 PNS::NODE* world = router->GetWorld();
928
929 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
930 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
931
932 //wxCHECK( startItem && endItem, std::nullopt );
933
934 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
935 {
936 if( !testItem )
937 continue;
938
939 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
940 SHAPE_LINE_CHAIN oldChain = line.CLine();
941
942 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
943 return line;
944 }
945
946 return std::nullopt;
947}
948
949
950bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard,
951 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
952 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
953{
954 PNS::NODE* world = aRouter->GetWorld();
955
956 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
957 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
958
959 VECTOR2I startSnapPoint, endSnapPoint;
960
961 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aLayer, startSnapPoint );
962 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aLayer, endSnapPoint );
963
964 wxASSERT( startItem );
965 wxASSERT( endItem );
966
967 if( !startItem || !endItem )
968 return false;
969
970 PNS::LINE line = world->AssembleLine( startItem );
971 const SHAPE_LINE_CHAIN& chain = line.CLine();
972
973 wxASSERT( line.ContainsLink( endItem ) );
974
975 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
976 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
977
980 SHAPE_LINE_CHAIN post;
981
982 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
983
984 aBaseLine = mid;
985
986 return true;
987}
988
989
990bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard )
991{
992 m_baseLineCoupled.reset();
993
994 PCB_TRACK* track = nullptr;
995
996 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
997 wxCHECK( track, false );
998
999 NETINFO_ITEM* net = track->GetNet();
1000
1001 if( !initBaseLine( aRouter, aLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
1002 return false;
1003
1004 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
1005 // DRC rules against.
1007 {
1008 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
1009 {
1010 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
1011 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
1012
1013 return initBaseLine( aRouter, aLayer, aBoard, coupledStart, coupledEnd, coupledNet,
1015 }
1016
1017 return false;
1018 }
1019
1020 return true;
1021}
1022
1024 SHAPE_LINE_CHAIN& aBaseLine )
1025{
1026 VECTOR2I startSnapPoint, endSnapPoint;
1027
1028 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1029 aRouter, aLayer, startSnapPoint, endSnapPoint );
1030
1031 wxCHECK( pnsLine, false );
1032
1033 SHAPE_LINE_CHAIN pre;
1034 SHAPE_LINE_CHAIN mid;
1035 SHAPE_LINE_CHAIN post;
1036 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1037
1038 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
1039 aRouter->GetInterface()->RemoveItem( li );
1040
1041 aRouter->GetWorld()->Remove( *pnsLine );
1042
1043 SHAPE_LINE_CHAIN straightChain;
1044 straightChain.Append( pre );
1045 straightChain.Append( aBaseLine );
1046 straightChain.Append( post );
1047 straightChain.Simplify();
1048
1049 PNS::LINE straightLine( *pnsLine, straightChain );
1050
1051 aRouter->GetWorld()->Add( straightLine, false );
1052
1053 for( PNS::LINKED_ITEM* li : straightLine.Links() )
1054 aRouter->GetInterface()->AddItem( li );
1055
1056 return true;
1057}
1058
1059
1061{
1062 SetFlags( IN_EDIT );
1063
1064 aTool->Router()->SyncWorld();
1065
1066 PNS::ROUTER* router = aTool->Router();
1067 int layer = GetLayer();
1068
1069 // Ungroup first so that undo works
1070 if( !GetItems().empty() )
1071 {
1072 PCB_GENERATOR* group = this;
1073
1074 for( BOARD_ITEM* member : group->GetItems() )
1075 aCommit->Stage( member, CHT_UNGROUP );
1076
1077 group->GetItems().clear();
1078 }
1079
1080 aCommit->Remove( this );
1081
1082 aTool->ClearRouterChanges();
1083
1084 if( baselineValid() )
1085 {
1086 bool success = true;
1087
1088 success &= removeToBaseline( router, layer, *m_baseLine );
1089
1090 if( m_tuningMode == DIFF_PAIR )
1091 success &= removeToBaseline( router, layer, *m_baseLineCoupled );
1092
1093 if( !success )
1094 recoverBaseline( router );
1095 }
1096
1097 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
1098
1099 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
1100 {
1101 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
1102 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
1103
1104 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1105 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1106 << " m_removedItems " << m_removedItems.size() << std::endl;*/
1107
1108 for( BOARD_ITEM* item : routerRemovedItems )
1109 {
1110 item->ClearSelected();
1111 aCommit->Remove( item );
1112 }
1113
1114 for( BOARD_ITEM* item : routerAddedItems )
1115 aCommit->Add( item );
1116 }
1117
1118 aCommit->Push( "Remove Tuning Pattern" );
1119}
1120
1121
1123{
1124 PNS::SOLID queryItem;
1125
1126 SHAPE_LINE_CHAIN* chain = static_cast<SHAPE_LINE_CHAIN*>( getOutline().Clone() );
1127 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
1128 queryItem.SetLayer( m_layer );
1129
1130 int lineWidth = 0;
1131
1132 PNS::NODE::OBSTACLES obstacles;
1134 opts.m_useClearanceEpsilon = false;
1135
1136 PNS::NODE* world = aRouter->GetWorld();
1137 PNS::NODE* branch = world->Branch();
1138
1139 branch->QueryColliding( &queryItem, obstacles, opts );
1140
1141 for( const PNS::OBSTACLE& obs : obstacles )
1142 {
1143 PNS::ITEM* item = obs.m_item;
1144
1146 continue;
1147
1148 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
1149 {
1150 if( lineWidth == 0 || li->Width() < lineWidth )
1151 lineWidth = li->Width();
1152 }
1153
1154 if( chain->PointInside( item->Anchor( 0 ), 10 )
1155 && chain->PointInside( item->Anchor( 1 ), 10 ) )
1156 {
1157 branch->Remove( item );
1158 }
1159 }
1160
1161 if( lineWidth == 0 )
1162 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1163
1164 if( baselineValid() )
1165 {
1166 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1167 PNS::LINE recoverLine;
1168
1169 recoverLine.SetLayer( m_layer );
1170 recoverLine.SetWidth( lineWidth );
1171 recoverLine.Line() = *m_baseLine;
1172 recoverLine.SetNet( recoverNet );
1173 branch->Add( recoverLine, false );
1174
1176 {
1177 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1178 PNS::LINE recoverLineCoupled;
1179
1180 recoverLineCoupled.SetLayer( m_layer );
1181 recoverLineCoupled.SetWidth( lineWidth );
1182 recoverLineCoupled.Line() = *m_baseLineCoupled;
1183 recoverLineCoupled.SetNet( recoverCoupledNet );
1184 branch->Add( recoverLineCoupled, false );
1185 }
1186 }
1187
1188 aRouter->CommitRouting( branch );
1189
1190 //wxLogWarning( "PNS baseline recovered" );
1191
1192 return true;
1193}
1194
1195
1197 SHAPE_LINE_CHAIN& aBaseLine, bool aPrimary )
1198{
1199 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1200 PNS::ROUTER* router = aTool->Router();
1201 PNS::NODE* world = router->GetWorld();
1202 VECTOR2I startSnapPoint, endSnapPoint;
1203
1204 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1205 router, aLayer, startSnapPoint, endSnapPoint );
1206
1207 if( !pnsLine )
1208 {
1209 // TODO
1210 //recoverBaseline( aRouter );
1211 return true;
1212 }
1213
1214 PNS::NODE* branch = world->Branch();
1215
1216 SHAPE_LINE_CHAIN straightChain;
1217 {
1218 SHAPE_LINE_CHAIN pre, mid, post;
1219 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1220
1221 straightChain.Append( pre );
1222 straightChain.Append( aBaseLine );
1223 straightChain.Append( post );
1224 straightChain.Simplify();
1225 }
1226
1227 branch->Remove( *pnsLine );
1228
1229 SHAPE_LINE_CHAIN newLineChain;
1230
1231 if( aPrimary )
1232 {
1233 m_origin = straightChain.NearestPoint( m_origin );
1234 m_end = straightChain.NearestPoint( m_end );
1235
1236 // Don't allow points too close
1237 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1238 {
1239 m_origin = startSnapPoint;
1240 m_end = endSnapPoint;
1241 }
1242
1243 {
1244 SHAPE_LINE_CHAIN pre, mid, post;
1245 straightChain.Split( m_origin, m_end, pre, mid, post );
1246
1247 newLineChain.Append( pre );
1248 newLineChain.Append( mid );
1249 newLineChain.Append( post );
1250
1251 m_baseLine = mid;
1252 }
1253 }
1254 else
1255 {
1256 VECTOR2I start = straightChain.NearestPoint( m_origin );
1257 VECTOR2I end = straightChain.NearestPoint( m_end );
1258
1259 {
1260 SHAPE_LINE_CHAIN pre, mid, post;
1261 straightChain.Split( start, end, pre, mid, post );
1262
1263 newLineChain.Append( pre );
1264 newLineChain.Append( mid );
1265 newLineChain.Append( post );
1266
1267 m_baseLineCoupled = mid;
1268 }
1269 }
1270
1271 PNS::LINE newLine( *pnsLine, newLineChain );
1272
1273 branch->Add( newLine, false );
1274 router->CommitRouting( branch );
1275
1276 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1277
1278 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1279
1280 return true;
1281}
1282
1283
1285{
1286 if( !( GetFlags() & IN_EDIT ) )
1287 return false;
1288
1289 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1290 PNS::ROUTER* router = aTool->Router();
1291 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1292 int layer = GetLayer();
1293
1294 auto hideRemovedItems = [&]( bool aHide )
1295 {
1296 if( view )
1297 {
1298 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1299 {
1300 for( BOARD_ITEM* item : pnsCommit.removedItems )
1301 {
1302 if( view )
1303 view->Hide( item, aHide, aHide );
1304 }
1305 }
1306 }
1307 };
1308
1309 iface->SetStartLayer( layer );
1310
1311 if( router->RoutingInProgress() )
1312 {
1313 router->StopRouting();
1314 }
1315
1316 if( !baselineValid() )
1317 {
1318 initBaseLines( router, layer, aBoard );
1319 }
1320 else
1321 {
1322 if( resetToBaseline( aTool, layer, *m_baseLine, true ) )
1323 {
1324 m_origin = m_baseLine->CPoint( 0 );
1325 m_end = m_baseLine->CPoint( -1 );
1326 }
1327 else
1328 {
1329 //initBaseLines( router, layer, aBoard );
1330 return false;
1331 }
1332
1333 if( m_tuningMode == DIFF_PAIR )
1334 {
1335 if( !resetToBaseline( aTool, layer, *m_baseLineCoupled, false ) )
1336 {
1337 initBaseLines( router, layer, aBoard );
1338 return false;
1339 }
1340 }
1341 }
1342
1343 hideRemovedItems( true );
1344 // Snap points
1345 VECTOR2I startSnapPoint, endSnapPoint;
1346
1347 wxCHECK( m_baseLine, false );
1348
1349 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, layer, startSnapPoint, *m_baseLine);
1350 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, layer, endSnapPoint, *m_baseLine );
1351
1352 wxASSERT( startItem );
1353 wxASSERT( endItem );
1354
1355 if( !startItem || !endItem )
1356 return false;
1357
1358 router->SetMode( GetPNSMode() );
1359
1360 if( !router->StartRouting( startSnapPoint, startItem, layer ) )
1361 {
1362 //recoverBaseline( router );
1363 return false;
1364 }
1365
1366 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1367
1368 m_settings.m_keepEndpoints = true; // Required for re-grouping
1369 placer->UpdateSettings( m_settings );
1370
1371 router->Move( m_end, nullptr );
1372
1373 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1374 {
1375 m_trackWidth = dpPlacer->GetOriginPair().Width();
1376 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1377 }
1378 else
1379 {
1380 m_trackWidth = startItem->Width();
1381 m_diffPairGap = router->Sizes().DiffPairGap();
1382 }
1383
1384 m_settings = placer->MeanderSettings();
1385 m_lastNetName = iface->GetNetName( startItem->Net() );
1386 m_tuningStatus = placer->TuningStatus();
1387
1388 wxString statusMessage;
1389
1390 switch ( m_tuningStatus )
1391 {
1392 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1393 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1394 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1395 default: statusMessage = _( "unknown" ); break;
1396 }
1397
1398 wxString result;
1399 EDA_UNITS userUnits = EDA_UNITS::MILLIMETRES;
1400
1401 if( aTool->GetManager()->GetSettings() )
1402 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1403
1405 (double) placer->TuningResult() );
1406
1407 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1408
1409 return true;
1410}
1411
1412
1414 const wxString& aCommitMsg, int aCommitFlags )
1415{
1416 if( !( GetFlags() & IN_EDIT ) )
1417 return;
1418
1420
1421 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1422 PNS::ROUTER* router = aTool->Router();
1423 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1424 SHAPE_LINE_CHAIN bounds = getOutline();
1425 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1426
1427 iface->EraseView();
1428
1429 if( router->RoutingInProgress() )
1430 {
1431 bool forceFinish = true;
1432 bool forceCommit = false;
1433
1434 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1435 router->StopRouting();
1436 }
1437
1438 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1439
1440 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1441 {
1442 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1443 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1444
1445 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1446 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1447 // << " m_removedItems " << m_removedItems.size() << std::endl;
1448
1449 for( BOARD_ITEM* item : routerRemovedItems )
1450 {
1451 if( view )
1452 view->Hide( item, false );
1453
1454 aCommit->Remove( item );
1455 }
1456
1457 for( BOARD_ITEM* item : routerAddedItems )
1458 {
1459 aCommit->Add( item );
1460
1461 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1462 {
1463 if( bounds.PointInside( track->GetStart(), epsilon )
1464 && bounds.PointInside( track->GetEnd(), epsilon ) )
1465 {
1466 aCommit->Stage( item, CHT_GROUP );
1467 }
1468 }
1469 }
1470 }
1471
1472 if( aCommitMsg.IsEmpty() )
1473 aCommit->Push( _( "Edit Tuning Pattern" ), aCommitFlags );
1474 else
1475 aCommit->Push( aCommitMsg, aCommitFlags );
1476}
1477
1478
1480{
1481 if( !( GetFlags() & IN_EDIT ) )
1482 return;
1483
1485
1486 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1487
1488 iface->EraseView();
1489
1490 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1491 {
1492 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1493 {
1494 for( BOARD_ITEM* item : pnsCommit.removedItems )
1495 view->Hide( item, false );
1496 }
1497 }
1498
1499 aTool->Router()->StopRouting();
1500
1501 if( aCommit )
1502 aCommit->Revert();
1503}
1504
1505
1506bool PCB_TUNING_PATTERN::MakeEditPoints( std::shared_ptr<EDIT_POINTS> points ) const
1507{
1508 VECTOR2I centerlineOffset;
1509 VECTOR2I centerlineOffsetEnd;
1510
1511 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1512 {
1513 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1514 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1515 }
1516
1517 points->AddPoint( m_origin + centerlineOffset );
1518 points->AddPoint( m_end + centerlineOffsetEnd );
1519
1520 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1521 : SEG( m_origin, m_end );
1522
1523 base.A += centerlineOffset;
1524 base.B += centerlineOffset;
1525
1526 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1527
1528 if( m_tuningMode == DIFF_PAIR )
1529 amplitude += m_trackWidth + m_diffPairGap;
1530
1531 if( m_settings.m_initialSide == -1 )
1532 amplitude *= -1;
1533
1534 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1535
1536 points->AddPoint( base.A + widthHandleOffset );
1537 points->Point( 2 ).SetGridConstraint( IGNORE_GRID );
1538
1539 VECTOR2I spacingHandleOffset =
1540 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1541
1542 points->AddPoint( base.A + spacingHandleOffset );
1543 points->Point( 3 ).SetGridConstraint( IGNORE_GRID );
1544
1545 return true;
1546}
1547
1548
1549bool PCB_TUNING_PATTERN::UpdateFromEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints,
1550 BOARD_COMMIT* aCommit )
1551{
1552 VECTOR2I centerlineOffset;
1553 VECTOR2I centerlineOffsetEnd;
1554
1555 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1556 {
1557 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1558 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1559 }
1560
1561 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1562 : SEG( m_origin, m_end );
1563
1564 base.A += centerlineOffset;
1565 base.B += centerlineOffset;
1566
1567 m_origin = aEditPoints->Point( 0 ).GetPosition() - centerlineOffset;
1568 m_end = aEditPoints->Point( 1 ).GetPosition() - centerlineOffsetEnd;
1569
1570 if( aEditPoints->Point( 2 ).IsActive() )
1571 {
1572 VECTOR2I wHandle = aEditPoints->Point( 2 ).GetPosition();
1573
1574 int value = base.LineDistance( wHandle );
1575
1576 value -= KiROUND( m_trackWidth / 2.0 );
1577
1578 if( m_tuningMode == DIFF_PAIR )
1579 value -= m_trackWidth + m_diffPairGap;
1580
1581 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1582
1583 int side = base.Side( wHandle );
1584
1585 if( side < 0 )
1587 else
1589 }
1590
1591 if( aEditPoints->Point( 3 ).IsActive() )
1592 {
1593 VECTOR2I wHandle = aEditPoints->Point( 2 ).GetPosition();
1594 VECTOR2I sHandle = aEditPoints->Point( 3 ).GetPosition();
1595
1596 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1597
1598 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1599 }
1600
1601 return true;
1602}
1603
1604
1605bool PCB_TUNING_PATTERN::UpdateEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints )
1606{
1607 VECTOR2I centerlineOffset;
1608 VECTOR2I centerlineOffsetEnd;
1609
1610 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1611 {
1612 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1613 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1614 }
1615
1616 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1617 : SEG( m_origin, m_end );
1618
1619 base.A += centerlineOffset;
1620 base.B += centerlineOffset;
1621
1622 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1623
1624 if( m_tuningMode == DIFF_PAIR )
1625 amplitude += m_trackWidth + m_diffPairGap;
1626
1627 if( m_settings.m_initialSide == -1 )
1628 amplitude *= -1;
1629
1630 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1631
1632 aEditPoints->Point( 0 ).SetPosition( m_origin + centerlineOffset );
1633 aEditPoints->Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1634
1635 aEditPoints->Point( 2 ).SetPosition( base.A + widthHandleOffset );
1636
1637 VECTOR2I spacingHandleOffset =
1638 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1639
1640 aEditPoints->Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1641
1642 return true;
1643}
1644
1645
1647{
1648 if( m_baseLine )
1649 {
1650 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1651 int minAllowedAmplitude = 0;
1652 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1653
1655 {
1656 minAllowedAmplitude = baselineOffset + m_trackWidth;
1657 }
1658 else
1659 {
1660 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1661 minAllowedAmplitude = baselineOffset + correction;
1662 }
1663
1664 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1665
1667 {
1668 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1670
1671 if( m_tuningMode != DIFF_PAIR )
1672 {
1673 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1674
1675 SHAPE_LINE_CHAIN chain;
1676
1677 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1678 left, right, true ) )
1679 {
1680 chain.Append( m_settings.m_initialSide >= 0 ? right : left );
1681 chain.Append( clBase.Reverse() );
1682 chain.SetClosed( true );
1683
1684 return chain;
1685 }
1686 }
1688 {
1689 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1690
1692 SHAPE_LINE_CHAIN chain1, chain2;
1693
1694 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1695 left, right, true ) )
1696 {
1697 if( m_settings.m_initialSide >= 0 )
1698 chain1.Append( right );
1699 else
1700 chain1.Append( left );
1701
1702 if( clBase.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1703 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1704 right, true ) )
1705 {
1706 if( m_settings.m_initialSide >= 0 )
1707 chain1.Append( left.Reverse() );
1708 else
1709 chain1.Append( right.Reverse() );
1710 }
1711
1712 chain1.SetClosed( true );
1713 }
1714
1715 if( clCoupled.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1716 ARC_LOW_DEF, left, right, true ) )
1717 {
1718 if( m_settings.m_initialSide >= 0 )
1719 chain2.Append( right );
1720 else
1721 chain2.Append( left );
1722
1723 if( clCoupled.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1724 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1725 right, true ) )
1726 {
1727 if( m_settings.m_initialSide >= 0 )
1728 chain2.Append( left.Reverse() );
1729 else
1730 chain2.Append( right.Reverse() );
1731 }
1732
1733 chain2.SetClosed( true );
1734 }
1735
1736 SHAPE_POLY_SET merged;
1737 merged.BooleanAdd( chain1, chain2, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1738
1739 if( merged.OutlineCount() > 0 )
1740 return merged.Outline( 0 );
1741 }
1742 }
1743
1744 // Not single-sided / fallback
1745 SHAPE_POLY_SET poly;
1747
1748 int amplitude = 0;
1749
1750 if( m_tuningMode == DIFF_PAIR )
1751 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1752 else
1753 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1754
1755 poly.OffsetLineChain( *m_baseLine, amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1756 ARC_LOW_DEF, false );
1757
1759 {
1760 SHAPE_POLY_SET polyCoupled;
1761 polyCoupled.OffsetLineChain( *m_baseLineCoupled, amplitude,
1762 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, false );
1763
1764 SHAPE_POLY_SET merged;
1765 merged.BooleanAdd( poly, polyCoupled, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1766
1767 if( merged.OutlineCount() > 0 )
1768 return merged.Outline( 0 );
1769 }
1770
1771 if( poly.OutlineCount() > 0 )
1772 return poly.Outline( 0 );
1773 }
1774
1775 return SHAPE_LINE_CHAIN();
1776}
1777
1778
1779void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1780{
1781 if( !IsSelected() && !IsNew() )
1782 return;
1783
1784 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1785
1786 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1787 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1788
1789 if( !HasFlag( IN_EDIT ) )
1790 {
1791 if( m_baseLine )
1792 {
1793 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1794 {
1795 SEG seg = m_baseLine->CSegment( i );
1796 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1797 }
1798 }
1799 else
1800 {
1801 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1802 }
1803
1805 {
1806 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1807 {
1808 SEG seg = m_baseLineCoupled->CSegment( i );
1809 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1810 }
1811 }
1812 }
1813
1814 SHAPE_LINE_CHAIN chain = getOutline();
1815
1816 for( int i = 0; i < chain.SegmentCount(); i++ )
1817 {
1818 SEG seg = chain.Segment( i );
1819 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1820 }
1821}
1822
1823
1825{
1827
1828 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
1829 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
1830 props.set( "last_status", statusToString( m_tuningStatus ) );
1831
1832 props.set( "end", m_end );
1833 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1834 props.set( "single_sided", m_settings.m_singleSided );
1836
1837 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
1838 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
1839 props.set_iu( "min_spacing", m_settings.m_spacing );
1840 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
1841 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
1842 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
1843 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
1844 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
1845 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
1846 props.set_iu( "last_track_width", m_trackWidth );
1847 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
1848
1849 props.set( "last_netname", m_lastNetName );
1850 props.set( "last_tuning", m_tuningInfo );
1851 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
1852
1853 if( m_baseLine )
1854 props.set( "base_line", wxAny( *m_baseLine ) );
1855
1856 if( m_baseLineCoupled )
1857 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
1858
1859 return props;
1860}
1861
1862
1864{
1866
1867 wxString tuningMode;
1868 aProps.get_to( "tuning_mode", tuningMode );
1869 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
1870
1871 wxString side;
1872 aProps.get_to( "initial_side", side );
1873 m_settings.m_initialSide = sideFromString( side.utf8_string() );
1874
1875 wxString status;
1876 aProps.get_to( "last_status", status );
1877 m_tuningStatus = statusFromString( status.utf8_string() );
1878
1879 aProps.get_to( "end", m_end );
1880 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1881 aProps.get_to( "single_sided", m_settings.m_singleSided );
1882 aProps.get_to( "side", m_settings.m_initialSide );
1883
1884 bool rounded = false;
1885 aProps.get_to( "rounded", rounded );
1887
1888 long long int val;
1889
1890 aProps.get_to_iu( "target_length", val );
1892
1893 if( aProps.get_to_iu( "target_length_min", val ) )
1895
1896 if( aProps.get_to_iu( "target_length_max", val ) )
1898
1899 int int_val;
1900
1901 aProps.get_to_iu( "target_skew", int_val );
1902 m_settings.SetTargetSkew( int_val );
1903
1904 if( aProps.get_to_iu( "target_skew_min", int_val ) )
1905 m_settings.m_targetSkew.SetMin( int_val );
1906
1907 if( aProps.get_to_iu( "target_skew_max", int_val ) )
1908 m_settings.m_targetSkew.SetMax( int_val );
1909
1910 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
1911 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
1912 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
1913 aProps.get_to_iu( "last_track_width", m_trackWidth );
1914 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
1915 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
1916
1917 aProps.get_to( "last_netname", m_lastNetName );
1918 aProps.get_to( "last_tuning", m_tuningInfo );
1919
1920 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
1921 m_baseLine = *baseLine;
1922
1923 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
1924 m_baseLineCoupled = *baseLineCoupled;
1925}
1926
1927
1929{
1931 DRC_CONSTRAINT constraint;
1932
1933 if( !m_items.empty() )
1934 {
1935 BOARD_ITEM* startItem = *m_items.begin();
1936 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1937
1938 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
1939
1940 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
1941 settings.SetTargetLength( constraint.GetValue() );
1942 }
1943
1944 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
1945
1946 if( dlg.ShowModal() == wxID_OK )
1947 {
1948 BOARD_COMMIT commit( aEditFrame );
1949 commit.Modify( this );
1950 m_settings = settings;
1951
1952 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
1953 EditStart( generatorTool, GetBoard(), &commit );
1954 Update( generatorTool, GetBoard(), &commit );
1955 EditPush( generatorTool, GetBoard(), &commit );
1956 }
1957}
1958
1959
1961 PCB_BASE_EDIT_FRAME* aFrame,
1962 bool aStatusItemsOnly )
1963{
1964 std::vector<EDA_ITEM*> previewItems;
1965 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
1966
1967 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
1968 {
1969 if( !aStatusItemsOnly )
1970 {
1971 PNS::ITEM_SET items = placer->TunedPath();
1972
1973 for( PNS::ITEM* item : items )
1974 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item, view, PNS_HOVER_ITEM ) );
1975 }
1976
1977 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
1978
1980 {
1982 }
1983 else
1984 {
1986 {
1987 statusItem->ClearMinMax();
1988 }
1989 else
1990 {
1991 statusItem->SetMinMax( (double) m_settings.m_targetLength.Min(),
1992 (double) m_settings.m_targetLength.Max() );
1993 }
1994 }
1995
1997 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current skew" ) );
1998 else
1999 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current length" ) );
2000
2001 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
2002 previewItems.push_back( statusItem );
2003 }
2004
2005 return previewItems;
2006}
2007
2008
2010 std::vector<MSG_PANEL_ITEM>& aList )
2011{
2012 wxString msg;
2013 NETINFO_ITEM* primaryNet = nullptr;
2014 NETINFO_ITEM* coupledNet = nullptr;
2015 PCB_TRACK* primaryItem = nullptr;
2016 PCB_TRACK* coupledItem = nullptr;
2017 NETCLASS* netclass = nullptr;
2018 int width = 0;
2019 bool mixedWidth = false;
2020
2021 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2022
2023 for( BOARD_ITEM* member : GetItems() )
2024 {
2025 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
2026 {
2027 if( !primaryNet )
2028 {
2029 primaryItem = track;
2030 primaryNet = track->GetNet();
2031 }
2032 else if( !coupledNet && track->GetNet() != primaryNet )
2033 {
2034 coupledItem = track;
2035 coupledNet = track->GetNet();
2036 }
2037
2038 if( !netclass )
2039 netclass = track->GetEffectiveNetClass();
2040
2041 if( !width )
2042 width = track->GetWidth();
2043 else if( width != track->GetWidth() )
2044 mixedWidth = true;
2045 }
2046 }
2047
2048 if( coupledNet )
2049 {
2050 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2051 + wxS( ", " )
2052 + UnescapeString( coupledNet->GetNetname() ) );
2053 }
2054 else if( primaryNet )
2055 {
2056 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2057 }
2058
2059 if( netclass )
2060 aList.emplace_back( _( "Resolved Netclass" ), UnescapeString( netclass->GetName() ) );
2061
2062 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
2063
2064 if( width && !mixedWidth )
2065 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2066
2067 BOARD* board = GetBoard();
2068 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2069 DRC_CONSTRAINT constraint;
2070
2071 // Display full track length (in Pcbnew)
2072 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2073 {
2074 int count;
2075 double trackLen;
2076 double lenPadToDie;
2077
2078 std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *primaryItem );
2079
2080 if( coupledItem && coupledItem->GetNetCode() > 0 )
2081 {
2082 double coupledLen;
2083 std::tie( count, coupledLen, lenPadToDie ) = board->GetTrackLength( *coupledItem );
2084
2085 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen )
2086 + wxS( ", " )
2087 + aFrame->MessageTextFromValue( coupledLen ) );
2088 }
2089 else
2090 {
2091 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2092 }
2093
2094 if( lenPadToDie != 0 )
2095 {
2096 msg = aFrame->MessageTextFromValue( lenPadToDie );
2097 aList.emplace_back( _( "Pad To Die Length" ), msg );
2098
2099 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2100 aList.emplace_back( _( "Full Length" ), msg );
2101 }
2102 }
2103
2105 {
2106 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2107
2108 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2109 {
2111
2112 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2113 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2114 }
2115 else
2116 {
2117 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2118
2119 if( !msg.IsEmpty() )
2120 {
2121 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2122 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2123 }
2124 }
2125 }
2126 else
2127 {
2128 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2129
2130 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2131 {
2132 msg = aFrame->MessageTextFromValue( (double) m_settings.m_targetLength.Opt() );
2133
2134 aList.emplace_back( wxString::Format( _( "Target Length: %s" ), msg ),
2135 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2136 }
2137 else
2138 {
2139 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2140
2141 if( !msg.IsEmpty() )
2142 {
2143 aList.emplace_back( wxString::Format( _( "Length Constraints: %s" ), msg ),
2144 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2145 }
2146 }
2147 }
2148}
2149
2150
2151const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2152const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2153
2154
2156
2157
2158#define HITTEST_THRESHOLD_PIXELS 5
2159
2160
2162{
2164 return 0;
2165
2166 if( m_inDrawingTool )
2167 return 0;
2168
2170
2172
2173 m_frame->PushTool( aEvent );
2174 Activate();
2175
2177 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2178 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2179 PNS::ROUTER* router = generatorTool->Router();
2181
2185 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2186
2187 m_pickerItem = nullptr;
2188 m_tuningPattern = nullptr;
2189
2190 // Add a VIEW_GROUP that serves as a preview for the new item
2191 m_preview.Clear();
2192 m_view->Add( &m_preview );
2193
2194 auto setCursor =
2195 [&]()
2196 {
2197 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
2198 controls->ShowCursor( true );
2199 };
2200
2201 auto updateHoverStatus =
2202 [&]()
2203 {
2204 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2205
2206 if( m_pickerItem )
2207 {
2208 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2209 m_pickerItem, mode ) );
2210 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2211 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2212 }
2213
2214 if( dummyPattern )
2215 {
2216 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2217 dummyPattern->Update( generatorTool, m_board, nullptr );
2218
2220
2221 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2222 m_preview.Add( item );
2223
2224 generatorTool->Router()->StopRouting();
2225
2226 m_view->Update( &m_preview );
2227 }
2228 else
2229 {
2231 m_view->Update( &m_preview );
2232 }
2233 };
2234
2235 auto updateTuningPattern =
2236 [&]()
2237 {
2239 {
2240 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2241 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2242
2244
2245 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame,
2246 true ) )
2247 {
2248 m_preview.Add( item );
2249 }
2250
2251 m_view->Update( &m_preview );
2252 }
2253 };
2254
2255 // Set initial cursor
2256 setCursor();
2257
2258 while( TOOL_EVENT* evt = Wait() )
2259 {
2260 setCursor();
2261 VECTOR2D cursorPos = controls->GetMousePosition();
2262
2263 if( evt->IsCancelInteractive() || evt->IsActivate()
2264 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2265 {
2266 if( m_tuningPattern )
2267 {
2268 // First click already made; clean up tuning pattern preview
2269 m_tuningPattern->EditRevert( generatorTool, m_board, nullptr );
2270
2271 delete m_tuningPattern;
2272 m_tuningPattern = nullptr;
2273 }
2274
2275 break;
2276 }
2277 else if( evt->IsMotion() )
2278 {
2279 if( !m_tuningPattern )
2280 {
2281 // First click not yet made; we're in highlight-net-under-cursor mode
2282
2283 GENERAL_COLLECTOR collector;
2284 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2285
2286 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2287 guide.SetIncludeSecondary( false );
2288 else
2289 guide.SetIncludeSecondary( true );
2290
2291 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2292
2293 if( collector.GetCount() > 1 )
2294 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2295
2296 m_pickerItem = nullptr;
2297
2298 if( collector.GetCount() > 0 )
2299 {
2300 double min_dist_sq = std::numeric_limits<double>::max();
2301
2302 for( EDA_ITEM* candidate : collector )
2303 {
2304 VECTOR2I candidatePos;
2305
2306 if( candidate->Type() == PCB_TRACE_T )
2307 {
2308 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2309 }
2310 else if( candidate->Type() == PCB_ARC_T )
2311 {
2312 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2313 }
2314
2315 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2316
2317 if( dist_sq < min_dist_sq )
2318 {
2319 min_dist_sq = dist_sq;
2320 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2321 }
2322 }
2323 }
2324
2325 updateHoverStatus();
2326 }
2327 else
2328 {
2329 // First click already made; we're in preview-tuning-pattern mode
2330
2331 m_tuningPattern->SetEnd( cursorPos );
2332 updateTuningPattern();
2333 }
2334 }
2335 else if( evt->IsClick( BUT_LEFT ) )
2336 {
2338 {
2339 // First click; create a tuning pattern
2340
2341 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2342 {
2343 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2344 "tuning patterns." ) );
2345 }
2346 else
2347 {
2349
2352 m_pickerItem, mode );
2353
2354 int dummyDist;
2355 int dummyClearance = std::numeric_limits<int>::max() / 2;
2356 VECTOR2I closestPt;
2357
2358 // With an artificially-large clearance this can't *not* collide, but the
2359 // if stmt keeps Coverity happy....
2360 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2361 &dummyDist, &closestPt ) )
2362 {
2363 m_tuningPattern->SetPosition( closestPt );
2364 m_tuningPattern->SetEnd( closestPt );
2365 }
2366
2368 }
2369 }
2370 else if( m_pickerItem && m_tuningPattern )
2371 {
2372 // Second click; we're done
2373 BOARD_COMMIT commit( m_frame );
2374
2375 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2376 m_tuningPattern->Update( generatorTool, m_board, &commit );
2377 m_tuningPattern->EditPush( generatorTool, m_board, &commit, _( "Tune" ) );
2378
2379 for( BOARD_ITEM* item : m_tuningPattern->GetItems() )
2380 item->SetSelected();
2381
2382 break;
2383 }
2384 }
2385 else if( evt->IsClick( BUT_RIGHT ) )
2386 {
2389 }
2390 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2391 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2392 {
2393 if( m_tuningPattern )
2394 {
2395 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2396
2397 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2398 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2399 updateTuningPattern();
2400 }
2401 else
2402 {
2403 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2404 }
2405 }
2406 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2407 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2408 {
2409 if( m_tuningPattern )
2410 {
2411 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2412
2413 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2414 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2415 updateTuningPattern();
2416 }
2417 else
2418 {
2419 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2420 }
2421 }
2422 else if( evt->IsAction( &PCB_ACTIONS::properties )
2423 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2424 {
2425 if( m_tuningPattern )
2426 {
2427 DRC_CONSTRAINT constraint;
2428
2429 if( !m_tuningPattern->GetItems().empty() )
2430 {
2431 BOARD_ITEM* startItem = *m_tuningPattern->GetItems().begin();
2432
2433 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2434 startItem->GetLayer() );
2435 }
2436
2438 m_tuningPattern->GetPNSMode(), constraint );
2439
2440 if( dlg.ShowModal() == wxID_OK )
2441 updateTuningPattern();
2442 }
2443 else
2444 {
2445 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2446 }
2447 }
2448 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2449 // but we don't at present have that, so we just knock out some of the egregious ones.
2450 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2451 {
2452 wxBell();
2453 }
2454 else
2455 {
2456 evt->SetPassEvent();
2457 }
2458
2459 controls->CaptureCursor( m_tuningPattern != nullptr );
2460 controls->SetAutoPan( m_tuningPattern != nullptr );
2461 }
2462
2463 controls->CaptureCursor( false );
2464 controls->SetAutoPan( false );
2465 controls->ForceCursorPosition( false );
2466 controls->ShowCursor( false );
2467 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2468
2470 m_view->Remove( &m_preview );
2471
2473
2474 if( m_tuningPattern )
2475 selectionTool->AddItemToSel( m_tuningPattern );
2476
2477 m_frame->PopTool( aEvent );
2478 return 0;
2479}
2480
2481
2483{
2485 {
2487 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2488 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2489 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2490
2492 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2493 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2494 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2495
2502
2503 const wxString groupTab = _HKI( "Pattern Properties" );
2504
2506 _HKI( "End X" ), &PCB_TUNING_PATTERN::SetEndX,
2507 &PCB_TUNING_PATTERN::GetEndX, PROPERTY_DISPLAY::PT_SIZE,
2509 groupTab );
2510
2512 _HKI( "End Y" ), &PCB_TUNING_PATTERN::SetEndY,
2513 &PCB_TUNING_PATTERN::GetEndY, PROPERTY_DISPLAY::PT_SIZE,
2515 groupTab );
2516
2518 _HKI( "Tuning Mode" ),
2521 groupTab );
2522
2524 _HKI( "Min Amplitude" ),
2527 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2528 groupTab );
2529
2531 _HKI( "Max Amplitude" ),
2534 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2535 groupTab );
2536
2538 _HKI( "Initial Side" ),
2541 groupTab );
2542
2544 _HKI( "Min Spacing" ), &PCB_TUNING_PATTERN::SetSpacing,
2545 &PCB_TUNING_PATTERN::GetSpacing, PROPERTY_DISPLAY::PT_SIZE,
2547 groupTab );
2548
2550 _HKI( "Corner Radius %" ),
2553 PROPERTY_DISPLAY::PT_DEFAULT, ORIGIN_TRANSFORMS::NOT_A_COORD ),
2554 groupTab );
2555
2556 auto isSkew =
2557 []( INSPECTABLE* aItem ) -> bool
2558 {
2559 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2560 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2561
2562 return false;
2563 };
2564
2565 auto notIsSkew =
2566 [&]( INSPECTABLE* aItem ) -> bool
2567 {
2568 return !isSkew( aItem );
2569 };
2570
2571 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2572 _HKI( "Target Length" ),
2575 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2576 groupTab )
2577 .SetAvailableFunc( notIsSkew );
2578
2579
2581 _HKI( "Target Skew" ), &PCB_TUNING_PATTERN::SetTargetSkew,
2583 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2584 groupTab )
2585 .SetAvailableFunc( isSkew );
2586
2587
2589 _HKI( "Override Custom Rules" ),
2592 groupTab );
2593
2595 _HKI( "Single-sided" ),
2598 groupTab );
2599
2601 _HKI( "Rounded" ), &PCB_TUNING_PATTERN::SetRounded,
2603 groupTab );
2604 }
2606
2609
2611
2612// Also register under the 7.99 name
2613template <typename T>
2615{
2617 {
2618 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2619 []()
2620 {
2621 return new T;
2622 } );
2623 }
2624};
2625
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr int ARC_LOW_DEF
Definition: base_units.h:119
static TOOL_ACTION undo
Definition: actions.h:67
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
virtual void Revert() override
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
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
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:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:231
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:91
PCB_LAYER_ID m_layer
Definition: board_item.h:398
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:228
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:115
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition: board.cpp:1874
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1803
const TRACKS & Tracks() const
Definition: board.h:321
std::tuple< int, 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:2181
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:794
void SetMaximum()
Definition: box2.h:70
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:294
bool Contains(const Vec &aPoint) const
Definition: box2.h:158
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
int m_Threshold
Definition: collector.h:234
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been removed.
Definition: commit.h:92
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
PCB_SELECTION m_preview
Definition: drawing_tool.h:362
KIGFX::VIEW * m_view
Definition: drawing_tool.h:351
BOARD_CONNECTED_ITEM * m_pickerItem
Definition: drawing_tool.h:363
bool m_inDrawingTool
Definition: drawing_tool.h:356
int PlaceTuningPattern(const TOOL_EVENT &aEvent)
BOARD * m_board
Definition: drawing_tool.h:353
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:354
PCB_TUNING_PATTERN * m_tuningPattern
Definition: drawing_tool.h:364
wxString GetName() const
Definition: drc_rule.h:149
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:141
bool IsNull() const
Definition: drc_rule.h:136
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
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
virtual const VECTOR2I GetFocusPosition() const
Similar to GetPosition, but allows items to return their visual center rather than their anchor.
Definition: eda_item.h:249
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:128
bool IsSelected() const
Definition: eda_item.h:109
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:130
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:129
bool IsNew() const
Definition: eda_item.h:106
static const int POINT_SIZE
Definition: edit_points.h:190
static ENUM_MAP< T > & Instance()
Definition: property.h:663
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:271
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:323
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:206
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:482
A factory which returns an instance of a PCB_GENERATOR.
void Register(const wxString &aTypeStr, const wxString &aName, std::function< PCB_GENERATOR *(void)> aCreateFunc)
Associate a type string to display name and create function.
static GENERATORS_MGR & Instance()
const std::vector< GENERATOR_PNS_CHANGES > & GetRouterChanges()
Handle actions specific to filling copper zones.
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:36
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)
Definition: font.cpp:146
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:257
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:204
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:315
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:354
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:1631
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
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:449
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1579
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
T Opt() const
Definition: minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:44
const wxString GetName() const
Definition: netclass.h:62
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:176
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:207
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:208
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:209
static TOOL_ACTION lengthTunerSettings
Definition: pcb_actions.h:210
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:206
const VECTOR2I & GetMid() const
Definition: pcb_track.h:293
Common, abstract interface for edit frames.
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
virtual void SetProperties(const STRING_ANY_MAP &aProps)
wxString m_generatorType
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
VECTOR2I m_origin
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_generator.h:82
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
VECTOR2I GetPosition() const override
Definition: pcb_generator.h:81
void Move(const VECTOR2I &aMoveVector) override
Move this object.
virtual std::vector< std::pair< wxString, wxVariant > > GetRowData()
virtual const STRING_ANY_MAP GetProperties() const
std::unordered_set< BOARD_ITEM * > m_items
Definition: pcb_group.h:216
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
wxString m_name
Definition: pcb_group.h:217
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
int GetWidth() const
Definition: pcb_track.h:108
const VECTOR2I & GetStart() const
Definition: pcb_track.h:114
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:111
void SetTargetSkew(int aValue)
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)
bool initBaseLines(PNS::ROUTER *aRouter, int aLayer, BOARD *aBoard)
wxString GetGeneratorType() const override
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()
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
PCB_TUNING_PATTERN(BOARD_ITEM *aParent=nullptr, PCB_LAYER_ID aLayer=F_Cu, LENGTH_TUNING_MODE aMode=LENGTH_TUNING_MODE::SINGLE)
void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
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
bool UpdateEditPoints(std::shared_ptr< EDIT_POINTS > aEditPoints) override
void SetInitialSide(PNS::MEANDER_SIDE aValue)
wxString GetFriendlyName() const override
LENGTH_TUNING_MODE GetTuningMode() 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 EditStart(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool resetToBaseline(GENERATOR_TOOL *aTool, int aLayer, SHAPE_LINE_CHAIN &aBaseLine, bool aPrimary)
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
void SetCornerRadiusPercentage(int aValue)
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
PNS::MEANDER_PLACER_BASE::TUNING_STATUS m_tuningStatus
bool UpdateFromEditPoints(std::shared_ptr< EDIT_POINTS > aEditPoints, BOARD_COMMIT *aCommit) override
std::optional< SHAPE_LINE_CHAIN > m_baseLineCoupled
void SetProperties(const STRING_ANY_MAP &aProps) override
bool removeToBaseline(PNS::ROUTER *aRouter, int aLayer, SHAPE_LINE_CHAIN &aBaseLine)
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
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 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 initBaseLine(PNS::ROUTER *aRouter, int aLayer, BOARD *aBoard, VECTOR2I &aStart, VECTOR2I &aEnd, NETINFO_ITEM *aNet, std::optional< 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)
bool MakeEditPoints(std::shared_ptr< EDIT_POINTS > points) const override
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:97
virtual NET_HANDLE Net() const
Definition: pns_item.h:194
void SetNet(NET_HANDLE aNet)
Definition: pns_item.h:193
void SetLayer(int aLayer)
Definition: pns_item.h:199
@ SEGMENT_T
Definition: pns_item.h:106
void SetParent(BOARD_ITEM *aParent)
Definition: pns_item.h:185
bool OfKind(int aKindMask) const
Definition: pns_item.h:175
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:237
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition: pns_line.h:61
const SHAPE_LINE_CHAIN & CLine() const
Definition: pns_line.h:136
SHAPE_LINE_CHAIN & Line()
Definition: pns_line.h:135
void SetWidth(int aWidth)
Return line width.
Definition: pns_line.h:148
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 long long int TuningResult() const =0
Return the resultant length or skew of the tuned traces.
virtual void AmplitudeStep(int aSign)
Increase/decreases the current meandering amplitude by one step.
Dimensions for the meandering algorithm.
Definition: pns_meander.h:68
int m_minAmplitude
Maximum meandering amplitude.
Definition: pns_meander.h:82
void SetTargetLength(long long int aOpt)
Definition: pns_meander.cpp:54
static const long long int LENGTH_UNCONSTRAINED
Definition: pns_meander.h:71
int m_cornerRadiusPercentage
Place meanders on one side.
Definition: pns_meander.h:108
MEANDER_SIDE m_initialSide
Allowable tuning error.
Definition: pns_meander.h:114
bool m_singleSided
Initial side when placing meanders at segment.
Definition: pns_meander.h:111
MINOPTMAX< long long int > m_targetLength
Target skew value for diff pair de-skewing.
Definition: pns_meander.h:97
void SetTargetSkew(int aOpt)
Definition: pns_meander.cpp:83
MINOPTMAX< int > m_targetSkew
Definition: pns_meander.h:100
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
Definition: pns_meander.h:105
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition: pns_meander.h:85
bool m_overrideCustomRules
Type of corners for the meandered line.
Definition: pns_meander.h:102
int m_spacing
Amplitude/spacing adjustment step.
Definition: pns_meander.h:88
Keep the router "world" - i.e.
Definition: pns_node.h:207
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:663
std::set< OBSTACLE > OBSTACLES
Definition: pns_node.h:219
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:252
void Remove(ARC *aArc)
Remove an item from this branch.
Definition: pns_node.cpp:884
const LINE AssembleLine(LINKED_ITEM *aSeg, int *aOriginSegmentIndex=nullptr, bool aStopAtLockedJoints=false, bool aFollowLockedSegments=false)
Follow the joint map to assemble a line connecting two non-trivial joints starting from segment aSeg.
Definition: pns_node.cpp:1014
virtual void RemoveItem(ITEM *aItem)=0
virtual void AddItem(ITEM *aItem)=0
void SetMode(ROUTER_MODE aMode)
void StopRouting()
Definition: pns_router.cpp:905
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:216
ROUTER_IFACE * GetInterface() const
Definition: pns_router.h:218
void CommitRouting()
Definition: pns_router.cpp:896
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, int aSlopRadius=0)
Definition: pns_router.cpp:123
void SyncWorld()
Definition: pns_router.cpp:94
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:180
bool RoutingInProgress() const
Definition: pns_router.cpp:117
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:390
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:211
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
Definition: pns_router.cpp:858
NODE * GetWorld() const
Definition: pns_router.h:164
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:450
virtual int Clearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
const SHAPE_LINE_CHAIN CLine() const
Definition: pns_segment.h:89
const SHAPE * Shape() const override
Return the geometrical shape of the item.
Definition: pns_segment.h:69
void SetShape(SHAPE *shape)
Definition: pns_solid.h:98
ROUTER * Router() const
PNS_KICAD_IFACE * GetInterface() const
void SetStartLayer(int aLayer)
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:257
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:87
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
RAII class that sets an value at construction and resets it to the original value at destruction.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Return the closest Euclidean distance between point aP and the line defined by the ends of segment (t...
Definition: seg.cpp:341
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:269
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition: seg.h:143
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:93
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:115
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Definition: shape_arc.cpp:399
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.
void Simplify(int aMaxError=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
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.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
int SegmentCount() const
Return the number of segments in this line chain.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
bool OffsetLine(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, SHAPE_LINE_CHAIN &aLeft, SHAPE_LINE_CHAIN &aRight, bool aSimplify=false) const
Creates line chains aLeft and aRight offset to this line chain.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
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:145
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:217
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
Generic, UI-independent tool event.
Definition: tool_event.h:167
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
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:400
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
wxString GetClass() const override
Return the class name.
VECTOR2I GetPosition() const override
void SetMinMax(double aMin, double aMax)
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
void SetCurrent(double aCurrent, const wxString &aLabel)
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 MessageTextFromMinOptMax(const MINOPTMAX< int > &aValue) const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:75
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:380
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
@ CHT_GROUP
Definition: commit.h:45
@ CHT_UNGROUP
Definition: commit.h:46
#define _HKI(x)
static bool empty(const wxTextEntryBase *aCtrl)
@ LENGTH_CONSTRAINT
Definition: drc_rule.h:64
@ SKEW_CONSTRAINT
Definition: drc_rule.h:65
#define _(s)
#define IS_NEW
New item, just created.
#define IN_EDIT
Item currently edited.
EDA_UNITS
Definition: eda_units.h:46
@ IGNORE_GRID
#define HITTEST_THRESHOLD_PIXELS
static FILENAME_RESOLVER * resolver
Definition: export_idf.cpp:53
@ LAYER_UI_START
Definition: layer_ids.h:265
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:205
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_Cu
Definition: layer_ids.h:64
void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:40
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:408
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:71
#define NO_SETTER(owner, type)
Definition: property.h:774
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:765
#define REGISTER_TYPE(x)
Definition: property_mgr.h:371
constexpr double correction
const double epsilon
#define PNS_HOVER_ITEM
#define PNS_COLLISION
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition: pns_node.h:73
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:87
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
double DEG2RAD(double deg)
Definition: trigo.h:140
@ 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
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:638