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 The 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#include <wx/log.h>
71
72
74{
78};
79
80
82{
83public:
85 EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
86 m_frame( aFrame ),
87 m_min( 0.0 ),
88 m_max( 0.0 ),
89 m_current( 0.0 )
90 { }
91
92 wxString GetClass() const override { return wxT( "TUNING_STATUS" ); }
93
94#if defined(DEBUG)
95 void Show( int nestLevel, std::ostream& os ) const override {}
96#endif
97
98 VECTOR2I GetPosition() const override { return m_pos; }
99 void SetPosition( const VECTOR2I& aPos ) override { m_pos = aPos; };
100
101 void SetMinMax( double aMin, double aMax )
102 {
103 m_min = aMin;
105 m_max = aMax;
107 }
108
110 {
111 m_min = 0.0;
112 m_minText = wxT( "---" );
113 m_max = std::numeric_limits<double>::max();
114 m_maxText = wxT( "---" );
115 }
116
117 void SetCurrent( double aCurrent, const wxString& aLabel )
118 {
119 m_current = aCurrent;
121 m_currentLabel = aLabel;
122 }
123
124 const BOX2I ViewBBox() const override
125 {
126 BOX2I tmp;
127
128 // this is an edit-time artefact; no reason to try and be smart with the bounding box
129 // (besides, we can't tell the text extents without a view to know what the scale is)
130 tmp.SetMaximum();
131 return tmp;
132 }
133
134 std::vector<int> ViewGetLayers() const override
135 {
136 return { LAYER_UI_START, LAYER_UI_START + 1 };
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 std::vector<int> ViewGetLayers() const override
360 {
361 return { LAYER_ANCHOR, GetLayer() };
362 }
363
364 bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
365 {
366 return getOutline().Collide( aPosition, aAccuracy );
367 }
368
369 bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
370 {
371 BOX2I sel = aRect;
372
373 if ( aAccuracy )
374 sel.Inflate( aAccuracy );
375
376 if( aContained )
377 return sel.Contains( GetBoundingBox() );
378
379 return sel.Intersects( GetBoundingBox() );
380 }
381
382 const BOX2I ViewBBox() const override { return GetBoundingBox(); }
383
384 EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
385
386 void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
387
388 const VECTOR2I& GetEnd() const { return m_end; }
389 void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
390
391 int GetEndX() const { return m_end.x; }
392 void SetEndX( int aValue ) { m_end.x = aValue; }
393
394 int GetEndY() const { return m_end.y; }
395 void SetEndY( int aValue ) { m_end.y = aValue; }
396
398
400 {
401 switch( m_tuningMode )
402 {
403 case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
404 case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
405 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
406 default: return PNS::PNS_MODE_TUNE_SINGLE;
407 }
408 }
409
411
413 void SetMinAmplitude( int aValue )
414 {
415 aValue = std::max( aValue, 0 );
416
417 m_settings.m_minAmplitude = aValue;
418
421 }
422
424 void SetMaxAmplitude( int aValue )
425 {
426 aValue = std::max( aValue, 0 );
427
428 m_settings.m_maxAmplitude = aValue;
429
432 }
433
434 // Update the initial side one time at EditStart based on m_end.
436
439
440 int GetSpacing() const { return m_settings.m_spacing; }
441 void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
442
443 std::optional<int> GetTargetLength() const
444 {
446 return std::optional<int>();
447 else
449 }
450
451 void SetTargetLength( std::optional<int> aValue )
452 {
453 if( aValue.has_value() )
454 m_settings.SetTargetLength( aValue.value() );
455 else
457 }
458
459 int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
460 void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
461
463 void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
464
467
468 bool IsSingleSided() const { return m_settings.m_singleSided; }
469 void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
470
474
475 std::vector<std::pair<wxString, wxVariant>> GetRowData() override
476 {
477 std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
478 data.emplace_back( _HKI( "Net" ), m_lastNetName );
479 data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
480 return data;
481 }
482
483 const STRING_ANY_MAP GetProperties() const override;
484 void SetProperties( const STRING_ANY_MAP& aProps ) override;
485
486 void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
487
488 std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
489 bool aStatusItemsOnly = false ) override;
490
491 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
492
493protected:
494 void swapData( BOARD_ITEM* aImage ) override
495 {
496 wxASSERT( aImage->Type() == PCB_GENERATOR_T );
497
498 std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
499 }
500
501 bool recoverBaseline( PNS::ROUTER* aRouter );
502
503 bool baselineValid();
504
505 bool initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard, VECTOR2I& aStart,
506 VECTOR2I& aEnd, NETINFO_ITEM* aNet,
507 std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
508
509 bool initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard );
510
511 bool removeToBaseline( PNS::ROUTER* aRouter, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine );
512
513 bool resetToBaseline( GENERATOR_TOOL* aTool, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine,
514 bool aPrimary );
515
517
518 void baseMirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
519 {
520 PCB_GENERATOR::baseMirror( aCentre, aFlipDirection );
521
522 if( m_baseLine )
523 {
524 m_baseLine->Mirror( aCentre, aFlipDirection );
525 m_origin = m_baseLine->CPoint( 0 );
526 m_end = m_baseLine->CPoint( -1 );
527 }
528
530 m_baseLineCoupled->Mirror( aCentre, aFlipDirection );
531
534 else
536 }
537
538protected:
540
542
543 std::optional<SHAPE_LINE_CHAIN> m_baseLine;
544 std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
545
548
550
552 wxString m_tuningInfo;
553
555
557};
558
559
560static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
561{
562 if( aStr == "single" )
564 else if( aStr == "diff_pair" )
566 else if( aStr == "diff_pair_skew" )
568 else
569 {
570 wxFAIL_MSG( wxS( "Unknown length tuning token" ) );
572 }
573}
574
575
576static std::string tuningToString( const LENGTH_TUNING_MODE aTuning )
577{
578 switch( aTuning )
579 {
580 case LENGTH_TUNING_MODE::SINGLE: return "single";
581 case LENGTH_TUNING_MODE::DIFF_PAIR: return "diff_pair";
582 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return "diff_pair_skew";
583 default: wxFAIL; return "";
584 }
585}
586
587
589{
590 switch( aRouterMode )
591 {
595 default: return LENGTH_TUNING_MODE::SINGLE;
596 }
597}
598
599
600static PNS::MEANDER_SIDE sideFromString( const std::string& aStr )
601{
602 if( aStr == "default" )
604 else if( aStr == "left" )
606 else if( aStr == "right" )
608 else
609 {
610 wxFAIL_MSG( wxS( "Unknown length-tuning side token" ) );
612 }
613}
614
615
617{
618 switch( aStatus )
619 {
620 case PNS::MEANDER_PLACER_BASE::TOO_LONG: return "too_long";
621 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: return "too_short";
622 case PNS::MEANDER_PLACER_BASE::TUNED: return "tuned";
623 default: wxFAIL; return "";
624 }
625}
626
627
629{
630 if( aStr == "too_long" )
632 else if( aStr == "too_short" )
634 else if( aStr == "tuned" )
636 else
637 {
638 wxFAIL_MSG( wxS( "Unknown tuning status token" ) );
640 }
641}
642
643
644static std::string sideToString( const PNS::MEANDER_SIDE aValue )
645{
646 switch( aValue )
647 {
648 case PNS::MEANDER_SIDE_DEFAULT: return "default";
649 case PNS::MEANDER_SIDE_LEFT: return "left";
650 case PNS::MEANDER_SIDE_RIGHT: return "right";
651 default: wxFAIL; return "";
652 }
653}
654
655
657 LENGTH_TUNING_MODE aMode ) :
658 PCB_GENERATOR( aParent, aLayer ),
659 m_trackWidth( 0 ),
660 m_diffPairGap( 0 ),
661 m_tuningMode( aMode ),
662 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED ),
663 m_updateSideFromEnd(false)
664{
667 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
669}
670
671
672static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
673 PCB_TRACK** aNearestTrack )
674{
676 VECTOR2I closestPt = aP;
677
678 for( PCB_TRACK *track : aBoard->Tracks() )
679 {
680 if( aNet && track->GetNet() != aNet )
681 continue;
682
683 VECTOR2I nearest;
684
685 if( track->Type() == PCB_ARC_T )
686 {
687 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
688 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
689 pcbArc->GetWidth() );
690
691 nearest = arc.NearestPoint( aP );
692 }
693 else
694 {
695 SEG seg( track->GetStart(), track->GetEnd() );
696 nearest = seg.NearestPoint( aP );
697 }
698
699 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
700
701 if( dist_sq < minDist_sq )
702 {
703 minDist_sq = dist_sq;
704 closestPt = nearest;
705
706 if( aNearestTrack )
707 *aNearestTrack = track;
708 }
709 }
710
711 return closestPt;
712}
713
714
716{
718 {
719 return( m_baseLine && m_baseLine->PointCount() > 1
720 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
721 }
722 else
723 {
724 return( m_baseLine && m_baseLine->PointCount() > 1 );
725 }
726}
727
728
730 PCB_BASE_EDIT_FRAME* aFrame,
731 BOARD_CONNECTED_ITEM* aStartItem,
732 LENGTH_TUNING_MODE aMode )
733{
734 BOARD* board = aStartItem->GetBoard();
736 DRC_CONSTRAINT constraint;
737 PCB_LAYER_ID layer = aStartItem->GetLayer();
738
739 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
740
741 switch( aMode )
742 {
743 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
744 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
745 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
746 }
747
748 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
749
750 if( !constraint.IsNull() )
751 {
752 if( aMode == DIFF_PAIR_SKEW )
753 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
754 else
755 pattern->m_settings.SetTargetLength( constraint.GetValue() );
756 }
757
758 pattern->SetFlags( IS_NEW );
759
760 return pattern;
761}
762
764{
765 if( aCommit )
766 {
767 if( IsNew() )
768 aCommit->Add( this );
769 else
770 aCommit->Modify( this );
771 }
772
773 SetFlags( IN_EDIT );
774
775 PNS::ROUTER* router = aTool->Router();
776 int layer = router->GetInterface()->GetPNSLayerFromBoardLayer( GetLayer() );
777
778 aTool->ClearRouterChanges();
779 router->SyncWorld();
780
782 PNS::CONSTRAINT constraint;
783
784 if( !baselineValid() )
785 initBaseLines( router, layer, aBoard );
786
788 {
789 VECTOR2I centerlineOffsetEnd;
790
792 && m_baseLineCoupled->SegmentCount() > 0 )
793 {
794 centerlineOffsetEnd =
795 ( m_baseLineCoupled->CPoint( -1 ) - m_baseLine->CPoint( -1 ) ) / 2;
796 }
797
798 SEG baseEnd = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( -1 )
799 : SEG( m_origin, m_end );
800
801 baseEnd.A += centerlineOffsetEnd;
802 baseEnd.B += centerlineOffsetEnd;
803
804 if( baseEnd.A != baseEnd.B )
805 {
806 int side = baseEnd.Side( m_end );
807
808 if( side < 0 )
810 else
812 }
813
814 m_updateSideFromEnd = false;
815 }
816
818 {
819 PCB_TRACK* track = nullptr;
820 PNS::SEGMENT pnsItem;
821
822 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
823 wxCHECK( track, /* void */ );
824
825 NETINFO_ITEM* net = track->GetNet();
826
827 pnsItem.SetParent( track );
828 pnsItem.SetNet( net );
829
830 if( m_tuningMode == SINGLE )
831 {
832 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
833 &pnsItem, nullptr, layer, &constraint ) )
834 {
835 m_settings.SetTargetLength( constraint.m_Value );
837 }
838 }
839 else
840 {
841 PCB_TRACK* coupledTrack = nullptr;
842 PNS::SEGMENT pnsCoupledItem;
843 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
844
845 if( coupledNet )
846 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
847
848 pnsCoupledItem.SetParent( coupledTrack );
849 pnsCoupledItem.SetNet( coupledNet );
850
851 if( m_tuningMode == DIFF_PAIR )
852 {
853 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
854 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
855 {
856 m_settings.SetTargetLength( constraint.m_Value );
858 }
859 }
860 else
861 {
863 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
864 {
865 m_settings.m_targetSkew = constraint.m_Value;
867 }
868 }
869 }
870 }
871}
872
873
874static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
875 VECTOR2I& aPointOut,
876 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
877{
878 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
879
880 static const int candidateCount = 2;
881 PNS::LINKED_ITEM* prioritized[candidateCount];
882 SEG::ecoord dist[candidateCount];
883 SEG::ecoord distBaseline[candidateCount];
884 VECTOR2I point[candidateCount];
885
886 for( int i = 0; i < candidateCount; i++ )
887 {
888 prioritized[i] = nullptr;
889 dist[i] = VECTOR2I::ECOORD_MAX;
890 distBaseline[i] = VECTOR2I::ECOORD_MAX;
891 }
892
893 for( int slopRadius : { 0, maxSlopRadius } )
894 {
895 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
896
897 for( PNS::ITEM* item : candidates.Items() )
898 {
899 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
900 continue;
901
902 if( !item->IsRoutable() )
903 continue;
904
905 if( !item->Layers().Overlaps( aLayer ) )
906 continue;
907
908 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
909
910 if( item->Kind() & PNS::ITEM::ARC_T )
911 {
912 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
913
914 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
915 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
916
917 if( d0 > dist[1] )
918 continue;
919
920 if( aBaseline.PointCount() > 0 )
921 {
922 SEG::ecoord dcBaseline;
923 VECTOR2I target = pnsArc->Arc().GetArcMid();
924
925 if( aBaseline.SegmentCount() > 0 )
926 dcBaseline = aBaseline.SquaredDistance( target );
927 else
928 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
929
930 if( dcBaseline > distBaseline[1] )
931 continue;
932
933 distBaseline[1] = dcBaseline;
934 }
935
936 prioritized[1] = linked;
937 dist[1] = d0;
938 point[1] = nearest;
939 }
940 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
941 {
942 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
943
944 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
945 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
946
947 if( dd > dist[1] )
948 continue;
949
950 if( aBaseline.PointCount() > 0 )
951 {
952 SEG::ecoord dcBaseline;
953 VECTOR2I target = segm->Shape( -1 )->Centre();
954
955 if( aBaseline.SegmentCount() > 0 )
956 dcBaseline = aBaseline.SquaredDistance( target );
957 else
958 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
959
960 if( dcBaseline > distBaseline[1] )
961 continue;
962
963 distBaseline[1] = dcBaseline;
964 }
965
966 prioritized[1] = segm;
967 dist[1] = dd;
968 point[1] = nearest;
969 }
970 }
971 }
972
973 PNS::LINKED_ITEM* rv = nullptr;
974
975 for( int i = 0; i < candidateCount; i++ )
976 {
977 PNS::LINKED_ITEM* item = prioritized[i];
978
979 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
980 {
981 rv = item;
982 aPointOut = point[i];
983 break;
984 }
985 }
986
987 return rv;
988}
989
990
991static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
992 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
993 VECTOR2I& aEndOut )
994{
995 PNS::NODE* world = router->GetWorld();
996
997 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
998 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
999
1000 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
1001 {
1002 if( !testItem )
1003 continue;
1004
1005 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
1006 SHAPE_LINE_CHAIN oldChain = line.CLine();
1007
1008 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
1009 return line;
1010 }
1011
1012 return std::nullopt;
1013}
1014
1015
1016bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard,
1017 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
1018 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
1019{
1020 PNS::NODE* world = aRouter->GetWorld();
1021
1022 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
1023 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
1024
1025 VECTOR2I startSnapPoint, endSnapPoint;
1026
1027 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aPNSLayer, startSnapPoint );
1028 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aPNSLayer, endSnapPoint );
1029
1030 wxASSERT( startItem );
1031 wxASSERT( endItem );
1032
1033 if( !startItem || !endItem )
1034 return false;
1035
1036 PNS::LINE line = world->AssembleLine( startItem );
1037 const SHAPE_LINE_CHAIN& chain = line.CLine();
1038
1039 wxASSERT( line.ContainsLink( endItem ) );
1040
1041 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
1042 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
1043
1044 SHAPE_LINE_CHAIN pre;
1045 SHAPE_LINE_CHAIN mid;
1046 SHAPE_LINE_CHAIN post;
1047
1048 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
1049
1050 aBaseLine = mid;
1051
1052 return true;
1053}
1054
1055
1056bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard )
1057{
1058 m_baseLineCoupled.reset();
1059
1060 PCB_TRACK* track = nullptr;
1061
1062 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
1063 wxCHECK( track, false );
1064
1065 NETINFO_ITEM* net = track->GetNet();
1066
1067 if( !initBaseLine( aRouter, aPNSLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
1068 return false;
1069
1070 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
1071 // DRC rules against.
1073 {
1074 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
1075 {
1076 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
1077 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
1078
1079 return initBaseLine( aRouter, aPNSLayer, aBoard, coupledStart, coupledEnd, coupledNet,
1081 }
1082
1083 return false;
1084 }
1085
1086 return true;
1087}
1088
1090 SHAPE_LINE_CHAIN& aBaseLine )
1091{
1092 VECTOR2I startSnapPoint, endSnapPoint;
1093
1094 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1095 aRouter, aPNSLayer, startSnapPoint, endSnapPoint );
1096
1097 wxCHECK( pnsLine, false );
1098
1099 SHAPE_LINE_CHAIN pre;
1100 SHAPE_LINE_CHAIN mid;
1101 SHAPE_LINE_CHAIN post;
1102 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1103
1104 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
1105 aRouter->GetInterface()->RemoveItem( li );
1106
1107 aRouter->GetWorld()->Remove( *pnsLine );
1108
1109 SHAPE_LINE_CHAIN straightChain;
1110 straightChain.Append( pre );
1111 straightChain.Append( aBaseLine );
1112 straightChain.Append( post );
1113 straightChain.Simplify();
1114
1115 PNS::LINE straightLine( *pnsLine, straightChain );
1116
1117 aRouter->GetWorld()->Add( straightLine, false );
1118
1119 for( PNS::LINKED_ITEM* li : straightLine.Links() )
1120 aRouter->GetInterface()->AddItem( li );
1121
1122 return true;
1123}
1124
1125
1127{
1128 SetFlags( IN_EDIT );
1129
1130 aTool->Router()->SyncWorld();
1131
1132 PNS::ROUTER* router = aTool->Router();
1133 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1134
1135 // Ungroup first so that undo works
1136 if( !GetItems().empty() )
1137 {
1138 PCB_GENERATOR* group = this;
1139
1140 for( BOARD_ITEM* member : group->GetItems() )
1141 aCommit->Stage( member, CHT_UNGROUP );
1142
1143 group->GetItems().clear();
1144 }
1145
1146 aCommit->Remove( this );
1147
1148 aTool->ClearRouterChanges();
1149
1150 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1151 int pnslayer = iface->GetPNSLayerFromBoardLayer( GetLayer() );
1152
1153 if( baselineValid() )
1154 {
1155 bool success = true;
1156
1157 success &= removeToBaseline( router, pnslayer, *m_baseLine );
1158
1159 if( m_tuningMode == DIFF_PAIR )
1160 success &= removeToBaseline( router, pnslayer, *m_baseLineCoupled );
1161
1162 if( !success )
1163 recoverBaseline( router );
1164 }
1165
1166 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
1167
1168 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
1169 {
1170 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
1171 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
1172
1173 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1174 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1175 << " m_removedItems " << m_removedItems.size() << std::endl;*/
1176
1177 for( BOARD_ITEM* item : routerRemovedItems )
1178 {
1179 item->ClearSelected();
1180 aCommit->Remove( item );
1181 }
1182
1183 for( BOARD_ITEM* item : routerAddedItems )
1184 aCommit->Add( item );
1185 }
1186
1187 aCommit->Push( "Remove Tuning Pattern" );
1188}
1189
1190
1192{
1193 PNS::SOLID queryItem;
1194
1195 SHAPE_LINE_CHAIN* chain = static_cast<SHAPE_LINE_CHAIN*>( getOutline().Clone() );
1196 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
1197 queryItem.SetLayer( m_layer );
1198
1199 int lineWidth = 0;
1200
1201 PNS::NODE::OBSTACLES obstacles;
1203 opts.m_useClearanceEpsilon = false;
1204
1205 PNS::NODE* world = aRouter->GetWorld();
1206 PNS::NODE* branch = world->Branch();
1207
1208 branch->QueryColliding( &queryItem, obstacles, opts );
1209
1210 for( const PNS::OBSTACLE& obs : obstacles )
1211 {
1212 PNS::ITEM* item = obs.m_item;
1213
1215 continue;
1216
1217 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
1218 {
1219 if( lineWidth == 0 || li->Width() < lineWidth )
1220 lineWidth = li->Width();
1221 }
1222
1223 if( chain->PointInside( item->Anchor( 0 ), 10 )
1224 && chain->PointInside( item->Anchor( 1 ), 10 ) )
1225 {
1226 branch->Remove( item );
1227 }
1228 }
1229
1230 if( lineWidth == 0 )
1231 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1232
1233 if( baselineValid() )
1234 {
1235 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1236 PNS::LINE recoverLine;
1237
1238 recoverLine.SetLayer( m_layer );
1239 recoverLine.SetWidth( lineWidth );
1240 recoverLine.Line() = *m_baseLine;
1241 recoverLine.SetNet( recoverNet );
1242 branch->Add( recoverLine, false );
1243
1245 {
1246 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1247 PNS::LINE recoverLineCoupled;
1248
1249 recoverLineCoupled.SetLayer( m_layer );
1250 recoverLineCoupled.SetWidth( lineWidth );
1251 recoverLineCoupled.Line() = *m_baseLineCoupled;
1252 recoverLineCoupled.SetNet( recoverCoupledNet );
1253 branch->Add( recoverLineCoupled, false );
1254 }
1255 }
1256
1257 aRouter->CommitRouting( branch );
1258
1259 //wxLogWarning( "PNS baseline recovered" );
1260
1261 return true;
1262}
1263
1264
1266 SHAPE_LINE_CHAIN& aBaseLine, bool aPrimary )
1267{
1268 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1269 PNS::ROUTER* router = aTool->Router();
1270 PNS::NODE* world = router->GetWorld();
1271 VECTOR2I startSnapPoint, endSnapPoint;
1272
1273 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CPoint( -1 ),
1274 router, aPNSLayer, startSnapPoint, endSnapPoint );
1275
1276 if( !pnsLine )
1277 {
1278 // TODO
1279 //recoverBaseline( aRouter );
1280 return true;
1281 }
1282
1283 PNS::NODE* branch = world->Branch();
1284
1285 SHAPE_LINE_CHAIN straightChain;
1286 {
1287 SHAPE_LINE_CHAIN pre, mid, post;
1288 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1289
1290 straightChain.Append( pre );
1291 straightChain.Append( aBaseLine );
1292 straightChain.Append( post );
1293 straightChain.Simplify();
1294 }
1295
1296 branch->Remove( *pnsLine );
1297
1298 SHAPE_LINE_CHAIN newLineChain;
1299
1300 if( aPrimary )
1301 {
1302 m_origin = straightChain.NearestPoint( m_origin );
1303 m_end = straightChain.NearestPoint( m_end );
1304
1305 // Don't allow points too close
1306 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1307 {
1308 m_origin = startSnapPoint;
1309 m_end = endSnapPoint;
1310 }
1311
1312 {
1313 SHAPE_LINE_CHAIN pre, mid, post;
1314 straightChain.Split( m_origin, m_end, pre, mid, post );
1315
1316 newLineChain.Append( pre );
1317 newLineChain.Append( mid );
1318 newLineChain.Append( post );
1319
1320 m_baseLine = mid;
1321 }
1322 }
1323 else
1324 {
1325 VECTOR2I start = straightChain.NearestPoint( m_origin );
1326 VECTOR2I end = straightChain.NearestPoint( m_end );
1327
1328 {
1329 SHAPE_LINE_CHAIN pre, mid, post;
1330 straightChain.Split( start, end, pre, mid, post );
1331
1332 newLineChain.Append( pre );
1333 newLineChain.Append( mid );
1334 newLineChain.Append( post );
1335
1336 m_baseLineCoupled = mid;
1337 }
1338 }
1339
1340 PNS::LINE newLine( *pnsLine, newLineChain );
1341
1342 branch->Add( newLine, false );
1343 router->CommitRouting( branch );
1344
1345 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1346
1347 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1348
1349 return true;
1350}
1351
1352
1354{
1355 if( !( GetFlags() & IN_EDIT ) )
1356 return false;
1357
1358 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1359 PNS::ROUTER* router = aTool->Router();
1360 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1361 PCB_LAYER_ID pcblayer = GetLayer();
1362
1363 auto hideRemovedItems = [&]( bool aHide )
1364 {
1365 if( view )
1366 {
1367 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1368 {
1369 for( BOARD_ITEM* item : pnsCommit.removedItems )
1370 {
1371 if( view )
1372 view->Hide( item, aHide, aHide );
1373 }
1374 }
1375 }
1376 };
1377
1378 iface->SetStartLayerFromPCBNew( pcblayer );
1379
1380 if( router->RoutingInProgress() )
1381 {
1382 router->StopRouting();
1383 }
1384
1385 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1386 int pnslayer = iface->GetPNSLayerFromBoardLayer( pcblayer );
1387
1388 if( !baselineValid() )
1389 {
1390 initBaseLines( router, pnslayer, aBoard );
1391 }
1392 else
1393 {
1394 if( resetToBaseline( aTool, pnslayer, *m_baseLine, true ) )
1395 {
1396 m_origin = m_baseLine->CPoint( 0 );
1397 m_end = m_baseLine->CPoint( -1 );
1398 }
1399 else
1400 {
1401 //initBaseLines( router, layer, aBoard );
1402 return false;
1403 }
1404
1405 if( m_tuningMode == DIFF_PAIR )
1406 {
1407 if( !resetToBaseline( aTool, pnslayer, *m_baseLineCoupled, false ) )
1408 {
1409 initBaseLines( router, pnslayer, aBoard );
1410 return false;
1411 }
1412 }
1413 }
1414
1415 hideRemovedItems( true );
1416 // Snap points
1417 VECTOR2I startSnapPoint, endSnapPoint;
1418
1419 wxCHECK( m_baseLine, false );
1420
1421 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, pnslayer, startSnapPoint, *m_baseLine);
1422 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, pnslayer, endSnapPoint, *m_baseLine );
1423
1424 wxASSERT( startItem );
1425 wxASSERT( endItem );
1426
1427 if( !startItem || !endItem )
1428 return false;
1429
1430 router->SetMode( GetPNSMode() );
1431
1432 if( !router->StartRouting( startSnapPoint, startItem, pnslayer ) )
1433 {
1434 //recoverBaseline( router );
1435 return false;
1436 }
1437
1438 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1439
1440 m_settings.m_keepEndpoints = true; // Required for re-grouping
1441 placer->UpdateSettings( m_settings );
1442
1443 router->Move( m_end, nullptr );
1444
1445 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1446 {
1447 m_trackWidth = dpPlacer->GetOriginPair().Width();
1448 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1449 }
1450 else
1451 {
1452 m_trackWidth = startItem->Width();
1453 m_diffPairGap = router->Sizes().DiffPairGap();
1454 }
1455
1456 m_settings = placer->MeanderSettings();
1457 m_lastNetName = iface->GetNetName( startItem->Net() );
1458 m_tuningStatus = placer->TuningStatus();
1459
1460 wxString statusMessage;
1461
1462 switch ( m_tuningStatus )
1463 {
1464 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1465 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1466 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1467 default: statusMessage = _( "unknown" ); break;
1468 }
1469
1470 wxString result;
1471 EDA_UNITS userUnits = EDA_UNITS::MILLIMETRES;
1472
1473 if( aTool->GetManager()->GetSettings() )
1474 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1475
1477 (double) placer->TuningResult() );
1478
1479 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1480
1481 return true;
1482}
1483
1484
1486 const wxString& aCommitMsg, int aCommitFlags )
1487{
1488 if( !( GetFlags() & IN_EDIT ) )
1489 return;
1490
1492
1493 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1494 PNS::ROUTER* router = aTool->Router();
1495 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1496 SHAPE_LINE_CHAIN bounds = getOutline();
1497 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1498
1499 iface->EraseView();
1500
1501 if( router->RoutingInProgress() )
1502 {
1503 bool forceFinish = true;
1504 bool forceCommit = false;
1505
1506 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1507 router->StopRouting();
1508 }
1509
1510 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1511
1512 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1513 {
1514 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1515 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1516
1517 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1518 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1519 // << " m_removedItems " << m_removedItems.size() << std::endl;
1520
1521 for( BOARD_ITEM* item : routerRemovedItems )
1522 {
1523 if( view )
1524 view->Hide( item, false );
1525
1526 aCommit->Remove( item );
1527 }
1528
1529 for( BOARD_ITEM* item : routerAddedItems )
1530 {
1531 aCommit->Add( item );
1532
1533 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1534 {
1535 if( bounds.PointInside( track->GetStart(), epsilon )
1536 && bounds.PointInside( track->GetEnd(), epsilon ) )
1537 {
1538 AddItem( item );
1539 aCommit->Stage( item, CHT_GROUP );
1540 }
1541 }
1542 }
1543 }
1544
1545 if( aCommitMsg.IsEmpty() )
1546 aCommit->Push( _( "Edit Tuning Pattern" ), aCommitFlags );
1547 else
1548 aCommit->Push( aCommitMsg, aCommitFlags );
1549}
1550
1551
1553{
1554 if( !( GetFlags() & IN_EDIT ) )
1555 return;
1556
1558
1559 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1560
1561 iface->EraseView();
1562
1563 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1564 {
1565 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1566 {
1567 for( BOARD_ITEM* item : pnsCommit.removedItems )
1568 view->Hide( item, false );
1569 }
1570 }
1571
1572 aTool->Router()->StopRouting();
1573
1574 if( aCommit )
1575 aCommit->Revert();
1576}
1577
1578
1580{
1581 VECTOR2I centerlineOffset;
1582 VECTOR2I centerlineOffsetEnd;
1583
1584 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1585 {
1586 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1587 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1588 }
1589
1590 aPoints.AddPoint( m_origin + centerlineOffset );
1591 aPoints.AddPoint( m_end + centerlineOffsetEnd );
1592
1593 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1594 : SEG( m_origin, m_end );
1595
1596 base.A += centerlineOffset;
1597 base.B += centerlineOffset;
1598
1599 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1600
1601 if( m_tuningMode == DIFF_PAIR )
1602 amplitude += m_trackWidth + m_diffPairGap;
1603
1604 if( m_settings.m_initialSide == -1 )
1605 amplitude *= -1;
1606
1607 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1608
1609 aPoints.AddPoint( base.A + widthHandleOffset );
1610 aPoints.Point( 2 ).SetGridConstraint( IGNORE_GRID );
1611
1612 VECTOR2I spacingHandleOffset =
1613 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1614
1615 aPoints.AddPoint( base.A + spacingHandleOffset );
1616 aPoints.Point( 3 ).SetGridConstraint( IGNORE_GRID );
1617
1618 return true;
1619}
1620
1621
1623{
1624 VECTOR2I centerlineOffset;
1625 VECTOR2I centerlineOffsetEnd;
1626
1627 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1628 {
1629 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1630 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1631 }
1632
1633 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1634 : SEG( m_origin, m_end );
1635
1636 base.A += centerlineOffset;
1637 base.B += centerlineOffset;
1638
1639 m_origin = aEditPoints.Point( 0 ).GetPosition() - centerlineOffset;
1640 m_end = aEditPoints.Point( 1 ).GetPosition() - centerlineOffsetEnd;
1641
1642 if( aEditPoints.Point( 2 ).IsActive() )
1643 {
1644 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1645
1646 int value = base.LineDistance( wHandle );
1647
1648 value -= KiROUND( m_trackWidth / 2.0 );
1649
1650 if( m_tuningMode == DIFF_PAIR )
1651 value -= m_trackWidth + m_diffPairGap;
1652
1653 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1654
1655 int side = base.Side( wHandle );
1656
1657 if( side < 0 )
1659 else
1661 }
1662
1663 if( aEditPoints.Point( 3 ).IsActive() )
1664 {
1665 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1666 VECTOR2I sHandle = aEditPoints.Point( 3 ).GetPosition();
1667
1668 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1669
1670 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1671 }
1672
1673 return true;
1674}
1675
1676
1678{
1679 VECTOR2I centerlineOffset;
1680 VECTOR2I centerlineOffsetEnd;
1681
1682 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1683 {
1684 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1685 centerlineOffsetEnd = ( m_baseLineCoupled->CPoint( -1 ) - m_end ) / 2;
1686 }
1687
1688 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1689 : SEG( m_origin, m_end );
1690
1691 base.A += centerlineOffset;
1692 base.B += centerlineOffset;
1693
1694 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1695
1696 if( m_tuningMode == DIFF_PAIR )
1697 amplitude += m_trackWidth + m_diffPairGap;
1698
1699 if( m_settings.m_initialSide == -1 )
1700 amplitude *= -1;
1701
1702 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1703
1704 aEditPoints.Point( 0 ).SetPosition( m_origin + centerlineOffset );
1705 aEditPoints.Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1706
1707 aEditPoints.Point( 2 ).SetPosition( base.A + widthHandleOffset );
1708
1709 VECTOR2I spacingHandleOffset =
1710 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1711
1712 aEditPoints.Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1713
1714 return true;
1715}
1716
1717
1719{
1720 if( m_baseLine )
1721 {
1722 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1723 int minAllowedAmplitude = 0;
1724 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1725
1727 {
1728 minAllowedAmplitude = baselineOffset + m_trackWidth;
1729 }
1730 else
1731 {
1732 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1733 minAllowedAmplitude = baselineOffset + correction;
1734 }
1735
1736 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1737
1739 {
1740 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1742
1743 if( m_tuningMode != DIFF_PAIR )
1744 {
1745 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1746
1747 SHAPE_LINE_CHAIN chain;
1748
1749 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1750 left, right, true ) )
1751 {
1752 chain.Append( m_settings.m_initialSide >= 0 ? right : left );
1753 chain.Append( clBase.Reverse() );
1754 chain.SetClosed( true );
1755
1756 return chain;
1757 }
1758 }
1760 {
1761 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1762
1764 SHAPE_LINE_CHAIN chain1, chain2;
1765
1766 if( clBase.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF,
1767 left, right, true ) )
1768 {
1769 if( m_settings.m_initialSide >= 0 )
1770 chain1.Append( right );
1771 else
1772 chain1.Append( left );
1773
1774 if( clBase.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1775 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1776 right, true ) )
1777 {
1778 if( m_settings.m_initialSide >= 0 )
1779 chain1.Append( left.Reverse() );
1780 else
1781 chain1.Append( right.Reverse() );
1782 }
1783
1784 chain1.SetClosed( true );
1785 }
1786
1787 if( clCoupled.OffsetLine( amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1788 ARC_LOW_DEF, left, right, true ) )
1789 {
1790 if( m_settings.m_initialSide >= 0 )
1791 chain2.Append( right );
1792 else
1793 chain2.Append( left );
1794
1795 if( clCoupled.OffsetLine( KiROUND( m_trackWidth / 2.0 ),
1796 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, left,
1797 right, true ) )
1798 {
1799 if( m_settings.m_initialSide >= 0 )
1800 chain2.Append( left.Reverse() );
1801 else
1802 chain2.Append( right.Reverse() );
1803 }
1804
1805 chain2.SetClosed( true );
1806 }
1807
1808 SHAPE_POLY_SET merged;
1809 merged.BooleanAdd( chain1, chain2 );
1810
1811 if( merged.OutlineCount() > 0 )
1812 return merged.Outline( 0 );
1813 }
1814 }
1815
1816 // Not single-sided / fallback
1817 SHAPE_POLY_SET poly;
1819
1820 int amplitude = 0;
1821
1822 if( m_tuningMode == DIFF_PAIR )
1823 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1824 else
1825 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1826
1827 poly.OffsetLineChain( *m_baseLine, amplitude, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1828 ARC_LOW_DEF, false );
1829
1831 {
1832 SHAPE_POLY_SET polyCoupled;
1833 polyCoupled.OffsetLineChain( *m_baseLineCoupled, amplitude,
1834 CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, false );
1835
1836 SHAPE_POLY_SET merged;
1837 merged.BooleanAdd( poly, polyCoupled );
1838
1839 if( merged.OutlineCount() > 0 )
1840 return merged.Outline( 0 );
1841 }
1842
1843 if( poly.OutlineCount() > 0 )
1844 return poly.Outline( 0 );
1845 }
1846
1847 return SHAPE_LINE_CHAIN();
1848}
1849
1850
1851void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1852{
1853 if( !IsSelected() && !IsNew() )
1854 return;
1855
1856 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1857
1858 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1859 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1860
1861 if( !HasFlag( IN_EDIT ) )
1862 {
1863 if( m_baseLine )
1864 {
1865 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1866 {
1867 SEG seg = m_baseLine->CSegment( i );
1868 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1869 }
1870 }
1871 else
1872 {
1873 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1874 }
1875
1877 {
1878 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1879 {
1880 SEG seg = m_baseLineCoupled->CSegment( i );
1881 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1882 }
1883 }
1884 }
1885
1886 SHAPE_LINE_CHAIN chain = getOutline();
1887
1888 for( int i = 0; i < chain.SegmentCount(); i++ )
1889 {
1890 SEG seg = chain.Segment( i );
1891 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1892 }
1893}
1894
1895
1897{
1899
1900 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
1901 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
1902 props.set( "last_status", statusToString( m_tuningStatus ) );
1903
1904 props.set( "end", m_end );
1905 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1906 props.set( "single_sided", m_settings.m_singleSided );
1908
1909 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
1910 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
1911 props.set_iu( "min_spacing", m_settings.m_spacing );
1912 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
1913 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
1914 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
1915 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
1916 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
1917 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
1918 props.set_iu( "last_track_width", m_trackWidth );
1919 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
1920
1921 props.set( "last_netname", m_lastNetName );
1922 props.set( "last_tuning", m_tuningInfo );
1923 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
1924
1925 if( m_baseLine )
1926 props.set( "base_line", wxAny( *m_baseLine ) );
1927
1928 if( m_baseLineCoupled )
1929 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
1930
1931 return props;
1932}
1933
1934
1936{
1938
1939 wxString tuningMode;
1940 aProps.get_to( "tuning_mode", tuningMode );
1941 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
1942
1943 wxString side;
1944 aProps.get_to( "initial_side", side );
1945 m_settings.m_initialSide = sideFromString( side.utf8_string() );
1946
1947 wxString status;
1948 aProps.get_to( "last_status", status );
1949 m_tuningStatus = statusFromString( status.utf8_string() );
1950
1951 aProps.get_to( "end", m_end );
1952 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1953 aProps.get_to( "single_sided", m_settings.m_singleSided );
1954 aProps.get_to( "side", m_settings.m_initialSide );
1955
1956 bool rounded = false;
1957 aProps.get_to( "rounded", rounded );
1959
1960 long long int val;
1961
1962 aProps.get_to_iu( "target_length", val );
1964
1965 if( aProps.get_to_iu( "target_length_min", val ) )
1967
1968 if( aProps.get_to_iu( "target_length_max", val ) )
1970
1971 int int_val;
1972
1973 aProps.get_to_iu( "target_skew", int_val );
1974 m_settings.SetTargetSkew( int_val );
1975
1976 if( aProps.get_to_iu( "target_skew_min", int_val ) )
1977 m_settings.m_targetSkew.SetMin( int_val );
1978
1979 if( aProps.get_to_iu( "target_skew_max", int_val ) )
1980 m_settings.m_targetSkew.SetMax( int_val );
1981
1982 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
1983 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
1984 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
1985 aProps.get_to_iu( "last_track_width", m_trackWidth );
1986 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
1987 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
1988
1989 aProps.get_to( "last_netname", m_lastNetName );
1990 aProps.get_to( "last_tuning", m_tuningInfo );
1991
1992 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
1993 m_baseLine = *baseLine;
1994
1995 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
1996 m_baseLineCoupled = *baseLineCoupled;
1997}
1998
1999
2001{
2003 DRC_CONSTRAINT constraint;
2004
2005 if( !m_items.empty() )
2006 {
2007 BOARD_ITEM* startItem = *m_items.begin();
2008 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
2009
2010 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
2011
2012 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
2013 settings.SetTargetLength( constraint.GetValue() );
2014 }
2015
2016 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
2017
2018 if( dlg.ShowModal() == wxID_OK )
2019 {
2020 BOARD_COMMIT commit( aEditFrame );
2021 commit.Modify( this );
2022 m_settings = settings;
2023
2024 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
2025 EditStart( generatorTool, GetBoard(), &commit );
2026 Update( generatorTool, GetBoard(), &commit );
2027 EditPush( generatorTool, GetBoard(), &commit );
2028 }
2029}
2030
2031
2033 PCB_BASE_EDIT_FRAME* aFrame,
2034 bool aStatusItemsOnly )
2035{
2036 std::vector<EDA_ITEM*> previewItems;
2037 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
2038
2039 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
2040 {
2041 if( !aStatusItemsOnly )
2042 {
2043 PNS::ITEM_SET items = placer->TunedPath();
2044
2045 for( PNS::ITEM* item : items )
2046 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item,
2047 aTool->Router()->GetInterface(),
2048 view, PNS_HOVER_ITEM ) );
2049 }
2050
2051 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
2052
2054 {
2056 }
2057 else
2058 {
2060 {
2061 statusItem->ClearMinMax();
2062 }
2063 else
2064 {
2065 statusItem->SetMinMax( (double) m_settings.m_targetLength.Min(),
2066 (double) m_settings.m_targetLength.Max() );
2067 }
2068 }
2069
2071 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current skew" ) );
2072 else
2073 statusItem->SetCurrent( (double) placer->TuningResult(), _( "current length" ) );
2074
2075 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
2076 previewItems.push_back( statusItem );
2077 }
2078
2079 return previewItems;
2080}
2081
2082
2084 std::vector<MSG_PANEL_ITEM>& aList )
2085{
2086 wxString msg;
2087 NETINFO_ITEM* primaryNet = nullptr;
2088 NETINFO_ITEM* coupledNet = nullptr;
2089 PCB_TRACK* primaryItem = nullptr;
2090 PCB_TRACK* coupledItem = nullptr;
2091 NETCLASS* netclass = nullptr;
2092 int width = 0;
2093 bool mixedWidth = false;
2094
2095 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2096
2097 for( BOARD_ITEM* member : GetItems() )
2098 {
2099 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
2100 {
2101 if( !primaryNet )
2102 {
2103 primaryItem = track;
2104 primaryNet = track->GetNet();
2105 }
2106 else if( !coupledNet && track->GetNet() != primaryNet )
2107 {
2108 coupledItem = track;
2109 coupledNet = track->GetNet();
2110 }
2111
2112 if( !netclass )
2113 netclass = track->GetEffectiveNetClass();
2114
2115 if( !width )
2116 width = track->GetWidth();
2117 else if( width != track->GetWidth() )
2118 mixedWidth = true;
2119 }
2120 }
2121
2122 if( coupledNet )
2123 {
2124 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2125 + wxS( ", " )
2126 + UnescapeString( coupledNet->GetNetname() ) );
2127 }
2128 else if( primaryNet )
2129 {
2130 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2131 }
2132
2133 if( netclass )
2134 aList.emplace_back( _( "Resolved Netclass" ),
2135 UnescapeString( netclass->GetHumanReadableName() ) );
2136
2137 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
2138
2139 if( width && !mixedWidth )
2140 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2141
2142 BOARD* board = GetBoard();
2143 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2144 DRC_CONSTRAINT constraint;
2145
2146 // Display full track length (in Pcbnew)
2147 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2148 {
2149 int count;
2150 double trackLen;
2151 double lenPadToDie;
2152
2153 std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *primaryItem );
2154
2155 if( coupledItem && coupledItem->GetNetCode() > 0 )
2156 {
2157 double coupledLen;
2158 std::tie( count, coupledLen, lenPadToDie ) = board->GetTrackLength( *coupledItem );
2159
2160 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen )
2161 + wxS( ", " )
2162 + aFrame->MessageTextFromValue( coupledLen ) );
2163 }
2164 else
2165 {
2166 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2167 }
2168
2169 if( lenPadToDie != 0 )
2170 {
2171 msg = aFrame->MessageTextFromValue( lenPadToDie );
2172 aList.emplace_back( _( "Pad To Die Length" ), msg );
2173
2174 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2175 aList.emplace_back( _( "Full Length" ), msg );
2176 }
2177 }
2178
2180 {
2181 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2182
2183 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2184 {
2186
2187 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2188 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2189 }
2190 else
2191 {
2192 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2193
2194 if( !msg.IsEmpty() )
2195 {
2196 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2197 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2198 }
2199 }
2200 }
2201 else
2202 {
2203 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2204
2205 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2206 {
2207 msg = aFrame->MessageTextFromValue( (double) m_settings.m_targetLength.Opt() );
2208
2209 aList.emplace_back( wxString::Format( _( "Target Length: %s" ), msg ),
2210 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2211 }
2212 else
2213 {
2214 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2215
2216 if( !msg.IsEmpty() )
2217 {
2218 aList.emplace_back( wxString::Format( _( "Length Constraints: %s" ), msg ),
2219 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2220 }
2221 }
2222 }
2223}
2224
2225
2226const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2227const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2228
2229
2231
2232
2233#define HITTEST_THRESHOLD_PIXELS 5
2234
2235
2237{
2238 // TODO: (JJ) Reserving before v9 string freeze
2239 wxLogDebug( _( "Tune Skew" ) );
2240
2242 return 0;
2243
2244 if( m_inDrawingTool )
2245 return 0;
2246
2248
2250
2251 m_frame->PushTool( aEvent );
2252 Activate();
2253
2256 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
2257 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2258 PNS::ROUTER* router = generatorTool->Router();
2259 PNS::ROUTER_MODE routerMode = aEvent.Parameter<PNS::ROUTER_MODE>();
2260 LENGTH_TUNING_MODE mode = fromPNSMode( routerMode );
2261 PNS::MEANDER_SETTINGS meanderSettings;
2262
2263 switch( mode )
2264 {
2265 case LENGTH_TUNING_MODE::SINGLE: meanderSettings = bds.m_SingleTrackMeanderSettings; break;
2266 case DIFF_PAIR: meanderSettings = bds.m_DiffPairMeanderSettings; break;
2267 case DIFF_PAIR_SKEW: meanderSettings = bds.m_SkewMeanderSettings; break;
2268 }
2269
2273 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2274
2275 m_pickerItem = nullptr;
2276 m_tuningPattern = nullptr;
2277
2278 // Add a VIEW_GROUP that serves as a preview for the new item
2279 m_preview.Clear();
2280 m_view->Add( &m_preview );
2281
2282 auto setCursor =
2283 [&]()
2284 {
2285 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
2286 controls->ShowCursor( true );
2287 };
2288
2289 auto applyCommonSettings = [&]( PCB_TUNING_PATTERN* aPattern )
2290 {
2291 const auto& origTargetLength = aPattern->GetSettings().m_targetLength;
2292 const auto& origTargetSkew = aPattern->GetSettings().m_targetSkew;
2293
2294 aPattern->GetSettings() = meanderSettings;
2295
2296 if( meanderSettings.m_targetLength.IsNull() )
2297 aPattern->GetSettings().m_targetLength = origTargetLength;
2298
2299 if( meanderSettings.m_targetSkew.IsNull() )
2300 aPattern->GetSettings().m_targetSkew = origTargetSkew;
2301 };
2302
2303 auto updateHoverStatus =
2304 [&]()
2305 {
2306 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2307
2308 if( m_pickerItem )
2309 {
2310 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2311 m_pickerItem, mode ) );
2312 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2313 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2314 }
2315
2316 if( dummyPattern )
2317 {
2318 applyCommonSettings( dummyPattern.get() );
2319
2320 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2321 dummyPattern->Update( generatorTool, m_board, nullptr );
2322
2324
2325 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2326 m_preview.Add( item );
2327
2328 generatorTool->Router()->StopRouting();
2329
2330 m_view->Update( &m_preview );
2331 }
2332 else
2333 {
2334
2336 m_view->Update( &m_preview );
2337 }
2338 };
2339
2340 auto updateTuningPattern =
2341 [&]()
2342 {
2344 {
2345 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2346 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2347
2349
2350 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame,
2351 true ) )
2352 {
2353 m_preview.Add( item );
2354 }
2355
2356 m_view->Update( &m_preview );
2357 }
2358 };
2359
2360 // Set initial cursor
2361 setCursor();
2362
2363 while( TOOL_EVENT* evt = Wait() )
2364 {
2365 setCursor();
2366 VECTOR2D cursorPos = controls->GetMousePosition();
2367
2368 if( evt->IsCancelInteractive() || evt->IsActivate()
2369 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2370 {
2371 if( m_tuningPattern )
2372 {
2373 // First click already made; clean up tuning pattern preview
2374 m_tuningPattern->EditRevert( generatorTool, m_board, nullptr );
2375
2376 delete m_tuningPattern;
2377 m_tuningPattern = nullptr;
2378 }
2379
2380 break;
2381 }
2382 else if( evt->IsMotion() )
2383 {
2384 if( !m_tuningPattern )
2385 {
2386 // First click not yet made; we're in highlight-net-under-cursor mode
2387
2388 GENERAL_COLLECTOR collector;
2389 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2390
2391 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2392 guide.SetIncludeSecondary( false );
2393 else
2394 guide.SetIncludeSecondary( true );
2395
2396 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2397
2398 if( collector.GetCount() > 1 )
2399 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2400
2401 m_pickerItem = nullptr;
2402
2403 if( collector.GetCount() > 0 )
2404 {
2405 double min_dist_sq = std::numeric_limits<double>::max();
2406
2407 for( EDA_ITEM* candidate : collector )
2408 {
2409 VECTOR2I candidatePos;
2410
2411 if( candidate->Type() == PCB_TRACE_T )
2412 {
2413 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2414 }
2415 else if( candidate->Type() == PCB_ARC_T )
2416 {
2417 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2418 }
2419
2420 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2421
2422 if( dist_sq < min_dist_sq )
2423 {
2424 min_dist_sq = dist_sq;
2425 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2426 }
2427 }
2428 }
2429
2430 updateHoverStatus();
2431 }
2432 else
2433 {
2434 // First click already made; we're in preview-tuning-pattern mode
2435
2436 m_tuningPattern->SetEnd( cursorPos );
2438
2439 updateTuningPattern();
2440 }
2441 }
2442 else if( evt->IsClick( BUT_LEFT ) )
2443 {
2445 {
2446 // First click; create a tuning pattern
2447
2448 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2449 {
2450 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2451 "tuning patterns." ) );
2452 }
2453 else
2454 {
2456
2459 m_pickerItem, mode );
2460
2461 applyCommonSettings( m_tuningPattern );
2462
2463 int dummyDist;
2464 int dummyClearance = std::numeric_limits<int>::max() / 2;
2465 VECTOR2I closestPt;
2466
2467 // With an artificially-large clearance this can't *not* collide, but the
2468 // if stmt keeps Coverity happy....
2469 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2470 &dummyDist, &closestPt ) )
2471 {
2472 m_tuningPattern->SetPosition( closestPt );
2473 m_tuningPattern->SetEnd( closestPt );
2474 }
2475
2477 }
2478 }
2479 else if( m_pickerItem && m_tuningPattern )
2480 {
2481 // Second click; we're done
2482 BOARD_COMMIT commit( m_frame );
2483
2484 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2485 m_tuningPattern->Update( generatorTool, m_board, &commit );
2486 m_tuningPattern->EditPush( generatorTool, m_board, &commit, _( "Tune" ) );
2487
2488 m_tuningPattern = nullptr;
2489 m_pickerItem = nullptr;
2490 }
2491 }
2492 else if( evt->IsClick( BUT_RIGHT ) )
2493 {
2495 m_menu->ShowContextMenu( dummy );
2496 }
2497 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2498 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2499 {
2500 if( m_tuningPattern )
2501 {
2502 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2503
2504 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2505 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2506 meanderSettings.m_spacing = placer->MeanderSettings().m_spacing;
2507
2508 updateTuningPattern();
2509 }
2510 else
2511 {
2512 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2513 }
2514 }
2515 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2516 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2517 {
2518 if( m_tuningPattern )
2519 {
2520 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2521
2522 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2523 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2524 meanderSettings.m_maxAmplitude = placer->MeanderSettings().m_maxAmplitude;
2525
2526 updateTuningPattern();
2527 }
2528 else
2529 {
2530 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2531 }
2532 }
2533 else if( evt->IsAction( &PCB_ACTIONS::properties )
2534 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2535 {
2536 DRC_CONSTRAINT constraint;
2537
2538 if( m_tuningPattern )
2539 {
2540 if( !m_tuningPattern->GetItems().empty() )
2541 {
2542 BOARD_ITEM* startItem = *m_tuningPattern->GetItems().begin();
2543
2544 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2545 startItem->GetLayer() );
2546 }
2547 }
2548
2549 DIALOG_TUNING_PATTERN_PROPERTIES dlg( m_frame, meanderSettings, routerMode,
2550 constraint );
2551
2552 if( dlg.ShowModal() == wxID_OK )
2553 {
2554 if( m_tuningPattern )
2555 applyCommonSettings( m_tuningPattern );
2556
2557 updateTuningPattern();
2558 }
2559 }
2560 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2561 // but we don't at present have that, so we just knock out some of the egregious ones.
2562 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2563 {
2564 wxBell();
2565 }
2566 else
2567 {
2568 evt->SetPassEvent();
2569 }
2570
2571 controls->CaptureCursor( m_tuningPattern != nullptr );
2572 controls->SetAutoPan( m_tuningPattern != nullptr );
2573 }
2574
2575 controls->CaptureCursor( false );
2576 controls->SetAutoPan( false );
2577 controls->ForceCursorPosition( false );
2578 controls->ShowCursor( false );
2579 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2580
2582 m_view->Remove( &m_preview );
2583
2585
2586 if( m_tuningPattern )
2587 selectionTool->AddItemToSel( m_tuningPattern );
2588
2589 m_frame->PopTool( aEvent );
2590 return 0;
2591}
2592
2593
2595{
2597 {
2599 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2600 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2601 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2602
2604 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2605 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2606 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2607
2614
2615 const wxString groupTab = _HKI( "Pattern Properties" );
2616
2618 _HKI( "End X" ), &PCB_TUNING_PATTERN::SetEndX,
2619 &PCB_TUNING_PATTERN::GetEndX, PROPERTY_DISPLAY::PT_SIZE,
2621 groupTab );
2622
2624 _HKI( "End Y" ), &PCB_TUNING_PATTERN::SetEndY,
2625 &PCB_TUNING_PATTERN::GetEndY, PROPERTY_DISPLAY::PT_SIZE,
2627 groupTab );
2628
2630 _HKI( "Tuning Mode" ),
2633 groupTab );
2634
2636 _HKI( "Min Amplitude" ),
2639 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2640 groupTab );
2641
2643 _HKI( "Max Amplitude" ),
2646 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2647 groupTab );
2648
2650 _HKI( "Initial Side" ),
2653 groupTab );
2654
2656 _HKI( "Min Spacing" ), &PCB_TUNING_PATTERN::SetSpacing,
2657 &PCB_TUNING_PATTERN::GetSpacing, PROPERTY_DISPLAY::PT_SIZE,
2659 groupTab );
2660
2662 _HKI( "Corner Radius %" ),
2665 PROPERTY_DISPLAY::PT_DEFAULT, ORIGIN_TRANSFORMS::NOT_A_COORD ),
2666 groupTab );
2667
2668 auto isSkew =
2669 []( INSPECTABLE* aItem ) -> bool
2670 {
2671 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2672 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2673
2674 return false;
2675 };
2676
2677 auto notIsSkew =
2678 [&]( INSPECTABLE* aItem ) -> bool
2679 {
2680 return !isSkew( aItem );
2681 };
2682
2683 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>(
2684 _HKI( "Target Length" ),
2687 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2688 groupTab )
2689 .SetAvailableFunc( notIsSkew );
2690
2691
2693 _HKI( "Target Skew" ), &PCB_TUNING_PATTERN::SetTargetSkew,
2695 PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ),
2696 groupTab )
2697 .SetAvailableFunc( isSkew );
2698
2699
2701 _HKI( "Override Custom Rules" ),
2704 groupTab );
2705
2707 _HKI( "Single-sided" ),
2710 groupTab );
2711
2713 _HKI( "Rounded" ), &PCB_TUNING_PATTERN::SetRounded,
2715 groupTab );
2716 }
2718
2721
2723
2724// Also register under the 7.99 name
2725template <typename T>
2727{
2729 {
2730 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2731 []()
2732 {
2733 return new T;
2734 } );
2735 }
2736};
2737
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
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
Add a change of the item aItem of type aChangeType to the change list.
virtual void Revert() override
Revert the commit by restoring the modified items state.
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
int GetDRCEpsilon() const
Return an epsilon which accounts for rounding errors, etc.
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:239
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:90
PCB_LAYER_ID m_layer
Definition: board_item.h:438
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:278
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:47
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:166
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:295
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition: board.cpp:2032
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1961
const TRACKS & Tracks() const
Definition: board.h:334
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:2341
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:934
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)
Remove a new item from the model.
Definition: commit.h:92
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Definition: commit.h:108
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:80
int ShowModal() override
PCB_SELECTION m_preview
Definition: drawing_tool.h:404
KIGFX::VIEW * m_view
Definition: drawing_tool.h:393
BOARD_CONNECTED_ITEM * m_pickerItem
Definition: drawing_tool.h:405
bool m_inDrawingTool
Definition: drawing_tool.h:398
int PlaceTuningPattern(const TOOL_EVENT &aEvent)
BOARD * m_board
Definition: drawing_tool.h:395
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:396
PCB_TUNING_PATTERN * m_tuningPattern
Definition: drawing_tool.h:406
wxString GetName() const
Definition: drc_rule.h:160
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:152
bool IsNull() const
Definition: drc_rule.h:147
void ShowInfoBarWarning(const wxString &aWarningMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and a warning icon on the left ...
The base class for create windows for drawing purpose.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
virtual const VECTOR2I GetFocusPosition() const
Similar to GetPosition() but allows items to return their visual center rather than their anchor.
Definition: eda_item.h:251
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
Single point size in pixels.
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:680
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:37
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:249
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:211
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:297
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:332
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:1673
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:198
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:457
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1621
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition: matrix3x3.h:295
T Min() const
Definition: minoptmax.h:33
void SetMin(T v)
Definition: minoptmax.h:41
void SetMax(T v)
Definition: minoptmax.h:42
T Max() const
Definition: minoptmax.h:34
bool IsNull() const
Definition: minoptmax.h:45
T Opt() const
Definition: minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:45
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition: netclass.cpp:286
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:180
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:212
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:213
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:214
static TOOL_ACTION lengthTunerSettings
Definition: pcb_actions.h:215
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:211
const VECTOR2I & GetMid() const
Definition: pcb_track.h:305
Common, abstract interface for edit frames.
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
virtual void SetProperties(const STRING_ANY_MAP &aProps)
void baseMirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
wxString m_generatorType
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aMirrorDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
bool AddItem(BOARD_ITEM *aItem) override
Add item to group.
VECTOR2I m_origin
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_generator.h:82
VECTOR2I GetPosition() const override
Definition: pcb_generator.h:81
virtual std::vector< std::pair< wxString, wxVariant > > GetRowData()
virtual const STRING_ANY_MAP GetProperties() const
std::unordered_set< BOARD_ITEM * > m_items
Definition: pcb_group.h:221
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:69
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_group.cpp:347
wxString m_name
Definition: pcb_group.h:222
The selection tool: currently supports:
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
bool m_isFootprintEditor
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
virtual int GetWidth() const
Definition: pcb_track.h:116
void SetTargetSkew(int aValue)
void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
bool initBaseLines(PNS::ROUTER *aRouter, int aPNSLayer, BOARD *aBoard)
const STRING_ANY_MAP GetProperties() const override
bool HitTest(const BOX2I &aRect, bool aContained, int aAccuracy) const override
Test if aRect intersects this item.
void SetEnd(const VECTOR2I &aValue)
void SetMinAmplitude(int aValue)
void SetSpacing(int aValue)
wxString GetGeneratorType() const override
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
static const wxString DISPLAY_NAME
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
PNS::ROUTER_MODE GetPNSMode()
bool initBaseLine(PNS::ROUTER *aRouter, int aPNSLayer, BOARD *aBoard, VECTOR2I &aStart, VECTOR2I &aEnd, NETINFO_ITEM *aNet, std::optional< SHAPE_LINE_CHAIN > &aBaseLine)
PCB_TUNING_PATTERN(BOARD_ITEM *aParent=nullptr, PCB_LAYER_ID aLayer=F_Cu, LENGTH_TUNING_MODE aMode=LENGTH_TUNING_MODE::SINGLE)
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
void swapData(BOARD_ITEM *aImage) override
bool recoverBaseline(PNS::ROUTER *aRouter)
void EditRevert(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
PNS::MEANDER_SIDE GetInitialSide() const
const VECTOR2I & GetEnd() const
void SetInitialSide(PNS::MEANDER_SIDE aValue)
wxString GetFriendlyName() const override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
LENGTH_TUNING_MODE GetTuningMode() const
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
std::vector< EDA_ITEM * > GetPreviewItems(GENERATOR_TOOL *aTool, PCB_BASE_EDIT_FRAME *aFrame, bool aStatusItemsOnly=false) override
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void EditStart(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
void baseMirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void SetOverrideCustomRules(bool aOverride)
void SetRounded(bool aFlag)
LENGTH_TUNING_MODE m_tuningMode
std::vector< std::pair< wxString, wxVariant > > GetRowData() override
static const wxString GENERATOR_TYPE
bool resetToBaseline(GENERATOR_TOOL *aTool, int aPNSLayer, SHAPE_LINE_CHAIN &aBaseLine, bool aPrimary)
bool MakeEditPoints(EDIT_POINTS &points) const override
void SetCornerRadiusPercentage(int aValue)
PNS::MEANDER_PLACER_BASE::TUNING_STATUS m_tuningStatus
std::optional< SHAPE_LINE_CHAIN > m_baseLineCoupled
void SetProperties(const STRING_ANY_MAP &aProps) override
wxString GetPluralName() const override
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override final
Draw the parts of the object belonging to layer aLayer.
void Remove(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool UpdateFromEditPoints(EDIT_POINTS &aEditPoints) override
std::optional< SHAPE_LINE_CHAIN > m_baseLine
PNS::MEANDER_SETTINGS m_settings
void SetEndX(int aValue)
void ShowPropertiesDialog(PCB_BASE_EDIT_FRAME *aEditFrame) override
bool Update(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool UpdateEditPoints(EDIT_POINTS &aEditPoints) override
bool GetOverrideCustomRules() const
void SetMaxAmplitude(int aValue)
void EditPush(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit, const wxString &aCommitMsg=wxEmptyString, int aCommitFlags=0) override
PNS::MEANDER_SETTINGS & GetSettings()
void SetSingleSided(bool aValue)
bool removeToBaseline(PNS::ROUTER *aRouter, int aPNSLayer, SHAPE_LINE_CHAIN &aBaseLine)
std::optional< int > GetTargetLength() const
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
int GetCornerRadiusPercentage() const
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
SHAPE_LINE_CHAIN getOutline() const
void SetEndY(int aValue)
void SetTargetLength(std::optional< int > aValue)
static PCB_TUNING_PATTERN * CreateNew(GENERATOR_TOOL *aTool, PCB_BASE_EDIT_FRAME *aFrame, BOARD_CONNECTED_ITEM *aStartItem, LENGTH_TUNING_MODE aMode)
SHAPE_ARC & Arc()
Definition: pns_arc.h:115
Differential Pair length-matching/meandering tool.
std::vector< ITEM * > & Items()
Definition: pns_itemset.h:87
Base class for PNS router board items.
Definition: pns_item.h:98
virtual NET_HANDLE Net() const
Definition: pns_item.h:198
void SetNet(NET_HANDLE aNet)
Definition: pns_item.h:197
void SetLayer(int aLayer)
Definition: pns_item.h:203
@ SEGMENT_T
Definition: pns_item.h:107
void SetParent(BOARD_ITEM *aParent)
Definition: pns_item.h:189
bool OfKind(int aKindMask) const
Definition: pns_item.h:179
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:256
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:909
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:1047
virtual int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const =0
virtual void RemoveItem(ITEM *aItem)=0
virtual void AddItem(ITEM *aItem)=0
void SetMode(ROUTER_MODE aMode)
void StopRouting()
Definition: pns_router.cpp:930
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:221
ROUTER_IFACE * GetInterface() const
Definition: pns_router.h:223
void CommitRouting()
Definition: pns_router.cpp:921
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, int aSlopRadius=0)
Definition: pns_router.cpp:124
void SyncWorld()
Definition: pns_router.cpp:95
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:185
bool RoutingInProgress() const
Definition: pns_router.cpp:118
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:408
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:216
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
Definition: pns_router.cpp:878
NODE * GetWorld() const
Definition: pns_router.h:169
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:468
virtual int Clearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
const SHAPE_LINE_CHAIN CLine() const
Definition: pns_segment.h:95
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition: pns_segment.h:75
void SetShape(SHAPE *shape)
Definition: pns_solid.h:98
ROUTER * Router() const
PNS_KICAD_IFACE * GetInterface() const
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
void EraseView() override
wxString GetNetName(PNS::NET_HANDLE aNet) const override
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:257
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:87
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
RAII class that sets an value at construction and resets it to the original value at destruction.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Return the closest Euclidean distance between point aP and the line defined by the ends of segment (t...
Definition: seg.cpp:428
VECTOR2I::extended_type ecoord
Definition: seg.h:44
VECTOR2I B
Definition: seg.h:50
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:327
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition: seg.h:143
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:93
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Definition: shape_arc.cpp:427
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)
Perform boolean polyset union.
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:44
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:38
Generic, UI-independent tool event.
Definition: tool_event.h:168
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
VECTOR2D GetMousePosition() const
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:400
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
wxString GetClass() const override
Return the class name.
VECTOR2I GetPosition() const override
void SetMinMax(double aMin, double aMax)
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
void SetCurrent(double aCurrent, const wxString &aLabel)
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
TUNING_STATUS_VIEW_ITEM(PCB_BASE_EDIT_FRAME *aFrame)
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
void SetPosition(const VECTOR2I &aPos) override
wxString MessageTextFromMinOptMax(const MINOPTMAX< int > &aValue) const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
Definition: vector2d.h:569
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:310
@ LAYER_ANCHOR
Anchor of items having an anchor point (texts, footprints).
Definition: layer_ids.h:210
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:385
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:791
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:782
#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:132
@ BUT_RIGHT
Definition: tool_event.h:133
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:695