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