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, bool aFull ) 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
269 BITMAPS GetMenuImage() const override
270 {
271 switch( m_tuningMode )
272 {
273 case SINGLE: return BITMAPS::ps_tune_length; break;
274 case DIFF_PAIR: return BITMAPS::ps_diff_pair_tune_length; break;
275 case DIFF_PAIR_SKEW: return BITMAPS::ps_diff_pair_tune_phase; break;
276 }
277
278 return BITMAPS::unknown;
279 }
280
282 BOARD_CONNECTED_ITEM* aStartItem,
283 LENGTH_TUNING_MODE aMode );
284
285 void EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
286
287 bool Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
288
289 void EditPush( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit,
290 const wxString& aCommitMsg = wxEmptyString, int aCommitFlags = 0 ) override;
291
292 void EditRevert( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
293
294 void Remove( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
295
296 bool MakeEditPoints( std::shared_ptr<EDIT_POINTS> points ) const override;
297
298 bool UpdateFromEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints,
299 BOARD_COMMIT* aCommit ) override;
300
301 bool UpdateEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints ) override;
302
303 void Move( const VECTOR2I& aMoveVector ) override
304 {
305 m_origin += aMoveVector;
306 m_end += aMoveVector;
307
308 if( !this->HasFlag( IN_EDIT ) )
309 {
310 PCB_GROUP::Move( aMoveVector );
311
312 if( m_baseLine )
313 m_baseLine->Move( aMoveVector );
314
316 m_baseLineCoupled->Move( aMoveVector );
317 }
318 }
319
320 void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override
321 {
322 if( !this->HasFlag( IN_EDIT ) )
323 {
324 PCB_GENERATOR::Rotate( aRotCentre, aAngle );
325 RotatePoint( m_end, aRotCentre, aAngle );
326
327 if( m_baseLine )
328 m_baseLine->Rotate( aAngle, aRotCentre );
329
331 m_baseLineCoupled->Rotate( aAngle, aRotCentre );
332 }
333 }
334
335 void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override
336 {
337 if( !this->HasFlag( IN_EDIT ) )
338 {
339 PCB_GENERATOR::Flip( aCentre, aFlipLeftRight );
340
341 if( aFlipLeftRight )
342 MIRROR( m_end.x, aCentre.x );
343 else
344 MIRROR( m_end.y, aCentre.y );
345
346 if( m_baseLine )
347 m_baseLine->Mirror( aFlipLeftRight, !aFlipLeftRight, aCentre );
348
350 m_baseLineCoupled->Mirror( aFlipLeftRight, !aFlipLeftRight, aCentre );
351 }
352 }
353
354 const BOX2I GetBoundingBox() const override
355 {
356 return getOutline().BBox();
357 }
358
359 void ViewGetLayers( int aLayers[], int& aCount ) const override
360 {
361 aCount = 0;
362 aLayers[aCount++] = LAYER_ANCHOR;
363 aLayers[aCount++] = GetLayer();
364 }
365
366 bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
367 {
368 return getOutline().Collide( aPosition, aAccuracy );
369 }
370
371 bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
372 {
373 BOX2I sel = aRect;
374
375 if ( aAccuracy )
376 sel.Inflate( aAccuracy );
377
378 if( aContained )
379 return sel.Contains( GetBoundingBox() );
380
381 return sel.Intersects( GetBoundingBox() );
382 }
383
384 const BOX2I ViewBBox() const override { return GetBoundingBox(); }
385
386 EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
387
388 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
389
390 const VECTOR2I& GetEnd() const { return m_end; }
391 void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
392
393 int GetEndX() const { return m_end.x; }
394 void SetEndX( int aValue ) { m_end.x = aValue; }
395
396 int GetEndY() const { return m_end.y; }
397 void SetEndY( int aValue ) { m_end.y = aValue; }
398
400
402 {
403 switch( m_tuningMode )
404 {
405 case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
406 case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
407 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
408 default: return PNS::PNS_MODE_TUNE_SINGLE;
409 }
410 }
411
413
415 void SetMinAmplitude( int aValue )
416 {
417 aValue = std::max( aValue, 0 );
418
419 m_settings.m_minAmplitude = aValue;
420
423 }
424
426 void SetMaxAmplitude( int aValue )
427 {
428 aValue = std::max( aValue, 0 );
429
430 m_settings.m_maxAmplitude = aValue;
431
434 }
435
438
439 int GetSpacing() const { return m_settings.m_spacing; }
440 void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
441
442 std::optional<int> GetTargetLength() const
443 {
445 return std::optional<int>();
446 else
448 }
449
450 void SetTargetLength( std::optional<int> aValue )
451 {
452 if( aValue.has_value() )
453 m_settings.SetTargetLength( aValue.value() );
454 else
456 }
457
458 int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
459 void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
460
462 void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
463
466
467 bool IsSingleSided() const { return m_settings.m_singleSided; }
468 void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
469
473
474 std::vector<std::pair<wxString, wxVariant>> GetRowData() override
475 {
476 std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
477 data.emplace_back( _HKI( "Net" ), m_lastNetName );
478 data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
479 return data;
480 }
481
482 const STRING_ANY_MAP GetProperties() const override;
483 void SetProperties( const STRING_ANY_MAP& aProps ) override;
484
485 void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
486
487 std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
488 bool aStatusItemsOnly = false ) override;
489
490 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
491
492protected:
493 void swapData( BOARD_ITEM* aImage ) override
494 {
495 wxASSERT( aImage->Type() == PCB_GENERATOR_T );
496
497 std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
498 }
499
500 bool recoverBaseline( PNS::ROUTER* aRouter );
501
502 bool baselineValid();
503
504 bool initBaseLine( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard, VECTOR2I& aStart,
505 VECTOR2I& aEnd, NETINFO_ITEM* aNet,
506 std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
507
508 bool initBaseLines( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard );
509
510 bool removeToBaseline( PNS::ROUTER* aRouter, int aLayer, SHAPE_LINE_CHAIN& aBaseLine );
511
512 bool resetToBaseline( GENERATOR_TOOL* aTool, int aLayer, SHAPE_LINE_CHAIN& aBaseLine,
513 bool aPrimary );
514
516
517protected:
519
521
522 std::optional<SHAPE_LINE_CHAIN> m_baseLine;
523 std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
524
527
529
531 wxString m_tuningInfo;
532
534};
535
536
537static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
538{
539 if( aStr == "single" )
541 else if( aStr == "diff_pair" )
543 else if( aStr == "diff_pair_skew" )
545 else
546 {
547 wxFAIL_MSG( wxS( "Unknown length tuning token" ) );
549 }
550}
551
552
553static std::string tuningToString( const LENGTH_TUNING_MODE aTuning )
554{
555 switch( aTuning )
556 {
557 case LENGTH_TUNING_MODE::SINGLE: return "single";
558 case LENGTH_TUNING_MODE::DIFF_PAIR: return "diff_pair";
559 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return "diff_pair_skew";
560 default: wxFAIL; return "";
561 }
562}
563
564
566{
567 switch( aRouterMode )
568 {
572 default: return LENGTH_TUNING_MODE::SINGLE;
573 }
574}
575
576
577static PNS::MEANDER_SIDE sideFromString( const std::string& aStr )
578{
579 if( aStr == "default" )
581 else if( aStr == "left" )
583 else if( aStr == "right" )
585 else
586 {
587 wxFAIL_MSG( wxS( "Unknown length-tuning side token" ) );
589 }
590}
591
592
594{
595 switch( aStatus )
596 {
597 case PNS::MEANDER_PLACER_BASE::TOO_LONG: return "too_long";
598 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: return "too_short";
599 case PNS::MEANDER_PLACER_BASE::TUNED: return "tuned";
600 default: wxFAIL; return "";
601 }
602}
603
604
606{
607 if( aStr == "too_long" )
609 else if( aStr == "too_short" )
611 else if( aStr == "tuned" )
613 else
614 {
615 wxFAIL_MSG( wxS( "Unknown tuning status token" ) );
617 }
618}
619
620
621static std::string sideToString( const PNS::MEANDER_SIDE aValue )
622{
623 switch( aValue )
624 {
625 case PNS::MEANDER_SIDE_DEFAULT: return "default";
626 case PNS::MEANDER_SIDE_LEFT: return "left";
627 case PNS::MEANDER_SIDE_RIGHT: return "right";
628 default: wxFAIL; return "";
629 }
630}
631
632
634 LENGTH_TUNING_MODE aMode ) :
635 PCB_GENERATOR( aParent, aLayer ),
636 m_trackWidth( 0 ),
637 m_diffPairGap( 0 ),
638 m_tuningMode( aMode ),
639 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED )
640{
643 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
645}
646
647
648static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
649 PCB_TRACK** aNearestTrack )
650{
652 VECTOR2I closestPt = aP;
653
654 for( PCB_TRACK *track : aBoard->Tracks() )
655 {
656 if( aNet && track->GetNet() != aNet )
657 continue;
658
659 VECTOR2I nearest;
660
661 if( track->Type() == PCB_ARC_T )
662 {
663 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
664 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
665 pcbArc->GetWidth() );
666
667 nearest = arc.NearestPoint( aP );
668 }
669 else
670 {
671 SEG seg( track->GetStart(), track->GetEnd() );
672 nearest = seg.NearestPoint( aP );
673 }
674
675 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
676
677 if( dist_sq < minDist_sq )
678 {
679 minDist_sq = dist_sq;
680 closestPt = nearest;
681
682 if( aNearestTrack )
683 *aNearestTrack = track;
684 }
685 }
686
687 return closestPt;
688}
689
690
692{
694 {
695 return( m_baseLine && m_baseLine->PointCount() > 1
696 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
697 }
698 else
699 {
700 return( m_baseLine && m_baseLine->PointCount() > 1 );
701 }
702}
703
704
706 PCB_BASE_EDIT_FRAME* aFrame,
707 BOARD_CONNECTED_ITEM* aStartItem,
708 LENGTH_TUNING_MODE aMode )
709{
710 BOARD* board = aStartItem->GetBoard();
712 DRC_CONSTRAINT constraint;
713 PCB_LAYER_ID layer = aStartItem->GetLayer();
714
715 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
716
717 switch( aMode )
718 {
719 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
720 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
721 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
722 }
723
724 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
725
726 if( !constraint.IsNull() )
727 {
728 if( aMode == DIFF_PAIR_SKEW )
729 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
730 else
731 pattern->m_settings.SetTargetLength( constraint.GetValue() );
732 }
733
734 pattern->SetFlags( IS_NEW );
735
736 return pattern;
737}
738
740{
741 if( aCommit )
742 {
743 if( IsNew() )
744 aCommit->Add( this );
745 else
746 aCommit->Modify( this );
747 }
748
749 SetFlags( IN_EDIT );
750
751 int layer = GetLayer();
752 PNS::ROUTER* router = aTool->Router();
753
754 aTool->ClearRouterChanges();
755 router->SyncWorld();
756
758 PNS::CONSTRAINT constraint;
759
760 if( !baselineValid() )
761 initBaseLines( router, layer, aBoard );
762
764 {
765 PCB_TRACK* track = nullptr;
766 PNS::SEGMENT pnsItem;
767
768 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
769 wxCHECK( track, /* void */ );
770
771 NETINFO_ITEM* net = track->GetNet();
772
773 pnsItem.SetParent( track );
774 pnsItem.SetNet( net );
775
776 if( m_tuningMode == SINGLE )
777 {
778 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
779 &pnsItem, nullptr, layer, &constraint ) )
780 {
781 m_settings.SetTargetLength( constraint.m_Value );
783 }
784 }
785 else
786 {
787 PCB_TRACK* coupledTrack = nullptr;
788 PNS::SEGMENT pnsCoupledItem;
789 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
790
791 if( coupledNet )
792 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
793
794 pnsCoupledItem.SetParent( coupledTrack );
795 pnsCoupledItem.SetNet( coupledNet );
796
797 if( m_tuningMode == DIFF_PAIR )
798 {
799 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
800 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
801 {
802 m_settings.SetTargetLength( constraint.m_Value );
804 }
805 }
806 else
807 {
809 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
810 {
811 m_settings.m_targetSkew = constraint.m_Value;
813 }
814 }
815 }
816 }
817}
818
819
820static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
821 VECTOR2I& aPointOut,
822 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
823{
824 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
825
826 static const int candidateCount = 2;
827 PNS::LINKED_ITEM* prioritized[candidateCount];
828 SEG::ecoord dist[candidateCount];
829 SEG::ecoord distBaseline[candidateCount];
830 VECTOR2I point[candidateCount];
831
832 for( int i = 0; i < candidateCount; i++ )
833 {
834 prioritized[i] = nullptr;
835 dist[i] = VECTOR2I::ECOORD_MAX;
836 distBaseline[i] = VECTOR2I::ECOORD_MAX;
837 }
838
839 for( int slopRadius : { 0, maxSlopRadius } )
840 {
841 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
842
843 for( PNS::ITEM* item : candidates.Items() )
844 {
845 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
846 continue;
847
848 if( !item->IsRoutable() )
849 continue;
850
851 if( !item->Layers().Overlaps( aLayer ) )
852 continue;
853
854 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
855
856 if( item->Kind() & PNS::ITEM::ARC_T )
857 {
858 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
859
860 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
861 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
862
863 if( d0 > dist[1] )
864 continue;
865
866 if( aBaseline.PointCount() > 0 )
867 {
868 SEG::ecoord dcBaseline;
869 VECTOR2I target = pnsArc->Arc().GetArcMid();
870
871 if( aBaseline.SegmentCount() > 0 )
872 dcBaseline = aBaseline.SquaredDistance( target );
873 else
874 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
875
876 if( dcBaseline > distBaseline[1] )
877 continue;
878
879 distBaseline[1] = dcBaseline;
880 }
881
882 prioritized[1] = linked;
883 dist[1] = d0;
884 point[1] = nearest;
885 }
886 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
887 {
888 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
889
890 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
891 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
892
893 if( dd > dist[1] )
894 continue;
895
896 if( aBaseline.PointCount() > 0 )
897 {
898 SEG::ecoord dcBaseline;
899 VECTOR2I target = segm->Shape()->Centre();
900
901 if( aBaseline.SegmentCount() > 0 )
902 dcBaseline = aBaseline.SquaredDistance( target );
903 else
904 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
905
906 if( dcBaseline > distBaseline[1] )
907 continue;
908
909 distBaseline[1] = dcBaseline;
910 }
911
912 prioritized[1] = segm;
913 dist[1] = dd;
914 point[1] = nearest;
915 }
916 }
917 }
918
919 PNS::LINKED_ITEM* rv = nullptr;
920
921 for( int i = 0; i < candidateCount; i++ )
922 {
923 PNS::LINKED_ITEM* item = prioritized[i];
924
925 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
926 {
927 rv = item;
928 aPointOut = point[i];
929 break;
930 }
931 }
932
933 return rv;
934}
935
936
937static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
938 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
939 VECTOR2I& aEndOut )
940{
941 PNS::NODE* world = router->GetWorld();
942
943 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
944 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
945
946 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
947 {
948 if( !testItem )
949 continue;
950
951 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
952 SHAPE_LINE_CHAIN oldChain = line.CLine();
953
954 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
955 return line;
956 }
957
958 return std::nullopt;
959}
960
961
962bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard,
963 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
964 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
965{
966 PNS::NODE* world = aRouter->GetWorld();
967
968 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
969 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
970
971 VECTOR2I startSnapPoint, endSnapPoint;
972
973 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aLayer, startSnapPoint );
974 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aLayer, endSnapPoint );
975
976 wxASSERT( startItem );
977 wxASSERT( endItem );
978
979 if( !startItem || !endItem )
980 return false;
981
982 PNS::LINE line = world->AssembleLine( startItem );
983 const SHAPE_LINE_CHAIN& chain = line.CLine();
984
985 wxASSERT( line.ContainsLink( endItem ) );
986
987 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
988 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
989
992 SHAPE_LINE_CHAIN post;
993
994 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
995
996 aBaseLine = mid;
997
998 return true;
999}
1000
1001
1002bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard )
1003{
1004 m_baseLineCoupled.reset();
1005
1006 PCB_TRACK* track = nullptr;
1007
1008 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
1009 wxCHECK( track, false );
1010
1011 NETINFO_ITEM* net = track->GetNet();
1012
1013 if( !initBaseLine( aRouter, aLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
1014 return false;
1015
1016 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
1017 // DRC rules against.
1019 {
1020 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
1021 {
1022 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
1023 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
1024
1025 return initBaseLine( aRouter, aLayer, aBoard, coupledStart, coupledEnd, coupledNet,
1027 }
1028
1029 return false;
1030 }
1031
1032 return true;
1033}
1034
1036 SHAPE_LINE_CHAIN& aBaseLine )
1037{
1038 VECTOR2I startSnapPoint, endSnapPoint;
1039
1040 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1041 aRouter, aLayer, startSnapPoint, endSnapPoint );
1042
1043 wxCHECK( pnsLine, false );
1044
1045 SHAPE_LINE_CHAIN pre;
1046 SHAPE_LINE_CHAIN mid;
1047 SHAPE_LINE_CHAIN post;
1048 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1049
1050 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
1051 aRouter->GetInterface()->RemoveItem( li );
1052
1053 aRouter->GetWorld()->Remove( *pnsLine );
1054
1055 SHAPE_LINE_CHAIN straightChain;
1056 straightChain.Append( pre );
1057 straightChain.Append( aBaseLine );
1058 straightChain.Append( post );
1059 straightChain.Simplify();
1060
1061 PNS::LINE straightLine( *pnsLine, straightChain );
1062
1063 aRouter->GetWorld()->Add( straightLine, false );
1064
1065 for( PNS::LINKED_ITEM* li : straightLine.Links() )
1066 aRouter->GetInterface()->AddItem( li );
1067
1068 return true;
1069}
1070
1071
1073{
1074 SetFlags( IN_EDIT );
1075
1076 aTool->Router()->SyncWorld();
1077
1078 PNS::ROUTER* router = aTool->Router();
1079 int layer = GetLayer();
1080
1081 // Ungroup first so that undo works
1082 if( !GetItems().empty() )
1083 {
1084 PCB_GENERATOR* group = this;
1085
1086 for( BOARD_ITEM* member : group->GetItems() )
1087 aCommit->Stage( member, CHT_UNGROUP );
1088
1089 group->GetItems().clear();
1090 }
1091
1092 aCommit->Remove( this );
1093
1094 aTool->ClearRouterChanges();
1095
1096 if( baselineValid() )
1097 {
1098 bool success = true;
1099
1100 success &= removeToBaseline( router, layer, *m_baseLine );
1101
1102 if( m_tuningMode == DIFF_PAIR )
1103 success &= removeToBaseline( router, layer, *m_baseLineCoupled );
1104
1105 if( !success )
1106 recoverBaseline( router );
1107 }
1108
1109 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
1110
1111 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
1112 {
1113 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
1114 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
1115
1116 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1117 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1118 << " m_removedItems " << m_removedItems.size() << std::endl;*/
1119
1120 for( BOARD_ITEM* item : routerRemovedItems )
1121 {
1122 item->ClearSelected();
1123 aCommit->Remove( item );
1124 }
1125
1126 for( BOARD_ITEM* item : routerAddedItems )
1127 aCommit->Add( item );
1128 }
1129
1130 aCommit->Push( "Remove Tuning Pattern" );
1131}
1132
1133
1135{
1136 PNS::SOLID queryItem;
1137
1138 SHAPE_LINE_CHAIN* chain = static_cast<SHAPE_LINE_CHAIN*>( getOutline().Clone() );
1139 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
1140 queryItem.SetLayer( m_layer );
1141
1142 int lineWidth = 0;
1143
1144 PNS::NODE::OBSTACLES obstacles;
1146 opts.m_useClearanceEpsilon = false;
1147
1148 PNS::NODE* world = aRouter->GetWorld();
1149 PNS::NODE* branch = world->Branch();
1150
1151 branch->QueryColliding( &queryItem, obstacles, opts );
1152
1153 for( const PNS::OBSTACLE& obs : obstacles )
1154 {
1155 PNS::ITEM* item = obs.m_item;
1156
1158 continue;
1159
1160 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
1161 {
1162 if( lineWidth == 0 || li->Width() < lineWidth )
1163 lineWidth = li->Width();
1164 }
1165
1166 if( chain->PointInside( item->Anchor( 0 ), 10 )
1167 && chain->PointInside( item->Anchor( 1 ), 10 ) )
1168 {
1169 branch->Remove( item );
1170 }
1171 }
1172
1173 if( lineWidth == 0 )
1174 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1175
1176 if( baselineValid() )
1177 {
1178 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1179 PNS::LINE recoverLine;
1180
1181 recoverLine.SetLayer( m_layer );
1182 recoverLine.SetWidth( lineWidth );
1183 recoverLine.Line() = *m_baseLine;
1184 recoverLine.SetNet( recoverNet );
1185 branch->Add( recoverLine, false );
1186
1188 {
1189 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1190 PNS::LINE recoverLineCoupled;
1191
1192 recoverLineCoupled.SetLayer( m_layer );
1193 recoverLineCoupled.SetWidth( lineWidth );
1194 recoverLineCoupled.Line() = *m_baseLineCoupled;
1195 recoverLineCoupled.SetNet( recoverCoupledNet );
1196 branch->Add( recoverLineCoupled, false );
1197 }
1198 }
1199
1200 aRouter->CommitRouting( branch );
1201
1202 //wxLogWarning( "PNS baseline recovered" );
1203
1204 return true;
1205}
1206
1207
1209 SHAPE_LINE_CHAIN& aBaseLine, bool aPrimary )
1210{
1211 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1212 PNS::ROUTER* router = aTool->Router();
1213 PNS::NODE* world = router->GetWorld();
1214 VECTOR2I startSnapPoint, endSnapPoint;
1215
1216 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1217 router, aLayer, startSnapPoint, endSnapPoint );
1218
1219 if( !pnsLine )
1220 {
1221 // TODO
1222 //recoverBaseline( aRouter );
1223 return true;
1224 }
1225
1226 PNS::NODE* branch = world->Branch();
1227
1228 SHAPE_LINE_CHAIN straightChain;
1229 {
1230 SHAPE_LINE_CHAIN pre, mid, post;
1231 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1232
1233 straightChain.Append( pre );
1234 straightChain.Append( aBaseLine );
1235 straightChain.Append( post );
1236 straightChain.Simplify();
1237 }
1238
1239 branch->Remove( *pnsLine );
1240
1241 SHAPE_LINE_CHAIN newLineChain;
1242
1243 if( aPrimary )
1244 {
1245 m_origin = straightChain.NearestPoint( m_origin );
1246 m_end = straightChain.NearestPoint( m_end );
1247
1248 // Don't allow points too close
1249 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1250 {
1251 m_origin = startSnapPoint;
1252 m_end = endSnapPoint;
1253 }
1254
1255 {
1256 SHAPE_LINE_CHAIN pre, mid, post;
1257 straightChain.Split( m_origin, m_end, pre, mid, post );
1258
1259 newLineChain.Append( pre );
1260 newLineChain.Append( mid );
1261 newLineChain.Append( post );
1262
1263 m_baseLine = mid;
1264 }
1265 }
1266 else
1267 {
1268 VECTOR2I start = straightChain.NearestPoint( m_origin );
1269 VECTOR2I end = straightChain.NearestPoint( m_end );
1270
1271 {
1272 SHAPE_LINE_CHAIN pre, mid, post;
1273 straightChain.Split( start, end, pre, mid, post );
1274
1275 newLineChain.Append( pre );
1276 newLineChain.Append( mid );
1277 newLineChain.Append( post );
1278
1279 m_baseLineCoupled = mid;
1280 }
1281 }
1282
1283 PNS::LINE newLine( *pnsLine, newLineChain );
1284
1285 branch->Add( newLine, false );
1286 router->CommitRouting( branch );
1287
1288 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1289
1290 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1291
1292 return true;
1293}
1294
1295
1297{
1298 if( !( GetFlags() & IN_EDIT ) )
1299 return false;
1300
1301 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1302 PNS::ROUTER* router = aTool->Router();
1303 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1304 int layer = GetLayer();
1305
1306 auto hideRemovedItems = [&]( bool aHide )
1307 {
1308 if( view )
1309 {
1310 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1311 {
1312 for( BOARD_ITEM* item : pnsCommit.removedItems )
1313 {
1314 if( view )
1315 view->Hide( item, aHide, aHide );
1316 }
1317 }
1318 }
1319 };
1320
1321 iface->SetStartLayer( layer );
1322
1323 if( router->RoutingInProgress() )
1324 {
1325 router->StopRouting();
1326 }
1327
1328 if( !baselineValid() )
1329 {
1330 initBaseLines( router, layer, aBoard );
1331 }
1332 else
1333 {
1334 if( resetToBaseline( aTool, layer, *m_baseLine, true ) )
1335 {
1336 m_origin = m_baseLine->CPoint( 0 );
1337 m_end = m_baseLine->CPoint( -1 );
1338 }
1339 else
1340 {
1341 //initBaseLines( router, layer, aBoard );
1342 return false;
1343 }
1344
1345 if( m_tuningMode == DIFF_PAIR )
1346 {
1347 if( !resetToBaseline( aTool, layer, *m_baseLineCoupled, false ) )
1348 {
1349 initBaseLines( router, layer, aBoard );
1350 return false;
1351 }
1352 }
1353 }
1354
1355 hideRemovedItems( true );
1356 // Snap points
1357 VECTOR2I startSnapPoint, endSnapPoint;
1358
1359 wxCHECK( m_baseLine, false );
1360
1361 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, layer, startSnapPoint, *m_baseLine);
1362 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, layer, endSnapPoint, *m_baseLine );
1363
1364 wxASSERT( startItem );
1365 wxASSERT( endItem );
1366
1367 if( !startItem || !endItem )
1368 return false;
1369
1370 router->SetMode( GetPNSMode() );
1371
1372 if( !router->StartRouting( startSnapPoint, startItem, layer ) )
1373 {
1374 //recoverBaseline( router );
1375 return false;
1376 }
1377
1378 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1379
1380 m_settings.m_keepEndpoints = true; // Required for re-grouping
1381 placer->UpdateSettings( m_settings );
1382
1383 router->Move( m_end, nullptr );
1384
1385 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1386 {
1387 m_trackWidth = dpPlacer->GetOriginPair().Width();
1388 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1389 }
1390 else
1391 {
1392 m_trackWidth = startItem->Width();
1393 m_diffPairGap = router->Sizes().DiffPairGap();
1394 }
1395
1396 m_settings = placer->MeanderSettings();
1397 m_lastNetName = iface->GetNetName( startItem->Net() );
1398 m_tuningStatus = placer->TuningStatus();
1399
1400 wxString statusMessage;
1401
1402 switch ( m_tuningStatus )
1403 {
1404 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1405 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1406 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1407 default: statusMessage = _( "unknown" ); break;
1408 }
1409
1410 wxString result;
1411 EDA_UNITS userUnits = EDA_UNITS::MILLIMETRES;
1412
1413 if( aTool->GetManager()->GetSettings() )
1414 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1415
1417 (double) placer->TuningResult() );
1418
1419 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1420
1421 return true;
1422}
1423
1424
1426 const wxString& aCommitMsg, int aCommitFlags )
1427{
1428 if( !( GetFlags() & IN_EDIT ) )
1429 return;
1430
1432
1433 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1434 PNS::ROUTER* router = aTool->Router();
1435 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1436 SHAPE_LINE_CHAIN bounds = getOutline();
1437 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1438
1439 iface->EraseView();
1440
1441 if( router->RoutingInProgress() )
1442 {
1443 bool forceFinish = true;
1444 bool forceCommit = false;
1445
1446 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1447 router->StopRouting();
1448 }
1449
1450 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1451
1452 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1453 {
1454 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1455 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1456
1457 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1458 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1459 // << " m_removedItems " << m_removedItems.size() << std::endl;
1460
1461 for( BOARD_ITEM* item : routerRemovedItems )
1462 {
1463 if( view )
1464 view->Hide( item, false );
1465
1466 aCommit->Remove( item );
1467 }
1468
1469 for( BOARD_ITEM* item : routerAddedItems )
1470 {
1471 aCommit->Add( item );
1472
1473 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1474 {
1475 if( bounds.PointInside( track->GetStart(), epsilon )
1476 && bounds.PointInside( track->GetEnd(), epsilon ) )
1477 {
1478 AddItem( item );
1479 aCommit->Stage( item, CHT_GROUP );
1480 }
1481 }
1482 }
1483 }
1484
1485 if( aCommitMsg.IsEmpty() )
1486 aCommit->Push( _( "Edit Tuning Pattern" ), aCommitFlags );
1487 else
1488 aCommit->Push( aCommitMsg, aCommitFlags );
1489}
1490
1491
1493{
1494 if( !( GetFlags() & IN_EDIT ) )
1495 return;
1496
1498
1499 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1500
1501 iface->EraseView();
1502
1503 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1504 {
1505 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1506 {
1507 for( BOARD_ITEM* item : pnsCommit.removedItems )
1508 view->Hide( item, false );
1509 }
1510 }
1511
1512 aTool->Router()->StopRouting();
1513
1514 if( aCommit )
1515 aCommit->Revert();
1516}
1517
1518
1519bool PCB_TUNING_PATTERN::MakeEditPoints( std::shared_ptr<EDIT_POINTS> points ) const
1520{
1521 VECTOR2I centerlineOffset;
1522 VECTOR2I centerlineOffsetEnd;
1523
1524 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1525 {
1526 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1527 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1528 }
1529
1530 points->AddPoint( m_origin + centerlineOffset );
1531 points->AddPoint( m_end + centerlineOffsetEnd );
1532
1533 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1534 : SEG( m_origin, m_end );
1535
1536 base.A += centerlineOffset;
1537 base.B += centerlineOffset;
1538
1539 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1540
1541 if( m_tuningMode == DIFF_PAIR )
1542 amplitude += m_trackWidth + m_diffPairGap;
1543
1544 if( m_settings.m_initialSide == -1 )
1545 amplitude *= -1;
1546
1547 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1548
1549 points->AddPoint( base.A + widthHandleOffset );
1550 points->Point( 2 ).SetGridConstraint( IGNORE_GRID );
1551
1552 VECTOR2I spacingHandleOffset =
1553 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1554
1555 points->AddPoint( base.A + spacingHandleOffset );
1556 points->Point( 3 ).SetGridConstraint( IGNORE_GRID );
1557
1558 return true;
1559}
1560
1561
1562bool PCB_TUNING_PATTERN::UpdateFromEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints,
1563 BOARD_COMMIT* aCommit )
1564{
1565 VECTOR2I centerlineOffset;
1566 VECTOR2I centerlineOffsetEnd;
1567
1568 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1569 {
1570 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1571 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1572 }
1573
1574 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1575 : SEG( m_origin, m_end );
1576
1577 base.A += centerlineOffset;
1578 base.B += centerlineOffset;
1579
1580 m_origin = aEditPoints->Point( 0 ).GetPosition() - centerlineOffset;
1581 m_end = aEditPoints->Point( 1 ).GetPosition() - centerlineOffsetEnd;
1582
1583 if( aEditPoints->Point( 2 ).IsActive() )
1584 {
1585 VECTOR2I wHandle = aEditPoints->Point( 2 ).GetPosition();
1586
1587 int value = base.LineDistance( wHandle );
1588
1589 value -= KiROUND( m_trackWidth / 2.0 );
1590
1591 if( m_tuningMode == DIFF_PAIR )
1592 value -= m_trackWidth + m_diffPairGap;
1593
1594 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1595
1596 int side = base.Side( wHandle );
1597
1598 if( side < 0 )
1600 else
1602 }
1603
1604 if( aEditPoints->Point( 3 ).IsActive() )
1605 {
1606 VECTOR2I wHandle = aEditPoints->Point( 2 ).GetPosition();
1607 VECTOR2I sHandle = aEditPoints->Point( 3 ).GetPosition();
1608
1609 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1610
1611 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1612 }
1613
1614 return true;
1615}
1616
1617
1618bool PCB_TUNING_PATTERN::UpdateEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints )
1619{
1620 VECTOR2I centerlineOffset;
1621 VECTOR2I centerlineOffsetEnd;
1622
1623 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1624 {
1625 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1626 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1627 }
1628
1629 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1630 : SEG( m_origin, m_end );
1631
1632 base.A += centerlineOffset;
1633 base.B += centerlineOffset;
1634
1635 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1636
1637 if( m_tuningMode == DIFF_PAIR )
1638 amplitude += m_trackWidth + m_diffPairGap;
1639
1640 if( m_settings.m_initialSide == -1 )
1641 amplitude *= -1;
1642
1643 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1644
1645 aEditPoints->Point( 0 ).SetPosition( m_origin + centerlineOffset );
1646 aEditPoints->Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1647
1648 aEditPoints->Point( 2 ).SetPosition( base.A + widthHandleOffset );
1649
1650 VECTOR2I spacingHandleOffset =
1651 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1652
1653 aEditPoints->Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1654
1655 return true;
1656}
1657
1658
1660{
1661 if( m_baseLine )
1662 {
1663 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1664 int minAllowedAmplitude = 0;
1665 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1666
1668 {
1669 minAllowedAmplitude = baselineOffset + m_trackWidth;
1670 }
1671 else
1672 {
1673 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1674 minAllowedAmplitude = baselineOffset + correction;
1675 }
1676
1677 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1678
1680 {
1681 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1683
1684 if( m_tuningMode != DIFF_PAIR )
1685 {
1686 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1687
1688 SHAPE_LINE_CHAIN chain;
1689
1690 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1691 left, right, true ) )
1692 {
1693 chain.Append( m_settings.m_initialSide >= 0 ? right : left );
1694 chain.Append( clBase.Reverse() );
1695 chain.SetClosed( true );
1696
1697 return chain;
1698 }
1699 }
1701 {
1702 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1703
1705 SHAPE_LINE_CHAIN chain1, chain2;
1706
1707 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1708 left, right, true ) )
1709 {
1710 if( m_settings.m_initialSide >= 0 )
1711 chain1.Append( right );
1712 else
1713 chain1.Append( left );
1714
1715 if( clBase.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1716 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1717 right, true ) )
1718 {
1719 if( m_settings.m_initialSide >= 0 )
1720 chain1.Append( left.Reverse() );
1721 else
1722 chain1.Append( right.Reverse() );
1723 }
1724
1725 chain1.SetClosed( true );
1726 }
1727
1728 if( clCoupled.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1729 ARC_LOW_DEF, left, right, true ) )
1730 {
1731 if( m_settings.m_initialSide >= 0 )
1732 chain2.Append( right );
1733 else
1734 chain2.Append( left );
1735
1736 if( clCoupled.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1737 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1738 right, true ) )
1739 {
1740 if( m_settings.m_initialSide >= 0 )
1741 chain2.Append( left.Reverse() );
1742 else
1743 chain2.Append( right.Reverse() );
1744 }
1745
1746 chain2.SetClosed( true );
1747 }
1748
1749 SHAPE_POLY_SET merged;
1750 merged.BooleanAdd( chain1, chain2, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1751
1752 if( merged.OutlineCount() > 0 )
1753 return merged.Outline( 0 );
1754 }
1755 }
1756
1757 // Not single-sided / fallback
1758 SHAPE_POLY_SET poly;
1760
1761 int amplitude = 0;
1762
1763 if( m_tuningMode == DIFF_PAIR )
1764 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1765 else
1766 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1767
1768 poly.OffsetLineChain( *m_baseLine, amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1769 ARC_LOW_DEF, false );
1770
1772 {
1773 SHAPE_POLY_SET polyCoupled;
1774 polyCoupled.OffsetLineChain( *m_baseLineCoupled, amplitude,
1775 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, false );
1776
1777 SHAPE_POLY_SET merged;
1778 merged.BooleanAdd( poly, polyCoupled, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1779
1780 if( merged.OutlineCount() > 0 )
1781 return merged.Outline( 0 );
1782 }
1783
1784 if( poly.OutlineCount() > 0 )
1785 return poly.Outline( 0 );
1786 }
1787
1788 return SHAPE_LINE_CHAIN();
1789}
1790
1791
1792void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1793{
1794 if( !IsSelected() && !IsNew() )
1795 return;
1796
1797 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1798
1799 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1800 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1801
1802 if( !HasFlag( IN_EDIT ) )
1803 {
1804 if( m_baseLine )
1805 {
1806 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1807 {
1808 SEG seg = m_baseLine->CSegment( i );
1809 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1810 }
1811 }
1812 else
1813 {
1814 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1815 }
1816
1818 {
1819 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1820 {
1821 SEG seg = m_baseLineCoupled->CSegment( i );
1822 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1823 }
1824 }
1825 }
1826
1827 SHAPE_LINE_CHAIN chain = getOutline();
1828
1829 for( int i = 0; i < chain.SegmentCount(); i++ )
1830 {
1831 SEG seg = chain.Segment( i );
1832 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1833 }
1834}
1835
1836
1838{
1840
1841 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
1842 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
1843 props.set( "last_status", statusToString( m_tuningStatus ) );
1844
1845 props.set( "end", m_end );
1846 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1847 props.set( "single_sided", m_settings.m_singleSided );
1849
1850 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
1851 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
1852 props.set_iu( "min_spacing", m_settings.m_spacing );
1853 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
1854 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
1855 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
1856 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
1857 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
1858 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
1859 props.set_iu( "last_track_width", m_trackWidth );
1860 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
1861
1862 props.set( "last_netname", m_lastNetName );
1863 props.set( "last_tuning", m_tuningInfo );
1864 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
1865
1866 if( m_baseLine )
1867 props.set( "base_line", wxAny( *m_baseLine ) );
1868
1869 if( m_baseLineCoupled )
1870 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
1871
1872 return props;
1873}
1874
1875
1877{
1879
1880 wxString tuningMode;
1881 aProps.get_to( "tuning_mode", tuningMode );
1882 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
1883
1884 wxString side;
1885 aProps.get_to( "initial_side", side );
1886 m_settings.m_initialSide = sideFromString( side.utf8_string() );
1887
1888 wxString status;
1889 aProps.get_to( "last_status", status );
1890 m_tuningStatus = statusFromString( status.utf8_string() );
1891
1892 aProps.get_to( "end", m_end );
1893 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1894 aProps.get_to( "single_sided", m_settings.m_singleSided );
1895 aProps.get_to( "side", m_settings.m_initialSide );
1896
1897 bool rounded = false;
1898 aProps.get_to( "rounded", rounded );
1900
1901 long long int val;
1902
1903 aProps.get_to_iu( "target_length", val );
1905
1906 if( aProps.get_to_iu( "target_length_min", val ) )
1908
1909 if( aProps.get_to_iu( "target_length_max", val ) )
1911
1912 int int_val;
1913
1914 aProps.get_to_iu( "target_skew", int_val );
1915 m_settings.SetTargetSkew( int_val );
1916
1917 if( aProps.get_to_iu( "target_skew_min", int_val ) )
1918 m_settings.m_targetSkew.SetMin( int_val );
1919
1920 if( aProps.get_to_iu( "target_skew_max", int_val ) )
1921 m_settings.m_targetSkew.SetMax( int_val );
1922
1923 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
1924 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
1925 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
1926 aProps.get_to_iu( "last_track_width", m_trackWidth );
1927 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
1928 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
1929
1930 aProps.get_to( "last_netname", m_lastNetName );
1931 aProps.get_to( "last_tuning", m_tuningInfo );
1932
1933 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
1934 m_baseLine = *baseLine;
1935
1936 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
1937 m_baseLineCoupled = *baseLineCoupled;
1938}
1939
1940
1942{
1944 DRC_CONSTRAINT constraint;
1945
1946 if( !m_items.empty() )
1947 {
1948 BOARD_ITEM* startItem = *m_items.begin();
1949 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1950
1951 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
1952
1953 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
1954 settings.SetTargetLength( constraint.GetValue() );
1955 }
1956
1957 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
1958
1959 if( dlg.ShowModal() == wxID_OK )
1960 {
1961 BOARD_COMMIT commit( aEditFrame );
1962 commit.Modify( this );
1963 m_settings = settings;
1964
1965 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
1966 EditStart( generatorTool, GetBoard(), &commit );
1967 Update( generatorTool, GetBoard(), &commit );
1968 EditPush( generatorTool, GetBoard(), &commit );
1969 }
1970}
1971
1972
1974 PCB_BASE_EDIT_FRAME* aFrame,
1975 bool aStatusItemsOnly )
1976{
1977 std::vector<EDA_ITEM*> previewItems;
1978 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
1979
1980 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
1981 {
1982 if( !aStatusItemsOnly )
1983 {
1984 PNS::ITEM_SET items = placer->TunedPath();
1985
1986 for( PNS::ITEM* item : items )
1987 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item, view, PNS_HOVER_ITEM ) );
1988 }
1989
1990 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
1991
1993 {
1995 }
1996 else
1997 {
1999 {
2000 statusItem->ClearMinMax();
2001 }
2002 else
2003 {
2004 statusItem->SetMinMax( (double) m_settings.m_targetLength.Min(),
2005 (double) m_settings.m_targetLength.Max() );
2006 }
2007 }
2008
2010 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current skew" ) );
2011 else
2012 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current length" ) );
2013
2014 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
2015 previewItems.push_back( statusItem );
2016 }
2017
2018 return previewItems;
2019}
2020
2021
2023 std::vector<MSG_PANEL_ITEM>& aList )
2024{
2025 wxString msg;
2026 NETINFO_ITEM* primaryNet = nullptr;
2027 NETINFO_ITEM* coupledNet = nullptr;
2028 PCB_TRACK* primaryItem = nullptr;
2029 PCB_TRACK* coupledItem = nullptr;
2030 NETCLASS* netclass = nullptr;
2031 int width = 0;
2032 bool mixedWidth = false;
2033
2034 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2035
2036 for( BOARD_ITEM* member : GetItems() )
2037 {
2038 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
2039 {
2040 if( !primaryNet )
2041 {
2042 primaryItem = track;
2043 primaryNet = track->GetNet();
2044 }
2045 else if( !coupledNet && track->GetNet() != primaryNet )
2046 {
2047 coupledItem = track;
2048 coupledNet = track->GetNet();
2049 }
2050
2051 if( !netclass )
2052 netclass = track->GetEffectiveNetClass();
2053
2054 if( !width )
2055 width = track->GetWidth();
2056 else if( width != track->GetWidth() )
2057 mixedWidth = true;
2058 }
2059 }
2060
2061 if( coupledNet )
2062 {
2063 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2064 + wxS( ", " )
2065 + UnescapeString( coupledNet->GetNetname() ) );
2066 }
2067 else if( primaryNet )
2068 {
2069 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2070 }
2071
2072 if( netclass )
2073 aList.emplace_back( _( "Resolved Netclass" ), UnescapeString( netclass->GetName() ) );
2074
2075 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
2076
2077 if( width && !mixedWidth )
2078 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2079
2080 BOARD* board = GetBoard();
2081 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2082 DRC_CONSTRAINT constraint;
2083
2084 // Display full track length (in Pcbnew)
2085 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2086 {
2087 int count;
2088 double trackLen;
2089 double lenPadToDie;
2090
2091 std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *primaryItem );
2092
2093 if( coupledItem && coupledItem->GetNetCode() > 0 )
2094 {
2095 double coupledLen;
2096 std::tie( count, coupledLen, lenPadToDie ) = board->GetTrackLength( *coupledItem );
2097
2098 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen )
2099 + wxS( ", " )
2100 + aFrame->MessageTextFromValue( coupledLen ) );
2101 }
2102 else
2103 {
2104 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2105 }
2106
2107 if( lenPadToDie != 0 )
2108 {
2109 msg = aFrame->MessageTextFromValue( lenPadToDie );
2110 aList.emplace_back( _( "Pad To Die Length" ), msg );
2111
2112 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2113 aList.emplace_back( _( "Full Length" ), msg );
2114 }
2115 }
2116
2118 {
2119 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2120
2121 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2122 {
2124
2125 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2126 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2127 }
2128 else
2129 {
2130 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2131
2132 if( !msg.IsEmpty() )
2133 {
2134 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2135 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2136 }
2137 }
2138 }
2139 else
2140 {
2141 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2142
2143 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2144 {
2145 msg = aFrame->MessageTextFromValue( (double) m_settings.m_targetLength.Opt() );
2146
2147 aList.emplace_back( wxString::Format( _( "Target Length: %s" ), msg ),
2148 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2149 }
2150 else
2151 {
2152 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2153
2154 if( !msg.IsEmpty() )
2155 {
2156 aList.emplace_back( wxString::Format( _( "Length Constraints: %s" ), msg ),
2157 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2158 }
2159 }
2160 }
2161}
2162
2163
2164const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2165const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2166
2167
2169
2170
2171#define HITTEST_THRESHOLD_PIXELS 5
2172
2173
2175{
2177 return 0;
2178
2179 if( m_inDrawingTool )
2180 return 0;
2181
2183
2185
2186 m_frame->PushTool( aEvent );
2187 Activate();
2188
2190 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2191 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2192 PNS::ROUTER* router = generatorTool->Router();
2194
2198 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2199
2200 m_pickerItem = nullptr;
2201 m_tuningPattern = nullptr;
2202
2203 // Add a VIEW_GROUP that serves as a preview for the new item
2204 m_preview.Clear();
2205 m_view->Add( &m_preview );
2206
2207 auto setCursor =
2208 [&]()
2209 {
2210 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
2211 controls->ShowCursor( true );
2212 };
2213
2214 auto updateHoverStatus =
2215 [&]()
2216 {
2217 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2218
2219 if( m_pickerItem )
2220 {
2221 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2222 m_pickerItem, mode ) );
2223 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2224 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2225 }
2226
2227 if( dummyPattern )
2228 {
2229 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2230 dummyPattern->Update( generatorTool, m_board, nullptr );
2231
2233
2234 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2235 m_preview.Add( item );
2236
2237 generatorTool->Router()->StopRouting();
2238
2239 m_view->Update( &m_preview );
2240 }
2241 else
2242 {
2244 m_view->Update( &m_preview );
2245 }
2246 };
2247
2248 auto updateTuningPattern =
2249 [&]()
2250 {
2252 {
2253 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2254 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2255
2257
2258 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame,
2259 true ) )
2260 {
2261 m_preview.Add( item );
2262 }
2263
2264 m_view->Update( &m_preview );
2265 }
2266 };
2267
2268 // Set initial cursor
2269 setCursor();
2270
2271 while( TOOL_EVENT* evt = Wait() )
2272 {
2273 setCursor();
2274 VECTOR2D cursorPos = controls->GetMousePosition();
2275
2276 if( evt->IsCancelInteractive() || evt->IsActivate()
2277 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2278 {
2279 if( m_tuningPattern )
2280 {
2281 // First click already made; clean up tuning pattern preview
2282 m_tuningPattern->EditRevert( generatorTool, m_board, nullptr );
2283
2284 delete m_tuningPattern;
2285 m_tuningPattern = nullptr;
2286 }
2287
2288 break;
2289 }
2290 else if( evt->IsMotion() )
2291 {
2292 if( !m_tuningPattern )
2293 {
2294 // First click not yet made; we're in highlight-net-under-cursor mode
2295
2296 GENERAL_COLLECTOR collector;
2297 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2298
2299 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2300 guide.SetIncludeSecondary( false );
2301 else
2302 guide.SetIncludeSecondary( true );
2303
2304 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2305
2306 if( collector.GetCount() > 1 )
2307 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2308
2309 m_pickerItem = nullptr;
2310
2311 if( collector.GetCount() > 0 )
2312 {
2313 double min_dist_sq = std::numeric_limits<double>::max();
2314
2315 for( EDA_ITEM* candidate : collector )
2316 {
2317 VECTOR2I candidatePos;
2318
2319 if( candidate->Type() == PCB_TRACE_T )
2320 {
2321 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2322 }
2323 else if( candidate->Type() == PCB_ARC_T )
2324 {
2325 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2326 }
2327
2328 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2329
2330 if( dist_sq < min_dist_sq )
2331 {
2332 min_dist_sq = dist_sq;
2333 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2334 }
2335 }
2336 }
2337
2338 updateHoverStatus();
2339 }
2340 else
2341 {
2342 // First click already made; we're in preview-tuning-pattern mode
2343
2344 m_tuningPattern->SetEnd( cursorPos );
2345 updateTuningPattern();
2346 }
2347 }
2348 else if( evt->IsClick( BUT_LEFT ) )
2349 {
2351 {
2352 // First click; create a tuning pattern
2353
2354 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2355 {
2356 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2357 "tuning patterns." ) );
2358 }
2359 else
2360 {
2362
2365 m_pickerItem, mode );
2366
2367 int dummyDist;
2368 int dummyClearance = std::numeric_limits<int>::max() / 2;
2369 VECTOR2I closestPt;
2370
2371 // With an artificially-large clearance this can't *not* collide, but the
2372 // if stmt keeps Coverity happy....
2373 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2374 &dummyDist, &closestPt ) )
2375 {
2376 m_tuningPattern->SetPosition( closestPt );
2377 m_tuningPattern->SetEnd( closestPt );
2378 }
2379
2381 }
2382 }
2383 else if( m_pickerItem && m_tuningPattern )
2384 {
2385 // Second click; we're done
2386 BOARD_COMMIT commit( m_frame );
2387
2388 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2389 m_tuningPattern->Update( generatorTool, m_board, &commit );
2390 m_tuningPattern->EditPush( generatorTool, m_board, &commit, _( "Tune" ) );
2391
2392 for( BOARD_ITEM* item : m_tuningPattern->GetItems() )
2393 item->SetSelected();
2394
2395 break;
2396 }
2397 }
2398 else if( evt->IsClick( BUT_RIGHT ) )
2399 {
2401 m_menu->ShowContextMenu( dummy );
2402 }
2403 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2404 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2405 {
2406 if( m_tuningPattern )
2407 {
2408 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2409
2410 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2411 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2412 updateTuningPattern();
2413 }
2414 else
2415 {
2416 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2417 }
2418 }
2419 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2420 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2421 {
2422 if( m_tuningPattern )
2423 {
2424 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2425
2426 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2427 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2428 updateTuningPattern();
2429 }
2430 else
2431 {
2432 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2433 }
2434 }
2435 else if( evt->IsAction( &PCB_ACTIONS::properties )
2436 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2437 {
2438 if( m_tuningPattern )
2439 {
2440 DRC_CONSTRAINT constraint;
2441
2442 if( !m_tuningPattern->GetItems().empty() )
2443 {
2444 BOARD_ITEM* startItem = *m_tuningPattern->GetItems().begin();
2445
2446 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2447 startItem->GetLayer() );
2448 }
2449
2451 m_tuningPattern->GetPNSMode(), constraint );
2452
2453 if( dlg.ShowModal() == wxID_OK )
2454 updateTuningPattern();
2455 }
2456 else
2457 {
2458 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2459 }
2460 }
2461 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2462 // but we don't at present have that, so we just knock out some of the egregious ones.
2463 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2464 {
2465 wxBell();
2466 }
2467 else
2468 {
2469 evt->SetPassEvent();
2470 }
2471
2472 controls->CaptureCursor( m_tuningPattern != nullptr );
2473 controls->SetAutoPan( m_tuningPattern != nullptr );
2474 }
2475
2476 controls->CaptureCursor( false );
2477 controls->SetAutoPan( false );
2478 controls->ForceCursorPosition( false );
2479 controls->ShowCursor( false );
2480 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2481
2483 m_view->Remove( &m_preview );
2484
2486
2487 if( m_tuningPattern )
2488 selectionTool->AddItemToSel( m_tuningPattern );
2489
2490 m_frame->PopTool( aEvent );
2491 return 0;
2492}
2493
2494
2496{
2498 {
2500 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2501 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2502 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2503
2505 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2506 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2507 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2508
2515
2516 const wxString groupTab = _HKI( "Pattern Properties" );
2517
2519 _HKI( "End X" ), &PCB_TUNING_PATTERN::SetEndX,
2520 &PCB_TUNING_PATTERN::GetEndX, PROPERTY_DISPLAY::PT_SIZE,
2522 groupTab );
2523
2525 _HKI( "End Y" ), &PCB_TUNING_PATTERN::SetEndY,
2526 &PCB_TUNING_PATTERN::GetEndY, PROPERTY_DISPLAY::PT_SIZE,
2528 groupTab );
2529
2531 _HKI( "Tuning Mode" ),
2534 groupTab );
2535
2537 _HKI( "Min Amplitude" ),
2540 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2541 groupTab );
2542
2544 _HKI( "Max Amplitude" ),
2547 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2548 groupTab );
2549
2551 _HKI( "Initial Side" ),
2554 groupTab );
2555
2557 _HKI( "Min Spacing" ), &PCB_TUNING_PATTERN::SetSpacing,
2558 &PCB_TUNING_PATTERN::GetSpacing, PROPERTY_DISPLAY::PT_SIZE,
2560 groupTab );
2561
2563 _HKI( "Corner Radius %" ),
2566 PROPERTY_DISPLAY::PT_DEFAULT, ORIGIN_TRANSFORMS::NOT_A_COORD ),
2567 groupTab );
2568
2569 auto isSkew =
2570 []( INSPECTABLE* aItem ) -> bool
2571 {
2572 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2573 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2574
2575 return false;
2576 };
2577
2578 auto notIsSkew =
2579 [&]( INSPECTABLE* aItem ) -> bool
2580 {
2581 return !isSkew( aItem );
2582 };
2583
2584 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2585 _HKI( "Target Length" ),
2588 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2589 groupTab )
2590 .SetAvailableFunc( notIsSkew );
2591
2592
2594 _HKI( "Target Skew" ), &PCB_TUNING_PATTERN::SetTargetSkew,
2596 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2597 groupTab )
2598 .SetAvailableFunc( isSkew );
2599
2600
2602 _HKI( "Override Custom Rules" ),
2605 groupTab );
2606
2608 _HKI( "Single-sided" ),
2611 groupTab );
2612
2614 _HKI( "Rounded" ), &PCB_TUNING_PATTERN::SetRounded,
2616 groupTab );
2617 }
2619
2622
2624
2625// Also register under the 7.99 name
2626template <typename T>
2628{
2630 {
2631 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2632 []()
2633 {
2634 return new T;
2635 } );
2636 }
2637};
2638
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr int ARC_LOW_DEF
Definition: base_units.h:119
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
static TOOL_ACTION undo
Definition: actions.h:68
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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:240
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:93
PCB_LAYER_ID m_layer
Definition: board_item.h:409
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:246
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:47
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:133
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:289
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition: board.cpp:1974
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1903
const TRACKS & Tracks() const
Definition: board.h:328
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:2283
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:877
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:156
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:148
bool IsNull() const
Definition: drc_rule.h:143
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:89
virtual const VECTOR2I GetFocusPosition() const
Similar to GetPosition, but allows items to return their visual center rather than their anchor.
Definition: eda_item.h:250
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:129
bool IsSelected() const
Definition: eda_item.h:110
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:131
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:130
bool IsNew() const
Definition: eda_item.h:107
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:277
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:324
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:207
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:485
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, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=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:258
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:317
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:357
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:1687
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:203
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:484
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1635
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
Gets the consolidated name of this netclass (which may be an aggregate)
Definition: netclass.cpp:151
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:178
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:209
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:210
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:211
static TOOL_ACTION lengthTunerSettings
Definition: pcb_actions.h:212
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:208
const VECTOR2I & GetMid() const
Definition: pcb_track.h:281
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.
bool AddItem(BOARD_ITEM *aItem) override
Add item to group.
VECTOR2I m_origin
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_generator.h:83
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
VECTOR2I GetPosition() const override
Definition: pcb_generator.h:82
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:218
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:69
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_group.cpp:345
wxString m_name
Definition: pcb_group.h:219
The selection tool: currently supports:
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
bool m_isFootprintEditor
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
virtual int GetWidth() const
Definition: pcb_track.h:116
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
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
static const wxString DISPLAY_NAME
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
PNS::ROUTER_MODE GetPNSMode()
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
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
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:83
void SetTargetLength(long long int aOpt)
Definition: pns_meander.cpp:55
static const long long int LENGTH_UNCONSTRAINED
Definition: pns_meander.h:71
int m_cornerRadiusPercentage
Place meanders on one side.
Definition: pns_meander.h:109
MEANDER_SIDE m_initialSide
Allowable tuning error.
Definition: pns_meander.h:115
bool m_singleSided
Initial side when placing meanders at segment.
Definition: pns_meander.h:112
MINOPTMAX< long long int > m_targetLength
Target skew value for diff pair de-skewing.
Definition: pns_meander.h:98
void SetTargetSkew(int aOpt)
Definition: pns_meander.cpp:84
MINOPTMAX< int > m_targetSkew
Definition: pns_meander.h:101
MEANDER_STYLE m_cornerStyle
Rounding percentage (0 - 100).
Definition: pns_meander.h:106
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition: pns_meander.h:86
bool m_overrideCustomRules
Type of corners for the meandered line.
Definition: pns_meander.h:103
int m_spacing
Amplitude/spacing adjustment step.
Definition: pns_meander.h:89
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:1017
virtual void RemoveItem(ITEM *aItem)=0
virtual void AddItem(ITEM *aItem)=0
void SetMode(ROUTER_MODE aMode)
void StopRouting()
Definition: pns_router.cpp:908
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:217
ROUTER_IFACE * GetInterface() const
Definition: pns_router.h:219
void CommitRouting()
Definition: pns_router.cpp:899
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:181
bool RoutingInProgress() const
Definition: pns_router.cpp:117
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:393
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:212
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
Definition: pns_router.cpp:861
NODE * GetWorld() const
Definition: pns_router.h:165
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:453
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:428
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:327
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:116
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Definition: shape_arc.cpp:417
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:146
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:218
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
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
VECTOR2D GetMousePosition() const
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:400
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
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:76
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:383
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:66
@ SKEW_CONSTRAINT
Definition: drc_rule.h:67
#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:266
@ 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:229
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, bool aQuiet=false)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:100
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:676