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