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
58#include <router/pns_meander.h>
60#include <router/pns_segment.h>
61#include <router/pns_arc.h>
62#include <router/pns_solid.h>
63#include <router/pns_topology.h>
65
67
68
70{
74};
75
76
78{
79public:
81 EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
82 m_frame( aFrame ),
83 m_min( 0.0 ),
84 m_max( 0.0 ),
85 m_current( 0.0 )
86 { }
87
88 wxString GetClass() const override { return wxT( "TUNING_STATUS" ); }
89
90#if defined(DEBUG)
91 void Show( int nestLevel, std::ostream& os ) const override {}
92#endif
93
94 VECTOR2I GetPosition() const override { return m_pos; }
95 void SetPosition( const VECTOR2I& aPos ) override { m_pos = aPos; };
96
97 void SetMinMax( double aMin, double aMax )
98 {
99 m_min = aMin;
101 m_max = aMax;
103 }
104
106 {
107 m_min = 0.0;
108 m_minText = wxT( "---" );
109 m_max = std::numeric_limits<double>::max();
110 m_maxText = wxT( "---" );
111 }
112
113 void SetCurrent( double aCurrent, const wxString& aLabel )
114 {
115 m_current = aCurrent;
117 m_currentLabel = aLabel;
118 }
119
120 const BOX2I ViewBBox() const override
121 {
122 BOX2I tmp;
123
124 // this is an edit-time artefact; no reason to try and be smart with the bounding box
125 // (besides, we can't tell the text extents without a view to know what the scale is)
126 tmp.SetMaximum();
127 return tmp;
128 }
129
130 void ViewGetLayers( int aLayers[], int& aCount ) const override
131 {
132 aLayers[0] = LAYER_UI_START;
133 aLayers[1] = LAYER_UI_START + 1;
134 aCount = 2;
135 }
136
137 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override
138 {
139 KIGFX::GAL* gal = aView->GetGAL();
140 bool viewFlipped = gal->IsFlippedX();
141 bool drawingDropShadows = ( aLayer == LAYER_UI_START );
142
143 gal->Save();
144 gal->Scale( { 1., 1. } );
145
149 const KIFONT::METRICS& fontMetrics = KIFONT::METRICS::Default();
150 TEXT_ATTRIBUTES textAttrs;
151
152 int glyphWidth = textDims.GlyphSize.x;
153 VECTOR2I margin( KiROUND( glyphWidth * 0.4 ), KiROUND( glyphWidth ) );
154 VECTOR2I size( glyphWidth * 25 + margin.x * 2, headerDims.GlyphSize.y + textDims.GlyphSize.y );
155 VECTOR2I offset( margin.x * 2, -( size.y + margin.y * 2 ) );
156
157 if( drawingDropShadows )
158 {
159 gal->SetIsFill( true );
160 gal->SetIsStroke( true );
161 gal->SetLineWidth( gal->GetScreenWorldMatrix().GetScale().x * 2 );
162 gal->SetStrokeColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) );
163 KIGFX::COLOR4D bgColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
164 gal->SetFillColor( bgColor.WithAlpha( 0.9 ) );
165
166 gal->DrawRectangle( GetPosition() + offset - margin,
167 GetPosition() + offset + size + margin );
168 gal->Restore();
169 return;
170 }
171
172 COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
173 COLOR4D normal = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
174 COLOR4D red;
175
176 // Choose a red with reasonable contrasting with the background
177 double bg_h, bg_s, bg_l;
178 bg.ToHSL( bg_h, bg_s, bg_l );
179 red.FromHSL( 0, 1.0, bg_l < 0.5 ? 0.7 : 0.3 );
180
181 if( viewFlipped )
183 else
184 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
185
186 gal->SetIsFill( false );
187 gal->SetIsStroke( true );
188 gal->SetStrokeColor( normal );
189 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
190
191 // Prevent text flipping when view is flipped
192 if( gal->IsFlippedX() )
193 {
194 textAttrs.m_Mirrored = true;
196 }
197
198 textAttrs.m_Size = headerDims.GlyphSize;
199 textAttrs.m_StrokeWidth = headerDims.StrokeWidth;
200
201 VECTOR2I textPos = GetPosition() + offset;
202 font->Draw( gal, m_currentLabel, textPos, textAttrs, KIFONT::METRICS::Default() );
203
204 textPos.x += glyphWidth * 11 + margin.x;
205 font->Draw( gal, _( "min" ), textPos, textAttrs, fontMetrics );
206
207 textPos.x += glyphWidth * 7 + margin.x;
208 font->Draw( gal, _( "max" ), textPos, textAttrs, fontMetrics );
209
210 textAttrs.m_Size = textDims.GlyphSize;
211 textAttrs.m_StrokeWidth = textDims.StrokeWidth;
212
213 textPos = GetPosition() + offset;
214 textPos.y += KiROUND( headerDims.LinePitch * 1.3 );
215 font->Draw( gal, m_currentText, textPos, textAttrs, KIFONT::METRICS::Default() );
216
217 textPos.x += glyphWidth * 11 + margin.x;
219 font->Draw( gal, m_minText, textPos, textAttrs, fontMetrics );
220
221 textPos.x += glyphWidth * 7 + margin.x;
223 font->Draw( gal, m_maxText, textPos, textAttrs, fontMetrics );
224
225 gal->Restore();
226 }
227
228protected:
231 double m_min;
232 double m_max;
233 double m_current;
236 wxString m_minText;
237 wxString m_maxText;
238};
239
240
242{
243public:
244 static const wxString GENERATOR_TYPE;
245 static const wxString DISPLAY_NAME;
246
247 PCB_TUNING_PATTERN( BOARD_ITEM* aParent = nullptr, PCB_LAYER_ID aLayer = F_Cu,
248 LENGTH_TUNING_MODE aMode = LENGTH_TUNING_MODE::SINGLE );
249
250 wxString GetGeneratorType() const override { return wxS( "tuning_pattern" ); }
251
252 wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override
253 {
254 return wxString( _( "Tuning Pattern" ) );
255 }
256
257 wxString GetFriendlyName() const override
258 {
259 return wxString( _( "Tuning Pattern" ) );
260 }
261
262 wxString GetPluralName() const override
263 {
264 return wxString( _( "Tuning Patterns" ) );
265 }
266
268 BOARD_CONNECTED_ITEM* aStartItem,
269 LENGTH_TUNING_MODE aMode );
270
271 void EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
272
273 bool Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
274
275 void EditPush( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit,
276 const wxString& aCommitMsg = wxEmptyString, int aCommitFlags = 0 ) override;
277
278 void EditRevert( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
279
280 void Remove( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
281
282 bool MakeEditPoints( std::shared_ptr<EDIT_POINTS> points ) const override;
283
284 bool UpdateFromEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints,
285 BOARD_COMMIT* aCommit ) override;
286
287 bool UpdateEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints ) override;
288
289 void Move( const VECTOR2I& aMoveVector ) override
290 {
291 m_origin += aMoveVector;
292 m_end += aMoveVector;
293
294 if( !this->HasFlag( IN_EDIT ) )
295 {
296 PCB_GROUP::Move( aMoveVector );
297
298 if( m_baseLine )
299 m_baseLine->Move( aMoveVector );
300
302 m_baseLineCoupled->Move( aMoveVector );
303 }
304 }
305
306 void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override
307 {
308 if( !this->HasFlag( IN_EDIT ) )
309 {
310 RotatePoint( m_origin, aRotCentre, aAngle );
311 RotatePoint( m_end, aRotCentre, aAngle );
312 PCB_GROUP::Rotate( aRotCentre, aAngle );
313
314 if( m_baseLine )
315 m_baseLine->Rotate( aAngle, aRotCentre );
316
318 m_baseLineCoupled->Rotate( aAngle, aRotCentre );
319 }
320 }
321
322 const BOX2I GetBoundingBox() const override
323 {
324 return getOutline().BBox();
325 }
326
327 void ViewGetLayers( int aLayers[], int& aCount ) const override
328 {
329 aCount = 0;
330 aLayers[aCount++] = LAYER_ANCHOR;
331 aLayers[aCount++] = GetLayer();
332 }
333
334 bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
335 {
336 return getOutline().Collide( aPosition, aAccuracy );
337 }
338
339 bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
340 {
341 BOX2I sel = aRect;
342
343 if ( aAccuracy )
344 sel.Inflate( aAccuracy );
345
346 if( aContained )
347 return sel.Contains( GetBoundingBox() );
348
349 return sel.Intersects( GetBoundingBox() );
350 }
351
352 const BOX2I ViewBBox() const override { return GetBoundingBox(); }
353
354 EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
355
356 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
357
358 const VECTOR2I& GetEnd() const { return m_end; }
359 void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
360
361 int GetEndX() const { return m_end.x; }
362 void SetEndX( int aValue ) { m_end.x = aValue; }
363
364 int GetEndY() const { return m_end.y; }
365 void SetEndY( int aValue ) { m_end.y = aValue; }
366
368
370 {
371 switch( m_tuningMode )
372 {
373 case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
374 case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
375 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
376 default: return PNS::PNS_MODE_TUNE_SINGLE;
377 }
378 }
379
381
383 void SetMinAmplitude( int aValue )
384 {
385 aValue = std::max( aValue, 0 );
386
387 m_settings.m_minAmplitude = aValue;
388
391 }
392
394 void SetMaxAmplitude( int aValue )
395 {
396 aValue = std::max( aValue, 0 );
397
398 m_settings.m_maxAmplitude = aValue;
399
402 }
403
406
407 int GetSpacing() const { return m_settings.m_spacing; }
408 void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
409
410 std::optional<int> GetTargetLength() const
411 {
413 return std::optional<int>();
414 else
416 }
417
418 void SetTargetLength( std::optional<int> aValue )
419 {
420 if( aValue.has_value() )
421 m_settings.SetTargetLength( aValue.value() );
422 else
424 }
425
426 int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
427 void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
428
430 void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
431
434
435 bool IsSingleSided() const { return m_settings.m_singleSided; }
436 void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
437
441
442 std::vector<std::pair<wxString, wxVariant>> GetRowData() override
443 {
444 std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
445 data.emplace_back( _HKI( "Net" ), m_lastNetName );
446 data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
447 return data;
448 }
449
450 const STRING_ANY_MAP GetProperties() const override;
451 void SetProperties( const STRING_ANY_MAP& aProps ) override;
452
453 void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
454
455 std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
456 bool aStatusItemsOnly = false ) override;
457
458 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
459
460protected:
461 void swapData( BOARD_ITEM* aImage ) override
462 {
463 wxASSERT( aImage->Type() == PCB_GENERATOR_T );
464
465 std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
466 }
467
468 bool recoverBaseline( PNS::ROUTER* aRouter );
469
470 bool baselineValid();
471
472 bool initBaseLine( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard, VECTOR2I& aStart,
473 VECTOR2I& aEnd, NETINFO_ITEM* aNet,
474 std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
475
476 bool initBaseLines( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard );
477
478 bool removeToBaseline( PNS::ROUTER* aRouter, int aLayer, SHAPE_LINE_CHAIN& aBaseLine );
479
480 bool resetToBaseline( GENERATOR_TOOL* aTool, int aLayer, SHAPE_LINE_CHAIN& aBaseLine,
481 bool aPrimary );
482
484
485protected:
487
489
490 std::optional<SHAPE_LINE_CHAIN> m_baseLine;
491 std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
492
495
497
499 wxString m_tuningInfo;
500
502};
503
504
505static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
506{
507 if( aStr == "single" )
509 else if( aStr == "diff_pair" )
511 else if( aStr == "diff_pair_skew" )
513 else
514 {
515 wxFAIL_MSG( wxS( "Unknown length tuning token" ) );
517 }
518}
519
520
521static std::string tuningToString( const LENGTH_TUNING_MODE aTuning )
522{
523 switch( aTuning )
524 {
525 case LENGTH_TUNING_MODE::SINGLE: return "single";
526 case LENGTH_TUNING_MODE::DIFF_PAIR: return "diff_pair";
527 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return "diff_pair_skew";
528 default: wxFAIL; return "";
529 }
530}
531
532
534{
535 switch( aRouterMode )
536 {
540 default: return LENGTH_TUNING_MODE::SINGLE;
541 }
542}
543
544
545static PNS::MEANDER_SIDE sideFromString( const std::string& aStr )
546{
547 if( aStr == "default" )
549 else if( aStr == "left" )
551 else if( aStr == "right" )
553 else
554 {
555 wxFAIL_MSG( wxS( "Unknown length-tuning side token" ) );
557 }
558}
559
560
562{
563 switch( aStatus )
564 {
565 case PNS::MEANDER_PLACER_BASE::TOO_LONG: return "too_long";
566 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: return "too_short";
567 case PNS::MEANDER_PLACER_BASE::TUNED: return "tuned";
568 default: wxFAIL; return "";
569 }
570}
571
572
574{
575 if( aStr == "too_long" )
577 else if( aStr == "too_short" )
579 else if( aStr == "tuned" )
581 else
582 {
583 wxFAIL_MSG( wxS( "Unknown tuning status token" ) );
585 }
586}
587
588
589static std::string sideToString( const PNS::MEANDER_SIDE aValue )
590{
591 switch( aValue )
592 {
593 case PNS::MEANDER_SIDE_DEFAULT: return "default";
594 case PNS::MEANDER_SIDE_LEFT: return "left";
595 case PNS::MEANDER_SIDE_RIGHT: return "right";
596 default: wxFAIL; return "";
597 }
598}
599
600
602 LENGTH_TUNING_MODE aMode ) :
603 PCB_GENERATOR( aParent, aLayer ),
604 m_trackWidth( 0 ),
605 m_diffPairGap( 0 ),
606 m_tuningMode( aMode ),
607 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED )
608{
611 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
613}
614
615
616static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
617 PCB_TRACK** aNearestTrack )
618{
620 VECTOR2I closestPt = aP;
621
622 for( PCB_TRACK *track : aBoard->Tracks() )
623 {
624 if( aNet && track->GetNet() != aNet )
625 continue;
626
627 VECTOR2I nearest;
628
629 if( track->Type() == PCB_ARC_T )
630 {
631 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
632 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
633 pcbArc->GetWidth() );
634
635 nearest = arc.NearestPoint( aP );
636 }
637 else
638 {
639 SEG seg( track->GetStart(), track->GetEnd() );
640 nearest = seg.NearestPoint( aP );
641 }
642
643 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
644
645 if( dist_sq < minDist_sq )
646 {
647 minDist_sq = dist_sq;
648 closestPt = nearest;
649
650 if( aNearestTrack )
651 *aNearestTrack = track;
652 }
653 }
654
655 return closestPt;
656}
657
658
660{
662 {
663 return( m_baseLine && m_baseLine->PointCount() > 1
664 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
665 }
666 else
667 {
668 return( m_baseLine && m_baseLine->PointCount() > 1 );
669 }
670}
671
672
674 PCB_BASE_EDIT_FRAME* aFrame,
675 BOARD_CONNECTED_ITEM* aStartItem,
676 LENGTH_TUNING_MODE aMode )
677{
678 BOARD* board = aStartItem->GetBoard();
680 DRC_CONSTRAINT constraint;
681 PCB_LAYER_ID layer = aStartItem->GetLayer();
682
683 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
684
685 switch( aMode )
686 {
687 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
688 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
689 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
690 }
691
692 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
693
694 if( !constraint.IsNull() )
695 {
696 if( aMode == DIFF_PAIR_SKEW )
697 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
698 else
699 pattern->m_settings.SetTargetLength( constraint.GetValue() );
700 }
701
702 pattern->SetFlags( IS_NEW );
703
704 return pattern;
705}
706
708{
709 if( aCommit )
710 {
711 if( IsNew() )
712 aCommit->Add( this );
713 else
714 aCommit->Modify( this );
715 }
716
717 SetFlags( IN_EDIT );
718
719 int layer = GetLayer();
720 PNS::ROUTER* router = aTool->Router();
721
722 aTool->ClearRouterChanges();
723 router->SyncWorld();
724
726 PNS::CONSTRAINT constraint;
727
728 if( !baselineValid() )
729 initBaseLines( router, layer, aBoard );
730
732 {
733 PCB_TRACK* track = nullptr;
734 PNS::SEGMENT pnsItem;
735
736 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
737 wxCHECK( track, /* void */ );
738
739 NETINFO_ITEM* net = track->GetNet();
740
741 pnsItem.SetParent( track );
742 pnsItem.SetNet( net );
743
744 if( m_tuningMode == SINGLE )
745 {
746 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
747 &pnsItem, nullptr, layer, &constraint ) )
748 {
749 m_settings.SetTargetLength( constraint.m_Value );
751 }
752 }
753 else
754 {
755 PCB_TRACK* coupledTrack = nullptr;
756 PNS::SEGMENT pnsCoupledItem;
757 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
758
759 if( coupledNet )
760 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
761
762 pnsCoupledItem.SetParent( coupledTrack );
763 pnsCoupledItem.SetNet( coupledNet );
764
765 if( m_tuningMode == DIFF_PAIR )
766 {
767 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
768 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
769 {
770 m_settings.SetTargetLength( constraint.m_Value );
772 }
773 }
774 else
775 {
777 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
778 {
779 m_settings.m_targetSkew = constraint.m_Value;
781 }
782 }
783 }
784 }
785}
786
787
788static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
789 VECTOR2I& aPointOut,
790 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
791{
792 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
793
794 static const int candidateCount = 2;
795 PNS::LINKED_ITEM* prioritized[candidateCount];
796 SEG::ecoord dist[candidateCount];
797 SEG::ecoord distBaseline[candidateCount];
798 VECTOR2I point[candidateCount];
799
800 for( int i = 0; i < candidateCount; i++ )
801 {
802 prioritized[i] = nullptr;
803 dist[i] = VECTOR2I::ECOORD_MAX;
804 distBaseline[i] = VECTOR2I::ECOORD_MAX;
805 }
806
807 for( int slopRadius : { 0, maxSlopRadius } )
808 {
809 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
810
811 for( PNS::ITEM* item : candidates.Items() )
812 {
813 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
814 continue;
815
816 if( !item->IsRoutable() )
817 continue;
818
819 if( !item->Layers().Overlaps( aLayer ) )
820 continue;
821
822 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
823
824 if( item->Kind() & PNS::ITEM::ARC_T )
825 {
826 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
827
828 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
829 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
830
831 if( d0 > dist[1] )
832 continue;
833
834 if( aBaseline.PointCount() > 0 )
835 {
836 SEG::ecoord dcBaseline;
837 VECTOR2I target = pnsArc->Arc().GetArcMid();
838
839 if( aBaseline.SegmentCount() > 0 )
840 dcBaseline = aBaseline.SquaredDistance( target );
841 else
842 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
843
844 if( dcBaseline > distBaseline[1] )
845 continue;
846
847 distBaseline[1] = dcBaseline;
848 }
849
850 prioritized[1] = linked;
851 dist[1] = d0;
852 point[1] = nearest;
853 }
854 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
855 {
856 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
857
858 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
859 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
860
861 if( dd > dist[1] )
862 continue;
863
864 if( aBaseline.PointCount() > 0 )
865 {
866 SEG::ecoord dcBaseline;
867 VECTOR2I target = segm->Shape()->Centre();
868
869 if( aBaseline.SegmentCount() > 0 )
870 dcBaseline = aBaseline.SquaredDistance( target );
871 else
872 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
873
874 if( dcBaseline > distBaseline[1] )
875 continue;
876
877 distBaseline[1] = dcBaseline;
878 }
879
880 prioritized[1] = segm;
881 dist[1] = dd;
882 point[1] = nearest;
883 }
884 }
885 }
886
887 PNS::LINKED_ITEM* rv = nullptr;
888
889 for( int i = 0; i < candidateCount; i++ )
890 {
891 PNS::LINKED_ITEM* item = prioritized[i];
892
893 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
894 {
895 rv = item;
896 aPointOut = point[i];
897 break;
898 }
899 }
900
901 return rv;
902}
903
904
905static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
906 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
907 VECTOR2I& aEndOut )
908{
909 PNS::NODE* world = router->GetWorld();
910
911 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
912 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
913
914 //wxCHECK( startItem && endItem, std::nullopt );
915
916 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
917 {
918 if( !testItem )
919 continue;
920
921 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
922 SHAPE_LINE_CHAIN oldChain = line.CLine();
923
924 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
925 return line;
926 }
927
928 return std::nullopt;
929}
930
931
932bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard,
933 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
934 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
935{
936 PNS::NODE* world = aRouter->GetWorld();
937
938 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
939 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
940
941 VECTOR2I startSnapPoint, endSnapPoint;
942
943 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aLayer, startSnapPoint );
944 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aLayer, endSnapPoint );
945
946 wxASSERT( startItem );
947 wxASSERT( endItem );
948
949 if( !startItem || !endItem )
950 return false;
951
952 PNS::LINE line = world->AssembleLine( startItem );
953 const SHAPE_LINE_CHAIN& chain = line.CLine();
954
955 wxASSERT( line.ContainsLink( endItem ) );
956
957 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
958 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
959
962 SHAPE_LINE_CHAIN post;
963
964 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
965
966 aBaseLine = mid;
967
968 return true;
969}
970
971
972bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aLayer, BOARD* aBoard )
973{
974 m_baseLineCoupled.reset();
975
976 PCB_TRACK* track = nullptr;
977
978 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
979 wxCHECK( track, false );
980
981 NETINFO_ITEM* net = track->GetNet();
982
983 if( !initBaseLine( aRouter, aLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
984 return false;
985
986 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
987 // DRC rules against.
989 {
990 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
991 {
992 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
993 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
994
995 return initBaseLine( aRouter, aLayer, aBoard, coupledStart, coupledEnd, coupledNet,
997 }
998
999 return false;
1000 }
1001
1002 return true;
1003}
1004
1006 SHAPE_LINE_CHAIN& aBaseLine )
1007{
1008 VECTOR2I startSnapPoint, endSnapPoint;
1009
1010 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1011 aRouter, aLayer, startSnapPoint, endSnapPoint );
1012
1013 wxCHECK( pnsLine, false );
1014
1015 SHAPE_LINE_CHAIN pre;
1016 SHAPE_LINE_CHAIN mid;
1017 SHAPE_LINE_CHAIN post;
1018 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1019
1020 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
1021 aRouter->GetInterface()->RemoveItem( li );
1022
1023 aRouter->GetWorld()->Remove( *pnsLine );
1024
1025 SHAPE_LINE_CHAIN straightChain;
1026 straightChain.Append( pre );
1027 straightChain.Append( aBaseLine );
1028 straightChain.Append( post );
1029 straightChain.Simplify();
1030
1031 PNS::LINE straightLine( *pnsLine, straightChain );
1032
1033 aRouter->GetWorld()->Add( straightLine, false );
1034
1035 for( PNS::LINKED_ITEM* li : straightLine.Links() )
1036 aRouter->GetInterface()->AddItem( li );
1037
1038 return true;
1039}
1040
1041
1043{
1044 SetFlags( IN_EDIT );
1045
1046 aTool->Router()->SyncWorld();
1047
1048 PNS::ROUTER* router = aTool->Router();
1049 int layer = GetLayer();
1050
1051 // Ungroup first so that undo works
1052 if( !GetItems().empty() )
1053 {
1054 PCB_GENERATOR* group = this;
1055
1056 for( BOARD_ITEM* member : group->GetItems() )
1057 aCommit->Stage( member, CHT_UNGROUP );
1058
1059 group->GetItems().clear();
1060 }
1061
1062 aCommit->Remove( this );
1063
1064 aTool->ClearRouterChanges();
1065
1066 if( baselineValid() )
1067 {
1068 bool success = true;
1069
1070 success &= removeToBaseline( router, layer, *m_baseLine );
1071
1072 if( m_tuningMode == DIFF_PAIR )
1073 success &= removeToBaseline( router, layer, *m_baseLineCoupled );
1074
1075 if( !success )
1076 recoverBaseline( router );
1077 }
1078
1079 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
1080
1081 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
1082 {
1083 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
1084 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
1085
1086 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1087 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1088 << " m_removedItems " << m_removedItems.size() << std::endl;*/
1089
1090 for( BOARD_ITEM* item : routerRemovedItems )
1091 {
1092 item->ClearSelected();
1093 aCommit->Remove( item );
1094 }
1095
1096 for( BOARD_ITEM* item : routerAddedItems )
1097 aCommit->Add( item );
1098 }
1099
1100 aCommit->Push( "Remove Tuning Pattern" );
1101}
1102
1103
1105{
1106 PNS::SOLID queryItem;
1107
1108 SHAPE_LINE_CHAIN* chain = static_cast<SHAPE_LINE_CHAIN*>( getOutline().Clone() );
1109 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
1110 queryItem.SetLayer( m_layer );
1111
1112 int lineWidth = 0;
1113
1114 PNS::NODE::OBSTACLES obstacles;
1116 opts.m_useClearanceEpsilon = false;
1117
1118 PNS::NODE* world = aRouter->GetWorld();
1119 PNS::NODE* branch = world->Branch();
1120
1121 branch->QueryColliding( &queryItem, obstacles, opts );
1122
1123 for( const PNS::OBSTACLE& obs : obstacles )
1124 {
1125 PNS::ITEM* item = obs.m_item;
1126
1128 continue;
1129
1130 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
1131 {
1132 if( lineWidth == 0 || li->Width() < lineWidth )
1133 lineWidth = li->Width();
1134 }
1135
1136 if( chain->PointInside( item->Anchor( 0 ), 10 )
1137 && chain->PointInside( item->Anchor( 1 ), 10 ) )
1138 {
1139 branch->Remove( item );
1140 }
1141 }
1142
1143 if( lineWidth == 0 )
1144 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1145
1146 if( baselineValid() )
1147 {
1148 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1149 PNS::LINE recoverLine;
1150
1151 recoverLine.SetLayer( m_layer );
1152 recoverLine.SetWidth( lineWidth );
1153 recoverLine.Line() = *m_baseLine;
1154 recoverLine.SetNet( recoverNet );
1155 branch->Add( recoverLine, false );
1156
1158 {
1159 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1160 PNS::LINE recoverLineCoupled;
1161
1162 recoverLineCoupled.SetLayer( m_layer );
1163 recoverLineCoupled.SetWidth( lineWidth );
1164 recoverLineCoupled.Line() = *m_baseLineCoupled;
1165 recoverLineCoupled.SetNet( recoverCoupledNet );
1166 branch->Add( recoverLineCoupled, false );
1167 }
1168 }
1169
1170 aRouter->CommitRouting( branch );
1171
1172 //wxLogWarning( "PNS baseline recovered" );
1173
1174 return true;
1175}
1176
1177
1179 SHAPE_LINE_CHAIN& aBaseLine, bool aPrimary )
1180{
1181 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1182 PNS::ROUTER* router = aTool->Router();
1183 PNS::NODE* world = router->GetWorld();
1184 VECTOR2I startSnapPoint, endSnapPoint;
1185
1186 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1187 router, aLayer, startSnapPoint, endSnapPoint );
1188
1189 if( !pnsLine )
1190 {
1191 // TODO
1192 //recoverBaseline( aRouter );
1193 return true;
1194 }
1195
1196 PNS::NODE* branch = world->Branch();
1197
1198 SHAPE_LINE_CHAIN straightChain;
1199 {
1200 SHAPE_LINE_CHAIN pre, mid, post;
1201 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1202
1203 straightChain.Append( pre );
1204 straightChain.Append( aBaseLine );
1205 straightChain.Append( post );
1206 straightChain.Simplify();
1207 }
1208
1209 branch->Remove( *pnsLine );
1210
1211 SHAPE_LINE_CHAIN newLineChain;
1212
1213 if( aPrimary )
1214 {
1215 m_origin = straightChain.NearestPoint( m_origin );
1216 m_end = straightChain.NearestPoint( m_end );
1217
1218 // Don't allow points too close
1219 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1220 {
1221 m_origin = startSnapPoint;
1222 m_end = endSnapPoint;
1223 }
1224
1225 {
1226 SHAPE_LINE_CHAIN pre, mid, post;
1227 straightChain.Split( m_origin, m_end, pre, mid, post );
1228
1229 newLineChain.Append( pre );
1230 newLineChain.Append( mid );
1231 newLineChain.Append( post );
1232
1233 m_baseLine = mid;
1234 }
1235 }
1236 else
1237 {
1238 VECTOR2I start = straightChain.NearestPoint( m_origin );
1239 VECTOR2I end = straightChain.NearestPoint( m_end );
1240
1241 {
1242 SHAPE_LINE_CHAIN pre, mid, post;
1243 straightChain.Split( start, end, pre, mid, post );
1244
1245 newLineChain.Append( pre );
1246 newLineChain.Append( mid );
1247 newLineChain.Append( post );
1248
1249 m_baseLineCoupled = mid;
1250 }
1251 }
1252
1253 PNS::LINE newLine( *pnsLine, newLineChain );
1254
1255 branch->Add( newLine, false );
1256 router->CommitRouting( branch );
1257
1258 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1259
1260 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1261
1262 return true;
1263}
1264
1265
1267{
1268 if( !( GetFlags() & IN_EDIT ) )
1269 return false;
1270
1271 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1272 PNS::ROUTER* router = aTool->Router();
1273 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1274 int layer = GetLayer();
1275
1276 auto hideRemovedItems = [&]( bool aHide )
1277 {
1278 if( view )
1279 {
1280 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1281 {
1282 for( BOARD_ITEM* item : pnsCommit.removedItems )
1283 {
1284 if( view )
1285 view->Hide( item, aHide, aHide );
1286 }
1287 }
1288 }
1289 };
1290
1291 iface->SetStartLayer( layer );
1292
1293 if( router->RoutingInProgress() )
1294 {
1295 router->StopRouting();
1296 }
1297
1298 if( !baselineValid() )
1299 {
1300 initBaseLines( router, layer, aBoard );
1301 }
1302 else
1303 {
1304 if( resetToBaseline( aTool, layer, *m_baseLine, true ) )
1305 {
1306 m_origin = m_baseLine->CPoint( 0 );
1307 m_end = m_baseLine->CPoint( -1 );
1308 }
1309 else
1310 {
1311 //initBaseLines( router, layer, aBoard );
1312 return false;
1313 }
1314
1315 if( m_tuningMode == DIFF_PAIR )
1316 {
1317 if( !resetToBaseline( aTool, layer, *m_baseLineCoupled, false ) )
1318 {
1319 initBaseLines( router, layer, aBoard );
1320 return false;
1321 }
1322 }
1323 }
1324
1325 hideRemovedItems( true );
1326 // Snap points
1327 VECTOR2I startSnapPoint, endSnapPoint;
1328
1329 wxCHECK( m_baseLine, false );
1330
1331 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, layer, startSnapPoint, *m_baseLine);
1332 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, layer, endSnapPoint, *m_baseLine );
1333
1334 wxASSERT( startItem );
1335 wxASSERT( endItem );
1336
1337 if( !startItem || !endItem )
1338 return false;
1339
1340 router->SetMode( GetPNSMode() );
1341
1342 if( !router->StartRouting( startSnapPoint, startItem, layer ) )
1343 {
1344 //recoverBaseline( router );
1345 return false;
1346 }
1347
1348 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1349
1350 m_settings.m_keepEndpoints = true; // Required for re-grouping
1351 placer->UpdateSettings( m_settings );
1352
1353 router->Move( m_end, nullptr );
1354
1355 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1356 {
1357 m_trackWidth = dpPlacer->GetOriginPair().Width();
1358 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1359 }
1360 else
1361 {
1362 m_trackWidth = startItem->Width();
1363 m_diffPairGap = router->Sizes().DiffPairGap();
1364 }
1365
1366 m_settings = placer->MeanderSettings();
1367 m_lastNetName = iface->GetNetName( startItem->Net() );
1368 m_tuningStatus = placer->TuningStatus();
1369
1370 wxString statusMessage;
1371
1372 switch ( m_tuningStatus )
1373 {
1374 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1375 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1376 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1377 default: statusMessage = _( "unknown" ); break;
1378 }
1379
1380 wxString result;
1381 EDA_UNITS userUnits = EDA_UNITS::MILLIMETRES;
1382
1383 if( aTool->GetManager()->GetSettings() )
1384 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1385
1387 (double) placer->TuningResult() );
1388
1389 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1390
1391 return true;
1392}
1393
1394
1396 const wxString& aCommitMsg, int aCommitFlags )
1397{
1398 if( !( GetFlags() & IN_EDIT ) )
1399 return;
1400
1402
1403 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1404 PNS::ROUTER* router = aTool->Router();
1405 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1406 SHAPE_LINE_CHAIN bounds = getOutline();
1407 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1408
1409 iface->EraseView();
1410
1411 if( router->RoutingInProgress() )
1412 {
1413 bool forceFinish = true;
1414 bool forceCommit = false;
1415
1416 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1417 router->StopRouting();
1418 }
1419
1420 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1421
1422 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1423 {
1424 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1425 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1426
1427 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1428 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1429 // << " m_removedItems " << m_removedItems.size() << std::endl;
1430
1431 for( BOARD_ITEM* item : routerRemovedItems )
1432 {
1433 if( view )
1434 view->Hide( item, false );
1435
1436 aCommit->Remove( item );
1437 }
1438
1439 for( BOARD_ITEM* item : routerAddedItems )
1440 {
1441 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1442 {
1443 if( bounds.PointInside( track->GetStart(), epsilon )
1444 && bounds.PointInside( track->GetEnd(), epsilon ) )
1445 {
1446 AddItem( item );
1447 aCommit->Stage( item, CHT_GROUP );
1448 }
1449 }
1450
1451 aCommit->Add( item );
1452 }
1453 }
1454
1455 if( aCommitMsg.IsEmpty() )
1456 aCommit->Push( _( "Edit Tuning Pattern" ), aCommitFlags );
1457 else
1458 aCommit->Push( aCommitMsg, aCommitFlags );
1459}
1460
1461
1463{
1464 if( !( GetFlags() & IN_EDIT ) )
1465 return;
1466
1468
1469 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1470
1471 iface->EraseView();
1472
1473 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1474 {
1475 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1476 {
1477 for( BOARD_ITEM* item : pnsCommit.removedItems )
1478 view->Hide( item, false );
1479 }
1480 }
1481
1482 aTool->Router()->StopRouting();
1483
1484 if( aCommit )
1485 aCommit->Revert();
1486}
1487
1488
1489bool PCB_TUNING_PATTERN::MakeEditPoints( std::shared_ptr<EDIT_POINTS> points ) const
1490{
1491 VECTOR2I centerlineOffset;
1492 VECTOR2I centerlineOffsetEnd;
1493
1494 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1495 {
1496 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1497 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1498 }
1499
1500 points->AddPoint( m_origin + centerlineOffset );
1501 points->AddPoint( m_end + centerlineOffsetEnd );
1502
1503 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1504 : SEG( m_origin, m_end );
1505
1506 base.A += centerlineOffset;
1507 base.B += centerlineOffset;
1508
1509 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1510
1511 if( m_tuningMode == DIFF_PAIR )
1512 amplitude += m_trackWidth + m_diffPairGap;
1513
1514 if( m_settings.m_initialSide == -1 )
1515 amplitude *= -1;
1516
1517 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1518
1519 points->AddPoint( base.A + widthHandleOffset );
1520 points->Point( 2 ).SetGridConstraint( IGNORE_GRID );
1521
1522 VECTOR2I spacingHandleOffset =
1523 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1524
1525 points->AddPoint( base.A + spacingHandleOffset );
1526 points->Point( 3 ).SetGridConstraint( IGNORE_GRID );
1527
1528 return true;
1529}
1530
1531
1532bool PCB_TUNING_PATTERN::UpdateFromEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints,
1533 BOARD_COMMIT* aCommit )
1534{
1535 VECTOR2I centerlineOffset;
1536 VECTOR2I centerlineOffsetEnd;
1537
1538 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1539 {
1540 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1541 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1542 }
1543
1544 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1545 : SEG( m_origin, m_end );
1546
1547 base.A += centerlineOffset;
1548 base.B += centerlineOffset;
1549
1550 m_origin = aEditPoints->Point( 0 ).GetPosition() - centerlineOffset;
1551 m_end = aEditPoints->Point( 1 ).GetPosition() - centerlineOffsetEnd;
1552
1553 if( aEditPoints->Point( 2 ).IsActive() )
1554 {
1555 VECTOR2I wHandle = aEditPoints->Point( 2 ).GetPosition();
1556
1557 int value = base.LineDistance( wHandle );
1558
1559 value -= KiROUND( m_trackWidth / 2.0 );
1560
1561 if( m_tuningMode == DIFF_PAIR )
1562 value -= m_trackWidth + m_diffPairGap;
1563
1564 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1565
1566 int side = base.Side( wHandle );
1567
1568 if( side < 0 )
1570 else
1572 }
1573
1574 if( aEditPoints->Point( 3 ).IsActive() )
1575 {
1576 VECTOR2I wHandle = aEditPoints->Point( 2 ).GetPosition();
1577 VECTOR2I sHandle = aEditPoints->Point( 3 ).GetPosition();
1578
1579 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1580
1581 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1582 }
1583
1584 return true;
1585}
1586
1587
1588bool PCB_TUNING_PATTERN::UpdateEditPoints( std::shared_ptr<EDIT_POINTS> aEditPoints )
1589{
1590 VECTOR2I centerlineOffset;
1591 VECTOR2I centerlineOffsetEnd;
1592
1593 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1594 {
1595 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1596 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1597 }
1598
1599 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1600 : SEG( m_origin, m_end );
1601
1602 base.A += centerlineOffset;
1603 base.B += centerlineOffset;
1604
1605 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1606
1607 if( m_tuningMode == DIFF_PAIR )
1608 amplitude += m_trackWidth + m_diffPairGap;
1609
1610 if( m_settings.m_initialSide == -1 )
1611 amplitude *= -1;
1612
1613 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1614
1615 aEditPoints->Point( 0 ).SetPosition( m_origin + centerlineOffset );
1616 aEditPoints->Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1617
1618 aEditPoints->Point( 2 ).SetPosition( base.A + widthHandleOffset );
1619
1620 VECTOR2I spacingHandleOffset =
1621 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1622
1623 aEditPoints->Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1624
1625 return true;
1626}
1627
1628
1630{
1631 if( m_baseLine )
1632 {
1633 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1634 int minAllowedAmplitude = 0;
1635 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1636
1638 {
1639 minAllowedAmplitude = baselineOffset + m_trackWidth;
1640 }
1641 else
1642 {
1643 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1644 minAllowedAmplitude = baselineOffset + correction;
1645 }
1646
1647 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1648
1650 {
1651 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1653
1654 if( m_tuningMode != DIFF_PAIR )
1655 {
1656 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1657
1658 SHAPE_LINE_CHAIN chain;
1659
1660 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1661 left, right, true ) )
1662 {
1663 chain.Append( m_settings.m_initialSide >= 0 ? right : left );
1664 chain.Append( clBase.Reverse() );
1665 chain.SetClosed( true );
1666
1667 return chain;
1668 }
1669 }
1671 {
1672 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1673
1675 SHAPE_LINE_CHAIN chain1, chain2;
1676
1677 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1678 left, right, true ) )
1679 {
1680 if( m_settings.m_initialSide >= 0 )
1681 chain1.Append( right );
1682 else
1683 chain1.Append( left );
1684
1685 if( clBase.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1686 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1687 right, true ) )
1688 {
1689 if( m_settings.m_initialSide >= 0 )
1690 chain1.Append( left.Reverse() );
1691 else
1692 chain1.Append( right.Reverse() );
1693 }
1694
1695 chain1.SetClosed( true );
1696 }
1697
1698 if( clCoupled.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1699 ARC_LOW_DEF, left, right, true ) )
1700 {
1701 if( m_settings.m_initialSide >= 0 )
1702 chain2.Append( right );
1703 else
1704 chain2.Append( left );
1705
1706 if( clCoupled.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1707 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1708 right, true ) )
1709 {
1710 if( m_settings.m_initialSide >= 0 )
1711 chain2.Append( left.Reverse() );
1712 else
1713 chain2.Append( right.Reverse() );
1714 }
1715
1716 chain2.SetClosed( true );
1717 }
1718
1719 SHAPE_POLY_SET merged;
1720 merged.BooleanAdd( chain1, chain2, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1721
1722 if( merged.OutlineCount() > 0 )
1723 return merged.Outline( 0 );
1724 }
1725 }
1726
1727 // Not single-sided / fallback
1728 SHAPE_POLY_SET poly;
1730
1731 int amplitude = 0;
1732
1733 if( m_tuningMode == DIFF_PAIR )
1734 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1735 else
1736 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1737
1738 poly.OffsetLineChain( *m_baseLine, amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1739 ARC_LOW_DEF, false );
1740
1742 {
1743 SHAPE_POLY_SET polyCoupled;
1744 polyCoupled.OffsetLineChain( *m_baseLineCoupled, amplitude,
1745 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, false );
1746
1747 SHAPE_POLY_SET merged;
1748 merged.BooleanAdd( poly, polyCoupled, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1749
1750 if( merged.OutlineCount() > 0 )
1751 return merged.Outline( 0 );
1752 }
1753
1754 if( poly.OutlineCount() > 0 )
1755 return poly.Outline( 0 );
1756 }
1757
1758 return SHAPE_LINE_CHAIN();
1759}
1760
1761
1762void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1763{
1764 if( !IsSelected() && !IsNew() )
1765 return;
1766
1767 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1768
1769 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1770 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1771
1772 if( !HasFlag( IN_EDIT ) )
1773 {
1774 if( m_baseLine )
1775 {
1776 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1777 {
1778 SEG seg = m_baseLine->CSegment( i );
1779 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1780 }
1781 }
1782 else
1783 {
1784 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1785 }
1786
1788 {
1789 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1790 {
1791 SEG seg = m_baseLineCoupled->CSegment( i );
1792 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1793 }
1794 }
1795 }
1796
1797 SHAPE_LINE_CHAIN chain = getOutline();
1798
1799 for( int i = 0; i < chain.SegmentCount(); i++ )
1800 {
1801 SEG seg = chain.Segment( i );
1802 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1803 }
1804}
1805
1806
1808{
1810
1811 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
1812 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
1813 props.set( "last_status", statusToString( m_tuningStatus ) );
1814
1815 props.set( "end", m_end );
1816 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1817 props.set( "single_sided", m_settings.m_singleSided );
1819
1820 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
1821 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
1822 props.set_iu( "min_spacing", m_settings.m_spacing );
1823 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
1824 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
1825 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
1826 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
1827 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
1828 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
1829 props.set_iu( "last_track_width", m_trackWidth );
1830 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
1831
1832 props.set( "last_netname", m_lastNetName );
1833 props.set( "last_tuning", m_tuningInfo );
1834 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
1835
1836 if( m_baseLine )
1837 props.set( "base_line", wxAny( *m_baseLine ) );
1838
1839 if( m_baseLineCoupled )
1840 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
1841
1842 return props;
1843}
1844
1845
1847{
1849
1850 wxString tuningMode;
1851 aProps.get_to( "tuning_mode", tuningMode );
1852 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
1853
1854 wxString side;
1855 aProps.get_to( "initial_side", side );
1856 m_settings.m_initialSide = sideFromString( side.utf8_string() );
1857
1858 wxString status;
1859 aProps.get_to( "last_status", status );
1860 m_tuningStatus = statusFromString( status.utf8_string() );
1861
1862 aProps.get_to( "end", m_end );
1863 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1864 aProps.get_to( "single_sided", m_settings.m_singleSided );
1865 aProps.get_to( "side", m_settings.m_initialSide );
1866
1867 bool rounded = false;
1868 aProps.get_to( "rounded", rounded );
1870
1871 long long int val;
1872
1873 aProps.get_to_iu( "target_length", val );
1875
1876 if( aProps.get_to_iu( "target_length_min", val ) )
1878
1879 if( aProps.get_to_iu( "target_length_max", val ) )
1881
1882 int int_val;
1883
1884 aProps.get_to_iu( "target_skew", int_val );
1885 m_settings.SetTargetSkew( int_val );
1886
1887 if( aProps.get_to_iu( "target_skew_min", int_val ) )
1888 m_settings.m_targetSkew.SetMin( int_val );
1889
1890 if( aProps.get_to_iu( "target_skew_max", int_val ) )
1891 m_settings.m_targetSkew.SetMax( int_val );
1892
1893 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
1894 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
1895 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
1896 aProps.get_to_iu( "last_track_width", m_trackWidth );
1897 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
1898 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
1899
1900 aProps.get_to( "last_netname", m_lastNetName );
1901 aProps.get_to( "last_tuning", m_tuningInfo );
1902
1903 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
1904 m_baseLine = *baseLine;
1905
1906 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
1907 m_baseLineCoupled = *baseLineCoupled;
1908}
1909
1910
1912{
1914 DRC_CONSTRAINT constraint;
1915
1916 if( !m_items.empty() )
1917 {
1918 BOARD_ITEM* startItem = *m_items.begin();
1919 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1920
1921 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
1922
1923 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
1924 settings.SetTargetLength( constraint.GetValue() );
1925 }
1926
1927 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
1928
1929 if( dlg.ShowModal() == wxID_OK )
1930 {
1931 BOARD_COMMIT commit( aEditFrame );
1932 commit.Modify( this );
1933 m_settings = settings;
1934
1935 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
1936 EditStart( generatorTool, GetBoard(), &commit );
1937 Update( generatorTool, GetBoard(), &commit );
1938 EditPush( generatorTool, GetBoard(), &commit );
1939 }
1940}
1941
1942
1944 PCB_BASE_EDIT_FRAME* aFrame,
1945 bool aStatusItemsOnly )
1946{
1947 std::vector<EDA_ITEM*> previewItems;
1948 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
1949
1950 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
1951 {
1952 if( !aStatusItemsOnly )
1953 {
1954 PNS::ITEM_SET items = placer->TunedPath();
1955
1956 for( PNS::ITEM* item : items )
1957 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item, view, PNS_HOVER_ITEM ) );
1958 }
1959
1960 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
1961
1963 {
1965 }
1966 else
1967 {
1969 {
1970 statusItem->ClearMinMax();
1971 }
1972 else
1973 {
1974 statusItem->SetMinMax( (double) m_settings.m_targetLength.Min(),
1975 (double) m_settings.m_targetLength.Max() );
1976 }
1977 }
1978
1980 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current skew" ) );
1981 else
1982 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current length" ) );
1983
1984 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
1985 previewItems.push_back( statusItem );
1986 }
1987
1988 return previewItems;
1989}
1990
1991
1993 std::vector<MSG_PANEL_ITEM>& aList )
1994{
1995 wxString msg;
1996 NETINFO_ITEM* primaryNet = nullptr;
1997 NETINFO_ITEM* coupledNet = nullptr;
1998 PCB_TRACK* primaryItem = nullptr;
1999 PCB_TRACK* coupledItem = nullptr;
2000 NETCLASS* netclass = nullptr;
2001 int width = 0;
2002 bool mixedWidth = false;
2003
2004 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2005
2006 for( BOARD_ITEM* member : GetItems() )
2007 {
2008 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
2009 {
2010 if( !primaryNet )
2011 {
2012 primaryItem = track;
2013 primaryNet = track->GetNet();
2014 }
2015 else if( !coupledNet && track->GetNet() != primaryNet )
2016 {
2017 coupledItem = track;
2018 coupledNet = track->GetNet();
2019 }
2020
2021 if( !netclass )
2022 netclass = track->GetEffectiveNetClass();
2023
2024 if( !width )
2025 width = track->GetWidth();
2026 else if( width != track->GetWidth() )
2027 mixedWidth = true;
2028 }
2029 }
2030
2031 if( coupledNet )
2032 {
2033 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2034 + wxS( ", " )
2035 + UnescapeString( coupledNet->GetNetname() ) );
2036 }
2037 else if( primaryNet )
2038 {
2039 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2040 }
2041
2042 if( netclass )
2043 aList.emplace_back( _( "Resolved Netclass" ), UnescapeString( netclass->GetName() ) );
2044
2045 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
2046
2047 if( width && !mixedWidth )
2048 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2049
2050 BOARD* board = GetBoard();
2051 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2052 DRC_CONSTRAINT constraint;
2053
2054 // Display full track length (in Pcbnew)
2055 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2056 {
2057 int count;
2058 double trackLen;
2059 double lenPadToDie;
2060
2061 std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *primaryItem );
2062
2063 if( coupledItem && coupledItem->GetNetCode() > 0 )
2064 {
2065 double coupledLen;
2066 std::tie( count, coupledLen, lenPadToDie ) = board->GetTrackLength( *coupledItem );
2067
2068 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen )
2069 + wxS( ", " )
2070 + aFrame->MessageTextFromValue( coupledLen ) );
2071 }
2072 else
2073 {
2074 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2075 }
2076
2077 if( lenPadToDie != 0 )
2078 {
2079 msg = aFrame->MessageTextFromValue( lenPadToDie );
2080 aList.emplace_back( _( "Pad To Die Length" ), msg );
2081
2082 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2083 aList.emplace_back( _( "Full Length" ), msg );
2084 }
2085 }
2086
2088 {
2089 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2090
2091 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2092 {
2094
2095 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2096 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2097 }
2098 else
2099 {
2100 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2101
2102 if( !msg.IsEmpty() )
2103 {
2104 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2105 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2106 }
2107 }
2108 }
2109 else
2110 {
2111 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2112
2113 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2114 {
2115 msg = aFrame->MessageTextFromValue( (double) m_settings.m_targetLength.Opt() );
2116
2117 aList.emplace_back( wxString::Format( _( "Target Length: %s" ), msg ),
2118 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2119 }
2120 else
2121 {
2122 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2123
2124 if( !msg.IsEmpty() )
2125 {
2126 aList.emplace_back( wxString::Format( _( "Length Constraints: %s" ), msg ),
2127 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2128 }
2129 }
2130 }
2131}
2132
2133
2134const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2135const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2136
2137
2139
2140
2141#define HITTEST_THRESHOLD_PIXELS 5
2142
2143
2145{
2147 return 0;
2148
2149 if( m_inDrawingTool )
2150 return 0;
2151
2153
2155
2156 m_frame->PushTool( aEvent );
2157 Activate();
2158
2160 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2161 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2162 PNS::ROUTER* router = generatorTool->Router();
2164
2168 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2169
2170 m_pickerItem = nullptr;
2171 m_tuningPattern = nullptr;
2172
2173 // Add a VIEW_GROUP that serves as a preview for the new item
2174 m_preview.Clear();
2175 m_view->Add( &m_preview );
2176
2177 auto setCursor =
2178 [&]()
2179 {
2180 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
2181 controls->ShowCursor( true );
2182 };
2183
2184 auto updateHoverStatus =
2185 [&]()
2186 {
2187 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2188
2189 if( m_pickerItem )
2190 {
2191 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2192 m_pickerItem, mode ) );
2193 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2194 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2195 }
2196
2197 if( dummyPattern )
2198 {
2199 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2200 dummyPattern->Update( generatorTool, m_board, nullptr );
2201
2203
2204 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2205 m_preview.Add( item );
2206
2207 generatorTool->Router()->StopRouting();
2208
2209 m_view->Update( &m_preview );
2210 }
2211 else
2212 {
2214 m_view->Update( &m_preview );
2215 }
2216 };
2217
2218 auto updateTuningPattern =
2219 [&]()
2220 {
2222 {
2223 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2224 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2225
2227
2228 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame,
2229 true ) )
2230 {
2231 m_preview.Add( item );
2232 }
2233
2234 m_view->Update( &m_preview );
2235 }
2236 };
2237
2238 // Set initial cursor
2239 setCursor();
2240
2241 while( TOOL_EVENT* evt = Wait() )
2242 {
2243 setCursor();
2244 VECTOR2D cursorPos = controls->GetMousePosition();
2245
2246 if( evt->IsCancelInteractive() || evt->IsActivate()
2247 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2248 {
2249 if( m_tuningPattern )
2250 {
2251 // First click already made; clean up tuning pattern preview
2252 m_tuningPattern->EditRevert( generatorTool, m_board, nullptr );
2253
2254 delete m_tuningPattern;
2255 m_tuningPattern = nullptr;
2256 }
2257
2258 break;
2259 }
2260 else if( evt->IsMotion() )
2261 {
2262 if( !m_tuningPattern )
2263 {
2264 // First click not yet made; we're in highlight-net-under-cursor mode
2265
2266 GENERAL_COLLECTOR collector;
2267 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2268
2269 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2270 guide.SetIncludeSecondary( false );
2271 else
2272 guide.SetIncludeSecondary( true );
2273
2274 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2275
2276 if( collector.GetCount() > 1 )
2277 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2278
2279 m_pickerItem = nullptr;
2280
2281 if( collector.GetCount() > 0 )
2282 {
2283 double min_dist_sq = std::numeric_limits<double>::max();
2284
2285 for( EDA_ITEM* candidate : collector )
2286 {
2287 VECTOR2I candidatePos;
2288
2289 if( candidate->Type() == PCB_TRACE_T )
2290 {
2291 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2292 }
2293 else if( candidate->Type() == PCB_ARC_T )
2294 {
2295 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2296 }
2297
2298 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2299
2300 if( dist_sq < min_dist_sq )
2301 {
2302 min_dist_sq = dist_sq;
2303 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2304 }
2305 }
2306 }
2307
2308 updateHoverStatus();
2309 }
2310 else
2311 {
2312 // First click already made; we're in preview-tuning-pattern mode
2313
2314 m_tuningPattern->SetEnd( cursorPos );
2315 updateTuningPattern();
2316 }
2317 }
2318 else if( evt->IsClick( BUT_LEFT ) )
2319 {
2321 {
2322 // First click; create a tuning pattern
2323
2324 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2325 {
2326 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2327 "tuning patterns." ) );
2328 }
2329 else
2330 {
2332
2335 m_pickerItem, mode );
2336
2337 int dummyDist;
2338 int dummyClearance = std::numeric_limits<int>::max() / 2;
2339 VECTOR2I closestPt;
2340
2341 // With an artificially-large clearance this can't *not* collide, but the
2342 // if stmt keeps Coverity happy....
2343 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2344 &dummyDist, &closestPt ) )
2345 {
2346 m_tuningPattern->SetPosition( closestPt );
2347 m_tuningPattern->SetEnd( closestPt );
2348 }
2349
2351 }
2352 }
2353 else if( m_pickerItem && m_tuningPattern )
2354 {
2355 // Second click; we're done
2356 BOARD_COMMIT commit( m_frame );
2357
2358 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2359 m_tuningPattern->Update( generatorTool, m_board, &commit );
2360 m_tuningPattern->EditPush( generatorTool, m_board, &commit, _( "Tune" ) );
2361
2362 for( BOARD_ITEM* item : m_tuningPattern->GetItems() )
2363 item->SetSelected();
2364
2365 break;
2366 }
2367 }
2368 else if( evt->IsClick( BUT_RIGHT ) )
2369 {
2372 }
2373 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2374 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2375 {
2376 if( m_tuningPattern )
2377 {
2378 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2379
2380 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2381 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2382 updateTuningPattern();
2383 }
2384 else
2385 {
2386 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2387 }
2388 }
2389 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2390 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2391 {
2392 if( m_tuningPattern )
2393 {
2394 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2395
2396 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2397 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2398 updateTuningPattern();
2399 }
2400 else
2401 {
2402 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2403 }
2404 }
2405 else if( evt->IsAction( &PCB_ACTIONS::properties )
2406 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2407 {
2408 if( m_tuningPattern )
2409 {
2410 DRC_CONSTRAINT constraint;
2411
2412 if( !m_tuningPattern->GetItems().empty() )
2413 {
2414 BOARD_ITEM* startItem = *m_tuningPattern->GetItems().begin();
2415
2416 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2417 startItem->GetLayer() );
2418 }
2419
2421 m_tuningPattern->GetPNSMode(), constraint );
2422
2423 if( dlg.ShowModal() == wxID_OK )
2424 updateTuningPattern();
2425 }
2426 else
2427 {
2428 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2429 }
2430 }
2431 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2432 // but we don't at present have that, so we just knock out some of the egregious ones.
2433 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2434 {
2435 wxBell();
2436 }
2437 else
2438 {
2439 evt->SetPassEvent();
2440 }
2441
2442 controls->CaptureCursor( m_tuningPattern != nullptr );
2443 controls->SetAutoPan( m_tuningPattern != nullptr );
2444 }
2445
2446 controls->CaptureCursor( false );
2447 controls->SetAutoPan( false );
2448 controls->ForceCursorPosition( false );
2449 controls->ShowCursor( false );
2450 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2451
2453 m_view->Remove( &m_preview );
2454
2456
2457 if( m_tuningPattern )
2458 selectionTool->AddItemToSel( m_tuningPattern );
2459
2460 m_frame->PopTool( aEvent );
2461 return 0;
2462}
2463
2464
2466{
2468 {
2470 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2471 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2472 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2473
2475 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2476 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2477 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2478
2485
2486 const wxString groupTab = _HKI( "Pattern Properties" );
2487
2489 _HKI( "End X" ), &PCB_TUNING_PATTERN::SetEndX,
2490 &PCB_TUNING_PATTERN::GetEndX, PROPERTY_DISPLAY::PT_SIZE,
2492 groupTab );
2493
2495 _HKI( "End Y" ), &PCB_TUNING_PATTERN::SetEndY,
2496 &PCB_TUNING_PATTERN::GetEndY, PROPERTY_DISPLAY::PT_SIZE,
2498 groupTab );
2499
2501 _HKI( "Tuning Mode" ),
2504 groupTab );
2505
2507 _HKI( "Min Amplitude" ),
2510 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2511 groupTab );
2512
2514 _HKI( "Max Amplitude" ),
2517 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2518 groupTab );
2519
2521 _HKI( "Initial Side" ),
2524 groupTab );
2525
2527 _HKI( "Min Spacing" ), &PCB_TUNING_PATTERN::SetSpacing,
2528 &PCB_TUNING_PATTERN::GetSpacing, PROPERTY_DISPLAY::PT_SIZE,
2530 groupTab );
2531
2533 _HKI( "Corner Radius %" ),
2536 PROPERTY_DISPLAY::PT_DEFAULT, ORIGIN_TRANSFORMS::NOT_A_COORD ),
2537 groupTab );
2538
2539 auto isSkew =
2540 []( INSPECTABLE* aItem ) -> bool
2541 {
2542 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2543 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2544
2545 return false;
2546 };
2547
2548 auto notIsSkew =
2549 [&]( INSPECTABLE* aItem ) -> bool
2550 {
2551 return !isSkew( aItem );
2552 };
2553
2554 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2555 _HKI( "Target Length" ),
2558 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2559 groupTab )
2560 .SetAvailableFunc( notIsSkew );
2561
2562
2564 _HKI( "Target Skew" ), &PCB_TUNING_PATTERN::SetTargetSkew,
2566 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2567 groupTab )
2568 .SetAvailableFunc( isSkew );
2569
2570
2572 _HKI( "Override Custom Rules" ),
2575 groupTab );
2576
2578 _HKI( "Single-sided" ),
2581 groupTab );
2582
2584 _HKI( "Rounded" ), &PCB_TUNING_PATTERN::SetRounded,
2586 groupTab );
2587 }
2589
2592
2594
2595// Also register under the 7.99 name
2596template <typename T>
2598{
2600 {
2601 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2602 []()
2603 {
2604 return new T;
2605 } );
2606 }
2607};
2608
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:388
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:1881
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1810
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:2188
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:797
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:481
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:174
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:205
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:206
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:207
static TOOL_ACTION lengthTunerSettings
Definition: pcb_actions.h:208
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:204
const VECTOR2I & GetMid() const
Definition: pcb_track.h:315
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:107
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
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:92
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:216
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:145
VECTOR2D GetMousePosition() const
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:395
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:386
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:350
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:404
TEXT_DIMS GetConstantGlyphHeight(KIGFX::GAL *aGal, int aRelativeSize=0)
Set the GAL glyph height to a constant scaled value, so that it always looks the same on screen.
Push and Shove diff pair dimensions (gap) settings dialog.
MEANDER_SIDE
Definition: pns_meander.h:58
@ MEANDER_SIDE_RIGHT
Definition: pns_meander.h:61
@ MEANDER_SIDE_DEFAULT
Definition: pns_meander.h:60
@ MEANDER_SIDE_LEFT
Definition: pns_meander.h:59
@ MEANDER_STYLE_ROUND
Definition: pns_meander.h:52
@ MEANDER_STYLE_CHAMFER
Definition: pns_meander.h:53
ROUTER_MODE
Definition: pns_router.h:62
@ PNS_MODE_TUNE_DIFF_PAIR
Definition: pns_router.h:66
@ PNS_MODE_TUNE_SINGLE
Definition: pns_router.h:65
@ PNS_MODE_TUNE_DIFF_PAIR_SKEW
Definition: pns_router.h:67
Class to handle a set of BOARD_ITEMs.
static PNS::MEANDER_SIDE sideFromString(const std::string &aStr)
static LENGTH_TUNING_MODE tuningFromString(const std::string &aStr)
static std::string tuningToString(const LENGTH_TUNING_MODE aTuning)
static struct PCB_TUNING_PATTERN_DESC _PCB_TUNING_PATTERN_DESC
static LENGTH_TUNING_MODE fromPNSMode(PNS::ROUTER_MODE aRouterMode)
static PNS::MEANDER_PLACER_BASE::TUNING_STATUS statusFromString(const std::string &aStr)
static std::string sideToString(const PNS::MEANDER_SIDE aValue)
static std::string statusToString(const PNS::MEANDER_PLACER_BASE::TUNING_STATUS aStatus)
static GENERATORS_MGR::REGISTER< PCB_TUNING_PATTERN > registerMe
static PNS::LINKED_ITEM * pickSegment(PNS::ROUTER *aRouter, const VECTOR2I &aWhere, int aLayer, VECTOR2I &aPointOut, const SHAPE_LINE_CHAIN &aBaseline=SHAPE_LINE_CHAIN())
static std::optional< PNS::LINE > getPNSLine(const VECTOR2I &aStart, const VECTOR2I &aEnd, PNS::ROUTER *router, int layer, VECTOR2I &aStartOut, VECTOR2I &aEndOut)
LENGTH_TUNING_MODE
@ DIFF_PAIR
@ DIFF_PAIR_SKEW
static VECTOR2I snapToNearestTrack(const VECTOR2I &aP, BOARD *aBoard, NETINFO_ITEM *aNet, PCB_TRACK **aNearestTrack)
static REGISTER_LEGACY_TUNING_PATTERN< PCB_TUNING_PATTERN > registerMeToo
#define TYPE_HASH(x)
Definition: property.h: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:366
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:588