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
815 && secondaryDrill.start != UNDEFINED_LAYER
816 && secondaryDrill.end != UNDEFINED_LAYER )
817 {
818 // Contains honours copper Z-order; the range iterator instead walks PCB_LAYER_ID enum
819 // order, which for a bottom-anchored span spans the wrong (top inner) layers.
820 if( LAYER_RANGE::Contains( secondaryDrill.start, secondaryDrill.end, aLayer ) )
821 return true;
822 }
823
824 // Check tertiary drill (backdrill from bottom)
825 const PADSTACK::DRILL_PROPS& tertiaryDrill = m_padStack.TertiaryDrill();
826
827 if( tertiaryDrill.size.x > 0
828 && tertiaryDrill.start != UNDEFINED_LAYER
829 && tertiaryDrill.end != UNDEFINED_LAYER )
830 {
831 if( LAYER_RANGE::Contains( tertiaryDrill.start, tertiaryDrill.end, aLayer ) )
832 return true;
833 }
834
835 // Check if the layer is affected by post-machining
836 if( GetPostMachiningKnockout( aLayer ) > 0 )
837 return true;
838
839 return false;
840}
841
842
844{
845 if( !IsCopperLayer( aLayer ) )
846 return 0;
847
848 const BOARD* board = GetBoard();
849
850 if( !board )
851 return 0;
852
853 const BOARD_STACKUP& stackup = board->GetDesignSettings().GetStackupDescriptor();
854
855 // Check front post-machining (counterbore/countersink from top)
856 const PADSTACK::POST_MACHINING_PROPS& frontPM = m_padStack.FrontPostMachining();
857
858 if( frontPM.mode.has_value()
861 && frontPM.size > 0 )
862 {
863 int pmDepth = frontPM.depth;
864
865 // For countersink without explicit depth, calculate from diameter and angle
866 if( pmDepth <= 0
868 && frontPM.angle > 0 )
869 {
870 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
871 pmDepth = static_cast<int>( ( frontPM.size / 2.0 ) / tan( halfAngleRad ) );
872 }
873
874 if( pmDepth > 0 )
875 {
876 // Calculate distance from F_Cu to aLayer
877 int layerDist = stackup.GetLayerDistance( F_Cu, aLayer );
878
879 if( layerDist < pmDepth )
880 {
881 // For countersink, diameter decreases with depth
882 if( *frontPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && frontPM.angle > 0 )
883 {
884 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
885 int diameterAtLayer = frontPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
886 return std::max( 0, diameterAtLayer );
887 }
888 else
889 {
890 // Counterbore - constant diameter
891 return frontPM.size;
892 }
893 }
894 }
895 }
896
897 // Check back post-machining (counterbore/countersink from bottom)
898 const PADSTACK::POST_MACHINING_PROPS& backPM = m_padStack.BackPostMachining();
899
900 if( backPM.mode.has_value()
903 && backPM.size > 0 )
904 {
905 int pmDepth = backPM.depth;
906
907 // For countersink without explicit depth, calculate from diameter and angle
908 if( pmDepth <= 0
910 && backPM.angle > 0 )
911 {
912 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
913 pmDepth = static_cast<int>( ( backPM.size / 2.0 ) / tan( halfAngleRad ) );
914 }
915
916 if( pmDepth > 0 )
917 {
918 // Calculate distance from B_Cu to aLayer
919 int layerDist = stackup.GetLayerDistance( B_Cu, aLayer );
920
921 if( layerDist < pmDepth )
922 {
923 // For countersink, diameter decreases with depth
924 if( *backPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && backPM.angle > 0 )
925 {
926 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
927 int diameterAtLayer = backPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
928 return std::max( 0, diameterAtLayer );
929 }
930 else
931 {
932 // Counterbore - constant diameter
933 return backPM.size;
934 }
935 }
936 }
937 }
938
939 return 0;
940}
941
942
943EDA_ITEM_FLAGS PCB_TRACK::IsPointOnEnds( const VECTOR2I& point, int min_dist ) const
944{
946
947 if( min_dist < 0 )
948 min_dist = m_width / 2;
949
950 if( min_dist == 0 )
951 {
952 if( m_Start == point )
954
955 if( m_End == point )
956 result |= ENDPOINT;
957 }
958 else
959 {
960 double dist = m_Start.Distance( point );
961
962 if( min_dist >= dist )
964
965 dist = m_End.Distance( point );
966
967 if( min_dist >= dist )
968 result |= ENDPOINT;
969 }
970
971 return result;
972}
973
974
976{
977 // end of track is round, this is its radius, rounded up
978 int radius = ( m_width + 1 ) / 2;
979 int ymax, xmax, ymin, xmin;
980
981 if( Type() == PCB_VIA_T )
982 {
983 ymax = m_Start.y;
984 xmax = m_Start.x;
985
986 ymin = m_Start.y;
987 xmin = m_Start.x;
988 }
989 else if( Type() == PCB_ARC_T )
990 {
991 std::shared_ptr<SHAPE> arc = GetEffectiveShape();
992 BOX2I bbox = arc->BBox();
993
994 xmin = bbox.GetLeft();
995 xmax = bbox.GetRight();
996 ymin = bbox.GetTop();
997 ymax = bbox.GetBottom();
998 }
999 else
1000 {
1001 ymax = std::max( m_Start.y, m_End.y );
1002 xmax = std::max( m_Start.x, m_End.x );
1003
1004 ymin = std::min( m_Start.y, m_End.y );
1005 xmin = std::min( m_Start.x, m_End.x );
1006 }
1007
1008 ymax += radius;
1009 xmax += radius;
1010
1011 ymin -= radius;
1012 xmin -= radius;
1013
1014 // return a rectangle which is [pos,dim) in nature. therefore the +1
1015 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1016 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1017}
1018
1019
1021{
1022 int radius = 0;
1023
1025 [&]( PCB_LAYER_ID aLayer )
1026 {
1027 radius = std::max( radius, GetWidth( aLayer ) );
1028 } );
1029
1030 // via is round, this is its radius, rounded up
1031 radius = ( radius + 1 ) / 2;
1032
1033 int ymax = m_Start.y + radius;
1034 int xmax = m_Start.x + radius;
1035
1036 int ymin = m_Start.y - radius;
1037 int xmin = m_Start.x - radius;
1038
1039 // return a rectangle which is [pos,dim) in nature. therefore the +1
1040 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1041 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1042}
1043
1044
1046{
1047 int radius = GetWidth( aLayer );
1048
1049 // via is round, this is its radius, rounded up
1050 radius = ( radius + 1 ) / 2;
1051
1052 int ymax = m_Start.y + radius;
1053 int xmax = m_Start.x + radius;
1054
1055 int ymin = m_Start.y - radius;
1056 int xmin = m_Start.x - radius;
1057
1058 // return a rectangle which is [pos,dim) in nature. therefore the +1
1059 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1060 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1061}
1062
1063
1065{
1066 return m_Start.Distance( m_End );
1067}
1068
1069
1071{
1072 const BOARD* board = GetBoard();
1073
1074 if( !board )
1075 return 0.0;
1076
1077 const LENGTH_DELAY_CALCULATION* calc = board->GetLengthCalculation();
1078 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items{ calc->GetLengthCalculationItem( this ) };
1079 constexpr PATH_OPTIMISATIONS opts = { .OptimiseVias = false,
1080 .MergeTracks = false,
1081 .OptimiseTracesInPads = false,
1082 .InferViaInPad = false
1083 };
1084
1085 return (double) calc->CalculateDelay( items, opts );
1086}
1087
1088
1089void PCB_TRACK::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1090{
1091 RotatePoint( m_Start, aRotCentre, aAngle );
1092 RotatePoint( m_End, aRotCentre, aAngle );
1093}
1094
1095
1096void PCB_ARC::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1097{
1098 RotatePoint( m_Start, aRotCentre, aAngle );
1099 RotatePoint( m_End, aRotCentre, aAngle );
1100 RotatePoint( m_Mid, aRotCentre, aAngle );
1101}
1102
1103
1104void PCB_TRACK::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1105{
1106 MIRROR( m_Start, aCentre, aFlipDirection );
1107 MIRROR( m_End, aCentre, aFlipDirection );
1108}
1109
1110
1111void PCB_ARC::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1112{
1113 MIRROR( m_Start, aCentre, aFlipDirection );
1114 MIRROR( m_End, aCentre, aFlipDirection );
1115 MIRROR( m_Mid, aCentre, aFlipDirection );
1116}
1117
1118
1119void PCB_TRACK::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1120{
1121 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1122 {
1123 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1124 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1125 }
1126 else
1127 {
1128 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1129 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1130 }
1131
1133}
1134
1135
1136void PCB_ARC::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1137{
1138 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1139 {
1140 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1141 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1142 m_Mid.x = aCentre.x - ( m_Mid.x - aCentre.x );
1143 }
1144 else
1145 {
1146 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1147 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1148 m_Mid.y = aCentre.y - ( m_Mid.y - aCentre.y );
1149 }
1150
1152}
1153
1154
1155bool PCB_ARC::IsCCW() const
1156{
1157 VECTOR2L start = m_Start;
1158 VECTOR2L start_end = m_End - start;
1159 VECTOR2L start_mid = m_Mid - start;
1160
1161 return start_end.Cross( start_mid ) < 0;
1162}
1163
1164
1165void PCB_VIA::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1166{
1167 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1168 {
1169 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1170 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1171 }
1172 else
1173 {
1174 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1175 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1176 }
1177
1178 if( GetViaType() != VIATYPE::THROUGH )
1179 {
1180 PCB_LAYER_ID top_layer;
1181 PCB_LAYER_ID bottom_layer;
1182 LayerPair( &top_layer, &bottom_layer );
1183 top_layer = GetBoard()->FlipLayer( top_layer );
1184 bottom_layer = GetBoard()->FlipLayer( bottom_layer );
1185 SetLayerPair( top_layer, bottom_layer );
1186 }
1187}
1188
1189
1190INSPECT_RESULT PCB_TRACK::Visit( INSPECTOR inspector, void* testData, const std::vector<KICAD_T>& aScanTypes )
1191{
1192 for( KICAD_T scanType : aScanTypes )
1193 {
1194 if( scanType == Type() )
1195 {
1196 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
1197 return INSPECT_RESULT::QUIT;
1198 }
1199 }
1200
1202}
1203
1204
1205std::shared_ptr<SHAPE_SEGMENT> PCB_VIA::GetEffectiveHoleShape() const
1206{
1207 return std::make_shared<SHAPE_SEGMENT>( SEG( m_Start, m_Start ), Padstack().Drill().size.x );
1208}
1209
1210// clang-format off: the suggestion is slightly less readable
1212{
1213 switch( aMode )
1214 {
1215 case TENTING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_solder_mask.reset(); break;
1216 case TENTING_MODE::TENTED: m_padStack.FrontOuterLayers().has_solder_mask = true; break;
1217 case TENTING_MODE::NOT_TENTED: m_padStack.FrontOuterLayers().has_solder_mask = false; break;
1218 }
1219}
1220
1221
1223{
1224 if( m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
1225 {
1226 return *m_padStack.FrontOuterLayers().has_solder_mask ? TENTING_MODE::TENTED
1228 }
1229
1231}
1232
1233
1235{
1236 switch( aMode )
1237 {
1238 case TENTING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_solder_mask.reset(); break;
1239 case TENTING_MODE::TENTED: m_padStack.BackOuterLayers().has_solder_mask = true; break;
1240 case TENTING_MODE::NOT_TENTED: m_padStack.BackOuterLayers().has_solder_mask = false; break;
1241 }
1242}
1243
1244
1246{
1247 if( m_padStack.BackOuterLayers().has_solder_mask.has_value() )
1248 {
1249 return *m_padStack.BackOuterLayers().has_solder_mask ? TENTING_MODE::TENTED
1251 }
1252
1254}
1255
1256
1258{
1259 switch( aMode )
1260 {
1261 case COVERING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_covering.reset(); break;
1262 case COVERING_MODE::COVERED: m_padStack.FrontOuterLayers().has_covering = true; break;
1263 case COVERING_MODE::NOT_COVERED: m_padStack.FrontOuterLayers().has_covering = false; break;
1264 }
1265}
1266
1267
1269{
1270 if( m_padStack.FrontOuterLayers().has_covering.has_value() )
1271 {
1272 return *m_padStack.FrontOuterLayers().has_covering ? COVERING_MODE::COVERED
1274 }
1275
1277}
1278
1279
1281{
1282 switch( aMode )
1283 {
1284 case COVERING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_covering.reset(); break;
1285 case COVERING_MODE::COVERED: m_padStack.BackOuterLayers().has_covering = true; break;
1286 case COVERING_MODE::NOT_COVERED: m_padStack.BackOuterLayers().has_covering = false; break;
1287 }
1288}
1289
1290
1292{
1293 if( m_padStack.BackOuterLayers().has_covering.has_value() )
1294 {
1295 return *m_padStack.BackOuterLayers().has_covering ? COVERING_MODE::COVERED
1297 }
1298
1300}
1301
1302
1304{
1305 switch( aMode )
1306 {
1307 case PLUGGING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_plugging.reset(); break;
1308 case PLUGGING_MODE::PLUGGED: m_padStack.FrontOuterLayers().has_plugging = true; break;
1309 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.FrontOuterLayers().has_plugging = false; break;
1310 }
1311}
1312
1313
1315{
1316 if( m_padStack.FrontOuterLayers().has_plugging.has_value() )
1317 {
1318 return *m_padStack.FrontOuterLayers().has_plugging ? PLUGGING_MODE::PLUGGED
1320 }
1321
1323}
1324
1325
1327{
1328 switch( aMode )
1329 {
1330 case PLUGGING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_plugging.reset(); break;
1331 case PLUGGING_MODE::PLUGGED: m_padStack.BackOuterLayers().has_plugging = true; break;
1332 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.BackOuterLayers().has_plugging = false; break;
1333 }
1334}
1335
1336
1338{
1339 if( m_padStack.BackOuterLayers().has_plugging.has_value() )
1340 {
1341 return *m_padStack.BackOuterLayers().has_plugging ? PLUGGING_MODE::PLUGGED
1343 }
1344
1346}
1347
1348
1350{
1351 switch( aMode )
1352 {
1353 case CAPPING_MODE::FROM_BOARD: m_padStack.Drill().is_capped.reset(); break;
1354 case CAPPING_MODE::CAPPED: m_padStack.Drill().is_capped = true; break;
1355 case CAPPING_MODE::NOT_CAPPED: m_padStack.Drill().is_capped = false; break;
1356 }
1357}
1358
1359
1361{
1362 if( m_padStack.Drill().is_capped.has_value() )
1363 {
1364 return *m_padStack.Drill().is_capped ? CAPPING_MODE::CAPPED
1366 }
1367
1369}
1370
1371
1373{
1374 switch( aMode )
1375 {
1376 case FILLING_MODE::FROM_BOARD: m_padStack.Drill().is_filled.reset(); break;
1377 case FILLING_MODE::FILLED: m_padStack.Drill().is_filled = true; break;
1378 case FILLING_MODE::NOT_FILLED: m_padStack.Drill().is_filled = false; break;
1379 }
1380}
1381
1382
1384{
1385 if( m_padStack.Drill().is_filled.has_value() )
1386 {
1387 return *m_padStack.Drill().is_filled ? FILLING_MODE::FILLED
1389 }
1390
1392}
1393
1394
1396{
1397 wxCHECK_MSG( IsFrontLayer( aLayer ) || IsBackLayer( aLayer ), true, "Invalid layer passed to IsTented" );
1398
1399 bool front = IsFrontLayer( aLayer );
1400
1401 if( front && m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
1402 return *m_padStack.FrontOuterLayers().has_solder_mask;
1403
1404 if( !front && m_padStack.BackOuterLayers().has_solder_mask.has_value() )
1405 return *m_padStack.BackOuterLayers().has_solder_mask;
1406
1407 if( const BOARD* board = GetBoard() )
1408 {
1409 return front ? board->GetDesignSettings().m_TentViasFront
1410 : board->GetDesignSettings().m_TentViasBack;
1411 }
1412
1413 return true;
1414}
1415
1416
1418{
1419 if( const BOARD* board = GetBoard() )
1420 return board->GetDesignSettings().m_SolderMaskExpansion;
1421 else
1422 return 0;
1423}
1424
1425
1427{
1428 int margin = 0;
1429
1430 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine
1431 && GetBoard()->GetDesignSettings().m_DRCEngine->HasRulesForConstraintType( SOLDER_MASK_EXPANSION_CONSTRAINT ) )
1432 {
1433 DRC_CONSTRAINT constraint;
1434 std::shared_ptr<DRC_ENGINE> drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1435
1436 constraint = drcEngine->EvalRules( SOLDER_MASK_EXPANSION_CONSTRAINT, this, nullptr, m_layer );
1437
1438 if( constraint.m_Value.HasOpt() )
1439 margin = constraint.m_Value.Opt();
1440 }
1441 else if( m_solderMaskMargin.has_value() )
1442 {
1443 margin = m_solderMaskMargin.value();
1444 }
1445 else if( const BOARD* board = GetBoard() )
1446 {
1447 margin = board->GetDesignSettings().m_SolderMaskExpansion;
1448 }
1449
1450 // Ensure the resulting mask opening has a non-negative size
1451 if( margin < 0 )
1452 margin = std::max( margin, -m_width / 2 );
1453
1454 return margin;
1455}
1456
1457
1459{
1460 if( aLayer == m_layer )
1461 {
1462 return true;
1463 }
1464
1465 if( m_hasSolderMask && ( ( aLayer == F_Mask && m_layer == F_Cu )
1466 || ( aLayer == B_Mask && m_layer == B_Cu ) ) )
1467 {
1468 return true;
1469 }
1470
1471 return false;
1472}
1473
1474
1476{
1477#if 0
1478 // Nice and simple, but raises its ugly head in performance profiles....
1479 return GetLayerSet().test( aLayer );
1480#endif
1481 if( IsCopperLayer( aLayer ) &&
1482 LAYER_RANGE::Contains( Padstack().Drill().start, Padstack().Drill().end, aLayer ) )
1483 {
1484 return true;
1485 }
1486
1487 // Test for via on mask layers: a via on on a mask layer if not tented and if
1488 // it is on the corresponding external copper layer
1489 if( aLayer == F_Mask )
1490 return Padstack().Drill().start == F_Cu && !IsTented( F_Mask );
1491 else if( aLayer == B_Mask )
1492 return Padstack().Drill().end == B_Cu && !IsTented( B_Mask );
1493
1494 return false;
1495}
1496
1497
1498bool PCB_VIA::HasValidLayerPair( int aCopperLayerCount )
1499{
1500 // return true if top and bottom layers are valid, depending on the copper layer count
1501 // aCopperLayerCount is expected >= 2
1502
1503 int layer_id = aCopperLayerCount*2;
1504
1505 if( Padstack().Drill().start > B_Cu )
1506 {
1507 if( Padstack().Drill().start > layer_id )
1508 return false;
1509 }
1510 if( Padstack().Drill().end > B_Cu )
1511 {
1512 if( Padstack().Drill().end > layer_id )
1513 return false;
1514 }
1515
1516 return true;
1517}
1518
1519
1521{
1522 return Padstack().Drill().start;
1523}
1524
1525
1527{
1528 Padstack().Drill().start = aLayer;
1529}
1530
1531
1532void PCB_TRACK::SetLayerSet( const LSET& aLayerSet )
1533{
1534 aLayerSet.RunOnLayers(
1535 [&]( PCB_LAYER_ID layer )
1536 {
1537 if( IsCopperLayer( layer ) )
1538 SetLayer( layer );
1539 else if( IsSolderMaskLayer( layer ) )
1540 SetHasSolderMask( true );
1541 } );
1542}
1543
1544
1546{
1547 LSET layermask( { m_layer } );
1548
1549 if( m_hasSolderMask )
1550 {
1551 if( layermask.test( F_Cu ) )
1552 layermask.set( F_Mask );
1553 else if( layermask.test( B_Cu ) )
1554 layermask.set( B_Mask );
1555 }
1556
1557 return layermask;
1558}
1559
1560
1562{
1563 LSET layermask;
1564
1565 if( Padstack().Drill().start < PCBNEW_LAYER_ID_START )
1566 return layermask;
1567
1568 if( GetViaType() == VIATYPE::THROUGH )
1569 {
1570 layermask = LSET::AllCuMask( BoardCopperLayerCount() );
1571 }
1572 else
1573 {
1574 LAYER_RANGE range( Padstack().Drill().start, Padstack().Drill().end, BoardCopperLayerCount() );
1575
1576 int cnt = BoardCopperLayerCount();
1577 // PCB_LAYER_IDs are numbered from front to back, this is top to bottom.
1578 for( PCB_LAYER_ID id : range )
1579 {
1580 layermask.set( id );
1581
1582 if( --cnt <= 0 )
1583 break;
1584 }
1585 }
1586
1587 if( !IsTented( F_Mask ) && layermask.test( F_Cu ) )
1588 layermask.set( F_Mask );
1589
1590 if( !IsTented( B_Mask ) && layermask.test( B_Cu ) )
1591 layermask.set( B_Mask );
1592
1593 return layermask;
1594}
1595
1596
1597void PCB_VIA::SetLayerSet( const LSET& aLayerSet )
1598{
1599 // Vias do not use a LSET, just a top and bottom layer pair
1600 // So we need to set these 2 layers according to the allowed layers in aLayerSet
1601
1602 // For via through, only F_Cu and B_Cu are allowed. aLayerSet is ignored
1603 if( GetViaType() == VIATYPE::THROUGH )
1604 {
1605 Padstack().Drill().start = F_Cu;
1606 Padstack().Drill().end = B_Cu;
1607 return;
1608 }
1609
1610 // For blind buried vias, find the top and bottom layers
1611 bool top_found = false;
1612 bool bottom_found = false;
1613
1614 aLayerSet.RunOnLayers(
1615 [&]( PCB_LAYER_ID layer )
1616 {
1617 // tpo layer and bottom Layer are copper layers, so consider only copper layers
1618 if( IsCopperLayer( layer ) )
1619 {
1620 // The top layer is the first layer found in list and
1621 // cannot the B_Cu
1622 if( !top_found && layer != B_Cu )
1623 {
1624 Padstack().Drill().start = layer;
1625 top_found = true;
1626 }
1627
1628 // The bottom layer is the last layer found in list or B_Cu
1629 if( !bottom_found )
1630 Padstack().Drill().end = layer;
1631
1632 if( layer == B_Cu )
1633 bottom_found = true;
1634 }
1635 } );
1636}
1637
1638
1639void PCB_VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer )
1640{
1641 Padstack().Drill().start = aTopLayer;
1642 Padstack().Drill().end = aBottomLayer;
1644
1645 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1646 {
1647 if( BOARD* board = GetBoard() )
1648 board->InvalidateClearanceCache( m_Uuid );
1649 }
1650}
1651
1652
1654{
1655 // refuse invalid via
1656 if( aLayer == Padstack().Drill().end )
1657 return;
1658
1659 Padstack().Drill().start = aLayer;
1661
1662 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1663 {
1664 if( BOARD* board = GetBoard() )
1665 board->InvalidateClearanceCache( m_Uuid );
1666 }
1667}
1668
1669
1671{
1672 // refuse invalid via
1673 if( aLayer == Padstack().Drill().start )
1674 return;
1675
1676 Padstack().Drill().end = aLayer;
1678
1679 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1680 {
1681 if( BOARD* board = GetBoard() )
1682 board->InvalidateClearanceCache( m_Uuid );
1683 }
1684}
1685
1686
1687void PCB_VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) const
1688{
1689 PCB_LAYER_ID t_layer = F_Cu;
1690 PCB_LAYER_ID b_layer = B_Cu;
1691
1692 if( GetViaType() != VIATYPE::THROUGH )
1693 {
1694 b_layer = Padstack().Drill().end;
1695 t_layer = Padstack().Drill().start;
1696
1697 if( !IsCopperLayerLowerThan( b_layer, t_layer ) )
1698 std::swap( b_layer, t_layer );
1699 }
1700
1701 if( top_layer )
1702 *top_layer = t_layer;
1703
1704 if( bottom_layer )
1705 *bottom_layer = b_layer;
1706}
1707
1708
1710{
1711 return Padstack().Drill().start;
1712}
1713
1714
1716{
1717 return Padstack().Drill().end;
1718}
1719
1720
1722{
1723 if( GetViaType() == VIATYPE::THROUGH )
1724 {
1725 Padstack().Drill().start = F_Cu;
1726 Padstack().Drill().end = B_Cu;
1727 }
1728
1729 if( !IsCopperLayerLowerThan( Padstack().Drill().end, Padstack().Drill().start) )
1730 std::swap( Padstack().Drill().end, Padstack().Drill().start );
1731
1732 int copperCount = BoardCopperLayerCount();
1733
1734 auto sanitizeBackdrill =
1735 [copperCount]( PADSTACK::DRILL_PROPS& aDrill )
1736 {
1737 if( aDrill.start != UNDEFINED_LAYER && !IsCopperLayer( aDrill.start ) )
1738 aDrill.start = UNDEFINED_LAYER;
1739
1740 if( aDrill.end != UNDEFINED_LAYER && !IsCopperLayer( aDrill.end ) )
1741 aDrill.end = UNDEFINED_LAYER;
1742
1743 if( copperCount > 0 )
1744 {
1745 LSET cuMask = LSET::AllCuMask( copperCount );
1746
1747 if( aDrill.start != UNDEFINED_LAYER && !cuMask.Contains( aDrill.start ) )
1748 aDrill.start = UNDEFINED_LAYER;
1749
1750 if( aDrill.end != UNDEFINED_LAYER && !cuMask.Contains( aDrill.end ) )
1751 aDrill.end = UNDEFINED_LAYER;
1752 }
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." );
1782 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DIAMETER;
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." );
1789 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DRILL;
1790 return error;
1791 }
1792
1793 if( aDiameter.has_value() && !aPrimaryDrill.has_value() )
1794 {
1795 error.m_Message = _( "No via hole size defined." );
1796 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DRILL;
1797 return error;
1798 }
1799
1800 if( aPrimaryDrill.has_value() && !aDiameter.has_value() )
1801 {
1802 error.m_Message = _( "No via diameter defined." );
1803 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DIAMETER;
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" );
1811 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DRILL;
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" );
1861 error.m_Field = VIA_PARAMETER_ERROR::FIELD::START_LAYER;
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." );
1870 error.m_Field = VIA_PARAMETER_ERROR::FIELD::SECONDARY_DRILL;
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." );
1886 error.m_Field = VIA_PARAMETER_ERROR::FIELD::TERTIARY_DRILL;
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:1524
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:3289
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:642
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:613
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