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