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 ), 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;
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_tuningLength( 0 ),
355 m_tuningStatus( PNS::MEANDER_PLACER_BASE::TUNING_STATUS::TUNED ),
356 m_updateSideFromEnd( false )
357{
360 m_end = VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 );
361 m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
362}
363
364
365static VECTOR2I snapToNearestTrack( const VECTOR2I& aP, BOARD* aBoard, NETINFO_ITEM* aNet,
366 PCB_TRACK** aNearestTrack )
367{
369 VECTOR2I closestPt = aP;
370
371 for( PCB_TRACK *track : aBoard->Tracks() )
372 {
373 if( aNet && track->GetNet() != aNet )
374 continue;
375
376 VECTOR2I nearest;
377
378 if( track->Type() == PCB_ARC_T )
379 {
380 PCB_ARC* pcbArc = static_cast<PCB_ARC*>( track );
381 SHAPE_ARC arc( pcbArc->GetStart(), pcbArc->GetMid(), pcbArc->GetEnd(),
382 pcbArc->GetWidth() );
383
384 nearest = arc.NearestPoint( aP );
385 }
386 else
387 {
388 SEG seg( track->GetStart(), track->GetEnd() );
389 nearest = seg.NearestPoint( aP );
390 }
391
392 SEG::ecoord dist_sq = ( nearest - aP ).SquaredEuclideanNorm();
393
394 if( dist_sq < minDist_sq )
395 {
396 minDist_sq = dist_sq;
397 closestPt = nearest;
398
399 if( aNearestTrack )
400 *aNearestTrack = track;
401 }
402 }
403
404 return closestPt;
405}
406
407
409{
411 {
412 return( m_baseLine && m_baseLine->PointCount() > 1
413 && m_baseLineCoupled && m_baseLineCoupled->PointCount() > 1 );
414 }
415 else
416 {
417 return( m_baseLine && m_baseLine->PointCount() > 1 );
418 }
419}
420
421
423 PCB_BASE_EDIT_FRAME* aFrame,
424 BOARD_CONNECTED_ITEM* aStartItem,
425 LENGTH_TUNING_MODE aMode )
426{
427 BOARD* board = aStartItem->GetBoard();
429 DRC_CONSTRAINT constraint;
430 PCB_LAYER_ID layer = aStartItem->GetLayer();
431
432 PCB_TUNING_PATTERN* pattern = new PCB_TUNING_PATTERN( board, layer, aMode );
433
434 switch( aMode )
435 {
436 case SINGLE: pattern->m_settings = bds.m_SingleTrackMeanderSettings; break;
437 case DIFF_PAIR: pattern->m_settings = bds.m_DiffPairMeanderSettings; break;
438 case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break;
439 }
440
441 if( aMode == SINGLE || aMode == DIFF_PAIR )
442 {
443 constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer );
444
445 if( !constraint.IsNull() )
446 {
448 {
449 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
451 pattern->m_settings.m_isTimeDomain = true;
452 }
453 else
454 {
456 pattern->m_settings.SetTargetLength( constraint.GetValue() );
457 pattern->m_settings.m_isTimeDomain = false;
458 }
459 }
460 }
461 else
462 {
463 constraint = bds.m_DRCEngine->EvalRules( SKEW_CONSTRAINT, aStartItem, nullptr, layer );
464
465 if( !constraint.IsNull() )
466 {
468 {
470 pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() );
471 pattern->m_settings.m_isTimeDomain = true;
472 }
473 else
474 {
475 pattern->m_settings.SetTargetSkew( constraint.GetValue() );
477 pattern->m_settings.m_isTimeDomain = true;
478 }
479 }
480 }
481
482 pattern->SetFlags( IS_NEW );
483 pattern->m_settings.m_netClass = aStartItem->GetEffectiveNetClass();
484
485 return pattern;
486}
487
489{
490 if( aCommit )
491 {
492 if( IsNew() )
493 aCommit->Add( this );
494 else
495 aCommit->Modify( this );
496 }
497
498 SetFlags( IN_EDIT );
499
500 PNS::ROUTER* router = aTool->Router();
501 int layer = router->GetInterface()->GetPNSLayerFromBoardLayer( GetLayer() );
502
503 aTool->ClearRouterChanges();
504 router->SyncWorld();
505
507 PNS::CONSTRAINT constraint;
508
509 if( !baselineValid() )
510 initBaseLines( router, layer, aBoard );
511
513 {
514 VECTOR2I centerlineOffsetEnd;
515
517 && m_baseLineCoupled->SegmentCount() > 0 )
518 {
519 centerlineOffsetEnd =
520 ( m_baseLineCoupled->CLastPoint() - m_baseLine->CLastPoint() ) / 2;
521 }
522
523 SEG baseEnd = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( -1 )
524 : SEG( m_origin, m_end );
525
526 baseEnd.A += centerlineOffsetEnd;
527 baseEnd.B += centerlineOffsetEnd;
528
529 if( baseEnd.A != baseEnd.B )
530 {
531 int side = baseEnd.Side( m_end );
532
533 if( side < 0 )
534 m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
535 else
536 m_settings.m_initialSide = PNS::MEANDER_SIDE_RIGHT;
537 }
538
539 m_updateSideFromEnd = false;
540 }
541
542 PCB_TRACK* track = nullptr;
543 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
544 wxCHECK( track, /* void */ );
545
546 m_settings.m_netClass = track->GetEffectiveNetClass();
547
548 if( !m_settings.m_overrideCustomRules )
549 {
550 PNS::SEGMENT pnsItem;
551 NETINFO_ITEM* net = track->GetNet();
552
553 pnsItem.SetParent( track );
554 pnsItem.SetNet( net );
555
556 if( m_tuningMode == SINGLE )
557 {
558 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
559 &pnsItem, nullptr, layer, &constraint ) )
560 {
561 if( constraint.m_IsTimeDomain )
562 {
563 m_settings.SetTargetLengthDelay( constraint.m_Value );
564 m_settings.SetTargetLength( MINOPTMAX<int>() );
565 }
566 else
567 {
568 m_settings.SetTargetLengthDelay( MINOPTMAX<int>() );
569 m_settings.SetTargetLength( constraint.m_Value );
570 }
571
572 m_settings.m_isTimeDomain = constraint.m_IsTimeDomain;
574 }
575 }
576 else
577 {
578 PCB_TRACK* coupledTrack = nullptr;
579 PNS::SEGMENT pnsCoupledItem;
580 NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
581
582 if( coupledNet )
583 snapToNearestTrack( m_origin, aBoard, coupledNet, &coupledTrack );
584
585 pnsCoupledItem.SetParent( coupledTrack );
586 pnsCoupledItem.SetNet( coupledNet );
587
588 if( m_tuningMode == DIFF_PAIR )
589 {
590 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH,
591 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
592 {
593 if( constraint.m_IsTimeDomain )
594 {
595 m_settings.SetTargetLengthDelay( constraint.m_Value );
596 m_settings.SetTargetLength( MINOPTMAX<int>() );
597 }
598 else
599 {
600 m_settings.SetTargetLengthDelay( MINOPTMAX<int>() );
601 m_settings.SetTargetLength( constraint.m_Value );
602 }
603
604 m_settings.m_isTimeDomain = constraint.m_IsTimeDomain;
606 }
607 }
608 else
609 {
611 &pnsItem, &pnsCoupledItem, layer, &constraint ) )
612 {
613 if( constraint.m_IsTimeDomain )
614 {
615 m_settings.SetTargetSkewDelay( constraint.m_Value );
616 m_settings.SetTargetSkew( MINOPTMAX<int>() );
617 }
618 else
619 {
620 m_settings.SetTargetSkewDelay( MINOPTMAX<int>() );
621 m_settings.SetTargetSkew( constraint.m_Value );
622 }
623
624 m_settings.m_isTimeDomain = constraint.m_IsTimeDomain;
626 }
627 }
628 }
629 }
630}
631
632
633static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhere, int aLayer,
634 VECTOR2I& aPointOut,
635 const SHAPE_LINE_CHAIN& aBaseline = SHAPE_LINE_CHAIN() )
636{
637 int maxSlopRadius = aRouter->Sizes().Clearance() + aRouter->Sizes().TrackWidth() / 2;
638
639 static const int candidateCount = 2;
640 PNS::LINKED_ITEM* prioritized[candidateCount];
641 SEG::ecoord dist[candidateCount];
642 SEG::ecoord distBaseline[candidateCount];
643 VECTOR2I point[candidateCount];
644
645 for( int i = 0; i < candidateCount; i++ )
646 {
647 prioritized[i] = nullptr;
648 dist[i] = VECTOR2I::ECOORD_MAX;
649 distBaseline[i] = VECTOR2I::ECOORD_MAX;
650 }
651
652 for( int slopRadius : { 0, maxSlopRadius } )
653 {
654 PNS::ITEM_SET candidates = aRouter->QueryHoverItems( aWhere, slopRadius );
655
656 for( PNS::ITEM* item : candidates.Items() )
657 {
658 if( !item->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
659 continue;
660
661 if( !item->IsRoutable() )
662 continue;
663
664 if( !item->Layers().Overlaps( aLayer ) )
665 continue;
666
667 PNS::LINKED_ITEM* linked = static_cast<PNS::LINKED_ITEM*>( item );
668
669 if( item->Kind() & PNS::ITEM::ARC_T )
670 {
671 PNS::ARC* pnsArc = static_cast<PNS::ARC*>( item );
672
673 VECTOR2I nearest = pnsArc->Arc().NearestPoint( aWhere );
674 SEG::ecoord d0 = ( nearest - aWhere ).SquaredEuclideanNorm();
675
676 if( d0 > dist[1] )
677 continue;
678
679 if( aBaseline.PointCount() > 0 )
680 {
681 SEG::ecoord dcBaseline;
682 VECTOR2I target = pnsArc->Arc().GetArcMid();
683
684 if( aBaseline.SegmentCount() > 0 )
685 dcBaseline = aBaseline.SquaredDistance( target );
686 else
687 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
688
689 if( dcBaseline > distBaseline[1] )
690 continue;
691
692 distBaseline[1] = dcBaseline;
693 }
694
695 prioritized[1] = linked;
696 dist[1] = d0;
697 point[1] = nearest;
698 }
699 else if( item->Kind() & PNS::ITEM::SEGMENT_T )
700 {
701 PNS::SEGMENT* segm = static_cast<PNS::SEGMENT*>( item );
702
703 VECTOR2I nearest = segm->CLine().NearestPoint( aWhere, false );
704 SEG::ecoord dd = ( aWhere - nearest ).SquaredEuclideanNorm();
705
706 if( dd > dist[1] )
707 continue;
708
709 if( aBaseline.PointCount() > 0 )
710 {
711 SEG::ecoord dcBaseline;
712 VECTOR2I target = segm->Shape( -1 )->Centre();
713
714 if( aBaseline.SegmentCount() > 0 )
715 dcBaseline = aBaseline.SquaredDistance( target );
716 else
717 dcBaseline = ( aBaseline.CPoint( 0 ) - target ).SquaredEuclideanNorm();
718
719 if( dcBaseline > distBaseline[1] )
720 continue;
721
722 distBaseline[1] = dcBaseline;
723 }
724
725 prioritized[1] = segm;
726 dist[1] = dd;
727 point[1] = nearest;
728 }
729 }
730 }
731
732 PNS::LINKED_ITEM* rv = nullptr;
733
734 for( int i = 0; i < candidateCount; i++ )
735 {
736 PNS::LINKED_ITEM* item = prioritized[i];
737
738 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
739 {
740 rv = item;
741 aPointOut = point[i];
742 break;
743 }
744 }
745
746 return rv;
747}
748
749
750static std::optional<PNS::LINE> getPNSLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
751 PNS::ROUTER* router, int layer, VECTOR2I& aStartOut,
752 VECTOR2I& aEndOut )
753{
754 PNS::NODE* world = router->GetWorld();
755
756 PNS::LINKED_ITEM* startItem = pickSegment( router, aStart, layer, aStartOut );
757 PNS::LINKED_ITEM* endItem = pickSegment( router, aEnd, layer, aEndOut );
758
759 for( PNS::LINKED_ITEM* testItem : { startItem, endItem } )
760 {
761 if( !testItem )
762 continue;
763
764 PNS::LINE line = world->AssembleLine( testItem, nullptr, false, false );
765 SHAPE_LINE_CHAIN oldChain = line.CLine();
766
767 if( oldChain.PointOnEdge( aStartOut, 1 ) && oldChain.PointOnEdge( aEndOut, 1 ) )
768 return line;
769 }
770
771 return std::nullopt;
772}
773
774
775bool PCB_TUNING_PATTERN::initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard,
776 VECTOR2I& aStart, VECTOR2I& aEnd, NETINFO_ITEM* aNet,
777 std::optional<SHAPE_LINE_CHAIN>& aBaseLine )
778{
779 PNS::NODE* world = aRouter->GetWorld();
780
781 aStart = snapToNearestTrack( aStart, aBoard, aNet, nullptr );
782 aEnd = snapToNearestTrack( aEnd, aBoard, aNet, nullptr );
783
784 VECTOR2I startSnapPoint, endSnapPoint;
785
786 PNS::LINKED_ITEM* startItem = pickSegment( aRouter, aStart, aPNSLayer, startSnapPoint );
787 PNS::LINKED_ITEM* endItem = pickSegment( aRouter, aEnd, aPNSLayer, endSnapPoint );
788
789 wxASSERT( startItem );
790 wxASSERT( endItem );
791
792 if( !startItem || !endItem )
793 return false;
794
795 PNS::LINE line = world->AssembleLine( startItem );
796 const SHAPE_LINE_CHAIN& chain = line.CLine();
797
798 wxASSERT( line.ContainsLink( endItem ) );
799
800 wxASSERT( chain.PointOnEdge( startSnapPoint, 40000 ) );
801 wxASSERT( chain.PointOnEdge( endSnapPoint, 40000 ) );
802
805 SHAPE_LINE_CHAIN post;
806
807 chain.Split( startSnapPoint, endSnapPoint, pre, mid, post );
808
809 aBaseLine = mid;
810
811 return true;
812}
813
814
815bool PCB_TUNING_PATTERN::initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard )
816{
817 m_baseLineCoupled.reset();
818
819 PCB_TRACK* track = nullptr;
820
821 m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track );
822 wxCHECK( track, false );
823
824 NETINFO_ITEM* net = track->GetNet();
825
826 if( !initBaseLine( aRouter, aPNSLayer, aBoard, m_origin, m_end, net, m_baseLine ) )
827 return false;
828
829 // Generate both baselines even if we're skewing. We need the coupled baseline to run the
830 // DRC rules against.
832 {
833 if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
834 {
835 VECTOR2I coupledStart = snapToNearestTrack( m_origin, aBoard, coupledNet, nullptr );
836 VECTOR2I coupledEnd = snapToNearestTrack( m_end, aBoard, coupledNet, nullptr );
837
838 return initBaseLine( aRouter, aPNSLayer, aBoard, coupledStart, coupledEnd, coupledNet,
840 }
841
842 return false;
843 }
844
845 return true;
846}
847
848
850{
851public:
853 m_pattern( aPattern ),
854 m_wasLocked( aPattern->IsLocked() )
855 {
856 m_pattern->SetLocked( false );
857 }
858
860 {
861 if( m_wasLocked )
862 m_pattern->SetLocked( true );
863 }
864
865private:
868};
869
870
871bool PCB_TUNING_PATTERN::removeToBaseline( PNS::ROUTER* aRouter, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine )
872{
873 VECTOR2I startSnapPoint, endSnapPoint;
874
875 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CLastPoint(), aRouter,
876 aPNSLayer, startSnapPoint, endSnapPoint );
877
878 wxCHECK( pnsLine, false );
879
882 SHAPE_LINE_CHAIN post;
883 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
884
885 for( PNS::LINKED_ITEM* li : pnsLine->Links() )
886 aRouter->GetInterface()->RemoveItem( li );
887
888 aRouter->GetWorld()->Remove( *pnsLine );
889
890 SHAPE_LINE_CHAIN straightChain;
891 straightChain.Append( pre );
892 straightChain.Append( aBaseLine );
893 straightChain.Append( post );
894 straightChain.Simplify();
895
896 PNS::LINE straightLine( *pnsLine, straightChain );
897
898 aRouter->GetWorld()->Add( straightLine, false );
899
900 for( PNS::LINKED_ITEM* li : straightLine.Links() )
901 aRouter->GetInterface()->AddItem( li );
902
903 return true;
904}
905
906
908{
909 UNLOCKER raiiUnlocker( this );
910 SetFlags( IN_EDIT );
911
912 aTool->Router()->SyncWorld();
913
914 PNS::ROUTER* router = aTool->Router();
915 PNS_KICAD_IFACE* iface = aTool->GetInterface();
916
917 aCommit->Remove( this );
918
919 aTool->ClearRouterChanges();
920
921 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
922 int pnslayer = iface->GetPNSLayerFromBoardLayer( GetLayer() );
923
924 if( baselineValid() )
925 {
926 bool success = true;
927
928 success &= removeToBaseline( router, pnslayer, *m_baseLine );
929
930 if( m_tuningMode == DIFF_PAIR )
931 success &= removeToBaseline( router, pnslayer, *m_baseLineCoupled );
932
933 if( !success )
934 recoverBaseline( router );
935 }
936
937 const std::vector<GENERATOR_PNS_CHANGES>& allPnsChanges = aTool->GetRouterChanges();
938
939 for( const GENERATOR_PNS_CHANGES& pnsChanges : allPnsChanges )
940 {
941 const std::set<BOARD_ITEM*> routerRemovedItems = pnsChanges.removedItems;
942 const std::set<BOARD_ITEM*> routerAddedItems = pnsChanges.addedItems;
943
944 /*std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
945 << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
946 << " m_removedItems " << m_removedItems.size() << std::endl;*/
947
948 for( BOARD_ITEM* item : routerRemovedItems )
949 {
950 item->ClearSelected();
951 aCommit->Remove( item );
952 }
953
954 for( BOARD_ITEM* item : routerAddedItems )
955 aCommit->Add( item );
956 }
957}
958
959
961{
962 PNS::SOLID queryItem;
963
965 queryItem.SetShape( chain ); // PNS::SOLID takes ownership
966 queryItem.SetLayer( m_layer );
967
968 int lineWidth = 0;
969
970 PNS::NODE::OBSTACLES obstacles;
972 opts.m_useClearanceEpsilon = false;
973
974 PNS::NODE* world = aRouter->GetWorld();
975 PNS::NODE* branch = world->Branch();
976
977 branch->QueryColliding( &queryItem, obstacles, opts );
978
979 for( const PNS::OBSTACLE& obs : obstacles )
980 {
981 PNS::ITEM* item = obs.m_item;
982
984 continue;
985
986 if( PNS::LINKED_ITEM* li = dynamic_cast<PNS::LINKED_ITEM*>( item ) )
987 {
988 if( lineWidth == 0 || li->Width() < lineWidth )
989 lineWidth = li->Width();
990 }
991
992 if( chain->PointInside( item->Anchor( 0 ), 10 )
993 && chain->PointInside( item->Anchor( 1 ), 10 ) )
994 {
995 branch->Remove( item );
996 }
997 }
998
999 if( lineWidth == 0 )
1000 lineWidth = pcbIUScale.mmToIU( 0.1 ); // Fallback
1001
1002 if( baselineValid() )
1003 {
1004 NETINFO_ITEM* recoverNet = GetBoard()->FindNet( m_lastNetName );
1005 PNS::LINE recoverLine;
1006
1007 recoverLine.SetLayer( m_layer );
1008 recoverLine.SetWidth( lineWidth );
1009 recoverLine.Line() = *m_baseLine;
1010 recoverLine.SetNet( recoverNet );
1011 branch->Add( recoverLine, false );
1012
1014 {
1015 NETINFO_ITEM* recoverCoupledNet = GetBoard()->DpCoupledNet( recoverNet );
1016 PNS::LINE recoverLineCoupled;
1017
1018 recoverLineCoupled.SetLayer( m_layer );
1019 recoverLineCoupled.SetWidth( lineWidth );
1020 recoverLineCoupled.Line() = *m_baseLineCoupled;
1021 recoverLineCoupled.SetNet( recoverCoupledNet );
1022 branch->Add( recoverLineCoupled, false );
1023 }
1024 }
1025
1026 aRouter->CommitRouting( branch );
1027
1028 //wxLogWarning( "PNS baseline recovered" );
1029
1030 return true;
1031}
1032
1033
1035 bool aPrimary )
1036{
1037 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1038 PNS::ROUTER* router = aTool->Router();
1039 PNS::NODE* world = router->GetWorld();
1040 VECTOR2I startSnapPoint, endSnapPoint;
1041
1042 std::optional<PNS::LINE> pnsLine = getPNSLine( aBaseLine.CPoint( 0 ), aBaseLine.CLastPoint(), router,
1043 aPNSLayer, startSnapPoint, endSnapPoint );
1044
1045 if( !pnsLine )
1046 {
1047 // TODO
1048 //recoverBaseline( aRouter );
1049 return true;
1050 }
1051
1052 PNS::NODE* branch = world->Branch();
1053
1054 SHAPE_LINE_CHAIN straightChain;
1055 {
1056 SHAPE_LINE_CHAIN pre, mid, post;
1057 pnsLine->CLine().Split( startSnapPoint, endSnapPoint, pre, mid, post );
1058
1059 straightChain.Append( pre );
1060 straightChain.Append( aBaseLine );
1061 straightChain.Append( post );
1062 straightChain.Simplify();
1063 }
1064
1065 branch->Remove( *pnsLine );
1066
1067 SHAPE_LINE_CHAIN newLineChain;
1068
1069 if( aPrimary )
1070 {
1071 m_origin = straightChain.NearestPoint( m_origin );
1072 m_end = straightChain.NearestPoint( m_end );
1073
1074 // Don't allow points too close
1075 if( ( m_end - m_origin ).EuclideanNorm() < pcbIUScale.mmToIU( 0.1 ) )
1076 {
1077 m_origin = startSnapPoint;
1078 m_end = endSnapPoint;
1079 }
1080
1081 {
1082 SHAPE_LINE_CHAIN pre, mid, post;
1083 straightChain.Split( m_origin, m_end, pre, mid, post );
1084
1085 newLineChain.Append( pre );
1086 newLineChain.Append( mid );
1087 newLineChain.Append( post );
1088
1089 m_baseLine = mid;
1090 }
1091 }
1092 else
1093 {
1094 VECTOR2I start = straightChain.NearestPoint( m_origin );
1095 VECTOR2I end = straightChain.NearestPoint( m_end );
1096
1097 {
1098 SHAPE_LINE_CHAIN pre, mid, post;
1099 straightChain.Split( start, end, pre, mid, post );
1100
1101 newLineChain.Append( pre );
1102 newLineChain.Append( mid );
1103 newLineChain.Append( post );
1104
1105 m_baseLineCoupled = mid;
1106 }
1107 }
1108
1109 PNS::LINE newLine( *pnsLine, newLineChain );
1110
1111 branch->Add( newLine, false );
1112 router->CommitRouting( branch );
1113
1114 int clearance = router->GetRuleResolver()->Clearance( &newLine, nullptr );
1115
1116 iface->DisplayItem( &newLine, clearance, true, PNS_COLLISION );
1117
1118 return true;
1119}
1120
1121
1123{
1124 if( !( GetFlags() & IN_EDIT ) )
1125 return false;
1126
1127 UNLOCKER raiiUnlocker( this );
1128
1129 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1130 PNS::ROUTER* router = aTool->Router();
1131 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1132 PCB_LAYER_ID pcblayer = GetLayer();
1133
1134 auto hideRemovedItems = [&]( bool aHide )
1135 {
1136 if( view )
1137 {
1138 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1139 {
1140 for( BOARD_ITEM* item : pnsCommit.removedItems )
1141 {
1142 if( view )
1143 view->Hide( item, aHide, aHide );
1144 }
1145 }
1146 }
1147 };
1148
1149 iface->SetStartLayerFromPCBNew( pcblayer );
1150
1151 if( router->RoutingInProgress() )
1152 {
1153 router->StopRouting();
1154 }
1155
1156 // PNS layers and PCB layers have different coding. so convert PCB layer to PNS layer
1157 int pnslayer = iface->GetPNSLayerFromBoardLayer( pcblayer );
1158
1159 if( !baselineValid() )
1160 {
1161 initBaseLines( router, pnslayer, aBoard );
1162 }
1163 else
1164 {
1165 if( resetToBaseline( aTool, pnslayer, *m_baseLine, true ) )
1166 {
1167 m_origin = m_baseLine->CPoint( 0 );
1168 m_end = m_baseLine->CLastPoint();
1169 }
1170 else
1171 {
1172 //initBaseLines( router, layer, aBoard );
1173 return false;
1174 }
1175
1176 if( m_tuningMode == DIFF_PAIR )
1177 {
1178 if( !resetToBaseline( aTool, pnslayer, *m_baseLineCoupled, false ) )
1179 {
1180 initBaseLines( router, pnslayer, aBoard );
1181 return false;
1182 }
1183 }
1184 }
1185
1186 hideRemovedItems( true );
1187 // Snap points
1188 VECTOR2I startSnapPoint, endSnapPoint;
1189
1190 wxCHECK( m_baseLine, false );
1191
1192 PNS::LINKED_ITEM* startItem = pickSegment( router, m_origin, pnslayer, startSnapPoint, *m_baseLine);
1193 PNS::LINKED_ITEM* endItem = pickSegment( router, m_end, pnslayer, endSnapPoint, *m_baseLine );
1194
1195 wxASSERT( startItem );
1196 wxASSERT( endItem );
1197
1198 if( !startItem || !endItem )
1199 return false;
1200
1201 router->SetMode( GetPNSMode() );
1202
1203 if( !router->StartRouting( startSnapPoint, startItem, pnslayer ) )
1204 {
1205 //recoverBaseline( router );
1206 return false;
1207 }
1208
1209 PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
1210
1211 m_settings.m_keepEndpoints = true; // Required for re-grouping
1212 placer->UpdateSettings( m_settings );
1213
1214 router->Move( m_end, nullptr );
1215
1216 if( PNS::DP_MEANDER_PLACER* dpPlacer = dynamic_cast<PNS::DP_MEANDER_PLACER*>( placer ) )
1217 {
1218 m_trackWidth = dpPlacer->GetOriginPair().Width();
1219 m_diffPairGap = dpPlacer->GetOriginPair().Gap();
1220 }
1221 else
1222 {
1223 m_trackWidth = startItem->Width();
1224 m_diffPairGap = router->Sizes().DiffPairGap();
1225 }
1226
1227 m_settings = placer->MeanderSettings();
1228 m_lastNetName = iface->GetNetName( startItem->Net() );
1229 m_tuningStatus = placer->TuningStatus();
1231
1232 wxString statusMessage;
1233
1234 switch( m_tuningStatus )
1235 {
1236 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1237 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1238 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1239 default: statusMessage = _( "unknown" ); break;
1240 }
1241
1242 wxString result;
1243 EDA_UNITS userUnits = EDA_UNITS::MM;
1244
1245 if( aTool->GetManager()->GetSettings() )
1246 userUnits = static_cast<EDA_UNITS>( aTool->GetManager()->GetSettings()->m_System.units );
1247
1248 if( m_settings.m_isTimeDomain )
1249 {
1251 (double) m_tuningLength );
1252 }
1253 else
1254 {
1256 (double) m_tuningLength );
1257 }
1258
1259 m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage );
1260
1261 return true;
1262}
1263
1264
1266{
1267 if( !( GetFlags() & IN_EDIT ) )
1268 return;
1269
1271
1272 KIGFX::VIEW* view = aTool->GetManager()->GetView();
1273 PNS::ROUTER* router = aTool->Router();
1274 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1275 SHAPE_LINE_CHAIN bounds = getOutline();
1276 int epsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
1277
1278 iface->EraseView();
1279
1280 if( router->RoutingInProgress() )
1281 {
1282 bool forceFinish = true;
1283 bool forceCommit = false;
1284
1285 router->FixRoute( m_end, nullptr, forceFinish, forceCommit );
1286 router->StopRouting();
1287 }
1288
1289 const std::vector<GENERATOR_PNS_CHANGES>& pnsCommits = aTool->GetRouterChanges();
1290
1291 for( const GENERATOR_PNS_CHANGES& pnsCommit : pnsCommits )
1292 {
1293 const std::set<BOARD_ITEM*> routerRemovedItems = pnsCommit.removedItems;
1294 const std::set<BOARD_ITEM*> routerAddedItems = pnsCommit.addedItems;
1295
1296 //std::cout << "Push commits << " << allPnsChanges.size() << " routerRemovedItems "
1297 // << routerRemovedItems.size() << " routerAddedItems " << routerAddedItems.size()
1298 // << " m_removedItems " << m_removedItems.size() << std::endl;
1299
1300 for( BOARD_ITEM* item : routerRemovedItems )
1301 {
1302 if( view )
1303 view->Hide( item, false );
1304
1305 aCommit->Remove( item );
1306 }
1307
1308 for( BOARD_ITEM* item : routerAddedItems )
1309 {
1310 aCommit->Add( item );
1311
1312 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1313 {
1314 if( bounds.PointInside( track->GetStart(), epsilon )
1315 && bounds.PointInside( track->GetEnd(), epsilon ) )
1316 {
1317 AddItem( item );
1318 }
1319 }
1320 }
1321 }
1322}
1323
1324
1326{
1327 if( !( GetFlags() & IN_EDIT ) )
1328 return;
1329
1331
1332 PNS_KICAD_IFACE* iface = aTool->GetInterface();
1333
1334 iface->EraseView();
1335
1336 if( KIGFX::VIEW* view = aTool->GetManager()->GetView() )
1337 {
1338 for( const GENERATOR_PNS_CHANGES& pnsCommit : aTool->GetRouterChanges() )
1339 {
1340 for( BOARD_ITEM* item : pnsCommit.removedItems )
1341 view->Hide( item, false );
1342 }
1343 }
1344
1345 aTool->Router()->StopRouting();
1346}
1347
1348
1350{
1351 VECTOR2I centerlineOffset;
1352 VECTOR2I centerlineOffsetEnd;
1353
1354 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1355 {
1356 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1357 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1358 }
1359
1360 aPoints.AddPoint( m_origin + centerlineOffset );
1361 aPoints.AddPoint( m_end + centerlineOffsetEnd );
1362
1363 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1364 : SEG( m_origin, m_end );
1365
1366 base.A += centerlineOffset;
1367 base.B += centerlineOffset;
1368
1369 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1370
1371 if( m_tuningMode == DIFF_PAIR )
1372 amplitude += m_trackWidth + m_diffPairGap;
1373
1374 if( m_settings.m_initialSide == -1 )
1375 amplitude *= -1;
1376
1377 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1378
1379 aPoints.AddPoint( base.A + widthHandleOffset );
1380 aPoints.Point( 2 ).SetGridConstraint( IGNORE_GRID );
1381
1382 VECTOR2I spacingHandleOffset =
1383 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1384
1385 aPoints.AddPoint( base.A + spacingHandleOffset );
1386 aPoints.Point( 3 ).SetGridConstraint( IGNORE_GRID );
1387
1388 return true;
1389}
1390
1391
1393{
1394 VECTOR2I centerlineOffset;
1395 VECTOR2I centerlineOffsetEnd;
1396
1397 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1398 {
1399 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1400 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1401 }
1402
1403 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1404 : SEG( m_origin, m_end );
1405
1406 base.A += centerlineOffset;
1407 base.B += centerlineOffset;
1408
1409 m_origin = aEditPoints.Point( 0 ).GetPosition() - centerlineOffset;
1410 m_end = aEditPoints.Point( 1 ).GetPosition() - centerlineOffsetEnd;
1411
1412 if( aEditPoints.Point( 2 ).IsActive() )
1413 {
1414 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1415
1416 int value = base.LineDistance( wHandle );
1417
1418 value -= KiROUND( m_trackWidth / 2.0 );
1419
1420 if( m_tuningMode == DIFF_PAIR )
1421 value -= m_trackWidth + m_diffPairGap;
1422
1423 SetMaxAmplitude( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1424
1425 int side = base.Side( wHandle );
1426
1427 if( side < 0 )
1428 m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
1429 else
1430 m_settings.m_initialSide = PNS::MEANDER_SIDE_RIGHT;
1431 }
1432
1433 if( aEditPoints.Point( 3 ).IsActive() )
1434 {
1435 VECTOR2I wHandle = aEditPoints.Point( 2 ).GetPosition();
1436 VECTOR2I sHandle = aEditPoints.Point( 3 ).GetPosition();
1437
1438 int value = KiROUND( SEG( base.A, wHandle ).LineDistance( sHandle ) / 1.5 );
1439
1440 SetSpacing( KiROUND( value / pcbIUScale.mmToIU( 0.01 ) ) * pcbIUScale.mmToIU( 0.01 ) );
1441 }
1442
1443 return true;
1444}
1445
1446
1448{
1449 VECTOR2I centerlineOffset;
1450 VECTOR2I centerlineOffsetEnd;
1451
1452 if( m_tuningMode == DIFF_PAIR && m_baseLineCoupled && m_baseLineCoupled->SegmentCount() > 0 )
1453 {
1454 centerlineOffset = ( m_baseLineCoupled->CPoint( 0 ) - m_origin ) / 2;
1455 centerlineOffsetEnd = ( m_baseLineCoupled->CLastPoint() - m_end ) / 2;
1456 }
1457
1458 SEG base = m_baseLine && m_baseLine->SegmentCount() > 0 ? m_baseLine->CSegment( 0 )
1459 : SEG( m_origin, m_end );
1460
1461 base.A += centerlineOffset;
1462 base.B += centerlineOffset;
1463
1464 int amplitude = m_settings.m_maxAmplitude + KiROUND( m_trackWidth / 2.0 );
1465
1466 if( m_tuningMode == DIFF_PAIR )
1467 amplitude += m_trackWidth + m_diffPairGap;
1468
1469 if( m_settings.m_initialSide == -1 )
1470 amplitude *= -1;
1471
1472 VECTOR2I widthHandleOffset = ( base.B - base.A ).Perpendicular().Resize( amplitude );
1473
1474 aEditPoints.Point( 0 ).SetPosition( m_origin + centerlineOffset );
1475 aEditPoints.Point( 1 ).SetPosition( m_end + centerlineOffsetEnd );
1476
1477 aEditPoints.Point( 2 ).SetPosition( base.A + widthHandleOffset );
1478
1479 VECTOR2I spacingHandleOffset =
1480 widthHandleOffset + ( base.B - base.A ).Resize( KiROUND( m_settings.m_spacing * 1.5 ) );
1481
1482 aEditPoints.Point( 3 ).SetPosition( base.A + spacingHandleOffset );
1483
1484 return true;
1485}
1486
1487
1489{
1490 if( m_baseLine )
1491 {
1492 int clampedMaxAmplitude = m_settings.m_maxAmplitude;
1493 int minAllowedAmplitude = 0;
1494 int baselineOffset = m_tuningMode == DIFF_PAIR ? ( m_diffPairGap + m_trackWidth ) / 2 : 0;
1495
1497 {
1498 minAllowedAmplitude = baselineOffset + m_trackWidth;
1499 }
1500 else
1501 {
1502 int correction = m_trackWidth * tan( 1 - tan( DEG2RAD( 22.5 ) ) );
1503 minAllowedAmplitude = baselineOffset + correction;
1504 }
1505
1506 clampedMaxAmplitude = std::max( clampedMaxAmplitude, minAllowedAmplitude );
1507
1508 if( m_settings.m_singleSided )
1509 {
1510 SHAPE_LINE_CHAIN clBase = *m_baseLine;
1512
1513 if( m_tuningMode != DIFF_PAIR )
1514 {
1515 int amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1516
1518
1520 true ) )
1521 {
1522 chain.Append( m_settings.m_initialSide >= 0 ? right : left );
1523 chain.Append( clBase.Reverse() );
1524 chain.SetClosed( true );
1525
1526 return chain;
1527 }
1528 }
1530 {
1531 int amplitude = clampedMaxAmplitude + m_trackWidth + KiROUND( m_diffPairGap / 2.0 );
1532
1534 SHAPE_LINE_CHAIN chain1, chain2;
1535
1537 true ) )
1538 {
1539 if( m_settings.m_initialSide >= 0 )
1540 chain1.Append( right );
1541 else
1542 chain1.Append( left );
1543
1545 ARC_LOW_DEF, left, right, true ) )
1546 {
1547 if( m_settings.m_initialSide >= 0 )
1548 chain1.Append( left.Reverse() );
1549 else
1550 chain1.Append( right.Reverse() );
1551 }
1552
1553 chain1.SetClosed( true );
1554 }
1555
1557 true ) )
1558 {
1559 if( m_settings.m_initialSide >= 0 )
1560 chain2.Append( right );
1561 else
1562 chain2.Append( left );
1563
1565 ARC_LOW_DEF, left, right, true ) )
1566 {
1567 if( m_settings.m_initialSide >= 0 )
1568 chain2.Append( left.Reverse() );
1569 else
1570 chain2.Append( right.Reverse() );
1571 }
1572
1573 chain2.SetClosed( true );
1574 }
1575
1576 SHAPE_POLY_SET merged;
1577 merged.BooleanAdd( chain1, chain2 );
1578
1579 if( merged.OutlineCount() > 0 )
1580 return merged.Outline( 0 );
1581 }
1582 }
1583
1584 // Not single-sided / fallback
1585 SHAPE_POLY_SET poly;
1587
1588 int amplitude = 0;
1589
1590 if( m_tuningMode == DIFF_PAIR )
1591 amplitude = clampedMaxAmplitude + m_diffPairGap / 2 + KiROUND( m_trackWidth );
1592 else
1593 amplitude = clampedMaxAmplitude + KiROUND( m_trackWidth / 2.0 );
1594
1596
1598 {
1599 SHAPE_POLY_SET polyCoupled;
1601 ARC_LOW_DEF, false );
1602
1603 poly.ClearArcs();
1604 polyCoupled.ClearArcs();
1605
1606 SHAPE_POLY_SET merged;
1607 merged.BooleanAdd( poly, polyCoupled );
1608
1609 if( merged.OutlineCount() > 0 )
1610 return merged.Outline( 0 );
1611 }
1612
1613 if( poly.OutlineCount() > 0 )
1614 return poly.Outline( 0 );
1615 }
1616
1617 return SHAPE_LINE_CHAIN();
1618}
1619
1620
1621void PCB_TUNING_PATTERN::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
1622{
1623 if( !IsSelected() && !IsNew() )
1624 return;
1625
1626 KIGFX::PREVIEW::DRAW_CONTEXT ctx( *aView );
1627
1628 int size = KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) * 0.8 );
1629 size = std::max( size, pcbIUScale.mmToIU( 0.05 ) );
1630
1631 if( !HasFlag( IN_EDIT ) )
1632 {
1633 if( m_baseLine )
1634 {
1635 for( int i = 0; i < m_baseLine->SegmentCount(); i++ )
1636 {
1637 SEG seg = m_baseLine->CSegment( i );
1638 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1639 }
1640 }
1641 else
1642 {
1643 ctx.DrawLineDashed( m_origin, m_end, size, size / 6, false );
1644 }
1645
1647 {
1648 for( int i = 0; i < m_baseLineCoupled->SegmentCount(); i++ )
1649 {
1650 SEG seg = m_baseLineCoupled->CSegment( i );
1651 ctx.DrawLineDashed( seg.A, seg.B, size, size / 6, true );
1652 }
1653 }
1654 }
1655
1657
1658 for( int i = 0; i < chain.SegmentCount(); i++ )
1659 {
1660 SEG seg = chain.Segment( i );
1661 ctx.DrawLineDashed( seg.A, seg.B, size, size / 2, false );
1662 }
1663}
1664
1665
1667{
1669
1670 props.set( "tuning_mode", tuningToString( m_tuningMode ) );
1671 props.set( "initial_side", sideToString( m_settings.m_initialSide ) );
1672 props.set( "last_status", statusToString( m_tuningStatus ) );
1673 props.set( "is_time_domain", m_settings.m_isTimeDomain );
1674
1675 props.set( "end", m_end );
1676 props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1677 props.set( "single_sided", m_settings.m_singleSided );
1678 props.set( "rounded", m_settings.m_cornerStyle == PNS::MEANDER_STYLE_ROUND );
1679
1680 props.set_iu( "max_amplitude", m_settings.m_maxAmplitude );
1681 props.set_iu( "min_amplitude", m_settings.m_minAmplitude );
1682 props.set_iu( "min_spacing", m_settings.m_spacing );
1683 props.set_iu( "target_length_min", m_settings.m_targetLength.Min() );
1684 props.set_iu( "target_length", m_settings.m_targetLength.Opt() );
1685 props.set_iu( "target_length_max", m_settings.m_targetLength.Max() );
1686 props.set_iu( "target_delay_min", m_settings.m_targetLengthDelay.Min() );
1687 props.set_iu( "target_delay", m_settings.m_targetLengthDelay.Opt() );
1688 props.set_iu( "target_delay_max", m_settings.m_targetLengthDelay.Max() );
1689 props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() );
1690 props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() );
1691 props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() );
1692 props.set_iu( "last_track_width", m_trackWidth );
1693 props.set_iu( "last_diff_pair_gap", m_diffPairGap );
1694 props.set_iu( "last_tuning_length", m_tuningLength );
1695
1696 props.set( "last_netname", m_lastNetName );
1697 props.set( "override_custom_rules", m_settings.m_overrideCustomRules );
1698
1699 if( m_baseLine )
1700 props.set( "base_line", wxAny( *m_baseLine ) );
1701
1702 if( m_baseLineCoupled )
1703 props.set( "base_line_coupled", wxAny( *m_baseLineCoupled ) );
1704
1705 return props;
1706}
1707
1708
1710{
1712
1713 wxString tuningMode;
1714 aProps.get_to( "tuning_mode", tuningMode );
1715 m_tuningMode = tuningFromString( tuningMode.utf8_string() );
1716
1717 wxString side;
1718 aProps.get_to( "initial_side", side );
1719 m_settings.m_initialSide = sideFromString( side.utf8_string() );
1720
1721 wxString status;
1722 aProps.get_to( "last_status", status );
1723 m_tuningStatus = statusFromString( status.utf8_string() );
1724
1725 aProps.get_to( "is_time_domain", m_settings.m_isTimeDomain );
1726
1727 aProps.get_to( "end", m_end );
1728 aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage );
1729 aProps.get_to( "single_sided", m_settings.m_singleSided );
1730 aProps.get_to( "side", m_settings.m_initialSide );
1731
1732 bool rounded = false;
1733 aProps.get_to( "rounded", rounded );
1735
1736 long long int val;
1737
1738 aProps.get_to_iu( "target_length", val );
1739 m_settings.SetTargetLength( val );
1740
1741 if( aProps.get_to_iu( "target_length_min", val ) )
1742 m_settings.m_targetLength.SetMin( val );
1743
1744 if( aProps.get_to_iu( "target_length_max", val ) )
1745 m_settings.m_targetLength.SetMax( val );
1746
1747 aProps.get_to_iu( "target_delay", val );
1748 m_settings.SetTargetLengthDelay( val );
1749
1750 if( aProps.get_to_iu( "target_delay_min", val ) )
1751 m_settings.m_targetLengthDelay.SetMin( val );
1752
1753 if( aProps.get_to_iu( "target_delay_max", val ) )
1754 m_settings.m_targetLengthDelay.SetMax( val );
1755
1756 int int_val;
1757
1758 aProps.get_to_iu( "target_skew", int_val );
1759 m_settings.SetTargetSkew( int_val );
1760
1761 if( aProps.get_to_iu( "target_skew_min", int_val ) )
1762 m_settings.m_targetSkew.SetMin( int_val );
1763
1764 if( aProps.get_to_iu( "target_skew_max", int_val ) )
1765 m_settings.m_targetSkew.SetMax( int_val );
1766
1767 aProps.get_to_iu( "max_amplitude", m_settings.m_maxAmplitude );
1768 aProps.get_to_iu( "min_amplitude", m_settings.m_minAmplitude );
1769 aProps.get_to_iu( "min_spacing", m_settings.m_spacing );
1770 aProps.get_to_iu( "last_track_width", m_trackWidth );
1771 aProps.get_to_iu( "last_diff_pair_gap", m_diffPairGap );
1772 aProps.get_to_iu( "last_tuning_length", m_tuningLength );
1773 aProps.get_to( "override_custom_rules", m_settings.m_overrideCustomRules );
1774
1775 aProps.get_to( "last_netname", m_lastNetName );
1776
1777 if( auto baseLine = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line" ) )
1778 m_baseLine = *baseLine;
1779
1780 if( auto baseLineCoupled = aProps.get_opt<SHAPE_LINE_CHAIN>( "base_line_coupled" ) )
1781 m_baseLineCoupled = *baseLineCoupled;
1782
1783 // Reconstruct m_tuningInfo from loaded length and status
1784 if( m_tuningLength != 0 )
1785 {
1786 wxString statusMessage;
1787
1788 switch( m_tuningStatus )
1789 {
1790 case PNS::MEANDER_PLACER_BASE::TOO_LONG: statusMessage = _( "too long" ); break;
1791 case PNS::MEANDER_PLACER_BASE::TOO_SHORT: statusMessage = _( "too short" ); break;
1792 case PNS::MEANDER_PLACER_BASE::TUNED: statusMessage = _( "tuned" ); break;
1793 default: statusMessage = _( "unknown" ); break;
1794 }
1795
1796 EDA_UNITS units = m_settings.m_isTimeDomain ? EDA_UNITS::PS : EDA_UNITS::MM;
1797 wxString lengthStr = EDA_UNIT_UTILS::UI::MessageTextFromValue( pcbIUScale, units,
1798 (double) m_tuningLength );
1799
1800 m_tuningInfo.Printf( wxS( "%s (%s)" ), lengthStr, statusMessage );
1801 }
1802}
1803
1804
1806{
1808 DRC_CONSTRAINT constraint;
1809
1810 if( !m_items.empty() )
1811 {
1812 BOARD_ITEM* startItem = static_cast<BOARD_ITEM*>( *m_items.begin() );
1813 std::shared_ptr<DRC_ENGINE>& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1814
1816 {
1817 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, startItem, nullptr, GetLayer() );
1818
1819 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
1820 {
1822 {
1823 settings.SetTargetLengthDelay( constraint.GetValue() );
1824 settings.SetTargetLength( MINOPTMAX<int>() );
1825 settings.m_isTimeDomain = true;
1826 }
1827 else
1828 {
1830 settings.SetTargetLength( constraint.GetValue() );
1831 settings.m_isTimeDomain = false;
1832 }
1833 }
1834 }
1835 else
1836 {
1837 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() );
1838
1839 if( !constraint.IsNull() && !settings.m_overrideCustomRules )
1840 {
1842 {
1843 settings.SetTargetLengthDelay( constraint.GetValue() );
1844 settings.SetTargetLength( MINOPTMAX<int>() );
1845 settings.m_isTimeDomain = true;
1846 }
1847 else
1848 {
1850 settings.SetTargetLength( constraint.GetValue() );
1851 settings.m_isTimeDomain = false;
1852 }
1853 }
1854 }
1855 }
1856
1857 DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint );
1858
1859 if( dlg.ShowModal() == wxID_OK )
1860 {
1861 BOARD_COMMIT commit( aEditFrame );
1862 commit.Modify( this );
1863 m_settings = settings;
1864
1865 GENERATOR_TOOL* generatorTool = aEditFrame->GetToolManager()->GetTool<GENERATOR_TOOL>();
1866 EditStart( generatorTool, GetBoard(), &commit );
1867 Update( generatorTool, GetBoard(), &commit );
1868 EditFinish( generatorTool, GetBoard(), &commit );
1869
1870 commit.Push( _( "Edit Tuning Pattern" ) );
1871 }
1872}
1873
1874
1876 PCB_BASE_EDIT_FRAME* aFrame,
1877 bool aStatusItemsOnly )
1878{
1879 std::vector<EDA_ITEM*> previewItems;
1880 KIGFX::VIEW* view = aFrame->GetCanvas()->GetView();
1881
1882 if( auto* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aTool->Router()->Placer() ) )
1883 {
1884 if( !aStatusItemsOnly )
1885 {
1886 PNS::ITEM_SET items = placer->TunedPath();
1887
1888 for( PNS::ITEM* item : items )
1889 previewItems.push_back( new ROUTER_PREVIEW_ITEM( item,
1890 aTool->Router()->GetInterface(),
1891 view, PNS_HOVER_ITEM ) );
1892 }
1893
1894 TUNING_STATUS_VIEW_ITEM* statusItem = new TUNING_STATUS_VIEW_ITEM( aFrame );
1895
1897 {
1898 if( m_settings.m_isTimeDomain )
1899 statusItem->SetMinMax( m_settings.m_targetSkewDelay.Min(), m_settings.m_targetSkewDelay.Max() );
1900 else
1901 statusItem->SetMinMax( m_settings.m_targetSkew.Min(), m_settings.m_targetSkew.Max() );
1902 }
1903 else
1904 {
1905 if( m_settings.m_isTimeDomain )
1906 {
1907 if( m_settings.m_targetLengthDelay.Opt() == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED )
1908 {
1909 statusItem->ClearMinMax();
1910 }
1911 else
1912 {
1913 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLengthDelay.Min() ),
1914 static_cast<double>( m_settings.m_targetLengthDelay.Max() ) );
1915 }
1916 }
1917 else
1918 {
1919 if( m_settings.m_targetLength.Opt() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
1920 {
1921 statusItem->ClearMinMax();
1922 }
1923 else
1924 {
1925 statusItem->SetMinMax( static_cast<double>( m_settings.m_targetLength.Min() ),
1926 static_cast<double>( m_settings.m_targetLength.Max() ) );
1927 }
1928 }
1929 }
1930
1931 statusItem->SetIsTimeDomain( m_settings.m_isTimeDomain );
1932
1934 {
1935 if( m_settings.m_isTimeDomain )
1936 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current skew" ) );
1937 else
1938 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current skew" ) );
1939 }
1940 else
1941 {
1942 if( m_settings.m_isTimeDomain )
1943 statusItem->SetCurrent( static_cast<double>( placer->TuningDelayResult() ), _( "current delay" ) );
1944 else
1945 statusItem->SetCurrent( static_cast<double>( placer->TuningLengthResult() ), _( "current length" ) );
1946 }
1947
1948 statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() );
1949 previewItems.push_back( statusItem );
1950 }
1951
1952 return previewItems;
1953}
1954
1955
1957 std::vector<MSG_PANEL_ITEM>& aList )
1958{
1959 wxString msg;
1960 NETINFO_ITEM* primaryNet = nullptr;
1961 NETINFO_ITEM* coupledNet = nullptr;
1962 PCB_TRACK* primaryItem = nullptr;
1963 PCB_TRACK* coupledItem = nullptr;
1964 NETCLASS* netclass = nullptr;
1965 int width = 0;
1966 bool mixedWidth = false;
1967
1969
1970 aList.emplace_back( _( "Type" ), GetFriendlyName() );
1971
1972 for( EDA_ITEM* member : GetItems() )
1973 {
1974 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( member ) )
1975 {
1976 if( !primaryNet )
1977 {
1978 primaryItem = track;
1979 primaryNet = track->GetNet();
1980 }
1981 else if( !coupledNet && track->GetNet() != primaryNet )
1982 {
1983 coupledItem = track;
1984 coupledNet = track->GetNet();
1985 }
1986
1987 if( !netclass )
1988 netclass = track->GetEffectiveNetClass();
1989
1990 if( !width )
1991 width = track->GetWidth();
1992 else if( width != track->GetWidth() )
1993 mixedWidth = true;
1994 }
1995 }
1996
1997 if( coupledNet )
1998 {
1999 aList.emplace_back( _( "Nets" ), UnescapeString( primaryNet->GetNetname() )
2000 + wxS( ", " )
2001 + UnescapeString( coupledNet->GetNetname() ) );
2002 }
2003 else if( primaryNet )
2004 {
2005 aList.emplace_back( _( "Net" ), UnescapeString( primaryNet->GetNetname() ) );
2006 }
2007
2008 if( netclass )
2009 aList.emplace_back( _( "Resolved Netclass" ),
2010 UnescapeString( netclass->GetHumanReadableName() ) );
2011
2012 aList.emplace_back( _( "Layer" ), LayerMaskDescribe() );
2013
2014 if( width && !mixedWidth )
2015 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( width ) );
2016
2017 BOARD* board = GetBoard();
2018 std::shared_ptr<DRC_ENGINE>& drcEngine = board->GetDesignSettings().m_DRCEngine;
2019 DRC_CONSTRAINT constraint;
2020
2021 // Display full track length (in Pcbnew)
2022 if( board && primaryItem && primaryItem->GetNetCode() > 0 )
2023 {
2024 int count = 0;
2025 double trackLen = 0.0;
2026 double lenPadToDie = 0.0;
2027 double trackDelay = 0.0;
2028 double delayPadToDie = 0.0;
2029
2030 std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *primaryItem );
2031
2032 if( coupledItem && coupledItem->GetNetCode() > 0 )
2033 {
2034 double coupledLen = 0.0;
2035 double coupledLenPadToDie = 0.0;
2036 double coupledTrackDelay = 0.0;
2037 double doubledDelayPadToDie = 0.0;
2038
2039 std::tie( count, coupledLen, coupledLenPadToDie, coupledTrackDelay, doubledDelayPadToDie ) =
2040 board->GetTrackLength( *coupledItem );
2041
2042 if( trackDelay == 0.0 || coupledTrackDelay == 0.0 )
2043 {
2044 aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen ) + wxS( ", " )
2045 + aFrame->MessageTextFromValue( coupledLen ) );
2046 }
2047 else
2048 {
2049 aList.emplace_back(
2050 _( "Routed Delays" ),
2051 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) + wxS( ", " )
2052 + aFrame->MessageTextFromValue( coupledTrackDelay, true, EDA_DATA_TYPE::TIME ) );
2053 }
2054 }
2055 else
2056 {
2057 if( trackDelay == 0.0 )
2058 {
2059 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2060 }
2061 else
2062 {
2063 aList.emplace_back( _( "Routed Delay" ),
2064 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) );
2065 }
2066 }
2067
2068 if( lenPadToDie != 0 && delayPadToDie == 0.0 )
2069 {
2070 msg = aFrame->MessageTextFromValue( lenPadToDie );
2071 aList.emplace_back( _( "Pad To Die Length" ), msg );
2072
2073 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2074 aList.emplace_back( _( "Full Length" ), msg );
2075 }
2076 else if( delayPadToDie > 0.0 )
2077 {
2078 msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME );
2079 aList.emplace_back( _( "Pad To Die Delay" ), msg );
2080
2081 msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME );
2082 aList.emplace_back( _( "Full Delay" ), msg );
2083 }
2084 }
2085
2087 {
2088 constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, primaryItem, coupledItem, m_layer );
2089
2090 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2091 {
2092 msg = aFrame->MessageTextFromValue( m_settings.m_targetSkew.Opt() );
2093
2094 aList.emplace_back( wxString::Format( _( "Target Skew: %s" ), msg ),
2095 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2096 }
2097 else
2098 {
2099 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() );
2100
2101 if( !msg.IsEmpty() )
2102 {
2103 aList.emplace_back( wxString::Format( _( "Skew Constraints: %s" ), msg ),
2104 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2105 }
2106 }
2107 }
2108 else
2109 {
2110 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, primaryItem, coupledItem, m_layer );
2111
2112 if( constraint.IsNull() || m_settings.m_overrideCustomRules )
2113 {
2114 wxString caption;
2115
2116 if( m_settings.m_isTimeDomain )
2117 {
2118 caption = _( "Target Delay: %s" );
2119 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLengthDelay.Opt() ), true,
2121 }
2122 else
2123 {
2124 caption = _( "Target Length: %s" );
2125 msg = aFrame->MessageTextFromValue( static_cast<double>( m_settings.m_targetLength.Opt() ) );
2126 }
2127
2128 aList.emplace_back( wxString::Format( caption, msg ),
2129 wxString::Format( _( "(from tuning pattern properties)" ) ) );
2130 }
2131 else
2132 {
2133 msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue(), unitType );
2134
2135 wxString caption = m_settings.m_isTimeDomain ? _( "Delay Constraints: %s" ) : _( "Length Constraints: %s" );
2136
2137 if( !msg.IsEmpty() )
2138 {
2139 aList.emplace_back( wxString::Format( caption, msg ),
2140 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2141 }
2142 }
2143 }
2144}
2145
2146
2147const wxString PCB_TUNING_PATTERN::DISPLAY_NAME = _HKI( "Tuning Pattern" );
2148const wxString PCB_TUNING_PATTERN::GENERATOR_TYPE = wxS( "tuning_pattern" );
2149
2150
2152
2153
2154#define HITTEST_THRESHOLD_PIXELS 5
2155
2156
2158{
2160 return 0;
2161
2162 if( m_inDrawingTool )
2163 return 0;
2164
2166
2167 m_toolMgr->RunAction( ACTIONS::selectionClear );
2168
2169 m_frame->PushTool( aEvent );
2170 Activate();
2171
2172 BOARD* board = m_frame->GetBoard();
2173 BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
2174 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
2175 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2176 PNS::ROUTER* router = generatorTool->Router();
2177 PNS::ROUTER_MODE routerMode = aEvent.Parameter<PNS::ROUTER_MODE>();
2178 LENGTH_TUNING_MODE mode = fromPNSMode( routerMode );
2179 PNS::MEANDER_SETTINGS meanderSettings;
2180
2181 switch( mode )
2182 {
2183 case LENGTH_TUNING_MODE::SINGLE: meanderSettings = bds.m_SingleTrackMeanderSettings; break;
2184 case DIFF_PAIR: meanderSettings = bds.m_DiffPairMeanderSettings; break;
2185 case DIFF_PAIR_SKEW: meanderSettings = bds.m_SkewMeanderSettings; break;
2186 }
2187
2189 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2190 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
2191 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TUNING );
2192
2193 m_pickerItem = nullptr;
2194 m_tuningPattern = nullptr;
2195
2196 // Add a VIEW_GROUP that serves as a preview for the new item
2197 m_preview.Clear();
2198 m_view->Add( &m_preview );
2199
2200 auto applyCommonSettings =
2201 [&]( PCB_TUNING_PATTERN* aPattern )
2202 {
2203 const auto& origTargetLength = aPattern->GetSettings().m_targetLength;
2204 const auto& origTargetSkew = aPattern->GetSettings().m_targetSkew;
2205
2206 aPattern->GetSettings() = meanderSettings;
2207
2208 if( meanderSettings.m_targetLength.IsNull() )
2209 aPattern->GetSettings().m_targetLength = origTargetLength;
2210
2211 if( meanderSettings.m_targetSkew.IsNull() )
2212 aPattern->GetSettings().m_targetSkew = origTargetSkew;
2213 };
2214
2215 auto updateHoverStatus =
2216 [&]()
2217 {
2218 std::unique_ptr<PCB_TUNING_PATTERN> dummyPattern;
2219
2220 if( m_pickerItem )
2221 {
2222 dummyPattern.reset( PCB_TUNING_PATTERN::CreateNew( generatorTool, m_frame,
2223 m_pickerItem, mode ) );
2224 dummyPattern->SetPosition( m_pickerItem->GetFocusPosition() );
2225 dummyPattern->SetEnd( m_pickerItem->GetFocusPosition() );
2226 }
2227
2228 if( dummyPattern )
2229 {
2230 applyCommonSettings( dummyPattern.get() );
2231
2232 dummyPattern->EditStart( generatorTool, m_board, nullptr );
2233 dummyPattern->Update( generatorTool, m_board, nullptr );
2234
2235 m_preview.FreeItems();
2236
2237 for( EDA_ITEM* item : dummyPattern->GetPreviewItems( generatorTool, m_frame ) )
2238 m_preview.Add( item );
2239
2240 generatorTool->Router()->StopRouting();
2241
2242 m_view->Update( &m_preview );
2243 }
2244 else
2245 {
2246
2247 m_preview.FreeItems();
2248 m_view->Update( &m_preview );
2249 }
2250 };
2251
2252 auto updateTuningPattern =
2253 [&]()
2254 {
2255 if( m_tuningPattern && m_tuningPattern->GetPosition() != m_tuningPattern->GetEnd() )
2256 {
2257 m_tuningPattern->EditStart( generatorTool, m_board, nullptr );
2258 m_tuningPattern->Update( generatorTool, m_board, nullptr );
2259
2260 m_preview.FreeItems();
2261
2262 for( EDA_ITEM* item : m_tuningPattern->GetPreviewItems( generatorTool, m_frame, true ) )
2263 m_preview.Add( item );
2264
2265 m_view->Update( &m_preview );
2266 }
2267 };
2268
2269 while( TOOL_EVENT* evt = Wait() )
2270 {
2271 VECTOR2D cursorPos = controls->GetMousePosition();
2272
2273 if( evt->IsCancelInteractive() || evt->IsActivate()
2274 || ( m_tuningPattern && evt->IsAction( &ACTIONS::undo ) ) )
2275 {
2276 if( m_tuningPattern )
2277 {
2278 // First click already made; clean up tuning pattern preview
2279 m_tuningPattern->EditCancel( generatorTool, m_board, nullptr );
2280
2281 delete m_tuningPattern;
2282 m_tuningPattern = nullptr;
2283 }
2284 else
2285 {
2286 break;
2287 }
2288 }
2289 else if( evt->IsMotion() )
2290 {
2291 if( !m_tuningPattern )
2292 {
2293 // First click not yet made; we're in highlight-net-under-cursor mode
2294
2295 GENERAL_COLLECTOR collector;
2296 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2297
2298 if( m_frame->GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL )
2299 guide.SetIncludeSecondary( false );
2300 else
2301 guide.SetIncludeSecondary( true );
2302
2303 guide.SetPreferredLayer( m_frame->GetActiveLayer() );
2304
2305 collector.Collect( board, { PCB_TRACE_T, PCB_ARC_T }, cursorPos, guide );
2306
2307 if( collector.GetCount() > 1 )
2308 selectionTool->GuessSelectionCandidates( collector, cursorPos );
2309
2310 m_pickerItem = nullptr;
2311
2312 if( collector.GetCount() > 0 )
2313 {
2314 double min_dist_sq = std::numeric_limits<double>::max();
2315
2316 for( EDA_ITEM* candidate : collector )
2317 {
2318 VECTOR2I candidatePos;
2319
2320 if( candidate->Type() == PCB_TRACE_T )
2321 {
2322 candidatePos = static_cast<PCB_TRACK*>( candidate )->GetCenter();
2323 }
2324 else if( candidate->Type() == PCB_ARC_T )
2325 {
2326 candidatePos = static_cast<PCB_ARC*>( candidate )->GetMid();
2327 }
2328
2329 double dist_sq = ( cursorPos - candidatePos ).SquaredEuclideanNorm();
2330
2331 if( dist_sq < min_dist_sq )
2332 {
2333 min_dist_sq = dist_sq;
2334 m_pickerItem = static_cast<BOARD_CONNECTED_ITEM*>( candidate );
2335 }
2336 }
2337 }
2338
2339 updateHoverStatus();
2340 }
2341 else
2342 {
2343 // First click already made; we're in preview-tuning-pattern mode
2344
2345 m_tuningPattern->SetEnd( cursorPos );
2346 m_tuningPattern->UpdateSideFromEnd();
2347
2348 updateTuningPattern();
2349 }
2350 }
2351 else if( evt->IsClick( BUT_LEFT ) )
2352 {
2354 {
2355 // First click; create a tuning pattern
2356
2357 if( dynamic_cast<PCB_TUNING_PATTERN*>( m_pickerItem->GetParentGroup() ) )
2358 {
2359 m_frame->ShowInfoBarWarning( _( "Unable to tune segments inside other "
2360 "tuning patterns." ) );
2361 }
2362 else
2363 {
2364 m_preview.FreeItems();
2365
2366 m_frame->SetActiveLayer( m_pickerItem->GetLayer() );
2368 m_pickerItem, mode );
2369
2370 applyCommonSettings( m_tuningPattern );
2371
2372 int dummyDist;
2373 int dummyClearance = std::numeric_limits<int>::max() / 2;
2374 VECTOR2I closestPt;
2375
2376 // With an artificially-large clearance this can't *not* collide, but the
2377 // if stmt keeps Coverity happy....
2378 if( m_pickerItem->GetEffectiveShape()->Collide( cursorPos, dummyClearance,
2379 &dummyDist, &closestPt ) )
2380 {
2381 m_tuningPattern->SetPosition( closestPt );
2382 m_tuningPattern->SetEnd( closestPt );
2383 }
2384
2385 m_preview.Add( m_tuningPattern->Clone() );
2386 }
2387 }
2388 else if( m_pickerItem && m_tuningPattern )
2389 {
2390 // Second click; we're done
2391 BOARD_COMMIT commit( m_frame );
2392
2393 m_tuningPattern->EditStart( generatorTool, m_board, &commit );
2394 m_tuningPattern->Update( generatorTool, m_board, &commit );
2395 m_tuningPattern->EditFinish( generatorTool, m_board, &commit );
2396
2397 commit.Push( _( "Tune" ) );
2398
2399 m_tuningPattern = nullptr;
2400 m_pickerItem = nullptr;
2401 }
2402 }
2403 else if( evt->IsClick( BUT_RIGHT ) )
2404 {
2406 m_menu->ShowContextMenu( dummy );
2407 }
2408 else if( evt->IsAction( &PCB_ACTIONS::spacingIncrease )
2409 || evt->IsAction( &PCB_ACTIONS::spacingDecrease ) )
2410 {
2411 if( m_tuningPattern )
2412 {
2413 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2414
2415 placer->SpacingStep( evt->IsAction( &PCB_ACTIONS::spacingIncrease ) ? 1 : -1 );
2416 m_tuningPattern->SetSpacing( placer->MeanderSettings().m_spacing );
2417 meanderSettings.m_spacing = placer->MeanderSettings().m_spacing;
2418
2419 updateTuningPattern();
2420 }
2421 else
2422 {
2423 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2424 }
2425 }
2426 else if( evt->IsAction( &PCB_ACTIONS::amplIncrease )
2427 || evt->IsAction( &PCB_ACTIONS::amplDecrease ) )
2428 {
2429 if( m_tuningPattern )
2430 {
2431 auto* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( router->Placer() );
2432
2433 placer->AmplitudeStep( evt->IsAction( &PCB_ACTIONS::amplIncrease ) ? 1 : -1 );
2434 m_tuningPattern->SetMaxAmplitude( placer->MeanderSettings().m_maxAmplitude );
2435 meanderSettings.m_maxAmplitude = placer->MeanderSettings().m_maxAmplitude;
2436
2437 updateTuningPattern();
2438 }
2439 else
2440 {
2441 m_frame->ShowInfoBarWarning( _( "Select a track to tune first." ) );
2442 }
2443 }
2444 else if( evt->IsAction( &PCB_ACTIONS::properties )
2445 || evt->IsAction( &PCB_ACTIONS::lengthTunerSettings ) )
2446 {
2447 DRC_CONSTRAINT constraint;
2448
2449 if( m_tuningPattern )
2450 {
2451 if( !m_tuningPattern->GetItems().empty() )
2452 {
2453 BOARD_ITEM* startItem = *m_tuningPattern->GetBoardItems().begin();
2454
2455 constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr,
2456 startItem->GetLayer() );
2457 }
2458 }
2459
2460 DIALOG_TUNING_PATTERN_PROPERTIES dlg( m_frame, meanderSettings, routerMode, constraint );
2461
2462 if( dlg.ShowModal() == wxID_OK )
2463 {
2464 if( m_tuningPattern )
2465 applyCommonSettings( m_tuningPattern );
2466
2467 updateTuningPattern();
2468 }
2469 }
2470 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2471 // but we don't at present have that, so we just knock out some of the egregious ones.
2472 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
2473 {
2474 wxBell();
2475 }
2476 else
2477 {
2478 evt->SetPassEvent();
2479 }
2480
2481 controls->CaptureCursor( m_tuningPattern != nullptr );
2482 controls->SetAutoPan( m_tuningPattern != nullptr );
2483 }
2484
2485 controls->CaptureCursor( false );
2486 controls->SetAutoPan( false );
2487 controls->ForceCursorPosition( false );
2488 controls->ShowCursor( false );
2489 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2490
2491 m_preview.FreeItems();
2492 m_view->Remove( &m_preview );
2493
2494 m_frame->GetCanvas()->Refresh();
2495
2496 if( m_tuningPattern )
2497 selectionTool->AddItemToSel( m_tuningPattern );
2498
2499 m_frame->PopTool( aEvent );
2500 return 0;
2501}
2502
2503
2505{
2507 {
2509 .Map( LENGTH_TUNING_MODE::SINGLE, _HKI( "Single track" ) )
2510 .Map( LENGTH_TUNING_MODE::DIFF_PAIR, _HKI( "Differential pair" ) )
2511 .Map( LENGTH_TUNING_MODE::DIFF_PAIR_SKEW, _HKI( "Diff pair skew" ) );
2512
2514 .Map( PNS::MEANDER_SIDE_LEFT, _HKI( "Left" ) )
2515 .Map( PNS::MEANDER_SIDE_RIGHT, _HKI( "Right" ) )
2516 .Map( PNS::MEANDER_SIDE_DEFAULT, _HKI( "Default" ) );
2517
2524
2526
2527 if( layerEnum.Choices().GetCount() == 0 )
2528 {
2529 layerEnum.Undefined( UNDEFINED_LAYER );
2530
2531 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
2532 layerEnum.Map( layer, LSET::Name( layer ) );
2533 }
2534
2537 layer->SetChoices( layerEnum.Choices() );
2538 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
2539
2540 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Width" ),
2543
2546
2547 const wxString groupTechLayers = _HKI( "Technical Layers" );
2548
2549 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Soldermask" ),
2551 groupTechLayers );
2552
2553 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
2557 groupTechLayers );
2558
2559 const wxString groupTab = _HKI( "Pattern Properties" );
2560
2561 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "End X" ),
2564 groupTab );
2565
2566 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "End Y" ),
2569 groupTab );
2570
2574 groupTab );
2575
2576 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Min Amplitude" ),
2579 groupTab );
2580
2581 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Max Amplitude" ),
2584 groupTab );
2585
2588 groupTab );
2589
2590 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Min Spacing" ),
2593 groupTab );
2594
2595 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Corner Radius %" ),
2599 groupTab );
2600
2601 auto isSkew =
2602 []( INSPECTABLE* aItem ) -> bool
2603 {
2604 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2605 return pattern->GetTuningMode() == DIFF_PAIR_SKEW;
2606
2607 return false;
2608 };
2609
2610 auto isTimeDomain = []( INSPECTABLE* aItem ) -> bool
2611 {
2612 if( PCB_TUNING_PATTERN* pattern = dynamic_cast<PCB_TUNING_PATTERN*>( aItem ) )
2613 return pattern->GetSettings().m_isTimeDomain;
2614
2615 return false;
2616 };
2617
2618 auto isLengthIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2619 {
2620 return !isSkew( aItem ) && !isTimeDomain( aItem );
2621 };
2622
2623 auto isLengthIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2624 {
2625 return !isSkew( aItem ) && isTimeDomain( aItem );
2626 };
2627
2628 auto isSkewIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool
2629 {
2630 return isSkew( aItem ) && !isTimeDomain( aItem );
2631 };
2632
2633 auto isSkewIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool
2634 {
2635 return isSkew( aItem ) && isTimeDomain( aItem );
2636 };
2637
2638 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>( _HKI( "Target Length" ),
2641 groupTab )
2642 .SetAvailableFunc( isLengthIsSpaceDomain );
2643
2644 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>( _HKI( "Target Delay" ),
2647 groupTab )
2648 .SetAvailableFunc( isLengthIsTimeDomain );
2649
2650 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Target Skew" ),
2653 groupTab )
2654 .SetAvailableFunc( isSkewIsSpaceDomain );
2655
2656 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Target Skew Delay" ),
2659 groupTab )
2660 .SetAvailableFunc( isSkewIsTimeDomain );
2661
2662 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Override Custom Rules" ),
2665 groupTab );
2666
2667 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Single-sided" ),
2669 groupTab );
2670
2671 propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Rounded" ),
2673 groupTab );
2674 }
2676
2679
2681
2682// Also register under the 7.99 name
2683template <typename T>
2685{
2687 {
2688 GENERATORS_MGR::Instance().Register( wxS( "meanders" ), T::DISPLAY_NAME,
2689 []()
2690 {
2691 return new T;
2692 } );
2693 }
2694};
2695
int red
int green
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
constexpr int ARC_LOW_DEF
Definition base_units.h:128
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int GetDRCEpsilon() const
Return an epsilon which accounts for rounding errors, etc.
PNS::MEANDER_SETTINGS m_DiffPairMeanderSettings
PNS::MEANDER_SETTINGS m_SingleTrackMeanderSettings
PNS::MEANDER_SETTINGS m_SkewMeanderSettings
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:85
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:236
PCB_LAYER_ID m_layer
Definition board_item.h:458
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
virtual wxString LayerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition board.cpp:2429
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:2902
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2362
const TRACKS & Tracks() const
Definition board.h:361
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1084
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:194
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:186
bool GetOption(OPTIONS option) const
Definition drc_rule.h:219
bool IsNull() const
Definition drc_rule.h:181
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:147
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:149
bool IsSelected() const
Definition eda_item.h:127
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:151
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:150
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:727
static ENUM_MAP< T > & Instance()
Definition property.h:721
ENUM_MAP & Undefined(T aValue)
Definition property.h:734
wxPGChoices & Choices()
Definition property.h:770
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:352
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:324
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
A factory which returns an instance of a PCB_GENERATOR.
void Register(const wxString &aTypeStr, const wxString &aName, std::function< PCB_GENERATOR *(void)> aCreateFunc)
Associate a type string to display name and create function.
static GENERATORS_MGR & Instance()
const std::vector< GENERATOR_PNS_CHANGES > & GetRouterChanges()
Handle actions specific to filling copper zones.
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h: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, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
Draw a string.
Definition font.cpp:250
static const METRICS & Default()
Definition font.cpp:52
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:312
void ToHSL(double &aOutHue, double &aOutSaturation, double &aOutLightness) const
Converts current color (stored in RGB) to HSL format.
Definition color4d.cpp:313
Abstract interface for drawing on a 2D-surface.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
virtual void Restore()
Restore the context.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
virtual void Scale(const VECTOR2D &aScale)
Scale the context.
virtual void Save()
Save the context.
A KIGFX::PREVIEW::DRAW_CONTEXT is a wrapper around a GAL and some other settings that makes it easy t...
void DrawLineDashed(const VECTOR2I &aStart, const VECTOR2I &aEn, int aDashStep, int aDashFill, bool aDeEmphasised)
Draw a dashed line on the current layer.
An interface for classes handling user events controlling the view behavior such as zooming,...
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h: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:468
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1644
static const LSET & AllLayersMask()
Definition lset.cpp:641
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition matrix3x3.h:295
bool IsNull() const
Definition minoptmax.h:45
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition netclass.cpp:294
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:347
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:154
const VECTOR2I & GetEnd() const
Definition pcb_track.h:151
virtual int GetWidth() const
Definition pcb_track.h:148
void SetTargetSkew(int aValue)
bool initBaseLines(PNS::ROUTER *aRouter, int aPNSLayer, BOARD *aBoard)
const STRING_ANY_MAP GetProperties() const override
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
void SetMinAmplitude(int aValue)
void SetSpacing(int aValue)
static const wxString DISPLAY_NAME
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
PNS::ROUTER_MODE GetPNSMode()
bool initBaseLine(PNS::ROUTER *aRouter, int aPNSLayer, BOARD *aBoard, VECTOR2I &aStart, VECTOR2I &aEnd, NETINFO_ITEM *aNet, std::optional< SHAPE_LINE_CHAIN > &aBaseLine)
void SetTargetSkewDelay(int aValue)
PCB_TUNING_PATTERN(BOARD_ITEM *aParent=nullptr, PCB_LAYER_ID aLayer=F_Cu, LENGTH_TUNING_MODE aMode=LENGTH_TUNING_MODE::SINGLE)
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
bool recoverBaseline(PNS::ROUTER *aRouter)
void SetWidth(int aValue)
PNS::MEANDER_SIDE GetInitialSide() const
std::optional< int > GetLocalSolderMaskMargin() const
void SetInitialSide(PNS::MEANDER_SIDE aValue)
wxString GetFriendlyName() const override
void SetTargetDelay(std::optional< int > aValue)
LENGTH_TUNING_MODE GetTuningMode() const
void SetHasSolderMask(bool aVal)
std::optional< int > GetTargetDelay() const
std::vector< EDA_ITEM * > GetPreviewItems(GENERATOR_TOOL *aTool, PCB_BASE_EDIT_FRAME *aFrame, bool aStatusItemsOnly=false) override
void EditStart(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
void SetOverrideCustomRules(bool aOverride)
void SetRounded(bool aFlag)
LENGTH_TUNING_MODE m_tuningMode
static const wxString GENERATOR_TYPE
bool resetToBaseline(GENERATOR_TOOL *aTool, int aPNSLayer, SHAPE_LINE_CHAIN &aBaseLine, bool aPrimary)
bool MakeEditPoints(EDIT_POINTS &points) const override
void SetCornerRadiusPercentage(int aValue)
PNS::MEANDER_PLACER_BASE::TUNING_STATUS m_tuningStatus
std::optional< SHAPE_LINE_CHAIN > m_baseLineCoupled
void SetProperties(const STRING_ANY_MAP &aProps) override
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override final
Draw the parts of the object belonging to layer aLayer.
void Remove(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool UpdateFromEditPoints(EDIT_POINTS &aEditPoints) override
std::optional< SHAPE_LINE_CHAIN > m_baseLine
PNS::MEANDER_SETTINGS m_settings
void SetEndX(int aValue)
void ShowPropertiesDialog(PCB_BASE_EDIT_FRAME *aEditFrame) override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
bool Update(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
void SetNetCode(int aNetCode)
bool UpdateEditPoints(EDIT_POINTS &aEditPoints) override
void EditCancel(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
bool GetOverrideCustomRules() const
void SetMaxAmplitude(int aValue)
PNS::MEANDER_SETTINGS & GetSettings()
void SetSingleSided(bool aValue)
bool removeToBaseline(PNS::ROUTER *aRouter, int aPNSLayer, SHAPE_LINE_CHAIN &aBaseLine)
std::optional< int > GetTargetLength() const
void EditFinish(GENERATOR_TOOL *aTool, BOARD *aBoard, BOARD_COMMIT *aCommit) override
int GetCornerRadiusPercentage() const
SHAPE_LINE_CHAIN getOutline() const
void SetEndY(int aValue)
void SetTargetLength(std::optional< int > aValue)
static PCB_TUNING_PATTERN * CreateNew(GENERATOR_TOOL *aTool, PCB_BASE_EDIT_FRAME *aFrame, BOARD_CONNECTED_ITEM *aStartItem, LENGTH_TUNING_MODE aMode)
SHAPE_ARC & Arc()
Definition pns_arc.h:115
Differential Pair length-matching/meandering tool.
std::vector< ITEM * > & Items()
Definition pns_itemset.h:87
Base class for PNS router board items.
Definition pns_item.h:98
virtual NET_HANDLE Net() const
Definition pns_item.h:210
void SetNet(NET_HANDLE aNet)
Definition pns_item.h:209
void SetLayer(int aLayer)
Definition pns_item.h:215
void SetParent(BOARD_ITEM *aParent)
Definition pns_item.h:191
bool OfKind(int aKindMask) const
Definition pns_item.h:181
virtual VECTOR2I Anchor(int n) const
Definition pns_item.h:268
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
const SHAPE_LINE_CHAIN & CLine() const
Definition pns_line.h:142
SHAPE_LINE_CHAIN & Line()
Definition pns_line.h:141
void SetWidth(int aWidth)
Return line width.
Definition pns_line.h:155
virtual int Width() const
Base class for Single trace & Differential pair meandering tools, as both of them share a lot of code...
virtual void UpdateSettings(const MEANDER_SETTINGS &aSettings)
TUNING_STATUS
< Result of the length tuning operation
virtual void SpacingStep(int aSign)
Increase/decrease the current meandering spacing by one step.
virtual TUNING_STATUS TuningStatus() const =0
Return the tuning status (too short, too long, etc.) of the trace(s) being tuned.
virtual const MEANDER_SETTINGS & MeanderSettings() const
Return the current meandering configuration.
virtual void AmplitudeStep(int aSign)
Increase/decreases the current meandering amplitude by one step.
virtual long long int TuningLengthResult() const =0
Return the resultant length or skew of the tuned traces.
Dimensions for the meandering algorithm.
Definition pns_meander.h:70
void SetTargetLength(long long int aOpt)
bool m_isTimeDomain
The net class this meander pattern belongs to.
static const long long int LENGTH_UNCONSTRAINED
Definition pns_meander.h:73
void SetTargetLengthDelay(long long int aOpt)
MINOPTMAX< long long int > m_targetLength
Desired propagation delay of the tuned line.
void SetTargetSkew(int aOpt)
MINOPTMAX< int > m_targetSkew
Target skew value for diff pair de-skewing.
int m_maxAmplitude
Meandering period/spacing (see dialog picture for explanation).
Definition pns_meander.h:98
bool m_overrideCustomRules
Type of corners for the meandered line.
void SetTargetSkewDelay(int aOpt)
static const long long int DELAY_UNCONSTRAINED
Definition pns_meander.h:76
int m_spacing
Amplitude/spacing adjustment step.
Keep the router "world" - i.e.
Definition pns_node.h:240
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:155
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition pns_node.cpp:695
std::set< OBSTACLE > OBSTACLES
Definition pns_node.h:252
const LINE AssembleLine(LINKED_ITEM *aSeg, int *aOriginSegmentIndex=nullptr, bool aStopAtLockedJoints=false, bool aFollowLockedSegments=false, bool aAllowSegmentSizeMismatch=true)
Follow the joint map to assemble a line connecting two non-trivial joints starting from segment aSeg.
int QueryColliding(const ITEM *aItem, OBSTACLES &aObstacles, const COLLISION_SEARCH_OPTIONS &aOpts=COLLISION_SEARCH_OPTIONS()) const
Find items colliding (closer than clearance) with the item aItem.
Definition pns_node.cpp:267
void Remove(ARC *aArc)
Remove an item from this branch.
Definition pns_node.cpp:939
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:113
ROUTER * Router() const
PNS_KICAD_IFACE * GetInterface() const
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
void EraseView() override
wxString GetNetName(PNS::NET_HANDLE aNet) const override
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & ReplaceProperty(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:746
VECTOR2I::extended_type ecoord
Definition seg.h:44
VECTOR2I B
Definition seg.h:50
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition seg.cpp:633
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition seg.h:143
int AddItemToSel(const TOOL_EVENT &aEvent)
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:120
VECTOR2I NearestPoint(const VECTOR2I &aP) const
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of the line chain.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
int Split(const VECTOR2I &aP, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
bool OffsetLine(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, SHAPE_LINE_CHAIN &aLeft, SHAPE_LINE_CHAIN &aRight, bool aSimplify=false) const
Creates line chains aLeft and aRight offset to this line chain.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void OffsetLineChain(const SHAPE_LINE_CHAIN &aLine, int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify)
Perform offsetting of a line chain.
int OutlineCount() const
Return the number of outlines in the set.
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Definition shape.h:232
A name/value tuple with unique names and wxAny values.
void set_iu(const std::string &aKey, const T &aVar)
bool get_to(const std::string &aKey, T &aVar) const
std::optional< T > get_opt(const std::string &aKey) const
void set(const std::string &aKey, const T &aVar)
bool get_to_iu(const std::string &aKey, T &aVar) const
GR_TEXT_H_ALIGN_T m_Halign
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition tool_base.h:146
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:38
Generic, UI-independent tool event.
Definition tool_event.h:171
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
VECTOR2D GetMousePosition() const
APP_SETTINGS_BASE * GetSettings() const
KIGFX::VIEW * GetView() const
void SetIsTimeDomain(const bool aIsTimeDomain)
void SetCurrent(const double aCurrent, const wxString &aLabel)
wxString GetClass() const override
Return the class name.
VECTOR2I GetPosition() const override
void SetMinMax(const double aMin, const double aMax)
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
TUNING_STATUS_VIEW_ITEM(PCB_BASE_EDIT_FRAME *aFrame)
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
void SetPosition(const VECTOR2I &aPos) override
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString MessageTextFromMinOptMax(const MINOPTMAX< int > &aValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
PCB_TUNING_PATTERN * m_pattern
UNLOCKER(PCB_TUNING_PATTERN *aPattern)
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
Definition vector2d.h:569
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:76
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
@ ROUND_ALL_CORNERS
All angles are rounded.
@ ARROW
Definition cursors.h:46
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ SKEW_CONSTRAINT
Definition drc_rule.h:72
#define _(s)
#define IS_NEW
New item, just created.
#define IN_EDIT
Item currently edited.
EDA_DATA_TYPE
The type of unit.
Definition eda_units.h:38
EDA_UNITS
Definition eda_units.h:48
@ IGNORE_GRID
static FILENAME_RESOLVER * resolver
a few functions useful in geometry calculations.
@ LAYER_UI_START
Definition layer_ids.h:357
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
KICOMMON_API wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
TEXT_DIMS GetConstantGlyphHeight(KIGFX::GAL *aGal, int aRelativeSize=0)
Set the GAL glyph height to a constant scaled value, so that it always looks the same on screen.
Push and Shove diff pair dimensions (gap) settings dialog.
MEANDER_SIDE
Definition pns_meander.h:60
@ MEANDER_SIDE_RIGHT
Definition pns_meander.h:63
@ MEANDER_SIDE_DEFAULT
Definition pns_meander.h:62
@ MEANDER_SIDE_LEFT
Definition pns_meander.h:61
@ MEANDER_STYLE_ROUND
Definition pns_meander.h:54
@ MEANDER_STYLE_CHAMFER
Definition pns_meander.h:55
ROUTER_MODE
Definition pns_router.h: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:74
#define NO_SETTER(owner, type)
Definition property.h:828
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:823
@ PT_DEFAULT
Default property for a given type.
Definition property.h:62
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
@ PT_NET
Net selection property.
Definition property.h:70
@ PT_TIME
Time expressed in ps.
Definition property.h:69
#define REGISTER_TYPE(x)
constexpr double correction
const double epsilon
#define PNS_HOVER_ITEM
#define PNS_COLLISION
#define HITTEST_THRESHOLD_PIXELS
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition pns_node.h:73
bool m_IsTimeDomain
Definition pns_node.h:80
MINOPTMAX< int > m_Value
Definition pns_node.h:75
Hold an object colliding with another object, along with some useful data about the collision.
Definition pns_node.h:88
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