KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_track.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2012 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include "pcb_track.h"
24
25#include <pcb_base_frame.h>
26#include <core/mirror.h>
28#include <board.h>
31#include <base_units.h>
32#include <layer_range.h>
34#include <lset.h>
35#include <cstdlib>
36#include <map>
37#include <set>
38#include <string_utils.h>
39#include <view/view.h>
43#include <geometry/seg.h>
46#include <geometry/shape_arc.h>
47#include <drc/drc_engine.h>
48#include <pcb_painter.h>
49#include <trigo.h>
51#include <properties/property.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
124
125 m_isFree = false;
126}
127
128
129PCB_VIA::PCB_VIA( const PCB_VIA& aOther ) :
130 PCB_TRACK( aOther.GetParent(), PCB_VIA_T ),
131 m_padStack( this )
132{
133 PCB_VIA::operator=( aOther );
134
135 SetUuidDirect( aOther.m_Uuid );
136
137 for( size_t ii = 0; ii < m_zoneLayerOverrides.size(); ++ii )
138 {
139 m_zoneLayerOverrides[ii].store( aOther.m_zoneLayerOverrides[ii].load( std::memory_order_relaxed ),
140 std::memory_order_relaxed );
141 }
142}
143
144
146{
148
149 m_Start = aOther.m_Start;
150 m_End = aOther.m_End;
151
152 m_viaType = aOther.m_viaType;
153 m_padStack = aOther.m_padStack;
154 m_isFree = aOther.m_isFree;
155
156 return *this;
157}
158
159
160void PCB_VIA::CopyFrom( const BOARD_ITEM* aOther )
161{
162 wxCHECK( aOther && aOther->Type() == PCB_VIA_T, /* void */ );
163 *this = *static_cast<const PCB_VIA*>( aOther );
164}
165
166
168{
169 return new PCB_VIA( *this );
170}
171
172
173wxString PCB_VIA::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
174{
175 wxString formatStr;
176
177 switch( GetViaType() )
178 {
179 case VIATYPE::BLIND: formatStr = _( "Blind via %s on %s" ); break;
180 case VIATYPE::BURIED: formatStr = _( "Buried via %s on %s" ); break;
181 case VIATYPE::MICROVIA: formatStr = _( "Micro via %s on %s" ); break;
182 default: formatStr = _( "Via %s on %s" ); break;
183 }
184
185 return wxString::Format( formatStr, GetNetnameMsg(), LayerMaskDescribe() );
186}
187
188
190{
191 return BITMAPS::via;
192}
193
194
195bool PCB_TRACK::operator==( const BOARD_ITEM& aBoardItem ) const
196{
197 if( aBoardItem.Type() != Type() )
198 return false;
199
200 const PCB_TRACK& other = static_cast<const PCB_TRACK&>( aBoardItem );
201
202 return *this == other;
203}
204
205
206bool PCB_TRACK::operator==( const PCB_TRACK& aOther ) const
207{
208 return m_Start == aOther.m_Start
209 && m_End == aOther.m_End
210 && m_layer == aOther.m_layer
211 && m_width == aOther.m_width
214}
215
216
217double PCB_TRACK::Similarity( const BOARD_ITEM& aOther ) const
218{
219 if( aOther.Type() != Type() )
220 return 0.0;
221
222 const PCB_TRACK& other = static_cast<const PCB_TRACK&>( aOther );
223
224 double similarity = 1.0;
225
226 if( m_layer != other.m_layer )
227 similarity *= 0.9;
228
229 if( m_width != other.m_width )
230 similarity *= 0.9;
231
232 if( m_Start != other.m_Start )
233 similarity *= 0.9;
234
235 if( m_End != other.m_End )
236 similarity *= 0.9;
237
238 if( m_hasSolderMask != other.m_hasSolderMask )
239 similarity *= 0.9;
240
242 similarity *= 0.9;
243
244 return similarity;
245}
246
247
248bool PCB_ARC::operator==( const BOARD_ITEM& aBoardItem ) const
249{
250 if( aBoardItem.Type() != Type() )
251 return false;
252
253 const PCB_ARC& other = static_cast<const PCB_ARC&>( aBoardItem );
254
255 return *this == other;
256}
257
258
259bool PCB_ARC::operator==( const PCB_TRACK& aOther ) const
260{
261 if( aOther.Type() != Type() )
262 return false;
263
264 const PCB_ARC& other = static_cast<const PCB_ARC&>( aOther );
265
266 return *this == other;
267}
268
269
270bool PCB_ARC::operator==( const PCB_ARC& aOther ) const
271{
272 return m_Start == aOther.m_Start
273 && m_End == aOther.m_End
274 && m_Mid == aOther.m_Mid
275 && m_layer == aOther.m_layer
276 && GetWidth() == aOther.GetWidth()
279}
280
281
282double PCB_ARC::Similarity( const BOARD_ITEM& aOther ) const
283{
284 if( aOther.Type() != Type() )
285 return 0.0;
286
287 const PCB_ARC& other = static_cast<const PCB_ARC&>( aOther );
288
289 double similarity = 1.0;
290
291 if( m_layer != other.m_layer )
292 similarity *= 0.9;
293
294 if( GetWidth() != other.GetWidth() )
295 similarity *= 0.9;
296
297 if( m_Start != other.m_Start )
298 similarity *= 0.9;
299
300 if( m_End != other.m_End )
301 similarity *= 0.9;
302
303 if( m_Mid != other.m_Mid )
304 similarity *= 0.9;
305
306 if( m_hasSolderMask != other.m_hasSolderMask )
307 similarity *= 0.9;
308
310 similarity *= 0.9;
311
312 return similarity;
313}
314
315
316bool PCB_VIA::operator==( const BOARD_ITEM& aBoardItem ) const
317{
318 if( aBoardItem.Type() != Type() )
319 return false;
320
321 const PCB_VIA& other = static_cast<const PCB_VIA&>( aBoardItem );
322
323 return *this == other;
324}
325
326
327bool PCB_VIA::operator==( const PCB_TRACK& aOther ) const
328{
329 if( aOther.Type() != Type() )
330 return false;
331
332 const PCB_VIA& other = static_cast<const PCB_VIA&>( aOther );
333
334 return *this == other;
335}
336
337
338bool PCB_VIA::operator==( const PCB_VIA& aOther ) const
339{
340 return m_Start == aOther.m_Start
341 && m_End == aOther.m_End
342 && m_layer == aOther.m_layer
343 && m_padStack == aOther.m_padStack
344 && m_viaType == aOther.m_viaType
345 && sameZoneLayerOverrides( aOther );
346}
347
348
349bool PCB_VIA::sameZoneLayerOverrides( const PCB_VIA& aOther ) const
350{
351 for( size_t ii = 0; ii < m_zoneLayerOverrides.size(); ++ii )
352 {
353 if( m_zoneLayerOverrides[ii].load( std::memory_order_relaxed )
354 != aOther.m_zoneLayerOverrides[ii].load( std::memory_order_relaxed ) )
355 {
356 return false;
357 }
358 }
359
360 return true;
361}
362
363
364double PCB_VIA::Similarity( const BOARD_ITEM& aOther ) const
365{
366 if( aOther.Type() != Type() )
367 return 0.0;
368
369 const PCB_VIA& other = static_cast<const PCB_VIA&>( aOther );
370
371 double similarity = 1.0;
372
373 if( m_layer != other.m_layer )
374 similarity *= 0.9;
375
376 if( m_Start != other.m_Start )
377 similarity *= 0.9;
378
379 if( m_End != other.m_End )
380 similarity *= 0.9;
381
382 if( m_padStack != other.m_padStack )
383 similarity *= 0.9;
384
385 if( m_viaType != other.m_viaType )
386 similarity *= 0.9;
387
388 if( !sameZoneLayerOverrides( other ) )
389 similarity *= 0.9;
390
391 return similarity;
392}
393
394
395void PCB_VIA::SetWidth( int aWidth )
396{
397 m_padStack.SetSize( { aWidth, aWidth }, PADSTACK::ALL_LAYERS );
398 wxFAIL_MSG( wxT( "Warning: PCB_VIA::SetWidth() called without a layer argument" ) );
399}
400
401
403{
404 // This is present because of the parent class. It should never be actually called on a via.
405 wxCHECK_MSG( false, m_padStack.Size( PADSTACK::ALL_LAYERS ).x,
406 wxT( "Warning: PCB_VIA::GetWidth() called without a layer argument" ) );
407}
408
409
410void PCB_VIA::SetWidth( PCB_LAYER_ID aLayer, int aWidth )
411{
412 m_padStack.SetSize( { aWidth, aWidth }, aLayer );
413}
414
415
417{
418 return m_padStack.Size( aLayer ).x;
419}
420
421
422void PCB_TRACK::Serialize( google::protobuf::Any &aContainer ) const
423{
424 kiapi::board::types::Track track;
425
426 track.mutable_id()->set_value( m_Uuid.AsStdString() );
427 track.mutable_start()->set_x_nm( GetStart().x );
428 track.mutable_start()->set_y_nm( GetStart().y );
429 track.mutable_end()->set_x_nm( GetEnd().x );
430 track.mutable_end()->set_y_nm( GetEnd().y );
431 track.mutable_width()->set_value_nm( GetWidth() );
433 track.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
434 : kiapi::common::types::LockedState::LS_UNLOCKED );
435 PackNet( track.mutable_net() );
436
437 if( const BOARD* board = GetBoard() )
438 track.mutable_parent()->set_value( board->m_Uuid.AsStdString() );
439
440 if( HasSolderMask() )
441 {
442 kiapi::board::types::SolderMaskOverrides* sm = track.mutable_solder_mask();
443 sm->set_expose_copper( true );
444
445 if( GetLocalSolderMaskMargin().has_value() )
446 sm->mutable_solder_mask_margin()->set_value_nm( GetLocalSolderMaskMargin().value() );
447 }
448
449 kiapi::common::PackCustomProperties( track.mutable_custom_properties(), *this );
450 aContainer.PackFrom( track );
451}
452
453
454bool PCB_TRACK::Deserialize( const google::protobuf::Any &aContainer )
455{
456 kiapi::board::types::Track track;
457
458 if( !aContainer.UnpackTo( &track ) )
459 return false;
460
461 SetUuidDirect( KIID( track.id().value() ) );
462 SetStart( VECTOR2I( track.start().x_nm(), track.start().y_nm() ) );
463 SetEnd( VECTOR2I( track.end().x_nm(), track.end().y_nm() ) );
464 SetWidth( track.width().value_nm() );
466 UnpackNet( track.net() );
467 SetLocked( track.locked() == kiapi::common::types::LockedState::LS_LOCKED );
468 kiapi::common::UnpackCustomProperties( track.custom_properties(), *this );
469
470 if( track.has_solder_mask() )
471 {
472 SetHasSolderMask( track.solder_mask().expose_copper() );
473
474 if( track.solder_mask().has_solder_mask_margin() )
475 SetLocalSolderMaskMargin( track.solder_mask().solder_mask_margin().value_nm() );
476 else
478 }
479 else
480 {
481 SetHasSolderMask( false );
483 }
484
485 return true;
486}
487
488
489void PCB_ARC::Serialize( google::protobuf::Any &aContainer ) const
490{
491 kiapi::board::types::Arc arc;
492
493 arc.mutable_id()->set_value( m_Uuid.AsStdString() );
494 arc.mutable_start()->set_x_nm( GetStart().x );
495 arc.mutable_start()->set_y_nm( GetStart().y );
496 arc.mutable_mid()->set_x_nm( GetMid().x );
497 arc.mutable_mid()->set_y_nm( GetMid().y );
498 arc.mutable_end()->set_x_nm( GetEnd().x );
499 arc.mutable_end()->set_y_nm( GetEnd().y );
500 arc.mutable_width()->set_value_nm( GetWidth() );
502 arc.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
503 : kiapi::common::types::LockedState::LS_UNLOCKED );
504 PackNet( arc.mutable_net() );
505
506 if( const BOARD* board = GetBoard() )
507 arc.mutable_parent()->set_value( board->m_Uuid.AsStdString() );
508
509 if( HasSolderMask() )
510 {
511 kiapi::board::types::SolderMaskOverrides* sm = arc.mutable_solder_mask();
512 sm->set_expose_copper( true );
513
514 if( GetLocalSolderMaskMargin().has_value() )
515 sm->mutable_solder_mask_margin()->set_value_nm( GetLocalSolderMaskMargin().value() );
516 }
517
518 kiapi::common::PackCustomProperties( arc.mutable_custom_properties(), *this );
519 aContainer.PackFrom( arc );
520}
521
522
523bool PCB_ARC::Deserialize( const google::protobuf::Any &aContainer )
524{
525 kiapi::board::types::Arc arc;
526
527 if( !aContainer.UnpackTo( &arc ) )
528 return false;
529
530 SetUuidDirect( KIID( arc.id().value() ) );
531 SetStart( VECTOR2I( arc.start().x_nm(), arc.start().y_nm() ) );
532 SetMid( VECTOR2I( arc.mid().x_nm(), arc.mid().y_nm() ) );
533 SetEnd( VECTOR2I( arc.end().x_nm(), arc.end().y_nm() ) );
534 SetWidth( arc.width().value_nm() );
536 UnpackNet( arc.net() );
537 SetLocked( arc.locked() == kiapi::common::types::LockedState::LS_LOCKED );
538 kiapi::common::UnpackCustomProperties( arc.custom_properties(), *this );
539
540 if( arc.has_solder_mask() )
541 {
542 SetHasSolderMask( arc.solder_mask().expose_copper() );
543
544 if( arc.solder_mask().has_solder_mask_margin() )
545 SetLocalSolderMaskMargin( arc.solder_mask().solder_mask_margin().value_nm() );
546 else
548 }
549 else
550 {
551 SetHasSolderMask( false );
553 }
554
555 return true;
556}
557
558
559void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
560{
561 kiapi::board::types::Via via;
562 Serialize( via );
563 aContainer.PackFrom( via );
564}
565
566
567void PCB_VIA::Serialize( kiapi::board::types::Via& aVia ) const
568{
569 aVia.mutable_id()->set_value( m_Uuid.AsStdString() );
570 aVia.mutable_position()->set_x_nm( GetPosition().x );
571 aVia.mutable_position()->set_y_nm( GetPosition().y );
572
573 PADSTACK padstack = Padstack();
574
575 padstack.Serialize( *aVia.mutable_pad_stack() );
576
577 // PADSTACK::m_layerSet is not used by vias
578 aVia.mutable_pad_stack()->clear_layers();
579 kiapi::board::PackLayerSet( *aVia.mutable_pad_stack()->mutable_layers(), GetLayerSet() );
580
582 aVia.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
583 : kiapi::common::types::LockedState::LS_UNLOCKED );
584 PackNet( aVia.mutable_net() );
585
586 if( const BOARD* board = GetBoard() )
587 aVia.mutable_parent()->set_value( board->m_Uuid.AsStdString() );
588
589 kiapi::board::PackTeardropSettings( *aVia.mutable_teardrop(), GetTeardropParams() );
590
591 aVia.set_is_free( GetIsFree() );
592
593 {
594 // Pack drops ZLO_NONE, so walking every copper layer emits only the overridden ones
595 std::map<PCB_LAYER_ID, ZONE_LAYER_OVERRIDE> overrides;
596
598 overrides[layer] = GetZoneLayerOverride( layer );
599
600 kiapi::board::PackZoneLayerOverrides( aVia.mutable_zone_layer_overrides(), overrides );
601 }
602
603 kiapi::common::PackCustomProperties( aVia.mutable_custom_properties(), *this );
604}
605
606
607bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
608{
609 kiapi::board::types::Via via;
610
611 if( !aContainer.UnpackTo( &via ) )
612 return false;
613
614 return Deserialize( via );
615}
616
617
618bool PCB_VIA::Deserialize( const kiapi::board::types::Via& aVia )
619{
620 SetUuidDirect( KIID( aVia.id().value() ) );
621 SetStart( VECTOR2I( aVia.position().x_nm(), aVia.position().y_nm() ) );
622 SetEnd( GetStart() );
623
624 google::protobuf::Any padStackWrapper;
625 padStackWrapper.PackFrom( aVia.pad_stack() );
626
627 if( !m_padStack.Deserialize( padStackWrapper ) )
628 return false;
629
630 // PADSTACK::m_layerSet is not used by vias
631 m_padStack.LayerSet().reset();
632
633 SetViaType( FromProtoEnum<VIATYPE>( aVia.type() ) );
634 UnpackNet( aVia.net() );
635 SetLocked( aVia.locked() == kiapi::common::types::LockedState::LS_LOCKED );
636 kiapi::common::UnpackCustomProperties( aVia.custom_properties(), *this );
637
638 if( aVia.has_teardrop() )
640 else
641 SetTeardropsEnabled( false );
642
643 SetIsFree( aVia.is_free() );
644
646
647 {
648 std::map<PCB_LAYER_ID, ZONE_LAYER_OVERRIDE> overrides;
649 kiapi::board::UnpackZoneLayerOverrides( overrides, aVia.zone_layer_overrides() );
650
651 for( const auto& [layer, value] : overrides )
652 SetZoneLayerOverride( layer, value );
653 }
654
655 return true;
656}
657
658
660{
661 SEG a( m_Start, m_End );
662 SEG b( aTrack.GetStart(), aTrack.GetEnd() );
663 return a.ApproxCollinear( b );
664}
665
666
668{
669 DRC_CONSTRAINT constraint;
670
671 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
672 {
674
675 constraint = bds.m_DRCEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, this, nullptr, m_layer );
676 }
677
678 if( aSource )
679 *aSource = constraint.GetName();
680
681 return constraint.Value();
682}
683
684
686{
687 DRC_CONSTRAINT constraint;
688
689 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
690 {
692
693 constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, this, nullptr, m_layer );
694 }
695
696 if( aSource )
697 *aSource = constraint.GetName();
698
699 return constraint.Value();
700}
701
702
704{
705 DRC_CONSTRAINT constraint;
706
707 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
708 {
710
711 // Holes are not layer-specific, as in the hole size test
712 constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, this, nullptr, UNDEFINED_LAYER );
713 }
714
715 if( aSource )
716 *aSource = constraint.GetName();
717
718 return constraint.Value();
719}
720
721
722void PCB_VIA::SetSizeFromRules( int aDiameter, int aDrill )
723{
724 // Area rules test the via's shape, so evaluate them at the preferred size
726 SetWidth( PADSTACK::ALL_LAYERS, aDiameter );
727 SetDrill( aDrill );
728
729 // Callers size vias that may still move, so keep them out of the pointer-keyed rule caches
730 bool wasTransient = HasFlag( ROUTER_TRANSIENT );
732
733 int diameter = GetWidthConstraint().PinnedOpt( aDiameter );
734 int drill = GetDrillConstraint().PinnedOpt( aDrill );
735
736 if( !wasTransient )
738
739 SetWidth( PADSTACK::ALL_LAYERS, diameter );
740 SetDrill( drill );
741}
742
743
744int PCB_VIA::GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const
745{
746 if( !FlashLayer( aLayer ) )
747 {
748 if( aSource )
749 *aSource = _( "removed annular ring" );
750
751 return 0;
752 }
753
754 DRC_CONSTRAINT constraint;
755
756 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
757 {
759
760 constraint = bds.m_DRCEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, this, nullptr, aLayer );
761 }
762
763 if( constraint.Value().HasMin() )
764 {
765 if( aSource )
766 *aSource = constraint.GetName();
767
768 return constraint.Value().Min();
769 }
770
771 return 0;
772}
773
774
776{
777 m_padStack.Drill().size = aSize;
778}
779
780
782{
783 m_padStack.Drill().shape = aShape;
784}
785
786
788{
789 m_padStack.Drill().start = aLayer;
790}
791
792
794{
795 m_padStack.Drill().end = aLayer;
796}
797
798
799void PCB_VIA::SetFrontPostMachining( const std::optional<PAD_DRILL_POST_MACHINING_MODE>& aMode )
800{
801 m_padStack.FrontPostMachining().mode = aMode;
802}
803
804
805void PCB_VIA::SetBackPostMachining( const std::optional<PAD_DRILL_POST_MACHINING_MODE>& aMode )
806{
807 m_padStack.BackPostMachining().mode = aMode;
808}
809
810
811void PCB_VIA::SetPrimaryDrillFilled( const std::optional<bool>& aFilled )
812{
813 m_padStack.Drill().is_filled = aFilled;
814}
815
816
818{
819 m_padStack.Drill().is_filled = aFilled;
820}
821
822
823void PCB_VIA::SetPrimaryDrillCapped( const std::optional<bool>& aCapped )
824{
825 m_padStack.Drill().is_capped = aCapped;
826}
827
828
830{
831 m_padStack.Drill().is_capped = aCapped;
832}
833
834
835// Two microvias belong to one structure when the upper one lands on the lower one. Exact
836// concentricity is only the extreme case of that, so the test is hole overlap.
837std::vector<std::vector<PCB_VIA*>> PCB_VIA::CollectMicroviaColumns( BOARD* aBoard )
838{
839 std::map<int, int> ordinals;
840 int n = 0;
841
842 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, aBoard->GetCopperLayerCount() ) )
843 ordinals[layer] = n++;
844
845 std::vector<PCB_VIA*> microvias;
846
847 for( PCB_TRACK* track : aBoard->Tracks() )
848 {
849 if( track->Type() != PCB_VIA_T )
850 continue;
851
852 PCB_VIA* via = static_cast<PCB_VIA*>( track );
853
854 if( via->GetViaType() != VIATYPE::MICROVIA )
855 continue;
856
857 // A via on a single layer lands on nothing.
858 if( via->TopLayer() == via->BottomLayer() )
859 continue;
860
861 if( ordinals.count( via->TopLayer() ) && ordinals.count( via->BottomLayer() ) )
862 microvias.push_back( via );
863 }
864
865 auto upper = [&]( PCB_VIA* aVia )
866 {
867 return std::min( ordinals[aVia->TopLayer()], ordinals[aVia->BottomLayer()] );
868 };
869
870 auto lower = [&]( PCB_VIA* aVia )
871 {
872 return std::max( ordinals[aVia->TopLayer()], ordinals[aVia->BottomLayer()] );
873 };
874
875 // Touching holes have no wall between them, so they count as one column too.
876 auto overlaps = []( PCB_VIA* aFirst, PCB_VIA* aSecond )
877 {
878 double reach = ( aFirst->GetDrillValue() + aSecond->GetDrillValue() ) / 2.0;
879
880 return ( aFirst->GetPosition() - aSecond->GetPosition() ).EuclideanNorm() <= reach;
881 };
882
883 // Overlap needs the centres closer than the largest hole, so bucket the vias by landing
884 // layer and position and only the neighbouring buckets have to be looked at.
885 int cellSize = 1;
886
887 for( PCB_VIA* via : microvias )
888 cellSize = std::max( cellSize, via->GetDrillValue() );
889
890 auto cellOf = [&]( int aCoord )
891 {
892 return (int) std::floor( (double) aCoord / cellSize );
893 };
894
895 std::map<std::tuple<int, int, int>, std::vector<PCB_VIA*>> byCell;
896
897 for( PCB_VIA* via : microvias )
898 {
899 VECTOR2I pos = via->GetPosition();
900 byCell[{ upper( via ), cellOf( pos.x ), cellOf( pos.y ) }].push_back( via );
901 }
902
903 // The via a given one lands on, if any.
904 auto below = [&]( PCB_VIA* aVia ) -> PCB_VIA*
905 {
906 VECTOR2I pos = aVia->GetPosition();
907
908 for( int dx = -1; dx <= 1; ++dx )
909 {
910 for( int dy = -1; dy <= 1; ++dy )
911 {
912 auto it = byCell.find( { lower( aVia ), cellOf( pos.x ) + dx, cellOf( pos.y ) + dy } );
913
914 if( it == byCell.end() )
915 continue;
916
917 for( PCB_VIA* other : it->second )
918 {
919 if( other != aVia && overlaps( aVia, other ) )
920 return other;
921 }
922 }
923 }
924
925 return nullptr;
926 };
927
928 std::set<PCB_VIA*> carried;
929
930 for( PCB_VIA* via : microvias )
931 {
932 if( PCB_VIA* under = below( via ) )
933 carried.insert( under );
934 }
935
936 std::vector<std::vector<PCB_VIA*>> columns;
937 std::set<PCB_VIA*> taken;
938
939 for( PCB_VIA* via : microvias )
940 {
941 // Walk down from the top of each structure so every one is built once.
942 if( carried.count( via ) )
943 continue;
944
945 std::vector<PCB_VIA*> column;
946 bool landsOnAnother = false;
947
948 for( PCB_VIA* step = via; step; step = below( step ) )
949 {
950 if( !taken.insert( step ).second )
951 {
952 landsOnAnother = true;
953 break;
954 }
955
956 column.push_back( step );
957
958 if( column.size() > ordinals.size() )
959 break;
960 }
961
962 if( column.size() > 1 || landsOnAnother )
963 columns.push_back( std::move( column ) );
964 }
965
966 return columns;
967}
968
969
971{
972 if( m_padStack.Drill().size.x > 0 ) // Use the specific value.
973 return m_padStack.Drill().size.x;
974
975 // Use the default value from the Netclass
976 NETCLASS* netclass = GetEffectiveNetClass();
977
979 return netclass->GetuViaDrill();
980
981 return netclass->GetViaDrill();
982}
983
984
986{
987 m_padStack.SecondaryDrill().size = aSize;
988}
989
990
992{
993 m_padStack.SecondaryDrill().size = { 0, 0 };
994}
995
996
997void PCB_VIA::SetSecondaryDrillSize( const std::optional<int>& aDrill )
998{
999 if( aDrill.has_value() && *aDrill > 0 )
1000 SetSecondaryDrillSize( { *aDrill, *aDrill } );
1001 else
1003}
1004
1005
1006std::optional<int> PCB_VIA::GetSecondaryDrillSize() const
1007{
1008 if( m_padStack.SecondaryDrill().size.x > 0 )
1009 return m_padStack.SecondaryDrill().size.x;
1010
1011 return std::nullopt;
1012}
1013
1014
1016{
1017 m_padStack.SecondaryDrill().start = aLayer;
1018}
1019
1020
1022{
1023 m_padStack.SecondaryDrill().end = aLayer;
1024}
1025
1026
1028{
1029 m_padStack.SecondaryDrill().shape = aShape;
1030}
1031
1032
1034{
1035 m_padStack.TertiaryDrill().size = aSize;
1036}
1037
1038
1040{
1041 m_padStack.TertiaryDrill().size = { 0, 0 };
1042}
1043
1044
1045void PCB_VIA::SetTertiaryDrillSize( const std::optional<int>& aDrill )
1046{
1047 if( aDrill.has_value() && *aDrill > 0 )
1048 SetTertiaryDrillSize( { *aDrill, *aDrill } );
1049 else
1051}
1052
1053
1054std::optional<int> PCB_VIA::GetTertiaryDrillSize() const
1055{
1056 if( m_padStack.TertiaryDrill().size.x > 0 )
1057 return m_padStack.TertiaryDrill().size.x;
1058
1059 return std::nullopt;
1060}
1061
1062
1064{
1065 m_padStack.TertiaryDrill().start = aLayer;
1066}
1067
1068
1070{
1071 m_padStack.TertiaryDrill().end = aLayer;
1072}
1073
1074
1076{
1077 m_padStack.TertiaryDrill().shape = aShape;
1078}
1079
1080
1082{
1083 if( !IsCopperLayer( aLayer ) )
1084 return false;
1085
1086 const BOARD* board = GetBoard();
1087
1088 if( !board )
1089 return false;
1090
1091 // Check secondary drill (backdrill from top)
1092 const PADSTACK::DRILL_PROPS& secondaryDrill = m_padStack.SecondaryDrill();
1093
1094 if( secondaryDrill.size.x > 0
1095 && secondaryDrill.start != UNDEFINED_LAYER
1096 && secondaryDrill.end != UNDEFINED_LAYER )
1097 {
1098 // Contains honours copper Z-order; the range iterator instead walks PCB_LAYER_ID enum
1099 // order, which for a bottom-anchored span spans the wrong (top inner) layers.
1100 if( LAYER_RANGE::Contains( secondaryDrill.start, secondaryDrill.end, aLayer ) )
1101 return true;
1102 }
1103
1104 // Check tertiary drill (backdrill from bottom)
1105 const PADSTACK::DRILL_PROPS& tertiaryDrill = m_padStack.TertiaryDrill();
1106
1107 if( tertiaryDrill.size.x > 0
1108 && tertiaryDrill.start != UNDEFINED_LAYER
1109 && tertiaryDrill.end != UNDEFINED_LAYER )
1110 {
1111 if( LAYER_RANGE::Contains( tertiaryDrill.start, tertiaryDrill.end, aLayer ) )
1112 return true;
1113 }
1114
1115 // Check if the layer is affected by post-machining
1116 if( GetPostMachiningKnockout( aLayer ) > 0 )
1117 return true;
1118
1119 return false;
1120}
1121
1122
1124{
1125 if( !IsCopperLayer( aLayer ) )
1126 return 0;
1127
1128 const BOARD* board = GetBoard();
1129
1130 if( !board )
1131 return 0;
1132
1133 const BOARD_STACKUP& stackup = board->GetDesignSettings().GetStackupDescriptor();
1134
1135 // Check front post-machining (counterbore/countersink from top)
1136 const PADSTACK::POST_MACHINING_PROPS& frontPM = m_padStack.FrontPostMachining();
1137
1138 if( frontPM.mode.has_value()
1141 && frontPM.size > 0 )
1142 {
1143 int pmDepth = frontPM.depth;
1144
1145 // For countersink without explicit depth, calculate from diameter and angle
1146 if( pmDepth <= 0
1148 && frontPM.angle > 0 )
1149 {
1150 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
1151 pmDepth = static_cast<int>( ( frontPM.size / 2.0 ) / tan( halfAngleRad ) );
1152 }
1153
1154 if( pmDepth > 0 )
1155 {
1156 // Calculate distance from F_Cu to aLayer
1157 int layerDist = stackup.GetLayerDistance( F_Cu, aLayer );
1158
1159 if( layerDist < pmDepth )
1160 {
1161 // For countersink, diameter decreases with depth
1162 if( *frontPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && frontPM.angle > 0 )
1163 {
1164 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
1165 int diameterAtLayer = frontPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
1166 return std::max( 0, diameterAtLayer );
1167 }
1168 else
1169 {
1170 // Counterbore - constant diameter
1171 return frontPM.size;
1172 }
1173 }
1174 }
1175 }
1176
1177 // Check back post-machining (counterbore/countersink from bottom)
1178 const PADSTACK::POST_MACHINING_PROPS& backPM = m_padStack.BackPostMachining();
1179
1180 if( backPM.mode.has_value()
1183 && backPM.size > 0 )
1184 {
1185 int pmDepth = backPM.depth;
1186
1187 // For countersink without explicit depth, calculate from diameter and angle
1188 if( pmDepth <= 0
1190 && backPM.angle > 0 )
1191 {
1192 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
1193 pmDepth = static_cast<int>( ( backPM.size / 2.0 ) / tan( halfAngleRad ) );
1194 }
1195
1196 if( pmDepth > 0 )
1197 {
1198 // Calculate distance from B_Cu to aLayer
1199 int layerDist = stackup.GetLayerDistance( B_Cu, aLayer );
1200
1201 if( layerDist < pmDepth )
1202 {
1203 // For countersink, diameter decreases with depth
1204 if( *backPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && backPM.angle > 0 )
1205 {
1206 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
1207 int diameterAtLayer = backPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
1208 return std::max( 0, diameterAtLayer );
1209 }
1210 else
1211 {
1212 // Counterbore - constant diameter
1213 return backPM.size;
1214 }
1215 }
1216 }
1217 }
1218
1219 return 0;
1220}
1221
1222
1223EDA_ITEM_FLAGS PCB_TRACK::IsPointOnEnds( const VECTOR2I& point, int min_dist ) const
1224{
1226
1227 if( min_dist < 0 )
1228 min_dist = m_width / 2;
1229
1230 if( min_dist == 0 )
1231 {
1232 if( m_Start == point )
1233 result |= STARTPOINT;
1234
1235 if( m_End == point )
1236 result |= ENDPOINT;
1237 }
1238 else
1239 {
1240 double dist = m_Start.Distance( point );
1241
1242 if( min_dist >= dist )
1243 result |= STARTPOINT;
1244
1245 dist = m_End.Distance( point );
1246
1247 if( min_dist >= dist )
1248 result |= ENDPOINT;
1249 }
1250
1251 return result;
1252}
1253
1254
1256{
1257 // end of track is round, this is its radius, rounded up
1258 int radius = ( m_width + 1 ) / 2;
1259 int ymax, xmax, ymin, xmin;
1260
1261 if( Type() == PCB_ARC_T )
1262 {
1263 std::shared_ptr<SHAPE> arc = GetEffectiveShape();
1264 BOX2I bbox = arc->BBox();
1265
1266 xmin = bbox.GetLeft();
1267 xmax = bbox.GetRight();
1268 ymin = bbox.GetTop();
1269 ymax = bbox.GetBottom();
1270 }
1271 else
1272 {
1273 ymax = std::max( m_Start.y, m_End.y );
1274 xmax = std::max( m_Start.x, m_End.x );
1275
1276 ymin = std::min( m_Start.y, m_End.y );
1277 xmin = std::min( m_Start.x, m_End.x );
1278 }
1279
1280 ymax += radius;
1281 xmax += radius;
1282
1283 ymin -= radius;
1284 xmin -= radius;
1285
1286 // return a rectangle which is [pos,dim) in nature. therefore the +1
1287 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1288 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1289}
1290
1291
1293{
1294 int diameter = 0;
1295
1297 [&]( PCB_LAYER_ID aLayer )
1298 {
1299 if( IsGhostLayer( aLayer ) )
1300 return;
1301
1302 diameter = std::max( diameter, GetWidth( aLayer ) );
1303 } );
1304
1305 diameter = std::max( diameter, Padstack().GetMaxHoleSize() );
1306
1307 // via is round, this is its radius, rounded up
1308 int radius = ( diameter + 1 ) / 2;
1309
1310 int ymax = m_Start.y + radius;
1311 int xmax = m_Start.x + radius;
1312
1313 int ymin = m_Start.y - radius;
1314 int xmin = m_Start.x - radius;
1315
1316 // return a rectangle which is [pos,dim) in nature. therefore the +1
1317 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1318 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1319}
1320
1321
1323{
1324 int diameter = GetWidth( aLayer );
1325
1326 if( IsBackdrilledOrPostMachined( aLayer ) )
1327 diameter = std::max( diameter, Padstack().GetMaxHoleSize() );
1328
1329 // via is round, this is its radius, rounded up
1330 int radius = ( diameter + 1 ) / 2;
1331
1332 int ymax = m_Start.y + radius;
1333 int xmax = m_Start.x + radius;
1334
1335 int ymin = m_Start.y - radius;
1336 int xmin = m_Start.x - radius;
1337
1338 // return a rectangle which is [pos,dim) in nature. therefore the +1
1339 return BOX2ISafe( VECTOR2I( xmin, ymin ),
1340 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
1341}
1342
1343
1345{
1346 return m_Start.Distance( m_End );
1347}
1348
1349
1351{
1352 const BOARD* board = GetBoard();
1353
1354 if( !board )
1355 return 0.0;
1356
1357 const LENGTH_DELAY_CALCULATION* calc = board->GetLengthCalculation();
1358 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items{ calc->GetLengthCalculationItem( this ) };
1359 constexpr PATH_OPTIMISATIONS opts = { .OptimiseVias = false,
1360 .MergeTracks = false,
1361 .OptimiseTracesInPads = false,
1362 .InferViaInPad = false
1363 };
1364
1365 return (double) calc->CalculateDelay( items, opts );
1366}
1367
1368
1369void PCB_TRACK::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1370{
1371 RotatePoint( m_Start, aRotCentre, aAngle );
1372 RotatePoint( m_End, aRotCentre, aAngle );
1373}
1374
1375
1376void PCB_ARC::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1377{
1378 RotatePoint( m_Start, aRotCentre, aAngle );
1379 RotatePoint( m_End, aRotCentre, aAngle );
1380 RotatePoint( m_Mid, aRotCentre, aAngle );
1381}
1382
1383
1384void PCB_TRACK::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1385{
1386 MIRROR( m_Start, aCentre, aFlipDirection );
1387 MIRROR( m_End, aCentre, aFlipDirection );
1388}
1389
1390
1391void PCB_ARC::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1392{
1393 MIRROR( m_Start, aCentre, aFlipDirection );
1394 MIRROR( m_End, aCentre, aFlipDirection );
1395 MIRROR( m_Mid, aCentre, aFlipDirection );
1396}
1397
1398
1399void PCB_TRACK::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1400{
1401 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1402 {
1403 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1404 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1405 }
1406 else
1407 {
1408 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1409 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1410 }
1411
1413}
1414
1415
1416void PCB_ARC::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1417{
1418 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1419 {
1420 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1421 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1422 m_Mid.x = aCentre.x - ( m_Mid.x - aCentre.x );
1423 }
1424 else
1425 {
1426 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1427 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1428 m_Mid.y = aCentre.y - ( m_Mid.y - aCentre.y );
1429 }
1430
1432}
1433
1434
1435bool PCB_ARC::IsCCW() const
1436{
1437 VECTOR2L start = m_Start;
1438 VECTOR2L start_end = m_End - start;
1439 VECTOR2L start_mid = m_Mid - start;
1440
1441 return start_end.Cross( start_mid ) < 0;
1442}
1443
1444
1445void PCB_VIA::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1446{
1447 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1448 {
1449 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
1450 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
1451 }
1452 else
1453 {
1454 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
1455 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
1456 }
1457
1458 if( GetViaType() != VIATYPE::THROUGH )
1459 {
1460 PCB_LAYER_ID top_layer;
1461 PCB_LAYER_ID bottom_layer;
1462 LayerPair( &top_layer, &bottom_layer );
1463 top_layer = GetBoard()->FlipLayer( top_layer );
1464 bottom_layer = GetBoard()->FlipLayer( bottom_layer );
1465 SetLayerPair( top_layer, bottom_layer );
1466 }
1467}
1468
1469
1470INSPECT_RESULT PCB_TRACK::Visit( INSPECTOR inspector, void* testData, const std::vector<KICAD_T>& aScanTypes )
1471{
1472 for( KICAD_T scanType : aScanTypes )
1473 {
1474 if( scanType == Type() )
1475 {
1476 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
1477 return INSPECT_RESULT::QUIT;
1478 }
1479 }
1480
1482}
1483
1484
1485std::shared_ptr<SHAPE_SEGMENT> PCB_VIA::GetEffectiveHoleShape( PCB_LAYER_ID aLayer, DRC_CONSTRAINT_T aUsage ) const
1486{
1487 // An unset padstack drill falls back to the netclass value
1488 int holeSize = GetDrillValue();
1489
1490 // See if we want to include a larger backdrill or post-machining hole
1491 if( aUsage == HOLE_TO_HOLE_CONSTRAINT
1492 || ( aUsage == HOLE_CLEARANCE_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) )
1493 || ( aUsage == ANNULAR_WIDTH_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) )
1495 || ( aUsage == SILK_CLEARANCE_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) ) )
1496 {
1497 holeSize = std::max( holeSize, Padstack().GetMaxHoleSize() );
1498 }
1499
1500 return std::make_shared<SHAPE_SEGMENT>( SEG( m_Start, m_Start ), holeSize );
1501}
1502
1503// clang-format off: the suggestion is slightly less readable
1505{
1506 switch( aMode )
1507 {
1508 case TENTING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_solder_mask.reset(); break;
1509 case TENTING_MODE::TENTED: m_padStack.FrontOuterLayers().has_solder_mask = true; break;
1510 case TENTING_MODE::NOT_TENTED: m_padStack.FrontOuterLayers().has_solder_mask = false; break;
1511 }
1512}
1513
1514
1516{
1517 if( m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
1518 {
1519 return *m_padStack.FrontOuterLayers().has_solder_mask ? TENTING_MODE::TENTED
1521 }
1522
1524}
1525
1526
1528{
1529 switch( aMode )
1530 {
1531 case TENTING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_solder_mask.reset(); break;
1532 case TENTING_MODE::TENTED: m_padStack.BackOuterLayers().has_solder_mask = true; break;
1533 case TENTING_MODE::NOT_TENTED: m_padStack.BackOuterLayers().has_solder_mask = false; break;
1534 }
1535}
1536
1537
1539{
1540 if( m_padStack.BackOuterLayers().has_solder_mask.has_value() )
1541 {
1542 return *m_padStack.BackOuterLayers().has_solder_mask ? TENTING_MODE::TENTED
1544 }
1545
1547}
1548
1549
1551{
1552 switch( aMode )
1553 {
1554 case COVERING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_covering.reset(); break;
1555 case COVERING_MODE::COVERED: m_padStack.FrontOuterLayers().has_covering = true; break;
1556 case COVERING_MODE::NOT_COVERED: m_padStack.FrontOuterLayers().has_covering = false; break;
1557 }
1558}
1559
1560
1562{
1563 if( m_padStack.FrontOuterLayers().has_covering.has_value() )
1564 {
1565 return *m_padStack.FrontOuterLayers().has_covering ? COVERING_MODE::COVERED
1567 }
1568
1570}
1571
1572
1574{
1575 switch( aMode )
1576 {
1577 case COVERING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_covering.reset(); break;
1578 case COVERING_MODE::COVERED: m_padStack.BackOuterLayers().has_covering = true; break;
1579 case COVERING_MODE::NOT_COVERED: m_padStack.BackOuterLayers().has_covering = false; break;
1580 }
1581}
1582
1583
1585{
1586 if( m_padStack.BackOuterLayers().has_covering.has_value() )
1587 {
1588 return *m_padStack.BackOuterLayers().has_covering ? COVERING_MODE::COVERED
1590 }
1591
1593}
1594
1595
1597{
1598 switch( aMode )
1599 {
1600 case PLUGGING_MODE::FROM_BOARD: m_padStack.FrontOuterLayers().has_plugging.reset(); break;
1601 case PLUGGING_MODE::PLUGGED: m_padStack.FrontOuterLayers().has_plugging = true; break;
1602 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.FrontOuterLayers().has_plugging = false; break;
1603 }
1604}
1605
1606
1608{
1609 if( m_padStack.FrontOuterLayers().has_plugging.has_value() )
1610 {
1611 return *m_padStack.FrontOuterLayers().has_plugging ? PLUGGING_MODE::PLUGGED
1613 }
1614
1616}
1617
1618
1620{
1621 switch( aMode )
1622 {
1623 case PLUGGING_MODE::FROM_BOARD: m_padStack.BackOuterLayers().has_plugging.reset(); break;
1624 case PLUGGING_MODE::PLUGGED: m_padStack.BackOuterLayers().has_plugging = true; break;
1625 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.BackOuterLayers().has_plugging = false; break;
1626 }
1627}
1628
1629
1631{
1632 if( m_padStack.BackOuterLayers().has_plugging.has_value() )
1633 {
1634 return *m_padStack.BackOuterLayers().has_plugging ? PLUGGING_MODE::PLUGGED
1636 }
1637
1639}
1640
1641
1643{
1644 switch( aMode )
1645 {
1646 case CAPPING_MODE::FROM_BOARD: m_padStack.Drill().is_capped.reset(); break;
1647 case CAPPING_MODE::CAPPED: m_padStack.Drill().is_capped = true; break;
1648 case CAPPING_MODE::NOT_CAPPED: m_padStack.Drill().is_capped = false; break;
1649 }
1650}
1651
1652
1654{
1655 if( m_padStack.Drill().is_capped.has_value() )
1656 {
1657 return *m_padStack.Drill().is_capped ? CAPPING_MODE::CAPPED
1659 }
1660
1662}
1663
1664
1666{
1667 switch( aMode )
1668 {
1669 case FILLING_MODE::FROM_BOARD: m_padStack.Drill().is_filled.reset(); break;
1670 case FILLING_MODE::FILLED: m_padStack.Drill().is_filled = true; break;
1671 case FILLING_MODE::NOT_FILLED: m_padStack.Drill().is_filled = false; break;
1672 }
1673}
1674
1675
1677{
1678 if( m_padStack.Drill().is_filled.has_value() )
1679 {
1680 return *m_padStack.Drill().is_filled ? FILLING_MODE::FILLED
1682 }
1683
1685}
1686
1687
1689{
1690 wxCHECK_MSG( IsFrontLayer( aLayer ) || IsBackLayer( aLayer ), true, "Invalid layer passed to IsTented" );
1691
1692 bool front = IsFrontLayer( aLayer );
1693
1694 if( front && m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
1695 return *m_padStack.FrontOuterLayers().has_solder_mask;
1696
1697 if( !front && m_padStack.BackOuterLayers().has_solder_mask.has_value() )
1698 return *m_padStack.BackOuterLayers().has_solder_mask;
1699
1700 if( const BOARD* board = GetBoard() )
1701 {
1702 return front ? board->GetDesignSettings().m_TentViasFront
1703 : board->GetDesignSettings().m_TentViasBack;
1704 }
1705
1706 return true;
1707}
1708
1709
1711{
1712 if( const BOARD* board = GetBoard() )
1713 return board->GetDesignSettings().m_SolderMaskExpansion;
1714 else
1715 return 0;
1716}
1717
1718
1720{
1721 int margin = 0;
1722
1723 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine
1724 && GetBoard()->GetDesignSettings().m_DRCEngine->HasRulesForConstraintType( SOLDER_MASK_EXPANSION_CONSTRAINT ) )
1725 {
1726 DRC_CONSTRAINT constraint;
1727 std::shared_ptr<DRC_ENGINE> drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1728
1729 constraint = drcEngine->EvalRules( SOLDER_MASK_EXPANSION_CONSTRAINT, this, nullptr, m_layer );
1730
1731 if( constraint.m_Value.HasOpt() )
1732 margin = constraint.m_Value.Opt();
1733 }
1734 else if( m_solderMaskMargin.has_value() )
1735 {
1736 margin = m_solderMaskMargin.value();
1737 }
1738 else if( const BOARD* board = GetBoard() )
1739 {
1740 margin = board->GetDesignSettings().m_SolderMaskExpansion;
1741 }
1742
1743 // Ensure the resulting mask opening has a non-negative size
1744 if( margin < 0 )
1745 margin = std::max( margin, -m_width / 2 );
1746
1747 return margin;
1748}
1749
1750
1752{
1753 if( aLayer == m_layer )
1754 {
1755 return true;
1756 }
1757
1758 if( m_hasSolderMask && ( ( aLayer == F_Mask && m_layer == F_Cu )
1759 || ( aLayer == B_Mask && m_layer == B_Cu ) ) )
1760 {
1761 return true;
1762 }
1763
1764 return false;
1765}
1766
1767
1769{
1770 if( IsCopperLayer( aLayer ) &&
1771 LAYER_RANGE::Contains( Padstack().Drill().start, Padstack().Drill().end, aLayer ) )
1772 {
1773 return true;
1774 }
1775
1776 // Test for via on mask layers: a via on on a mask layer if not tented and if
1777 // it is on the corresponding external copper layer
1778 if( aLayer == F_Mask )
1779 return Padstack().Drill().start == F_Cu && !IsTented( F_Mask );
1780 else if( aLayer == B_Mask )
1781 return Padstack().Drill().end == B_Cu && !IsTented( B_Mask );
1782
1783 return false;
1784}
1785
1786
1788{
1789 return true;
1790}
1791
1792
1793bool PCB_VIA::HasValidLayerPair( int aCopperLayerCount ) const
1794{
1795 // return true if top and bottom layers are valid, depending on the copper layer count
1796 // aCopperLayerCount is expected >= 2
1797
1798 int layer_id = aCopperLayerCount*2;
1799
1800 if( Padstack().Drill().start > B_Cu )
1801 {
1802 if( Padstack().Drill().start > layer_id )
1803 return false;
1804 }
1805 if( Padstack().Drill().end > B_Cu )
1806 {
1807 if( Padstack().Drill().end > layer_id )
1808 return false;
1809 }
1810
1811 return true;
1812}
1813
1814
1816{
1817 return Padstack().Drill().start;
1818}
1819
1820
1822{
1823 Padstack().Drill().start = aLayer;
1824}
1825
1826
1827void PCB_TRACK::SetLayerSet( const LSET& aLayerSet )
1828{
1829 aLayerSet.RunOnLayers(
1830 [&]( PCB_LAYER_ID layer )
1831 {
1832 if( IsCopperLayer( layer ) )
1833 SetLayer( layer );
1834 else if( IsSolderMaskLayer( layer ) )
1835 SetHasSolderMask( true );
1836 } );
1837}
1838
1839
1841{
1842 LSET layermask( { m_layer } );
1843
1844 if( m_hasSolderMask )
1845 {
1846 if( layermask.test( F_Cu ) )
1847 layermask.set( F_Mask );
1848 else if( layermask.test( B_Cu ) )
1849 layermask.set( B_Mask );
1850 }
1851
1852 return layermask;
1853}
1854
1855
1857{
1858 LSET layermask;
1859
1860 if( Padstack().Drill().start < PCBNEW_LAYER_ID_START )
1861 return layermask;
1862
1863 if( GetViaType() == VIATYPE::THROUGH )
1864 {
1865 layermask = LSET::AllCuMask( BoardCopperLayerCount() );
1866 }
1867 else
1868 {
1869 LAYER_RANGE range( Padstack().Drill().start, Padstack().Drill().end, BoardCopperLayerCount() );
1870
1871 int cnt = BoardCopperLayerCount();
1872 // PCB_LAYER_IDs are numbered from front to back, this is top to bottom.
1873 for( PCB_LAYER_ID id : range )
1874 {
1875 layermask.set( id );
1876
1877 if( --cnt <= 0 )
1878 break;
1879 }
1880 }
1881
1882 if( !IsTented( F_Mask ) && layermask.test( F_Cu ) )
1883 layermask.set( F_Mask );
1884
1885 if( !IsTented( B_Mask ) && layermask.test( B_Cu ) )
1886 layermask.set( B_Mask );
1887
1888 return layermask;
1889}
1890
1891
1892void PCB_VIA::SetLayerSet( const LSET& aLayerSet )
1893{
1894 // Vias do not use a LSET, just a top and bottom layer pair
1895 // So we need to set these 2 layers according to the allowed layers in aLayerSet
1896
1897 // For via through, only F_Cu and B_Cu are allowed. aLayerSet is ignored
1898 if( GetViaType() == VIATYPE::THROUGH )
1899 {
1900 Padstack().Drill().start = F_Cu;
1901 Padstack().Drill().end = B_Cu;
1902 return;
1903 }
1904
1905 // For blind buried vias, find the top and bottom layers
1906 bool top_found = false;
1907 bool bottom_found = false;
1908
1909 aLayerSet.RunOnLayers(
1910 [&]( PCB_LAYER_ID layer )
1911 {
1912 // tpo layer and bottom Layer are copper layers, so consider only copper layers
1913 if( IsCopperLayer( layer ) )
1914 {
1915 // The top layer is the first layer found in list and
1916 // cannot the B_Cu
1917 if( !top_found && layer != B_Cu )
1918 {
1919 Padstack().Drill().start = layer;
1920 top_found = true;
1921 }
1922
1923 // The bottom layer is the last layer found in list or B_Cu
1924 if( !bottom_found )
1925 Padstack().Drill().end = layer;
1926
1927 if( layer == B_Cu )
1928 bottom_found = true;
1929 }
1930 } );
1931}
1932
1933
1934void PCB_VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer )
1935{
1936 Padstack().Drill().start = aTopLayer;
1937 Padstack().Drill().end = aBottomLayer;
1939
1940 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1941 {
1942 if( BOARD* board = GetBoard() )
1943 board->InvalidateClearanceCache( m_Uuid );
1944 }
1945}
1946
1947
1949{
1950 // refuse invalid via
1951 if( aLayer == Padstack().Drill().end )
1952 return;
1953
1954 Padstack().Drill().start = aLayer;
1956
1957 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1958 {
1959 if( BOARD* board = GetBoard() )
1960 board->InvalidateClearanceCache( m_Uuid );
1961 }
1962}
1963
1964
1966{
1967 // refuse invalid via
1968 if( aLayer == Padstack().Drill().start )
1969 return;
1970
1971 Padstack().Drill().end = aLayer;
1973
1974 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1975 {
1976 if( BOARD* board = GetBoard() )
1977 board->InvalidateClearanceCache( m_Uuid );
1978 }
1979}
1980
1981
1982void PCB_VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) const
1983{
1984 PCB_LAYER_ID t_layer = F_Cu;
1985 PCB_LAYER_ID b_layer = B_Cu;
1986
1987 if( GetViaType() != VIATYPE::THROUGH )
1988 {
1989 b_layer = Padstack().Drill().end;
1990 t_layer = Padstack().Drill().start;
1991
1992 if( !IsCopperLayerLowerThan( b_layer, t_layer ) )
1993 std::swap( b_layer, t_layer );
1994 }
1995
1996 if( top_layer )
1997 *top_layer = t_layer;
1998
1999 if( bottom_layer )
2000 *bottom_layer = b_layer;
2001}
2002
2003
2005{
2006 return Padstack().Drill().start;
2007}
2008
2009
2011{
2012 return Padstack().Drill().end;
2013}
2014
2015
2017{
2018 if( GetViaType() == VIATYPE::THROUGH )
2019 {
2020 Padstack().Drill().start = F_Cu;
2021 Padstack().Drill().end = B_Cu;
2022 }
2023
2024 if( !IsCopperLayerLowerThan( Padstack().Drill().end, Padstack().Drill().start) )
2025 std::swap( Padstack().Drill().end, Padstack().Drill().start );
2026
2027 int copperCount = BoardCopperLayerCount();
2028
2029 auto sanitizeBackdrill =
2030 [copperCount]( PADSTACK::DRILL_PROPS& aDrill )
2031 {
2032 if( aDrill.start != UNDEFINED_LAYER && !IsCopperLayer( aDrill.start ) )
2033 aDrill.start = UNDEFINED_LAYER;
2034
2035 if( aDrill.end != UNDEFINED_LAYER && !IsCopperLayer( aDrill.end ) )
2036 aDrill.end = UNDEFINED_LAYER;
2037
2038 if( copperCount > 0 )
2039 {
2040 LSET cuMask = LSET::AllCuMask( copperCount );
2041
2042 if( aDrill.start != UNDEFINED_LAYER && !cuMask.Contains( aDrill.start ) )
2043 aDrill.start = UNDEFINED_LAYER;
2044
2045 if( aDrill.end != UNDEFINED_LAYER && !cuMask.Contains( aDrill.end ) )
2046 aDrill.end = UNDEFINED_LAYER;
2047 }
2048
2049 // A backdrill side with no must-cut layer does not exist.
2050 if( aDrill.end == UNDEFINED_LAYER )
2051 aDrill.size = { 0, 0 };
2052 };
2053
2054 sanitizeBackdrill( Padstack().SecondaryDrill() );
2055 sanitizeBackdrill( Padstack().TertiaryDrill() );
2056}
2057
2058
2059std::optional<PCB_VIA::VIA_PARAMETER_ERROR>
2060PCB_VIA::ValidateViaParameters( std::optional<int> aDiameter,
2061 std::optional<int> aPrimaryDrill,
2062 std::optional<PCB_LAYER_ID> aPrimaryStartLayer,
2063 std::optional<PCB_LAYER_ID> aPrimaryEndLayer,
2064 std::optional<int> aSecondaryDrill,
2065 std::optional<PCB_LAYER_ID> aSecondaryStartLayer,
2066 std::optional<PCB_LAYER_ID> aSecondaryEndLayer,
2067 std::optional<int> aTertiaryDrill,
2068 std::optional<PCB_LAYER_ID> aTertiaryStartLayer,
2069 std::optional<PCB_LAYER_ID> aTertiaryEndLayer,
2070 int aCopperLayerCount )
2071{
2072 VIA_PARAMETER_ERROR error;
2073
2074 if( aDiameter.has_value() && aDiameter.value() < GEOMETRY_MIN_SIZE )
2075 {
2076 error.m_Message = _( "Via diameter is too small." );
2077 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DIAMETER;
2078 return error;
2079 }
2080
2081 if( aPrimaryDrill.has_value() && aPrimaryDrill.value() < GEOMETRY_MIN_SIZE )
2082 {
2083 error.m_Message = _( "Via drill is too small." );
2084 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DRILL;
2085 return error;
2086 }
2087
2088 if( aDiameter.has_value() && !aPrimaryDrill.has_value() )
2089 {
2090 error.m_Message = _( "No via hole size defined." );
2091 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DRILL;
2092 return error;
2093 }
2094
2095 if( aPrimaryDrill.has_value() && !aDiameter.has_value() )
2096 {
2097 error.m_Message = _( "No via diameter defined." );
2098 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DIAMETER;
2099 return error;
2100 }
2101
2102 if( aDiameter.has_value() && aPrimaryDrill.has_value()
2103 && aDiameter.value() <= aPrimaryDrill.value() )
2104 {
2105 error.m_Message = _( "Via hole size must be smaller than via diameter" );
2106 error.m_Field = VIA_PARAMETER_ERROR::FIELD::DRILL;
2107 return error;
2108 }
2109
2110 std::optional<LSET> copperMask;
2111
2112 auto validateLayer = [&]( std::optional<PCB_LAYER_ID> aLayer,
2113 VIA_PARAMETER_ERROR::FIELD aField ) -> bool
2114 {
2115 if( !aLayer.has_value() )
2116 return true;
2117
2118 PCB_LAYER_ID layer = aLayer.value();
2119
2120 if( layer == UNDEFINED_LAYER )
2121 return true;
2122
2123 if( !IsCopperLayer( layer ) )
2124 {
2125 error.m_Message = _( "Via layer must be a copper layer." );
2126 error.m_Field = aField;
2127 return false;
2128 }
2129
2130 if( aCopperLayerCount > 0 )
2131 {
2132 if( !copperMask.has_value() )
2133 copperMask = LSET::AllCuMask( aCopperLayerCount );
2134
2135 if( !copperMask->Contains( layer ) )
2136 {
2137 error.m_Message = _( "Via layer is outside the board stack." );
2138 error.m_Field = aField;
2139 return false;
2140 }
2141 }
2142
2143 return true;
2144 };
2145
2146 if( !validateLayer( aPrimaryStartLayer, VIA_PARAMETER_ERROR::FIELD::START_LAYER ) )
2147 return error;
2148
2149 if( !validateLayer( aPrimaryEndLayer, VIA_PARAMETER_ERROR::FIELD::END_LAYER ) )
2150 return error;
2151
2152 if( aPrimaryStartLayer.has_value() && aPrimaryEndLayer.has_value()
2153 && aPrimaryStartLayer.value() == aPrimaryEndLayer.value() )
2154 {
2155 error.m_Message = _( "Via start layer and end layer cannot be the same" );
2156 error.m_Field = VIA_PARAMETER_ERROR::FIELD::START_LAYER;
2157 return error;
2158 }
2159
2160 if( aSecondaryDrill.has_value() )
2161 {
2162 if( aSecondaryDrill.value() < aPrimaryDrill.value_or( GEOMETRY_MIN_SIZE ) )
2163 {
2164 error.m_Message = _( "Backdrill diameter is too small." );
2165 error.m_Field = VIA_PARAMETER_ERROR::FIELD::SECONDARY_DRILL;
2166 return error;
2167 }
2168
2169 if( !validateLayer( aSecondaryStartLayer, VIA_PARAMETER_ERROR::FIELD::SECONDARY_START_LAYER ) )
2170 return error;
2171
2172 if( !validateLayer( aSecondaryEndLayer, VIA_PARAMETER_ERROR::FIELD::SECONDARY_END_LAYER ) )
2173 return error;
2174 }
2175
2176 if( aTertiaryDrill.has_value() )
2177 {
2178 if( aTertiaryDrill.value() < aPrimaryDrill.value_or( GEOMETRY_MIN_SIZE ) )
2179 {
2180 error.m_Message = _( "Tertiary backdrill diameter is too small." );
2181 error.m_Field = VIA_PARAMETER_ERROR::FIELD::TERTIARY_DRILL;
2182 return error;
2183 }
2184
2185 if( !validateLayer( aTertiaryStartLayer, VIA_PARAMETER_ERROR::FIELD::TERTIARY_START_LAYER ) )
2186 return error;
2187
2188 if( !validateLayer( aTertiaryEndLayer, VIA_PARAMETER_ERROR::FIELD::TERTIARY_END_LAYER ) )
2189 return error;
2190 }
2191
2192 return std::nullopt;
2193}
2194
2195
2197{
2198 return m_viaType == VIATYPE::MICROVIA;
2199}
2200
2201
2203{
2204 // We don't actually have an GUI or file tokens to differentiate these, so we have to look at
2205 // the layers.
2207 {
2208 bool startOuter = Padstack().Drill().start == F_Cu || Padstack().Drill().start == B_Cu;
2209 bool endOuter = Padstack().Drill().end == F_Cu || Padstack().Drill().end == B_Cu;
2210
2211 return startOuter ^ endOuter;
2212 }
2213
2214 return false;
2215}
2216
2217
2219{
2220 // We don't actually have an GUI or file tokens to differentiate these, so we have to look at
2221 // the layers.
2223 {
2224 return Padstack().Drill().start != F_Cu && Padstack().Drill().start != B_Cu
2225 && Padstack().Drill().end != F_Cu && Padstack().Drill().end != B_Cu;
2226 }
2227
2228 return false;
2229}
2230
2231
2233{
2236 {
2237 switch( aLayer )
2238 {
2239 case F_Cu:
2240 if( Padstack().Drill().start != F_Cu )
2241 return true;
2242
2243 break;
2244
2245 case B_Cu:
2246 if( Padstack().Drill().end != B_Cu )
2247 return true;
2248
2249 break;
2250
2252 if( GetBoard() && GetBoard()->GetCopperLayerCount() == 2 )
2253 return true;
2254
2255 break;
2256
2257 default:
2258 wxFAIL_MSG( wxT( "Unsupported layer for FRONT_INNER_BACK" ) );
2259 }
2260 }
2261
2262 return false;
2263}
2264
2265
2266bool PCB_VIA::FlashLayer( const LSET& aLayers ) const
2267{
2268 for( PCB_LAYER_ID layer : aLayers )
2269 {
2270 if( FlashLayer( layer ) )
2271 return true;
2272 }
2273
2274 return false;
2275}
2276
2277
2278bool PCB_VIA::FlashLayer( int aLayer ) const
2279{
2280 // Return the "normal" shape if the caller doesn't specify a particular layer
2281 if( aLayer == UNDEFINED_LAYER )
2282 return true;
2283
2284 const BOARD* board = GetBoard();
2285 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer );
2286
2287 if( !board )
2288 return true;
2289
2290 if( !IsOnLayer( layer ) )
2291 return false;
2292
2293 if( !IsCopperLayer( layer ) )
2294 return true;
2295
2296 switch( Padstack().UnconnectedLayerMode() )
2297 {
2299 return true;
2300
2302 if( layer == Padstack().Drill().start || layer == Padstack().Drill().end )
2303 return true;
2304
2305 // Check for removal below
2306 break;
2307
2309 // Check for removal below
2310 break;
2311
2313 return layer == Padstack().Drill().start || layer == Padstack().Drill().end;
2314 }
2315
2316 if( GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
2317 {
2318 return true;
2319 }
2320 else
2321 {
2322 // Must be static to keep from raising its ugly head in performance profiles
2323 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
2324 PCB_PAD_T };
2325
2326 return board->GetConnectivity()->IsConnectedOnLayer( this, layer, nonZoneTypes );
2327 }
2328}
2329
2330
2331// IsCopperLayer() accepts any even id below PCB_LAYER_ID_COUNT, but only F_Cu..In30_Cu carry a
2332// distinct ordinal. Anything above aliases B_Cu or indexes past the override array
2333static bool hasLayerOrdinal( PCB_LAYER_ID aLayer )
2334{
2335 return IsCopperLayer( aLayer ) && aLayer <= In30_Cu;
2336}
2337
2338
2340{
2341 for( std::atomic<ZONE_LAYER_OVERRIDE>& entry : m_zoneLayerOverrides )
2342 entry.store( ZLO_NONE, std::memory_order_relaxed );
2343}
2344
2345
2347{
2348 if( !hasLayerOrdinal( aLayer ) )
2349 return ZLO_NONE;
2350
2351 return m_zoneLayerOverrides[CopperLayerToOrdinal( aLayer )].load( std::memory_order_relaxed );
2352}
2353
2354
2356{
2357 if( !hasLayerOrdinal( aLayer ) )
2358 return;
2359
2360 m_zoneLayerOverrides[CopperLayerToOrdinal( aLayer )].store( aOverride, std::memory_order_relaxed );
2361}
2362
2363
2365 PCB_LAYER_ID* aBottommost ) const
2366{
2367 *aTopmost = UNDEFINED_LAYER;
2368 *aBottommost = UNDEFINED_LAYER;
2369
2370 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
2371 PCB_PAD_T };
2372
2373 for( int layer = TopLayer(); layer <= BottomLayer(); ++layer )
2374 {
2375 bool connected = false;
2376
2377 if( GetZoneLayerOverride( static_cast<PCB_LAYER_ID>( layer ) ) == ZLO_FORCE_FLASHED )
2378 {
2379 connected = true;
2380 }
2381 else if( GetBoard()->GetConnectivity()->IsConnectedOnLayer( this, layer, nonZoneTypes ) )
2382 {
2383 connected = true;
2384 }
2385
2386 if( connected )
2387 {
2388 if( *aTopmost == UNDEFINED_LAYER )
2389 *aTopmost = ToLAYER_ID( layer );
2390
2391 *aBottommost = ToLAYER_ID( layer );
2392 }
2393 }
2394
2395}
2396
2397
2398std::vector<int> PCB_TRACK::ViewGetLayers() const
2399{
2400 // Show the track and its netname on different layers
2401 const PCB_LAYER_ID layer = GetLayer();
2402 std::vector<int> layers{
2403 layer,
2404 GetNetnameLayer( layer ),
2405 LAYER_CLEARANCE_START + layer,
2406 };
2407
2408 layers.reserve( 6 );
2409
2410 if( m_hasSolderMask )
2411 {
2412 if( m_layer == F_Cu )
2413 layers.push_back( F_Mask );
2414 else if( m_layer == B_Cu )
2415 layers.push_back( B_Mask );
2416 }
2417
2418 if( IsLocked() )
2419 layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
2420
2421 return layers;
2422}
2423
2424
2425double PCB_TRACK::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
2426{
2427 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
2428 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
2429
2430 if( !aView->IsLayerVisibleCached( LAYER_TRACKS ) )
2431 return LOD_HIDE;
2432
2433 if( IsNetnameLayer( aLayer ) )
2434 {
2436 return LOD_HIDE;
2437
2438 // Hide netnames on dimmed tracks
2439 if( renderSettings->GetHighContrast() )
2440 {
2441 if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
2442 return LOD_HIDE;
2443 }
2444
2445 VECTOR2I start( GetStart() );
2446 VECTOR2I end( GetEnd() );
2447
2448 // Calc the approximate size of the netname (assume square chars)
2449 SEG::ecoord nameSize = GetDisplayNetname().size() * GetWidth();
2450
2451 if( VECTOR2I( end - start ).SquaredEuclideanNorm() < nameSize * nameSize )
2452 return LOD_HIDE;
2453
2454 BOX2I clipBox = BOX2ISafe( aView->GetViewport() );
2455
2456 ClipLine( &clipBox, start.x, start.y, end.x, end.y );
2457
2458 if( VECTOR2I( end - start ).SquaredEuclideanNorm() == 0 )
2459 return LOD_HIDE;
2460
2461 // Netnames will be shown only if zoom is appropriate
2462 return lodScaleForThreshold( aView, m_width, pcbIUScale.mmToIU( 4.0 ) );
2463 }
2464
2465 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
2466 {
2467 // Hide shadow if the main layer is not shown
2468 if( !aView->IsLayerVisibleCached( m_layer ) )
2469 return LOD_HIDE;
2470
2471 // Hide shadow on dimmed tracks
2472 if( renderSettings->GetHighContrast() )
2473 {
2474 if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
2475 return LOD_HIDE;
2476 }
2477 }
2478
2479 // Other layers are shown without any conditions
2480 return LOD_SHOW;
2481}
2482
2483
2485{
2486 BOX2I bbox = GetBoundingBox();
2487
2488 if( const BOARD* board = GetBoard() )
2489 {
2490 bbox.Inflate( 2 * board->GetDesignSettings().GetBiggestClearanceValue() );
2491
2492 // Only a via drills, so a plain segment would just be given an oversized box
2493 if( HasHole() )
2494 bbox = board->ExpandBoundingBoxForDrillSymbols( bbox );
2495 }
2496 else
2497 {
2498 bbox.Inflate( GetWidth() ); // Add a bit extra for safety
2499 }
2500
2501 return bbox;
2502}
2503
2504
2505std::vector<int> PCB_VIA::ViewGetLayers() const
2506{
2507 LAYER_RANGE layers( Padstack().Drill().start, Padstack().Drill().end, MAX_CU_LAYERS );
2508 std::vector<int> ret_layers{ LAYER_VIA_HOLES, LAYER_VIA_HOLEWALLS, LAYER_VIA_NETNAMES };
2509 ret_layers.reserve( MAX_CU_LAYERS + 6 );
2510
2511 // A drill map on a layer asks the holes to draw their symbols there, so the symbols stay
2512 // in the view index and one hole edit repaints one hole
2513 if( const BOARD* drillBoard = GetBoard() )
2514 {
2515 for( PCB_LAYER_ID mapLayer : drillBoard->DrillSymbolLayers().Seq() )
2516 ret_layers.push_back( DRILL_SYMBOL_LAYER_FOR( mapLayer ) );
2517 }
2518
2519 // TODO(JE) Rendering order issue
2520#if 0
2521 // Blind/buried vias (and microvias) use a different net name layer
2522 PCB_LAYER_ID layerTop, layerBottom;
2523 LayerPair( &layerTop, &layerBottom );
2524
2525 bool isBlindBuried =
2528 || ( m_viaType == VIATYPE::MICROVIA && ( layerTop != F_Cu || layerBottom != B_Cu ) );
2529#endif
2530 LSET cuMask = LSET::AllCuMask();
2531
2532 if( const BOARD* board = GetBoard() )
2533 cuMask &= board->GetEnabledLayers();
2534
2535 for( PCB_LAYER_ID layer : layers )
2536 {
2537 if( !cuMask.Contains( layer ) )
2538 continue;
2539
2540 ret_layers.push_back( LAYER_VIA_COPPER_START + layer );
2541 ret_layers.push_back( LAYER_CLEARANCE_START + layer );
2542 }
2543
2544 if( IsLocked() )
2545 ret_layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
2546
2547 // Vias can also be on a solder mask layer. They are on these layers or not,
2548 // depending on the plot and solder mask options
2549 if( IsOnLayer( F_Mask ) )
2550 ret_layers.push_back( F_Mask );
2551
2552 if( IsOnLayer( B_Mask ) )
2553 ret_layers.push_back( B_Mask );
2554
2555 return ret_layers;
2556}
2557
2558
2559double PCB_VIA::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
2560{
2561 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
2562 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
2563 const BOARD* board = GetBoard();
2564
2565 // Reviewing a drill drawing with vias hidden is normal, so the symbols answer to the
2566 // map's own layer rather than to the vias meta control
2567 if( IsDrillSymbolLayer( aLayer ) )
2568 {
2569 return aView->IsLayerVisibleCached( aLayer - LAYER_DRILL_SYMBOL_START ) ? LOD_SHOW
2570 : LOD_HIDE;
2571 }
2572
2573 // Meta control for hiding all vias
2574 if( !aView->IsLayerVisibleCached( LAYER_VIAS ) )
2575 return LOD_HIDE;
2576
2577 // In high contrast mode don't show vias that don't cross the high-contrast layer
2578 if( renderSettings->GetHighContrast() )
2579 {
2580 PCB_LAYER_ID highContrastLayer = renderSettings->GetPrimaryHighContrastLayer();
2581
2582 if( LSET::FrontTechMask().Contains( highContrastLayer ) )
2583 highContrastLayer = F_Cu;
2584 else if( LSET::BackTechMask().Contains( highContrastLayer ) )
2585 highContrastLayer = B_Cu;
2586
2587 if( IsCopperLayer( highContrastLayer ) && GetViaType() != VIATYPE::THROUGH )
2588 {
2589 if( IsCopperLayerLowerThan( Padstack().Drill().start, highContrastLayer )
2590 || IsCopperLayerLowerThan( highContrastLayer, Padstack().Drill().end ) )
2591 {
2592 return LOD_HIDE;
2593 }
2594 }
2595 }
2596
2597 if( IsHoleLayer( aLayer ) )
2598 {
2599 LSET visible;
2600
2601 if( board )
2602 {
2603 visible = board->GetVisibleLayers();
2604 visible &= board->GetEnabledLayers();
2605 }
2606 else
2607 {
2608 visible = LSET::AllLayersMask();
2609 }
2610
2612 {
2613 // Show a through via's hole if any physical layer is shown
2614 visible &= LSET::PhysicalLayersMask();
2615
2616 if( !visible.any() )
2617 return LOD_HIDE;
2618 }
2619 else
2620 {
2621 // Show a blind or micro via's hole if it crosses a visible layer
2622 visible &= GetLayerSet();
2623
2624 if( !visible.any() )
2625 return LOD_HIDE;
2626 }
2627
2628 // The hole won't be visible anyway at this scale
2629 return lodScaleForThreshold( aView, GetDrillValue(), pcbIUScale.mmToIU( 0.25 ) );
2630 }
2631 else if( IsNetnameLayer( aLayer ) )
2632 {
2633 if( renderSettings->GetHighContrast() )
2634 {
2635 // Hide netnames unless via is flashed to a high-contrast layer
2636 if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
2637 return LOD_HIDE;
2638 }
2639 else
2640 {
2641 LSET visible;
2642
2643 if( board )
2644 {
2645 visible = board->GetVisibleLayers();
2646 visible &= board->GetEnabledLayers();
2647 }
2648 else
2649 {
2650 visible = LSET::AllLayersMask();
2651 }
2652
2653 // Hide netnames unless pad is flashed to a visible layer
2654 if( !FlashLayer( visible ) )
2655 return LOD_HIDE;
2656 }
2657
2658 int width = GetWidth( ToLAYER_ID( aLayer ) );
2659
2660 // Netnames will be shown only if zoom is appropriate
2661 return lodScaleForThreshold( aView, width, pcbIUScale.mmToIU( 10 ) );
2662 }
2663
2664 if( !IsCopperLayer( aLayer ) )
2665 {
2666 int width = GetWidth( ToLAYER_ID( aLayer ) );
2667
2668 return lodScaleForThreshold( aView, width, pcbIUScale.mmToIU( 0.6 ) );
2669 }
2670
2671 return LOD_SHOW;
2672}
2673
2674
2676{
2677 switch( Type() )
2678 {
2679 case PCB_ARC_T: return _( "Track (arc)" );
2680 case PCB_VIA_T: return _( "Via" );
2681 case PCB_TRACE_T:
2682 default: return _( "Track" );
2683 }
2684}
2685
2686
2687void PCB_TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2688{
2689 wxString msg;
2690 BOARD* board = GetBoard();
2691
2692 aList.emplace_back( _( "Type" ), GetFriendlyName() );
2693
2694 GetMsgPanelInfoBase_Common( aFrame, aList );
2695
2696 aList.emplace_back( _( "Layer" ), LayerMaskDescribe() );
2697
2698 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( m_width ) );
2699
2700 if( Type() == PCB_ARC_T )
2701 {
2702 double radius = static_cast<PCB_ARC*>( this )->GetRadius();
2703 aList.emplace_back( _( "Radius" ), aFrame->MessageTextFromValue( radius ) );
2704
2705 aList.emplace_back( _( "Angle" ), wxString::Format( "%.2fdeg",
2706 static_cast<PCB_ARC*>(this)->GetAngle().AsDegrees() ) );
2707 }
2708
2709 double segmentLength = GetLength();
2710 double segmentDelay = GetDelay();
2711
2712 if( segmentDelay == 0.0 )
2713 {
2714 aList.emplace_back( _( "Segment Length" ), aFrame->MessageTextFromValue( segmentLength ) );
2715 }
2716 else
2717 {
2718 aList.emplace_back( _( "Segment Delay" ),
2719 aFrame->MessageTextFromValue( segmentDelay, true, EDA_DATA_TYPE::TIME ) );
2720 }
2721
2722 // Display full track length (in Pcbnew)
2723 if( board && GetNetCode() > 0 )
2724 {
2725 int count = 0;
2726 double trackLen = 0.0;
2727 double lenPadToDie = 0.0;
2728 double trackDelay = 0.0;
2729 double delayPadToDie = 0.0;
2730
2731 std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *this );
2732
2733 if( trackDelay == 0.0 )
2734 {
2735 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
2736
2737 if( lenPadToDie != 0 )
2738 {
2739 msg = aFrame->MessageTextFromValue( lenPadToDie );
2740 aList.emplace_back( _( "Pad To Die Length" ), msg );
2741
2742 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
2743 aList.emplace_back( _( "Full Length" ), msg );
2744 }
2745 }
2746 else
2747 {
2748 aList.emplace_back( _( "Routed Delay" ),
2749 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) );
2750
2751 if( delayPadToDie != 0.0 )
2752 {
2753 msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME );
2754 aList.emplace_back( _( "Pad To Die Delay" ), msg );
2755
2756 msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME );
2757 aList.emplace_back( _( "Full Delay" ), msg );
2758 }
2759 }
2760 }
2761
2762 SHAPE_POLY_SET copper;
2764 aList.emplace_back( _( "Copper Area" ),
2765 aFrame->MessageTextFromValue( copper.Area(), true, EDA_DATA_TYPE::AREA ) );
2766
2767 wxString source;
2769
2770 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2771 aFrame->MessageTextFromValue( clearance ) ),
2772 wxString::Format( _( "(from %s)" ), source ) );
2773
2774 MINOPTMAX<int> constraintValue = GetWidthConstraint( &source );
2775 msg = aFrame->MessageTextFromMinOptMax( constraintValue );
2776
2777 if( !msg.IsEmpty() )
2778 {
2779 aList.emplace_back( wxString::Format( _( "Width Constraints: %s" ), msg ),
2780 wxString::Format( _( "(from %s)" ), source ) );
2781 }
2782}
2783
2784
2785void PCB_VIA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2786{
2787 wxString msg;
2788
2789 switch( GetViaType() )
2790 {
2791 case VIATYPE::MICROVIA: msg = _( "Micro Via" ); break;
2792 case VIATYPE::BLIND: msg = _( "Blind Via" ); break;
2793 case VIATYPE::BURIED: msg = _( "Buried Via" ); break;
2794 case VIATYPE::THROUGH: msg = _( "Through Via" ); break;
2795 default: msg = _( "Via" ); break;
2796 }
2797
2798 aList.emplace_back( _( "Type" ), msg );
2799
2800 GetMsgPanelInfoBase_Common( aFrame, aList );
2801
2802 aList.emplace_back( _( "Layer" ), LayerMaskDescribe() );
2803
2804 std::set<int> widths;
2805 m_padStack.ForEachUniqueLayer(
2806 [&]( PCB_LAYER_ID aLayer )
2807 {
2808 if( IsGhostLayer( aLayer ) )
2809 return;
2810
2811 widths.insert( GetWidth( aLayer ) );
2812 } );
2813
2814 if( widths.size() == 1 )
2815 aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( *widths.begin() ) );
2816 else
2817 aList.emplace_back( _( "Diameter" ), _( "(mixed)" ) );
2818
2819 aList.emplace_back( _( "Hole" ), aFrame->MessageTextFromValue( GetDrillValue() ) );
2820
2821 wxString source;
2823
2824 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ), aFrame->MessageTextFromValue( clearance ) ),
2825 wxString::Format( _( "(from %s)" ), source ) );
2826
2827 int minAnnulus = GetMinAnnulus( GetLayer(), &source );
2828
2829 aList.emplace_back( wxString::Format( _( "Min Annular Width: %s" ), aFrame->MessageTextFromValue( minAnnulus ) ),
2830 wxString::Format( _( "(from %s)" ), source ) );
2831}
2832
2833
2834void PCB_TRACK::GetMsgPanelInfoBase_Common( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) const
2835{
2836 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
2837
2838 if( NETINFO_ITEM* netInfo = GetNet() )
2839 {
2840 const wxString& chainName = netInfo->GetNetChain();
2841
2842 if( !chainName.IsEmpty() )
2843 aList.emplace_back( _( "Net Chain" ), UnescapeString( chainName ) );
2844 }
2845
2846 aList.emplace_back( _( "Resolved Netclass" ),
2847 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
2848
2849#if 0 // Enable for debugging
2850 if( GetBoard() )
2851 aList.emplace_back( _( "NetCode" ), fmt::format( "{}", GetNetCode() ) );
2852
2853 aList.emplace_back( wxT( "Flags" ), fmt::format( "#08X", m_flags ) );
2854
2855 aList.emplace_back( wxT( "Start pos" ), fmt::format( "{} {}", m_Start.x, m_Start.y ) );
2856 aList.emplace_back( wxT( "End pos" ), fmt::format( "{} {}", m_End.x, m_End.y ) );
2857#endif
2858
2859 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
2860 aList.emplace_back( _( "Status" ), _( "Locked" ) );
2861}
2862
2863
2865{
2866 const BOARD* board = GetBoard();
2867 PCB_LAYER_ID top_layer;
2868 PCB_LAYER_ID bottom_layer;
2869
2870 LayerPair( &top_layer, &bottom_layer );
2871
2872 return board->GetLayerName( top_layer ) + wxT( " - " ) + board->GetLayerName( bottom_layer );
2873}
2874
2875
2876double PCB_TRACK::GetCoverageArea( int aTextMargin ) const
2877{
2878 // Width squared, so a long track does not outrank a short one it happens to cross
2879 const double width = GetWidth();
2880 return width * width;
2881}
2882
2883
2884bool PCB_TRACK::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2885{
2886 return TestSegmentHit( aPosition, m_Start, m_End, aAccuracy + ( m_width / 2 ) );
2887}
2888
2889
2890bool PCB_ARC::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2891{
2892 double max_dist = aAccuracy + ( GetWidth() / 2.0 );
2893
2894 // Short-circuit common cases where the arc is connected to a track or via at an endpoint
2895 if( GetStart().Distance( aPosition ) <= max_dist || GetEnd().Distance( aPosition ) <= max_dist )
2896 {
2897 return true;
2898 }
2899
2901 VECTOR2L relpos = aPosition - center;
2902 int64_t dist = relpos.EuclideanNorm();
2903 double radius = GetRadius();
2904
2905 if( std::abs( dist - radius ) > max_dist )
2906 return false;
2907
2908 EDA_ANGLE arc_angle = GetAngle();
2909 EDA_ANGLE arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg
2910 EDA_ANGLE arc_hittest( relpos );
2911
2912 // Calculate relative angle between the starting point of the arc, and the test point
2913 arc_hittest -= arc_angle_start;
2914
2915 // Normalise arc_hittest between 0 ... 360 deg
2916 arc_hittest.Normalize();
2917
2918 if( arc_angle < ANGLE_0 )
2919 return arc_hittest >= ANGLE_360 + arc_angle;
2920
2921 return arc_hittest <= arc_angle;
2922}
2923
2924
2925double PCB_VIA::GetCoverageArea( int aTextMargin ) const
2926{
2927 // A via covers its pad, so the width rule it inherits from tracks does not apply
2928 return BOARD_ITEM::GetCoverageArea( aTextMargin );
2929}
2930
2931
2932bool PCB_VIA::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2933{
2934 bool hit = false;
2935
2937 [&]( PCB_LAYER_ID aLayer )
2938 {
2939 if( hit )
2940 return;
2941
2942 if( IsGhostLayer( aLayer ) )
2943 return;
2944
2945 int max_dist = aAccuracy + ( GetWidth( aLayer ) / 2 );
2946
2947 // rel_pos is aPosition relative to m_Start (or the center of the via)
2948 VECTOR2D rel_pos = aPosition - m_Start;
2949 double dist = rel_pos.x * rel_pos.x + rel_pos.y * rel_pos.y;
2950
2951 if( dist <= static_cast<double>( max_dist ) * max_dist )
2952 hit = true;
2953 } );
2954
2955 return hit;
2956}
2957
2958
2959bool PCB_TRACK::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2960{
2961 BOX2I arect = aRect;
2962 arect.Inflate( aAccuracy );
2963
2964 if( aContained )
2965 return arect.Contains( GetStart() ) && arect.Contains( GetEnd() );
2966 else
2967 return arect.Intersects( GetStart(), GetEnd() );
2968}
2969
2970
2971bool PCB_ARC::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2972{
2973 BOX2I arect = aRect;
2974 arect.Inflate( aAccuracy );
2975
2976 BOX2I box( GetStart() );
2977 box.Merge( GetMid() );
2978 box.Merge( GetEnd() );
2979
2980 box.Inflate( GetWidth() / 2 );
2981
2982 if( aContained )
2983 return arect.Contains( box );
2984 else
2985 return arect.Intersects( box );
2986}
2987
2988
2989bool PCB_VIA::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2990{
2991 BOX2I arect = aRect;
2992 arect.Inflate( aAccuracy );
2993
2994 bool hit = false;
2995
2997 [&]( PCB_LAYER_ID aLayer )
2998 {
2999 if( hit )
3000 return;
3001
3002 if( IsGhostLayer( aLayer ) )
3003 return;
3004
3005 BOX2I box( GetStart() );
3006 box.Inflate( GetWidth( aLayer ) / 2 );
3007
3008 if( aContained )
3009 hit = arect.Contains( box );
3010 else
3011 hit = arect.IntersectsCircle( GetStart(), GetWidth( aLayer ) / 2 );
3012 } );
3013
3014 return hit;
3015}
3016
3017
3018bool PCB_TRACK::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
3019{
3020 return KIGEOM::ShapeHitTest( aPoly, *GetEffectiveShape(), aContained );
3021}
3022
3023
3024wxString PCB_TRACK::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
3025{
3026 return wxString::Format( Type() == PCB_ARC_T ? _("Track (arc) %s on %s, length %s" )
3027 : _("Track %s on %s, length %s" ),
3028 GetNetnameMsg(),
3029 GetLayerName(),
3030 aUnitsProvider->MessageTextFromValue( GetLength() ) );
3031}
3032
3033
3035{
3036 return BITMAPS::add_tracks;
3037}
3038
3039
3041{
3042 wxASSERT( aImage->Type() == PCB_TRACE_T );
3043
3044 std::swap( *((PCB_TRACK*) this), *((PCB_TRACK*) aImage) );
3045}
3046
3047
3049{
3050 wxASSERT( aImage->Type() == PCB_ARC_T );
3051
3052 std::swap( *this, *static_cast<PCB_ARC*>( aImage ) );
3053}
3054
3055
3057{
3058 wxASSERT( aImage->Type() == PCB_VIA_T );
3059
3060 std::swap( *((PCB_VIA*) this), *((PCB_VIA*) aImage) );
3061}
3062
3063
3069
3070
3072{
3073 auto center = CalcArcCenter( m_Start, m_Mid , m_End );
3074 return std::min( center.Distance( m_Start ), (double) INT_MAX / 2.0 );
3075}
3076
3077
3079{
3081 EDA_ANGLE angle1 = EDA_ANGLE( m_Mid - center ) - EDA_ANGLE( m_Start - center );
3082 EDA_ANGLE angle2 = EDA_ANGLE( m_End - center ) - EDA_ANGLE( m_Mid - center );
3083
3084 return angle1.Normalize180() + angle2.Normalize180();
3085}
3086
3087
3089{
3090 VECTOR2D pos( GetPosition() );
3091 EDA_ANGLE angleStart( m_Start - pos );
3092
3093 return angleStart.Normalize();
3094}
3095
3096
3097// Note: used in python tests. Ignore CLion's claim that it's unused....
3099{
3100 VECTOR2D pos( GetPosition() );
3101 EDA_ANGLE angleEnd( m_End - pos );
3102
3103 return angleEnd.Normalize();
3104}
3105
3106bool PCB_ARC::IsDegenerated( int aThreshold ) const
3107{
3108 // We have lots of code that will blow up if the radius overflows an int.
3109 if( GetRadius() >= (double)INT_MAX/2.0 )
3110 return true;
3111
3112 // Too small arcs cannot be really handled: arc center (and arc radius)
3113 // cannot be safely computed if the distance between mid and end points
3114 // is too small (a few internal units)
3115
3116 // len of both segments must be < aThreshold to be a very small degenerated arc
3117 return ( GetMid() - GetStart() ).EuclideanNorm() < aThreshold
3118 && ( GetMid() - GetEnd() ).EuclideanNorm() < aThreshold;
3119}
3120
3121
3123{
3124 if( a->GetNetCode() != b->GetNetCode() )
3125 return a->GetNetCode() < b->GetNetCode();
3126
3127 if( a->GetLayer() != b->GetLayer() )
3128 return a->GetLayer() < b->GetLayer();
3129
3130 if( a->Type() != b->Type() )
3131 return a->Type() < b->Type();
3132
3133 if( a->m_Uuid != b->m_Uuid )
3134 return a->m_Uuid < b->m_Uuid;
3135
3136 return a < b;
3137}
3138
3139
3141{
3142 int width = m_width;
3143
3144 if( IsSolderMaskLayer( aLayer ) )
3145 width += 2 * GetSolderMaskExpansion();
3146
3147 return std::make_shared<SHAPE_SEGMENT>( m_Start, m_End, width );
3148}
3149
3150
3151std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash,
3152 DRC_CONSTRAINT_T aUsage ) const
3153{
3154 int diameter = 0;
3155
3156 if( aFlash == FLASHING::ALWAYS_FLASHED || ( aFlash == FLASHING::DEFAULT && FlashLayer( aLayer ) ) )
3157 {
3158 if( aLayer == UNDEFINED_LAYER )
3159 {
3160 Padstack().ForEachUniqueLayer(
3161 [&]( PCB_LAYER_ID layer )
3162 {
3163 if( IsGhostLayer( layer ) )
3164 return;
3165
3166 diameter = std::max( diameter, GetWidth( layer ) );
3167 } );
3168 }
3169 else
3170 {
3171 PCB_LAYER_ID cuLayer = m_padStack.EffectiveLayerFor( aLayer );
3172 diameter = GetWidth( cuLayer );
3173 }
3174 }
3175 else
3176 {
3177 diameter = GetDrillValue();
3178 }
3179
3180 // In some cases we want to add in any backdrill or post-machining
3181 if( ( aUsage == PHYSICAL_CLEARANCE_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) )
3182 || ( aUsage == SILK_CLEARANCE_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) ) )
3183 {
3184 diameter = std::max( diameter, Padstack().GetMaxHoleSize() );
3185 }
3186
3187 return std::make_shared<SHAPE_CIRCLE>( m_Start, diameter / 2 );
3188}
3189
3190
3192{
3193 int width = GetWidth();
3194
3195 if( IsSolderMaskLayer( aLayer ) )
3196 width += 2 * GetSolderMaskExpansion();
3197
3198 SHAPE_ARC arc( GetStart(), GetMid(), GetEnd(), width );
3199
3200 if( arc.IsEffectiveLine() )
3201 return std::make_shared<SHAPE_SEGMENT>( GetStart(), GetEnd(), width );
3202
3203 return std::make_shared<SHAPE_ARC>( arc );
3204}
3205
3206
3208 int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
3209{
3210 wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for tracks." ) );
3211
3212 switch( Type() )
3213 {
3214 case PCB_VIA_T:
3215 {
3216 int radius = ( static_cast<const PCB_VIA*>( this )->GetWidth( aLayer ) / 2 ) + aClearance;
3217 TransformCircleToPolygon( aBuffer, m_Start, radius, aError, aErrorLoc );
3218 break;
3219 }
3220
3221 case PCB_ARC_T:
3222 {
3223 const PCB_ARC* arc = static_cast<const PCB_ARC*>( this );
3224 int width = m_width + ( 2 * aClearance );
3225
3226 if( IsSolderMaskLayer( aLayer ) )
3227 width += 2 * GetSolderMaskExpansion();
3228
3229 TransformArcToPolygon( aBuffer, arc->GetStart(), arc->GetMid(), arc->GetEnd(), width, aError, aErrorLoc );
3230 break;
3231 }
3232
3233 default:
3234 {
3235 int width = m_width + ( 2 * aClearance );
3236
3237 if( IsSolderMaskLayer( aLayer ) )
3238 width += 2 * GetSolderMaskExpansion();
3239
3240 TransformOvalToPolygon( aBuffer, m_Start, m_End, width, aError, aErrorLoc );
3241
3242 break;
3243 }
3244 }
3245}
3246
3247
3248static struct TRACK_VIA_DESC
3249{
3251 {
3252 // clang-format off: the suggestion is less readable
3254 .Undefined( VIATYPE::NOT_DEFINED )
3255 .Map( VIATYPE::THROUGH, _HKI( "Through" ) )
3256 .Map( VIATYPE::BLIND, _HKI( "Blind" ) )
3257 .Map( VIATYPE::BURIED, _HKI( "Buried" ) )
3258 .Map( VIATYPE::MICROVIA, _HKI( "Micro" ) );
3259
3261 .Undefined( TENTING_MODE::FROM_BOARD )
3262 .Map( TENTING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
3263 .Map( TENTING_MODE::TENTED, _HKI( "Tented" ) )
3264 .Map( TENTING_MODE::NOT_TENTED, _HKI( "Not tented" ) );
3265
3267 .Undefined( COVERING_MODE::FROM_BOARD )
3268 .Map( COVERING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
3269 .Map( COVERING_MODE::COVERED, _HKI( "Covered" ) )
3270 .Map( COVERING_MODE::NOT_COVERED, _HKI( "Not covered" ) );
3271
3273 .Undefined( PLUGGING_MODE::FROM_BOARD )
3274 .Map( PLUGGING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
3275 .Map( PLUGGING_MODE::PLUGGED, _HKI( "Plugged" ) )
3276 .Map( PLUGGING_MODE::NOT_PLUGGED, _HKI( "Not plugged" ) );
3277
3279 .Undefined( CAPPING_MODE::FROM_BOARD )
3280 .Map( CAPPING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
3281 .Map( CAPPING_MODE::CAPPED, _HKI( "Capped" ) )
3282 .Map( CAPPING_MODE::NOT_CAPPED, _HKI( "Not capped" ) );
3283
3285 .Undefined( FILLING_MODE::FROM_BOARD )
3286 .Map( FILLING_MODE::FROM_BOARD, _HKI( "From board stackup" ) )
3287 .Map( FILLING_MODE::FILLED, _HKI( "Filled" ) )
3288 .Map( FILLING_MODE::NOT_FILLED, _HKI( "Not filled" ) );
3289
3290 // clang-format on: the suggestion is less readable
3291
3292 // Pad and via registration can run in either order across translation units.
3294
3295 if( pmMap.Choices().GetCount() == 0 )
3296 {
3301 }
3302
3304
3305 if( bdMap.Choices().GetCount() == 0 )
3306 {
3308 .Map( BACKDRILL_MODE::NO_BACKDRILL, _HKI( "No backdrill" ) )
3309 .Map( BACKDRILL_MODE::BACKDRILL_BOTTOM, _HKI( "Backdrill bottom" ) )
3310 .Map( BACKDRILL_MODE::BACKDRILL_TOP, _HKI( "Backdrill top" ) )
3311 .Map( BACKDRILL_MODE::BACKDRILL_BOTH, _HKI( "Backdrill both" ) );
3312 }
3313
3315
3316 if( layerEnum.Choices().GetCount() == 0 )
3317 {
3318 layerEnum.Undefined( UNDEFINED_LAYER );
3319
3320 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
3321 layerEnum.Map( layer, LSET::Name( layer ) );
3322 }
3323
3324 auto viaDiameterPropertyValidator =
3325 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
3326 {
3327 if( !aItem || aItem->Type() != PCB_VIA_T )
3328 return std::nullopt;
3329
3330 if( !aValue.CheckType<int>() )
3331 return std::nullopt;
3332
3333 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3334
3335 std::optional<int> diameter = aValue.As<int>();
3336 std::optional<int> drill = via->GetDrillValue();
3337
3338 std::optional<PCB_LAYER_ID> startLayer;
3339
3340 if( via->Padstack().Drill().start != UNDEFINED_LAYER )
3341 startLayer = via->Padstack().Drill().start;
3342
3343 std::optional<PCB_LAYER_ID> endLayer;
3344
3345 if( via->Padstack().Drill().end != UNDEFINED_LAYER )
3346 endLayer = via->Padstack().Drill().end;
3347
3348 int copperLayerCount = via->BoardCopperLayerCount();
3349
3350 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
3351 PCB_VIA::ValidateViaParameters( diameter, drill, startLayer, endLayer,
3352 std::nullopt, std::nullopt, std::nullopt, // secondary drill
3353 std::nullopt, std::nullopt, std::nullopt, // tertiary drill
3354 copperLayerCount ) )
3355 {
3356 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
3357 }
3358
3359 return std::nullopt;
3360 };
3361
3362 auto viaDrillPropertyValidator =
3363 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
3364 {
3365 if( !aItem || aItem->Type() != PCB_VIA_T )
3366 return std::nullopt;
3367
3368 if( !aValue.CheckType<int>() )
3369 return std::nullopt;
3370
3371 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3372
3373 std::optional<int> diameter = via->GetFrontWidth();
3374 std::optional<int> drill = aValue.As<int>();
3375
3376 std::optional<PCB_LAYER_ID> startLayer;
3377
3378 if( via->Padstack().Drill().start != UNDEFINED_LAYER )
3379 startLayer = via->Padstack().Drill().start;
3380
3381 std::optional<PCB_LAYER_ID> endLayer;
3382
3383 if( via->Padstack().Drill().end != UNDEFINED_LAYER )
3384 endLayer = via->Padstack().Drill().end;
3385
3386 std::optional<int> secondaryDrill = via->GetSecondaryDrillSize();
3387
3388 std::optional<PCB_LAYER_ID> secondaryStart;
3389
3390 if( via->GetSecondaryDrillStartLayer() != UNDEFINED_LAYER )
3391 secondaryStart = via->GetSecondaryDrillStartLayer();
3392
3393 std::optional<PCB_LAYER_ID> secondaryEnd;
3394
3395 if( via->GetSecondaryDrillEndLayer() != UNDEFINED_LAYER )
3396 secondaryEnd = via->GetSecondaryDrillEndLayer();
3397
3398 std::optional<int> tertiaryDrill = via->GetTertiaryDrillSize();
3399
3400 std::optional<PCB_LAYER_ID> tertiaryStart;
3401
3402 if( via->GetTertiaryDrillStartLayer() != UNDEFINED_LAYER )
3403 tertiaryStart = via->GetTertiaryDrillStartLayer();
3404
3405 std::optional<PCB_LAYER_ID> tertiaryEnd;
3406
3407 if( via->GetTertiaryDrillEndLayer() != UNDEFINED_LAYER )
3408 tertiaryEnd = via->GetTertiaryDrillEndLayer();
3409
3410 int copperLayerCount = via->BoardCopperLayerCount();
3411
3412 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
3413 PCB_VIA::ValidateViaParameters( diameter, drill, startLayer, endLayer,
3414 secondaryDrill, secondaryStart, secondaryEnd,
3415 tertiaryDrill, tertiaryStart, tertiaryEnd,
3416 copperLayerCount ) )
3417 {
3418 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
3419 }
3420
3421 return std::nullopt;
3422 };
3423
3424 auto viaStartLayerPropertyValidator =
3425 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
3426 {
3427 if( !aItem || aItem->Type() != PCB_VIA_T )
3428 return std::nullopt;
3429
3430 PCB_LAYER_ID layer;
3431
3432 if( aValue.CheckType<PCB_LAYER_ID>() )
3433 layer = aValue.As<PCB_LAYER_ID>();
3434 else if( aValue.CheckType<int>() )
3435 layer = static_cast<PCB_LAYER_ID>( aValue.As<int>() );
3436 else
3437 return std::nullopt;
3438
3439 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3440
3441 std::optional<int> diameter = via->GetFrontWidth();
3442 std::optional<int> drill = via->GetDrillValue();
3443
3444 std::optional<PCB_LAYER_ID> endLayer;
3445
3446 if( via->BottomLayer() != UNDEFINED_LAYER )
3447 endLayer = via->BottomLayer();
3448
3449 std::optional<int> secondaryDrill = via->GetSecondaryDrillSize();
3450
3451 std::optional<PCB_LAYER_ID> secondaryStart;
3452
3453 if( via->GetSecondaryDrillStartLayer() != UNDEFINED_LAYER )
3454 secondaryStart = via->GetSecondaryDrillStartLayer();
3455
3456 std::optional<PCB_LAYER_ID> secondaryEnd;
3457
3458 if( via->GetSecondaryDrillEndLayer() != UNDEFINED_LAYER )
3459 secondaryEnd = via->GetSecondaryDrillEndLayer();
3460
3461 int copperLayerCount = via->BoardCopperLayerCount();
3462
3463 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
3464 PCB_VIA::ValidateViaParameters( diameter, drill, layer, endLayer,
3465 secondaryDrill, secondaryStart, secondaryEnd,
3466 std::nullopt, std::nullopt, std::nullopt, // tertiary drill
3467 copperLayerCount ) )
3468 {
3469 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
3470 }
3471
3472 return std::nullopt;
3473 };
3474
3475 auto viaEndLayerPropertyValidator =
3476 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
3477 {
3478 if( !aItem || aItem->Type() != PCB_VIA_T )
3479 return std::nullopt;
3480
3481 PCB_LAYER_ID layer;
3482
3483 if( aValue.CheckType<PCB_LAYER_ID>() )
3484 layer = aValue.As<PCB_LAYER_ID>();
3485 else if( aValue.CheckType<int>() )
3486 layer = static_cast<PCB_LAYER_ID>( aValue.As<int>() );
3487 else
3488 return std::nullopt;
3489
3490 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3491
3492 std::optional<int> diameter = via->GetFrontWidth();
3493 std::optional<int> drill = via->GetDrillValue();
3494
3495 std::optional<PCB_LAYER_ID> startLayer;
3496
3497 if( via->TopLayer() != UNDEFINED_LAYER )
3498 startLayer = via->TopLayer();
3499
3500 std::optional<int> secondaryDrill = via->GetSecondaryDrillSize();
3501
3502 std::optional<PCB_LAYER_ID> secondaryStart;
3503
3504 if( via->GetSecondaryDrillStartLayer() != UNDEFINED_LAYER )
3505 secondaryStart = via->GetSecondaryDrillStartLayer();
3506
3507 std::optional<PCB_LAYER_ID> secondaryEnd;
3508
3509 if( via->GetSecondaryDrillEndLayer() != UNDEFINED_LAYER )
3510 secondaryEnd = via->GetSecondaryDrillEndLayer();
3511
3512 int copperLayerCount = via->BoardCopperLayerCount();
3513
3514 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
3515 PCB_VIA::ValidateViaParameters( diameter, drill, startLayer, layer,
3516 secondaryDrill, secondaryStart, secondaryEnd,
3517 std::nullopt, std::nullopt, std::nullopt, // tertiary drill
3518 copperLayerCount ) )
3519 {
3520 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
3521 }
3522
3523 return std::nullopt;
3524 };
3525
3527
3528 // Track
3531
3532 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "Width" ),
3534 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
3535 new PROPERTY<PCB_TRACK, int>( _HKI( "Start X" ),
3538 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
3539 new PROPERTY<PCB_TRACK, int>( _HKI( "Start Y" ),
3542 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End X" ),
3545 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End Y" ),
3548
3549 const wxString groupTechLayers = _HKI( "Technical Layers" );
3550
3551 auto isExternalLayerTrack =
3552 []( INSPECTABLE* aItem )
3553 {
3554 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( aItem ) )
3555 return IsExternalCopperLayer( track->GetLayer() );
3556
3557 return false;
3558 };
3559
3560 propMgr.AddProperty( new PROPERTY<PCB_TRACK, bool>( _HKI( "Soldermask" ),
3562 .SetAvailableFunc( isExternalLayerTrack ).SetIsCopyable();
3563 propMgr.AddProperty( new PROPERTY<PCB_TRACK, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
3566 groupTechLayers )
3567 .SetAvailableFunc( isExternalLayerTrack ).SetIsCopyable();
3568
3569 // Arc
3572
3573 // Via
3576
3577 const wxString groupVia = _HKI( "Via Properties" );
3578 const wxString groupBackdrill = _HKI( "Backdrill" );
3579 const wxString groupPostMachining = _HKI( "Post-machining" );
3580
3581 propMgr.Mask( TYPE_HASH( PCB_VIA ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
3582
3583 propMgr.AddProperty( new PROPERTY<PCB_VIA, bool>( _HKI( "Automatically Update Net" ),
3585
3586 // clang-format off: the suggestion is less readable
3587 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Diameter" ),
3589 groupVia )
3590 .SetValidator( viaDiameterPropertyValidator ).SetIsCopyable();
3591 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Hole" ),
3593 groupVia )
3594 .SetValidator( viaDrillPropertyValidator ).SetIsCopyable();
3595 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Top" ),
3597 groupVia )
3598 .SetValidator( viaStartLayerPropertyValidator );
3599 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Bottom" ),
3601 groupVia )
3602 .SetValidator( viaEndLayerPropertyValidator );
3603 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, VIATYPE>( _HKI( "Via Type" ),
3605 groupVia );
3606 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, TENTING_MODE>( _HKI( "Front Tenting" ),
3608 groupVia ).SetIsCopyable();
3609 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, TENTING_MODE>( _HKI( "Back Tenting" ),
3611 groupVia ).SetIsCopyable();
3612 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, COVERING_MODE>( _HKI( "Front Covering" ),
3614 groupVia ).SetIsCopyable();
3615 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, COVERING_MODE>( _HKI( "Back Covering" ),
3617 groupVia ).SetIsCopyable();
3618 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PLUGGING_MODE>( _HKI( "Front Plugging" ),
3620 groupVia ).SetIsCopyable();
3621 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PLUGGING_MODE>( _HKI( "Back Plugging" ),
3623 groupVia ).SetIsCopyable();
3624 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, CAPPING_MODE>( _HKI( "Capping" ),
3626 groupVia ).SetIsCopyable();
3627 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, FILLING_MODE>( _HKI( "Filling" ),
3629 groupVia ).SetIsCopyable();
3630
3631 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, BACKDRILL_MODE>( _HKI( "Backdrill Mode" ),
3633 groupBackdrill )
3634 .SetAvailableFunc( []( INSPECTABLE* aItem )
3635 {
3636 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3637 {
3638 if( via->GetViaType() == VIATYPE::THROUGH )
3639 return true;
3640
3641 if( via->Padstack().GetBackdrillMode() != BACKDRILL_MODE::NO_BACKDRILL )
3642 return true;
3643 }
3644
3645 return false;
3646 } );
3647
3648 propMgr.AddProperty( new PROPERTY<PCB_VIA, std::optional<int>>( _HKI( "Bottom Backdrill Size" ),
3650 groupBackdrill )
3651 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
3652 {
3653 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3654 {
3655 BACKDRILL_MODE mode = via->GetBackdrillMode();
3658 }
3659
3660 return false;
3661 } );
3662
3663 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Bottom Backdrill Must-Cut" ),
3665 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
3666 {
3667 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3668 {
3669 BACKDRILL_MODE mode = via->GetBackdrillMode();
3672 }
3673
3674 return false;
3675 } );
3676
3677 propMgr.AddProperty( new PROPERTY<PCB_VIA, std::optional<int>>( _HKI( "Top Backdrill Size" ),
3679 groupBackdrill )
3680 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
3681 {
3682 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3683 {
3684 BACKDRILL_MODE mode = via->GetBackdrillMode();
3685 return mode == BACKDRILL_MODE::BACKDRILL_TOP
3687 }
3688
3689 return false;
3690 } );
3691
3692 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Top Backdrill Must-Cut" ),
3694 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
3695 {
3696 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3697 {
3698 BACKDRILL_MODE mode = via->GetBackdrillMode();
3699 return mode == BACKDRILL_MODE::BACKDRILL_TOP
3701 }
3702
3703 return false;
3704 } );
3705
3706 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PAD_DRILL_POST_MACHINING_MODE>( _HKI( "Front Post-machining" ),
3708 groupPostMachining );
3709
3710 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Front Post-machining Size" ),
3713 groupPostMachining )
3715 []( INSPECTABLE* aItem )
3716 {
3717 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3718 {
3719 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = via->GetFrontPostMachining();
3720
3721 if( mode.has_value() )
3722 {
3723 return mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE
3725 }
3726 }
3727
3728 return false;
3729 } );
3730
3731 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Front Post-machining Depth" ),
3734 groupPostMachining )
3736 []( INSPECTABLE* aItem )
3737 {
3738 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3739 {
3740 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = via->GetFrontPostMachining();
3741
3742 if( mode.has_value() )
3743 return mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE;
3744 }
3745
3746 return false;
3747 } );
3748
3749 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Front Post-machining Angle" ),
3752 groupPostMachining )
3754 []( INSPECTABLE* aItem )
3755 {
3756 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3757 {
3758 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = via->GetFrontPostMachining();
3759
3760 if( mode.has_value() )
3762 }
3763
3764 return false;
3765 } );
3766
3767 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PAD_DRILL_POST_MACHINING_MODE>( _HKI( "Back Post-machining" ),
3769
3770 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Back Post-machining Size" ),
3772 groupPostMachining )
3774 []( INSPECTABLE* aItem )
3775 {
3776 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3777 {
3778 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = via->GetBackPostMachining();
3779
3780 if( mode.has_value() )
3781 {
3782 return mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE
3784 }
3785 }
3786
3787 return false;
3788 } );
3789
3790 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Back Post-machining Depth" ),
3792 groupPostMachining )
3794 []( INSPECTABLE* aItem )
3795 {
3796 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3797 {
3798 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = via->GetBackPostMachining();
3799
3800 if( mode.has_value() )
3801 return mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE;
3802 }
3803
3804 return false;
3805 } );
3806
3807 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Back Post-machining Angle" ),
3809 groupPostMachining )
3811 []( INSPECTABLE* aItem )
3812 {
3813 if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem ) )
3814 {
3815 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = via->GetBackPostMachining();
3816
3817 if( mode.has_value() )
3818 return mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK;
3819 }
3820
3821 return false;
3822 } );
3823 // clang-format on: the suggestion is less readable
3824 }
3826
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
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:128
constexpr int ARC_LOW_DEF
Definition base_units.h:143
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:72
@ ZLO_NONE
Definition board_item.h:73
@ ZLO_FORCE_FLASHED
Definition board_item.h:74
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:921
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
BASE_SET & set(size_t pos)
Definition base_set.h:126
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
BOARD_CONNECTED_ITEM(BOARD_ITEM *aParent, KICAD_T idtype)
void PackNet(kiapi::board::types::Net *aProto) const
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
const wxString & GetDisplayNetname() const
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
void UnpackNet(const kiapi::board::types::Net &aProto)
Assigns a net to this item from an API message.
TEARDROP_PARAMETERS & GetTeardropParams()
void SetTeardropsEnabled(bool aEnable)
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:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
friend class BOARD
Definition board_item.h:593
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:418
PCB_LAYER_ID m_layer
Definition board_item.h:586
bool IsLocked() const override
virtual double GetCoverageArea(int aTextMargin) const
Return the board area this item covers, used to rank candidates under the cursor so a click on a smal...
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:546
virtual wxString LayerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
BOARD_ITEM & operator=(const BOARD_ITEM &aOther)
Definition board_item.h:103
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:266
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.
virtual bool HasHole() const
Definition board_item.h:207
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1672
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:3671
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1199
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:1131
int GetCopperLayerCount() const
Definition board.cpp:1138
const TRACKS & Tracks() const
Definition board.h:462
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:943
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1301
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1185
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:759
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
bool IntersectsCircle(const Vec &aCenter, const int aRadius) const
Definition box2.h:499
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetTop() const
Definition box2.h:226
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
constexpr coord_type GetBottom() const
Definition box2.h:219
bool IsConnectedOnLayer(const BOARD_CONNECTED_ITEM *aItem, int aLayer, const std::initializer_list< KICAD_T > &aTypes={}) const
wxString GetName() const
Definition drc_rule.h:237
MINOPTMAX< int > & Value()
Definition drc_rule.h:205
MINOPTMAX< int > m_Value
Definition drc_rule.h:279
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:228
EDA_ANGLE Normalize180()
Definition eda_angle.h:273
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
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:608
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:167
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:789
static ENUM_MAP< T > & Instance()
Definition property.h:783
ENUM_MAP & Undefined(T aValue)
Definition property.h:796
wxPGChoices & Choices()
Definition property.h:834
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
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:84
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition view_item.cpp:35
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:176
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition view.cpp:611
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:441
PAINTER * GetPainter() const
Return the painter object used by the view for drawing VIEW_ITEM objects.
Definition view.h:227
Definition kiid.h:46
static bool Contains(int aStart_layer, int aEnd_layer, int aTest_layer)
Class which calculates lengths (and associated routing statistics) in a BOARD context.
int64_t CalculateDelay(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical propagation delay of the given items.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
void RunOnLayers(const std::function< void(PCB_LAYER_ID)> &aFunction) const
Execute a function on each layer of the LSET.
Definition lset.h:275
static const LSET & BackTechMask()
Return a mask holding all technical layers (no CU layer) on back side.
Definition lset.cpp:644
static const LSET & AllLayersMask()
Definition lset.cpp:637
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:693
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
static const LSET & FrontTechMask()
Return a mask holding all technical layers (no CU layer) on front side.
Definition lset.cpp:658
T Min() const
Definition minoptmax.h:29
T PinnedOpt() const
Definition minoptmax.h:32
bool HasMin() const
Definition minoptmax.h:37
T Opt() const
Definition minoptmax.h:31
bool HasOpt() const
Definition minoptmax.h:39
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:43
int GetViaDrill() const
Definition netclass.h:158
int GetuViaDrill() const
Definition netclass.h:174
Handle the data for a net.
Definition netinfo.h:50
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:281
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:156
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:356
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:171
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition padstack.cpp:846
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:182
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
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
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:294
double GetRadius() const
EDA_ANGLE GetAngle() const
const VECTOR2I & GetMid() const
Definition pcb_track.h:295
PCB_ARC(BOARD_ITEM *aParent)
Definition pcb_track.h:268
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:360
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
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:107
void SetHasSolderMask(bool aVal)
Definition pcb_track.h:121
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:94
bool HasSolderMask() const
Definition pcb_track.h:122
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:97
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
int GetStartY() const
Definition pcb_track.h:104
int GetEndX() const
Definition pcb_track.h:109
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:255
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_track.h:124
std::optional< int > m_solderMaskMargin
Definition pcb_track.h:258
void CopyFrom(const BOARD_ITEM *aOther) override
Definition pcb_track.cpp:77
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:125
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:98
virtual bool operator==(const BOARD_ITEM &aOther) const override
VECTOR2I m_Start
Line start point.
Definition pcb_track.h:254
int GetEndY() const
Definition pcb_track.h:110
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:257
void SetStartX(int aX)
Definition pcb_track.h:100
const VECTOR2I & GetEnd() const
Definition pcb_track.h:95
PCB_TRACK(BOARD_ITEM *aParent, KICAD_T idtype=PCB_TRACE_T)
Definition pcb_track.cpp:63
void SetStartY(int aY)
Definition pcb_track.h:101
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
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
double GetCoverageArea(int aTextMargin) const override
Return the board area this item covers, used to rank candidates under the cursor so a click on a smal...
void SetEndX(int aX)
Definition pcb_track.h:106
int GetStartX() const
Definition pcb_track.h:103
int m_width
Thickness of track (or arc) – no longer the width of a via.
Definition pcb_track.h:261
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:91
virtual int GetWidth() const
Definition pcb_track.h:92
void GetMsgPanelInfoBase_Common(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) const
bool GetIsFree() const
Check if the via is a free via (as opposed to one created on a track by the router).
Definition pcb_track.h:860
int GetFrontPostMachiningSize() const
Definition pcb_track.h:740
PCB_LAYER_ID BottomLayer() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
PLUGGING_MODE GetFrontPluggingMode() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:599
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
double GetCoverageArea(int aTextMargin) const override
Return the board area this item covers, used to rank candidates under the cursor so a click on a smal...
PCB_LAYER_ID GetTopBackdrillLayer() const
Definition pcb_track.h:447
bool IsGhostLayer(PCB_LAYER_ID aLayer) const
void SetFrontPostMachiningDepth(int aDepth)
Definition pcb_track.h:741
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:765
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void SetBackPostMachiningAngle(int aAngle)
Definition pcb_track.h:766
int GetBackPostMachiningAngle() const
Definition pcb_track.h:767
COVERING_MODE GetBackCoveringMode() const
std::optional< int > GetTertiaryDrillSize() const
void SetTopBackdrillSize(std::optional< int > aSize)
Definition pcb_track.h:445
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
ZONE_LAYER_OVERRIDE GetZoneLayerOverride(PCB_LAYER_ID aLayer) const
void SetBackPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pcb_track.h:752
std::optional< int > GetTopBackdrillSize() const
Definition pcb_track.h:444
void SetBackdrillMode(BACKDRILL_MODE aMode)
Definition pcb_track.h:436
void SetDrillDefault()
Set the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
Definition pcb_track.h:820
void SetBottomBackdrillSize(std::optional< int > aSize)
Definition pcb_track.h:439
void ClearZoneLayerOverrides()
CAPPING_MODE GetCappingMode() const
const PADSTACK & Padstack() const
Definition pcb_track.h:427
void SetFrontTentingMode(TENTING_MODE aMode)
bool m_isFree
"Free" vias don't get their nets auto-updated
Definition pcb_track.h:908
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:742
bool IsBlindVia() const
static std::vector< std::vector< PCB_VIA * > > CollectMicroviaColumns(BOARD *aBoard)
Runs of microvias that land on one another, each ordered from its outermost hop down.
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)
bool HasValidLayerPair(int aCopperLayerCount) const
void ClearSecondaryDrillSize()
void SetBackPostMachiningDepth(int aDepth)
Definition pcb_track.h:764
void SetDrill(int aDrill)
Definition pcb_track.h:798
PLUGGING_MODE GetBackPluggingMode() const
void SetBackPluggingMode(PLUGGING_MODE aMode)
MINOPTMAX< int > GetDrillConstraint(wxString *aSource=nullptr) const
void SetPadstackMode(PADSTACK::MODE aMode)
Definition pcb_track.h:491
void SetBackTentingMode(TENTING_MODE aMode)
void SetIsFree(bool aFree=true)
Definition pcb_track.h:861
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:744
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
void SetFrontPostMachiningAngle(int aAngle)
Definition pcb_track.h:743
void SetTopLayer(PCB_LAYER_ID aLayer)
FILLING_MODE GetFillingMode() const
bool IsBuriedVia() const
int GetFrontWidth() const
Definition pcb_track.h:501
void SetSizeFromRules(int aDiameter, int aDrill)
Give the via a uniform padstack sized from its diameter and hole rules.
std::array< std::atomic< ZONE_LAYER_OVERRIDE >, MAX_CU_LAYERS > m_zoneLayerOverrides
Definition pcb_track.h:911
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:734
bool IsOnCopperLayer() const override
void SetFrontPostMachiningSize(int aSize)
Definition pcb_track.h:739
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:441
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)
bool GetIsNotFree() const
Definition pcb_track.h:864
PCB_VIA(BOARD_ITEM *aParent)
void SetPrimaryDrillFilledFlag(bool aFilled)
std::optional< int > GetBottomBackdrillSize() const
Definition pcb_track.h:438
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:419
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:904
void SetBottomBackdrillLayer(PCB_LAYER_ID aLayer)
Definition pcb_track.h:442
int GetBackPostMachiningSize() const
Definition pcb_track.h:763
void SetTertiaryDrillSize(const VECTOR2I &aSize)
void SetIsNotFree(bool aNotFree)
Definition pcb_track.h:865
PADSTACK m_padStack
Definition pcb_track.h:906
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)
bool sameZoneLayerOverrides(const PCB_VIA &aOther) const
PAD_DRILL_POST_MACHINING_MODE GetBackPostMachiningMode() const
Definition pcb_track.h:757
void SetFrontWidth(int aWidth)
Definition pcb_track.h:500
VIATYPE GetViaType() const
Definition pcb_track.h:418
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:435
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:448
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)
void SetFrontPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pcb_track.h:729
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void SetBackPostMachiningSize(int aSize)
Definition pcb_track.h:762
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:263
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:368
PROPERTY_BASE & SetIsCopyable(bool aIsCopyable=true)
Definition property.h:359
Provide class metadata.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
Definition seg.h:38
VECTOR2I::extended_type ecoord
Definition seg.h:40
bool ApproxCollinear(const SEG &aSeg, int aDistanceThreshold=1) const
Definition seg.cpp:759
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:116
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
bool IsEffectiveLine() const
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
double Area()
Return the area of this poly set.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString MessageTextFromMinOptMax(const MINOPTMAX< int > &aValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition vector2d.h:559
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:281
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.
DRC_CONSTRAINT_T
Definition drc_rule.h:49
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:63
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:72
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:58
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:68
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:56
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:82
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:54
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:454
#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 ROUTER_TRANSIENT
transient items that should NOT be cached
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define STARTPOINT
When a line is selected, these flags indicate which.
a few functions useful in geometry calculations.
bool ClipLine(const BOX2I *aClipBox, int &x1, int &y1, int &x2, int &y2)
Test if any part of a line falls within the bounds of a rectangle.
std::string source
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:179
bool IsSolderMaskLayer(int aLayer)
Definition layer_ids.h:774
@ LAYER_VIA_NETNAMES
Definition layer_ids.h:199
bool IsDrillSymbolLayer(int aLayer)
Definition layer_ids.h:925
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:850
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:170
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:806
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:180
@ DEFAULT
Flashing follows connectivity.
Definition layer_ids.h:181
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:182
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:829
#define MAX_CU_LAYERS
Definition layer_ids.h:172
int GetNetnameLayer(int aLayer)
Return a netname layer corresponding to the given layer.
Definition layer_ids.h:880
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
@ LAYER_DRILL_SYMBOL_START
Drill symbols, one channel per board layer.
Definition layer_ids.h:376
@ LAYER_LOCKED_ITEM_SHADOW
Shadow layer for locked items.
Definition layer_ids.h:303
@ LAYER_VIA_HOLEWALLS
Definition layer_ids.h:294
@ LAYER_VIA_COPPER_START
Virtual layers for via copper on a given copper layer.
Definition layer_ids.h:353
@ LAYER_TRACKS
Definition layer_ids.h:263
@ LAYER_CLEARANCE_START
Virtual layers for pad/via/track clearance outlines for a given copper layer.
Definition layer_ids.h:357
@ LAYER_VIA_HOLES
Draw via holes (pad holes do not use this layer).
Definition layer_ids.h:270
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition layer_ids.h:228
size_t CopperLayerToOrdinal(PCB_LAYER_ID aLayer)
Converts KiCad copper layer enum to an ordinal between the front and back layers.
Definition layer_ids.h:945
#define DRILL_SYMBOL_LAYER_FOR(boardLayer)
Definition layer_ids.h:391
bool IsNetnameLayer(int aLayer)
Test whether a layer is a netname layer.
Definition layer_ids.h:895
bool IsHoleLayer(int aLayer)
Definition layer_ids.h:765
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:714
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ In30_Cu
Definition layer_ids.h:91
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:41
FLIP_DIRECTION
Definition mirror.h:23
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
void PackZoneLayerOverrides(google::protobuf::RepeatedPtrField< types::ZoneLayerOverrideEntry > *aOutput, const std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > &aInput)
void UnpackTeardropSettings(TEARDROP_PARAMETERS &aOutput, const types::PadTeardropSettings &aProto)
void UnpackZoneLayerOverrides(std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > &aOutput, const google::protobuf::RepeatedPtrField< types::ZoneLayerOverrideEntry > &aInput)
void PackTeardropSettings(types::PadTeardropSettings &aOutput, const TEARDROP_PARAMETERS &aParams)
KICOMMON_API void PackCustomProperties(google::protobuf::RepeatedPtrField< types::CustomProperty > *aOutput, const EDA_ITEM &aItem)
KICOMMON_API void UnpackCustomProperties(const google::protobuf::RepeatedPtrField< types::CustomProperty > &aInput, EDA_ITEM &aItem)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition padstack.h:68
BACKDRILL_MODE
Definition padstack.h:83
#define _HKI(x)
Definition page_info.cpp:40
static bool hasLayerOrdinal(PCB_LAYER_ID aLayer)
static struct TRACK_VIA_DESC _TRACK_VIA_DESC
#define GEOMETRY_MIN_SIZE
Definition pcb_track.h:58
FILLING_MODE
VIATYPE
TENTING_MODE
COVERING_MODE
PLUGGING_MODE
CAPPING_MODE
#define TYPE_HASH(x)
Macro to generate unique identifier for a type.
Definition property.h:74
#define ENUM_TO_WXANY(type)
Definition property.h:890
@ 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)
Helper macro to map type hashes to names.
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.
Definition padstack.h:272
PCB_LAYER_ID start
Definition padstack.h:275
PCB_LAYER_ID end
Definition padstack.h:276
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:273
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:287
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:173
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:227
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:506
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:709