KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_track.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) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2012 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include "pcb_track.h"
24
25#include <pcb_base_frame.h>
26#include <core/mirror.h>
28#include <board.h>
31#include <base_units.h>
32#include <layer_range.h>
34#include <lset.h>
35#include <cstdlib>
36#include <string_utils.h>
37#include <view/view.h>
41#include <geometry/seg.h>
44#include <geometry/shape_arc.h>
45#include <drc/drc_engine.h>
46#include <pcb_painter.h>
47#include <trigo.h>
49#include <properties/property.h>
51
52#include <google/protobuf/any.pb.h>
53#include <api/api_enums.h>
54#include <api/api_utils.h>
55#include <api/api_pcb_utils.h>
56#include <api/board/board_types.pb.h>
57
60
62 BOARD_CONNECTED_ITEM( aParent, idtype )
63{
64 m_width = pcbIUScale.mmToIU( 0.2 ); // Gives a reasonable default width
65 m_hasSolderMask = false;
66}
67
68
70{
71 return new PCB_TRACK( *this );
72}
73
74
75void PCB_TRACK::CopyFrom( const BOARD_ITEM* aOther )
76{
77 wxCHECK( aOther && aOther->Type() == PCB_TRACE_T, /* void */ );
78 *this = *static_cast<const PCB_TRACK*>( aOther );
79}
80
81
82PCB_ARC::PCB_ARC( BOARD_ITEM* aParent, const SHAPE_ARC* aArc ) :
83 PCB_TRACK( aParent, PCB_ARC_T )
84{
85 m_Start = aArc->GetP0();
86 m_End = aArc->GetP1();
87 m_Mid = aArc->GetArcMid();
88}
89
90
92{
93 return new PCB_ARC( *this );
94}
95
96
97void PCB_ARC::CopyFrom( const BOARD_ITEM* aOther )
98{
99 wxCHECK( aOther && aOther->Type() == PCB_ARC_T, /* void */ );
100 *this = *static_cast<const PCB_ARC*>( aOther );
101}
102
103
105 PCB_TRACK( aParent, PCB_VIA_T ),
106 m_padStack( this )
107{
109 Padstack().Drill().start = F_Cu;
110 Padstack().Drill().end = B_Cu;
112
113 m_padStack.SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::KEEP_ALL );
114
115 // Padstack layerset is not used for vias right now
116 m_padStack.LayerSet().reset();
117
118 // For now, vias are always circles
120
123
124 m_isFree = false;
125}
126
127
128PCB_VIA::PCB_VIA( const PCB_VIA& aOther ) :
129 PCB_TRACK( aOther.GetParent(), PCB_VIA_T ),
130 m_padStack( this )
131{
132 PCB_VIA::operator=( aOther );
133
134 SetUuidDirect( aOther.m_Uuid );
136}
137
138
140{
142
143 m_Start = aOther.m_Start;
144 m_End = aOther.m_End;
145
146 m_viaType = aOther.m_viaType;
147 m_padStack = aOther.m_padStack;
148 m_isFree = aOther.m_isFree;
149
150 return *this;
151}
152
153
154void PCB_VIA::CopyFrom( const BOARD_ITEM* aOther )
155{
156 wxCHECK( aOther && aOther->Type() == PCB_VIA_T, /* void */ );
157 *this = *static_cast<const PCB_VIA*>( aOther );
158}
159
160
162{
163 return new PCB_VIA( *this );
164}
165
166
167wxString PCB_VIA::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
168{
169 wxString formatStr;
170
171 switch( GetViaType() )
172 {
173 case VIATYPE::BLIND: formatStr = _( "Blind via %s on %s" ); break;
174 case VIATYPE::BURIED: formatStr = _( "Buried via %s on %s" ); break;
175 case VIATYPE::MICROVIA: formatStr = _( "Micro via %s on %s" ); break;
176 default: formatStr = _( "Via %s on %s" ); break;
177 }
178
179 return wxString::Format( formatStr, GetNetnameMsg(), LayerMaskDescribe() );
180}
181
182
184{
185 return BITMAPS::via;
186}
187
188
189bool PCB_TRACK::operator==( const BOARD_ITEM& aBoardItem ) const
190{
191 if( aBoardItem.Type() != Type() )
192 return false;
193
194 const PCB_TRACK& other = static_cast<const PCB_TRACK&>( aBoardItem );
195
196 return *this == other;
197}
198
199
200bool PCB_TRACK::operator==( const PCB_TRACK& aOther ) const
201{
202 return m_Start == aOther.m_Start
203 && m_End == aOther.m_End
204 && m_layer == aOther.m_layer
205 && m_width == aOther.m_width
208}
209
210
211double PCB_TRACK::Similarity( const BOARD_ITEM& aOther ) const
212{
213 if( aOther.Type() != Type() )
214 return 0.0;
215
216 const PCB_TRACK& other = static_cast<const PCB_TRACK&>( aOther );
217
218 double similarity = 1.0;
219
220 if( m_layer != other.m_layer )
221 similarity *= 0.9;
222
223 if( m_width != other.m_width )
224 similarity *= 0.9;
225
226 if( m_Start != other.m_Start )
227 similarity *= 0.9;
228
229 if( m_End != other.m_End )
230 similarity *= 0.9;
231
232 if( m_hasSolderMask != other.m_hasSolderMask )
233 similarity *= 0.9;
234
236 similarity *= 0.9;
237
238 return similarity;
239}
240
241
242bool PCB_ARC::operator==( const BOARD_ITEM& aBoardItem ) const
243{
244 if( aBoardItem.Type() != Type() )
245 return false;
246
247 const PCB_ARC& other = static_cast<const PCB_ARC&>( aBoardItem );
248
249 return *this == other;
250}
251
252
253bool PCB_ARC::operator==( const PCB_TRACK& aOther ) const
254{
255 if( aOther.Type() != Type() )
256 return false;
257
258 const PCB_ARC& other = static_cast<const PCB_ARC&>( aOther );
259
260 return *this == other;
261}
262
263
264bool PCB_ARC::operator==( const PCB_ARC& aOther ) const
265{
266 return m_Start == aOther.m_Start
267 && m_End == aOther.m_End
268 && m_Mid == aOther.m_Mid
269 && m_layer == aOther.m_layer
270 && GetWidth() == aOther.GetWidth()
273}
274
275
276double PCB_ARC::Similarity( const BOARD_ITEM& aOther ) const
277{
278 if( aOther.Type() != Type() )
279 return 0.0;
280
281 const PCB_ARC& other = static_cast<const PCB_ARC&>( aOther );
282
283 double similarity = 1.0;
284
285 if( m_layer != other.m_layer )
286 similarity *= 0.9;
287
288 if( GetWidth() != other.GetWidth() )
289 similarity *= 0.9;
290
291 if( m_Start != other.m_Start )
292 similarity *= 0.9;
293
294 if( m_End != other.m_End )
295 similarity *= 0.9;
296
297 if( m_Mid != other.m_Mid )
298 similarity *= 0.9;
299
300 if( m_hasSolderMask != other.m_hasSolderMask )
301 similarity *= 0.9;
302
304 similarity *= 0.9;
305
306 return similarity;
307}
308
309
310bool PCB_VIA::operator==( const BOARD_ITEM& aBoardItem ) const
311{
312 if( aBoardItem.Type() != Type() )
313 return false;
314
315 const PCB_VIA& other = static_cast<const PCB_VIA&>( aBoardItem );
316
317 return *this == other;
318}
319
320
321bool PCB_VIA::operator==( const PCB_TRACK& aOther ) const
322{
323 if( aOther.Type() != Type() )
324 return false;
325
326 const PCB_VIA& other = static_cast<const PCB_VIA&>( aOther );
327
328 return *this == other;
329}
330
331
332bool PCB_VIA::operator==( const PCB_VIA& aOther ) const
333{
334 return m_Start == aOther.m_Start
335 && m_End == aOther.m_End
336 && m_layer == aOther.m_layer
337 && m_padStack == aOther.m_padStack
338 && m_viaType == aOther.m_viaType
340}
341
342
343double PCB_VIA::Similarity( const BOARD_ITEM& aOther ) const
344{
345 if( aOther.Type() != Type() )
346 return 0.0;
347
348 const PCB_VIA& other = static_cast<const PCB_VIA&>( aOther );
349
350 double similarity = 1.0;
351
352 if( m_layer != other.m_layer )
353 similarity *= 0.9;
354
355 if( m_Start != other.m_Start )
356 similarity *= 0.9;
357
358 if( m_End != other.m_End )
359 similarity *= 0.9;
360
361 if( m_padStack != other.m_padStack )
362 similarity *= 0.9;
363
364 if( m_viaType != other.m_viaType )
365 similarity *= 0.9;
366
368 similarity *= 0.9;
369
370 return similarity;
371}
372
373
374void PCB_VIA::SetWidth( int aWidth )
375{
376 m_padStack.SetSize( { aWidth, aWidth }, PADSTACK::ALL_LAYERS );
377}
378
379
381{
382 // This is present because of the parent class. It should never be actually called on a via.
383 wxCHECK_MSG( false, m_padStack.Size( PADSTACK::ALL_LAYERS ).x, "Warning: PCB_VIA::GetWidth called without a layer argument" );
384}
385
386
387void PCB_VIA::SetWidth( PCB_LAYER_ID aLayer, int aWidth )
388{
389 m_padStack.SetSize( { aWidth, aWidth }, aLayer );
390}
391
392
394{
395 return m_padStack.Size( aLayer ).x;
396}
397
398
399void PCB_TRACK::Serialize( google::protobuf::Any &aContainer ) const
400{
401 kiapi::board::types::Track track;
402
403 track.mutable_id()->set_value( m_Uuid.AsStdString() );
404 track.mutable_start()->set_x_nm( GetStart().x );
405 track.mutable_start()->set_y_nm( GetStart().y );
406 track.mutable_end()->set_x_nm( GetEnd().x );
407 track.mutable_end()->set_y_nm( GetEnd().y );
408 track.mutable_width()->set_value_nm( GetWidth() );
410 track.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
411 : kiapi::common::types::LockedState::LS_UNLOCKED );
412 PackNet( track.mutable_net() );
413 // TODO m_hasSolderMask and m_solderMaskMargin
414
415 aContainer.PackFrom( track );
416}
417
418
419bool PCB_TRACK::Deserialize( const google::protobuf::Any &aContainer )
420{
421 kiapi::board::types::Track track;
422
423 if( !aContainer.UnpackTo( &track ) )
424 return false;
425
426 SetUuidDirect( KIID( track.id().value() ) );
427 SetStart( VECTOR2I( track.start().x_nm(), track.start().y_nm() ) );
428 SetEnd( VECTOR2I( track.end().x_nm(), track.end().y_nm() ) );
429 SetWidth( track.width().value_nm() );
431 UnpackNet( track.net() );
432 SetLocked( track.locked() == kiapi::common::types::LockedState::LS_LOCKED );
433 // TODO m_hasSolderMask and m_solderMaskMargin
434
435 return true;
436}
437
438
439void PCB_ARC::Serialize( google::protobuf::Any &aContainer ) const
440{
441 kiapi::board::types::Arc arc;
442
443 arc.mutable_id()->set_value( m_Uuid.AsStdString() );
444 arc.mutable_start()->set_x_nm( GetStart().x );
445 arc.mutable_start()->set_y_nm( GetStart().y );
446 arc.mutable_mid()->set_x_nm( GetMid().x );
447 arc.mutable_mid()->set_y_nm( GetMid().y );
448 arc.mutable_end()->set_x_nm( GetEnd().x );
449 arc.mutable_end()->set_y_nm( GetEnd().y );
450 arc.mutable_width()->set_value_nm( GetWidth() );
452 arc.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
453 : kiapi::common::types::LockedState::LS_UNLOCKED );
454 PackNet( arc.mutable_net() );
455 // TODO m_hasSolderMask and m_solderMaskMargin
456
457 aContainer.PackFrom( arc );
458}
459
460
461bool PCB_ARC::Deserialize( const google::protobuf::Any &aContainer )
462{
463 kiapi::board::types::Arc arc;
464
465 if( !aContainer.UnpackTo( &arc ) )
466 return false;
467
468 SetUuidDirect( KIID( arc.id().value() ) );
469 SetStart( VECTOR2I( arc.start().x_nm(), arc.start().y_nm() ) );
470 SetMid( VECTOR2I( arc.mid().x_nm(), arc.mid().y_nm() ) );
471 SetEnd( VECTOR2I( arc.end().x_nm(), arc.end().y_nm() ) );
472 SetWidth( arc.width().value_nm() );
474 UnpackNet( arc.net() );
475 SetLocked( arc.locked() == kiapi::common::types::LockedState::LS_LOCKED );
476 // TODO m_hasSolderMask and m_solderMaskMargin
477
478 return true;
479}
480
481
482void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
483{
484 kiapi::board::types::Via via;
485
486 via.mutable_id()->set_value( m_Uuid.AsStdString() );
487 via.mutable_position()->set_x_nm( GetPosition().x );
488 via.mutable_position()->set_y_nm( GetPosition().y );
489
490 PADSTACK padstack = Padstack();
491
492 google::protobuf::Any padStackWrapper;
493 padstack.Serialize( padStackWrapper );
494 padStackWrapper.UnpackTo( via.mutable_pad_stack() );
495
496 // PADSTACK::m_layerSet is not used by vias
497 via.mutable_pad_stack()->clear_layers();
498 kiapi::board::PackLayerSet( *via.mutable_pad_stack()->mutable_layers(), GetLayerSet() );
499
501 via.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
502 : kiapi::common::types::LockedState::LS_UNLOCKED );
503 PackNet( via.mutable_net() );
504
505 aContainer.PackFrom( via );
506}
507
508
509bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
510{
511 kiapi::board::types::Via via;
512
513 if( !aContainer.UnpackTo( &via ) )
514 return false;
515
516 SetUuidDirect( KIID( via.id().value() ) );
517 SetStart( VECTOR2I( via.position().x_nm(), via.position().y_nm() ) );
518 SetEnd( GetStart() );
519
520 google::protobuf::Any padStackWrapper;
521 padStackWrapper.PackFrom( via.pad_stack() );
522
523 if( !m_padStack.Deserialize( padStackWrapper ) )
524 return false;
525
526 // PADSTACK::m_layerSet is not used by vias
527 m_padStack.LayerSet().reset();
528
530 UnpackNet( via.net() );
531 SetLocked( via.locked() == kiapi::common::types::LockedState::LS_LOCKED );
532
533 return true;
534}
535
536
538{
539 SEG a( m_Start, m_End );
540 SEG b( aTrack.GetStart(), aTrack.GetEnd() );
541 return a.ApproxCollinear( b );
542}
543
544
546{
547 DRC_CONSTRAINT constraint;
548
549 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
550 {
552
553 constraint = bds.m_DRCEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, this, nullptr, m_layer );
554 }
555
556 if( aSource )
557 *aSource = constraint.GetName();
558
559 return constraint.Value();
560}
561
562
564{
565 DRC_CONSTRAINT constraint;
566
567 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
568 {
570
571 constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, this, nullptr, m_layer );
572 }
573
574 if( aSource )
575 *aSource = constraint.GetName();
576
577 return constraint.Value();
578}
579
580
582{
583 DRC_CONSTRAINT constraint;
584
585 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
586 {
588
589 constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, this, nullptr, m_layer );
590 }
591
592 if( aSource )
593 *aSource = constraint.GetName();
594
595 return constraint.Value();
596}
597
598
599int PCB_VIA::GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const
600{
601 if( !FlashLayer( aLayer ) )
602 {
603 if( aSource )
604 *aSource = _( "removed annular ring" );
605
606 return 0;
607 }
608
609 DRC_CONSTRAINT constraint;
610
611 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
612 {
614
615 constraint = bds.m_DRCEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, this, nullptr, aLayer );
616 }
617
618 if( constraint.Value().HasMin() )
619 {
620 if( aSource )
621 *aSource = constraint.GetName();
622
623 return constraint.Value().Min();
624 }
625
626 return 0;
627}
628
629
631{
632 m_padStack.Drill().size = aSize;
633}
634
635
637{
638 m_padStack.Drill().shape = aShape;
639}
640
641
643{
644 m_padStack.Drill().start = aLayer;
645}
646
647
649{
650 m_padStack.Drill().end = aLayer;
651}
652
653
654void PCB_VIA::SetFrontPostMachining( const std::optional<PAD_DRILL_POST_MACHINING_MODE>& aMode )
655{
656 m_padStack.FrontPostMachining().mode = aMode;
657}
658
659
660void PCB_VIA::SetBackPostMachining( const std::optional<PAD_DRILL_POST_MACHINING_MODE>& aMode )
661{
662 m_padStack.BackPostMachining().mode = aMode;
663}
664
665
666void PCB_VIA::SetPrimaryDrillFilled( const std::optional<bool>& aFilled )
667{
668 m_padStack.Drill().is_filled = aFilled;
669}
670
671
673{
674 m_padStack.Drill().is_filled = aFilled;
675}
676
677
678void PCB_VIA::SetPrimaryDrillCapped( const std::optional<bool>& aCapped )
679{
680 m_padStack.Drill().is_capped = aCapped;
681}
682
683
685{
686 m_padStack.Drill().is_capped = aCapped;
687}
688
689
691{
692 if( m_padStack.Drill().size.x > 0 ) // Use the specific value.
693 return m_padStack.Drill().size.x;
694
695 // Use the default value from the Netclass
696 NETCLASS* netclass = GetEffectiveNetClass();
697
699 return netclass->GetuViaDrill();
700
701 return netclass->GetViaDrill();
702}
703
704
706{
707 m_padStack.SecondaryDrill().size = aSize;
708}
709
710
712{
713 m_padStack.SecondaryDrill().size = { 0, 0 };
714}
715
716
717void PCB_VIA::SetSecondaryDrillSize( const std::optional<int>& aDrill )
718{
719 if( aDrill.has_value() && *aDrill > 0 )
720 SetSecondaryDrillSize( { *aDrill, *aDrill } );
721 else
723}
724
725
726std::optional<int> PCB_VIA::GetSecondaryDrillSize() const
727{
728 if( m_padStack.SecondaryDrill().size.x > 0 )
729 return m_padStack.SecondaryDrill().size.x;
730
731 return std::nullopt;
732}
733
734
736{
737 m_padStack.SecondaryDrill().start = aLayer;
738}
739
740
742{
743 m_padStack.SecondaryDrill().end = aLayer;
744}
745
746
748{
749 m_padStack.SecondaryDrill().shape = aShape;
750}
751
752
754{
755 m_padStack.TertiaryDrill().size = aSize;
756}
757
758
760{
761 m_padStack.TertiaryDrill().size = { 0, 0 };
762}
763
764
765void PCB_VIA::SetTertiaryDrillSize( const std::optional<int>& aDrill )
766{
767 if( aDrill.has_value() && *aDrill > 0 )
768 SetTertiaryDrillSize( { *aDrill, *aDrill } );
769 else
771}
772
773
774std::optional<int> PCB_VIA::GetTertiaryDrillSize() const
775{
776 if( m_padStack.TertiaryDrill().size.x > 0 )
777 return m_padStack.TertiaryDrill().size.x;
778
779 return std::nullopt;
780}
781
782
784{
785 m_padStack.TertiaryDrill().start = aLayer;
786}
787
788
790{
791 m_padStack.TertiaryDrill().end = aLayer;
792}
793
794
796{
797 m_padStack.TertiaryDrill().shape = aShape;
798}
799
800
802{
803 if( !IsCopperLayer( aLayer ) )
804 return false;
805
806 const BOARD* board = GetBoard();
807
808 if( !board )
809 return false;
810
811 // Check secondary drill (backdrill from top)
812 const PADSTACK::DRILL_PROPS& secondaryDrill = m_padStack.SecondaryDrill();
813
814 if( secondaryDrill.size.x > 0 && secondaryDrill.start != UNDEFINED_LAYER
815 && secondaryDrill.end != UNDEFINED_LAYER )
816 {
817 // Contains honours copper Z-order; the range iterator instead walks PCB_LAYER_ID enum
818 // order, which for a bottom-anchored span spans the wrong (top inner) layers.
819 if( LAYER_RANGE::Contains( secondaryDrill.start, secondaryDrill.end, aLayer ) )
820 return true;
821 }
822
823 // Check tertiary drill (backdrill from bottom)
824 const PADSTACK::DRILL_PROPS& tertiaryDrill = m_padStack.TertiaryDrill();
825
826 if( tertiaryDrill.size.x > 0 && tertiaryDrill.start != UNDEFINED_LAYER
827 && tertiaryDrill.end != UNDEFINED_LAYER )
828 {
829 if( LAYER_RANGE::Contains( tertiaryDrill.start, tertiaryDrill.end, aLayer ) )
830 return true;
831 }
832
833 // Check if the layer is affected by post-machining
834 if( GetPostMachiningKnockout( aLayer ) > 0 )
835 return true;
836
837 return false;
838}
839
840
842{
843 if( !IsCopperLayer( aLayer ) )
844 return 0;
845
846 const BOARD* board = GetBoard();
847
848 if( !board )
849 return 0;
850
851 const BOARD_STACKUP& stackup = board->GetDesignSettings().GetStackupDescriptor();
852
853 // Check front post-machining (counterbore/countersink from top)
854 const PADSTACK::POST_MACHINING_PROPS& frontPM = m_padStack.FrontPostMachining();
855
856 if( frontPM.mode.has_value() && *frontPM.mode != PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED
857 && *frontPM.mode != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN && frontPM.size > 0 )
858 {
859 int pmDepth = frontPM.depth;
860
861 // For countersink without explicit depth, calculate from diameter and angle
862 if( pmDepth <= 0 && *frontPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK
863 && frontPM.angle > 0 )
864 {
865 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
866 pmDepth = static_cast<int>( ( frontPM.size / 2.0 ) / tan( halfAngleRad ) );
867 }
868
869 if( pmDepth > 0 )
870 {
871 // Calculate distance from F_Cu to aLayer
872 int layerDist = stackup.GetLayerDistance( F_Cu, aLayer );
873
874 if( layerDist < pmDepth )
875 {
876 // For countersink, diameter decreases with depth
877 if( *frontPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && frontPM.angle > 0 )
878 {
879 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
880 int diameterAtLayer = frontPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
881 return std::max( 0, diameterAtLayer );
882 }
883 else
884 {
885 // Counterbore - constant diameter
886 return frontPM.size;
887 }
888 }
889 }
890 }
891
892 // Check back post-machining (counterbore/countersink from bottom)
893 const PADSTACK::POST_MACHINING_PROPS& backPM = m_padStack.BackPostMachining();
894
895 if( backPM.mode.has_value() && *backPM.mode != PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED
896 && *backPM.mode != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN && backPM.size > 0 )
897 {
898 int pmDepth = backPM.depth;
899
900 // For countersink without explicit depth, calculate from diameter and angle
901 if( pmDepth <= 0 && *backPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK
902 && backPM.angle > 0 )
903 {
904 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
905 pmDepth = static_cast<int>( ( backPM.size / 2.0 ) / tan( halfAngleRad ) );
906 }
907
908 if( pmDepth > 0 )
909 {
910 // Calculate distance from B_Cu to aLayer
911 int layerDist = stackup.GetLayerDistance( B_Cu, aLayer );
912
913 if( layerDist < pmDepth )
914 {
915 // For countersink, diameter decreases with depth
916 if( *backPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && backPM.angle > 0 )
917 {
918 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
919 int diameterAtLayer = backPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
920 return std::max( 0, diameterAtLayer );
921 }
922 else
923 {
924 // Counterbore - constant diameter
925 return backPM.size;
926 }
927 }
928 }
929 }
930
931 return 0;
932}
933
934
935EDA_ITEM_FLAGS PCB_TRACK::IsPointOnEnds( const VECTOR2I& point, int min_dist ) const
936{
938
939 if( min_dist < 0 )
940 min_dist = m_width / 2;
941
942 if( min_dist == 0 )
943 {
944 if( m_Start == point )
946
947 if( m_End == point )
948 result |= ENDPOINT;
949 }
950 else
951 {
952 double dist = m_Start.Distance( point );
953
954 if( min_dist >= dist )
956
957 dist = m_End.Distance( point );
958
959 if( min_dist >= dist )
960 result |= ENDPOINT;
961 }
962
963 return result;
964}
965
966
968{
969 // end of track is round, this is its radius, rounded up
970 int radius = ( m_width + 1 ) / 2;
971 int ymax, xmax, ymin, xmin;
972
973 if( Type() == PCB_VIA_T )
974 {
975 ymax = m_Start.y;
976 xmax = m_Start.x;
977
978 ymin = m_Start.y;
979 xmin = m_Start.x;
980 }
981 else if( Type() == PCB_ARC_T )
982 {
983 std::shared_ptr<SHAPE> arc = GetEffectiveShape();
984 BOX2I bbox = arc->BBox();
985
986 xmin = bbox.GetLeft();
987 xmax = bbox.GetRight();
988 ymin = bbox.GetTop();
989 ymax = bbox.GetBottom();
990 }
991 else
992 {
993 ymax = std::max( m_Start.y, m_End.y );
994 xmax = std::max( m_Start.x, m_End.x );
995
996 ymin = std::min( m_Start.y, m_End.y );
997 xmin = std::min( m_Start.x, m_End.x );
998 }
999
1000 ymax += radius;
1001 xmax += radius;
1002
1003 ymin -= radius;
1004 xmin -= radius;
1005
1006 // return a rectangle which is [pos,dim) in nature. therefore the +1
1007 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1008 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1009}
1010
1011
1013{
1014 int radius = 0;
1015
1017 [&]( PCB_LAYER_ID aLayer )
1018 {
1019 radius = std::max( radius, GetWidth( aLayer ) );
1020 } );
1021
1022 // via is round, this is its radius, rounded up
1023 radius = ( radius + 1 ) / 2;
1024
1025 int ymax = m_Start.y + radius;
1026 int xmax = m_Start.x + radius;
1027
1028 int ymin = m_Start.y - radius;
1029 int xmin = m_Start.x - radius;
1030
1031 // return a rectangle which is [pos,dim) in nature. therefore the +1
1032 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1033 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1034}
1035
1036
1038{
1039 int radius = GetWidth( aLayer );
1040
1041 // via is round, this is its radius, rounded up
1042 radius = ( radius + 1 ) / 2;
1043
1044 int ymax = m_Start.y + radius;
1045 int xmax = m_Start.x + radius;
1046
1047 int ymin = m_Start.y - radius;
1048 int xmin = m_Start.x - radius;
1049
1050 // return a rectangle which is [pos,dim) in nature. therefore the +1
1051 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1052 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1053}
1054
1055
1057{
1058 return m_Start.Distance( m_End );
1059}
1060
1061
1063{
1064 const BOARD* board = GetBoard();
1065
1066 if( !board )
1067 return 0.0;
1068
1069 const LENGTH_DELAY_CALCULATION* calc = board->GetLengthCalculation();
1070 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items{ calc->GetLengthCalculationItem( this ) };
1071 constexpr PATH_OPTIMISATIONS opts = { .OptimiseVias = false,
1072 .MergeTracks = false,
1073 .OptimiseTracesInPads = false,
1074 .InferViaInPad = false
1075 };
1076
1077 return (double) calc->CalculateDelay( items, opts );
1078}
1079
1080
1081void PCB_TRACK::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1082{
1083 RotatePoint( m_Start, aRotCentre, aAngle );
1084 RotatePoint( m_End, aRotCentre, aAngle );
1085}
1086
1087
1088void PCB_ARC::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1089{
1090 RotatePoint( m_Start, aRotCentre, aAngle );
1091 RotatePoint( m_End, aRotCentre, aAngle );
1092 RotatePoint( m_Mid, aRotCentre, aAngle );
1093}
1094
1095
1096void PCB_TRACK::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1097{
1098 MIRROR( m_Start, aCentre, aFlipDirection );
1099 MIRROR( m_End, aCentre, aFlipDirection );
1100}
1101
1102
1103void PCB_ARC::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1104{
1105 MIRROR( m_Start, aCentre, aFlipDirection );
1106 MIRROR( m_End, aCentre, aFlipDirection );
1107 MIRROR( m_Mid, aCentre, aFlipDirection );
1108}
1109
1110
1111void PCB_TRACK::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1112{
1113 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1114 {
1115 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1116 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1117 }
1118 else
1119 {
1120 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1121 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1122 }
1123
1125}
1126
1127
1128void PCB_ARC::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1129{
1130 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1131 {
1132 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1133 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1134 m_Mid.x = aCentre.x - ( m_Mid.x - aCentre.x );
1135 }
1136 else
1137 {
1138 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1139 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1140 m_Mid.y = aCentre.y - ( m_Mid.y - aCentre.y );
1141 }
1142
1144}
1145
1146
1147bool PCB_ARC::IsCCW() const
1148{
1149 VECTOR2L start = m_Start;
1150 VECTOR2L start_end = m_End - start;
1151 VECTOR2L start_mid = m_Mid - start;
1152
1153 return start_end.Cross( start_mid ) < 0;
1154}
1155
1156
1157void PCB_VIA::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1158{
1159 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1160 {
1161 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1162 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1163 }
1164 else
1165 {
1166 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1167 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1168 }
1169
1170 if( GetViaType() != VIATYPE::THROUGH )
1171 {
1172 PCB_LAYER_ID top_layer;
1173 PCB_LAYER_ID bottom_layer;
1174 LayerPair( &top_layer, &bottom_layer );
1175 top_layer = GetBoard()->FlipLayer( top_layer );
1176 bottom_layer = GetBoard()->FlipLayer( bottom_layer );
1177 SetLayerPair( top_layer, bottom_layer );
1178 }
1179}
1180
1181
1182INSPECT_RESULT PCB_TRACK::Visit( INSPECTOR inspector, void* testData,
1183 const std::vector<KICAD_T>& aScanTypes )
1184{
1185 for( KICAD_T scanType : aScanTypes )
1186 {
1187 if( scanType == Type() )
1188 {
1189 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
1190 return INSPECT_RESULT::QUIT;
1191 }
1192 }
1193
1195}
1196
1197
1198std::shared_ptr<SHAPE_SEGMENT> PCB_VIA::GetEffectiveHoleShape() const
1199{
1200 return std::make_shared<SHAPE_SEGMENT>( SEG( m_Start, m_Start ), Padstack().Drill().size.x );
1201}
1202
1203// clang-format off: the suggestion is slightly less readable
1205{
1206 switch( aMode )
1207 {
1208 case TENTING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_solder_mask.reset(); break;
1209 case TENTING_MODE::TENTED: m_padStack.FrontOuterLayers().has_solder_mask = true; break;
1210 case TENTING_MODE::NOT_TENTED: m_padStack.FrontOuterLayers().has_solder_mask = false; break;
1211 }
1212}
1213
1214
1216{
1217 if( m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
1218 {
1219 return *m_padStack.FrontOuterLayers().has_solder_mask ? TENTING_MODE::TENTED
1221 }
1222
1224}
1225
1226
1228{
1229 switch( aMode )
1230 {
1231 case TENTING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_solder_mask.reset(); break;
1232 case TENTING_MODE::TENTED: m_padStack.BackOuterLayers().has_solder_mask = true; break;
1233 case TENTING_MODE::NOT_TENTED: m_padStack.BackOuterLayers().has_solder_mask = false; break;
1234 }
1235}
1236
1237
1239{
1240 if( m_padStack.BackOuterLayers().has_solder_mask.has_value() )
1241 {
1242 return *m_padStack.BackOuterLayers().has_solder_mask ? TENTING_MODE::TENTED
1244 }
1245
1247}
1248
1249
1251{
1252 switch( aMode )
1253 {
1254 case COVERING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_covering.reset(); break;
1255 case COVERING_MODE::COVERED: m_padStack.FrontOuterLayers().has_covering = true; break;
1256 case COVERING_MODE::NOT_COVERED: m_padStack.FrontOuterLayers().has_covering = false; break;
1257 }
1258}
1259
1260
1262{
1263 if( m_padStack.FrontOuterLayers().has_covering.has_value() )
1264 {
1265 return *m_padStack.FrontOuterLayers().has_covering ? COVERING_MODE::COVERED
1267 }
1268
1270}
1271
1272
1274{
1275 switch( aMode )
1276 {
1277 case COVERING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_covering.reset(); break;
1278 case COVERING_MODE::COVERED: m_padStack.BackOuterLayers().has_covering = true; break;
1279 case COVERING_MODE::NOT_COVERED: m_padStack.BackOuterLayers().has_covering = false; break;
1280 }
1281}
1282
1283
1285{
1286 if( m_padStack.BackOuterLayers().has_covering.has_value() )
1287 {
1288 return *m_padStack.BackOuterLayers().has_covering ? COVERING_MODE::COVERED
1290 }
1291
1293}
1294
1295
1297{
1298 switch( aMode )
1299 {
1300 case PLUGGING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_plugging.reset(); break;
1301 case PLUGGING_MODE::PLUGGED: m_padStack.FrontOuterLayers().has_plugging = true; break;
1302 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.FrontOuterLayers().has_plugging = false; break;
1303 }
1304}
1305
1306
1308{
1309 if( m_padStack.FrontOuterLayers().has_plugging.has_value() )
1310 {
1311 return *m_padStack.FrontOuterLayers().has_plugging ? PLUGGING_MODE::PLUGGED
1313 }
1314
1316}
1317
1318
1320{
1321 switch( aMode )
1322 {
1323 case PLUGGING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_plugging.reset(); break;
1324 case PLUGGING_MODE::PLUGGED: m_padStack.BackOuterLayers().has_plugging = true; break;
1325 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.BackOuterLayers().has_plugging = false; break;
1326 }
1327}
1328
1329
1331{
1332 if( m_padStack.BackOuterLayers().has_plugging.has_value() )
1333 {
1334 return *m_padStack.BackOuterLayers().has_plugging ? PLUGGING_MODE::PLUGGED
1336 }
1337
1339}
1340
1341
1343{
1344 switch( aMode )
1345 {
1346 case CAPPING_MODE::FROM_BOARD: m_padStack.Drill().is_capped.reset(); break;
1347 case CAPPING_MODE::CAPPED: m_padStack.Drill().is_capped = true; break;
1348 case CAPPING_MODE::NOT_CAPPED: m_padStack.Drill().is_capped = false; break;
1349 }
1350}
1351
1352
1354{
1355 if( m_padStack.Drill().is_capped.has_value() )
1356 {
1357 return *m_padStack.Drill().is_capped ? CAPPING_MODE::CAPPED
1359 }
1360
1362}
1363
1364
1366{
1367 switch( aMode )
1368 {
1369 case FILLING_MODE::FROM_BOARD: m_padStack.Drill().is_filled.reset(); break;
1370 case FILLING_MODE::FILLED: m_padStack.Drill().is_filled = true; break;
1371 case FILLING_MODE::NOT_FILLED: m_padStack.Drill().is_filled = false; break;
1372 }
1373}
1374
1375
1377{
1378 if( m_padStack.Drill().is_filled.has_value() )
1379 {
1380 return *m_padStack.Drill().is_filled ? FILLING_MODE::FILLED
1382 }
1383
1385}
1386
1387
1389{
1390 wxCHECK_MSG( IsFrontLayer( aLayer ) || IsBackLayer( aLayer ), true,
1391 "Invalid layer passed to IsTented" );
1392
1393 bool front = IsFrontLayer( aLayer );
1394
1395 if( front && m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
1396 return *m_padStack.FrontOuterLayers().has_solder_mask;
1397
1398 if( !front && m_padStack.BackOuterLayers().has_solder_mask.has_value() )
1399 return *m_padStack.BackOuterLayers().has_solder_mask;
1400
1401 if( const BOARD* board = GetBoard() )
1402 {
1403 return front ? board->GetDesignSettings().m_TentViasFront
1404 : board->GetDesignSettings().m_TentViasBack;
1405 }
1406
1407 return true;
1408}
1409
1410
1412{
1413 if( const BOARD* board = GetBoard() )
1414 return board->GetDesignSettings().m_SolderMaskExpansion;
1415 else
1416 return 0;
1417}
1418
1419
1421{
1422 int margin = 0;
1423
1424 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine
1425 && GetBoard()->GetDesignSettings().m_DRCEngine->HasRulesForConstraintType(
1427 {
1428 DRC_CONSTRAINT constraint;
1429 std::shared_ptr<DRC_ENGINE> drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1430
1431 constraint = drcEngine->EvalRules( SOLDER_MASK_EXPANSION_CONSTRAINT, this, nullptr, m_layer );
1432
1433 if( constraint.m_Value.HasOpt() )
1434 margin = constraint.m_Value.Opt();
1435 }
1436 else if( m_solderMaskMargin.has_value() )
1437 {
1438 margin = m_solderMaskMargin.value();
1439 }
1440 else if( const BOARD* board = GetBoard() )
1441 {
1442 margin = board->GetDesignSettings().m_SolderMaskExpansion;
1443 }
1444
1445 // Ensure the resulting mask opening has a non-negative size
1446 if( margin < 0 )
1447 margin = std::max( margin, -m_width / 2 );
1448
1449 return margin;
1450}
1451
1452
1454{
1455 if( aLayer == m_layer )
1456 {
1457 return true;
1458 }
1459
1460 if( m_hasSolderMask && ( ( aLayer == F_Mask && m_layer == F_Cu )
1461 || ( aLayer == B_Mask && m_layer == B_Cu ) ) )
1462 {
1463 return true;
1464 }
1465
1466 return false;
1467}
1468
1469
1471{
1472#if 0
1473 // Nice and simple, but raises its ugly head in performance profiles....
1474 return GetLayerSet().test( aLayer );
1475#endif
1476 if( IsCopperLayer( aLayer ) &&
1477 LAYER_RANGE::Contains( Padstack().Drill().start, Padstack().Drill().end, aLayer ) )
1478 {
1479 return true;
1480 }
1481
1482 // Test for via on mask layers: a via on on a mask layer if not tented and if
1483 // it is on the corresponding external copper layer
1484 if( aLayer == F_Mask )
1485 return Padstack().Drill().start == F_Cu && !IsTented( F_Mask );
1486 else if( aLayer == B_Mask )
1487 return Padstack().Drill().end == B_Cu && !IsTented( B_Mask );
1488
1489 return false;
1490}
1491
1492
1493bool PCB_VIA::HasValidLayerPair( int aCopperLayerCount )
1494{
1495 // return true if top and bottom layers are valid, depending on the copper layer count
1496 // aCopperLayerCount is expected >= 2
1497
1498 int layer_id = aCopperLayerCount*2;
1499
1500 if( Padstack().Drill().start > B_Cu )
1501 {
1502 if( Padstack().Drill().start > layer_id )
1503 return false;
1504 }
1505 if( Padstack().Drill().end > B_Cu )
1506 {
1507 if( Padstack().Drill().end > layer_id )
1508 return false;
1509 }
1510
1511 return true;
1512}
1513
1514
1516{
1517 return Padstack().Drill().start;
1518}
1519
1520
1522{
1523 Padstack().Drill().start = aLayer;
1524}
1525
1526
1527void PCB_TRACK::SetLayerSet( const LSET& aLayerSet )
1528{
1529 aLayerSet.RunOnLayers(
1530 [&]( PCB_LAYER_ID layer )
1531 {
1532 if( IsCopperLayer( layer ) )
1533 SetLayer( layer );
1534 else if( IsSolderMaskLayer( layer ) )
1535 SetHasSolderMask( true );
1536 } );
1537}
1538
1539
1541{
1542 LSET layermask( { m_layer } );
1543
1544 if( m_hasSolderMask )
1545 {
1546 if( layermask.test( F_Cu ) )
1547 layermask.set( F_Mask );
1548 else if( layermask.test( B_Cu ) )
1549 layermask.set( B_Mask );
1550 }
1551
1552 return layermask;
1553}
1554
1555
1557{
1558 LSET layermask;
1559
1560 if( Padstack().Drill().start < PCBNEW_LAYER_ID_START )
1561 return layermask;
1562
1563 if( GetViaType() == VIATYPE::THROUGH )
1564 {
1565 layermask = LSET::AllCuMask( BoardCopperLayerCount() );
1566 }
1567 else
1568 {
1569 LAYER_RANGE range( Padstack().Drill().start, Padstack().Drill().end, BoardCopperLayerCount() );
1570
1571 int cnt = BoardCopperLayerCount();
1572 // PCB_LAYER_IDs are numbered from front to back, this is top to bottom.
1573 for( PCB_LAYER_ID id : range )
1574 {
1575 layermask.set( id );
1576
1577 if( --cnt <= 0 )
1578 break;
1579 }
1580 }
1581
1582 if( !IsTented( F_Mask ) && layermask.test( F_Cu ) )
1583 layermask.set( F_Mask );
1584
1585 if( !IsTented( B_Mask ) && layermask.test( B_Cu ) )
1586 layermask.set( B_Mask );
1587
1588 return layermask;
1589}
1590
1591
1592void PCB_VIA::SetLayerSet( const LSET& aLayerSet )
1593{
1594 // Vias do not use a LSET, just a top and bottom layer pair
1595 // So we need to set these 2 layers according to the allowed layers in aLayerSet
1596
1597 // For via through, only F_Cu and B_Cu are allowed. aLayerSet is ignored
1598 if( GetViaType() == VIATYPE::THROUGH )
1599 {
1600 Padstack().Drill().start = F_Cu;
1601 Padstack().Drill().end = B_Cu;
1602 return;
1603 }
1604
1605 // For blind buried vias, find the top and bottom layers
1606 bool top_found = false;
1607 bool bottom_found = false;
1608
1609 aLayerSet.RunOnLayers(
1610 [&]( PCB_LAYER_ID layer )
1611 {
1612 // tpo layer and bottom Layer are copper layers, so consider only copper layers
1613 if( IsCopperLayer( layer ) )
1614 {
1615 // The top layer is the first layer found in list and
1616 // cannot the B_Cu
1617 if( !top_found && layer != B_Cu )
1618 {
1619 Padstack().Drill().start = layer;
1620 top_found = true;
1621 }
1622
1623 // The bottom layer is the last layer found in list or B_Cu
1624 if( !bottom_found )
1625 Padstack().Drill().end = layer;
1626
1627 if( layer == B_Cu )
1628 bottom_found = true;
1629 }
1630 } );
1631}
1632
1633
1634void PCB_VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer )
1635{
1636 Padstack().Drill().start = aTopLayer;
1637 Padstack().Drill().end = aBottomLayer;
1639
1640 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1641 {
1642 if( BOARD* board = GetBoard() )
1643 board->InvalidateClearanceCache( m_Uuid );
1644 }
1645}
1646
1647
1649{
1650 // refuse invalid via
1651 if( aLayer == Padstack().Drill().end )
1652 return;
1653
1654 Padstack().Drill().start = aLayer;
1656
1657 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1658 {
1659 if( BOARD* board = GetBoard() )
1660 board->InvalidateClearanceCache( m_Uuid );
1661 }
1662}
1663
1664
1666{
1667 // refuse invalid via
1668 if( aLayer == Padstack().Drill().start )
1669 return;
1670
1671 Padstack().Drill().end = aLayer;
1673
1674 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1675 {
1676 if( BOARD* board = GetBoard() )
1677 board->InvalidateClearanceCache( m_Uuid );
1678 }
1679}
1680
1681
1682void PCB_VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) const
1683{
1684 PCB_LAYER_ID t_layer = F_Cu;
1685 PCB_LAYER_ID b_layer = B_Cu;
1686
1687 if( GetViaType() != VIATYPE::THROUGH )
1688 {
1689 b_layer = Padstack().Drill().end;
1690 t_layer = Padstack().Drill().start;
1691
1692 if( !IsCopperLayerLowerThan( b_layer, t_layer ) )
1693 std::swap( b_layer, t_layer );
1694 }
1695
1696 if( top_layer )
1697 *top_layer = t_layer;
1698
1699 if( bottom_layer )
1700 *bottom_layer = b_layer;
1701}
1702
1703
1705{
1706 return Padstack().Drill().start;
1707}
1708
1709
1711{
1712 return Padstack().Drill().end;
1713}
1714
1715
1717{
1718 if( GetViaType() == VIATYPE::THROUGH )
1719 {
1720 Padstack().Drill().start = F_Cu;
1721 Padstack().Drill().end = B_Cu;
1722 }
1723
1724 if( !IsCopperLayerLowerThan( Padstack().Drill().end, Padstack().Drill().start) )
1725 std::swap( Padstack().Drill().end, Padstack().Drill().start );
1726
1727 int copperCount = BoardCopperLayerCount();
1728
1729 auto sanitizeBackdrill =
1730 [copperCount]( PADSTACK::DRILL_PROPS& aDrill )
1731 {
1732 if( aDrill.start != UNDEFINED_LAYER && !IsCopperLayer( aDrill.start ) )
1733 aDrill.start = UNDEFINED_LAYER;
1734
1735 if( aDrill.end != UNDEFINED_LAYER && !IsCopperLayer( aDrill.end ) )
1736 aDrill.end = UNDEFINED_LAYER;
1737
1738 if( copperCount > 0 )
1739 {
1740 LSET cuMask = LSET::AllCuMask( copperCount );
1741
1742 if( aDrill.start != UNDEFINED_LAYER && !cuMask.Contains( aDrill.start ) )
1743 aDrill.start = UNDEFINED_LAYER;
1744
1745 if( aDrill.end != UNDEFINED_LAYER && !cuMask.Contains( aDrill.end ) )
1746 aDrill.end = UNDEFINED_LAYER;
1747 }
1748
1749 // A must-cut equal to the entry layer is a zero-depth backdrill, which is not
1750 // manufacturable. The drill exporter requires the must-cut to be strictly deeper.
1751 if( aDrill.start != UNDEFINED_LAYER && aDrill.start == aDrill.end )
1752 aDrill.end = UNDEFINED_LAYER;
1753
1754 // A backdrill side with no must-cut layer does not exist.
1755 if( aDrill.end == UNDEFINED_LAYER )
1756 aDrill.size = { 0, 0 };
1757 };
1758
1759 sanitizeBackdrill( Padstack().SecondaryDrill() );
1760 sanitizeBackdrill( Padstack().TertiaryDrill() );
1761}
1762
1763
1764std::optional<PCB_VIA::VIA_PARAMETER_ERROR>
1765PCB_VIA::ValidateViaParameters( std::optional<int> aDiameter,
1766 std::optional<int> aPrimaryDrill,
1767 std::optional<PCB_LAYER_ID> aPrimaryStartLayer,
1768 std::optional<PCB_LAYER_ID> aPrimaryEndLayer,
1769 std::optional<int> aSecondaryDrill,
1770 std::optional<PCB_LAYER_ID> aSecondaryStartLayer,
1771 std::optional<PCB_LAYER_ID> aSecondaryEndLayer,
1772 std::optional<int> aTertiaryDrill,
1773 std::optional<PCB_LAYER_ID> aTertiaryStartLayer,
1774 std::optional<PCB_LAYER_ID> aTertiaryEndLayer,
1775 int aCopperLayerCount )
1776{
1777 VIA_PARAMETER_ERROR error;
1778
1779 if( aDiameter.has_value() && aDiameter.value() < GEOMETRY_MIN_SIZE )
1780 {
1781 error.m_Message = _( "Via diameter is too small." );
1783 return error;
1784 }
1785
1786 if( aPrimaryDrill.has_value() && aPrimaryDrill.value() < GEOMETRY_MIN_SIZE )
1787 {
1788 error.m_Message = _( "Via drill is too small." );
1790 return error;
1791 }
1792
1793 if( aDiameter.has_value() && !aPrimaryDrill.has_value() )
1794 {
1795 error.m_Message = _( "No via hole size defined." );
1797 return error;
1798 }
1799
1800 if( aPrimaryDrill.has_value() && !aDiameter.has_value() )
1801 {
1802 error.m_Message = _( "No via diameter defined." );
1804 return error;
1805 }
1806
1807 if( aDiameter.has_value() && aPrimaryDrill.has_value()
1808 && aDiameter.value() <= aPrimaryDrill.value() )
1809 {
1810 error.m_Message = _( "Via hole size must be smaller than via diameter" );
1812 return error;
1813 }
1814
1815 std::optional<LSET> copperMask;
1816
1817 auto validateLayer = [&]( std::optional<PCB_LAYER_ID> aLayer,
1818 VIA_PARAMETER_ERROR::FIELD aField ) -> bool
1819 {
1820 if( !aLayer.has_value() )
1821 return true;
1822
1823 PCB_LAYER_ID layer = aLayer.value();
1824
1825 if( layer == UNDEFINED_LAYER )
1826 return true;
1827
1828 if( !IsCopperLayer( layer ) )
1829 {
1830 error.m_Message = _( "Via layer must be a copper layer." );
1831 error.m_Field = aField;
1832 return false;
1833 }
1834
1835 if( aCopperLayerCount > 0 )
1836 {
1837 if( !copperMask.has_value() )
1838 copperMask = LSET::AllCuMask( aCopperLayerCount );
1839
1840 if( !copperMask->Contains( layer ) )
1841 {
1842 error.m_Message = _( "Via layer is outside the board stack." );
1843 error.m_Field = aField;
1844 return false;
1845 }
1846 }
1847
1848 return true;
1849 };
1850
1851 if( !validateLayer( aPrimaryStartLayer, VIA_PARAMETER_ERROR::FIELD::START_LAYER ) )
1852 return error;
1853
1854 if( !validateLayer( aPrimaryEndLayer, VIA_PARAMETER_ERROR::FIELD::END_LAYER ) )
1855 return error;
1856
1857 if( aPrimaryStartLayer.has_value() && aPrimaryEndLayer.has_value()
1858 && aPrimaryStartLayer.value() == aPrimaryEndLayer.value() )
1859 {
1860 error.m_Message = _( "Via start layer and end layer cannot be the same" );
1862 return error;
1863 }
1864
1865 if( aSecondaryDrill.has_value() )
1866 {
1867 if( aSecondaryDrill.value() < aPrimaryDrill.value_or( GEOMETRY_MIN_SIZE ) )
1868 {
1869 error.m_Message = _( "Backdrill diameter is too small." );
1871 return error;
1872 }
1873
1874 if( !validateLayer( aSecondaryStartLayer, VIA_PARAMETER_ERROR::FIELD::SECONDARY_START_LAYER ) )
1875 return error;
1876
1877 if( !validateLayer( aSecondaryEndLayer, VIA_PARAMETER_ERROR::FIELD::SECONDARY_END_LAYER ) )
1878 return error;
1879 }
1880
1881 if( aTertiaryDrill.has_value() )
1882 {
1883 if( aTertiaryDrill.value() < aPrimaryDrill.value_or( GEOMETRY_MIN_SIZE ) )
1884 {
1885 error.m_Message = _( "Tertiary backdrill diameter is too small." );
1887 return error;
1888 }
1889
1890 if( !validateLayer( aTertiaryStartLayer, VIA_PARAMETER_ERROR::FIELD::TERTIARY_START_LAYER ) )
1891 return error;
1892
1893 if( !validateLayer( aTertiaryEndLayer, VIA_PARAMETER_ERROR::FIELD::TERTIARY_END_LAYER ) )
1894 return error;
1895 }
1896
1897 return std::nullopt;
1898}
1899
1900
1902{
1903 return m_viaType == VIATYPE::MICROVIA;
1904}
1905
1906
1908{
1909 // We don't actually have an GUI or file tokens to differentiate these, so we have to look at
1910 // the layers.
1912 {
1913 bool startOuter = Padstack().Drill().start == F_Cu || Padstack().Drill().start == B_Cu;
1914 bool endOuter = Padstack().Drill().end == F_Cu || Padstack().Drill().end == B_Cu;
1915
1916 return startOuter ^ endOuter;
1917 }
1918
1919 return false;
1920}
1921
1922
1924{
1925 // We don't actually have an GUI or file tokens to differentiate these, so we have to look at
1926 // the layers.
1928 {
1929 return Padstack().Drill().start != F_Cu && Padstack().Drill().start != B_Cu
1930 && Padstack().Drill().end != F_Cu && Padstack().Drill().end != B_Cu;
1931 }
1932
1933 return false;
1934}
1935
1936
1937bool PCB_VIA::FlashLayer( const LSET& aLayers ) const
1938{
1939 for( PCB_LAYER_ID layer : aLayers )
1940 {
1941 if( FlashLayer( layer ) )
1942 return true;
1943 }
1944
1945 return false;
1946}
1947
1948
1949bool PCB_VIA::FlashLayer( int aLayer ) const
1950{
1951 // Return the "normal" shape if the caller doesn't specify a particular layer
1952 if( aLayer == UNDEFINED_LAYER )
1953 return true;
1954
1955 const BOARD* board = GetBoard();
1956 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer );
1957
1958 if( !board )
1959 return true;
1960
1961 if( !IsOnLayer( layer ) )
1962 return false;
1963
1964 if( !IsCopperLayer( layer ) )
1965 return true;
1966
1967 switch( Padstack().UnconnectedLayerMode() )
1968 {
1970 return true;
1971
1973 if( layer == Padstack().Drill().start || layer == Padstack().Drill().end )
1974 return true;
1975
1976 // Check for removal below
1977 break;
1978
1980 // Check for removal below
1981 break;
1982
1984 return layer == Padstack().Drill().start || layer == Padstack().Drill().end;
1985 }
1986
1987 if( GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
1988 {
1989 return true;
1990 }
1991 else
1992 {
1993 // Must be static to keep from raising its ugly head in performance profiles
1994 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
1995 PCB_PAD_T };
1996
1997 return board->GetConnectivity()->IsConnectedOnLayer( this, layer, nonZoneTypes );
1998 }
1999}
2000
2001
2003{
2004 std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
2005
2008}
2009
2010
2012{
2013 static const ZONE_LAYER_OVERRIDE defaultOverride = ZLO_NONE;
2014 auto it = m_zoneLayerOverrides.find( aLayer );
2015 return it != m_zoneLayerOverrides.end() ? it->second : defaultOverride;
2016}
2017
2018
2020{
2021 std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
2022 m_zoneLayerOverrides[aLayer] = aOverride;
2023}
2024
2025
2027 PCB_LAYER_ID* aBottommost ) const
2028{
2029 *aTopmost = UNDEFINED_LAYER;
2030 *aBottommost = UNDEFINED_LAYER;
2031
2032 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
2033 PCB_PAD_T };
2034
2035 for( int layer = TopLayer(); layer <= BottomLayer(); ++layer )
2036 {
2037 bool connected = false;
2038
2039 if( GetZoneLayerOverride( static_cast<PCB_LAYER_ID>( layer ) ) == ZLO_FORCE_FLASHED )
2040 {
2041 connected = true;
2042 }
2043 else if( GetBoard()->GetConnectivity()->IsConnectedOnLayer( this, layer, nonZoneTypes ) )
2044 {
2045 connected = true;
2046 }
2047
2048 if( connected )
2049 {
2050 if( *aTopmost == UNDEFINED_LAYER )
2051 *aTopmost = ToLAYER_ID( layer );
2052
2053 *aBottommost = ToLAYER_ID( layer );
2054 }
2055 }
2056
2057}
2058
2059
2060std::vector<int> PCB_TRACK::ViewGetLayers() const
2061{
2062 // Show the track and its netname on different layers
2063 const PCB_LAYER_ID layer = GetLayer();
2064 std::vector<int> layers{
2065 layer,
2066 GetNetnameLayer( layer ),
2067 LAYER_CLEARANCE_START + layer,
2068 };
2069
2070 layers.reserve( 6 );
2071
2072 if( m_hasSolderMask )
2073 {
2074 if( m_layer == F_Cu )
2075 layers.push_back( F_Mask );
2076 else if( m_layer == B_Cu )
2077 layers.push_back( B_Mask );
2078 }
2079
2080 if( IsLocked() )
2081 layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
2082
2083 return layers;
2084}
2085
2086
2087double PCB_TRACK::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
2088{
2089 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
2090 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
2091
2092 if( !aView->IsLayerVisibleCached( LAYER_TRACKS ) )
2093 return LOD_HIDE;
2094
2095 if( IsNetnameLayer( aLayer ) )
2096 {
2098 return LOD_HIDE;
2099
2100 // Hide netnames on dimmed tracks
2101 if( renderSettings->GetHighContrast() )
2102 {
2103 if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
2104 return LOD_HIDE;
2105 }
2106
2107 VECTOR2I start( GetStart() );
2108 VECTOR2I end( GetEnd() );
2109
2110 // Calc the approximate size of the netname (assume square chars)
2111 SEG::ecoord nameSize = GetDisplayNetname().size() * GetWidth();
2112
2113 if( VECTOR2I( end - start ).SquaredEuclideanNorm() < nameSize * nameSize )
2114 return LOD_HIDE;
2115
2116 BOX2I clipBox = BOX2ISafe( aView->GetViewport() );
2117
2118 ClipLine( &clipBox, start.x, start.y, end.x, end.y );
2119
2120 if( VECTOR2I( end - start ).SquaredEuclideanNorm() == 0 )
2121 return LOD_HIDE;
2122
2123 // Netnames will be shown only if zoom is appropriate
2124 return lodScaleForThreshold( aView, m_width, pcbIUScale.mmToIU( 4.0 ) );
2125 }
2126
2127 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
2128 {
2129 // Hide shadow if the main layer is not shown
2130 if( !aView->IsLayerVisibleCached( m_layer ) )
2131 return LOD_HIDE;
2132
2133 // Hide shadow on dimmed tracks
2134 if( renderSettings->GetHighContrast() )
2135 {
2136 if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
2137 return LOD_HIDE;
2138 }
2139 }
2140
2141 // Other layers are shown without any conditions
2142 return LOD_SHOW;
2143}
2144
2145
2147{
2148 BOX2I bbox = GetBoundingBox();
2149
2150 if( const BOARD* board = GetBoard() )
2151 bbox.Inflate( 2 * board->GetDesignSettings().GetBiggestClearanceValue() );
2152 else
2153 bbox.Inflate( GetWidth() ); // Add a bit extra for safety
2154
2155 return bbox;
2156}
2157
2158
2159std::vector<int> PCB_VIA::ViewGetLayers() const
2160{
2161 LAYER_RANGE layers( Padstack().Drill().start, Padstack().Drill().end, MAX_CU_LAYERS );
2162 std::vector<int> ret_layers{ LAYER_VIA_HOLES, LAYER_VIA_HOLEWALLS, LAYER_VIA_NETNAMES };
2163 ret_layers.reserve( MAX_CU_LAYERS + 6 );
2164
2165 // TODO(JE) Rendering order issue
2166#if 0
2167 // Blind/buried vias (and microvias) use a different net name layer
2168 PCB_LAYER_ID layerTop, layerBottom;
2169 LayerPair( &layerTop, &layerBottom );
2170
2171 bool isBlindBuried =
2174 || ( m_viaType == VIATYPE::MICROVIA && ( layerTop != F_Cu || layerBottom != B_Cu ) );
2175#endif
2176 LSET cuMask = LSET::AllCuMask();
2177
2178 if( const BOARD* board = GetBoard() )
2179 cuMask &= board->GetEnabledLayers();
2180
2181 for( PCB_LAYER_ID layer : layers )
2182 {
2183 if( !cuMask.Contains( layer ) )
2184 continue;
2185
2186 ret_layers.push_back( LAYER_VIA_COPPER_START + layer );
2187 ret_layers.push_back( LAYER_CLEARANCE_START + layer );
2188 }
2189
2190 if( IsLocked() )
2191 ret_layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
2192
2193 // Vias can also be on a solder mask layer. They are on these layers or not,
2194 // depending on the plot and solder mask options
2195 if( IsOnLayer( F_Mask ) )
2196 ret_layers.push_back( F_Mask );
2197
2198 if( IsOnLayer( B_Mask ) )
2199 ret_layers.push_back( B_Mask );
2200
2201 return ret_layers;
2202}
2203
2204
2205double PCB_VIA::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
2206{
2207 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
2208 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
2209 const BOARD* board = GetBoard();
2210
2211 // Meta control for hiding all vias
2212 if( !aView->IsLayerVisibleCached( LAYER_VIAS ) )
2213 return LOD_HIDE;
2214
2215 // In high contrast mode don't show vias that don't cross the high-contrast layer
2216 if( renderSettings->GetHighContrast() )
2217 {
2218 PCB_LAYER_ID highContrastLayer = renderSettings->GetPrimaryHighContrastLayer();
2219
2220 if( LSET::FrontTechMask().Contains( highContrastLayer ) )
2221 highContrastLayer = F_Cu;
2222 else if( LSET::BackTechMask().Contains( highContrastLayer ) )
2223 highContrastLayer = B_Cu;
2224
2225 if( IsCopperLayer( highContrastLayer ) && GetViaType() != VIATYPE::THROUGH )
2226 {
2227 if( IsCopperLayerLowerThan( Padstack().Drill().start, highContrastLayer )
2228 || IsCopperLayerLowerThan( highContrastLayer, Padstack().Drill().end ) )
2229 {
2230 return LOD_HIDE;
2231 }
2232 }
2233 }
2234
2235 if( IsHoleLayer( aLayer ) )
2236 {
2237 LSET visible;
2238
2239 if( board )
2240 {
2241 visible = board->GetVisibleLayers();
2242 visible &= board->GetEnabledLayers();
2243 }
2244 else
2245 {
2246 visible = LSET::AllLayersMask();
2247 }
2248
2250 {
2251 // Show a through via's hole if any physical layer is shown
2252 visible &= LSET::PhysicalLayersMask();
2253
2254 if( !visible.any() )
2255 return LOD_HIDE;
2256 }
2257 else
2258 {
2259 // Show a blind or micro via's hole if it crosses a visible layer
2260 visible &= GetLayerSet();
2261
2262 if( !visible.any() )
2263 return LOD_HIDE;
2264 }
2265
2266 // The hole won't be visible anyway at this scale
2267 return lodScaleForThreshold( aView, GetDrillValue(), pcbIUScale.mmToIU( 0.25 ) );
2268 }
2269 else if( IsNetnameLayer( aLayer ) )
2270 {
2271 if( renderSettings->GetHighContrast() )
2272 {
2273 // Hide netnames unless via is flashed to a high-contrast layer
2274 if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
2275 return LOD_HIDE;
2276 }
2277 else
2278 {
2279 LSET visible;
2280
2281 if( board )
2282 {
2283 visible = board->GetVisibleLayers();
2284 visible &= board->GetEnabledLayers();
2285 }
2286 else
2287 {
2288 visible = LSET::AllLayersMask();
2289 }
2290
2291 // Hide netnames unless pad is flashed to a visible layer
2292 if( !FlashLayer( visible ) )
2293 return LOD_HIDE;
2294 }
2295
2296 int width = GetWidth( ToLAYER_ID( aLayer ) );
2297
2298 // Netnames will be shown only if zoom is appropriate
2299 return lodScaleForThreshold( aView, width, pcbIUScale.mmToIU( 10 ) );
2300 }
2301
2302 if( !IsCopperLayer( aLayer ) )
2303 {
2304 int width = GetWidth( ToLAYER_ID( aLayer ) );
2305
2306 return lodScaleForThreshold( aView, width, pcbIUScale.mmToIU( 0.6 ) );
2307 }
2308
2309 return LOD_SHOW;
2310}
2311
2312
2314{
2315 switch( Type() )
2316 {
2317 case PCB_ARC_T: return _( "Track (arc)" );
2318 case PCB_VIA_T: return _( "Via" );
2319 case PCB_TRACE_T:
2320 default: return _( "Track" );
2321 }
2322}
2323
2324
2325void PCB_TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2326{
2327 wxString msg;
2328 BOARD* board = GetBoard();
2329
2330 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2331
2332 GetMsgPanelInfoBase_Common( aFrame, aList );
2333
2334 aList.emplace_back( _( "Layer" ), LayerMaskDescribe() );
2335
2336 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( m_width ) );
2337
2338 if( Type() == PCB_ARC_T )
2339 {
2340 double radius = static_cast<PCB_ARC*>( this )->GetRadius();
2341 aList.emplace_back( _( "Radius" ), aFrame->MessageTextFromValue( radius ) );
2342
2343 aList.emplace_back( _( "Angle" ), wxString::Format( "%.2fdeg",
2344 static_cast<PCB_ARC*>(this)->GetAngle().AsDegrees() ) );
2345 }
2346
2347 double segmentLength = GetLength();
2348 double segmentDelay = GetDelay();
2349
2350 if( segmentDelay == 0.0 )
2351 {
2352 aList.emplace_back( _( "Segment Length" ), aFrame->MessageTextFromValue( segmentLength ) );
2353 }
2354 else
2355 {
2356 aList.emplace_back( _( "Segment Delay" ),
2357 aFrame->MessageTextFromValue( segmentDelay, true, EDA_DATA_TYPE::TIME ) );
2358 }
2359
2360 // Display full track length (in Pcbnew)
2361 if( board && GetNetCode() > 0 )
2362 {
2363 int count = 0;
2364 double trackLen = 0.0;
2365 double lenPadToDie = 0.0;
2366 double trackDelay = 0.0;
2367 double delayPadToDie = 0.0;
2368
2369 std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *this );
2370
2371 if( trackDelay == 0.0 )
2372 {
2373 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2374
2375 if( lenPadToDie != 0 )
2376 {
2377 msg = aFrame->MessageTextFromValue( lenPadToDie );
2378 aList.emplace_back( _( "Pad To Die Length" ), msg );
2379
2380 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2381 aList.emplace_back( _( "Full Length" ), msg );
2382 }
2383 }
2384 else
2385 {
2386 aList.emplace_back( _( "Routed Delay" ),
2387 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) );
2388
2389 if( delayPadToDie != 0.0 )
2390 {
2391 msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME );
2392 aList.emplace_back( _( "Pad To Die Delay" ), msg );
2393
2394 msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME );
2395 aList.emplace_back( _( "Full Delay" ), msg );
2396 }
2397 }
2398 }
2399
2400 SHAPE_POLY_SET copper;
2402 aList.emplace_back( _( "Copper Area" ),
2403 aFrame->MessageTextFromValue( copper.Area(), true, EDA_DATA_TYPE::AREA ) );
2404
2405 wxString source;
2406 int clearance = GetOwnClearance( GetLayer(), &source );
2407
2408 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2409 aFrame->MessageTextFromValue( clearance ) ),
2410 wxString::Format( _( "(from %s)" ), source ) );
2411
2412 MINOPTMAX<int> constraintValue = GetWidthConstraint( &source );
2413 msg = aFrame->MessageTextFromMinOptMax( constraintValue );
2414
2415 if( !msg.IsEmpty() )
2416 {
2417 aList.emplace_back( wxString::Format( _( "Width Constraints: %s" ), msg ),
2418 wxString::Format( _( "(from %s)" ), source ) );
2419 }
2420}
2421
2422
2423void PCB_VIA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2424{
2425 wxString msg;
2426
2427 switch( GetViaType() )
2428 {
2429 case VIATYPE::MICROVIA: msg = _( "Micro Via" ); break;
2430 case VIATYPE::BLIND: msg = _( "Blind Via" ); break;
2431 case VIATYPE::BURIED: msg = _( "Buried Via" ); break;
2432 case VIATYPE::THROUGH: msg = _( "Through Via" ); break;
2433 default: msg = _( "Via" ); break;
2434 }
2435
2436 aList.emplace_back( _( "Type" ), msg );
2437
2438 GetMsgPanelInfoBase_Common( aFrame, aList );
2439
2440 aList.emplace_back( _( "Layer" ), LayerMaskDescribe() );
2441 // TODO(JE) padstacks
2442 aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( GetWidth( PADSTACK::ALL_LAYERS ) ) );
2443 aList.emplace_back( _( "Hole" ), aFrame->MessageTextFromValue( GetDrillValue() ) );
2444
2445 wxString source;
2446 int clearance = GetOwnClearance( GetLayer(), &source );
2447
2448 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ), aFrame->MessageTextFromValue( clearance ) ),
2449 wxString::Format( _( "(from %s)" ), source ) );
2450
2451 int minAnnulus = GetMinAnnulus( GetLayer(), &source );
2452
2453 aList.emplace_back( wxString::Format( _( "Min Annular Width: %s" ), aFrame->MessageTextFromValue( minAnnulus ) ),
2454 wxString::Format( _( "(from %s)" ), source ) );
2455}
2456
2457
2458void PCB_TRACK::GetMsgPanelInfoBase_Common( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) const
2459{
2460 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
2461
2462 if( NETINFO_ITEM* netInfo = GetNet() )
2463 {
2464 const wxString& chainName = netInfo->GetNetChain();
2465
2466 if( !chainName.IsEmpty() )
2467 aList.emplace_back( _( "Net Chain" ), UnescapeString( chainName ) );
2468 }
2469
2470 aList.emplace_back( _( "Resolved Netclass" ),
2471 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
2472
2473#if 0 // Enable for debugging
2474 if( GetBoard() )
2475 aList.emplace_back( _( "NetCode" ), fmt::format( "{}", GetNetCode() ) );
2476
2477 aList.emplace_back( wxT( "Flags" ), fmt::format( "#08X", m_flags ) );
2478
2479 aList.emplace_back( wxT( "Start pos" ), fmt::format( "{} {}", m_Start.x, m_Start.y ) );
2480 aList.emplace_back( wxT( "End pos" ), fmt::format( "{} {}", m_End.x, m_End.y ) );
2481#endif
2482
2483 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
2484 aList.emplace_back( _( "Status" ), _( "Locked" ) );
2485}
2486
2487
2489{
2490 const BOARD* board = GetBoard();
2491 PCB_LAYER_ID top_layer;
2492 PCB_LAYER_ID bottom_layer;
2493
2494 LayerPair( &top_layer, &bottom_layer );
2495
2496 return board->GetLayerName( top_layer ) + wxT( " - " ) + board->GetLayerName( bottom_layer );
2497}
2498
2499
2500bool PCB_TRACK::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2501{
2502 return TestSegmentHit( aPosition, m_Start, m_End, aAccuracy + ( m_width / 2 ) );
2503}
2504
2505
2506bool PCB_ARC::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2507{
2508 double max_dist = aAccuracy + ( GetWidth() / 2.0 );
2509
2510 // Short-circuit common cases where the arc is connected to a track or via at an endpoint
2511 if( GetStart().Distance( aPosition ) <= max_dist || GetEnd().Distance( aPosition ) <= max_dist )
2512 {
2513 return true;
2514 }
2515
2517 VECTOR2L relpos = aPosition - center;
2518 int64_t dist = relpos.EuclideanNorm();
2519 double radius = GetRadius();
2520
2521 if( std::abs( dist - radius ) > max_dist )
2522 return false;
2523
2524 EDA_ANGLE arc_angle = GetAngle();
2525 EDA_ANGLE arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg
2526 EDA_ANGLE arc_hittest( relpos );
2527
2528 // Calculate relative angle between the starting point of the arc, and the test point
2529 arc_hittest -= arc_angle_start;
2530
2531 // Normalise arc_hittest between 0 ... 360 deg
2532 arc_hittest.Normalize();
2533
2534 if( arc_angle < ANGLE_0 )
2535 return arc_hittest >= ANGLE_360 + arc_angle;
2536
2537 return arc_hittest <= arc_angle;
2538}
2539
2540
2541bool PCB_VIA::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2542{
2543 bool hit = false;
2544
2546 [&]( PCB_LAYER_ID aLayer )
2547 {
2548 if( hit )
2549 return;
2550
2551 int max_dist = aAccuracy + ( GetWidth( aLayer ) / 2 );
2552
2553 // rel_pos is aPosition relative to m_Start (or the center of the via)
2554 VECTOR2D rel_pos = aPosition - m_Start;
2555 double dist = rel_pos.x * rel_pos.x + rel_pos.y * rel_pos.y;
2556
2557 if( dist <= static_cast<double>( max_dist ) * max_dist )
2558 hit = true;
2559 } );
2560
2561 return hit;
2562}
2563
2564
2565bool PCB_TRACK::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2566{
2567 BOX2I arect = aRect;
2568 arect.Inflate( aAccuracy );
2569
2570 if( aContained )
2571 return arect.Contains( GetStart() ) && arect.Contains( GetEnd() );
2572 else
2573 return arect.Intersects( GetStart(), GetEnd() );
2574}
2575
2576
2577bool PCB_ARC::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2578{
2579 BOX2I arect = aRect;
2580 arect.Inflate( aAccuracy );
2581
2582 BOX2I box( GetStart() );
2583 box.Merge( GetMid() );
2584 box.Merge( GetEnd() );
2585
2586 box.Inflate( GetWidth() / 2 );
2587
2588 if( aContained )
2589 return arect.Contains( box );
2590 else
2591 return arect.Intersects( box );
2592}
2593
2594
2595bool PCB_VIA::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2596{
2597 BOX2I arect = aRect;
2598 arect.Inflate( aAccuracy );
2599
2600 bool hit = false;
2601
2603 [&]( PCB_LAYER_ID aLayer )
2604 {
2605 if( hit )
2606 return;
2607
2608 BOX2I box( GetStart() );
2609 box.Inflate( GetWidth( aLayer ) / 2 );
2610
2611 if( aContained )
2612 hit = arect.Contains( box );
2613 else
2614 hit = arect.IntersectsCircle( GetStart(), GetWidth( aLayer ) / 2 );
2615 } );
2616
2617 return hit;
2618}
2619
2620
2621bool PCB_TRACK::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
2622{
2623 return KIGEOM::ShapeHitTest( aPoly, *GetEffectiveShape(), aContained );
2624}
2625
2626
2627wxString PCB_TRACK::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
2628{
2629 return wxString::Format( Type() == PCB_ARC_T ? _("Track (arc) %s on %s, length %s" )
2630 : _("Track %s on %s, length %s" ),
2631 GetNetnameMsg(),
2632 GetLayerName(),
2633 aUnitsProvider->MessageTextFromValue( GetLength() ) );
2634}
2635
2636
2638{
2639 return BITMAPS::add_tracks;
2640}
2641
2642
2644{
2645 wxASSERT( aImage->Type() == PCB_TRACE_T );
2646
2647 std::swap( *((PCB_TRACK*) this), *((PCB_TRACK*) aImage) );
2648}
2649
2650
2652{
2653 wxASSERT( aImage->Type() == PCB_ARC_T );
2654
2655 std::swap( *this, *static_cast<PCB_ARC*>( aImage ) );
2656}
2657
2658
2660{
2661 wxASSERT( aImage->Type() == PCB_VIA_T );
2662
2663 std::swap( *((PCB_VIA*) this), *((PCB_VIA*) aImage) );
2664}
2665
2666
2672
2673
2675{
2676 auto center = CalcArcCenter( m_Start, m_Mid , m_End );
2677 return std::min( center.Distance( m_Start ), (double) INT_MAX / 2.0 );
2678}
2679
2680
2682{
2684 EDA_ANGLE angle1 = EDA_ANGLE( m_Mid - center ) - EDA_ANGLE( m_Start - center );
2685 EDA_ANGLE angle2 = EDA_ANGLE( m_End - center ) - EDA_ANGLE( m_Mid - center );
2686
2687 return angle1.Normalize180() + angle2.Normalize180();
2688}
2689
2690
2692{
2693 VECTOR2D pos( GetPosition() );
2694 EDA_ANGLE angleStart( m_Start - pos );
2695
2696 return angleStart.Normalize();
2697}
2698
2699
2700// Note: used in python tests. Ignore CLion's claim that it's unused....
2702{
2703 VECTOR2D pos( GetPosition() );
2704 EDA_ANGLE angleEnd( m_End - pos );
2705
2706 return angleEnd.Normalize();
2707}
2708
2709bool PCB_ARC::IsDegenerated( int aThreshold ) const
2710{
2711 // We have lots of code that will blow up if the radius overflows an int.
2712 if( GetRadius() >= (double)INT_MAX/2.0 )
2713 return true;
2714
2715 // Too small arcs cannot be really handled: arc center (and arc radius)
2716 // cannot be safely computed if the distance between mid and end points
2717 // is too small (a few internal units)
2718
2719 // len of both segments must be < aThreshold to be a very small degenerated arc
2720 return ( GetMid() - GetStart() ).EuclideanNorm() < aThreshold
2721 && ( GetMid() - GetEnd() ).EuclideanNorm() < aThreshold;
2722}
2723
2724
2726{
2727 if( a->GetNetCode() != b->GetNetCode() )
2728 return a->GetNetCode() < b->GetNetCode();
2729
2730 if( a->GetLayer() != b->GetLayer() )
2731 return a->GetLayer() < b->GetLayer();
2732
2733 if( a->Type() != b->Type() )
2734 return a->Type() < b->Type();
2735
2736 if( a->m_Uuid != b->m_Uuid )
2737 return a->m_Uuid < b->m_Uuid;
2738
2739 return a < b;
2740}
2741
2742
2743std::shared_ptr<SHAPE> PCB_TRACK::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2744{
2745 int width = m_width;
2746
2747 if( IsSolderMaskLayer( aLayer ) )
2748 width += 2 * GetSolderMaskExpansion();
2749
2750 return std::make_shared<SHAPE_SEGMENT>( m_Start, m_End, width );
2751}
2752
2753
2754std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2755{
2756 // Check if this layer has copper removed by backdrill or post-machining
2757 if( aLayer != UNDEFINED_LAYER && IsBackdrilledOrPostMachined( aLayer ) )
2758 {
2759 // Return the larger of the backdrill or post-machining hole
2760 int holeSize = 0;
2761
2762 const PADSTACK::POST_MACHINING_PROPS& frontPM = Padstack().FrontPostMachining();
2763 const PADSTACK::POST_MACHINING_PROPS& backPM = Padstack().BackPostMachining();
2764
2767 {
2768 holeSize = std::max( holeSize, frontPM.size );
2769 }
2770
2773 {
2774 holeSize = std::max( holeSize, backPM.size );
2775 }
2776
2777 const PADSTACK::DRILL_PROPS& secDrill = Padstack().SecondaryDrill();
2778
2779 if( secDrill.start != UNDEFINED_LAYER && secDrill.end != UNDEFINED_LAYER )
2780 holeSize = std::max( holeSize, secDrill.size.x );
2781
2782 if( holeSize > 0 )
2783 return std::make_shared<SHAPE_CIRCLE>( m_Start, holeSize / 2 );
2784 else
2785 return std::make_shared<SHAPE_CIRCLE>( m_Start, GetDrillValue() / 2 );
2786 }
2787
2788 if( aFlash == FLASHING::ALWAYS_FLASHED
2789 || ( aFlash == FLASHING::DEFAULT && FlashLayer( aLayer ) ) )
2790 {
2791 int width = 0;
2792
2793 if( aLayer == UNDEFINED_LAYER )
2794 {
2795 Padstack().ForEachUniqueLayer(
2796 [&]( PCB_LAYER_ID layer )
2797 {
2798 width = std::max( width, GetWidth( layer ) );
2799 } );
2800
2801 width /= 2;
2802 }
2803 else
2804 {
2805 PCB_LAYER_ID cuLayer = m_padStack.EffectiveLayerFor( aLayer );
2806 width = GetWidth( cuLayer ) / 2;
2807 }
2808
2809 return std::make_shared<SHAPE_CIRCLE>( m_Start, width );
2810 }
2811 else
2812 {
2813 return std::make_shared<SHAPE_CIRCLE>( m_Start, GetDrillValue() / 2 );
2814 }
2815}
2816
2817
2818std::shared_ptr<SHAPE> PCB_ARC::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2819{
2820 int width = GetWidth();
2821
2822 if( IsSolderMaskLayer( aLayer ) )
2823 width += 2 * GetSolderMaskExpansion();
2824
2825 SHAPE_ARC arc( GetStart(), GetMid(), GetEnd(), width );
2826
2827 if( arc.IsEffectiveLine() )
2828 return std::make_shared<SHAPE_SEGMENT>( GetStart(), GetEnd(), width );
2829
2830 return std::make_shared<SHAPE_ARC>( arc );
2831}
2832
2833
2835 int aClearance, int aError, ERROR_LOC aErrorLoc,
2836 bool ignoreLineWidth ) const
2837{
2838 wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for tracks." ) );
2839
2840
2841 switch( Type() )
2842 {
2843 case PCB_VIA_T:
2844 {
2845 int radius = ( static_cast<const PCB_VIA*>( this )->GetWidth( aLayer ) / 2 ) + aClearance;
2846 TransformCircleToPolygon( aBuffer, m_Start, radius, aError, aErrorLoc );
2847 break;
2848 }
2849
2850 case PCB_ARC_T:
2851 {
2852 const PCB_ARC* arc = static_cast<const PCB_ARC*>( this );
2853 int width = m_width + ( 2 * aClearance );
2854
2855 if( IsSolderMaskLayer( aLayer ) )
2856 width += 2 * GetSolderMaskExpansion();
2857
2858 TransformArcToPolygon( aBuffer, arc->GetStart(), arc->GetMid(), arc->GetEnd(), width,
2859 aError, aErrorLoc );
2860 break;
2861 }
2862
2863 default:
2864 {
2865 int width = m_width + ( 2 * aClearance );
2866
2867 if( IsSolderMaskLayer( aLayer ) )
2868 width += 2 * GetSolderMaskExpansion();
2869
2870 TransformOvalToPolygon( aBuffer, m_Start, m_End, width, aError, aErrorLoc );
2871
2872 break;
2873 }
2874 }
2875}
2876
2877
2878static struct TRACK_VIA_DESC
2879{
2881 {
2882 // clang-format off: the suggestion is less readable
2884 .Undefined( VIATYPE::NOT_DEFINED )
2885 .Map( VIATYPE::THROUGH, _HKI( "Through" ) )
2886 .Map( VIATYPE::BLIND, _HKI( "Blind" ) )
2887 .Map( VIATYPE::BURIED, _HKI( "Buried" ) )
2888 .Map( VIATYPE::MICROVIA, _HKI( "Micro" ) );
2889
2891 .Undefined( TENTING_MODE::FROM_BOARD )
2892 .Map( TENTING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
2893 .Map( TENTING_MODE::TENTED, _HKI( "Tented" ) )
2894 .Map( TENTING_MODE::NOT_TENTED, _HKI( "Not tented" ) );
2895
2897 .Undefined( COVERING_MODE::FROM_BOARD )
2898 .Map( COVERING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
2899 .Map( COVERING_MODE::COVERED, _HKI( "Covered" ) )
2900 .Map( COVERING_MODE::NOT_COVERED, _HKI( "Not covered" ) );
2901
2903 .Undefined( PLUGGING_MODE::FROM_BOARD )
2904 .Map( PLUGGING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
2905 .Map( PLUGGING_MODE::PLUGGED, _HKI( "Plugged" ) )
2906 .Map( PLUGGING_MODE::NOT_PLUGGED, _HKI( "Not plugged" ) );
2907
2909 .Undefined( CAPPING_MODE::FROM_BOARD )
2910 .Map( CAPPING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
2911 .Map( CAPPING_MODE::CAPPED, _HKI( "Capped" ) )
2912 .Map( CAPPING_MODE::NOT_CAPPED, _HKI( "Not capped" ) );
2913
2915 .Undefined( FILLING_MODE::FROM_BOARD )
2916 .Map( FILLING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
2917 .Map( FILLING_MODE::FILLED, _HKI( "Filled" ) )
2918 .Map( FILLING_MODE::NOT_FILLED, _HKI( "Not filled" ) );
2919
2920 // clang-format on: the suggestion is less readable
2921
2923
2924 if( layerEnum.Choices().GetCount() == 0 )
2925 {
2926 layerEnum.Undefined( UNDEFINED_LAYER );
2927
2928 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
2929 layerEnum.Map( layer, LSET::Name( layer ) );
2930 }
2931
2932 auto viaDiameterPropertyValidator =
2933 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2934 {
2935 if( !aItem || aItem->Type() != PCB_VIA_T )
2936 return std::nullopt;
2937
2938 if( !aValue.CheckType<int>() )
2939 return std::nullopt;
2940
2941 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2942
2943 std::optional<int> diameter = aValue.As<int>();
2944 std::optional<int> drill = via->GetDrillValue();
2945
2946 std::optional<PCB_LAYER_ID> startLayer;
2947
2948 if( via->Padstack().Drill().start != UNDEFINED_LAYER )
2949 startLayer = via->Padstack().Drill().start;
2950
2951 std::optional<PCB_LAYER_ID> endLayer;
2952
2953 if( via->Padstack().Drill().end != UNDEFINED_LAYER )
2954 endLayer = via->Padstack().Drill().end;
2955
2956 int copperLayerCount = via->BoardCopperLayerCount();
2957
2958 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
2959 PCB_VIA::ValidateViaParameters( diameter, drill, startLayer, endLayer,
2960 std::nullopt, std::nullopt, std::nullopt, // secondary drill
2961 std::nullopt, std::nullopt, std::nullopt, // tertiary drill
2962 copperLayerCount ) )
2963 {
2964 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
2965 }
2966
2967 return std::nullopt;
2968 };
2969
2970 auto viaDrillPropertyValidator =
2971 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2972 {
2973 if( !aItem || aItem->Type() != PCB_VIA_T )
2974 return std::nullopt;
2975
2976 if( !aValue.CheckType<int>() )
2977 return std::nullopt;
2978
2979 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2980
2981 std::optional<int> diameter = via->GetFrontWidth();
2982 std::optional<int> drill = aValue.As<int>();
2983
2984 std::optional<PCB_LAYER_ID> startLayer;
2985
2986 if( via->Padstack().Drill().start != UNDEFINED_LAYER )
2987 startLayer = via->Padstack().Drill().start;
2988
2989 std::optional<PCB_LAYER_ID> endLayer;
2990
2991 if( via->Padstack().Drill().end != UNDEFINED_LAYER )
2992 endLayer = via->Padstack().Drill().end;
2993
2994 std::optional<int> secondaryDrill = via->GetSecondaryDrillSize();
2995
2996 std::optional<PCB_LAYER_ID> secondaryStart;
2997
2998 if( via->GetSecondaryDrillStartLayer() != UNDEFINED_LAYER )
2999 secondaryStart = via->GetSecondaryDrillStartLayer();
3000
3001 std::optional<PCB_LAYER_ID> secondaryEnd;
3002
3003 if( via->GetSecondaryDrillEndLayer() != UNDEFINED_LAYER )
3004 secondaryEnd = via->GetSecondaryDrillEndLayer();
3005
3006 std::optional<int> tertiaryDrill = via->GetTertiaryDrillSize();
3007
3008 std::optional<PCB_LAYER_ID> tertiaryStart;
3009
3010 if( via->GetTertiaryDrillStartLayer() != UNDEFINED_LAYER )
3011 tertiaryStart = via->GetTertiaryDrillStartLayer();
3012
3013 std::optional<PCB_LAYER_ID> tertiaryEnd;
3014
3015 if( via->GetTertiaryDrillEndLayer() != UNDEFINED_LAYER )
3016 tertiaryEnd = via->GetTertiaryDrillEndLayer();
3017
3018 int copperLayerCount = via->BoardCopperLayerCount();
3019
3020 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
3021 PCB_VIA::ValidateViaParameters( diameter, drill, startLayer, endLayer,
3022 secondaryDrill, secondaryStart, secondaryEnd,
3023 tertiaryDrill, tertiaryStart, tertiaryEnd,
3024 copperLayerCount ) )
3025 {
3026 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
3027 }
3028
3029 return std::nullopt;
3030 };
3031
3032 auto viaStartLayerPropertyValidator =
3033 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
3034 {
3035 if( !aItem || aItem->Type() != PCB_VIA_T )
3036 return std::nullopt;
3037
3038 PCB_LAYER_ID layer;
3039
3040 if( aValue.CheckType<PCB_LAYER_ID>() )
3041 layer = aValue.As<PCB_LAYER_ID>();
3042 else if( aValue.CheckType<int>() )
3043 layer = static_cast<PCB_LAYER_ID>( aValue.As<int>() );
3044 else
3045 return std::nullopt;
3046
3047 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3048
3049 std::optional<int> diameter = via->GetFrontWidth();
3050 std::optional<int> drill = via->GetDrillValue();
3051
3052 std::optional<PCB_LAYER_ID> endLayer;
3053
3054 if( via->BottomLayer() != UNDEFINED_LAYER )
3055 endLayer = via->BottomLayer();
3056
3057 std::optional<int> secondaryDrill = via->GetSecondaryDrillSize();
3058
3059 std::optional<PCB_LAYER_ID> secondaryStart;
3060
3061 if( via->GetSecondaryDrillStartLayer() != UNDEFINED_LAYER )
3062 secondaryStart = via->GetSecondaryDrillStartLayer();
3063
3064 std::optional<PCB_LAYER_ID> secondaryEnd;
3065
3066 if( via->GetSecondaryDrillEndLayer() != UNDEFINED_LAYER )
3067 secondaryEnd = via->GetSecondaryDrillEndLayer();
3068
3069 int copperLayerCount = via->BoardCopperLayerCount();
3070
3071 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
3072 PCB_VIA::ValidateViaParameters( diameter, drill, layer, endLayer,
3073 secondaryDrill, secondaryStart, secondaryEnd,
3074 std::nullopt, std::nullopt, std::nullopt, // tertiary drill
3075 copperLayerCount ) )
3076 {
3077 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
3078 }
3079
3080 return std::nullopt;
3081 };
3082
3083 auto viaEndLayerPropertyValidator =
3084 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
3085 {
3086 if( !aItem || aItem->Type() != PCB_VIA_T )
3087 return std::nullopt;
3088
3089 PCB_LAYER_ID layer;
3090
3091 if( aValue.CheckType<PCB_LAYER_ID>() )
3092 layer = aValue.As<PCB_LAYER_ID>();
3093 else if( aValue.CheckType<int>() )
3094 layer = static_cast<PCB_LAYER_ID>( aValue.As<int>() );
3095 else
3096 return std::nullopt;
3097
3098 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3099
3100 std::optional<int> diameter = via->GetFrontWidth();
3101 std::optional<int> drill = via->GetDrillValue();
3102
3103 std::optional<PCB_LAYER_ID> startLayer;
3104
3105 if( via->TopLayer() != UNDEFINED_LAYER )
3106 startLayer = via->TopLayer();
3107
3108 std::optional<int> secondaryDrill = via->GetSecondaryDrillSize();
3109
3110 std::optional<PCB_LAYER_ID> secondaryStart;
3111
3112 if( via->GetSecondaryDrillStartLayer() != UNDEFINED_LAYER )
3113 secondaryStart = via->GetSecondaryDrillStartLayer();
3114
3115 std::optional<PCB_LAYER_ID> secondaryEnd;
3116
3117 if( via->GetSecondaryDrillEndLayer() != UNDEFINED_LAYER )
3118 secondaryEnd = via->GetSecondaryDrillEndLayer();
3119
3120 int copperLayerCount = via->BoardCopperLayerCount();
3121
3122 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
3123 PCB_VIA::ValidateViaParameters( diameter, drill, startLayer, layer,
3124 secondaryDrill, secondaryStart, secondaryEnd,
3125 std::nullopt, std::nullopt, std::nullopt, // tertiary drill
3126 copperLayerCount ) )
3127 {
3128 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
3129 }
3130
3131 return std::nullopt;
3132 };
3133
3135
3136 // Track
3139
3140 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "Width" ),
3142 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
3143 new PROPERTY<PCB_TRACK, int>( _HKI( "Start X" ),
3146 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
3147 new PROPERTY<PCB_TRACK, int>( _HKI( "Start Y" ),
3150 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End X" ),
3153 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End Y" ),
3156
3157 const wxString groupTechLayers = _HKI( "Technical Layers" );
3158
3159 auto isExternalLayerTrack =
3160 []( INSPECTABLE* aItem )
3161 {
3162 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( aItem ) )
3163 return IsExternalCopperLayer( track->GetLayer() );
3164
3165 return false;
3166 };
3167
3168 propMgr.AddProperty( new PROPERTY<PCB_TRACK, bool>( _HKI( "Soldermask" ),
3170 .SetAvailableFunc( isExternalLayerTrack );
3171 propMgr.AddProperty( new PROPERTY<PCB_TRACK, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
3173 PROPERTY_DISPLAY::PT_SIZE ), groupTechLayers )
3174 .SetAvailableFunc( isExternalLayerTrack );
3175
3176 // Arc
3179
3180 // Via
3183
3184 // TODO test drill, use getdrillvalue?
3185 const wxString groupVia = _HKI( "Via Properties" );
3186 const wxString groupBackdrill = _HKI( "Backdrill" );
3187 const wxString groupPostMachining = _HKI( "Post-machining" );
3188
3189 propMgr.Mask( TYPE_HASH( PCB_VIA ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
3190
3191 // clang-format off: the suggestion is less readable
3192 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Diameter" ),
3194 .SetValidator( viaDiameterPropertyValidator );
3195 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Hole" ),
3197 .SetValidator( viaDrillPropertyValidator );
3198 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Top" ),
3200 .SetValidator( viaStartLayerPropertyValidator );
3201 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Bottom" ),
3203 .SetValidator( viaEndLayerPropertyValidator );
3204 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, VIATYPE>( _HKI( "Via Type" ),
3206 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, TENTING_MODE>( _HKI( "Front tenting" ),
3208 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, TENTING_MODE>( _HKI( "Back tenting" ),
3210 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, COVERING_MODE>( _HKI( "Front covering" ),
3212 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, COVERING_MODE>( _HKI( "Back covering" ),
3214 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PLUGGING_MODE>( _HKI( "Front plugging" ),
3216 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PLUGGING_MODE>( _HKI( "Back plugging" ),
3218 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, CAPPING_MODE>( _HKI( "Capping" ),
3220 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, FILLING_MODE>( _HKI( "Filling" ),
3222
3223 auto canHaveBackdrill =
3224 []( INSPECTABLE* aItem )
3225 {
3226 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3227 {
3228 if( via->GetViaType() == VIATYPE::THROUGH )
3229 return true;
3230
3231 if( via->Padstack().GetBackdrillMode() != BACKDRILL_MODE::NO_BACKDRILL )
3232 return true;
3233 }
3234
3235 return false;
3236 };
3237
3238 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, BACKDRILL_MODE>( _HKI( "Backdrill Mode" ),
3240 .SetAvailableFunc( canHaveBackdrill );
3241
3242 propMgr.AddProperty( new PROPERTY<PCB_VIA, std::optional<int>>( _HKI( "Bottom Backdrill Size" ),
3244 groupBackdrill )
3246 []( INSPECTABLE* aItem ) -> bool
3247 {
3248 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3249 {
3250 auto mode = via->GetBackdrillMode();
3252 }
3253 return false;
3254 } );
3255
3256 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Bottom Backdrill Must-Cut" ),
3259 []( INSPECTABLE* aItem ) -> bool
3260 {
3261 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3262 {
3263 auto mode = via->GetBackdrillMode();
3265 }
3266 return false;
3267 } );
3268
3269 propMgr.AddProperty( new PROPERTY<PCB_VIA, std::optional<int>>( _HKI( "Top Backdrill Size" ),
3271 groupBackdrill )
3273 []( INSPECTABLE* aItem ) -> bool
3274 {
3275 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3276 {
3277 auto mode = via->GetBackdrillMode();
3279 }
3280 return false;
3281 } );
3282
3283 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Top Backdrill Must-Cut" ),
3286 []( INSPECTABLE* aItem ) -> bool
3287 {
3288 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3289 {
3290 auto mode = via->GetBackdrillMode();
3292 }
3293 return false;
3294 } );
3295
3296 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PAD_DRILL_POST_MACHINING_MODE>( _HKI( "Front Post-machining" ),
3298
3299 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Front Post-machining Size" ),
3301 groupPostMachining )
3303 []( INSPECTABLE* aItem )
3304 {
3305 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3306 {
3307 auto mode = via->GetFrontPostMachining();
3310 }
3311 return false;
3312 } );
3313
3314 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Front Post-machining Depth" ),
3316 groupPostMachining )
3318 []( INSPECTABLE* aItem )
3319 {
3320 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3321 {
3322 auto mode = via->GetFrontPostMachining();
3324 }
3325 return false;
3326 } );
3327
3328 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Front Post-machining Angle" ),
3330 groupPostMachining )
3332 []( INSPECTABLE* aItem )
3333 {
3334 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3335 {
3336 auto mode = via->GetFrontPostMachining();
3338 }
3339 return false;
3340 } );
3341
3342 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PAD_DRILL_POST_MACHINING_MODE>( _HKI( "Back Post-machining" ),
3344
3345 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Back Post-machining Size" ),
3347 groupPostMachining )
3349 []( INSPECTABLE* aItem )
3350 {
3351 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3352 {
3353 auto mode = via->GetBackPostMachining();
3356 }
3357 return false;
3358 } );
3359
3360 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Back Post-machining Depth" ),
3362 groupPostMachining )
3364 []( INSPECTABLE* aItem )
3365 {
3366 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3367 {
3368 auto mode = via->GetBackPostMachining();
3370 }
3371 return false;
3372 } );
3373
3374 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Back Post-machining Angle" ),
3376 groupPostMachining )
3378 []( INSPECTABLE* aItem )
3379 {
3380 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3381 {
3382 auto mode = via->GetBackPostMachining();
3384 }
3385 return false;
3386 } );
3387 // clang-format on: the suggestion is less readable
3388 }
3390
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:47
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
constexpr int ARC_LOW_DEF
Definition base_units.h:136
BITMAPS
A list of all bitmap identifiers.
ZONE_LAYER_OVERRIDE
Conditionally flashed vias and pads that interact with zones of different priority can be very squirr...
Definition board_item.h:69
@ ZLO_NONE
Definition board_item.h:70
@ ZLO_FORCE_FLASHED
Definition board_item.h:71
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:925
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
BASE_SET & set(size_t pos)
Definition base_set.h:116
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.
BOARD_CONNECTED_ITEM(BOARD_ITEM *aParent, KICAD_T idtype)
void PackNet(kiapi::board::types::Net *aProto) const
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
const wxString & GetDisplayNetname() const
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
void UnpackNet(const kiapi::board::types::Net &aProto)
Assigns a net to this item from an API message.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:83
friend class BOARD
Definition board_item.h:512
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:356
PCB_LAYER_ID m_layer
Definition board_item.h:508
bool IsLocked() const override
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
virtual void TransformShapeToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const
Convert the item shape to a polyset.
Definition board_item.h:479
virtual wxString LayerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
BOARD_ITEM & operator=(const BOARD_ITEM &aOther)
Definition board_item.h:100
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:231
virtual int BoardCopperLayerCount() const
Return the total number of copper layers for the board that this item resides on.
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1516
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:3238
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1048
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:978
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:793
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1034
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:634
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
bool IntersectsCircle(const Vec &aCenter, const int aRadius) const
Definition box2.h:500
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:164
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr coord_type GetTop() const
Definition box2.h:225
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:307
constexpr coord_type GetBottom() const
Definition box2.h:218
bool IsConnectedOnLayer(const BOARD_CONNECTED_ITEM *aItem, int aLayer, const std::initializer_list< KICAD_T > &aTypes={}) const
wxString GetName() const
Definition drc_rule.h:204
MINOPTMAX< int > & Value()
Definition drc_rule.h:197
MINOPTMAX< int > m_Value
Definition drc_rule.h:240
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
EDA_ANGLE Normalize()
Definition eda_angle.h:229
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
const KIID m_Uuid
Definition eda_item.h:531
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:542
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:155
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:37
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:772
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:38
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:78
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition view_item.cpp:35
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:176
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition view.cpp:597
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:437
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
Definition kiid.h:44
static bool Contains(int aStart_layer, int aEnd_layer, int aTest_layer)
Class which calculates lengths (and associated routing statistics) in a BOARD context.
int64_t CalculateDelay(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical propagation delay of the given items.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
void RunOnLayers(const std::function< void(PCB_LAYER_ID)> &aFunction) const
Execute a function on each layer of the LSET.
Definition lset.h:263
static const LSET & BackTechMask()
Return a mask holding all technical layers (no CU layer) on back side.
Definition lset.cpp:644
static const LSET & AllLayersMask()
Definition lset.cpp:637
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:693
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
static const LSET & FrontTechMask()
Return a mask holding all technical layers (no CU layer) on front side.
Definition lset.cpp:658
T Min() const
Definition minoptmax.h:29
bool HasMin() const
Definition minoptmax.h:33
T Opt() const
Definition minoptmax.h:31
bool HasOpt() const
Definition minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:38
int GetViaDrill() const
Definition netclass.h:147
int GetuViaDrill() const
Definition netclass.h:163
Handle the data for a net.
Definition netinfo.h:46
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:256
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:157
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
DRILL_PROPS & Drill()
Definition padstack.h:351
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition padstack.cpp:637
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
virtual VECTOR2I GetPosition() const override
bool IsDegenerated(int aThreshold=5) const
virtual void swapData(BOARD_ITEM *aImage) override
bool IsCCW() const
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_track.cpp:91
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
EDA_ANGLE GetArcAngleStart() const
void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
EDA_ANGLE GetArcAngleEnd() const
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h:285
double GetRadius() const
EDA_ANGLE GetAngle() const
const VECTOR2I & GetMid() const
Definition pcb_track.h:286
PCB_ARC(BOARD_ITEM *aParent)
Definition pcb_track.h:259
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
VECTOR2I m_Mid
Arc mid point, halfway between start and end.
Definition pcb_track.h:350
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
bool operator==(const PCB_ARC &aOther) const
void CopyFrom(const BOARD_ITEM *aOther) override
Definition pcb_track.cpp:97
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
virtual void SetLayerSet(const LSET &aLayers) override
int GetSolderMaskExpansion() const
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void SetEndY(int aY)
Definition pcb_track.h:102
void SetHasSolderMask(bool aVal)
Definition pcb_track.h:116
virtual double GetLength() const
Get the length of the track using the hypotenuse calculation.
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
virtual void swapData(BOARD_ITEM *aImage) override
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:89
bool HasSolderMask() const
Definition pcb_track.h:117
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:92
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
int GetStartY() const
Definition pcb_track.h:99
int GetEndX() const
Definition pcb_track.h:104
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
virtual void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
bool ApproxCollinear(const PCB_TRACK &aTrack)
VECTOR2I m_End
Line end point.
Definition pcb_track.h:246
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_track.h:119
std::optional< int > m_solderMaskMargin
Definition pcb_track.h:249
void CopyFrom(const BOARD_ITEM *aOther) override
Definition pcb_track.cpp:75
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:120
virtual double GetDelay() const
Get the time delay of the track.
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.
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_track.cpp:69
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the track shape to a closed polygon.
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
virtual bool operator==(const BOARD_ITEM &aOther) const override
VECTOR2I m_Start
Line start point.
Definition pcb_track.h:245
int GetEndY() const
Definition pcb_track.h:105
wxString GetFriendlyName() const override
virtual std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
virtual double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
bool m_hasSolderMask
Definition pcb_track.h:248
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
void SetStartX(int aX)
Definition pcb_track.h:95
const VECTOR2I & GetEnd() const
Definition pcb_track.h:90
PCB_TRACK(BOARD_ITEM *aParent, KICAD_T idtype=PCB_TRACE_T)
Definition pcb_track.cpp:61
void SetStartY(int aY)
Definition pcb_track.h:96
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
virtual MINOPTMAX< int > GetWidthConstraint(wxString *aSource=nullptr) const
void SetEndX(int aX)
Definition pcb_track.h:101
int GetStartX() const
Definition pcb_track.h:98
int m_width
Thickness of track (or arc) – no longer the width of a via.
Definition pcb_track.h:252
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Return STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if point if near (dist = m...
virtual void SetWidth(int aWidth)
Definition pcb_track.h:86
virtual int GetWidth() const
Definition pcb_track.h:87
void GetMsgPanelInfoBase_Common(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) const
int GetFrontPostMachiningSize() const
Definition pcb_track.h:689
PCB_LAYER_ID BottomLayer() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
PLUGGING_MODE GetFrontPluggingMode() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:553
bool IsTented(PCB_LAYER_ID aLayer) const override
Checks if the given object is tented (its copper shape is covered by solder mask) on a given side of ...
void CopyFrom(const BOARD_ITEM *aOther) override
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
PCB_LAYER_ID GetTopBackdrillLayer() const
Definition pcb_track.h:418
void SetFrontPostMachiningDepth(int aDepth)
Definition pcb_track.h:690
void SetCappingMode(CAPPING_MODE aMode)
void SetFrontCoveringMode(COVERING_MODE aMode)
wxString LayerMaskDescribe() const override
Return a string (to be shown to the user) describing a layer mask.
int GetBackPostMachiningDepth() const
Definition pcb_track.h:711
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void SetBackPostMachiningAngle(int aAngle)
Definition pcb_track.h:712
int GetBackPostMachiningAngle() const
Definition pcb_track.h:713
COVERING_MODE GetBackCoveringMode() const
std::optional< int > GetTertiaryDrillSize() const
void SetTopBackdrillSize(std::optional< int > aSize)
Definition pcb_track.h:416
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
void SetBackPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pcb_track.h:698
std::optional< int > GetTopBackdrillSize() const
Definition pcb_track.h:415
void SetBackdrillMode(BACKDRILL_MODE aMode)
Definition pcb_track.h:407
void SetDrillDefault()
Set the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
Definition pcb_track.h:766
std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > m_zoneLayerOverrides
Definition pcb_track.h:843
void SetBottomBackdrillSize(std::optional< int > aSize)
Definition pcb_track.h:410
void ClearZoneLayerOverrides()
CAPPING_MODE GetCappingMode() const
const PADSTACK & Padstack() const
Definition pcb_track.h:402
void SetFrontTentingMode(TENTING_MODE aMode)
bool m_isFree
"Free" vias don't get their nets auto-updated
Definition pcb_track.h:840
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
int GetFrontPostMachiningDepth() const
Definition pcb_track.h:691
bool IsBlindVia() const
TENTING_MODE GetFrontTentingMode() const
int GetPostMachiningKnockout(PCB_LAYER_ID aLayer) const
Get the knockout diameter for a layer affected by post-machining.
void SetBottomLayer(PCB_LAYER_ID aLayer)
void SetPrimaryDrillSize(const VECTOR2I &aSize)
Set the drill value for vias.
bool IsBackdrilledOrPostMachined(PCB_LAYER_ID aLayer) const
Check if a layer is affected by backdrilling or post-machining operations.
std::optional< int > GetSecondaryDrillSize() const
void SetPrimaryDrillCappedFlag(bool aCapped)
int GetSolderMaskExpansion() const
void SetSecondaryDrillStartLayer(PCB_LAYER_ID aLayer)
void SetTertiaryDrillEndLayer(PCB_LAYER_ID aLayer)
void ClearSecondaryDrillSize()
void SetBackPostMachiningDepth(int aDepth)
Definition pcb_track.h:710
void SetDrill(int aDrill)
Definition pcb_track.h:744
PLUGGING_MODE GetBackPluggingMode() const
void SetBackPluggingMode(PLUGGING_MODE aMode)
MINOPTMAX< int > GetDrillConstraint(wxString *aSource=nullptr) const
void SetBackTentingMode(TENTING_MODE aMode)
void SetFrontPluggingMode(PLUGGING_MODE aMode)
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
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.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void SetFrontPostMachining(const std::optional< PAD_DRILL_POST_MACHINING_MODE > &aMode)
bool operator==(const PCB_VIA &aOther) const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void SetSecondaryDrillEndLayer(PCB_LAYER_ID aLayer)
int GetFrontPostMachiningAngle() const
Definition pcb_track.h:693
std::mutex m_zoneLayerOverridesMutex
Definition pcb_track.h:842
void SetFrontPostMachiningAngle(int aAngle)
Definition pcb_track.h:692
void SetTopLayer(PCB_LAYER_ID aLayer)
FILLING_MODE GetFillingMode() const
bool IsBuriedVia() const
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
int GetFrontWidth() const
Definition pcb_track.h:470
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
PAD_DRILL_POST_MACHINING_MODE GetFrontPostMachiningMode() const
Definition pcb_track.h:683
void SetFrontPostMachiningSize(int aSize)
Definition pcb_track.h:688
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetTertiaryDrillStartLayer(PCB_LAYER_ID aLayer)
PCB_LAYER_ID GetBottomBackdrillLayer() const
Definition pcb_track.h:412
void SetPrimaryDrillShape(PAD_DRILL_SHAPE aShape)
static std::optional< VIA_PARAMETER_ERROR > ValidateViaParameters(std::optional< int > aDiameter, std::optional< int > aPrimaryDrill, std::optional< PCB_LAYER_ID > aPrimaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aPrimaryEndLayer=std::nullopt, std::optional< int > aSecondaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryEndLayer=std::nullopt, std::optional< int > aTertiaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryEndLayer=std::nullopt, int aCopperLayerCount=0)
bool IsMicroVia() const
void SetTertiaryDrillShape(PAD_DRILL_SHAPE aShape)
virtual void SetLayerSet(const LSET &aLayers) override
Note SetLayerSet() initialize the first and last copper layers connected by the via.
void GetOutermostConnectedLayers(PCB_LAYER_ID *aTopmost, PCB_LAYER_ID *aBottommost) const
Return the top-most and bottom-most connected layers.
void SetSecondaryDrillShape(PAD_DRILL_SHAPE aShape)
void SanitizeLayers()
Check so that the layers are correct depending on the type of via, and so that the top actually is on...
int GetWidth() const override
void SetBackPostMachining(const std::optional< PAD_DRILL_POST_MACHINING_MODE > &aMode)
PCB_VIA & operator=(const PCB_VIA &aOther)
void swapData(BOARD_ITEM *aImage) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void SetFillingMode(FILLING_MODE aMode)
PCB_VIA(BOARD_ITEM *aParent)
void SetPrimaryDrillFilledFlag(bool aFilled)
std::optional< int > GetBottomBackdrillSize() const
Definition pcb_track.h:409
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
void SetViaType(VIATYPE aViaType)
Definition pcb_track.h:395
int GetMinAnnulus(PCB_LAYER_ID aLayer, wxString *aSource) const
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
TENTING_MODE GetBackTentingMode() const
PCB_LAYER_ID TopLayer() const
void ClearTertiaryDrillSize()
VIATYPE m_viaType
through, blind/buried or micro
Definition pcb_track.h:836
void SetBottomBackdrillLayer(PCB_LAYER_ID aLayer)
Definition pcb_track.h:413
int GetBackPostMachiningSize() const
Definition pcb_track.h:709
void SetTertiaryDrillSize(const VECTOR2I &aSize)
PADSTACK m_padStack
Definition pcb_track.h:838
void SetSecondaryDrillSize(const VECTOR2I &aSize)
COVERING_MODE GetFrontCoveringMode() const
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
void SetZoneLayerOverride(PCB_LAYER_ID aLayer, ZONE_LAYER_OVERRIDE aOverride)
PAD_DRILL_POST_MACHINING_MODE GetBackPostMachiningMode() const
Definition pcb_track.h:703
void SetFrontWidth(int aWidth)
Definition pcb_track.h:469
VIATYPE GetViaType() const
Definition pcb_track.h:394
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
void SetPrimaryDrillCapped(const std::optional< bool > &aCapped)
MINOPTMAX< int > GetWidthConstraint(wxString *aSource=nullptr) const override
BACKDRILL_MODE GetBackdrillMode() const
Definition pcb_track.h:406
void SetWidth(int aWidth) override
void SetBackCoveringMode(COVERING_MODE aMode)
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
void SetPrimaryDrillFilled(const std::optional< bool > &aFilled)
void SetTopBackdrillLayer(PCB_LAYER_ID aLayer)
Definition pcb_track.h:419
const ZONE_LAYER_OVERRIDE & GetZoneLayerOverride(PCB_LAYER_ID aLayer) const
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
bool HasValidLayerPair(int aCopperLayerCount)
void SetFrontPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pcb_track.h:678
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void SetBackPostMachiningSize(int aSize)
Definition pcb_track.h:708
void SetPrimaryDrillEndLayer(PCB_LAYER_ID aLayer)
void SetPrimaryDrillStartLayer(PCB_LAYER_ID aLayer)
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:349
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.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
Definition seg.h:38
VECTOR2I::extended_type ecoord
Definition seg.h:40
bool ApproxCollinear(const SEG &aSeg, int aDistanceThreshold=1) const
Definition seg.cpp:791
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:116
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
bool IsEffectiveLine() const
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
double Area()
Return the area of this poly set.
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
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition vector2d.h:534
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:63
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:72
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:68
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:56
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
#define PCB_EDIT_FRAME_NAME
INSPECT_RESULT
Definition eda_item.h:42
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:89
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define STARTPOINT
When a line is selected, these flags indicate which.
a few functions useful in geometry calculations.
bool ClipLine(const BOX2I *aClipBox, int &x1, int &y1, int &x2, int &y2)
Test if any part of a line falls within the bounds of a rectangle.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:173
bool IsSolderMaskLayer(int aLayer)
Definition layer_ids.h:746
@ LAYER_VIA_NETNAMES
Definition layer_ids.h:199
bool IsCopperLayerLowerThan(PCB_LAYER_ID aLayerA, PCB_LAYER_ID aLayerB)
Return true if copper aLayerA is placed lower than aLayerB, false otherwise.
Definition layer_ids.h:822
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:170
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:778
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:180
@ DEFAULT
Flashing follows connectivity.
Definition layer_ids.h:181
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:182
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:801
#define MAX_CU_LAYERS
Definition layer_ids.h:172
int GetNetnameLayer(int aLayer)
Return a netname layer corresponding to the given layer.
Definition layer_ids.h:852
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
@ LAYER_LOCKED_ITEM_SHADOW
Shadow layer for locked items.
Definition layer_ids.h:303
@ LAYER_VIA_HOLEWALLS
Definition layer_ids.h:294
@ LAYER_VIA_COPPER_START
Virtual layers for via copper on a given copper layer.
Definition layer_ids.h:339
@ LAYER_TRACKS
Definition layer_ids.h:263
@ LAYER_CLEARANCE_START
Virtual layers for pad/via/track clearance outlines for a given copper layer.
Definition layer_ids.h:343
@ LAYER_VIA_HOLES
Draw via holes (pad holes do not use this layer).
Definition layer_ids.h:270
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition layer_ids.h:228
bool IsNetnameLayer(int aLayer)
Test whether a layer is a netname layer.
Definition layer_ids.h:867
bool IsHoleLayer(int aLayer)
Definition layer_ids.h:737
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:686
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:41
FLIP_DIRECTION
Definition mirror.h:23
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition padstack.h:69
#define _HKI(x)
Definition page_info.cpp:40
static struct TRACK_VIA_DESC _TRACK_VIA_DESC
#define GEOMETRY_MIN_SIZE
Definition pcb_track.h:53
FILLING_MODE
VIATYPE
TENTING_MODE
COVERING_MODE
PLUGGING_MODE
CAPPING_MODE
#define TYPE_HASH(x)
Definition property.h:74
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:828
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
@ PT_DECIDEGREE
Angle expressed in decidegrees.
Definition property.h:67
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
wxString UnescapeString(const wxString &aSource)
! The properties of a padstack drill. Drill position is always the pad position (origin).
Definition padstack.h:266
PCB_LAYER_ID start
Definition padstack.h:269
PCB_LAYER_ID end
Definition padstack.h:270
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:267
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:281
Struct to control which optimisations the length calculation code runs on the given path objects.
bool operator()(const PCB_TRACK *aFirst, const PCB_TRACK *aSecond) const
VECTOR2I center
int radius
VECTOR2I end
int clearance
wxString result
Test unit parsing edge cases and error handling.
#define M_PI
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition trigo.cpp:171
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition trigo.cpp:530
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:91
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:89
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:684