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