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 <functional>
29#include <optional>
30#include <magic_enum.hpp>
31
32#include <wx/debug.h>
33#include <wx/log.h>
34
38#include <kiplatform/ui.h>
40#include <collectors.h>
41#include <scoped_set_reset.h>
42#include <core/mirror.h>
43#include <string_utils.h>
44
45#include <board.h>
47#include <drc/drc_engine.h>
48#include <pcb_track.h>
49#include <pcb_shape.h>
50#include <pcb_group.h>
51
52#include <tool/edit_points.h>
53#include <tool/tool_manager.h>
54#include <tools/drawing_tool.h>
59
62#include <view/view.h>
63#include <view/view_controls.h>
64
67#include <router/pns_meander.h>
69#include <router/pns_segment.h>
70#include <router/pns_arc.h>
71#include <router/pns_solid.h>
72#include <router/pns_topology.h>
74
76
80#include <properties/property.h>
82
84 EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
85 m_frame( aFrame ),
86 m_min( 0.0 ),
87 m_max( 0.0 ),
88 m_current( 0.0 ),
89 m_isTimeDomain( false )
90{ }
91
92
94{
95 return wxT( "TUNING_STATUS" );
96}
97
98#if defined(DEBUG)
99void TUNING_STATUS_VIEW_ITEM::Show( int nestLevel, std::ostream& os ) const {}
100#endif
101
102
105
106
107void TUNING_STATUS_VIEW_ITEM::SetMinMax( const double aMin, const double aMax )
108{
110
111 m_min = aMin;
112 m_minText = m_frame->MessageTextFromValue( m_min, false, unitType );
113 m_max = aMax;
114 m_maxText = m_frame->MessageTextFromValue( m_max, false, unitType );
115}
116
117
119{
120 m_min = 0.0;
121 m_minText = wxT( "---" );
122 m_max = std::numeric_limits<double>::max();
123 m_maxText = wxT( "---" );
124}
125
126
127void TUNING_STATUS_VIEW_ITEM::SetCurrent( const double aCurrent, const wxString& aLabel )
128{
130
131 m_current = aCurrent;
132 m_currentText = m_frame->MessageTextFromValue( aCurrent, true, unitType );
133 m_currentLabel = aLabel;
134}
135
136
137void TUNING_STATUS_VIEW_ITEM::SetIsTimeDomain( const bool aIsTimeDomain )
138{
139 m_isTimeDomain = aIsTimeDomain;
140}
141
142
144{
145 BOX2I tmp;
146
147 // this is an edit-time artefact; no reason to try and be smart with the bounding box
148 // (besides, we can't tell the text extents without a view to know what the scale is)
149 tmp.SetMaximum();
150 return tmp;
151}
152
153
155{
156 return { LAYER_UI_START, LAYER_UI_START + 1 };
157}
158
159
160void TUNING_STATUS_VIEW_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
161{
162 KIGFX::GAL* gal = aView->GetGAL();
163 bool viewFlipped = gal->IsFlippedX();
164 bool drawingDropShadows = ( aLayer == LAYER_UI_START );
165
166 gal->Save();
167 gal->Scale( { 1., 1. } );
168
172 const KIFONT::METRICS& fontMetrics = KIFONT::METRICS::Default();
173 TEXT_ATTRIBUTES textAttrs;
174
175 int glyphWidth = textDims.GlyphSize.x;
176 VECTOR2I margin( KiROUND( glyphWidth * 0.4 ), glyphWidth );
177 VECTOR2I size( glyphWidth * 25 + margin.x * 2, headerDims.GlyphSize.y + textDims.GlyphSize.y );
178 VECTOR2I offset( margin.x * 2, -( size.y + margin.y * 2 ) );
179
180 if( drawingDropShadows )
181 {
182 gal->SetIsFill( true );
183 gal->SetIsStroke( true );
184 gal->SetLineWidth( gal->GetScreenWorldMatrix().GetScale().x * 2 );
185 gal->SetStrokeColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) );
186 KIGFX::COLOR4D bgColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
187 gal->SetFillColor( bgColor.WithAlpha( 0.9 ) );
188
189 gal->DrawRectangle( GetPosition() + offset - margin,
190 GetPosition() + offset + size + margin );
191 gal->Restore();
192 return;
193 }
194
195 COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
196 COLOR4D normal = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
197 COLOR4D red;
199
200 double bg_h, bg_s, bg_l;
201 bg.ToHSL( bg_h, bg_s, bg_l );
202
203 // Choose colors with reasonable contrasting with the background
204 red.FromHSL( 0.0, 1.0, bg_l < 0.5 ? 0.7 : 0.3 );
205 green.FromHSL( 120.0, 1.0, bg_l < 0.5 ? 0.8 : 0.2 );
206
207 if( viewFlipped )
209 else
210 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
211
212 gal->SetIsFill( false );
213 gal->SetIsStroke( true );
214 gal->SetStrokeColor( normal );
215 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
216
217 // Prevent text flipping when view is flipped
218 if( gal->IsFlippedX() )
219 {
220 textAttrs.m_Mirrored = true;
222 }
223
224 textAttrs.m_Size = headerDims.GlyphSize;
225 textAttrs.m_StrokeWidth = headerDims.StrokeWidth;
226
227 VECTOR2I textPos = GetPosition() + offset;
228 font->Draw( gal, m_currentLabel, textPos, textAttrs, KIFONT::METRICS::Default() );
229
230 textPos.x += glyphWidth * 11 + margin.x;
231 font->Draw( gal, _( "min" ), textPos, textAttrs, fontMetrics );
232
233 textPos.x += glyphWidth * 7 + margin.x;
234 font->Draw( gal, _( "max" ), textPos, textAttrs, fontMetrics );
235
236 textAttrs.m_Size = textDims.GlyphSize;
237 textAttrs.m_StrokeWidth = textDims.StrokeWidth;
238
239 textPos = GetPosition() + offset;
240 textPos.y += KiROUND( headerDims.LinePitch * 1.3 );
242 font->Draw( gal, m_currentText, textPos, textAttrs, KIFONT::METRICS::Default() );
243
244 textPos.x += glyphWidth * 11 + margin.x;
245 gal->SetStrokeColor( m_current < m_min ? red : green );
246 font->Draw( gal, m_minText, textPos, textAttrs, fontMetrics );
247
248 textPos.x += glyphWidth * 7 + margin.x;
249 gal->SetStrokeColor( m_current > m_max ? red : green );
250 font->Draw( gal, m_maxText, textPos, textAttrs, fontMetrics );
251
252 gal->Restore();
253}
254
255
256static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
257{
258 if( aStr == "single" )
260 else if( aStr == "diff_pair" )
262 else if( aStr == "diff_pair_skew" )
264 else
265 {
266 wxFAIL_MSG( wxS( "Unknown length tuning token" ) );
268 }
269}
270
271
272static std::string tuningToString( const LENGTH_TUNING_MODE aTuning )
273{
274 switch( aTuning )
275 {
276 case LENGTH_TUNING_MODE::SINGLE: return "single";
277 case LENGTH_TUNING_MODE::DIFF_PAIR: return "diff_pair";
278 case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return "diff_pair_skew";
279 default: wxFAIL; return "";
280 }
281}
282
283
294
295
296static PNS::MEANDER_SIDE sideFromString( const std::string& aStr )
297{
298 if( aStr == "default" )
300 else if( aStr == "left" )
302 else if( aStr == "right" )
304 else
305 {
306 wxFAIL_MSG( wxS( "Unknown length-tuning side token" ) );
308 }
309}
310
311
313{
314 switch( aStatus )
315 {
316 case PNS::MEANDER_PLACER_BASE::TOO_LONG: return "too_long";
317 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: return "too_short";
318 case PNS::MEANDER_PLACER_BASE::TUNED: return "tuned";
319 default: wxFAIL; return "";
320 }
321}
322
323
325{
326 if( aStr == "too_long" )
328 else if( aStr == "too_short" )
330 else if( aStr == "tuned" )
332 else
333 {
334 wxFAIL_MSG( wxS( "Unknown tuning status token" ) );
336 }
337}
338
339
340static std::string sideToString( const PNS::MEANDER_SIDE aValue )
341{
342 switch( aValue )
343 {
344 case PNS::MEANDER_SIDE_DEFAULT: return "default";
345 case PNS::MEANDER_SIDE_LEFT: return "left";
346 case PNS::MEANDER_SIDE_RIGHT: return "right";
347 default: wxFAIL; return "";
348 }
349}
350
351
353 LENGTH_TUNING_MODE aMode ) :
354 PCB_GENERATOR( aParent, aLayer ),
355 m_trackWidth( 0 ),
356 m_diffPairGap( 0 ),
357 m_tuningMode( aMode ),
358 m_tuningLength( 0 ),
359 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED ),
360 m_updateSideFromEnd( false )
361{
364 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
365 m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
366}
367
368
369static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
370 PCB_TRACK** aNearestTrack )
371{
373 VECTOR2I closestPt = aP;
374
375 for( PCB_TRACK *track : aBoard->Tracks() )
376 {
377 if( aNet && track->GetNet() != aNet )
378 continue;
379
380 VECTOR2I nearest;
381
382 if( track->Type() == PCB_ARC_T )
383 {
384 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
385 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
386 pcbArc->GetWidth() );
387
388 nearest = arc.NearestPoint( aP );
389 }
390 else
391 {
392 SEG seg( track->GetStart(), track->GetEnd() );
393 nearest = seg.NearestPoint( aP );
394 }
395
396 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
397
398 if( dist_sq < minDist_sq )
399 {
400 minDist_sq = dist_sq;
401 closestPt = nearest;
402
403 if( aNearestTrack )
404 *aNearestTrack = track;
405 }
406 }
407
408 return closestPt;
409}
410
411
413{
415 {
416 return( m_baseLine && m_baseLine->PointCount() > 1
417 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
418 }
419 else
420 {
421 return( m_baseLine && m_baseLine->PointCount() > 1 );
422 }
423}
424
425
427 PCB_BASE_EDIT_FRAME* aFrame,
428 BOARD_CONNECTED_ITEM* aStartItem,
429 LENGTH_TUNING_MODE aMode )
430{
431 BOARD* board = aStartItem->GetBoard();
433 DRC_CONSTRAINT constraint;
434 PCB_LAYER_ID layer = aStartItem->GetLayer();
435
436 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
437
438 switch( aMode )
439 {
440 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
441 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
442 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
443 }
444
445 if( aMode == SINGLE || aMode == DIFF_PAIR )
446 {
447 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
448
449 if( !constraint.IsNull() )
450 {
452 {
453 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
455 pattern->m_settings.m_isTimeDomain = true;
456 }
457 else
458 {
460 pattern->m_settings.SetTargetLength( constraint.GetValue() );
461 pattern->m_settings.m_isTimeDomain = false;
462 }
463 }
464 else if( aStartItem->GetEffectiveNetClass()->HasTuningProfile() )
465 {
466 // Check if the tuning profile has time domain tuning enabled
467 const std::shared_ptr<TUNING_PROFILES> tuningParams =
469 TUNING_PROFILE& profile =
470 tuningParams->GetTuningProfile( aStartItem->GetEffectiveNetClass()->GetTuningProfile() );
471
472 if( profile.m_EnableTimeDomainTuning )
473 pattern->m_settings.m_isTimeDomain = true;
474 }
475 }
476 else
477 {
478 constraint = bds.m_DRCEngine->EvalRules( SKEW_CONSTRAINT, aStartItem, nullptr, layer );
479
480 if( !constraint.IsNull() )
481 {
483 {
485 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
486 pattern->m_settings.m_isTimeDomain = true;
487 }
488 else
489 {
490 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
492 pattern->m_settings.m_isTimeDomain = true;
493 }
494 }
495 }
496
497 pattern->SetFlags( IS_NEW );
498 pattern->m_settings.m_netClass = aStartItem->GetEffectiveNetClass();
499
500 return pattern;
501}
502
504{
505 if( aCommit )
506 {
507 if( IsNew() )
508 aCommit->Add( this );
509 else
510 aCommit->Modify( this );
511 }
512
513 SetFlags( IN_EDIT );
514
515 PNS::ROUTER* router = aTool->Router();
516 int layer = router->GetInterface()->GetPNSLayerFromBoardLayer( GetLayer() );
517
518 aTool->ClearRouterChanges();
519 router->SyncWorld();
520
522 PNS::CONSTRAINT constraint;
523
524 if( !baselineValid() )
525 initBaseLines( router, layer, aBoard );
526
528 {
529 VECTOR2I centerlineOffsetEnd;
530
532 && m_baseLineCoupled->SegmentCount() > 0 )
533 {
534 centerlineOffsetEnd =
535 ( m_baseLineCoupled->CLastPoint() - m_baseLine->CLastPoint() ) / 2;
536 }
537
538 SEG baseEnd = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( -1 )
539 : SEG( m_origin, m_end );
540
541 baseEnd.A += centerlineOffsetEnd;
542 baseEnd.B += centerlineOffsetEnd;
543
544 if( baseEnd.A != baseEnd.B )
545 {
546 int side = baseEnd.Side( m_end );
547
548 if( side < 0 )
549 m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
550 else
551 m_settings.m_initialSide = PNS::MEANDER_SIDE_RIGHT;
552 }
553
554 m_updateSideFromEnd = false;
555 }
556
557 PCB_TRACK* track = nullptr;
558 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
559 wxCHECK( track, /* void */ );
560
561 m_settings.m_netClass = track->GetEffectiveNetClass();
562
563 if( !m_settings.m_overrideCustomRules )
564 {
565 PNS::SEGMENT pnsItem;
566 NETINFO_ITEM* net = track->GetNet();
567
568 pnsItem.SetParent( track );
569 pnsItem.SetNet( net );
570
571 if( m_tuningMode == SINGLE )
572 {
573 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
574 &pnsItem, nullptr, layer, &constraint ) )
575 {
576 if( constraint.m_IsTimeDomain )
577 {
578 m_settings.SetTargetLengthDelay( constraint.m_Value );
579 m_settings.SetTargetLength( MINOPTMAX<int>() );
580 }
581 else
582 {
583 m_settings.SetTargetLengthDelay( MINOPTMAX<int>() );
584 m_settings.SetTargetLength( constraint.m_Value );
585 }
586
587 m_settings.m_isTimeDomain = constraint.m_IsTimeDomain;
589 }
590 else if( track->GetEffectiveNetClass()->HasTuningProfile() )
591 {
592 m_settings.m_isTimeDomain = true;
594 }
595 }
596 else
597 {
598 PCB_TRACK* coupledTrack = nullptr;
599 PNS::SEGMENT pnsCoupledItem;
600 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
601
602 if( coupledNet )
603 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
604
605 pnsCoupledItem.SetParent( coupledTrack );
606 pnsCoupledItem.SetNet( coupledNet );
607
608 if( m_tuningMode == DIFF_PAIR )
609 {
610 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
611 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
612 {
613 if( constraint.m_IsTimeDomain )
614 {
615 m_settings.SetTargetLengthDelay( constraint.m_Value );
616 m_settings.SetTargetLength( MINOPTMAX<int>() );
617 }
618 else
619 {
620 m_settings.SetTargetLengthDelay( MINOPTMAX<int>() );
621 m_settings.SetTargetLength( constraint.m_Value );
622 }
623
624 m_settings.m_isTimeDomain = constraint.m_IsTimeDomain;
626 }
627 else if( track->GetEffectiveNetClass()->HasTuningProfile() )
628 {
629 m_settings.m_isTimeDomain = true;
631 }
632 }
633 else
634 {
636 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
637 {
638 if( constraint.m_IsTimeDomain )
639 {
640 m_settings.SetTargetSkewDelay( constraint.m_Value );
641 m_settings.SetTargetSkew( MINOPTMAX<int>() );
642 }
643 else
644 {
645 m_settings.SetTargetSkewDelay( MINOPTMAX<int>() );
646 m_settings.SetTargetSkew( constraint.m_Value );
647 }
648
649 m_settings.m_isTimeDomain = constraint.m_IsTimeDomain;
651 }
652 }
653 }
654 }
655}
656
657
658static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
659 VECTOR2I& aPointOut,
660 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
661{
662 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
663
664 static const int candidateCount = 2;
665 PNS::LINKED_ITEM* prioritized[candidateCount];
666 SEG::ecoord dist[candidateCount];
667 SEG::ecoord distBaseline[candidateCount];
668 VECTOR2I point[candidateCount];
669
670 for( int i = 0; i < candidateCount; i++ )
671 {
672 prioritized[i] = nullptr;
673 dist[i] = VECTOR2I::ECOORD_MAX;
674 distBaseline[i] = VECTOR2I::ECOORD_MAX;
675 }
676
677 for( int slopRadius : { 0, maxSlopRadius } )
678 {
679 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
680
681 for( PNS::ITEM* item : candidates.Items() )
682 {
683 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
684 continue;
685
686 if( !item->IsRoutable() )
687 continue;
688
689 if( !item->Layers().Overlaps( aLayer ) )
690 continue;
691
692 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
693
694 if( item->Kind() & PNS::ITEM::ARC_T )
695 {
696 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
697
698 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
699 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
700
701 if( d0 > dist[1] )
702 continue;
703
704 if( aBaseline.PointCount() > 0 )
705 {
706 SEG::ecoord dcBaseline;
707 VECTOR2I target = pnsArc->Arc().GetArcMid();
708
709 if( aBaseline.SegmentCount() > 0 )
710 dcBaseline = aBaseline.SquaredDistance( target );
711 else
712 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
713
714 if( dcBaseline > distBaseline[1] )
715 continue;
716
717 distBaseline[1] = dcBaseline;
718 }
719
720 prioritized[1] = linked;
721 dist[1] = d0;
722 point[1] = nearest;
723 }
724 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
725 {
726 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
727
728 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
729 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
730
731 if( dd > dist[1] )
732 continue;
733
734 if( aBaseline.PointCount() > 0 )
735 {
736 SEG::ecoord dcBaseline;
737 VECTOR2I target = segm->Shape( -1 )->Centre();
738
739 if( aBaseline.SegmentCount() > 0 )
740 dcBaseline = aBaseline.SquaredDistance( target );
741 else
742 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
743
744 if( dcBaseline > distBaseline[1] )
745 continue;
746
747 distBaseline[1] = dcBaseline;
748 }
749
750 prioritized[1] = segm;
751 dist[1] = dd;
752 point[1] = nearest;
753 }
754 }
755 }
756
757 PNS::LINKED_ITEM* rv = nullptr;
758
759 for( int i = 0; i < candidateCount; i++ )
760 {
761 PNS::LINKED_ITEM* item = prioritized[i];
762
763 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
764 {
765 rv = item;
766 aPointOut = point[i];
767 break;
768 }
769 }
770
771 return rv;
772}
773
774
775static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
776 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
777 VECTOR2I& aEndOut )
778{
779 PNS::NODE* world = router->GetWorld();
780
781 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
782 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
783
784 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
785 {
786 if( !testItem )
787 continue;
788
789 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
790 SHAPE_LINE_CHAIN oldChain = line.CLine();
791
792 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
793 return line;
794 }
795
796 return std::nullopt;
797}
798
799
800bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard,
801 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
802 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
803{
804 PNS::NODE* world = aRouter->GetWorld();
805
806 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
807 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
808
809 VECTOR2I startSnapPoint, endSnapPoint;
810
811 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aPNSLayer, startSnapPoint );
812 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aPNSLayer, endSnapPoint );
813
814 wxASSERT( startItem );
815 wxASSERT( endItem );
816
817 if( !startItem || !endItem )
818 return false;
819
820 PNS::LINE line = world->AssembleLine( startItem );
821 const SHAPE_LINE_CHAIN& chain = line.CLine();
822
823 wxASSERT( line.ContainsLink( endItem ) );
824
825 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
826 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
827
830 SHAPE_LINE_CHAIN post;
831
832 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
833
834 aBaseLine = mid;
835
836 return true;
837}
838
839
840bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard )
841{
842 m_baseLineCoupled.reset();
843
844 PCB_TRACK* track = nullptr;
845
846 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
847 wxCHECK( track, false );
848
849 NETINFO_ITEM* net = track->GetNet();
850
851 if( !initBaseLine( aRouter, aPNSLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
852 return false;
853
854 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
855 // DRC rules against.
857 {
858 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
859 {
860 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
861 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
862
863 return initBaseLine( aRouter, aPNSLayer, aBoard, coupledStart, coupledEnd, coupledNet,
865 }
866
867 return false;
868 }
869
870 return true;
871}
872
873
875{
876public:
878 m_pattern( aPattern ),
879 m_wasLocked( aPattern->IsLocked() )
880 {
881 m_pattern->SetLocked( false );
882 }
883
885 {
886 if( m_wasLocked )
887 m_pattern->SetLocked( true );
888 }
889
890private:
893};
894
895
896bool PCB_TUNING_PATTERN::removeToBaseline( PNS::ROUTER* aRouter, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine )
897{
898 VECTOR2I startSnapPoint, endSnapPoint;
899
900 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CLastPoint(), aRouter,
901 aPNSLayer, startSnapPoint, endSnapPoint );
902
903 wxCHECK( pnsLine, false );
904
907 SHAPE_LINE_CHAIN post;
908 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
909
910 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
911 aRouter->GetInterface()->RemoveItem( li );
912
913 aRouter->GetWorld()->Remove( *pnsLine );
914
915 SHAPE_LINE_CHAIN straightChain;
916 straightChain.Append( pre );
917 straightChain.Append( aBaseLine );
918 straightChain.Append( post );
919 straightChain.Simplify();
920
921 PNS::LINE straightLine( *pnsLine, straightChain );
922
923 aRouter->GetWorld()->Add( straightLine, false );
924
925 for( PNS::LINKED_ITEM* li : straightLine.Links() )
926 aRouter->GetInterface()->AddItem( li );
927
928 return true;
929}
930
931
933{
934 UNLOCKER raiiUnlocker( this );
935 SetFlags( IN_EDIT );
936
937 aTool->Router()->SyncWorld();
938
939 PNS::ROUTER* router = aTool->Router();
940 PNS_KICAD_IFACE* iface = aTool->GetInterface();
941
942 aCommit->Remove( this );
943
944 aTool->ClearRouterChanges();
945
946 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
947 int pnslayer = iface->GetPNSLayerFromBoardLayer( GetLayer() );
948
949 if( baselineValid() )
950 {
951 bool success = true;
952
953 success &= removeToBaseline( router, pnslayer, *m_baseLine );
954
955 if( m_tuningMode == DIFF_PAIR )
956 success &= removeToBaseline( router, pnslayer, *m_baseLineCoupled );
957
958 if( !success )
959 recoverBaseline( router );
960 }
961
962 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
963
964 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
965 {
966 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
967 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
968
969 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
970 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
971 << " m_removedItems " << m_removedItems.size() << std::endl;*/
972
973 for( BOARD_ITEM* item : routerRemovedItems )
974 {
975 item->ClearSelected();
976 aCommit->Remove( item );
977 }
978
979 for( BOARD_ITEM* item : routerAddedItems )
980 aCommit->Add( item );
981 }
982}
983
984
986{
987 PNS::SOLID queryItem;
988
990 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
991 queryItem.SetLayer( m_layer );
992
993 int lineWidth = 0;
994
995 PNS::NODE::OBSTACLES obstacles;
997 opts.m_useClearanceEpsilon = false;
998
999 PNS::NODE* world = aRouter->GetWorld();
1000 PNS::NODE* branch = world->Branch();
1001
1002 branch->QueryColliding( &queryItem, obstacles, opts );
1003
1004 for( const PNS::OBSTACLE& obs : obstacles )
1005 {
1006 PNS::ITEM* item = obs.m_item;
1007
1009 continue;
1010
1011 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
1012 {
1013 if( lineWidth == 0 || li->Width() < lineWidth )
1014 lineWidth = li->Width();
1015 }
1016
1017 if( chain->PointInside( item->Anchor( 0 ), 10 )
1018 && chain->PointInside( item->Anchor( 1 ), 10 ) )
1019 {
1020 branch->Remove( item );
1021 }
1022 }
1023
1024 if( lineWidth == 0 )
1025 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1026
1027 if( baselineValid() )
1028 {
1029 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1030 PNS::LINE recoverLine;
1031
1032 recoverLine.SetLayer( m_layer );
1033 recoverLine.SetWidth( lineWidth );
1034 recoverLine.Line() = *m_baseLine;
1035 recoverLine.SetNet( recoverNet );
1036 branch->Add( recoverLine, false );
1037
1039 {
1040 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1041 PNS::LINE recoverLineCoupled;
1042
1043 recoverLineCoupled.SetLayer( m_layer );
1044 recoverLineCoupled.SetWidth( lineWidth );
1045 recoverLineCoupled.Line() = *m_baseLineCoupled;
1046 recoverLineCoupled.SetNet( recoverCoupledNet );
1047 branch->Add( recoverLineCoupled, false );
1048 }
1049 }
1050
1051 aRouter->CommitRouting( branch );
1052
1053 //wxLogWarning( "PNS baseline recovered" );
1054
1055 return true;
1056}
1057
1058
1060 bool aPrimary )
1061{
1062 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1063 PNS::ROUTER* router = aTool->Router();
1064 PNS::NODE* world = router->GetWorld();
1065 VECTOR2I startSnapPoint, endSnapPoint;
1066
1067 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CLastPoint(), router,
1068 aPNSLayer, startSnapPoint, endSnapPoint );
1069
1070 if( !pnsLine )
1071 {
1072 // TODO
1073 //recoverBaseline( aRouter );
1074 return true;
1075 }
1076
1077 PNS::NODE* branch = world->Branch();
1078
1079 SHAPE_LINE_CHAIN straightChain;
1080 {
1081 SHAPE_LINE_CHAIN pre, mid, post;
1082 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1083
1084 straightChain.Append( pre );
1085 straightChain.Append( aBaseLine );
1086 straightChain.Append( post );
1087 straightChain.Simplify();
1088 }
1089
1090 branch->Remove( *pnsLine );
1091
1092 SHAPE_LINE_CHAIN newLineChain;
1093
1094 if( aPrimary )
1095 {
1096 m_origin = straightChain.NearestPoint( m_origin );
1097 m_end = straightChain.NearestPoint( m_end );
1098
1099 // Don't allow points too close
1100 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1101 {
1102 m_origin = startSnapPoint;
1103 m_end = endSnapPoint;
1104 }
1105
1106 {
1107 SHAPE_LINE_CHAIN pre, mid, post;
1108 straightChain.Split( m_origin, m_end, pre, mid, post );
1109
1110 newLineChain.Append( pre );
1111 newLineChain.Append( mid );
1112 newLineChain.Append( post );
1113
1114 m_baseLine = mid;
1115 }
1116 }
1117 else
1118 {
1119 VECTOR2I start = straightChain.NearestPoint( m_origin );
1120 VECTOR2I end = straightChain.NearestPoint( m_end );
1121
1122 {
1123 SHAPE_LINE_CHAIN pre, mid, post;
1124 straightChain.Split( start, end, pre, mid, post );
1125
1126 newLineChain.Append( pre );
1127 newLineChain.Append( mid );
1128 newLineChain.Append( post );
1129
1130 m_baseLineCoupled = mid;
1131 }
1132 }
1133
1134 PNS::LINE newLine( *pnsLine, newLineChain );
1135
1136 branch->Add( newLine, false );
1137 router->CommitRouting( branch );
1138
1139 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1140
1141 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1142
1143 return true;
1144}
1145
1146
1148{
1149 if( !( GetFlags() & IN_EDIT ) )
1150 return false;
1151
1152 UNLOCKER raiiUnlocker( this );
1153
1154 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1155 PNS::ROUTER* router = aTool->Router();
1156 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1157 PCB_LAYER_ID pcblayer = GetLayer();
1158
1159 auto hideRemovedItems = [&]( bool aHide )
1160 {
1161 if( view )
1162 {
1163 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1164 {
1165 for( BOARD_ITEM* item : pnsCommit.removedItems )
1166 {
1167 if( view )
1168 view->Hide( item, aHide, aHide );
1169 }
1170 }
1171 }
1172 };
1173
1174 iface->SetStartLayerFromPCBNew( pcblayer );
1175
1176 if( router->RoutingInProgress() )
1177 {
1178 router->StopRouting();
1179 }
1180
1181 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1182 int pnslayer = iface->GetPNSLayerFromBoardLayer( pcblayer );
1183
1184 if( !baselineValid() )
1185 {
1186 initBaseLines( router, pnslayer, aBoard );
1187 }
1188 else
1189 {
1190 if( resetToBaseline( aTool, pnslayer, *m_baseLine, true ) )
1191 {
1192 m_origin = m_baseLine->CPoint( 0 );
1193 m_end = m_baseLine->CLastPoint();
1194 }
1195 else
1196 {
1197 //initBaseLines( router, layer, aBoard );
1198 return false;
1199 }
1200
1201 if( m_tuningMode == DIFF_PAIR )
1202 {
1203 if( !resetToBaseline( aTool, pnslayer, *m_baseLineCoupled, false ) )
1204 {
1205 initBaseLines( router, pnslayer, aBoard );
1206 return false;
1207 }
1208 }
1209 }
1210
1211 hideRemovedItems( true );
1212 // Snap points
1213 VECTOR2I startSnapPoint, endSnapPoint;
1214
1215 wxCHECK( m_baseLine, false );
1216
1217 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, pnslayer, startSnapPoint, *m_baseLine);
1218 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, pnslayer, endSnapPoint, *m_baseLine );
1219
1220 wxASSERT( startItem );
1221 wxASSERT( endItem );
1222
1223 if( !startItem || !endItem )
1224 return false;
1225
1226 router->SetMode( GetPNSMode() );
1227
1228 if( !router->StartRouting( startSnapPoint, startItem, pnslayer ) )
1229 {
1230 //recoverBaseline( router );
1231 return false;
1232 }
1233
1234 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1235
1236 m_settings.m_keepEndpoints = true; // Required for re-grouping
1237 placer->UpdateSettings( m_settings );
1238
1239 router->Move( m_end, nullptr );
1240
1241 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1242 {
1243 m_trackWidth = dpPlacer->GetOriginPair().Width();
1244 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1245 }
1246 else
1247 {
1248 m_trackWidth = startItem->Width();
1249 m_diffPairGap = router->Sizes().DiffPairGap();
1250 }
1251
1252 m_settings = placer->MeanderSettings();
1253 m_lastNetName = iface->GetNetName( startItem->Net() );
1254 m_tuningStatus = placer->TuningStatus();
1256
1257 wxString statusMessage;
1258
1259 switch( m_tuningStatus )
1260 {
1261 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1262 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1263 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1264 default: statusMessage = _( "unknown" ); break;
1265 }
1266
1267 wxString result;
1268 EDA_UNITS userUnits = EDA_UNITS::MM;
1269
1270 if( aTool->GetManager()->GetSettings() )
1271 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1272
1273 if( m_settings.m_isTimeDomain )
1274 {
1276 (double) m_tuningLength );
1277 }
1278 else
1279 {
1281 (double) m_tuningLength );
1282 }
1283
1284 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1285
1286 return true;
1287}
1288
1289
1291{
1292 if( !( GetFlags() & IN_EDIT ) )
1293 return;
1294
1296
1297 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1298 PNS::ROUTER* router = aTool->Router();
1299 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1300 SHAPE_LINE_CHAIN bounds = getOutline();
1301 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1302
1303 iface->EraseView();
1304
1305 if( router->RoutingInProgress() )
1306 {
1307 bool forceFinish = true;
1308 bool forceCommit = false;
1309
1310 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1311 router->StopRouting();
1312 }
1313
1314 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1315
1316 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1317 {
1318 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1319 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1320
1321 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1322 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1323 // << " m_removedItems " << m_removedItems.size() << std::endl;
1324
1325 for( BOARD_ITEM* item : routerRemovedItems )
1326 {
1327 if( view )
1328 view->Hide( item, false );
1329
1330 aCommit->Remove( item );
1331 }
1332
1333 for( BOARD_ITEM* item : routerAddedItems )
1334 {
1335 aCommit->Add( item );
1336
1337 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1338 {
1339 if( bounds.PointInside( track->GetStart(), epsilon )
1340 && bounds.PointInside( track->GetEnd(), epsilon ) )
1341 {
1342 AddItem( item );
1343 }
1344 }
1345 }
1346 }
1347}
1348
1349
1351{
1352 if( !( GetFlags() & IN_EDIT ) )
1353 return;
1354
1356
1357 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1358
1359 iface->EraseView();
1360
1361 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1362 {
1363 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1364 {
1365 for( BOARD_ITEM* item : pnsCommit.removedItems )
1366 view->Hide( item, false );
1367 }
1368 }
1369
1370 aTool->Router()->StopRouting();
1371}
1372
1373
1375{
1376 VECTOR2I centerlineOffset;
1377 VECTOR2I centerlineOffsetEnd;
1378
1379 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1380 {
1381 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1382 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1383 }
1384
1385 aPoints.AddPoint( m_origin + centerlineOffset );
1386 aPoints.AddPoint( m_end + centerlineOffsetEnd );
1387
1388 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1389 : SEG( m_origin, m_end );
1390
1391 base.A += centerlineOffset;
1392 base.B += centerlineOffset;
1393
1394 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1395
1396 if( m_tuningMode == DIFF_PAIR )
1397 amplitude += m_trackWidth + m_diffPairGap;
1398
1399 if( m_settings.m_initialSide == -1 )
1400 amplitude *= -1;
1401
1402 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1403
1404 aPoints.AddPoint( base.A + widthHandleOffset );
1405 aPoints.Point( 2 ).SetGridConstraint( IGNORE_GRID );
1406
1407 VECTOR2I spacingHandleOffset =
1408 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1409
1410 aPoints.AddPoint( base.A + spacingHandleOffset );
1411 aPoints.Point( 3 ).SetGridConstraint( IGNORE_GRID );
1412
1413 return true;
1414}
1415
1416
1418{
1419 VECTOR2I centerlineOffset;
1420 VECTOR2I centerlineOffsetEnd;
1421
1422 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1423 {
1424 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1425 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1426 }
1427
1428 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1429 : SEG( m_origin, m_end );
1430
1431 base.A += centerlineOffset;
1432 base.B += centerlineOffset;
1433
1434 m_origin = aEditPoints.Point( 0 ).GetPosition() - centerlineOffset;
1435 m_end = aEditPoints.Point( 1 ).GetPosition() - centerlineOffsetEnd;
1436
1437 if( aEditPoints.Point( 2 ).IsActive() )
1438 {
1439 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1440
1441 int value = base.LineDistance( wHandle );
1442
1443 value -= KiROUND( m_trackWidth / 2.0 );
1444
1445 if( m_tuningMode == DIFF_PAIR )
1446 value -= m_trackWidth + m_diffPairGap;
1447
1448 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1449
1450 int side = base.Side( wHandle );
1451
1452 if( side < 0 )
1453 m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
1454 else
1455 m_settings.m_initialSide = PNS::MEANDER_SIDE_RIGHT;
1456 }
1457
1458 if( aEditPoints.Point( 3 ).IsActive() )
1459 {
1460 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1461 VECTOR2I sHandle = aEditPoints.Point( 3 ).GetPosition();
1462
1463 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1464
1465 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1466 }
1467
1468 return true;
1469}
1470
1471
1473{
1474 VECTOR2I centerlineOffset;
1475 VECTOR2I centerlineOffsetEnd;
1476
1477 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1478 {
1479 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1480 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1481 }
1482
1483 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1484 : SEG( m_origin, m_end );
1485
1486 base.A += centerlineOffset;
1487 base.B += centerlineOffset;
1488
1489 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1490
1491 if( m_tuningMode == DIFF_PAIR )
1492 amplitude += m_trackWidth + m_diffPairGap;
1493
1494 if( m_settings.m_initialSide == -1 )
1495 amplitude *= -1;
1496
1497 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1498
1499 aEditPoints.Point( 0 ).SetPosition( m_origin + centerlineOffset );
1500 aEditPoints.Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1501
1502 aEditPoints.Point( 2 ).SetPosition( base.A + widthHandleOffset );
1503
1504 VECTOR2I spacingHandleOffset =
1505 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1506
1507 aEditPoints.Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1508
1509 return true;
1510}
1511
1512
1514{
1515 if( m_baseLine )
1516 {
1517 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1518 int minAllowedAmplitude = 0;
1519 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1520
1522 {
1523 minAllowedAmplitude = baselineOffset + m_trackWidth;
1524 }
1525 else
1526 {
1527 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1528 minAllowedAmplitude = baselineOffset + correction;
1529 }
1530
1531 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1532
1533 if( m_settings.m_singleSided )
1534 {
1535 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1537
1538 if( m_tuningMode != DIFF_PAIR )
1539 {
1540 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1541
1543
1545 true ) )
1546 {
1547 chain.Append( m_settings.m_initialSide >= 0 ? right : left );
1548 chain.Append( clBase.Reverse() );
1549 chain.SetClosed( true );
1550
1551 return chain;
1552 }
1553 }
1555 {
1556 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1557
1559 SHAPE_LINE_CHAIN chain1, chain2;
1560
1562 true ) )
1563 {
1564 if( m_settings.m_initialSide >= 0 )
1565 chain1.Append( right );
1566 else
1567 chain1.Append( left );
1568
1570 ARC_LOW_DEF, left, right, true ) )
1571 {
1572 if( m_settings.m_initialSide >= 0 )
1573 chain1.Append( left.Reverse() );
1574 else
1575 chain1.Append( right.Reverse() );
1576 }
1577
1578 chain1.SetClosed( true );
1579 }
1580
1582 true ) )
1583 {
1584 if( m_settings.m_initialSide >= 0 )
1585 chain2.Append( right );
1586 else
1587 chain2.Append( left );
1588
1590 ARC_LOW_DEF, left, right, true ) )
1591 {
1592 if( m_settings.m_initialSide >= 0 )
1593 chain2.Append( left.Reverse() );
1594 else
1595 chain2.Append( right.Reverse() );
1596 }
1597
1598 chain2.SetClosed( true );
1599 }
1600
1601 SHAPE_POLY_SET merged;
1602 merged.BooleanAdd( chain1, chain2 );
1603
1604 if( merged.OutlineCount() > 0 )
1605 return merged.Outline( 0 );
1606 }
1607 }
1608
1609 // Not single-sided / fallback
1610 SHAPE_POLY_SET poly;
1612
1613 int amplitude = 0;
1614
1615 if( m_tuningMode == DIFF_PAIR )
1616 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1617 else
1618 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1619
1621
1623 {
1624 SHAPE_POLY_SET polyCoupled;
1626 ARC_LOW_DEF, false );
1627
1628 poly.ClearArcs();
1629 polyCoupled.ClearArcs();
1630
1631 SHAPE_POLY_SET merged;
1632 merged.BooleanAdd( poly, polyCoupled );
1633
1634 if( merged.OutlineCount() > 0 )
1635 return merged.Outline( 0 );
1636 }
1637
1638 if( poly.OutlineCount() > 0 )
1639 return poly.Outline( 0 );
1640 }
1641
1642 return SHAPE_LINE_CHAIN();
1643}
1644
1645
1646void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1647{
1648 if( !IsSelected() && !IsNew() )
1649 return;
1650
1651 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1652
1653 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1654 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1655
1656 if( !HasFlag( IN_EDIT ) )
1657 {
1658 if( m_baseLine )
1659 {
1660 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1661 {
1662 SEG seg = m_baseLine->CSegment( i );
1663 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1664 }
1665 }
1666 else
1667 {
1668 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1669 }
1670
1672 {
1673 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1674 {
1675 SEG seg = m_baseLineCoupled->CSegment( i );
1676 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1677 }
1678 }
1679 }
1680
1682
1683 for( int i = 0; i < chain.SegmentCount(); i++ )
1684 {
1685 SEG seg = chain.Segment( i );
1686 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1687 }
1688}
1689
1690
1692{
1694
1695 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
1696 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
1697 props.set( "last_status", statusToString( m_tuningStatus ) );
1698 props.set( "is_time_domain", m_settings.m_isTimeDomain );
1699
1700 props.set( "end", m_end );
1701 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1702 props.set( "single_sided", m_settings.m_singleSided );
1703 props.set( "rounded", m_settings.m_cornerStyle == PNS::MEANDER_STYLE_ROUND );
1704
1705 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
1706 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
1707 props.set_iu( "min_spacing", m_settings.m_spacing );
1708 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
1709 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
1710 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
1711 props.set_iu( "target_delay_min", m_settings.m_targetLengthDelay.Min() );
1712 props.set_iu( "target_delay", m_settings.m_targetLengthDelay.Opt() );
1713 props.set_iu( "target_delay_max", m_settings.m_targetLengthDelay.Max() );
1714 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
1715 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
1716 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
1717 props.set_iu( "last_track_width", m_trackWidth );
1718 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
1719 props.set_iu( "last_tuning_length", m_tuningLength );
1720
1721 props.set( "last_netname", m_lastNetName );
1722 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
1723
1724 if( m_baseLine )
1725 props.set( "base_line", wxAny( *m_baseLine ) );
1726
1727 if( m_baseLineCoupled )
1728 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
1729
1730 return props;
1731}
1732
1733
1735{
1737
1738 wxString tuningMode;
1739 aProps.get_to( "tuning_mode", tuningMode );
1740 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
1741
1742 wxString side;
1743 aProps.get_to( "initial_side", side );
1744 m_settings.m_initialSide = sideFromString( side.utf8_string() );
1745
1746 wxString status;
1747 aProps.get_to( "last_status", status );
1748 m_tuningStatus = statusFromString( status.utf8_string() );
1749
1750 aProps.get_to( "is_time_domain", m_settings.m_isTimeDomain );
1751
1752 aProps.get_to( "end", m_end );
1753 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1754 aProps.get_to( "single_sided", m_settings.m_singleSided );
1755 aProps.get_to( "side", m_settings.m_initialSide );
1756
1757 bool rounded = false;
1758 aProps.get_to( "rounded", rounded );
1760
1761 long long int val;
1762
1763 aProps.get_to_iu( "target_length", val );
1764 m_settings.SetTargetLength( val );
1765
1766 if( aProps.get_to_iu( "target_length_min", val ) )
1767 m_settings.m_targetLength.SetMin( val );
1768
1769 if( aProps.get_to_iu( "target_length_max", val ) )
1770 m_settings.m_targetLength.SetMax( val );
1771
1772 aProps.get_to_iu( "target_delay", val );
1773 m_settings.SetTargetLengthDelay( val );
1774
1775 if( aProps.get_to_iu( "target_delay_min", val ) )
1776 m_settings.m_targetLengthDelay.SetMin( val );
1777
1778 if( aProps.get_to_iu( "target_delay_max", val ) )
1779 m_settings.m_targetLengthDelay.SetMax( val );
1780
1781 int int_val;
1782
1783 aProps.get_to_iu( "target_skew", int_val );
1784 m_settings.SetTargetSkew( int_val );
1785
1786 if( aProps.get_to_iu( "target_skew_min", int_val ) )
1787 m_settings.m_targetSkew.SetMin( int_val );
1788
1789 if( aProps.get_to_iu( "target_skew_max", int_val ) )
1790 m_settings.m_targetSkew.SetMax( int_val );
1791
1792 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
1793 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
1794 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
1795 aProps.get_to_iu( "last_track_width", m_trackWidth );
1796 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
1797 aProps.get_to_iu( "last_tuning_length", m_tuningLength );
1798 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
1799
1800 aProps.get_to( "last_netname", m_lastNetName );
1801
1802 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
1803 m_baseLine = *baseLine;
1804
1805 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
1806 m_baseLineCoupled = *baseLineCoupled;
1807
1808 // Reconstruct m_tuningInfo from loaded length and status
1809 if( m_tuningLength != 0 )
1810 {
1811 wxString statusMessage;
1812
1813 switch( m_tuningStatus )
1814 {
1815 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1816 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1817 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1818 default: statusMessage = _( "unknown" ); break;
1819 }
1820
1821 EDA_UNITS units = m_settings.m_isTimeDomain ? EDA_UNITS::PS : EDA_UNITS::MM;
1822 wxString lengthStr = EDA_UNIT_UTILS::UI::MessageTextFromValue( pcbIUScale, units,
1823 (double) m_tuningLength );
1824
1825 m_tuningInfo.Printf( wxS( "%s (%s)" ), lengthStr, statusMessage );
1826 }
1827}
1828
1829
1831{
1833 DRC_CONSTRAINT constraint;
1834
1835 if( !m_items.empty() )
1836 {
1837 BOARD_ITEM* startItem = static_cast<BOARD_ITEM*>( *m_items.begin() );
1838 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1839
1841 {
1842 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, startItem, nullptr, GetLayer() );
1843
1844 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
1845 {
1847 {
1848 settings.SetTargetLengthDelay( constraint.GetValue() );
1849 settings.SetTargetLength( MINOPTMAX<int>() );
1850 settings.m_isTimeDomain = true;
1851 }
1852 else
1853 {
1855 settings.SetTargetLength( constraint.GetValue() );
1856 settings.m_isTimeDomain = false;
1857 }
1858 }
1859 }
1860 else
1861 {
1862 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
1863
1864 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
1865 {
1867 {
1868 settings.SetTargetLengthDelay( constraint.GetValue() );
1869 settings.SetTargetLength( MINOPTMAX<int>() );
1870 settings.m_isTimeDomain = true;
1871 }
1872 else
1873 {
1875 settings.SetTargetLength( constraint.GetValue() );
1876 settings.m_isTimeDomain = false;
1877 }
1878 }
1879 }
1880 }
1881
1882 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
1883
1884 if( dlg.ShowModal() == wxID_OK )
1885 {
1886 BOARD_COMMIT commit( aEditFrame );
1887 commit.Modify( this );
1888 m_settings = settings;
1889
1890 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
1891 EditStart( generatorTool, GetBoard(), &commit );
1892 Update( generatorTool, GetBoard(), &commit );
1893 EditFinish( generatorTool, GetBoard(), &commit );
1894
1895 commit.Push( _( "Edit Tuning Pattern" ) );
1896 }
1897}
1898
1899
1901 PCB_BASE_EDIT_FRAME* aFrame,
1902 bool aStatusItemsOnly )
1903{
1904 std::vector<EDA_ITEM*> previewItems;
1905 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
1906
1907 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
1908 {
1909 if( !aStatusItemsOnly )
1910 {
1911 PNS::ITEM_SET items = placer->TunedPath();
1912
1913 for( PNS::ITEM* item : items )
1914 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item,
1915 aTool->Router()->GetInterface(),
1916 view, PNS_HOVER_ITEM ) );
1917 }
1918
1919 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
1920
1922 {
1923 if( m_settings.m_isTimeDomain )
1924 statusItem->SetMinMax( m_settings.m_targetSkewDelay.Min(), m_settings.m_targetSkewDelay.Max() );
1925 else
1926 statusItem->SetMinMax( m_settings.m_targetSkew.Min(), m_settings.m_targetSkew.Max() );
1927 }
1928 else
1929 {
1930 if( m_settings.m_isTimeDomain )
1931 {
1932 if( m_settings.m_targetLengthDelay.Opt() == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED )
1933 {
1934 statusItem->ClearMinMax();
1935 }
1936 else
1937 {
1938 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLengthDelay.Min() ),
1939 static_cast<double>( m_settings.m_targetLengthDelay.Max() ) );
1940 }
1941 }
1942 else
1943 {
1944 if( m_settings.m_targetLength.Opt() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
1945 {
1946 statusItem->ClearMinMax();
1947 }
1948 else
1949 {
1950 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLength.Min() ),
1951 static_cast<double>( m_settings.m_targetLength.Max() ) );
1952 }
1953 }
1954 }
1955
1956 statusItem->SetIsTimeDomain( m_settings.m_isTimeDomain );
1957
1959 {
1960 if( m_settings.m_isTimeDomain )
1961 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current skew" ) );
1962 else
1963 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current skew" ) );
1964 }
1965 else
1966 {
1967 if( m_settings.m_isTimeDomain )
1968 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current delay" ) );
1969 else
1970 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current length" ) );
1971 }
1972
1973 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
1974 previewItems.push_back( statusItem );
1975 }
1976
1977 return previewItems;
1978}
1979
1980
1982 std::vector<MSG_PANEL_ITEM>& aList )
1983{
1984 wxString msg;
1985 NETINFO_ITEM* primaryNet = nullptr;
1986 NETINFO_ITEM* coupledNet = nullptr;
1987 PCB_TRACK* primaryItem = nullptr;
1988 PCB_TRACK* coupledItem = nullptr;
1989 NETCLASS* netclass = nullptr;
1990 int width = 0;
1991 bool mixedWidth = false;
1992
1994
1995 aList.emplace_back( _( "Type" ), GetFriendlyName() );
1996
1997 for( EDA_ITEM* member : GetItems() )
1998 {
1999 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
2000 {
2001 if( !primaryNet )
2002 {
2003 primaryItem = track;
2004 primaryNet = track->GetNet();
2005 }
2006 else if( !coupledNet && track->GetNet() != primaryNet )
2007 {
2008 coupledItem = track;
2009 coupledNet = track->GetNet();
2010 }
2011
2012 if( !netclass )
2013 netclass = track->GetEffectiveNetClass();
2014
2015 if( !width )
2016 width = track->GetWidth();
2017 else if( width != track->GetWidth() )
2018 mixedWidth = true;
2019 }
2020 }
2021
2022 if( coupledNet )
2023 {
2024 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2025 + wxS( ", " )
2026 + UnescapeString( coupledNet->GetNetname() ) );
2027 }
2028 else if( primaryNet )
2029 {
2030 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2031 }
2032
2033 if( netclass )
2034 aList.emplace_back( _( "Resolved Netclass" ),
2035 UnescapeString( netclass->GetHumanReadableName() ) );
2036
2037 aList.emplace_back( _( "Layer" ), LayerMaskDescribe() );
2038
2039 if( width && !mixedWidth )
2040 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2041
2042 BOARD* board = GetBoard();
2043 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2044 DRC_CONSTRAINT constraint;
2045
2046 // Display full track length (in Pcbnew)
2047 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2048 {
2049 int count = 0;
2050 double trackLen = 0.0;
2051 double lenPadToDie = 0.0;
2052 double trackDelay = 0.0;
2053 double delayPadToDie = 0.0;
2054
2055 std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *primaryItem );
2056
2057 if( coupledItem && coupledItem->GetNetCode() > 0 )
2058 {
2059 double coupledLen = 0.0;
2060 double coupledLenPadToDie = 0.0;
2061 double coupledTrackDelay = 0.0;
2062 double doubledDelayPadToDie = 0.0;
2063
2064 std::tie( count, coupledLen, coupledLenPadToDie, coupledTrackDelay, doubledDelayPadToDie ) =
2065 board->GetTrackLength( *coupledItem );
2066
2067 if( trackDelay == 0.0 || coupledTrackDelay == 0.0 )
2068 {
2069 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen ) + wxS( ", " )
2070 + aFrame->MessageTextFromValue( coupledLen ) );
2071 }
2072 else
2073 {
2074 aList.emplace_back(
2075 _( "Routed Delays" ),
2076 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) + wxS( ", " )
2077 + aFrame->MessageTextFromValue( coupledTrackDelay, true, EDA_DATA_TYPE::TIME ) );
2078 }
2079 }
2080 else
2081 {
2082 if( trackDelay == 0.0 )
2083 {
2084 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2085 }
2086 else
2087 {
2088 aList.emplace_back( _( "Routed Delay" ),
2089 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) );
2090 }
2091 }
2092
2093 if( lenPadToDie != 0 && delayPadToDie == 0.0 )
2094 {
2095 msg = aFrame->MessageTextFromValue( lenPadToDie );
2096 aList.emplace_back( _( "Pad To Die Length" ), msg );
2097
2098 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2099 aList.emplace_back( _( "Full Length" ), msg );
2100 }
2101 else if( delayPadToDie > 0.0 )
2102 {
2103 msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME );
2104 aList.emplace_back( _( "Pad To Die Delay" ), msg );
2105
2106 msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME );
2107 aList.emplace_back( _( "Full Delay" ), msg );
2108 }
2109 }
2110
2112 {
2113 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2114
2115 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2116 {
2117 msg = aFrame->MessageTextFromValue( m_settings.m_targetSkew.Opt() );
2118
2119 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2120 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2121 }
2122 else
2123 {
2124 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2125
2126 if( !msg.IsEmpty() )
2127 {
2128 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2129 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2130 }
2131 }
2132 }
2133 else
2134 {
2135 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2136
2137 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2138 {
2139 wxString caption;
2140
2141 if( m_settings.m_isTimeDomain )
2142 {
2143 caption = _( "Target Delay: %s" );
2144 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLengthDelay.Opt() ), true,
2146 }
2147 else
2148 {
2149 caption = _( "Target Length: %s" );
2150 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLength.Opt() ) );
2151 }
2152
2153 aList.emplace_back( wxString::Format( caption, msg ),
2154 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2155 }
2156 else
2157 {
2158 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue(), unitType );
2159
2160 wxString caption = m_settings.m_isTimeDomain ? _( "Delay Constraints: %s" ) : _( "Length Constraints: %s" );
2161
2162 if( !msg.IsEmpty() )
2163 {
2164 aList.emplace_back( wxString::Format( caption, msg ),
2165 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2166 }
2167 }
2168 }
2169}
2170
2171
2172const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2173const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2174
2175
2177
2178
2179#define HITTEST_THRESHOLD_PIXELS 5
2180
2181
2183{
2185 return 0;
2186
2187 if( m_inDrawingTool )
2188 return 0;
2189
2191
2192 m_toolMgr->RunAction( ACTIONS::selectionClear );
2193
2194 m_frame->PushTool( aEvent );
2195 Activate();
2196
2197 BOARD* board = m_frame->GetBoard();
2198 BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
2199 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
2200 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2201 PNS::ROUTER* router = generatorTool->Router();
2202 PNS::ROUTER_MODE routerMode = aEvent.Parameter<PNS::ROUTER_MODE>();
2203 LENGTH_TUNING_MODE mode = fromPNSMode( routerMode );
2204 PNS::MEANDER_SETTINGS meanderSettings;
2205
2206 switch( mode )
2207 {
2208 case LENGTH_TUNING_MODE::SINGLE: meanderSettings = bds.m_SingleTrackMeanderSettings; break;
2209 case DIFF_PAIR: meanderSettings = bds.m_DiffPairMeanderSettings; break;
2210 case DIFF_PAIR_SKEW: meanderSettings = bds.m_SkewMeanderSettings; break;
2211 }
2212
2214 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2215 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
2216 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2217
2218 m_pickerItem = nullptr;
2219 m_tuningPattern = nullptr;
2220
2221 // Add a VIEW_GROUP that serves as a preview for the new item
2222 m_preview.Clear();
2223 m_view->Add( &m_preview );
2224
2225 auto applyCommonSettings =
2226 [&]( PCB_TUNING_PATTERN* aPattern )
2227 {
2228 const auto& origTargetLength = aPattern->GetSettings().m_targetLength;
2229 const auto& origTargetSkew = aPattern->GetSettings().m_targetSkew;
2230
2231 aPattern->GetSettings() = meanderSettings;
2232
2233 if( meanderSettings.m_targetLength.IsNull() )
2234 aPattern->GetSettings().m_targetLength = origTargetLength;
2235
2236 if( meanderSettings.m_targetSkew.IsNull() )
2237 aPattern->GetSettings().m_targetSkew = origTargetSkew;
2238 };
2239
2240 auto updateHoverStatus =
2241 [&]()
2242 {
2243 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2244
2245 if( m_pickerItem )
2246 {
2247 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2248 m_pickerItem, mode ) );
2249 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2250 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2251 }
2252
2253 if( dummyPattern )
2254 {
2255 applyCommonSettings( dummyPattern.get() );
2256
2257 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2258 dummyPattern->Update( generatorTool, m_board, nullptr );
2259
2260 m_preview.FreeItems();
2261
2262 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2263 m_preview.Add( item );
2264
2265 generatorTool->Router()->StopRouting();
2266
2267 m_view->Update( &m_preview );
2268 }
2269 else
2270 {
2271
2272 m_preview.FreeItems();
2273 m_view->Update( &m_preview );
2274 }
2275 };
2276
2277 auto updateTuningPattern =
2278 [&]()
2279 {
2280 if( m_tuningPattern && m_tuningPattern->GetPosition() != m_tuningPattern->GetEnd() )
2281 {
2282 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2283 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2284
2285 m_preview.FreeItems();
2286
2287 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame, true ) )
2288 m_preview.Add( item );
2289
2290 m_view->Update( &m_preview );
2291 }
2292 };
2293
2294 while( TOOL_EVENT* evt = Wait() )
2295 {
2296 VECTOR2D cursorPos = controls->GetMousePosition();
2297
2298 if( evt->IsCancelInteractive() || evt->IsActivate()
2299 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2300 {
2301 if( m_tuningPattern )
2302 {
2303 // First click already made; clean up tuning pattern preview
2304 m_tuningPattern->EditCancel( generatorTool, m_board, nullptr );
2305
2306 delete m_tuningPattern;
2307 m_tuningPattern = nullptr;
2308 }
2309 else
2310 {
2311 break;
2312 }
2313 }
2314 else if( evt->IsMotion() )
2315 {
2316 if( !m_tuningPattern )
2317 {
2318 // First click not yet made; we're in highlight-net-under-cursor mode
2319
2320 GENERAL_COLLECTOR collector;
2321 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2322
2323 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2324 guide.SetIncludeSecondary( false );
2325 else
2326 guide.SetIncludeSecondary( true );
2327
2328 guide.SetPreferredLayer( m_frame->GetActiveLayer() );
2329
2330 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2331
2332 if( collector.GetCount() > 1 )
2333 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2334
2335 m_pickerItem = nullptr;
2336
2337 if( collector.GetCount() > 0 )
2338 {
2339 double min_dist_sq = std::numeric_limits<double>::max();
2340
2341 for( EDA_ITEM* candidate : collector )
2342 {
2343 VECTOR2I candidatePos;
2344
2345 if( candidate->Type() == PCB_TRACE_T )
2346 {
2347 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2348 }
2349 else if( candidate->Type() == PCB_ARC_T )
2350 {
2351 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2352 }
2353
2354 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2355
2356 if( dist_sq < min_dist_sq )
2357 {
2358 min_dist_sq = dist_sq;
2359 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2360 }
2361 }
2362 }
2363
2364 updateHoverStatus();
2365 }
2366 else
2367 {
2368 // First click already made; we're in preview-tuning-pattern mode
2369
2370 m_tuningPattern->SetEnd( cursorPos );
2371 m_tuningPattern->UpdateSideFromEnd();
2372
2373 updateTuningPattern();
2374 }
2375 }
2376 else if( evt->IsClick( BUT_LEFT ) )
2377 {
2379 {
2380 // First click; create a tuning pattern
2381
2382 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2383 {
2384 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2385 "tuning patterns." ) );
2386 }
2387 else
2388 {
2389 m_preview.FreeItems();
2390
2391 m_frame->SetActiveLayer( m_pickerItem->GetLayer() );
2393 m_pickerItem, mode );
2394
2395 applyCommonSettings( m_tuningPattern );
2396
2397 int dummyDist;
2398 int dummyClearance = std::numeric_limits<int>::max() / 2;
2399 VECTOR2I closestPt;
2400
2401 // With an artificially-large clearance this can't *not* collide, but the
2402 // if stmt keeps Coverity happy....
2403 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2404 &dummyDist, &closestPt ) )
2405 {
2406 m_tuningPattern->SetPosition( closestPt );
2407 m_tuningPattern->SetEnd( closestPt );
2408 }
2409
2410 m_preview.Add( m_tuningPattern->Clone() );
2411 }
2412 }
2413 else if( m_pickerItem && m_tuningPattern )
2414 {
2415 // Second click; we're done
2416 BOARD_COMMIT commit( m_frame );
2417
2418 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2419 m_tuningPattern->Update( generatorTool, m_board, &commit );
2420 m_tuningPattern->EditFinish( generatorTool, m_board, &commit );
2421
2422 commit.Push( _( "Tune" ) );
2423
2424 m_tuningPattern = nullptr;
2425 m_pickerItem = nullptr;
2426 }
2427 }
2428 else if( evt->IsClick( BUT_RIGHT ) )
2429 {
2431 m_menu->ShowContextMenu( dummy );
2432 }
2433 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2434 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2435 {
2436 if( m_tuningPattern )
2437 {
2438 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2439
2440 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2441 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2442 meanderSettings.m_spacing = placer->MeanderSettings().m_spacing;
2443
2444 updateTuningPattern();
2445 }
2446 else
2447 {
2448 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2449 }
2450 }
2451 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2452 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2453 {
2454 if( m_tuningPattern )
2455 {
2456 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2457
2458 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2459 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2460 meanderSettings.m_maxAmplitude = placer->MeanderSettings().m_maxAmplitude;
2461
2462 updateTuningPattern();
2463 }
2464 else
2465 {
2466 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2467 }
2468 }
2469 else if( evt->IsAction( &PCB_ACTIONS::properties )
2470 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2471 {
2472 DRC_CONSTRAINT constraint;
2473
2474 if( m_tuningPattern )
2475 {
2476 if( !m_tuningPattern->GetItems().empty() )
2477 {
2478 BOARD_ITEM* startItem = *m_tuningPattern->GetBoardItems().begin();
2479
2480 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2481 startItem->GetLayer() );
2482 }
2483 }
2484
2485 DIALOG_TUNING_PATTERN_PROPERTIES dlg( m_frame, meanderSettings, routerMode, constraint );
2486
2487 if( dlg.ShowModal() == wxID_OK )
2488 {
2489 if( m_tuningPattern )
2490 applyCommonSettings( m_tuningPattern );
2491
2492 updateTuningPattern();
2493 }
2494 }
2495 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2496 // but we don't at present have that, so we just knock out some of the egregious ones.
2497 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2498 {
2499 wxBell();
2500 }
2501 else
2502 {
2503 evt->SetPassEvent();
2504 }
2505
2506 controls->CaptureCursor( m_tuningPattern != nullptr );
2507 controls->SetAutoPan( m_tuningPattern != nullptr );
2508 }
2509
2510 controls->CaptureCursor( false );
2511 controls->SetAutoPan( false );
2512 controls->ForceCursorPosition( false );
2513 controls->ShowCursor( false );
2514 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2515
2516 m_preview.FreeItems();
2517 m_view->Remove( &m_preview );
2518
2519 m_frame->GetCanvas()->Refresh();
2520
2521 if( m_tuningPattern )
2522 selectionTool->AddItemToSel( m_tuningPattern );
2523
2524 m_frame->PopTool( aEvent );
2525 return 0;
2526}
2527
2528
2530{
2532 {
2534 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2535 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2536 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2537
2539 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2540 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2541 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2542
2549
2551
2552 if( layerEnum.Choices().GetCount() == 0 )
2553 {
2554 layerEnum.Undefined( UNDEFINED_LAYER );
2555
2556 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
2557 layerEnum.Map( layer, LSET::Name( layer ) );
2558 }
2559
2562 layer->SetChoices( layerEnum.Choices() );
2563 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
2564
2565 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Width" ),
2568
2571
2572 const wxString groupTechLayers = _HKI( "Technical Layers" );
2573
2574 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Soldermask" ),
2576 groupTechLayers );
2577
2578 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
2582 groupTechLayers );
2583
2584 const wxString groupTab = _HKI( "Pattern Properties" );
2585
2586 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "End X" ),
2589 groupTab );
2590
2591 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "End Y" ),
2594 groupTab );
2595
2599 groupTab );
2600
2601 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Min Amplitude" ),
2604 groupTab );
2605
2606 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Max Amplitude" ),
2609 groupTab );
2610
2613 groupTab );
2614
2615 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Min Spacing" ),
2618 groupTab );
2619
2620 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Corner Radius %" ),
2624 groupTab );
2625
2626 auto isSkew =
2627 []( INSPECTABLE* aItem ) -> bool
2628 {
2629 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2630 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2631
2632 return false;
2633 };
2634
2635 auto isTimeDomain = []( INSPECTABLE* aItem ) -> bool
2636 {
2637 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2638 return pattern->GetSettings().m_isTimeDomain;
2639
2640 return false;
2641 };
2642
2643 auto isLengthIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2644 {
2645 return !isSkew( aItem ) && !isTimeDomain( aItem );
2646 };
2647
2648 auto isLengthIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2649 {
2650 return !isSkew( aItem ) && isTimeDomain( aItem );
2651 };
2652
2653 auto isSkewIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2654 {
2655 return isSkew( aItem ) && !isTimeDomain( aItem );
2656 };
2657
2658 auto isSkewIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2659 {
2660 return isSkew( aItem ) && isTimeDomain( aItem );
2661 };
2662
2663 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>( _HKI( "Target Length" ),
2666 groupTab )
2667 .SetAvailableFunc( isLengthIsSpaceDomain );
2668
2669 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>( _HKI( "Target Delay" ),
2672 groupTab )
2673 .SetAvailableFunc( isLengthIsTimeDomain );
2674
2675 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Target Skew" ),
2678 groupTab )
2679 .SetAvailableFunc( isSkewIsSpaceDomain );
2680
2681 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Target Skew Delay" ),
2684 groupTab )
2685 .SetAvailableFunc( isSkewIsTimeDomain );
2686
2687 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Override Custom Rules" ),
2690 groupTab );
2691
2692 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Single-sided" ),
2694 groupTab );
2695
2696 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Rounded" ),
2698 groupTab );
2699 }
2701
2704
2706
2707// Also register under the 7.99 name
2708template <typename T>
2710{
2712 {
2713 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2714 []()
2715 {
2716 return new T;
2717 } );
2718 }
2719};
2720
int red
int green
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
constexpr int ARC_LOW_DEF
Definition base_units.h:128
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
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:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:237
PCB_LAYER_ID m_layer
Definition board_item.h:459
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
virtual wxString LayerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition board.cpp:2442
std::tuple< int, double, double, 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:2915
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2375
const TRACKS & Tracks() const
Definition board.h:361
PROJECT * GetProject() const
Definition board.h:579
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1083
constexpr void SetMaximum()
Definition box2.h:80
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
int m_Threshold
Definition collector.h:236
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:90
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
int ShowModal() override
PCB_SELECTION m_preview
KIGFX::VIEW * m_view
BOARD_CONNECTED_ITEM * m_pickerItem
int PlaceTuningPattern(const TOOL_EVENT &aEvent)
BOARD * m_board
PCB_BASE_EDIT_FRAME * m_frame
PCB_TUNING_PATTERN * m_tuningPattern
wxString GetName() const
Definition drc_rule.h:195
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:187
bool GetOption(OPTIONS option) const
Definition drc_rule.h:220
bool IsNull() const
Definition drc_rule.h:182
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
The base class for create windows for drawing purpose.
wxString m_name
Definition eda_group.h:77
std::unordered_set< EDA_ITEM * > m_items
Definition eda_group.h:76
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:54
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition eda_group.cpp:27
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:99
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:148
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:150
bool IsSelected() const
Definition eda_item.h:128
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:152
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:151
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:41
bool IsNew() const
Definition eda_item.h:125
EDIT_POINTS is a VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them.
void AddPoint(const EDIT_POINT &aPoint)
Add an EDIT_POINT.
EDIT_POINT & Point(unsigned int aIndex)
void SetGridConstraint(GRID_CONSTRAINT_TYPE aConstraint)
bool IsActive() const
static const int POINT_SIZE
Single point size in pixels.
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition edit_points.h:72
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:727
static ENUM_MAP< T > & Instance()
Definition property.h:721
ENUM_MAP & Undefined(T aValue)
Definition property.h:734
wxPGChoices & Choices()
Definition property.h:770
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:352
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:324
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
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.
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:38
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:98
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:147
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
Draw a string.
Definition font.cpp:250
static const METRICS & Default()
Definition font.cpp:52
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:312
void ToHSL(double &aOutHue, double &aOutSaturation, double &aOutLightness) const
Converts current color (stored in RGB) to HSL format.
Definition color4d.cpp:313
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...
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,...
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:203
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition view.cpp:473
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1675
static const LSET & AllLayersMask()
Definition lset.cpp:641
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition matrix3x3.h:295
bool IsNull() const
Definition minoptmax.h:45
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:294
wxString GetTuningProfile() const
Definition netclass.h:246
bool HasTuningProfile() const
Definition netclass.h:244
Handle the data for a net.
Definition netinfo.h:54
const wxString & GetNetname() const
Definition netinfo.h:112
static TOOL_ACTION properties
Activation of the edit tool.
static TOOL_ACTION spacingDecrease
static TOOL_ACTION amplIncrease
static TOOL_ACTION amplDecrease
static TOOL_ACTION lengthTunerSettings
static TOOL_ACTION spacingIncrease
const VECTOR2I & GetMid() const
Definition pcb_track.h:290
Common, abstract interface for edit frames.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
virtual void SetProperties(const STRING_ANY_MAP &aProps)
wxString m_generatorType
PCB_GENERATOR(BOARD_ITEM *aParent, PCB_LAYER_ID aLayer)
VECTOR2I m_origin
virtual const STRING_ANY_MAP GetProperties() const
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
const VECTOR2I & GetStart() const
Definition pcb_track.h:97
const VECTOR2I & GetEnd() const
Definition pcb_track.h:94
virtual int GetWidth() const
Definition pcb_track.h:91
void SetTargetSkew(int aValue)
bool initBaseLines(PNS::ROUTER *aRouter, int aPNSLayer, BOARD *aBoard)
const STRING_ANY_MAP GetProperties() const override
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
void SetMinAmplitude(int aValue)
void SetSpacing(int aValue)
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)
void SetTargetSkewDelay(int aValue)
PCB_TUNING_PATTERN(BOARD_ITEM *aParent=nullptr, PCB_LAYER_ID aLayer=F_Cu, LENGTH_TUNING_MODE aMode=LENGTH_TUNING_MODE::SINGLE)
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
bool recoverBaseline(PNS::ROUTER *aRouter)
void SetWidth(int aValue)
PNS::MEANDER_SIDE GetInitialSide() const
std::optional< int > GetLocalSolderMaskMargin() const
void SetInitialSide(PNS::MEANDER_SIDE aValue)
wxString GetFriendlyName() const override
void SetTargetDelay(std::optional< int > aValue)
LENGTH_TUNING_MODE GetTuningMode() const
void SetHasSolderMask(bool aVal)
std::optional< int > GetTargetDelay() const
std::vector< EDA_ITEM * > GetPreviewItems(GENERATOR_TOOL *aTool, PCB_BASE_EDIT_FRAME *aFrame, bool aStatusItemsOnly=false) override
void EditStart(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
void SetOverrideCustomRules(bool aOverride)
void SetRounded(bool aFlag)
LENGTH_TUNING_MODE m_tuningMode
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
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
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
bool Update(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
void SetNetCode(int aNetCode)
bool UpdateEditPoints(EDIT_POINTS &aEditPoints) override
void EditCancel(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool GetOverrideCustomRules() const
void SetMaxAmplitude(int aValue)
PNS::MEANDER_SETTINGS & GetSettings()
void SetSingleSided(bool aValue)
bool removeToBaseline(PNS::ROUTER *aRouter, int aPNSLayer, SHAPE_LINE_CHAIN &aBaseLine)
std::optional< int > GetTargetLength() const
void EditFinish(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
int GetCornerRadiusPercentage() const
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:210
void SetNet(NET_HANDLE aNet)
Definition pns_item.h:209
void SetLayer(int aLayer)
Definition pns_item.h:215
void SetParent(BOARD_ITEM *aParent)
Definition pns_item.h:191
bool OfKind(int aKindMask) const
Definition pns_item.h:181
virtual VECTOR2I Anchor(int n) const
Definition pns_item.h:268
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:142
SHAPE_LINE_CHAIN & Line()
Definition pns_line.h:141
void SetWidth(int aWidth)
Return line width.
Definition pns_line.h:155
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 void AmplitudeStep(int aSign)
Increase/decreases the current meandering amplitude by one step.
virtual long long int TuningLengthResult() const =0
Return the resultant length or skew of the tuned traces.
Dimensions for the meandering algorithm.
Definition pns_meander.h:70
void SetTargetLength(long long int aOpt)
bool m_isTimeDomain
The net class this meander pattern belongs to.
static const long long int LENGTH_UNCONSTRAINED
Definition pns_meander.h:73
void SetTargetLengthDelay(long long int aOpt)
MINOPTMAX< long long int > m_targetLength
Desired propagation delay of the tuned line.
void SetTargetSkew(int aOpt)
MINOPTMAX< int > m_targetSkew
Target skew value for diff pair de-skewing.
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition pns_meander.h:98
bool m_overrideCustomRules
Type of corners for the meandered line.
void SetTargetSkewDelay(int aOpt)
static const long long int DELAY_UNCONSTRAINED
Definition pns_meander.h:76
int m_spacing
Amplitude/spacing adjustment step.
Keep the router "world" - i.e.
Definition pns_node.h:240
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:157
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition pns_node.cpp:749
std::set< OBSTACLE > OBSTACLES
Definition pns_node.h:252
const LINE AssembleLine(LINKED_ITEM *aSeg, int *aOriginSegmentIndex=nullptr, bool aStopAtLockedJoints=false, bool aFollowLockedSegments=false, bool aAllowSegmentSizeMismatch=true)
Follow the joint map to assemble a line connecting two non-trivial joints starting from segment aSeg.
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:269
void Remove(ARC *aArc)
Remove an item from this branch.
Definition pns_node.cpp:993
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()
PLACEMENT_ALGO * Placer()
Definition pns_router.h:234
ROUTER_IFACE * GetInterface() const
Definition pns_router.h:236
void CommitRouting()
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, int aSlopRadius=0)
void SyncWorld()
RULE_RESOLVER * GetRuleResolver() const
Definition pns_router.h:198
bool RoutingInProgress() const
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
SIZES_SETTINGS & Sizes()
Definition pns_router.h:229
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
NODE * GetWorld() const
Definition pns_router.h:182
bool Move(const VECTOR2I &aP, ITEM *aItem)
virtual int Clearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
const SHAPE_LINE_CHAIN CLine() const
Definition pns_segment.h:98
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_segment.h:78
void SetShape(SHAPE *shape)
Definition pns_solid.h:113
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
std::shared_ptr< TUNING_PROFILES > & TuningProfileParameters()
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:203
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & ReplaceProperty(PROPERTY_BASE *aProperty, const wxString &aGroup)
Replace an existing 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:746
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:633
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)
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:120
VECTOR2I NearestPoint(const VECTOR2I &aP) const
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 aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
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.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
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.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
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
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
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:171
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
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.
VECTOR2D GetMousePosition() const
APP_SETTINGS_BASE * GetSettings() const
KIGFX::VIEW * GetView() const
void SetIsTimeDomain(const bool aIsTimeDomain)
void SetCurrent(const double aCurrent, const wxString &aLabel)
wxString GetClass() const override
Return the class name.
VECTOR2I GetPosition() const override
void SetMinMax(const double aMin, const double aMax)
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
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 MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString MessageTextFromMinOptMax(const MINOPTMAX< int > &aValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
PCB_TUNING_PATTERN * m_pattern
UNLOCKER(PCB_TUNING_PATTERN *aPattern)
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
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
@ ROUND_ALL_CORNERS
All angles are rounded.
@ ARROW
Definition cursors.h:46
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ SKEW_CONSTRAINT
Definition drc_rule.h:72
#define _(s)
#define IS_NEW
New item, just created.
#define IN_EDIT
Item currently edited.
EDA_DATA_TYPE
The type of unit.
Definition eda_units.h:38
EDA_UNITS
Definition eda_units.h:48
@ IGNORE_GRID
static FILENAME_RESOLVER * resolver
a few functions useful in geometry calculations.
@ LAYER_UI_START
Definition layer_ids.h:357
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
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.
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:60
@ MEANDER_SIDE_RIGHT
Definition pns_meander.h:63
@ MEANDER_SIDE_DEFAULT
Definition pns_meander.h:62
@ MEANDER_SIDE_LEFT
Definition pns_meander.h:61
@ MEANDER_STYLE_ROUND
Definition pns_meander.h:54
@ MEANDER_STYLE_CHAMFER
Definition pns_meander.h:55
ROUTER_MODE
Definition pns_router.h:67
@ PNS_MODE_TUNE_DIFF_PAIR
Definition pns_router.h:71
@ PNS_MODE_TUNE_SINGLE
Definition pns_router.h:70
@ PNS_MODE_TUNE_DIFF_PAIR_SKEW
Definition pns_router.h:72
#define _HKI(x)
Definition page_info.cpp:44
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)
static VECTOR2I snapToNearestTrack(const VECTOR2I &aP, BOARD *aBoard, NETINFO_ITEM *aNet, PCB_TRACK **aNearestTrack)
SCOPED_SET_RESET< DRAWING_TOOL::MODE > SCOPED_DRAW_MODE
static REGISTER_LEGACY_TUNING_PATTERN< PCB_TUNING_PATTERN > registerMeToo
LENGTH_TUNING_MODE
@ DIFF_PAIR
@ DIFF_PAIR_SKEW
#define TYPE_HASH(x)
Definition property.h:74
#define NO_SETTER(owner, type)
Definition property.h:828
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:823
@ PT_DEFAULT
Default property for a given type.
Definition property.h:62
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
@ PT_NET
Net selection property.
Definition property.h:70
@ PT_TIME
Time expressed in ps.
Definition property.h:69
#define REGISTER_TYPE(x)
constexpr double correction
const double epsilon
#define PNS_HOVER_ITEM
#define PNS_COLLISION
#define HITTEST_THRESHOLD_PIXELS
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition pns_node.h:73
bool m_IsTimeDomain
Definition pns_node.h:80
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:88
Represents a single line in the tuning profile configuration grid.
const SHAPE_LINE_CHAIN chain
VECTOR2I end
int clearance
wxString result
Test unit parsing edge cases and error handling.
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ BUT_LEFT
Definition tool_event.h:132
@ BUT_RIGHT
Definition tool_event.h:133
double DEG2RAD(double deg)
Definition trigo.h:166
@ 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
VECTOR2< double > VECTOR2D
Definition vector2d.h:694