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