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