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