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