KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pad.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <base_units.h>
23#include <api/api_pcb_utils.h>
24#include <bitmaps.h>
25#include <math/util.h> // for KiROUND
26#include <eda_draw_frame.h>
30#include <geometry/shape_rect.h>
32#include <geometry/shape_null.h>
34#include <layer_range.h>
35#include <string_utils.h>
36#include <i18n_utility.h>
37#include <view/view.h>
38#include <board.h>
41#include <footprint.h>
42#include <lset.h>
43#include <pad.h>
44#include <pad_utils.h>
45#include <pcb_shape.h>
47#include <drc/drc_engine.h>
48#include <eda_units.h>
50#include <widgets/msgpanel.h>
51#include <pcb_painter.h>
53#include <properties/property.h>
55#include <wx/log.h>
56#include <api/api_enums.h>
57#include <api/api_utils.h>
58#include <api/api_pcb_utils.h>
59#include <api/board/board_types.pb.h>
60
61#include <memory>
62#include <macros.h>
63#include <magic_enum.hpp>
64#include "kiface_base.h"
65#include "pcbnew_settings.h"
66
67#include <pcb_group.h>
69#include <pin_type.h>
70
73
74
75PAD::PAD( FOOTPRINT* parent ) :
78 m_padStack( this )
79{
80 VECTOR2I& drill = m_padStack.Drill().size;
83 drill.x = drill.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 30 ); // Default drill size 30 mils.
86
87 SetShape( F_Cu, PAD_SHAPE::CIRCLE ); // Default pad shape is PAD_CIRCLE.
88 SetAnchorPadShape( F_Cu, PAD_SHAPE::CIRCLE ); // Default anchor shape for custom shaped pads is PAD_CIRCLE.
89 SetDrillShape( PAD_DRILL_SHAPE::CIRCLE ); // Default pad drill shape is a circle.
90 m_attribute = PAD_ATTRIB::PTH; // Default pad type is plated through hole
91 SetProperty( PAD_PROP::NONE ); // no special fabrication property
92
93 // Parameters for round rect only:
94 m_padStack.SetRoundRectRadiusRatio( 0.25, F_Cu ); // from IPC-7351C standard
95
96 // Parameters for chamfered rect only:
97 m_padStack.SetChamferRatio( 0.2, F_Cu );
98 m_padStack.SetChamferPositions( RECT_NO_CHAMFER, F_Cu );
99
100 // Set layers mask to default for a standard thru hole pad.
101 m_padStack.SetLayerSet( PTHMask() );
102
103 SetSubRatsnest( 0 ); // used in ratsnest calculations
104
105 SetDirty();
107
110
111}
112
113
114PAD::PAD( const PAD& aOther ) :
117 m_padStack( this )
118{
119 PAD::operator=( aOther );
120
121 SetUuidDirect( aOther.m_Uuid );
122}
123
124
125namespace
126{
127
128static int scaleLength( int aLength, double aFactor )
129{
130 return KiROUND( aLength * aFactor );
131}
132
133
135static void scaleInChildFrame( double aSx, double aSy, const EDA_ANGLE& aRelOrient, double& aLocalSx, double& aLocalSy )
136{
137 const double c = aRelOrient.Cos();
138 const double s = aRelOrient.Sin();
139 aLocalSx = aSx * c * c + aSy * s * s;
140 aLocalSy = aSx * s * s + aSy * c * c;
141}
142
143
145static VECTOR2I derivePadBoardSize( const VECTOR2I& aLibSize, PAD_SHAPE aShape, const TRANSFORM_TRS& aXform,
146 const EDA_ANGLE& aRelOrient )
147{
148 const double sx = std::abs( aXform.GetScaleX() );
149 const double sy = std::abs( aXform.GetScaleY() );
150
151 if( aShape == PAD_SHAPE::CIRCLE )
152 {
153 const double uniform = ( sx + sy ) * 0.5;
154 return { scaleLength( aLibSize.x, uniform ), scaleLength( aLibSize.y, uniform ) };
155 }
156
157 // Size is in the pad frame, so conjugate the footprint scale by the pad orientation.
158 double localSx, localSy;
159 scaleInChildFrame( sx, sy, aRelOrient, localSx, localSy );
160 return { scaleLength( aLibSize.x, localSx ), scaleLength( aLibSize.y, localSy ) };
161}
162
163
165static VECTOR2I derivePadLibSize( const VECTOR2I& aBoardSize, PAD_SHAPE aShape, const TRANSFORM_TRS& aXform,
166 const EDA_ANGLE& aRelOrient )
167{
168 const double sx = std::abs( aXform.GetScaleX() );
169 const double sy = std::abs( aXform.GetScaleY() );
170
171 if( aShape == PAD_SHAPE::CIRCLE )
172 {
173 const double uniform = ( sx + sy ) * 0.5;
174 return { scaleLength( aBoardSize.x, 1.0 / uniform ), scaleLength( aBoardSize.y, 1.0 / uniform ) };
175 }
176
177 double localSx, localSy;
178 scaleInChildFrame( sx, sy, aRelOrient, localSx, localSy );
179 return { scaleLength( aBoardSize.x, 1.0 / localSx ), scaleLength( aBoardSize.y, 1.0 / localSy ) };
180}
181
182
184static VECTOR2I derivePadBoardDrill( const VECTOR2I& aLibDrill, PAD_DRILL_SHAPE aDrillShape,
185 const TRANSFORM_TRS& aXform, const EDA_ANGLE& aRelOrient )
186{
187 const double sx = std::abs( aXform.GetScaleX() );
188 const double sy = std::abs( aXform.GetScaleY() );
189
190 if( aDrillShape == PAD_DRILL_SHAPE::CIRCLE )
191 {
192 const double uniform = ( sx + sy ) * 0.5;
193 return { scaleLength( aLibDrill.x, uniform ), scaleLength( aLibDrill.y, uniform ) };
194 }
195
196
197 double localSx, localSy;
198 scaleInChildFrame( sx, sy, aRelOrient, localSx, localSy );
199 return { scaleLength( aLibDrill.x, localSx ), scaleLength( aLibDrill.y, localSy ) };
200}
201
202
204static VECTOR2I derivePadLibDrill( const VECTOR2I& aBoardDrill, PAD_DRILL_SHAPE aDrillShape,
205 const TRANSFORM_TRS& aXform, const EDA_ANGLE& aRelOrient )
206{
207 const double sx = std::abs( aXform.GetScaleX() );
208 const double sy = std::abs( aXform.GetScaleY() );
209
210 if( aDrillShape == PAD_DRILL_SHAPE::CIRCLE )
211 {
212 const double uniform = ( sx + sy ) * 0.5;
213 return { scaleLength( aBoardDrill.x, 1.0 / uniform ), scaleLength( aBoardDrill.y, 1.0 / uniform ) };
214 }
215
216 double localSx, localSy;
217 scaleInChildFrame( sx, sy, aRelOrient, localSx, localSy );
218 return { scaleLength( aBoardDrill.x, 1.0 / localSx ), scaleLength( aBoardDrill.y, 1.0 / localSy ) };
219}
220
221
223static VECTOR2I derivePadBoardOffset( const VECTOR2I& aLibOffset, const TRANSFORM_TRS& aXform,
224 const EDA_ANGLE& aRelOrient )
225{
226 double localSx, localSy;
227 scaleInChildFrame( std::abs( aXform.GetScaleX() ), std::abs( aXform.GetScaleY() ), aRelOrient, localSx, localSy );
228 return { scaleLength( aLibOffset.x, localSx ), scaleLength( aLibOffset.y, localSy ) };
229}
230
231
233static VECTOR2I derivePadLibOffset( const VECTOR2I& aBoardOffset, const TRANSFORM_TRS& aXform,
234 const EDA_ANGLE& aRelOrient )
235{
236 double localSx, localSy;
237 scaleInChildFrame( std::abs( aXform.GetScaleX() ), std::abs( aXform.GetScaleY() ), aRelOrient, localSx, localSy );
238 return { scaleLength( aBoardOffset.x, 1.0 / localSx ), scaleLength( aBoardOffset.y, 1.0 / localSy ) };
239}
240
241} // namespace
242
243
244void PAD::SetPosition( const VECTOR2I& aPos )
245{
246 if( const FOOTPRINT* fp = GetParentFootprint() )
247 m_libPos = fp->GetTransform().InverseApply( aPos );
248 else
249 m_libPos = aPos;
250
251 SetDirty();
252}
253
254
256{
257 if( const FOOTPRINT* fp = GetParentFootprint() )
258 return fp->GetTransform().Apply( m_libPos );
259
260 return m_libPos;
261}
262
263
264void PAD::SetSize( PCB_LAYER_ID aLayer, const VECTOR2I& aSize )
265{
266 if( const FOOTPRINT* fp = GetParentFootprint() )
267 m_padStack.SetSize(
268 derivePadLibSize( aSize, GetShape( aLayer ), fp->GetTransform(), GetFPRelativeOrientation() ), aLayer );
269 else
270 m_padStack.SetSize( aSize, aLayer );
271
272 SetDirty();
273}
274
275
276void PAD::SetLibSize( PCB_LAYER_ID aLayer, const VECTOR2I& aSize )
277{
278 m_padStack.SetSize( aSize, aLayer );
279 SetDirty();
280}
281
282
283void PAD::SetLibDrillSize( const VECTOR2I& aSize )
284{
285 m_padStack.Drill().size = aSize;
286 SetDirty();
287}
288
289
290void PAD::SetLibOffset( PCB_LAYER_ID aLayer, const VECTOR2I& aOffset )
291{
292 m_padStack.Offset( aLayer ) = aOffset;
293 SetDirty();
294}
295
296
298{
299 if( const FOOTPRINT* fp = GetParentFootprint() )
300 return derivePadBoardSize( m_padStack.Size( aLayer ), GetShape( aLayer ), fp->GetTransform(),
302
303 return m_padStack.Size( aLayer );
304}
305
306
307void PAD::SetSizeXProp( int aX )
308{
309 if( aX <= 0 )
310 return;
311
312 int y = GetSize( PADSTACK::ALL_LAYERS ).y;
313
315 y = aX;
316
317 SetSize( PADSTACK::ALL_LAYERS, { aX, y } );
318}
319
320
322{
324}
325
326
327void PAD::SetSizeYProp( int aY )
328{
329 if( aY <= 0 )
330 return;
331
332 int x = GetSize( PADSTACK::ALL_LAYERS ).x;
333
335 x = aY;
336
337 SetSize( PADSTACK::ALL_LAYERS, { x, aY } );
338}
339
340
342{
344}
345
346
347PAD& PAD::operator=( const PAD &aOther )
348{
350
351 ImportSettingsFrom( aOther );
355 SetPosition( aOther.GetPosition() );
356 SetNumber( aOther.GetNumber() );
357 SetPinType( aOther.GetPinType() );
358 SetPinFunction( aOther.GetPinFunction() );
359 SetSubRatsnest( aOther.GetSubRatsnest() );
361
362 return *this;
363}
364
365
366void PAD::CopyFrom( const BOARD_ITEM* aOther )
367{
368 wxCHECK( aOther && aOther->Type() == PCB_PAD_T, /* void */ );
369 *this = *static_cast<const PAD*>( aOther );
370}
371
372
373// This should probably move elsewhere once it is needed elsewhere
374std::optional<std::pair<ELECTRICAL_PINTYPE, bool>> parsePinType( const wxString& aPinTypeString )
375{
376 // The netlister formats the pin type as "<canonical_name>[+no_connect]"
377 static std::map<wxString, ELECTRICAL_PINTYPE> map = {
378 { wxT( "input" ), ELECTRICAL_PINTYPE::PT_INPUT },
379 { wxT( "output" ), ELECTRICAL_PINTYPE::PT_OUTPUT },
380 { wxT( "bidirectional" ), ELECTRICAL_PINTYPE::PT_BIDI },
381 { wxT( "tri_state" ), ELECTRICAL_PINTYPE::PT_TRISTATE },
382 { wxT( "passive" ), ELECTRICAL_PINTYPE::PT_PASSIVE },
383 { wxT( "free" ), ELECTRICAL_PINTYPE::PT_NIC },
384 { wxT( "unspecified" ), ELECTRICAL_PINTYPE::PT_UNSPECIFIED },
385 { wxT( "power_in" ), ELECTRICAL_PINTYPE::PT_POWER_IN },
386 { wxT( "power_out" ), ELECTRICAL_PINTYPE::PT_POWER_OUT },
387 { wxT( "open_collector" ), ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR },
388 { wxT( "open_emitter" ), ELECTRICAL_PINTYPE::PT_OPENEMITTER },
389 { wxT( "no_connect" ), ELECTRICAL_PINTYPE::PT_NC }
390 };
391
392 bool hasNoConnect = aPinTypeString.EndsWith( wxT( "+no_connect" ) );
393
394 if( auto it = map.find( aPinTypeString.BeforeFirst( '+' ) ); it != map.end() )
395 return std::make_pair( it->second, hasNoConnect );
396
397 return std::nullopt;
398}
399
400
401void PAD::Serialize( google::protobuf::Any &aContainer ) const
402{
403 using namespace kiapi::board::types;
404 using namespace kiapi::common::types;
405 Pad pad;
406
407 pad.mutable_id()->set_value( m_Uuid.AsStdString() );
408 kiapi::common::PackVector2( *pad.mutable_position(), GetPosition() );
409 pad.set_locked( IsLocked() ? LockedState::LS_LOCKED
410 : LockedState::LS_UNLOCKED );
411 PackNet( pad.mutable_net() );
412 pad.set_number( GetNumber().ToUTF8() );
414 pad.mutable_pad_to_die_length()->set_value_nm( GetPadToDieLength() );
415 pad.mutable_pad_to_die_delay()->set_value_as( GetPadToDieDelay() );
416
417 m_padStack.Serialize( *pad.mutable_pad_stack() );
418
419 if( GetLocalClearance().has_value() )
420 pad.mutable_copper_clearance_override()->set_value_nm( *GetLocalClearance() );
421
422 pad.mutable_symbol_pin()->set_name( m_pinFunction.ToUTF8() );
423
424 if( std::optional<std::pair<ELECTRICAL_PINTYPE, bool>> pt = parsePinType( m_pinType ) )
425 {
426 pad.mutable_symbol_pin()->set_type( ToProtoEnum<ELECTRICAL_PINTYPE, ElectricalPinType>( pt->first ) );
427 pad.mutable_symbol_pin()->set_no_connect( pt->second );
428 }
429
432
433 if( FOOTPRINT* parent = GetParentFootprint() )
434 pad.mutable_parent()->set_value( parent->m_Uuid.AsStdString() );
435
437
438 {
439 std::unique_lock lock( m_dataMutex );
440 kiapi::board::PackZoneLayerOverrides( pad.mutable_zone_layer_overrides(), m_zoneLayerOverrides );
441 }
442
443 kiapi::common::PackCustomProperties( pad.mutable_custom_properties(), *this );
444 aContainer.PackFrom( pad );
445}
446
447
448bool PAD::Deserialize( const google::protobuf::Any &aContainer )
449{
450 kiapi::board::types::Pad pad;
451
452 if( !aContainer.UnpackTo( &pad ) )
453 return false;
454
455 SetUuidDirect( KIID( pad.id().value() ) );
457 UnpackNet( pad.net() );
458 SetLocked( pad.locked() == kiapi::common::types::LockedState::LS_LOCKED );
460 SetNumber( wxString::FromUTF8( pad.number() ) );
461 SetPadToDieLength( pad.pad_to_die_length().value_nm() );
462 SetPadToDieDelay( pad.pad_to_die_delay().value_as() );
464 SetProperty( FromProtoEnum<PAD_PROP>( pad.fab_property() ) );
465
466 google::protobuf::Any padStackWrapper;
467 padStackWrapper.PackFrom( pad.pad_stack() );
468 m_padStack.Deserialize( padStackWrapper );
469 SetOrientation( m_padStack.GetOrientation() );
470
471 SetLayer( m_padStack.StartLayer() );
472
473 if( pad.has_copper_clearance_override() )
474 SetLocalClearance( pad.copper_clearance_override().value_nm() );
475 else
476 SetLocalClearance( std::nullopt );
477
478 m_pinFunction = wxString::FromUTF8( pad.symbol_pin().name() );
479
480 if( pad.symbol_pin().type() != kiapi::common::types::EPT_UNKNOWN )
481 {
482 ELECTRICAL_PINTYPE type = FromProtoEnum<ELECTRICAL_PINTYPE>( pad.symbol_pin().type() );
484
485 if( pad.symbol_pin().no_connect() )
486 m_pinType += wxT( "+no_connect" );
487 }
488
489 if( pad.has_teardrop() )
491 else
492 SetTeardropsEnabled( false );
493
495
496 {
497 std::unique_lock lock( m_dataMutex );
499 }
500
501 kiapi::common::UnpackCustomProperties( pad.custom_properties(), *this );
502
503 return true;
504}
505
506
508{
509 std::unique_lock<std::mutex> cacheLock( m_dataMutex );
510
513}
514
515
517{
518 std::unique_lock<std::mutex> cacheLock( m_dataMutex );
519
520 static const ZONE_LAYER_OVERRIDE defaultOverride = ZLO_NONE;
521 auto it = m_zoneLayerOverrides.find( aLayer );
522 return it != m_zoneLayerOverrides.end() ? it->second : defaultOverride;
523}
524
525
527{
528 std::unique_lock<std::mutex> cacheLock( m_dataMutex );
529 m_zoneLayerOverrides[aLayer] = aOverride;
530}
531
532
534{
535 // Aperture pads don't get a number
536 if( IsAperturePad() )
537 return false;
538
539 // NPTH pads don't get numbers
541 return false;
542
543 return true;
544}
545
546
548{
550 return false;
551
552 bool hasCopper = false;
553
555 [&]( PCB_LAYER_ID layer )
556 {
557 if( GetShape( layer ) == PAD_SHAPE::CIRCLE )
558 {
559 if( GetSize( layer ).x > GetDrillSize().x )
560 hasCopper = true;
561 }
562 else if( GetShape( layer ) == PAD_SHAPE::OVAL )
563 {
564 if( GetSize( layer ).x > GetDrillSize().x || GetSize( layer ).y > GetDrillSize().y )
565 hasCopper = true;
566 }
567 else
568 {
569 hasCopper = true;
570 }
571 } );
572
573 return !hasCopper;
574}
575
576
577bool PAD::IsLocked() const
578{
579 if( GetParent() && GetParent()->IsLocked() )
580 return true;
581
582 return BOARD_ITEM::IsLocked();
583};
584
585
586bool PAD::SharesNetTieGroup( const PAD* aOther ) const
587{
588 FOOTPRINT* parentFp = GetParentFootprint();
589
590 if( parentFp && parentFp->IsNetTie() && aOther->GetParentFootprint() == parentFp )
591 {
592 std::map<wxString, int> padToNetTieGroupMap = parentFp->MapPadNumbersToNetTieGroups();
593 int thisNetTieGroup = padToNetTieGroupMap[ GetNumber() ];
594 int otherNetTieGroup = padToNetTieGroupMap[ aOther->GetNumber() ];
595
596 return thisNetTieGroup >= 0 && thisNetTieGroup == otherNetTieGroup;
597 }
598
599 return false;
600}
601
602
604{
605 return m_pinType.Contains( wxT( "no_connect" ) );
606}
607
608
609bool PAD::IsFreePad() const
610{
611 return GetShortNetname().StartsWith( wxT( "unconnected-(" ) ) && m_pinType == wxT( "free" );
612}
613
614
616{
617 static LSET saved = LSET::AllCuMask() | LSET( { F_Mask, B_Mask } );
618 return saved;
619}
620
621
623{
624 static LSET saved( { F_Cu, F_Paste, F_Mask } );
625 return saved;
626}
627
628
630{
631 static LSET saved( { F_Cu, F_Mask } );
632 return saved;
633}
634
635
637{
638 static LSET saved = LSET( { F_Cu, B_Cu, F_Mask, B_Mask } );
639 return saved;
640}
641
642
644{
645 static LSET saved( { F_Paste } );
646 return saved;
647}
648
649
650bool PAD::IsFlipped() const
651{
652 FOOTPRINT* parent = GetParentFootprint();
653
654 return ( parent && parent->GetLayer() == B_Cu );
655}
656
657
659{
660 return GetPrincipalLayer();
661}
662
663
665{
667 return m_layer;
668 else
669 return GetLayerSet().Seq().front();
670
671}
672
673
674bool PAD::FlashLayer( const LSET& aLayers ) const
675{
676 for( PCB_LAYER_ID layer : aLayers )
677 {
678 if( FlashLayer( layer ) )
679 return true;
680 }
681
682 return false;
683}
684
685
686bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
687{
688 if( aLayer == UNDEFINED_LAYER )
689 return true;
690
691 // Sometimes this is called with GAL layers and should just return true
692 if( aLayer > PCB_LAYER_ID_COUNT )
693 return true;
694
695 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer );
696
697 if( !IsOnLayer( layer ) )
698 return false;
699
700 if( GetAttribute() == PAD_ATTRIB::NPTH && IsCopperLayer( aLayer ) )
701 {
703 {
704 if( GetOffset( layer ) == VECTOR2I( 0, 0 ) && GetDrillSize().x >= GetSize( layer ).x )
705 return false;
706 }
707 else if( GetShape( layer ) == PAD_SHAPE::OVAL
709 {
710 if( GetOffset( layer ) == VECTOR2I( 0, 0 )
711 && GetDrillSize().x >= GetSize( layer ).x
712 && GetDrillSize().y >= GetSize( layer ).y )
713 {
714 return false;
715 }
716 }
717 }
718
719 if( GetAttribute() == PAD_ATTRIB::PTH && ( layer == F_Mask || layer == B_Mask ) )
720 return true;
721
722 if( LSET::FrontBoardTechMask().test( aLayer ) )
723 aLayer = F_Cu;
724 else if( LSET::BackBoardTechMask().test( aLayer ) )
725 aLayer = B_Cu;
726
727 if( GetAttribute() == PAD_ATTRIB::PTH && IsCopperLayer( aLayer ) )
728 {
729 UNCONNECTED_LAYER_MODE mode = m_padStack.UnconnectedLayerMode();
730
732 return true;
733
734 // Plated through hole pads need copper on the top/bottom layers for proper soldering
735 // Unless the user has removed them in the pad dialog
737 {
738 return aLayer == m_padStack.Drill().start || aLayer == m_padStack.Drill().end;
739 }
740
742 && IsExternalCopperLayer( aLayer ) )
743 {
744 return true;
745 }
746
747 if( const BOARD* board = GetBoard() )
748 {
750 {
751 return true;
752 }
753 else if( aOnlyCheckIfPermitted )
754 {
755 return true;
756 }
757 else
758 {
759 // Must be static to keep from raising its ugly head in performance profiles
760 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T,
762
763 return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, nonZoneTypes );
764 }
765 }
766 }
767
768 return true;
769}
770
771
773{
774 if( const FOOTPRINT* fp = GetParentFootprint() )
775 m_padStack.Drill().size =
776 derivePadLibDrill( aSize, GetPrimaryDrillShape(), fp->GetTransform(), GetFPRelativeOrientation() );
777 else
778 m_padStack.Drill().size = aSize;
779
780 SetDirty();
781}
782
783
785{
786 if( const FOOTPRINT* fp = GetParentFootprint() )
787 return derivePadBoardDrill( m_padStack.Drill().size, GetPrimaryDrillShape(), fp->GetTransform(),
789
790 return m_padStack.Drill().size;
791}
792
793
794void PAD::SetPrimaryDrillSizeX( const int aX )
795{
797 drill.x = aX;
798
800 drill.y = aX;
801
802 SetPrimaryDrillSize( drill );
803}
804
805
806void PAD::SetDrillSizeXProp( const int aX )
807{
809}
810
811
812void PAD::SetPrimaryDrillSizeY( const int aY )
813{
815 drill.y = aY;
816 SetPrimaryDrillSize( drill );
817}
818
819
820void PAD::SetDrillSizeYProp( const int aY )
821{
823}
824
825
826void PAD::SetOffset( PCB_LAYER_ID aLayer, const VECTOR2I& aOffset )
827{
828 if( const FOOTPRINT* fp = GetParentFootprint() )
829 m_padStack.Offset( aLayer ) = derivePadLibOffset( aOffset, fp->GetTransform(), GetFPRelativeOrientation() );
830 else
831 m_padStack.Offset( aLayer ) = aOffset;
832
833 SetDirty();
834}
835
836
838{
839 if( const FOOTPRINT* fp = GetParentFootprint() )
840 return derivePadBoardOffset( m_padStack.Offset( aLayer ), fp->GetTransform(), GetFPRelativeOrientation() );
841
842 return m_padStack.Offset( aLayer );
843}
844
845
847{
848 m_padStack.Drill().shape = aShape;
849
850 if( aShape == PAD_DRILL_SHAPE::CIRCLE )
851 m_padStack.Drill().size.y = m_padStack.Drill().size.x;
852
853 m_shapesDirty = true;
854 SetDirty();
855}
856
857
859{
860 m_padStack.Drill().start = aLayer;
861 SetDirty();
862}
863
864
866{
867 m_padStack.Drill().end = aLayer;
868 SetDirty();
869}
870
871
873{
874 if( !IsCopperLayer( aLayer ) )
875 return false;
876
877 const BOARD* board = GetBoard();
878
879 if( !board )
880 return false;
881
882 // Check secondary drill (backdrill from top)
883 const PADSTACK::DRILL_PROPS& secondaryDrill = m_padStack.SecondaryDrill();
884
885 if( secondaryDrill.size.x > 0 && secondaryDrill.start != UNDEFINED_LAYER && secondaryDrill.end != UNDEFINED_LAYER )
886 {
887 // Secondary drill goes from start to end layer, removing copper on those layers
888 int startOrdinal = board->IsLayerEnabled( secondaryDrill.start )
889 ? board->IsLayerEnabled( F_Cu ) ? ( secondaryDrill.start == F_Cu ? 0
890 : secondaryDrill.start / 2 + 1 )
891 : secondaryDrill.start / 2
892 : -1;
893 int endOrdinal = board->IsLayerEnabled( secondaryDrill.end )
894 ? board->IsLayerEnabled( F_Cu ) ? ( secondaryDrill.end == B_Cu ? board->GetCopperLayerCount() - 1
895 : secondaryDrill.end / 2 + 1 )
896 : secondaryDrill.end / 2
897 : -1;
898 int layerOrdinal = board->IsLayerEnabled( aLayer )
899 ? board->IsLayerEnabled( F_Cu ) ? ( aLayer == F_Cu ? 0
900 : aLayer == B_Cu ? board->GetCopperLayerCount() - 1
901 : aLayer / 2 + 1 )
902 : aLayer / 2
903 : -1;
904
905 if( layerOrdinal >= 0 && startOrdinal >= 0 && endOrdinal >= 0 )
906 {
907 if( startOrdinal > endOrdinal )
908 std::swap( startOrdinal, endOrdinal );
909
910 if( layerOrdinal >= startOrdinal && layerOrdinal <= endOrdinal )
911 return true;
912 }
913 }
914
915 // Check tertiary drill (backdrill from bottom)
916 const PADSTACK::DRILL_PROPS& tertiaryDrill = m_padStack.TertiaryDrill();
917
918 if( tertiaryDrill.size.x > 0 && tertiaryDrill.start != UNDEFINED_LAYER && tertiaryDrill.end != UNDEFINED_LAYER )
919 {
920 int startOrdinal = board->IsLayerEnabled( tertiaryDrill.start )
921 ? board->IsLayerEnabled( F_Cu ) ? ( tertiaryDrill.start == F_Cu ? 0
922 : tertiaryDrill.start / 2 + 1 )
923 : tertiaryDrill.start / 2
924 : -1;
925 int endOrdinal = board->IsLayerEnabled( tertiaryDrill.end )
926 ? board->IsLayerEnabled( F_Cu ) ? ( tertiaryDrill.end == B_Cu ? board->GetCopperLayerCount() - 1
927 : tertiaryDrill.end / 2 + 1 )
928 : tertiaryDrill.end / 2
929 : -1;
930 int layerOrdinal = board->IsLayerEnabled( aLayer )
931 ? board->IsLayerEnabled( F_Cu ) ? ( aLayer == F_Cu ? 0
932 : aLayer == B_Cu ? board->GetCopperLayerCount() - 1
933 : aLayer / 2 + 1 )
934 : aLayer / 2
935 : -1;
936
937 if( layerOrdinal >= 0 && startOrdinal >= 0 && endOrdinal >= 0 )
938 {
939 if( startOrdinal > endOrdinal )
940 std::swap( startOrdinal, endOrdinal );
941
942 if( layerOrdinal >= startOrdinal && layerOrdinal <= endOrdinal )
943 return true;
944 }
945 }
946
947 // Check if the layer is affected by post-machining
948 if( GetPostMachiningKnockout( aLayer ) > 0 )
949 return true;
950
951 return false;
952}
953
954
956{
957 if( !IsCopperLayer( aLayer ) )
958 return 0;
959
960 const BOARD* board = GetBoard();
961
962 if( !board )
963 return 0;
964
965 const BOARD_STACKUP& stackup = board->GetDesignSettings().GetStackupDescriptor();
966
967 // Check front post-machining (counterbore/countersink from top)
968 const PADSTACK::POST_MACHINING_PROPS& frontPM = m_padStack.FrontPostMachining();
969
970 if( frontPM.mode.has_value() && *frontPM.mode != PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED
971 && *frontPM.mode != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN && frontPM.size > 0 )
972 {
973 int pmDepth = frontPM.depth;
974
975 // For countersink without explicit depth, calculate from diameter and angle
976 if( pmDepth <= 0 && *frontPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && frontPM.angle > 0 )
977 {
978 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
979 pmDepth = static_cast<int>( ( frontPM.size / 2.0 ) / tan( halfAngleRad ) );
980 }
981
982 if( pmDepth > 0 )
983 {
984 // Calculate distance from F_Cu to aLayer
985 int layerDist = stackup.GetLayerDistance( F_Cu, aLayer );
986
987 if( layerDist < pmDepth )
988 {
989 // For countersink, diameter decreases with depth
990 if( *frontPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && frontPM.angle > 0 )
991 {
992 double halfAngleRad = ( frontPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
993 int diameterAtLayer = frontPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
994 return std::max( 0, diameterAtLayer );
995 }
996 else
997 {
998 // Counterbore - constant diameter
999 return frontPM.size;
1000 }
1001 }
1002 }
1003 }
1004
1005 // Check back post-machining (counterbore/countersink from bottom)
1006 const PADSTACK::POST_MACHINING_PROPS& backPM = m_padStack.BackPostMachining();
1007
1008 if( backPM.mode.has_value() && *backPM.mode != PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED
1009 && *backPM.mode != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN && backPM.size > 0 )
1010 {
1011 int pmDepth = backPM.depth;
1012
1013 // For countersink without explicit depth, calculate from diameter and angle
1014 if( pmDepth <= 0 && *backPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && backPM.angle > 0 )
1015 {
1016 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
1017 pmDepth = static_cast<int>( ( backPM.size / 2.0 ) / tan( halfAngleRad ) );
1018 }
1019
1020 if( pmDepth > 0 )
1021 {
1022 // Calculate distance from B_Cu to aLayer
1023 int layerDist = stackup.GetLayerDistance( B_Cu, aLayer );
1024
1025 if( layerDist < pmDepth )
1026 {
1027 // For countersink, diameter decreases with depth
1028 if( *backPM.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK && backPM.angle > 0 )
1029 {
1030 double halfAngleRad = ( backPM.angle / 10.0 ) * M_PI / 180.0 / 2.0;
1031 int diameterAtLayer = backPM.size - static_cast<int>( 2.0 * layerDist * tan( halfAngleRad ) );
1032 return std::max( 0, diameterAtLayer );
1033 }
1034 else
1035 {
1036 // Counterbore - constant diameter
1037 return backPM.size;
1038 }
1039 }
1040 }
1041 }
1042
1043 return 0;
1044}
1045
1046
1047void PAD::SetPrimaryDrillFilled( const std::optional<bool>& aFilled )
1048{
1049 m_padStack.Drill().is_filled = aFilled;
1050 SetDirty();
1051}
1052
1053
1055{
1056 m_padStack.Drill().is_filled = aFilled;
1057 SetDirty();
1058}
1059
1060
1061void PAD::SetPrimaryDrillCapped( const std::optional<bool>& aCapped )
1062{
1063 m_padStack.Drill().is_capped = aCapped;
1064 SetDirty();
1065}
1066
1067
1069{
1070 m_padStack.Drill().is_capped = aCapped;
1071 SetDirty();
1072}
1073
1074
1076{
1077 m_padStack.SecondaryDrill().size = aSize;
1078 SetDirty();
1079}
1080
1081
1083{
1084 m_padStack.SecondaryDrill().size.x = aX;
1085
1087 m_padStack.SecondaryDrill().size.y = aX;
1088
1089 SetDirty();
1090}
1091
1092
1094{
1095 m_padStack.SecondaryDrill().size.y = aY;
1096 SetDirty();
1097}
1098
1099
1101{
1102 m_padStack.SecondaryDrill().size = VECTOR2I( 0, 0 );
1103 SetDirty();
1104}
1105
1106
1108{
1109 m_padStack.SecondaryDrill().shape = aShape;
1110 SetDirty();
1111}
1112
1113
1115{
1116 m_padStack.SecondaryDrill().start = aLayer;
1117 SetDirty();
1118}
1119
1120
1122{
1123 m_padStack.SecondaryDrill().end = aLayer;
1124 SetDirty();
1125}
1126
1127
1129{
1130 m_padStack.TertiaryDrill().size = aSize;
1131 SetDirty();
1132}
1133
1134
1136{
1137 m_padStack.TertiaryDrill().size.x = aX;
1138
1140 m_padStack.TertiaryDrill().size.y = aX;
1141
1142 SetDirty();
1143}
1144
1145
1147{
1148 m_padStack.TertiaryDrill().size.y = aY;
1149 SetDirty();
1150}
1151
1152
1154{
1155 m_padStack.TertiaryDrill().size = VECTOR2I( 0, 0 );
1156 SetDirty();
1157}
1158
1159
1161{
1162 m_padStack.TertiaryDrill().shape = aShape;
1163 SetDirty();
1164}
1165
1166
1168{
1169 m_padStack.TertiaryDrill().start = aLayer;
1170 SetDirty();
1171}
1172
1173
1175{
1176 m_padStack.TertiaryDrill().end = aLayer;
1177 SetDirty();
1178}
1179
1180
1182{
1183 return m_padStack.RoundRectRadius( aLayer );
1184}
1185
1186
1187void PAD::SetRoundRectCornerRadius( PCB_LAYER_ID aLayer, double aRadius )
1188{
1189 m_padStack.SetRoundRectRadius( aRadius, aLayer );
1190}
1191
1192
1193void PAD::SetRoundRectRadiusRatio( PCB_LAYER_ID aLayer, double aRadiusScale )
1194{
1195 m_padStack.SetRoundRectRadiusRatio( std::clamp( aRadiusScale, 0.0, 0.5 ), aLayer );
1196
1197 SetDirty();
1198}
1199
1200
1201void PAD::SetFrontRoundRectRadiusRatio( double aRadiusScale )
1202{
1203 wxASSERT_MSG( m_padStack.Mode() == PADSTACK::MODE::NORMAL,
1204 "Set front radius only meaningful for normal padstacks" );
1205
1206 m_padStack.SetRoundRectRadiusRatio( std::clamp( aRadiusScale, 0.0, 0.5 ), F_Cu );
1207 SetDirty();
1208}
1209
1210
1212{
1213 const VECTOR2I size = GetSize( F_Cu );
1214 const int minSize = std::min( size.x, size.y );
1215 const double newRatio = aRadius / double( minSize );
1216
1217 SetFrontRoundRectRadiusRatio( newRatio );
1218}
1219
1220
1222{
1223 const VECTOR2I size = GetSize( F_Cu );
1224 const int minSize = std::min( size.x, size.y );
1225 const double ratio = GetFrontRoundRectRadiusRatio();
1226
1227 return KiROUND( ratio * minSize );
1228}
1229
1230
1231void PAD::SetChamferRectRatio( PCB_LAYER_ID aLayer, double aChamferScale )
1232{
1233 m_padStack.SetChamferRatio( aChamferScale, aLayer );
1234
1235 SetDirty();
1236}
1237
1238
1239const std::shared_ptr<SHAPE_POLY_SET>& PAD::GetEffectivePolygon( PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc ) const
1240{
1241 if( m_polyDirty[ aErrorLoc ] )
1242 BuildEffectivePolygon( aErrorLoc );
1243
1244 aLayer = Padstack().EffectiveLayerFor( aLayer );
1245
1246 const PAD_DRAW_CACHE_DATA& drawCache = getDrawCache();
1247
1248 return drawCache.m_effectivePolygons.at( aLayer )[ aErrorLoc ];
1249}
1250
1251
1252std::shared_ptr<SHAPE> PAD::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash, DRC_CONSTRAINT_T aUsage ) const
1253{
1254 if( aLayer == Edge_Cuts )
1255 {
1256 std::shared_ptr<SHAPE_COMPOUND> effective_compound = std::make_shared<SHAPE_COMPOUND>();
1257
1259 {
1260 effective_compound->AddShape( GetEffectiveHoleShape( aLayer, aUsage ) );
1261 return effective_compound;
1262 }
1263 else
1264 {
1265 effective_compound->AddShape( std::make_shared<SHAPE_NULL>() );
1266 return effective_compound;
1267 }
1268 }
1269
1270 if( GetAttribute() == PAD_ATTRIB::PTH )
1271 {
1272 bool flash;
1273 std::shared_ptr<SHAPE_COMPOUND> effective_compund = std::make_shared<SHAPE_COMPOUND>();
1274
1275 if( aFlash == FLASHING::NEVER_FLASHED )
1276 flash = false;
1277 else if( aFlash == FLASHING::ALWAYS_FLASHED )
1278 flash = true;
1279 else
1280 flash = FlashLayer( aLayer );
1281
1282 if( !flash )
1283 {
1284 if( GetAttribute() == PAD_ATTRIB::PTH )
1285 {
1286 effective_compund->AddShape( GetEffectiveHoleShape( aLayer, aUsage ) );
1287 return effective_compund;
1288 }
1289 else
1290 {
1291 effective_compund->AddShape( std::make_shared<SHAPE_NULL>() );
1292 return effective_compund;
1293 }
1294 }
1295 }
1296
1297 if( m_shapesDirty )
1299
1300 // A normal padstack keeps one shape, under ALL_LAYERS, so the cache accepts only the remapped
1301 // layer. The machining tests below still use the layer that the caller asked for
1302 PCB_LAYER_ID effectiveLayer = Padstack().EffectiveLayerFor( aLayer );
1303
1304 const PAD_DRAW_CACHE_DATA& drawCache = getDrawCache();
1305
1306 wxCHECK_MSG( drawCache.m_effectiveShapes.contains( effectiveLayer ), nullptr,
1307 wxString::Format( wxT( "Missing shape in PAD::GetEffectiveShape for layer %s." ),
1308 magic_enum::enum_name( effectiveLayer ) ) );
1309 wxCHECK_MSG( drawCache.m_effectiveShapes.at( effectiveLayer ), nullptr,
1310 wxString::Format( wxT( "Null shape in PAD::GetEffectiveShape for layer %s." ),
1311 magic_enum::enum_name( effectiveLayer ) ) );
1312
1313 std::shared_ptr<SHAPE> shape = drawCache.m_effectiveShapes.at( effectiveLayer );
1314
1315 if( IsSolderMaskLayer( aLayer ) )
1316 {
1317 if( int expansion = GetSolderMaskExpansion( aLayer ) )
1318 shape = getMaskShape( aLayer, expansion );
1319 }
1320
1321 // In some cases we want to add in any backdrill or post-machining
1322 if( ( aUsage == PHYSICAL_CLEARANCE_CONSTRAINT || aUsage == SILK_CLEARANCE_CONSTRAINT )
1323 && IsBackdrilledOrPostMachined( aLayer ) )
1324 {
1325 std::shared_ptr<SHAPE_COMPOUND> effective_compound = std::make_shared<SHAPE_COMPOUND>();
1326 effective_compound->AddShape( shape );
1327 effective_compound->AddShape( GetEffectiveHoleShape( aLayer, aUsage ) );
1328 return effective_compound;
1329 }
1330
1331 return shape;
1332}
1333
1334
1335std::shared_ptr<SHAPE_COMPOUND> PAD::getMaskShape( PCB_LAYER_ID aLayer, int aExpansion ) const
1336{
1337 {
1338 std::lock_guard<std::mutex> RAII_lock( m_maskShapeMutex );
1339 auto it = m_maskShapes.find( aLayer );
1340
1341 if( it != m_maskShapes.end() && it->second.first == aExpansion )
1342 return it->second.second;
1343 }
1344
1345 // Built outside the lock because this can re-enter the pad through the rule engine
1346 SHAPE_POLY_SET aperture;
1347 TransformShapeToPolygon( aperture, aLayer, aExpansion, GetMaxError(), ERROR_OUTSIDE );
1348
1349 std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
1350
1351 for( int ii = 0; ii < aperture.OutlineCount(); ++ii )
1352 shape->AddShape( new SHAPE_SIMPLE( aperture.COutline( ii ) ) );
1353
1354 std::lock_guard<std::mutex> RAII_lock( m_maskShapeMutex );
1355 m_maskShapes[aLayer] = { aExpansion, shape };
1356
1357 return shape;
1358}
1359
1360
1361std::shared_ptr<SHAPE_SEGMENT> PAD::GetEffectiveHoleShape( PCB_LAYER_ID aLayer, DRC_CONSTRAINT_T aUsage ) const
1362{
1363 if( m_shapesDirty )
1365
1366 if( aUsage == HOLE_TO_HOLE_CONSTRAINT
1367 || ( aUsage == HOLE_CLEARANCE_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) )
1368 || ( aUsage == ANNULAR_WIDTH_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) )
1370 || ( aUsage == SILK_CLEARANCE_CONSTRAINT && IsBackdrilledOrPostMachined( aLayer ) ) )
1371 {
1372 int maxHoleSize = Padstack().GetMaxHoleSize();
1373
1374 // If it's bigger than the pad's hole, return it
1375 if( maxHoleSize > getDrawCache().m_effectiveHoleShape->GetWidth() )
1376 return std::make_shared<SHAPE_SEGMENT>( GetPosition(), GetPosition(), maxHoleSize );
1377 }
1378
1380}
1381
1382
1390
1391
1393{
1394 if( !m_drawCache )
1395 m_drawCache = std::make_unique<PAD_DRAW_CACHE_DATA>();
1396
1397 return *m_drawCache;
1398}
1399
1400
1402{
1403 std::lock_guard<std::mutex> RAII_lock( m_dataMutex );
1404
1405 // If we had to wait for the lock then we were probably waiting for someone else to
1406 // finish rebuilding the shapes. So check to see if they're clean now.
1407 if( !m_shapesDirty )
1408 return;
1409
1410 PAD_DRAW_CACHE_DATA& drawCache = getDrawCache();
1411
1412 drawCache.m_effectiveBoundingBox = BOX2I();
1413 drawCache.m_effectiveShapes.clear();
1414
1415 {
1416 std::lock_guard<std::mutex> RAII_maskLock( m_maskShapeMutex );
1417 m_maskShapes.clear();
1418 }
1419
1421 [&]( PCB_LAYER_ID aLayer )
1422 {
1423 const SHAPE_COMPOUND& layerShape = buildEffectiveShape( aLayer );
1424 drawCache.m_effectiveBoundingBox.Merge( layerShape.BBox() );
1425 } );
1426
1427 // Hole shape
1428 drawCache.m_effectiveHoleShape = nullptr;
1429
1430 VECTOR2I half_size = GetDrillSize() / 2;
1431 int half_width;
1432 VECTOR2I half_len;
1433
1434 if( m_padStack.Drill().shape == PAD_DRILL_SHAPE::CIRCLE )
1435 {
1436 half_width = half_size.x;
1437 }
1438 else
1439 {
1440 half_width = std::min( half_size.x, half_size.y );
1441 half_len = VECTOR2I( half_size.x - half_width, half_size.y - half_width );
1442 }
1443
1444 RotatePoint( half_len, GetOrientation() );
1445
1446 VECTOR2I pos = GetPosition();
1447 drawCache.m_effectiveHoleShape = std::make_shared<SHAPE_SEGMENT>( pos - half_len, pos + half_len, half_width * 2 );
1448
1449 drawCache.m_effectiveBoundingBox.Merge( drawCache.m_effectiveHoleShape->BBox() );
1450
1451 if( m_padStack.Drill().shape == PAD_DRILL_SHAPE::CIRCLE )
1452 {
1453 int maxHole = m_padStack.GetMaxHoleSize();
1454 drawCache.m_effectiveBoundingBox.Merge( BOX2I::ByCenter( pos, VECTOR2I( maxHole, maxHole ) ) );
1455 }
1456
1457 // All done
1458 m_shapesDirty = false;
1459}
1460
1461
1463{
1464 PAD_DRAW_CACHE_DATA& drawCache = getDrawCache();
1465
1466 drawCache.m_effectiveShapes[aLayer] = std::make_shared<SHAPE_COMPOUND>();
1467
1468 auto add = [this, aLayer]( SHAPE* aShape )
1469 {
1470 getDrawCache().m_effectiveShapes[aLayer]->AddShape( aShape );
1471 };
1472
1473 VECTOR2I shapePos = ShapePos( aLayer ); // Fetch only once; rotation involves trig
1474 PAD_SHAPE effectiveShape = GetShape( aLayer );
1475 const VECTOR2I size = GetSize( aLayer );
1476
1477 if( effectiveShape == PAD_SHAPE::CUSTOM )
1478 effectiveShape = GetAnchorPadShape( aLayer );
1479
1480 switch( effectiveShape )
1481 {
1482 case PAD_SHAPE::CIRCLE:
1483 add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
1484 break;
1485
1486 case PAD_SHAPE::OVAL:
1487 if( size.x == size.y ) // the oval pad is in fact a circle
1488 {
1489 add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
1490 }
1491 else
1492 {
1493 VECTOR2I half_size = size / 2;
1494 int half_width = std::min( half_size.x, half_size.y );
1495 VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
1496 RotatePoint( half_len, GetOrientation() );
1497 add( new SHAPE_SEGMENT( shapePos - half_len, shapePos + half_len, half_width * 2 ) );
1498 }
1499
1500 break;
1501
1505 {
1506 int r = ( effectiveShape == PAD_SHAPE::ROUNDRECT ) ? GetRoundRectCornerRadius( aLayer ) : 0;
1507 VECTOR2I half_size( size.x / 2, size.y / 2 );
1508 VECTOR2I trap_delta( 0, 0 );
1509
1510 if( r )
1511 {
1512 half_size -= VECTOR2I( r, r );
1513
1514 // Avoid degenerated shapes (0 length segments) that always create issues
1515 // For roundrect pad very near a circle, use only a circle
1516 const int min_len = pcbIUScale.mmToIU( 0.0001 );
1517
1518 if( half_size.x < min_len && half_size.y < min_len )
1519 {
1520 add( new SHAPE_CIRCLE( shapePos, r ) );
1521 break;
1522 }
1523 }
1524 else if( effectiveShape == PAD_SHAPE::TRAPEZOID )
1525 {
1526 trap_delta = m_padStack.TrapezoidDeltaSize( aLayer ) / 2;
1527 }
1528
1529 SHAPE_LINE_CHAIN corners;
1530
1531 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
1532 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
1533 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
1534 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
1535
1536 corners.Rotate( GetOrientation() );
1537 corners.Move( shapePos );
1538
1539 // GAL renders rectangles faster than 4-point polygons so it's worth checking if our
1540 // body shape is a rectangle.
1541 if( corners.PointCount() == 4
1542 &&
1543 ( ( corners.CPoint( 0 ).y == corners.CPoint( 1 ).y
1544 && corners.CPoint( 1 ).x == corners.CPoint( 2 ).x
1545 && corners.CPoint( 2 ).y == corners.CPoint( 3 ).y
1546 && corners.CPoint( 3 ).x == corners.CPoint( 0 ).x )
1547 ||
1548 ( corners.CPoint( 0 ).x == corners.CPoint( 1 ).x
1549 && corners.CPoint( 1 ).y == corners.CPoint( 2 ).y
1550 && corners.CPoint( 2 ).x == corners.CPoint( 3 ).x
1551 && corners.CPoint( 3 ).y == corners.CPoint( 0 ).y )
1552 )
1553 )
1554 {
1555 int width = std::abs( corners.CPoint( 2 ).x - corners.CPoint( 0 ).x );
1556 int height = std::abs( corners.CPoint( 2 ).y - corners.CPoint( 0 ).y );
1557 VECTOR2I pos( std::min( corners.CPoint( 2 ).x, corners.CPoint( 0 ).x ),
1558 std::min( corners.CPoint( 2 ).y, corners.CPoint( 0 ).y ) );
1559
1560 add( new SHAPE_RECT( pos, width, height ) );
1561 }
1562 else
1563 {
1564 add( new SHAPE_SIMPLE( corners ) );
1565 }
1566
1567 if( r )
1568 {
1569 add( new SHAPE_SEGMENT( corners.CPoint( 0 ), corners.CPoint( 1 ), r * 2 ) );
1570 add( new SHAPE_SEGMENT( corners.CPoint( 1 ), corners.CPoint( 2 ), r * 2 ) );
1571 add( new SHAPE_SEGMENT( corners.CPoint( 2 ), corners.CPoint( 3 ), r * 2 ) );
1572 add( new SHAPE_SEGMENT( corners.CPoint( 3 ), corners.CPoint( 0 ), r * 2 ) );
1573 }
1574 }
1575 break;
1576
1578 {
1579 SHAPE_POLY_SET outline;
1580
1581 TransformRoundChamferedRectToPolygon( outline, shapePos, GetSize( aLayer ),
1583 GetChamferRectRatio( aLayer ),
1584 GetChamferPositions( aLayer ), 0, GetMaxError(),
1585 ERROR_INSIDE );
1586
1587 add( new SHAPE_SIMPLE( outline.COutline( 0 ) ) );
1588 }
1589 break;
1590
1591 default:
1592 wxFAIL_MSG( wxT( "PAD::buildEffectiveShapes: Unsupported pad shape: PAD_SHAPE::" )
1593 + wxString( std::string( magic_enum::enum_name( effectiveShape ) ) ) );
1594 break;
1595 }
1596
1597 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
1598 {
1599 for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives( aLayer ) )
1600 {
1601 if( !primitive->IsProxyItem() )
1602 {
1603 for( SHAPE* shape : primitive->MakeEffectiveShapes() )
1604 {
1605 shape->Rotate( GetOrientation() );
1606 shape->Move( shapePos );
1607 add( shape );
1608 }
1609 }
1610 }
1611 }
1612
1613 return *drawCache.m_effectiveShapes[aLayer];
1614}
1615
1616
1618{
1619 std::lock_guard<std::mutex> RAII_lock( m_dataMutex );
1620
1621 // Only calculate this once, not for both ERROR_INSIDE and ERROR_OUTSIDE
1622 bool doBoundingRadius = aErrorLoc == ERROR_OUTSIDE;
1623
1624 // If we had to wait for the lock then we were probably waiting for someone else to
1625 // finish rebuilding the shapes. So check to see if they're clean now.
1626 if( !m_polyDirty[ aErrorLoc ] )
1627 return;
1628
1629 PAD_DRAW_CACHE_DATA& drawCache = getDrawCache();
1630
1632 [&]( PCB_LAYER_ID aLayer )
1633 {
1634 // Polygon
1635 std::shared_ptr<SHAPE_POLY_SET>& effectivePolygon =
1636 drawCache.m_effectivePolygons[ aLayer ][ aErrorLoc ];
1637
1638 effectivePolygon = std::make_shared<SHAPE_POLY_SET>();
1639 TransformShapeToPolygon( *effectivePolygon, aLayer, 0, GetMaxError(), aErrorLoc );
1640 } );
1641
1642 if( doBoundingRadius )
1643 {
1645
1647 [&]( PCB_LAYER_ID aLayer )
1648 {
1649 std::shared_ptr<SHAPE_POLY_SET>& effectivePolygon =
1650 drawCache.m_effectivePolygons[ aLayer ][ aErrorLoc ];
1651
1652 for( int cnt = 0; cnt < effectivePolygon->OutlineCount(); ++cnt )
1653 {
1654 const SHAPE_LINE_CHAIN& poly = effectivePolygon->COutline( cnt );
1655
1656 for( int ii = 0; ii < poly.PointCount(); ++ii )
1657 {
1658 int dist = KiROUND( ( poly.CPoint( ii ) - GetPosition() ).EuclideanNorm() );
1660 }
1661 }
1662 } );
1663
1666 }
1667
1668 // All done
1669 m_polyDirty[ aErrorLoc ] = false;
1670}
1671
1672
1674{
1675 if( m_shapesDirty )
1677
1679}
1680
1681
1682// Thermal spokes are built on the bounding box, so we must have a layer-specific version
1684{
1685 return buildEffectiveShape( aLayer ).BBox();
1686}
1687
1688
1690{
1691 if( m_attribute != aAttribute )
1692 {
1693 m_attribute = aAttribute;
1694
1695 LSET& layerMask = m_padStack.LayerSet();
1696
1697 switch( aAttribute )
1698 {
1699 case PAD_ATTRIB::PTH:
1700 // Plump up to all copper layers
1701 layerMask |= LSET::AllCuMask();
1702 break;
1703
1704 case PAD_ATTRIB::SMD:
1705 case PAD_ATTRIB::CONN:
1706 {
1707 // Trim down to no more than one copper layer
1708 LSET copperLayers = layerMask & LSET::AllCuMask();
1709
1710 if( copperLayers.count() > 1 )
1711 {
1712 layerMask &= ~LSET::AllCuMask();
1713
1714 if( copperLayers.test( B_Cu ) )
1715 layerMask.set( B_Cu );
1716 else
1717 layerMask.set( copperLayers.Seq().front() );
1718 }
1719
1720 // No hole, so no drilling of any kind
1722 break;
1723 }
1724
1725 case PAD_ATTRIB::NPTH:
1726 // No number; no net
1727 m_number = wxEmptyString;
1729 break;
1730 }
1731
1732 if( !( GetFlags() & ROUTER_TRANSIENT ) )
1733 {
1734 if( BOARD* board = GetBoard() )
1735 board->InvalidateClearanceCache( m_Uuid );
1736 }
1737 }
1738
1739 SetDirty();
1740}
1741
1742
1744{
1745 const bool wasRoundable = PAD_UTILS::PadHasMeaningfulRoundingRadius( *this, F_Cu );
1746
1747 m_padStack.SetShape( aShape, F_Cu );
1748
1749 const bool isRoundable = PAD_UTILS::PadHasMeaningfulRoundingRadius( *this, F_Cu );
1750
1751 // If we have become roundable, set a sensible rounding default using the IPC rules.
1752 if( !wasRoundable && isRoundable )
1753 {
1754 const double ipcRadiusRatio = PAD_UTILS::GetDefaultIpcRoundingRatio( *this, F_Cu );
1755 m_padStack.SetRoundRectRadiusRatio( ipcRadiusRatio, F_Cu );
1756 }
1757
1758 SetDirty();
1759}
1760
1761
1763{
1764 m_property = aProperty;
1765
1766 SetDirty();
1767}
1768
1769
1770void PAD::SetOrientation( const EDA_ANGLE& aAngle )
1771{
1772 if( const FOOTPRINT* parentFP = GetParentFootprint() )
1773 m_libOrientation = aAngle - parentFP->GetOrientation();
1774 else
1775 m_libOrientation = aAngle;
1776
1777 m_padStack.SetOrientation( aAngle );
1778 SetDirty();
1779}
1780
1781
1783{
1784 m_libOrientation = aAngle;
1785
1786 if( const FOOTPRINT* parentFP = GetParentFootprint() )
1787 m_padStack.SetOrientation( aAngle + parentFP->GetOrientation() );
1788 else
1789 m_padStack.SetOrientation( aAngle );
1790
1791 SetDirty();
1792}
1793
1794
1796{
1797 if( const FOOTPRINT* parentFP = GetParentFootprint() )
1798 {
1799 EDA_ANGLE angle = m_libOrientation.GetAngle() + parentFP->GetOrientation();
1800 return angle.Normalized();
1801 }
1802
1803 return m_libOrientation.GetAngle();
1804}
1805
1806
1808{
1809 return m_libOrientation.GetAngle();
1810}
1811
1812
1813void PAD::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1814{
1815 if( const FOOTPRINT* fp = GetParentFootprint() )
1816 {
1817 // Mirror in the footprint's library frame (rotation-independent).
1818 VECTOR2I libCentre = fp->GetTransform().InverseApply( aCentre );
1819 MIRROR( m_libPos, libCentre, aFlipDirection );
1820 }
1821 else
1822 {
1823 VECTOR2I newPos = GetPosition();
1824 MIRROR( newPos, aCentre, aFlipDirection );
1825 SetPosition( newPos );
1826 }
1827
1828 m_padStack.ForEachUniqueLayer(
1829 [&]( PCB_LAYER_ID aLayer )
1830 {
1831 MIRROR( m_padStack.Offset( aLayer ), VECTOR2I{ 0, 0 }, aFlipDirection );
1832 MIRROR( m_padStack.TrapezoidDeltaSize( aLayer ), VECTOR2I{ 0, 0 }, aFlipDirection );
1833 } );
1834
1836
1837 auto mirrorBitFlags = []( int& aBitfield, int a, int b )
1838 {
1839 bool temp = aBitfield & a;
1840
1841 if( aBitfield & b )
1842 aBitfield |= a;
1843 else
1844 aBitfield &= ~a;
1845
1846 if( temp )
1847 aBitfield |= b;
1848 else
1849 aBitfield &= ~b;
1850 };
1851
1853 [&]( PCB_LAYER_ID aLayer )
1854 {
1855 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1856 {
1857 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_TOP_LEFT,
1859 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_BOTTOM_LEFT,
1861 }
1862 else
1863 {
1864 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_TOP_LEFT,
1866 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_TOP_RIGHT,
1868 }
1869 } );
1870
1871 m_padStack.FlipLayers( GetBoard() );
1872
1873 // Flip pads layers after padstack geometry
1874 LSET flipped;
1875
1876 for( PCB_LAYER_ID layer : m_padStack.LayerSet() )
1877 flipped.set( GetFlippedLayer( layer ) );
1878
1879 SetLayerSet( flipped );
1880
1881 // Flip the basic shapes, in custom pads
1882 FlipPrimitives( aFlipDirection );
1883
1884 SetDirty();
1885}
1886
1887
1889{
1891 [&]( PCB_LAYER_ID aLayer )
1892 {
1893 for( std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives( aLayer ) )
1894 {
1895 // Ensure the primitive parent is up to date. Flip uses GetBoard() that
1896 // imply primitive parent is valid
1897 primitive->SetParent(this);
1898 primitive->Flip( VECTOR2I( 0, 0 ), aFlipDirection );
1899 }
1900 } );
1901
1902 SetDirty();
1903}
1904
1905
1907{
1908 VECTOR2I pos = GetPosition();
1909 VECTOR2I loc_offset = GetOffset( aLayer );
1910
1911 if( loc_offset.x == 0 && loc_offset.y == 0 )
1912 return pos;
1913
1914 RotatePoint( loc_offset, GetOrientation() );
1915
1916 return pos + loc_offset;
1917}
1918
1919
1920void PAD::SwapShapePositions( PAD* aLhs, PAD* aRhs )
1921{
1922 wxCHECK( aLhs && aRhs, /* void */ );
1923
1924 LSET uniqueLayerUnion;
1925
1927 [&]( PCB_LAYER_ID layer )
1928 {
1929 uniqueLayerUnion.set( layer );
1930 } );
1931
1933 [&]( PCB_LAYER_ID layer )
1934 {
1935 uniqueLayerUnion.set( layer );
1936 } );
1937
1938 std::map<PCB_LAYER_ID, std::pair<VECTOR2I, VECTOR2I>> positions;
1939
1940 for( PCB_LAYER_ID layer : uniqueLayerUnion.Seq() )
1941 {
1942 VECTOR2I lhsShapePos = aLhs->ShapePos( layer );
1943 VECTOR2I rhsShapePos = aRhs->ShapePos( layer );
1944
1945 VECTOR2I lhsOffset = aLhs->GetOffset( layer );
1946 VECTOR2I rhsOffset = aRhs->GetOffset( layer );
1947
1948 RotatePoint( lhsOffset, aLhs->GetOrientation() );
1949 RotatePoint( rhsOffset, aRhs->GetOrientation() );
1950
1951 positions[layer].first = rhsShapePos - lhsOffset;
1952 positions[layer].second = lhsShapePos - rhsOffset;
1953 }
1954
1956 [&]( PCB_LAYER_ID layer )
1957 {
1958 aLhs->SetPosition( positions[layer].first );
1959 } );
1960
1962 [&]( PCB_LAYER_ID layer )
1963 {
1964 aRhs->SetPosition( positions[layer].second );
1965 } );
1966}
1967
1968
1970{
1972 {
1973 // NPTH pads have no plated hole cylinder. If their annular ring size is 0 or
1974 // negative, then they have no annular ring either.
1975 bool hasAnnularRing = true;
1976
1978 [&]( PCB_LAYER_ID aLayer )
1979 {
1980 switch( GetShape( aLayer ) )
1981 {
1982 case PAD_SHAPE::CIRCLE:
1983 if( m_padStack.Offset( aLayer ) == VECTOR2I( 0, 0 )
1984 && m_padStack.Size( aLayer ).x <= m_padStack.Drill().size.x )
1985 {
1986 hasAnnularRing = false;
1987 }
1988
1989 break;
1990
1991 case PAD_SHAPE::OVAL:
1992 if( m_padStack.Offset( aLayer ) == VECTOR2I( 0, 0 )
1993 && m_padStack.Size( aLayer ).x <= m_padStack.Drill().size.x
1994 && m_padStack.Size( aLayer ).y <= m_padStack.Drill().size.y )
1995 {
1996 hasAnnularRing = false;
1997 }
1998
1999 break;
2000
2001 default:
2002 // We could subtract the hole polygon from the shape polygon for these, but it
2003 // would be expensive and we're probably well out of the common use cases....
2004 break;
2005 }
2006 } );
2007
2008 if( !hasAnnularRing )
2009 return false;
2010 }
2011
2012 return ( m_padStack.LayerSet() & LSET::AllCuMask() ).any();
2013}
2014
2015
2016std::optional<int> PAD::GetLocalClearance( wxString* aSource ) const
2017{
2018 if( m_padStack.Clearance().has_value() && aSource )
2019 *aSource = _( "pad" );
2020
2021 return m_padStack.Clearance();
2022}
2023
2024
2025std::optional<int> PAD::GetClearanceOverrides( wxString* aSource ) const
2026{
2027 if( m_padStack.Clearance().has_value() )
2028 return GetLocalClearance( aSource );
2029
2030 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
2031 return parentFootprint->GetClearanceOverrides( aSource );
2032
2033 return std::optional<int>();
2034}
2035
2036
2037void PAD::SetLayerSet( const LSET& aLayers )
2038{
2039 m_padStack.SetLayerSet( aLayers );
2040 SetDirty();
2041
2042 // In theory m_layer should never be read, but set it just to be safe.
2043 if( m_layer == UNDEFINED_LAYER || !aLayers.test( m_layer ) )
2044 {
2045 auto seq = aLayers.Seq();
2046 if( !seq.empty() )
2047 m_layer = seq.front();
2048 else
2050 }
2051
2052 if( !( GetFlags() & ROUTER_TRANSIENT ) )
2053 {
2054 if( BOARD* board = GetBoard() )
2055 board->InvalidateClearanceCache( m_Uuid );
2056 }
2057}
2058
2059
2060int PAD::GetOwnClearance( PCB_LAYER_ID aLayer, wxString* aSource ) const
2061{
2062 // The NPTH vs regular pad logic is handled in DRC_ENGINE::GetCachedOwnClearance
2063 return BOARD_CONNECTED_ITEM::GetOwnClearance( aLayer, aSource );
2064}
2065
2066
2068{
2069 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
2070 // defined by the pad settings only. ALL other pads, even those that don't actually have
2071 // any copper (such as NPTH pads with holes the same size as the pad) get mask expansion.
2072 if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
2073 return 0;
2074
2075 if( IsFrontLayer( aLayer ) )
2076 aLayer = F_Mask;
2077 else if( IsBackLayer( aLayer ) )
2078 aLayer = B_Mask;
2079 else
2080 return 0;
2081
2082 std::optional<int> margin;
2083
2084 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine
2085 && GetBoard()->GetDesignSettings().m_DRCEngine->HasRulesForConstraintType( SOLDER_MASK_EXPANSION_CONSTRAINT ) )
2086 {
2087 DRC_CONSTRAINT constraint;
2088 DRC_ENGINE* drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine.get();
2089
2090 constraint = drcEngine->EvalRules( SOLDER_MASK_EXPANSION_CONSTRAINT, this, nullptr, aLayer );
2091
2092 if( constraint.m_Value.HasOpt() )
2093 margin = constraint.m_Value.Opt();
2094 }
2095 else
2096 {
2097 margin = m_padStack.SolderMaskMargin( aLayer );
2098
2099 if( !margin.has_value() )
2100 {
2101 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
2102 margin = parentFootprint->GetLocalSolderMaskMargin();
2103 }
2104
2105 if( !margin.has_value() )
2106 {
2107 if( const BOARD* brd = GetBoard() )
2108 margin = brd->GetDesignSettings().m_SolderMaskExpansion;
2109 }
2110 }
2111
2112 int marginValue = margin.value_or( 0 );
2113
2114 PCB_LAYER_ID cuLayer = ( aLayer == B_Mask ) ? B_Cu : F_Cu;
2115
2116 // ensure mask have a size always >= 0
2117 if( marginValue < 0 )
2118 {
2119 int minsize = -std::min( m_padStack.Size( cuLayer ).x, m_padStack.Size( cuLayer ).y ) / 2;
2120
2121 if( marginValue < minsize )
2122 marginValue = minsize;
2123 }
2124
2125 return marginValue;
2126}
2127
2128
2130{
2131 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
2132 // defined by the pad settings only. ALL other pads, even those that don't actually have
2133 // any copper (such as NPTH pads with holes the same size as the pad) get paste expansion.
2134 if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
2135 return VECTOR2I( 0, 0 );
2136
2137 if( IsFrontLayer( aLayer ) )
2138 aLayer = F_Paste;
2139 else if( IsBackLayer( aLayer ) )
2140 aLayer = B_Paste;
2141 else
2142 return VECTOR2I( 0, 0 );
2143
2144 std::optional<int> margin;
2145 std::optional<double> mratio;
2146
2147 std::shared_ptr<DRC_ENGINE> drcEngine;
2148
2149 if( GetBoard() )
2150 drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
2151
2152 bool hasAbsRules = drcEngine
2153 && drcEngine->HasRulesForConstraintType( SOLDER_PASTE_ABS_MARGIN_CONSTRAINT );
2154 bool hasRelRules = drcEngine
2155 && drcEngine->HasRulesForConstraintType( SOLDER_PASTE_REL_MARGIN_CONSTRAINT );
2156
2157 if( hasAbsRules || hasRelRules )
2158 {
2159 DRC_CONSTRAINT constraint;
2160
2161 if( hasAbsRules )
2162 {
2163 constraint = drcEngine->EvalRules( SOLDER_PASTE_ABS_MARGIN_CONSTRAINT, this, nullptr,
2164 aLayer );
2165
2166 if( constraint.m_Value.HasOpt() )
2167 margin = constraint.m_Value.Opt();
2168 }
2169
2170 if( hasRelRules )
2171 {
2172 constraint = drcEngine->EvalRules( SOLDER_PASTE_REL_MARGIN_CONSTRAINT, this, nullptr,
2173 aLayer );
2174
2175 if( constraint.m_Value.HasOpt() )
2176 mratio = constraint.m_Value.Opt() / 1000.0;
2177 }
2178 }
2179
2180 if( !margin.has_value() )
2181 {
2182 margin = m_padStack.SolderPasteMargin( aLayer );
2183
2184 if( !margin.has_value() )
2185 {
2186 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
2187 margin = parentFootprint->GetLocalSolderPasteMargin();
2188 }
2189
2190 if( !margin.has_value() )
2191 {
2192 if( const BOARD* brd = GetBoard() )
2193 margin = brd->GetDesignSettings().m_SolderPasteMargin;
2194 }
2195 }
2196
2197 if( !mratio.has_value() )
2198 {
2199 mratio = m_padStack.SolderPasteMarginRatio( aLayer );
2200
2201 if( !mratio.has_value() )
2202 {
2203 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
2204 mratio = parentFootprint->GetLocalSolderPasteMarginRatio();
2205 }
2206
2207 if( !mratio.has_value() )
2208 {
2209 if( const BOARD* brd = GetBoard() )
2210 mratio = brd->GetDesignSettings().m_SolderPasteMarginRatio;
2211 }
2212 }
2213
2214 PCB_LAYER_ID cuLayer = ( aLayer == B_Paste ) ? B_Cu : F_Cu;
2215 VECTOR2I padSize = GetSize( cuLayer );
2216
2217 VECTOR2I pad_margin;
2218 pad_margin.x = margin.value_or( 0 ) + KiROUND( padSize.x * mratio.value_or( 0 ) );
2219 pad_margin.y = margin.value_or( 0 ) + KiROUND( padSize.y * mratio.value_or( 0 ) );
2220
2221 // ensure paste have a size always >= 0
2222 if( m_padStack.Shape( aLayer ) != PAD_SHAPE::CUSTOM )
2223 {
2224 if( pad_margin.x < -padSize.x / 2 )
2225 pad_margin.x = -padSize.x / 2;
2226
2227 if( pad_margin.y < -padSize.y / 2 )
2228 pad_margin.y = -padSize.y / 2;
2229 }
2230
2231 return pad_margin;
2232}
2233
2234
2236{
2237 ZONE_CONNECTION connection = m_padStack.ZoneConnection().value_or( ZONE_CONNECTION::INHERITED );
2238
2239 if( connection != ZONE_CONNECTION::INHERITED )
2240 {
2241 if( aSource )
2242 *aSource = _( "pad" );
2243 }
2244
2245 if( connection == ZONE_CONNECTION::INHERITED )
2246 {
2247 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
2248 connection = parentFootprint->GetZoneConnectionOverrides( aSource );
2249 }
2250
2251 return connection;
2252}
2253
2254
2255int PAD::GetLocalSpokeWidthOverride( wxString* aSource ) const
2256{
2257 if( m_padStack.ThermalSpokeWidth().has_value() && aSource )
2258 *aSource = _( "pad" );
2259
2260 return m_padStack.ThermalSpokeWidth().value_or( 0 );
2261}
2262
2263
2264int PAD::GetLocalThermalGapOverride( wxString* aSource ) const
2265{
2266 if( m_padStack.ThermalGap().has_value() && aSource )
2267 *aSource = _( "pad" );
2268
2269 return GetLocalThermalGapOverride().value_or( 0 );
2270}
2271
2272
2273void PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2274{
2275 wxString msg;
2276 FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( m_parent );
2277
2278 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
2279 {
2280 if( parentFootprint )
2281 aList.emplace_back( _( "Footprint" ), parentFootprint->GetReference() );
2282 }
2283
2284 aList.emplace_back( _( "Pad" ), m_number );
2285
2286 if( !GetPinFunction().IsEmpty() )
2287 aList.emplace_back( _( "Pin Name" ), GetPinFunction() );
2288
2289 if( !GetPinType().IsEmpty() )
2290 aList.emplace_back( _( "Pin Type" ), GetPinType() );
2291
2292 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
2293 {
2294 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
2295
2296 if( NETINFO_ITEM* netInfo = GetNet() )
2297 {
2298 const wxString& chainName = netInfo->GetNetChain();
2299
2300 if( !chainName.IsEmpty() )
2301 aList.emplace_back( _( "Net Chain" ), UnescapeString( chainName ) );
2302 }
2303
2304 aList.emplace_back( _( "Resolved Netclass" ),
2305 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
2306
2307 if( IsLocked() )
2308 aList.emplace_back( _( "Status" ), _( "Locked" ) );
2309 }
2310
2312 aList.emplace_back( _( "Layer" ), LayerMaskDescribe() );
2313
2314 if( aFrame->GetName() == FOOTPRINT_EDIT_FRAME_NAME )
2315 {
2316 if( GetAttribute() == PAD_ATTRIB::SMD )
2317 {
2318 // TOOD(JE) padstacks
2319 const std::shared_ptr<SHAPE_POLY_SET>& poly = GetEffectivePolygon( PADSTACK::TEMP_ALL_LAYERS );
2320 double area = poly->Area();
2321
2322 aList.emplace_back( _( "Area" ), aFrame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
2323 }
2324 }
2325
2326 // Show the pad shape, attribute and property
2327 wxString props = ShowPadAttr();
2328
2329 if( GetProperty() != PAD_PROP::NONE )
2330 props += ',';
2331
2332 switch( GetProperty() )
2333 {
2334 case PAD_PROP::NONE: break;
2335 case PAD_PROP::BGA: props += _( "BGA" ); break;
2336 case PAD_PROP::FIDUCIAL_GLBL: props += _( "Fiducial global" ); break;
2337 case PAD_PROP::FIDUCIAL_LOCAL: props += _( "Fiducial local" ); break;
2338 case PAD_PROP::TESTPOINT: props += _( "Test point" ); break;
2339 case PAD_PROP::HEATSINK: props += _( "Heat sink" ); break;
2340 case PAD_PROP::CASTELLATED: props += _( "Castellated" ); break;
2341 case PAD_PROP::MECHANICAL: props += _( "Mechanical" ); break;
2342 case PAD_PROP::PRESSFIT: props += _( "Press-fit" ); break;
2343 }
2344
2345 std::set<bool> circles;
2346 std::set<PAD_SHAPE> shapes;
2347 std::set<int> widths;
2348 std::set<int> heights;
2349
2351 [&]( PCB_LAYER_ID aLayer )
2352 {
2353 PAD_SHAPE shape = GetShape( aLayer );
2354 VECTOR2I size = GetSize( aLayer );
2355
2356 circles.insert( shape == PAD_SHAPE::CIRCLE || ( shape == PAD_SHAPE::OVAL && size.x == size.y ) );
2357 shapes.insert( shape );
2358 widths.insert( size.x );
2359 heights.insert( size.y );
2360 } );
2361
2362 aList.emplace_back( shapes.size() == 1 ? ShowPadShape( *shapes.begin() ) : _( "(mixed shapes)" ), props );
2363
2364 if( circles.size() == 1 && *circles.begin() )
2365 {
2366 aList.emplace_back( _( "Diameter" ), widths.size() == 1 ? aFrame->MessageTextFromValue( *widths.begin() )
2367 : _( "(mixed)" ) );
2368 }
2369 else
2370 {
2371 aList.emplace_back( _( "Width" ), widths.size() == 1 ? aFrame->MessageTextFromValue( *widths.begin() )
2372 : _( "(mixed)" ) );
2373 aList.emplace_back( _( "Height" ), heights.size() == 1 ? aFrame->MessageTextFromValue( *heights.begin() )
2374 : _( "(mixed)" ) );
2375 }
2376
2377 EDA_ANGLE fp_orient = parentFootprint ? parentFootprint->GetOrientation() : ANGLE_0;
2378 EDA_ANGLE pad_orient = GetOrientation() - fp_orient;
2379 pad_orient.Normalize180();
2380
2381 if( !fp_orient.IsZero() )
2382 msg.Printf( wxT( "%g(+ %g)" ), pad_orient.AsDegrees(), fp_orient.AsDegrees() );
2383 else
2384 msg.Printf( wxT( "%g" ), GetOrientation().AsDegrees() );
2385
2386 aList.emplace_back( _( "Rotation" ), msg );
2387
2388 if( GetPadToDieLength() )
2389 aList.emplace_back( _( "Length in Package" ), aFrame->MessageTextFromValue( GetPadToDieLength() ) );
2390
2391 const VECTOR2I drill = GetDrillSize();
2392
2393 if( drill.x > 0 || drill.y > 0 )
2394 {
2396 {
2397 aList.emplace_back( _( "Hole" ),
2398 wxString::Format( wxT( "%s" ),
2399 aFrame->MessageTextFromValue( drill.x ) ) );
2400 }
2401 else
2402 {
2403 aList.emplace_back( _( "Hole X / Y" ),
2404 wxString::Format( wxT( "%s / %s" ),
2405 aFrame->MessageTextFromValue( drill.x ),
2406 aFrame->MessageTextFromValue( drill.y ) ) );
2407 }
2408 }
2409
2410 wxString source;
2412
2413 if( !source.IsEmpty() )
2414 {
2415 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2416 aFrame->MessageTextFromValue( clearance ) ),
2417 wxString::Format( _( "(from %s)" ),
2418 source ) );
2419 }
2420#if 0
2421 // useful for debug only
2422 aList.emplace_back( wxT( "UUID" ), m_Uuid.AsString() );
2423#endif
2424}
2425
2426
2427bool PAD::HitTest( const VECTOR2I& aPosition, int aAccuracy, PCB_LAYER_ID aLayer ) const
2428{
2429 if( !IsOnLayer( aLayer ) )
2430 return false;
2431
2432 VECTOR2I delta = aPosition - GetPosition();
2433 int boundingRadius = GetBoundingRadius() + aAccuracy;
2434
2435 if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
2436 return false;
2437
2438 bool contains = GetEffectivePolygon( aLayer, ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy );
2439
2440 return contains;
2441}
2442
2443
2444bool PAD::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2445{
2446 VECTOR2I delta = aPosition - GetPosition();
2447 int boundingRadius = GetBoundingRadius() + aAccuracy;
2448
2449 if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
2450 return false;
2451
2452 bool contains = false;
2453
2455 [&]( PCB_LAYER_ID l )
2456 {
2457 if( contains )
2458 return;
2459
2460 if( GetEffectivePolygon( l, ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy ) )
2461 contains = true;
2462 } );
2463
2464 contains |= GetEffectiveHoleShape()->Collide( aPosition, aAccuracy );
2465
2466 return contains;
2467}
2468
2469
2470bool PAD::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2471{
2472 BOX2I arect = aRect;
2473 arect.Normalize();
2474 arect.Inflate( aAccuracy );
2475
2476 BOX2I bbox = GetBoundingBox();
2477
2478 if( aContained )
2479 {
2480 return arect.Contains( bbox );
2481 }
2482 else
2483 {
2484 // Fast test: if aRect is outside the polygon bounding box,
2485 // rectangles cannot intersect
2486 if( !arect.Intersects( bbox ) )
2487 return false;
2488
2489 bool hit = false;
2490
2492 [&]( PCB_LAYER_ID aLayer )
2493 {
2494 if( hit )
2495 return;
2496
2497 const std::shared_ptr<SHAPE_POLY_SET>& poly = GetEffectivePolygon( aLayer, ERROR_INSIDE );
2498
2499 int count = poly->TotalVertices();
2500
2501 for( int ii = 0; ii < count; ii++ )
2502 {
2503 VECTOR2I vertex = poly->CVertex( ii );
2504 VECTOR2I vertexNext = poly->CVertex( ( ii + 1 ) % count );
2505
2506 // Test if the point is within aRect
2507 if( arect.Contains( vertex ) )
2508 {
2509 hit = true;
2510 break;
2511 }
2512
2513 // Test if this edge intersects aRect
2514 if( arect.Intersects( vertex, vertexNext ) )
2515 {
2516 hit = true;
2517 break;
2518 }
2519 }
2520 } );
2521
2522 if( !hit )
2523 {
2524 SHAPE_RECT rect( arect );
2525 hit |= GetEffectiveHoleShape()->Collide( &rect );
2526 }
2527
2528 return hit;
2529 }
2530}
2531
2532
2533bool PAD::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
2534{
2535 SHAPE_COMPOUND effectiveShape;
2536
2537 // Add padstack shapes
2539 [&]( PCB_LAYER_ID aLayer )
2540 {
2541 effectiveShape.AddShape( GetEffectiveShape( aLayer ) );
2542 } );
2543
2544 // Add hole shape
2545 effectiveShape.AddShape( GetEffectiveHoleShape() );
2546
2547 return KIGEOM::ShapeHitTest( aPoly, effectiveShape, aContained );
2548}
2549
2550
2551int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
2552{
2553 int diff;
2554
2555 if( ( diff = static_cast<int>( aPadRef->m_attribute ) - static_cast<int>( aPadCmp->m_attribute ) ) != 0 )
2556 return diff;
2557
2558 return PADSTACK::Compare( &aPadRef->Padstack(), &aPadCmp->Padstack() );
2559}
2560
2561
2562void PAD::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
2563{
2564 VECTOR2I newPos = GetPosition();
2565 RotatePoint( newPos, aRotCentre, aAngle );
2566 SetPosition( newPos );
2567
2568 SetOrientation( GetOrientation() + aAngle );
2569}
2570
2571
2572void PAD::GetPrimitiveLibScale( double& aScaleX, double& aScaleY ) const
2573{
2574 aScaleX = 1.0;
2575 aScaleY = 1.0;
2576
2577 if( const FOOTPRINT* fp = GetParentFootprint() )
2578 {
2579 const TRANSFORM_TRS& xform = fp->GetTransform();
2580 scaleInChildFrame( std::abs( xform.GetScaleX() ), std::abs( xform.GetScaleY() ), GetFPRelativeOrientation(),
2581 aScaleX, aScaleY );
2582 }
2583}
2584
2585
2587{
2588 if( !GetParentFootprint() )
2589 return;
2590
2591 double localSx, localSy;
2592 GetPrimitiveLibScale( localSx, localSy );
2593 aPrimitive->RebakeWithScale( localSx, localSy );
2594}
2595
2596
2597void PAD::OnFootprintRescaled( double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I& aAnchor,
2598 const EDA_ANGLE& aParentRotate )
2599{
2600 // Pad size, drill, and offset auto-derive from lib-frame padstack values
2601 // through the parent transform on read. Custom-shape primitives carry their
2602 // own geometry in the pad frame and are excluded from the read-time transform
2603 // (transformFp returns null for pad children), so rescale them explicitly.
2605 [&]( PCB_LAYER_ID aLayer )
2606 {
2607 for( const std::shared_ptr<PCB_SHAPE>& prim : Padstack().Primitives( aLayer ) )
2608 rebakePrimitiveToFootprint( prim.get() );
2609 } );
2610
2612}
2613
2614
2616{
2617 EDA_ANGLE parentOrient = ANGLE_0;
2618
2619 if( const FOOTPRINT* fp = GetParentFootprint() )
2620 parentOrient = fp->GetOrientation();
2621
2622 Padstack().SetOrientation( GetFPRelativeOrientation() + parentOrient );
2623 SetDirty();
2624}
2625
2626
2628{
2629 switch( aShape )
2630 {
2631 case PAD_SHAPE::CIRCLE: return _( "Circle" );
2632 case PAD_SHAPE::OVAL: return _( "Oval" );
2633 case PAD_SHAPE::RECTANGLE: return _( "Rectangle" );
2634 case PAD_SHAPE::TRAPEZOID: return _( "Trapezoid" );
2635 case PAD_SHAPE::ROUNDRECT: return _( "Rounded rectangle" );
2636 case PAD_SHAPE::CHAMFERED_RECT: return _( "Chamfered rectangle" );
2637 case PAD_SHAPE::CUSTOM: return _( "Custom shape" );
2638 default: return wxT( "???" );
2639 }
2640}
2641
2642
2643wxString PAD::ShowPadShape( PCB_LAYER_ID aLayer ) const
2644{
2645 return ShowPadShape( GetShape( aLayer ) );
2646}
2647
2648
2650{
2651 switch( GetShape( aLayer ) )
2652 {
2653 case PAD_SHAPE::CIRCLE: return _( "Circle" );
2654 case PAD_SHAPE::OVAL: return _( "Oval" );
2655 case PAD_SHAPE::RECTANGLE: return _( "Rect" );
2656 case PAD_SHAPE::TRAPEZOID: return _( "Trap" );
2657 case PAD_SHAPE::ROUNDRECT: return _( "Roundrect" );
2658 case PAD_SHAPE::CHAMFERED_RECT: return _( "Chamferedrect" );
2659 case PAD_SHAPE::CUSTOM: return _( "CustomShape" );
2660 default: return wxT( "???" );
2661 }
2662}
2663
2664
2665wxString PAD::ShowPadAttr() const
2666{
2667 switch( GetAttribute() )
2668 {
2669 case PAD_ATTRIB::PTH: return _( "PTH" );
2670 case PAD_ATTRIB::SMD: return _( "SMD" );
2671 case PAD_ATTRIB::CONN: return _( "Conn" );
2672 case PAD_ATTRIB::NPTH: return _( "NPTH" );
2673 default: return wxT( "???" );
2674 }
2675}
2676
2677
2678wxString PAD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
2679{
2680 FOOTPRINT* parentFP = GetParentFootprint();
2681
2682 // Don't report parent footprint info from footprint editor, viewer, etc.
2683 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
2684 parentFP = nullptr;
2685
2687 {
2688 if( parentFP )
2689 return wxString::Format( _( "NPTH pad of %s" ), parentFP->GetReference() );
2690 else
2691 return _( "NPTH pad" );
2692 }
2693 else if( GetNumber().IsEmpty() )
2694 {
2696 {
2697 if( parentFP )
2698 {
2699 return wxString::Format( _( "Pad %s of %s on %s" ),
2700 GetNetnameMsg(),
2701 parentFP->GetReference(),
2703 }
2704 else
2705 {
2706 return wxString::Format( _( "Pad on %s" ),
2708 }
2709 }
2710 else
2711 {
2712 if( parentFP )
2713 {
2714 return wxString::Format( _( "PTH pad %s of %s" ),
2715 GetNetnameMsg(),
2716 parentFP->GetReference() );
2717 }
2718 else
2719 {
2720 return _( "PTH pad" );
2721 }
2722 }
2723 }
2724 else
2725 {
2727 {
2728 if( parentFP )
2729 {
2730 return wxString::Format( _( "Pad %s %s of %s on %s" ),
2731 GetNumber(),
2732 GetNetnameMsg(),
2733 parentFP->GetReference(),
2735 }
2736 else
2737 {
2738 return wxString::Format( _( "Pad %s on %s" ),
2739 GetNumber(),
2741 }
2742 }
2743 else
2744 {
2745 if( parentFP )
2746 {
2747 return wxString::Format( _( "PTH pad %s %s of %s" ),
2748 GetNumber(),
2749 GetNetnameMsg(),
2750 parentFP->GetReference() );
2751 }
2752 else
2753 {
2754 return wxString::Format( _( "PTH pad %s" ),
2755 GetNumber() );
2756 }
2757 }
2758 }
2759}
2760
2761
2763{
2764 return BITMAPS::pad;
2765}
2766
2767
2769{
2770 PAD* cloned = new PAD( *this );
2771
2772 // Ensure the cloned primitives of the pad stack have the right parent
2773 cloned->Padstack().ForEachUniqueLayer(
2774 [&]( PCB_LAYER_ID aLayer )
2775 {
2776 for( std::shared_ptr<PCB_SHAPE>& primitive : cloned->m_padStack.Primitives( aLayer ) )
2777 primitive->SetParent( cloned );
2778 } );
2779
2780 return cloned;
2781}
2782
2783
2784std::vector<int> PAD::ViewGetLayers() const
2785{
2786 std::vector<int> layers;
2787 layers.reserve( 64 );
2788
2789 // A drill map on a layer asks the holes to draw their symbols there, so the symbols stay
2790 // in the view index and one hole edit repaints one hole
2792 {
2793 if( const BOARD* drillBoard = GetBoard() )
2794 {
2795 for( PCB_LAYER_ID mapLayer : drillBoard->DrillSymbolLayers().Seq() )
2796 layers.push_back( DRILL_SYMBOL_LAYER_FOR( mapLayer ) );
2797 }
2798 }
2799
2800 // These 2 types of pads contain a hole
2802 {
2803 layers.push_back( LAYER_PAD_PLATEDHOLES );
2804 layers.push_back( LAYER_PAD_HOLEWALLS );
2805 }
2806
2808 layers.push_back( LAYER_NON_PLATEDHOLES );
2809
2810
2812 layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
2813
2814 LSET cuLayers = ( m_padStack.LayerSet() & LSET::AllCuMask() );
2815
2816 // Don't spend cycles rendering layers that aren't visible
2817 if( const BOARD* board = GetBoard() )
2818 cuLayers &= board->GetEnabledLayers();
2819
2820 if( cuLayers.count() > 1 )
2821 {
2822 // Multi layer pad
2823 for( PCB_LAYER_ID layer : cuLayers.Seq() )
2824 {
2825 layers.push_back( LAYER_PAD_COPPER_START + layer );
2826 layers.push_back( LAYER_CLEARANCE_START + layer );
2827 }
2828
2829 layers.push_back( LAYER_PAD_NETNAMES );
2830 }
2831 else if( IsOnLayer( F_Cu ) )
2832 {
2833 layers.push_back( LAYER_PAD_COPPER_START );
2834 layers.push_back( LAYER_CLEARANCE_START );
2835
2836 // Is this a PTH pad that has only front copper? If so, we need to also display the
2837 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
2839 layers.push_back( LAYER_PAD_NETNAMES );
2840 else
2841 layers.push_back( LAYER_PAD_FR_NETNAMES );
2842 }
2843 else if( IsOnLayer( B_Cu ) )
2844 {
2845 layers.push_back( LAYER_PAD_COPPER_START + B_Cu );
2846 layers.push_back( LAYER_CLEARANCE_START + B_Cu );
2847
2848 // Is this a PTH pad that has only back copper? If so, we need to also display the
2849 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
2851 layers.push_back( LAYER_PAD_NETNAMES );
2852 else
2853 layers.push_back( LAYER_PAD_BK_NETNAMES );
2854 }
2855 else if( cuLayers.count() == 1 )
2856 {
2857 PCB_LAYER_ID layer = cuLayers.Seq().front();
2858
2859 layers.push_back( LAYER_PAD_COPPER_START + layer );
2860 layers.push_back( LAYER_CLEARANCE_START + layer );
2861 layers.push_back( LAYER_PAD_NETNAMES );
2862 }
2863
2864 // Check non-copper layers. This list should include all the layers that the
2865 // footprint editor allows a pad to be placed on.
2866 static const PCB_LAYER_ID layers_mech[] = { F_Mask, B_Mask, F_Paste, B_Paste,
2868
2869 for( PCB_LAYER_ID each_layer : layers_mech )
2870 {
2871 if( IsOnLayer( each_layer ) )
2872 layers.push_back( each_layer );
2873 }
2874
2875 return layers;
2876}
2877
2878
2879double PAD::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
2880{
2881 PCB_PAINTER& painter = static_cast<PCB_PAINTER&>( *aView->GetPainter() );
2882 PCB_RENDER_SETTINGS& renderSettings = *painter.GetSettings();
2883 const BOARD* board = GetBoard();
2884
2885 // Reviewing a drill drawing with pads hidden is normal, so the symbols answer to the
2886 // map's own layer rather than to the pads meta control
2887 if( IsDrillSymbolLayer( aLayer ) )
2888 {
2889 return aView->IsLayerVisibleCached( aLayer - LAYER_DRILL_SYMBOL_START ) ? LOD_SHOW
2890 : LOD_HIDE;
2891 }
2892
2893 // Meta control for hiding all pads
2894 if( !aView->IsLayerVisibleCached( LAYER_PADS ) )
2895 return LOD_HIDE;
2896
2897 // Handle Render tab switches
2898 //const PCB_LAYER_ID& pcbLayer = static_cast<PCB_LAYER_ID>( aLayer );
2899
2900 {
2901 const LSET padLayers = GetLayerSet();
2902 const bool onFront = ( padLayers & LSET::FrontMask() ).any();
2903 const bool onBack = ( padLayers & LSET::BackMask() ).any();
2904 const bool frVis = aView->IsLayerVisible( LAYER_FOOTPRINTS_FR );
2905 const bool bkVis = aView->IsLayerVisible( LAYER_FOOTPRINTS_BK );
2906
2907 if( onFront && !onBack && !frVis )
2908 return LOD_HIDE;
2909
2910 if( onBack && !onFront && !bkVis )
2911 return LOD_HIDE;
2912
2913 if( onFront && onBack && !frVis && !bkVis )
2914 return LOD_HIDE;
2915 }
2916
2917 // Selection and net highlight draw a pad on layers where it otherwise draws nothing
2918 const bool drawnRegardless = IsSelected() || renderSettings.IsPrinting()
2919 || ( renderSettings.IsHighlightEnabled()
2920 && renderSettings.GetHighlightNetCodes().contains( GetNetCode() ) );
2921
2922 if( !drawnRegardless )
2923 {
2924 // The painter draws a pad copper layer only where the pad flashes, plus the post-machining
2925 // indicator of a layer that has one
2926 if( IsPadCopperLayer( aLayer ) )
2927 {
2928 const PCB_LAYER_ID copperLayer = ToLAYER_ID( aLayer - LAYER_PAD_COPPER_START );
2929
2930 if( !FlashLayer( copperLayer ) && GetPostMachiningKnockout( copperLayer ) <= 0 )
2931 return LOD_HIDE;
2932 }
2933
2934 // The painter draws clearance outlines only when the pad clearance option is on
2935 if( IsClearanceLayer( aLayer ) && pcbconfig() && !pcbconfig()->m_Display.m_PadClearance )
2936 return LOD_HIDE;
2937 }
2938
2939 if( IsHoleLayer( aLayer ) )
2940 {
2941 LSET visiblePhysical = board->GetVisibleLayers();
2942 visiblePhysical &= board->GetEnabledLayers();
2943 visiblePhysical &= LSET::PhysicalLayersMask();
2944
2945 if( !visiblePhysical.any() )
2946 return LOD_HIDE;
2947 }
2948 else if( IsNetnameLayer( aLayer ) )
2949 {
2950 if( renderSettings.GetHighContrast() )
2951 {
2952 // Hide netnames unless pad is flashed to a high-contrast layer
2953 if( !FlashLayer( renderSettings.GetPrimaryHighContrastLayer() ) )
2954 return LOD_HIDE;
2955 }
2956 else
2957 {
2958 LSET visible = board->GetVisibleLayers();
2959 visible &= board->GetEnabledLayers();
2960
2961 // Hide netnames unless pad is flashed to a visible layer
2962 if( !FlashLayer( visible ) )
2963 return LOD_HIDE;
2964 }
2965
2966 // Netnames will be shown only if zoom is appropriate
2967 const int minSize = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
2968
2969 return lodScaleForThreshold( aView, minSize, pcbIUScale.mmToIU( 0.5 ) );
2970 }
2971
2972 VECTOR2L padSize = GetBoundingBox().GetSize();
2973 int64_t minSide = std::min( padSize.x, padSize.y );
2974
2975 if( minSide > 0 )
2976 return std::min( lodScaleForThreshold( aView, minSide, pcbIUScale.mmToIU( 0.2 ) ), 3.5 );
2977
2978 return LOD_SHOW;
2979}
2980
2981
2983{
2984 // Bounding box includes soldermask too. Remember mask and/or paste margins can be < 0
2985 int solderMaskMargin = 0;
2986 VECTOR2I solderPasteMargin;
2987
2989 [&]( PCB_LAYER_ID aLayer )
2990 {
2991 solderMaskMargin = std::max( solderMaskMargin, std::max( GetSolderMaskExpansion( aLayer ), 0 ) );
2992 VECTOR2I layerMargin = GetSolderPasteMargin( aLayer );
2993 solderPasteMargin.x = std::max( solderPasteMargin.x, layerMargin.x );
2994 solderPasteMargin.y = std::max( solderPasteMargin.y, layerMargin.y );
2995 } );
2996
2997 BOX2I bbox = GetBoundingBox();
2998 int clearance = 0;
2999
3000 // If we're drawing clearance lines then get the biggest possible clearance
3001 if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
3002 {
3003 if( cfg && cfg->m_Display.m_PadClearance && GetBoard() )
3005 }
3006
3007 // Look for the biggest possible bounding box
3008 int xMargin = std::max( solderMaskMargin, solderPasteMargin.x ) + clearance;
3009 int yMargin = std::max( solderMaskMargin, solderPasteMargin.y ) + clearance;
3010
3011 BOX2I viewBox( VECTOR2I( bbox.GetOrigin() ) - VECTOR2I( xMargin, yMargin ),
3012 VECTOR2I( bbox.GetSize() ) + VECTOR2I( 2 * xMargin, 2 * yMargin ) );
3013
3014 // Only a hole draws a drill symbol, so an SMD pad would just be given an oversized box
3015 if( HasHole() && GetBoard() )
3016 return GetBoard()->ExpandBoundingBoxForDrillSymbols( viewBox );
3017
3018 return viewBox;
3019}
3020
3021
3022void PAD::ImportSettingsFrom( const PAD& aMasterPad )
3023{
3024 SetPadstack( aMasterPad.Padstack() );
3025 // Layer Set should be updated before calling SetAttribute()
3026 SetLayerSet( aMasterPad.GetLayerSet() );
3027 SetAttribute( aMasterPad.GetAttribute() );
3028 // Unfortunately, SetAttribute() can change m_layerMask.
3029 // Be sure we keep the original mask by calling SetLayerSet() after SetAttribute()
3030 SetLayerSet( aMasterPad.GetLayerSet() );
3031 SetProperty( aMasterPad.GetProperty() );
3032
3033 // Must be after setting attribute and layerSet
3034 if( !CanHaveNumber() )
3035 SetNumber( wxEmptyString );
3036
3037 // I am not sure the m_LengthPadToDie should be imported, because this is a parameter
3038 // really specific to a given pad (JPC).
3039#if 0
3040 SetPadToDieLength( aMasterPad.GetPadToDieLength() );
3041 SetPadToDieDelay( aMasterPad.GetPadToDieDelay() );
3042#endif
3043
3044 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
3045 EDA_ANGLE pad_rot = aMasterPad.GetOrientation();
3046
3047 if( aMasterPad.GetParentFootprint() )
3048 pad_rot -= aMasterPad.GetParentFootprint()->GetOrientation();
3049
3050 if( GetParentFootprint() )
3051 pad_rot += GetParentFootprint()->GetOrientation();
3052
3053 SetOrientation( pad_rot );
3054
3056 [&]( PCB_LAYER_ID aLayer )
3057 {
3058 // Ensure that circles are circles
3059 // Stay in the library frame, since a board-frame round trip under a scale rounds the size
3060 if( aMasterPad.GetShape( aLayer ) == PAD_SHAPE::CIRCLE )
3061 SetLibSize( aLayer, VECTOR2I( Padstack().Size( aLayer ).x, Padstack().Size( aLayer ).x ) );
3062 } );
3063
3064 switch( aMasterPad.GetAttribute() )
3065 {
3066 case PAD_ATTRIB::SMD:
3067 case PAD_ATTRIB::CONN:
3068 // These pads have no hole, or any kind of drilling.
3070 break;
3071
3072 default:
3073 ;
3074 }
3075
3076 // copy also local settings:
3077 SetLocalClearance( aMasterPad.GetLocalClearance() );
3081
3086
3088
3090
3091 SetDirty();
3092}
3093
3094
3096{
3097 assert( aImage->Type() == PCB_PAD_T );
3098
3099 std::swap( *this, *static_cast<PAD*>( aImage ) );
3100}
3101
3102
3103bool PAD::TransformHoleToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
3104 ERROR_LOC aErrorLoc ) const
3105{
3106 VECTOR2I drillsize = GetDrillSize();
3107
3108 if( !drillsize.x || !drillsize.y )
3109 return false;
3110
3111 std::shared_ptr<SHAPE_SEGMENT> slot = GetEffectiveHoleShape();
3112
3113 TransformOvalToPolygon( aBuffer, slot->GetSeg().A, slot->GetSeg().B, slot->GetWidth() + aClearance * 2,
3114 aError, aErrorLoc );
3115
3116 return true;
3117}
3118
3119
3120double PAD::GetCoverageArea( int aTextMargin ) const
3121{
3122 SHAPE_POLY_SET poly;
3123
3125 [&]( PCB_LAYER_ID aLayer )
3126 {
3127 SHAPE_POLY_SET layerPoly;
3128 TransformShapeToPolygon( layerPoly, aLayer, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
3129 poly.BooleanAdd( layerPoly );
3130 } );
3131
3132 return polygonArea( poly );
3133}
3134
3135
3136void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
3137 int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
3138{
3139 wxASSERT_MSG( aLayer != UNDEFINED_LAYER,
3140 wxT( "UNDEFINED_LAYER is no longer allowed for PAD::TransformShapeToPolygon" ) );
3141
3142 // minimal segment count to approximate a circle to create the polygonal pad shape
3143 // This minimal value is mainly for very small pads, like SM0402.
3144 // Most of time pads are using the segment count given by aError value.
3145 const int pad_min_seg_per_circle_count = 16;
3146 const VECTOR2I padSize = GetSize( aLayer );
3147 int dx = padSize.x / 2;
3148 int dy = padSize.y / 2;
3149
3150 VECTOR2I padShapePos = ShapePos( aLayer ); // Note: for pad having a shape offset, the pad
3151 // position is NOT the shape position
3152
3153 switch( PAD_SHAPE shape = GetShape( aLayer ) )
3154 {
3155 case PAD_SHAPE::CIRCLE:
3156 case PAD_SHAPE::OVAL:
3157 // Note: dx == dy is not guaranteed for circle pads in legacy boards
3158 if( dx == dy || ( shape == PAD_SHAPE::CIRCLE ) )
3159 {
3160 TransformCircleToPolygon( aBuffer, padShapePos, dx + aClearance, aMaxError, aErrorLoc,
3161 pad_min_seg_per_circle_count );
3162 }
3163 else
3164 {
3165 int half_width = std::min( dx, dy );
3166 VECTOR2I delta( dx - half_width, dy - half_width );
3167
3169
3170 TransformOvalToPolygon( aBuffer, padShapePos - delta, padShapePos + delta,
3171 ( half_width + aClearance ) * 2, aMaxError, aErrorLoc,
3172 pad_min_seg_per_circle_count );
3173 }
3174
3175 break;
3176
3179 {
3180 const VECTOR2I& trapDelta = m_padStack.TrapezoidDeltaSize( aLayer );
3181 int ddx = shape == PAD_SHAPE::TRAPEZOID ? trapDelta.x / 2 : 0;
3182 int ddy = shape == PAD_SHAPE::TRAPEZOID ? trapDelta.y / 2 : 0;
3183
3184 SHAPE_POLY_SET outline;
3185 TransformTrapezoidToPolygon( outline, padShapePos, padSize, GetOrientation(), ddx, ddy, aClearance, aMaxError,
3186 aErrorLoc );
3187 aBuffer.Append( outline );
3188 break;
3189 }
3190
3193 {
3194 bool doChamfer = shape == PAD_SHAPE::CHAMFERED_RECT;
3195
3196 SHAPE_POLY_SET outline;
3198 outline, padShapePos, padSize, GetOrientation(), GetRoundRectCornerRadius( aLayer ),
3199 doChamfer ? GetChamferRectRatio( aLayer ) : 0, doChamfer ? GetChamferPositions( aLayer ) : 0,
3200 aClearance, aMaxError, aErrorLoc );
3201 aBuffer.Append( outline );
3202 break;
3203 }
3204
3205 case PAD_SHAPE::CUSTOM:
3206 {
3207 SHAPE_POLY_SET outline;
3208 MergePrimitivesAsPolygon( aLayer, &outline, aErrorLoc );
3209 outline.Rotate( GetOrientation() );
3210 outline.Move( VECTOR2I( padShapePos ) );
3211
3212 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
3213 {
3214 if( aErrorLoc == ERROR_OUTSIDE )
3215 aClearance += aMaxError;
3216
3217 outline.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aMaxError );
3218 outline.Fracture();
3219 }
3220 else if( aClearance < 0 )
3221 {
3222 // Negative clearances are primarily for drawing solder paste layer, so we don't
3223 // worry ourselves overly about which side the error is on.
3224
3225 // aClearance is negative so this is actually a deflate
3226 outline.Inflate( aClearance, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, aMaxError );
3227 outline.Fracture();
3228 }
3229
3230 aBuffer.Append( outline );
3231 break;
3232 }
3233
3234 default:
3235 wxFAIL_MSG( wxT( "PAD::TransformShapeToPolygon no implementation for " )
3236 + wxString( std::string( magic_enum::enum_name( shape ) ) ) );
3237 break;
3238 }
3239}
3240
3241
3242std::vector<PCB_SHAPE*> PAD::Recombine( bool aIsDryRun, int maxError )
3243{
3244 FOOTPRINT* footprint = GetParentFootprint();
3245
3246 for( BOARD_ITEM* item : footprint->GraphicalItems() )
3247 item->ClearFlags( SKIP_STRUCT );
3248
3249 auto findNext =
3250 [&]( PCB_LAYER_ID aLayer ) -> PCB_SHAPE*
3251 {
3252 SHAPE_POLY_SET padPoly;
3253 TransformShapeToPolygon( padPoly, aLayer, 0, maxError, ERROR_INSIDE );
3254
3255 for( BOARD_ITEM* item : footprint->GraphicalItems() )
3256 {
3257 PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( item );
3258
3259 if( !shape || ( shape->GetFlags() & SKIP_STRUCT ) )
3260 continue;
3261
3262 if( shape->GetLayer() != aLayer )
3263 continue;
3264
3265 if( shape->IsProxyItem() ) // Pad number (and net name) box
3266 return shape;
3267
3268 SHAPE_POLY_SET drawPoly;
3269 shape->TransformShapeToPolygon( drawPoly, aLayer, 0, maxError, ERROR_INSIDE );
3270 drawPoly.BooleanIntersection( padPoly );
3271
3272 if( !drawPoly.IsEmpty() )
3273 return shape;
3274 }
3275
3276 return nullptr;
3277 };
3278
3279 auto findMatching =
3280 [&]( PCB_SHAPE* aShape ) -> std::vector<PCB_SHAPE*>
3281 {
3282 std::vector<PCB_SHAPE*> matching;
3283
3284 for( BOARD_ITEM* item : footprint->GraphicalItems() )
3285 {
3286 PCB_SHAPE* other = dynamic_cast<PCB_SHAPE*>( item );
3287
3288 if( !other || ( other->GetFlags() & SKIP_STRUCT ) )
3289 continue;
3290
3291 if( Padstack().Mode() == PADSTACK::MODE::NORMAL )
3292 {
3293 // A signle layer (F_Cu) in NORMAL mode represents _all_ layers,
3294 // so disable the layer test entirely
3295 }
3296 else
3297 {
3298 if( aShape->GetLayer() != other->GetLayer() )
3299 continue;
3300 }
3301
3302 if( aShape->Compare( other ) == 0 )
3303 matching.push_back( other );
3304 }
3305
3306 return matching;
3307 };
3308
3309 std::vector<PCB_SHAPE*> mergedShapes;
3310
3311 auto recombine =
3312 [&]( PCB_LAYER_ID sourceBoardLayer, PCB_LAYER_ID padstackStorageLayer )
3313 {
3314 PAD_SHAPE origShape = GetShape( sourceBoardLayer );
3315
3316 // If there are intersecting items to combine, we need to first make sure the pad is a
3317 // custom-shape pad.
3318 if( !aIsDryRun && findNext( sourceBoardLayer ) && origShape != PAD_SHAPE::CUSTOM )
3319 {
3320 if( origShape == PAD_SHAPE::CIRCLE || origShape == PAD_SHAPE::RECTANGLE )
3321 {
3322 // Use the existing pad as an anchor
3323 SetAnchorPadShape( padstackStorageLayer, origShape );
3324 SetShape( padstackStorageLayer, PAD_SHAPE::CUSTOM );
3325 }
3326 else
3327 {
3328 // Create a new circular anchor and convert existing pad to a polygon primitive
3329 SHAPE_POLY_SET existingOutline;
3330 TransformShapeToPolygon( existingOutline, padstackStorageLayer, 0, maxError, ERROR_INSIDE );
3331
3332 VECTOR2I origin( ShapePos( padstackStorageLayer ) );
3333 VECTOR2I nearestPoint, dummyPoint;
3334 SHAPE_SEGMENT originSeg( origin, origin );
3335 existingOutline.NearestPoints( &originSeg, nearestPoint, dummyPoint );
3336 int radius = ( nearestPoint - origin ).EuclideanNorm();
3337
3338 SetAnchorPadShape( padstackStorageLayer, PAD_SHAPE::CIRCLE );
3339 SetSize( padstackStorageLayer, VECTOR2I( radius * 2, radius * 2 ) );
3340 SetShape( padstackStorageLayer, PAD_SHAPE::CUSTOM );
3341
3342 PCB_SHAPE* shape = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
3343 shape->SetFilled( true );
3345 shape->SetPolyShape( existingOutline );
3346 shape->Move( - ShapePos( padstackStorageLayer ) );
3347 shape->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
3348 AddPrimitive( padstackStorageLayer, shape );
3349 }
3350 }
3351
3352 while( PCB_SHAPE* fpShape = findNext( sourceBoardLayer ) )
3353 {
3354 fpShape->SetFlags( SKIP_STRUCT );
3355
3356 mergedShapes.push_back( fpShape );
3357
3358 if( !aIsDryRun )
3359 {
3360 // If the editor was inside a group when the pad was exploded, the added exploded shapes
3361 // will be part of the group. Remove them here before duplicating; we don't want the
3362 // primitives to wind up in a group.
3363 if( EDA_GROUP* group = fpShape->GetParentGroup(); group )
3364 group->RemoveItem( fpShape );
3365
3366 PCB_SHAPE* primitive = static_cast<PCB_SHAPE*>( fpShape->Duplicate( IGNORE_PARENT_GROUP ) );
3367
3368 primitive->SetParent( nullptr );
3369
3370 // Convert any hatched fills to solid
3371 if( primitive->IsAnyFill() )
3372 primitive->SetFillMode( FILL_T::FILLED_SHAPE );
3373
3374 primitive->Move( - ShapePos( padstackStorageLayer ) );
3375 primitive->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
3376
3377 AddPrimitive( padstackStorageLayer, primitive );
3378 }
3379
3380 // See if there are other shapes that match and mark them for delete.
3381 for( PCB_SHAPE* other : findMatching( fpShape ) )
3382 {
3383 other->SetFlags( SKIP_STRUCT );
3384 mergedShapes.push_back( other );
3385 }
3386 }
3387 };
3388
3389 if( Padstack().Mode() == PADSTACK::MODE::NORMAL )
3390 {
3392 }
3393 else
3394 {
3396 [&]( PCB_LAYER_ID aLayer )
3397 {
3398 recombine( aLayer, aLayer );
3399 } );
3400 }
3401
3402 for( BOARD_ITEM* item : footprint->GraphicalItems() )
3403 item->ClearFlags( SKIP_STRUCT );
3404
3405 if( !aIsDryRun )
3407
3408 return mergedShapes;
3409}
3410
3411
3412bool PAD::operator==( const BOARD_ITEM& aBoardItem ) const
3413{
3414 if( Type() != aBoardItem.Type() )
3415 return false;
3416
3417 if( m_parent && aBoardItem.GetParent() && m_parent->m_Uuid != aBoardItem.GetParent()->m_Uuid )
3418 return false;
3419
3420 const PAD& other = static_cast<const PAD&>( aBoardItem );
3421
3422 return *this == other;
3423}
3424
3425
3426bool PAD::operator==( const PAD& aOther ) const
3427{
3428 if( Padstack() != aOther.Padstack() )
3429 return false;
3430
3431 if( GetPosition() != aOther.GetPosition() )
3432 return false;
3433
3434 if( GetAttribute() != aOther.GetAttribute() )
3435 return false;
3436
3437 return true;
3438}
3439
3440
3441double PAD::Similarity( const BOARD_ITEM& aOther ) const
3442{
3443 if( aOther.Type() != Type() )
3444 return 0.0;
3445
3446 if( m_parent->m_Uuid != aOther.GetParent()->m_Uuid )
3447 return 0.0;
3448
3449 const PAD& other = static_cast<const PAD&>( aOther );
3450
3451 double similarity = 1.0;
3452
3453 if( GetPosition() != other.GetPosition() )
3454 similarity *= 0.9;
3455
3456 if( GetAttribute() != other.GetAttribute() )
3457 similarity *= 0.9;
3458
3459 similarity *= Padstack().Similarity( other.Padstack() );
3460
3461 return similarity;
3462}
3463
3464
3465void PAD::AddPrimitivePoly( PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPoly, int aThickness,
3466 bool aFilled )
3467{
3468 // If aPoly has holes, convert it to a polygon with no holes.
3469 SHAPE_POLY_SET poly_no_hole;
3470 poly_no_hole.Append( aPoly );
3471
3472 if( poly_no_hole.HasHoles() )
3473 poly_no_hole.Fracture();
3474
3475 // There should never be multiple shapes, but if there are, we split them into
3476 // primitives so that we can edit them both.
3477 for( int ii = 0; ii < poly_no_hole.OutlineCount(); ++ii )
3478 {
3479 SHAPE_POLY_SET poly_outline( poly_no_hole.COutline( ii ) );
3480 PCB_SHAPE* item = new PCB_SHAPE();
3481 item->SetShape( SHAPE_T::POLY );
3482 item->SetFilled( aFilled );
3483 item->SetPolyShape( poly_outline );
3484 item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
3485 AddPrimitive( aLayer, item );
3486 }
3487
3488 SetDirty();
3489}
3490
3491
3492void PAD::AddPrimitivePoly( PCB_LAYER_ID aLayer, const std::vector<VECTOR2I>& aPoly, int aThickness,
3493 bool aFilled )
3494{
3495 PCB_SHAPE* item = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
3496 item->SetFilled( aFilled );
3497 item->SetPolyPoints( aPoly );
3498 item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
3499 AddPrimitive( aLayer, item );
3500 SetDirty();
3501}
3502
3503
3504void PAD::ReplacePrimitives( PCB_LAYER_ID aLayer, const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList )
3505{
3506 // clear old list
3507 DeletePrimitivesList( aLayer );
3508
3509 // Import to the given shape list
3510 if( aPrimitivesList.size() )
3511 AppendPrimitives( aLayer, aPrimitivesList );
3512
3513 SetDirty();
3514}
3515
3516
3517void PAD::AppendPrimitives( PCB_LAYER_ID aLayer, const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList )
3518{
3519 // Add duplicates of aPrimitivesList to the pad primitives list:
3520 for( const std::shared_ptr<PCB_SHAPE>& prim : aPrimitivesList )
3521 AddPrimitive( aLayer, new PCB_SHAPE( *prim ) );
3522
3523 SetDirty();
3524}
3525
3526
3527void PAD::AddPrimitive( PCB_LAYER_ID aLayer, PCB_SHAPE* aPrimitive )
3528{
3529 aPrimitive->SetParent( this );
3530
3531 // Seed lib state from the primitive's current values, then rebake so the
3532 // runtime cache reflects the parent FP transform reachable via the pad.
3533 aPrimitive->OverrideLibCoords( aPrimitive->GetStart(), aPrimitive->GetEnd(),
3534 aPrimitive->GetShape() == SHAPE_T::ARC ? aPrimitive->GetArcMid()
3535 : VECTOR2I( 0, 0 ) );
3536
3537 if( aPrimitive->GetShape() == SHAPE_T::BEZIER )
3538 aPrimitive->OverrideLibBezier( aPrimitive->GetBezierC1(), aPrimitive->GetBezierC2() );
3539
3540 if( aPrimitive->GetShape() == SHAPE_T::POLY )
3541 aPrimitive->OverrideLibPoly( aPrimitive->GetPolyShape() );
3542
3543 // Covers load, where the footprint scale is set before the primitives are parsed.
3544 rebakePrimitiveToFootprint( aPrimitive );
3545
3546 m_padStack.AddPrimitive( aPrimitive, aLayer );
3547
3548 SetDirty();
3549}
3550
3551
3553{
3554 if( aLayer == UNDEFINED_LAYER )
3555 {
3556 m_padStack.ForEachUniqueLayer(
3557 [&]( PCB_LAYER_ID l )
3558 {
3559 m_padStack.ClearPrimitives( l );
3560 } );
3561 }
3562 else
3563 {
3564 m_padStack.ClearPrimitives( aLayer);
3565 }
3566
3567 SetDirty();
3568}
3569
3570
3572 ERROR_LOC aErrorLoc ) const
3573{
3574 aMergedPolygon->RemoveAllContours();
3575
3576 // Add the anchor pad shape in aMergedPolygon, others in aux_polyset:
3577 // The anchor pad is always at 0,0
3578 VECTOR2I padSize = GetSize( aLayer );
3579
3580 switch( GetAnchorPadShape( aLayer ) )
3581 {
3583 {
3584 SHAPE_RECT rect( -padSize.x / 2, -padSize.y / 2, padSize.x, padSize.y );
3585 aMergedPolygon->AddOutline( rect.Outline() );
3586 break;
3587 }
3588
3589 default:
3590 case PAD_SHAPE::CIRCLE:
3591 TransformCircleToPolygon( *aMergedPolygon, VECTOR2I( 0, 0 ), padSize.x / 2, GetMaxError(), aErrorLoc );
3592 break;
3593 }
3594
3595 SHAPE_POLY_SET polyset;
3596
3597 for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives( aLayer ) )
3598 {
3599 if( !primitive->IsProxyItem() )
3600 primitive->TransformShapeToPolygon( polyset, UNDEFINED_LAYER, 0, GetMaxError(), aErrorLoc );
3601 }
3602
3603 polyset.Simplify();
3604
3605 // Merge all polygons with the initial pad anchor shape
3606 if( polyset.OutlineCount() )
3607 {
3608 aMergedPolygon->BooleanAdd( polyset );
3609 aMergedPolygon->Fracture();
3610 }
3611}
3612
3613
3614static struct PAD_DESC
3615{
3617 {
3619 .Map( PAD_ATTRIB::PTH, _HKI( "Through-hole" ) )
3620 .Map( PAD_ATTRIB::SMD, _HKI( "SMD" ) )
3621 .Map( PAD_ATTRIB::CONN, _HKI( "Edge connector" ) )
3622 .Map( PAD_ATTRIB::NPTH, _HKI( "NPTH, mechanical" ) );
3623
3625 .Map( PAD_SHAPE::CIRCLE, _HKI( "Circle" ) )
3626 .Map( PAD_SHAPE::RECTANGLE, _HKI( "Rectangle" ) )
3627 .Map( PAD_SHAPE::OVAL, _HKI( "Oval" ) )
3628 .Map( PAD_SHAPE::TRAPEZOID, _HKI( "Trapezoid" ) )
3629 .Map( PAD_SHAPE::ROUNDRECT, _HKI( "Rounded rectangle" ) )
3630 .Map( PAD_SHAPE::CHAMFERED_RECT, _HKI( "Chamfered rectangle" ) )
3631 .Map( PAD_SHAPE::CUSTOM, _HKI( "Custom" ) );
3632
3634 .Map( PAD_PROP::NONE, _HKI( "None" ) )
3635 .Map( PAD_PROP::BGA, _HKI( "BGA pad" ) )
3636 .Map( PAD_PROP::FIDUCIAL_GLBL, _HKI( "Fiducial, global to board" ) )
3637 .Map( PAD_PROP::FIDUCIAL_LOCAL, _HKI( "Fiducial, local to footprint" ) )
3638 .Map( PAD_PROP::TESTPOINT, _HKI( "Test point pad" ) )
3639 .Map( PAD_PROP::HEATSINK, _HKI( "Heatsink pad" ) )
3640 .Map( PAD_PROP::CASTELLATED, _HKI( "Castellated pad" ) )
3641 .Map( PAD_PROP::MECHANICAL, _HKI( "Mechanical pad" ) )
3642 .Map( PAD_PROP::PRESSFIT, _HKI( "Press-fit pad" ) );
3643
3645 .Map( PAD_DRILL_SHAPE::UNDEFINED, _HKI( "Undefined" ) )
3646 .Map( PAD_DRILL_SHAPE::CIRCLE, _HKI( "Round" ) )
3647 .Map( PAD_DRILL_SHAPE::OBLONG, _HKI( "Oblong" ) );
3648
3650 .Map( PAD_SIM_ELECTRICAL_TYPE::NONE, _HKI( "None" ) )
3651 .Map( PAD_SIM_ELECTRICAL_TYPE::SOURCE, _HKI( "Source" ) )
3652 .Map( PAD_SIM_ELECTRICAL_TYPE::SINK, _HKI( "Sink" ) );
3653
3654 // Ensure post-machining mode enum choices are defined before properties use them
3655 {
3658
3659 if( pmMap.Choices().GetCount() == 0 )
3660 {
3665 }
3666 }
3667
3668 // Ensure backdrill mode enum choices are defined before properties use them
3669 {
3671
3672 if( bdMap.Choices().GetCount() == 0 )
3673 {
3675 .Map( BACKDRILL_MODE::NO_BACKDRILL, _HKI( "No backdrill" ) )
3676 .Map( BACKDRILL_MODE::BACKDRILL_BOTTOM, _HKI( "Backdrill bottom" ) )
3677 .Map( BACKDRILL_MODE::BACKDRILL_TOP, _HKI( "Backdrill top" ) )
3678 .Map( BACKDRILL_MODE::BACKDRILL_BOTH, _HKI( "Backdrill both" ) );
3679 }
3680 }
3681
3683
3684 if( zcMap.Choices().GetCount() == 0 )
3685 {
3687 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
3688 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
3689 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
3690 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
3691 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
3692 }
3693
3695 .Map( UNCONNECTED_LAYER_MODE::KEEP_ALL, _HKI( "All copper layers" ) )
3696 .Map( UNCONNECTED_LAYER_MODE::REMOVE_ALL, _HKI( "Connected layers only" ) )
3697 .Map( UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END, _HKI( "Front, back and connected layers" ) )
3698 .Map( UNCONNECTED_LAYER_MODE::START_END_ONLY, _HKI( "Start and end layers only" ) );
3699
3701 REGISTER_TYPE( PAD );
3706
3707 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
3708 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_ITEM ), _HKI( "Locked" ) );
3709
3710 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Orientation" ),
3712
3713 auto isCopperPad =
3714 []( INSPECTABLE* aItem ) -> bool
3715 {
3716 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3717 return pad->GetAttribute() != PAD_ATTRIB::NPTH;
3718
3719 return false;
3720 };
3721
3722 auto padCanHaveHole =
3723 []( INSPECTABLE* aItem ) -> bool
3724 {
3725 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3726 return pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH;
3727
3728 return false;
3729 };
3730
3731 auto hasNormalPadstack =
3732 []( INSPECTABLE* aItem ) -> bool
3733 {
3734 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3735 return pad->Padstack().Mode() == PADSTACK::MODE::NORMAL;
3736
3737 return true;
3738 };
3739
3741 isCopperPad );
3742 propMgr.OverrideAvailability( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net Class" ),
3743 isCopperPad );
3744
3745 const wxString groupPad = _HKI( "Pad Properties" );
3746 const wxString groupPostMachining = _HKI( "Post-machining Properties" );
3747 const wxString groupBackdrill = _HKI( "Backdrill Properties" );
3748
3749 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_ATTRIB>( _HKI( "Pad Type" ),
3751 groupPad );
3752
3753 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_SHAPE>( _HKI( "Pad Shape" ),
3755 groupPad )
3756 .SetAvailableFunc( hasNormalPadstack );
3757
3758 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pad Number" ),
3760 groupPad )
3761 .SetAvailableFunc( isCopperPad );
3762
3763 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Name" ),
3765 groupPad )
3767
3768 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Type" ),
3770 groupPad )
3772 .SetChoicesFunc( []( INSPECTABLE* aItem )
3773 {
3774 wxPGChoices choices;
3775
3776 for( int ii = 0; ii < ELECTRICAL_PINTYPES_TOTAL; ii++ )
3778
3779 return choices;
3780 } );
3781
3782 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_SIM_ELECTRICAL_TYPE>( _HKI( "Simulation Electrical Type" ),
3784 groupPad );
3785
3786 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size X" ),
3788 groupPad )
3789 .SetAvailableFunc( hasNormalPadstack );
3790 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size Y" ),
3792 groupPad )
3793 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
3794 {
3795 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3796 {
3797 // Custom padstacks can't have size modified through panel
3798 if( pad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
3799 return false;
3800
3801 // Circle pads have no usable y-size
3802 return pad->GetShape( PADSTACK::ALL_LAYERS ) != PAD_SHAPE::CIRCLE;
3803 }
3804
3805 return true;
3806 } );
3807
3808 const auto hasRoundRadius =
3809 []( INSPECTABLE* aItem ) -> bool
3810 {
3811 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3812 {
3813 // Custom padstacks can't have this property modified through panel
3814 if( pad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
3815 return false;
3816
3818 }
3819
3820 return false;
3821 };
3822
3823 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Corner Radius Ratio" ),
3825 groupPad )
3826 .SetAvailableFunc( hasRoundRadius );
3827
3828 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Corner Radius Size" ),
3830 groupPad )
3831 .SetAvailableFunc( hasRoundRadius );
3832
3833 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_DRILL_SHAPE>( _HKI( "Hole Shape" ),
3834 &PAD::SetDrillShape, &PAD::GetDrillShape ), groupPad )
3835 .SetWriteableFunc( padCanHaveHole );
3836
3837 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size X" ),
3839 groupPad )
3840 .SetWriteableFunc( padCanHaveHole )
3842
3843 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size Y" ),
3845 groupPad )
3846 .SetWriteableFunc( padCanHaveHole )
3848 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
3849 {
3850 // Circle holes have no usable y-size
3851 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3852 return pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE;
3853
3854 return true;
3855 } );
3856
3857 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_DRILL_POST_MACHINING_MODE>( _HKI( "Top Post-machining" ),
3859 groupPostMachining )
3860 .SetWriteableFunc( padCanHaveHole )
3861 .SetAvailableFunc( []( INSPECTABLE* aItem )
3862 {
3863 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3864 return pad->GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE;
3865
3866 return false;
3867 } );
3868
3869 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Top Post-machining Size" ),
3871 groupPostMachining )
3872 .SetWriteableFunc( padCanHaveHole )
3874 []( INSPECTABLE* aItem )
3875 {
3876 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3877 {
3878 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
3879 return false;
3880
3881 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = pad->GetFrontPostMachining();
3882 return mode.has_value()
3884 || mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK );
3885 }
3886
3887 return false;
3888 } );
3889
3890 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Top Counterbore Depth" ),
3892 groupPostMachining )
3893 .SetWriteableFunc( padCanHaveHole )
3895 []( INSPECTABLE* aItem )
3896 {
3897 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3898 {
3899 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
3900 return false;
3901
3902 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = pad->GetFrontPostMachining();
3903 return mode.has_value() && mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE;
3904 }
3905
3906 return false;
3907 } );
3908
3909 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Top Countersink Angle" ),
3911 groupPostMachining )
3912 .SetWriteableFunc( padCanHaveHole )
3914 []( INSPECTABLE* aItem )
3915 {
3916 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3917 {
3918 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
3919 return false;
3920
3921 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = pad->GetFrontPostMachining();
3922 return mode.has_value() && mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK;
3923 }
3924
3925 return false;
3926 } );
3927
3928 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_DRILL_POST_MACHINING_MODE>( _HKI( "Bottom Post-machining" ),
3930 groupPostMachining )
3931 .SetWriteableFunc( padCanHaveHole )
3932 .SetAvailableFunc( []( INSPECTABLE* aItem )
3933 {
3934 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3935 return pad->GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE;
3936
3937 return false;
3938 } );
3939
3940 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Bottom Post-machining Size" ),
3942 groupPostMachining )
3943 .SetWriteableFunc( padCanHaveHole )
3945 []( INSPECTABLE* aItem )
3946 {
3947 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3948 {
3949 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
3950 return false;
3951
3952 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = pad->GetBackPostMachining();
3953 return mode.has_value()
3955 || mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK );
3956 }
3957
3958 return false;
3959 } );
3960
3961 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Bottom Counterbore Depth" ),
3963 groupPostMachining )
3964 .SetWriteableFunc( padCanHaveHole )
3966 []( INSPECTABLE* aItem )
3967 {
3968 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3969 {
3970 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
3971 return false;
3972
3973 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = pad->GetBackPostMachining();
3974 return mode.has_value() && mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE;
3975 }
3976
3977 return false;
3978 } );
3979
3980 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Bottom Countersink Angle" ),
3982 groupPostMachining )
3983 .SetWriteableFunc( padCanHaveHole )
3985 []( INSPECTABLE* aItem )
3986 {
3987 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
3988 {
3989 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
3990 return false;
3991
3992 std::optional<PAD_DRILL_POST_MACHINING_MODE> mode = pad->GetBackPostMachining();
3993 return mode.has_value() && mode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK;
3994 }
3995
3996 return false;
3997 } );
3998
3999 propMgr.AddProperty( new PROPERTY_ENUM<PAD, BACKDRILL_MODE>( _HKI( "Backdrill Mode" ),
4001 groupBackdrill );
4002
4003 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Bottom Backdrill Size" ),
4005 groupBackdrill )
4007 []( INSPECTABLE* aItem ) -> bool
4008 {
4009 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
4010 {
4011 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
4012 return false;
4013
4014 BACKDRILL_MODE mode = pad->GetBackdrillMode();
4017 }
4018
4019 return false;
4020 } );
4021
4022 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PCB_LAYER_ID>( _HKI( "Bottom Backdrill Must-Cut" ),
4024 groupBackdrill )
4026 []( INSPECTABLE* aItem ) -> bool
4027 {
4028 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
4029 {
4030 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
4031 return false;
4032
4033 BACKDRILL_MODE mode = pad->GetBackdrillMode();
4036 }
4037
4038 return false;
4039 } );
4040
4041 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Top Backdrill Size" ),
4043 groupBackdrill )
4045 []( INSPECTABLE* aItem ) -> bool
4046 {
4047 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
4048 {
4049 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
4050 return false;
4051
4052 BACKDRILL_MODE mode = pad->GetBackdrillMode();
4054 }
4055
4056 return false;
4057 } );
4058
4059 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PCB_LAYER_ID>( _HKI( "Top Backdrill Must-Cut" ),
4061 groupBackdrill )
4063 []( INSPECTABLE* aItem ) -> bool
4064 {
4065 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
4066 {
4067 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
4068 return false;
4069
4070 BACKDRILL_MODE mode = pad->GetBackdrillMode();
4072 }
4073
4074 return false;
4075 } );
4076
4077
4078 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_PROP>( _HKI( "Fabrication Property" ),
4080 groupPad );
4081
4082 propMgr.AddProperty( new PROPERTY_ENUM<PAD, UNCONNECTED_LAYER_MODE>( _HKI( "Copper Layers" ),
4084 groupPad );
4085
4086 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Pad To Die Length" ),
4088 groupPad )
4089 .SetAvailableFunc( isCopperPad );
4090
4091 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Pad To Die Delay" ),
4093 groupPad )
4094 .SetAvailableFunc( isCopperPad );
4095
4096 const wxString groupOverrides = _HKI( "Overrides" );
4097
4098 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Clearance Override" ),
4100 groupOverrides ).SetIsCopyable();
4101
4102 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
4104 groupOverrides ).SetIsCopyable();
4105
4106 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Solderpaste Margin Override" ),
4108 groupOverrides ).SetIsCopyable();
4109
4110 propMgr.AddProperty( new PROPERTY<PAD, std::optional<double>>( _HKI( "Solderpaste Margin Ratio Override" ),
4113 groupOverrides ).SetIsCopyable();
4114
4115 propMgr.AddProperty( new PROPERTY_ENUM<PAD, ZONE_CONNECTION>( _HKI( "Zone Connection Style" ),
4117 groupOverrides ).SetIsCopyable();
4118
4119 constexpr int minZoneWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
4120
4121 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Thermal Relief Spoke Width" ),
4124 groupOverrides )
4126
4127 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Thermal Relief Spoke Angle" ),
4130 groupOverrides ).SetIsCopyable();
4131
4132 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Thermal Relief Gap" ),
4135 groupOverrides )
4137
4138 // TODO delta, drill shape offset, layer set
4139 }
4141
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_OUTSIDE
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
constexpr int ARC_LOW_DEF
Definition base_units.h:143
BITMAPS
A list of all bitmap identifiers.
@ FPHOLDER
Definition board.h:403
ZONE_LAYER_OVERRIDE
Conditionally flashed vias and pads that interact with zones of different priority can be very squirr...
Definition board_item.h:73
@ ZLO_NONE
Definition board_item.h:74
@ ZLO_FORCE_FLASHED
Definition board_item.h:75
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
BASE_SET & set(size_t pos)
Definition base_set.h:126
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
BOARD_CONNECTED_ITEM(BOARD_ITEM *aParent, KICAD_T idtype)
void PackNet(kiapi::board::types::Net *aProto) const
TEARDROP_PARAMETERS m_teardropParams
Not all BOARD_CONNECTED_ITEMs support teardrops, but we want those that do to share a single section ...
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
const wxString & GetShortNetname() const
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
void UnpackNet(const kiapi::board::types::Net &aProto)
Assigns a net to this item from an API message.
TEARDROP_PARAMETERS & GetTeardropParams()
void SetTeardropsEnabled(bool aEnable)
std::shared_ptr< DRC_ENGINE > m_DRCEngine
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:87
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:427
PCB_LAYER_ID GetFlippedLayer(PCB_LAYER_ID aLayer) const
Return the layer paired with aLayer on the opposite side of the board.
static double polygonArea(SHAPE_POLY_SET &aPolySet)
Area of aPolySet with every contour closed first, holes subtracted.
PCB_LAYER_ID m_layer
Definition board_item.h:600
bool IsLocked() const override
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
virtual wxString LayerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
BOARD_ITEM & operator=(const BOARD_ITEM &aOther)
Definition board_item.h:104
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:267
virtual int BoardCopperLayerCount() const
Return the total number of copper layers for the board that this item resides on.
int GetMaxError() const
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition board.cpp:1325
BOX2I ExpandBoundingBoxForDrillSymbols(const BOX2I &aBoundingBox) const
Include every displaced copy of a hole-owned drill symbol in its view bounds.
Definition board.cpp:300
BOARD_DESIGN_SETTINGS & GetDesignSettings()
Definition board.cpp:1290
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 > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
static constexpr BOX2< VECTOR2I > ByCenter(const VECTOR2I &aCenter, const SizeVec &aSize)
Definition box2.h:72
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr const SizeVec & GetSize() const
Definition box2.h:203
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
MINOPTMAX< int > m_Value
Definition drc_rule.h:204
Design Rule Checker object that performs all the DRC tests.
Definition drc_engine.h:129
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
double Sin() const
Definition eda_angle.h:177
double AsDegrees() const
Definition eda_angle.h:115
bool IsZero() const
Definition eda_angle.h:135
EDA_ANGLE Normalize180()
Definition eda_angle.h:273
double Cos() const
Definition eda_angle.h:196
EDA_ANGLE Normalized() const
Definition eda_angle.h:241
The base class for create windows for drawing purpose.
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
bool IsSelected() const
Definition eda_item.h:134
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:609
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
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:376
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:177
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:144
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:333
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:283
bool IsAnyFill() const
Definition eda_shape.h:120
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:373
void SetPolyPoints(const std::vector< VECTOR2I > &aPoints)
void SetFillMode(FILL_T aFill)
VECTOR2I GetArcMid() const
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:798
static ENUM_MAP< T > & Instance()
Definition property.h:792
ENUM_MAP & Undefined(T aValue)
Definition property.h:805
wxPGChoices & Choices()
Definition property.h:843
EDA_ANGLE GetOrientation() const
Definition footprint.h:382
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:393
bool IsNetTie() const
Definition footprint.h:525
const wxString & GetReference() const
Definition footprint.h:793
DRAWINGS & GraphicalItems()
Definition footprint.h:358
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:94
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
bool IsHighlightEnabled() const
Return current highlight setting.
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition view_item.cpp:35
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:176
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:68
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:472
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition view.h:457
PAINTER * GetPainter() const
Return the painter object used by the view for drawing VIEW_ITEM objects.
Definition view.h:242
Definition kiid.h:46
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition lset.cpp:718
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
static const LSET & FrontBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on front side.
Definition lset.cpp:665
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition lset.cpp:725
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:309
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:693
static const LSET & BackBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on Back side.
Definition lset.cpp:651
T Opt() const
Definition minoptmax.h:31
bool HasOpt() const
Definition minoptmax.h:39
Handle the data for a net.
Definition netinfo.h:50
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:281
double Similarity(const PADSTACK &aOther) const
Return a measure of how likely the other object is to represent the same object.
int GetMaxHoleSize() const
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::...
PCB_LAYER_ID EffectiveLayerFor(PCB_LAYER_ID aLayer) const
Determines which geometry layer should be used for the given input layer.
static int Compare(const PADSTACK *aPadstackRef, const PADSTACK *aPadstackCmp)
Compare two padstacks and return 0 if they are equal.
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
void SetOrientation(const EDA_ANGLE &aAngle)
Definition padstack.h:356
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 TEMP_ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:176
std::vector< std::shared_ptr< PCB_SHAPE > > & Primitives(PCB_LAYER_ID aLayer)
Definition pad.h:61
VECTOR2I GetPrimaryDrillSize() const
Definition pad.cpp:784
void SetFrontPostMachiningSize(int aSize)
Definition pad.h:454
int GetBackPostMachiningSize() const
Definition pad.h:475
void SetAnchorPadShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition pad.h:249
bool IsAperturePad() const
Definition pad.h:567
void SetAttribute(PAD_ATTRIB aAttribute)
Definition pad.cpp:1689
int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const override
Return the pad's "own" clearance in internal units.
Definition pad.cpp:2060
PAD(FOOTPRINT *parent)
Definition pad.cpp:75
virtual void swapData(BOARD_ITEM *aImage) override
Definition pad.cpp:3095
PAD_PROP GetProperty() const
Definition pad.h:563
void SetFrontPostMachiningAngle(int aAngle)
Definition pad.h:458
void OnFootprintTransformed() override
Hook for items inside a footprint to refresh after the FP transform changes (translate,...
Definition pad.cpp:2615
void SetPrimaryDrillFilledFlag(bool aFilled)
Definition pad.cpp:1054
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition pad.cpp:401
double GetFrontRoundRectRadiusRatio() const
Definition pad.h:818
static wxString ShowPadShape(PAD_SHAPE aShape)
Definition pad.cpp:2627
std::optional< int > GetClearanceOverrides(wxString *aSource) const override
Return any clearance overrides set in the "classic" (ie: pre-rule) system.
Definition pad.cpp:2025
void SetPinType(const wxString &aType)
Set the pad electrical type.
Definition pad.h:159
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:557
const ZONE_LAYER_OVERRIDE & GetZoneLayerOverride(PCB_LAYER_ID aLayer) const
Definition pad.cpp:516
void MergePrimitivesAsPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
Definition pad.cpp:3571
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1181
void rebakePrimitiveToFootprint(PCB_SHAPE *aPrimitive) const
Definition pad.cpp:2586
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition pad.cpp:686
void SetLocalThermalGapOverride(const std::optional< int > &aOverride)
Definition pad.h:781
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1361
double GetCoverageArea(int aTextMargin) const override
Return the board area this item covers, used to rank candidates under the cursor so a click on a smal...
Definition pad.cpp:3120
void SetPrimaryDrillSize(const VECTOR2I &aSize)
Definition pad.cpp:772
std::mutex m_maskShapeMutex
Definition pad.h:1125
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.
Definition pad.cpp:2273
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition pad.cpp:1673
void SetTertiaryDrillStartLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:1167
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition pad.h:924
void AddPrimitivePoly(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPoly, int aThickness, bool aFilled)
Has meaning only for custom shape pads.
Definition pad.cpp:3465
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition pad.h:600
void SetFrontPostMachiningDepth(int aDepth)
Definition pad.h:456
void SetFrontShape(PAD_SHAPE aShape)
Definition pad.cpp:1743
void SetTopBackdrillLayer(PCB_LAYER_ID aLayer)
Definition pad.h:1072
const wxString & GetPinType() const
Definition pad.h:160
void SetZoneLayerOverride(PCB_LAYER_ID aLayer, ZONE_LAYER_OVERRIDE aOverride)
Definition pad.cpp:526
void SetSecondaryDrillSize(const VECTOR2I &aSize)
Definition pad.cpp:1075
void SetPrimaryDrillFilled(const std::optional< bool > &aFilled)
Definition pad.cpp:1047
PAD_ATTRIB GetAttribute() const
Definition pad.h:560
static LSET PTHMask()
layer set for a through hole pad
Definition pad.cpp:615
int GetDrillSizeYProp() const
Definition pad.h:324
static int Compare(const PAD *aPadRef, const PAD *aPadCmp)
Compare two pads and return 0 if they are equal.
Definition pad.cpp:2551
const wxString & GetPinFunction() const
Definition pad.h:154
bool CanHaveNumber() const
Indicates whether or not the pad can have a number.
Definition pad.cpp:533
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition pad.h:753
wxString m_pinType
Definition pad.h:1112
std::optional< int > GetBottomBackdrillSize() const
Definition pad.h:1062
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition pad.cpp:448
const wxString & GetNumber() const
Definition pad.h:143
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition pad.cpp:2879
void SetSecondaryDrillSizeX(int aX)
Definition pad.cpp:1082
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool aIgnoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition pad.cpp:3136
void SetFrontRoundRectRadiusRatio(double aRadiusScale)
Definition pad.cpp:1201
void SetPrimaryDrillSizeX(int aX)
Definition pad.cpp:794
PAD_DRAW_CACHE_DATA & getDrawCache() const
Definition pad.cpp:1392
std::mutex m_dataMutex
Definition pad.h:1120
void BuildEffectiveShapes() const
Rebuild the effective shape cache (and bounding box and radius) for the pad and clears the dirty bit.
Definition pad.cpp:1401
void SetPrimaryDrillEndLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:865
void SetSimElectricalType(PAD_SIM_ELECTRICAL_TYPE aType)
Definition pad.h:572
PAD_SHAPE GetFrontShape() const
Definition pad.h:210
void SetFrontPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pad.h:444
void CopyFrom(const BOARD_ITEM *aOther) override
Definition pad.cpp:366
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition pad.h:604
PAD & operator=(const PAD &aOther)
Definition pad.cpp:347
void SetLocalThermalSpokeWidthOverride(std::optional< int > aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition pad.h:737
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:196
void SetSecondaryDrillStartLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:1114
bool IsLocked() const override
Definition pad.cpp:577
wxString ShowLegacyPadShape(PCB_LAYER_ID aLayer) const
An older version still used by place file writer.
Definition pad.cpp:2649
void SetSizeXProp(int aX)
Definition pad.cpp:307
void OnFootprintRescaled(double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I &aAnchor, const EDA_ANGLE &aParentRotate) override
Apply a parent footprint scale to this item.
Definition pad.cpp:2597
VECTOR2I GetPosition() const override
Definition pad.cpp:255
void SetProperty(PAD_PROP aProperty)
Definition pad.cpp:1762
void SetThermalSpokeAngleDegrees(double aAngle)
Definition pad.h:763
void SetPrimaryDrillSizeY(int aY)
Definition pad.cpp:812
EDA_ANGLE GetThermalSpokeAngle() const
Definition pad.h:757
std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > m_zoneLayerOverrides
Definition pad.h:1146
PAD_ATTRIB m_attribute
Definition pad.h:1133
void Flip(const VECTOR2I &VECTOR2I, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition pad.cpp:1813
int GetDrillSizeXProp() const
Definition pad.h:322
void SetBackPostMachiningSize(int aSize)
Definition pad.h:474
std::vector< PCB_SHAPE * > Recombine(bool aIsDryRun, int aMaxError)
Recombines the pad with other graphical shapes in the footprint.
Definition pad.cpp:3242
PCB_LAYER_ID GetPrincipalLayer() const
Definition pad.cpp:664
void ClearTertiaryDrillSize()
Definition pad.cpp:1153
void SetDirty()
Definition pad.h:549
PAD_DRILL_SHAPE GetTertiaryDrillShape() const
Definition pad.h:537
int GetSizeXProp() const
Definition pad.cpp:321
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition pad.cpp:636
void SetBottomBackdrillLayer(PCB_LAYER_ID aLayer)
Definition pad.h:1066
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pad.cpp:2768
void SetTertiaryDrillShape(PAD_DRILL_SHAPE aShape)
Definition pad.cpp:1160
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.cpp:837
double GetOrientationDegrees() const
Definition pad.h:428
void SetBackdrillMode(BACKDRILL_MODE aMode)
Definition pad.h:1060
VECTOR2I GetDrillSize() const
Definition pad.h:320
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition pad.cpp:2562
int GetBackPostMachiningAngle() const
Definition pad.h:479
PADSTACK m_padStack
Definition pad.h:1117
void SetPadToDieDelay(int aDelay)
Definition pad.h:580
void FlipPrimitives(FLIP_DIRECTION aFlipDirection)
Flip (mirror) the primitives left to right or top to bottom, around the anchor position in custom pad...
Definition pad.cpp:1888
VECTOR2I m_libPos
Definition pad.h:1114
bool IsNoConnectPad() const
Definition pad.cpp:603
PAD_PROP m_property
Definition pad.h:1135
int GetFrontPostMachiningSize() const
Definition pad.h:455
void SetTertiaryDrillSizeX(int aX)
Definition pad.cpp:1135
void DeletePrimitivesList(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Clear the basic shapes list.
Definition pad.cpp:3552
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition pad.h:894
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition pad.h:142
BACKDRILL_MODE GetBackdrillMode() const
Definition pad.h:1059
void SetTertiaryDrillSize(const VECTOR2I &aSize)
Definition pad.cpp:1128
void SetFrontRoundRectRadiusSize(int aRadius)
Definition pad.cpp:1211
wxString ShowPadAttr() const
Definition pad.cpp:2665
wxString m_pinFunction
Definition pad.h:1111
void SetSecondaryDrillEndLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:1121
void AddPrimitive(PCB_LAYER_ID aLayer, PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
Definition pad.cpp:3527
int GetFrontPostMachiningDepth() const
Definition pad.h:457
void SetDrillShape(PAD_DRILL_SHAPE aShape)
Definition pad.h:433
int m_effectiveBoundingRadius
Definition pad.h:1128
void SetDrillSizeXProp(int aX)
Definition pad.cpp:806
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pad.h:587
void SetBackPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pad.h:464
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition pad.cpp:826
void SetCustomShapeInZoneOpt(CUSTOM_SHAPE_ZONE_MODE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones.
Definition pad.h:237
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition pad.h:610
void SetChamferRectRatio(PCB_LAYER_ID aLayer, double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition pad.cpp:1231
void SetPrimaryDrillCappedFlag(bool aCapped)
Definition pad.cpp:1068
int GetSolderMaskExpansion(PCB_LAYER_ID aLayer) const
Definition pad.cpp:2067
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:297
int GetPadToDieDelay() const
Definition pad.h:581
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition pad.h:583
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition pad.cpp:3022
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
Definition pad.cpp:3441
std::unique_ptr< PAD_DRAW_CACHE_DATA > m_drawCache
Definition pad.h:1122
bool IsOnCopperLayer() const override
Definition pad.cpp:1969
void SetTertiaryDrillEndLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:1174
void SetPadstack(const PADSTACK &aPadstack)
Definition pad.h:333
void SetPosition(const VECTOR2I &aPos) override
Definition pad.cpp:244
const SHAPE_COMPOUND & buildEffectiveShape(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1462
void SetPrimaryDrillShape(PAD_DRILL_SHAPE aShape)
Definition pad.cpp:846
const PADSTACK & Padstack() const
Definition pad.h:331
PAD_DRILL_SHAPE GetSecondaryDrillShape() const
Definition pad.h:520
void BuildEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1617
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition pad.cpp:629
PAD_DRILL_POST_MACHINING_MODE GetBackPostMachiningMode() const
Definition pad.h:469
bool IsFreePad() const
Definition pad.cpp:609
int GetFrontPostMachiningAngle() const
Definition pad.h:459
void SetLibOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition pad.cpp:290
PAD_DRILL_POST_MACHINING_MODE GetFrontPostMachiningMode() const
Definition pad.h:449
bool IsNPTHWithNoCopper() const
Definition pad.cpp:547
void SetLibSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.cpp:276
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1795
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.cpp:264
int m_delayPadToDie
Definition pad.h:1138
PAD_DRILL_SHAPE GetDrillShape() const
Definition pad.h:434
void SetSecondaryDrillShape(PAD_DRILL_SHAPE aShape)
Definition pad.cpp:1107
void ReplacePrimitives(PCB_LAYER_ID aLayer, const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Clear the current custom shape primitives list and import a new list.
Definition pad.cpp:3504
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:852
static LSET ApertureMask()
layer set for an aperture pad
Definition pad.cpp:643
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition pad.cpp:2982
UNCONNECTED_LAYER_MODE GetUnconnectedLayerMode() const
Definition pad.h:899
bool m_shapesDirty
Definition pad.h:1144
void SetRoundRectCornerRadius(PCB_LAYER_ID aLayer, double aRadius)
Definition pad.cpp:1187
void SetDrillSizeYProp(int aY)
Definition pad.cpp:820
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition pad.cpp:622
std::optional< int > GetLocalSolderPasteMargin() const
Definition pad.h:593
int GetFrontRoundRectRadiusSize() const
Definition pad.cpp:1221
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1239
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.
Definition pad.cpp:1252
int GetBackPostMachiningDepth() const
Definition pad.h:477
PAD_SIM_ELECTRICAL_TYPE GetSimElectricalType() const
Definition pad.h:573
std::optional< int > GetLocalSolderMaskMargin() const
Definition pad.h:586
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition pad.h:594
std::optional< int > GetLocalThermalGapOverride() const
Definition pad.h:777
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pad.cpp:658
void GetPrimitiveLibScale(double &aScaleX, double &aScaleY) const
Definition pad.cpp:2572
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition pad.cpp:2678
void SetPinFunction(const wxString &aName)
Set the pad function (pin name in schematic)
Definition pad.h:153
EDA_ANGLE GetFPRelativeOrientation() const
Definition pad.cpp:1807
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:834
bool m_polyDirty[2]
Definition pad.h:1143
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition pad.cpp:2444
void SetFPRelativeOrientation(const EDA_ANGLE &aAngle)
Definition pad.cpp:1782
int GetPostMachiningKnockout(PCB_LAYER_ID aLayer) const
Get the knockout diameter for a layer affected by post-machining.
Definition pad.cpp:955
int GetBoundingRadius() const
Return the radius of a minimum sized circle which fully encloses this pad.
Definition pad.cpp:1383
std::optional< int > GetTopBackdrillSize() const
Definition pad.h:1068
void ClearZoneLayerOverrides()
Definition pad.cpp:507
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition pad.cpp:1770
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:741
PAD_DRILL_SHAPE GetPrimaryDrillShape() const
Definition pad.h:431
bool IsBackdrilledOrPostMachined(PCB_LAYER_ID aLayer) const
Check if a layer is affected by backdrilling or post-machining operations.
Definition pad.cpp:872
void SetSizeYProp(int aY)
Definition pad.cpp:327
VECTOR2I GetSolderPasteMargin(PCB_LAYER_ID aLayer) const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition pad.cpp:2129
void SetTopBackdrillSize(std::optional< int > aSize)
Definition pad.h:1069
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition pad.cpp:2762
void AppendPrimitives(PCB_LAYER_ID aLayer, const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Import a custom shape primitive list (composed of basic shapes) and add items to the current list.
Definition pad.cpp:3517
static void SwapShapePositions(PAD *aLhs, PAD *aRhs)
Swap the visible shape positions of two pads, preserving each pad's own shape offset.
Definition pad.cpp:1920
wxString m_number
Definition pad.h:1110
std::map< PCB_LAYER_ID, std::pair< int, std::shared_ptr< SHAPE_COMPOUND > > > m_maskShapes
Definition pad.h:1126
void SetPrimaryDrillStartLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:858
void SetBackPostMachiningDepth(int aDepth)
Definition pad.h:476
void SetPrimaryDrillCapped(const std::optional< bool > &aCapped)
Definition pad.cpp:1061
void SetLibDrillSize(const VECTOR2I &aSize)
Definition pad.cpp:283
PCB_LAYER_ID GetBottomBackdrillLayer() const
Definition pad.h:1065
void SetLocalClearance(std::optional< int > aClearance)
Definition pad.h:584
int GetSubRatsnest() const
Definition pad.h:860
ZONE_CONNECTION GetLocalZoneConnection() const
Definition pad.h:611
void SetTertiaryDrillSizeY(int aY)
Definition pad.cpp:1146
int m_lengthPadToDie
Definition pad.h:1137
bool HasHole() const override
Definition pad.h:113
int GetSizeYProp() const
Definition pad.cpp:341
double GetThermalSpokeAngleDegrees() const
Definition pad.h:767
CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition pad.h:227
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1906
void SetSecondaryDrillSizeY(int aY)
Definition pad.cpp:1093
PCB_LAYER_ID GetTopBackdrillLayer() const
Definition pad.h:1071
EDA_ORIENTATION m_libOrientation
Definition pad.h:1115
void SetOrientationDegrees(double aOrientation)
Definition pad.h:424
ZONE_CONNECTION GetZoneConnectionOverrides(wxString *aSource=nullptr) const
Definition pad.cpp:2235
int GetLocalThermalGapOverride(wxString *aSource) const
Definition pad.cpp:2264
void SetLayerSet(const LSET &aLayers) override
Definition pad.cpp:2037
bool SharesNetTieGroup(const PAD *aOther) const
Definition pad.cpp:586
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition pad.h:219
void SetBottomBackdrillSize(std::optional< int > aSize)
Definition pad.h:1063
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition pad.cpp:1193
void ClearSecondaryDrillSize()
Definition pad.cpp:1100
void SetSubRatsnest(int aSubRatsnest)
Definition pad.h:861
int GetLocalSpokeWidthOverride(wxString *aSource=nullptr) const
Definition pad.cpp:2255
std::shared_ptr< SHAPE_COMPOUND > getMaskShape(PCB_LAYER_ID aLayer, int aExpansion) const
Definition pad.cpp:1335
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
Definition pad.cpp:3103
void SetPadToDieLength(int aLength)
Definition pad.h:577
bool IsFlipped() const
Definition pad.cpp:650
bool operator==(const PAD &aOther) const
Definition pad.cpp:3426
int GetPadToDieLength() const
Definition pad.h:578
void SetBackPostMachiningAngle(int aAngle)
Definition pad.h:478
virtual std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
Definition pad.cpp:2784
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void OverrideLibPoly(const SHAPE_POLY_SET &aPoly)
Definition pcb_shape.h:288
void OverrideLibBezier(const VECTOR2I &aC1, const VECTOR2I &aC2)
Definition pcb_shape.h:282
void SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:212
void SetPolyShape(const SHAPE_POLY_SET &aShape) override
bool IsProxyItem() const override
Definition pcb_shape.h:155
void OverrideLibCoords(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aArcMid=VECTOR2I(0, 0))
Definition pcb_shape.h:271
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
void RebakeWithScale(double aScaleX, double aScaleY)
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void SetStroke(const STROKE_PARAMS &aStroke) override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:70
PROPERTY_BASE & SetChoicesFunc(std::function< wxPGChoices(INSPECTABLE *)> aFunc)
Definition property.h:289
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:275
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition property.h:305
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:380
PROPERTY_BASE & SetIsCopyable(bool aIsCopyable=true)
Definition property.h:371
PROPERTY_BASE & SetIsHiddenFromLibraryEditors(bool aIsHidden=true)
Definition property.h:351
Provide class metadata.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void OverrideAvailability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override availability functor for a base class property of a given derived class.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
static VALIDATOR_RESULT PositiveIntValidator(const wxAny &&aValue, EDA_ITEM *aItem)
static VALIDATOR_RESULT RangeIntValidator(const wxAny &&aValue, EDA_ITEM *aItem)
static SEG::ecoord Square(int a)
Definition seg.h:119
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void AddShape(SHAPE *aShape)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
bool HasHoles() const
Return true if the polygon set has any holes.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
void Move(const VECTOR2I &aVector) override
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const SHAPE_LINE_CHAIN Outline() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
bool Collide(const SHAPE *aShape, int aClearance, VECTOR2I *aMTV) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
An abstract shape on 2D plane.
Definition shape.h:124
bool NearestPoints(const SHAPE *aOther, VECTOR2I &aPtThis, VECTOR2I &aPtOther) const
Return the two points that mark the closest distance between this shape and aOther.
Simple container to manage line stroke parameters.
double GetScaleX() const
double GetScaleY() const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
A type-safe container of any type.
Definition ki_any.h:92
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 TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
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.
void TransformTrapezoidToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aDeltaX, int aDeltaY, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle or trapezoid to a polygon.
@ ROUND_ALL_CORNERS
All angles are rounded.
@ ALLOW_ACUTE_CORNERS
just inflate the polygon. Acute angles create spikes
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition cvpcb.cpp:165
const int minSize
Push and Shove router track width and via size dialog.
@ ANNULAR_WIDTH_CONSTRAINT
@ SILK_CLEARANCE_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
@ SOLDER_MASK_EXPANSION_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
@ HOLE_TO_HOLE_CONSTRAINT
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
#define FOOTPRINT_EDIT_FRAME_NAME
#define PCB_EDIT_FRAME_NAME
@ FILLED_SHAPE
Fill with object color.
Definition eda_fill.h:31
#define IGNORE_PARENT_GROUP
Definition eda_item.h:55
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define ENTERED
indicates a group has been entered
#define SKIP_STRUCT
flag indicating that the structure should be ignored
static PCB_SHAPE * findNext(PCB_SHAPE *aShape, const VECTOR2I &aPoint, const KDTree &kdTree, const PCB_SHAPE_ENDPOINTS_ADAPTOR &adaptor, double aChainingEpsilon)
Searches for a PCB_SHAPE matching a given end point or start point in a list.
a few functions useful in geometry calculations.
Some functions to handle hotkeys in KiCad.
std::string source
bool IsSolderMaskLayer(int aLayer)
Definition layer_ids.h:812
@ LAYER_PAD_FR_NETNAMES
Additional netnames layers (not associated with a PCB layer).
Definition layer_ids.h:196
@ LAYER_PAD_BK_NETNAMES
Definition layer_ids.h:197
@ LAYER_PAD_NETNAMES
Definition layer_ids.h:198
bool IsDrillSymbolLayer(int aLayer)
Definition layer_ids.h:963
bool IsPadCopperLayer(int aLayer)
Definition layer_ids.h:945
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:844
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:180
@ NEVER_FLASHED
Never flashed for connectivity.
Definition layer_ids.h:183
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:182
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:867
bool IsClearanceLayer(int aLayer)
Definition layer_ids.h:957
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:741
@ LAYER_DRILL_SYMBOL_START
Drill symbols, one channel per board layer.
Definition layer_ids.h:382
@ LAYER_LOCKED_ITEM_SHADOW
Shadow layer for locked items.
Definition layer_ids.h:303
@ LAYER_PAD_COPPER_START
Virtual layers for pad copper on a given copper layer.
Definition layer_ids.h:355
@ LAYER_FOOTPRINTS_FR
Show footprints on front.
Definition layer_ids.h:255
@ LAYER_NON_PLATEDHOLES
Draw usual through hole vias.
Definition layer_ids.h:235
@ LAYER_PADS
Meta control for all pads opacity/visibility (color ignored).
Definition layer_ids.h:288
@ LAYER_PAD_PLATEDHOLES
to draw pad holes (plated)
Definition layer_ids.h:267
@ LAYER_CLEARANCE_START
Virtual layers for pad/via/track clearance outlines for a given copper layer.
Definition layer_ids.h:363
@ LAYER_FOOTPRINTS_BK
Show footprints on back.
Definition layer_ids.h:256
@ LAYER_PAD_HOLEWALLS
Definition layer_ids.h:293
#define DRILL_SYMBOL_LAYER_FOR(boardLayer)
Definition layer_ids.h:397
bool IsNetnameLayer(int aLayer)
Test whether a layer is a netname layer.
Definition layer_ids.h:933
bool IsHoleLayer(int aLayer)
Definition layer_ids.h:803
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:752
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Adhes
Definition layer_ids.h:99
@ Edge_Cuts
Definition layer_ids.h:108
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_SilkS
Definition layer_ids.h:96
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ Eco2_User
Definition layer_ids.h:106
@ B_SilkS
Definition layer_ids.h:97
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ F_Cu
Definition layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
This file contains miscellaneous commonly used macros and functions.
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
Message panel definition file.
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition eda_units.h:172
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
bool PadHasMeaningfulRoundingRadius(const PAD &aPad, PCB_LAYER_ID aLayer)
Returns true if the pad's rounding ratio is valid (i.e.
Definition pad_utils.cpp:49
void RemoveAllDrillsFromPadstack(PADSTACK &aPadstack)
Remove the primary drill, the secondary and tertiary drills, and any post-machining operations from a...
Definition pad_utils.cpp:56
double GetDefaultIpcRoundingRatio(const PAD &aPad, PCB_LAYER_ID aLayer)
Get a sensible default for a rounded rectangle pad's rounding ratio.
Definition pad_utils.cpp:35
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 VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void UnpackCustomProperties(const google::protobuf::RepeatedPtrField< types::CustomProperty > &aInput, EDA_ITEM &aItem)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
std::optional< std::pair< ELECTRICAL_PINTYPE, bool > > parsePinType(const wxString &aPinTypeString)
Definition pad.cpp:374
static struct PAD_DESC _PAD_DESC
PAD_SIM_ELECTRICAL_TYPE
The electrical type of a pad.
Definition pad.h:53
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition padstack.h:68
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition padstack.h:96
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
BACKDRILL_MODE
Definition padstack.h:83
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition padstack.h:51
@ CHAMFERED_RECT
Definition padstack.h:59
@ ROUNDRECT
Definition padstack.h:56
@ TRAPEZOID
Definition padstack.h:55
@ RECTANGLE
Definition padstack.h:53
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition padstack.h:113
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
Definition padstack.h:117
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
Definition padstack.h:116
@ MECHANICAL
a pad used for mechanical support
Definition padstack.h:121
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:122
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
Definition padstack.h:119
@ NONE
no special fabrication property
Definition padstack.h:114
@ TESTPOINT
a test point pad
Definition padstack.h:118
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:120
@ BGA
Smd pad, used in BGA footprints.
Definition padstack.h:115
UNCONNECTED_LAYER_MODE
Definition padstack.h:127
#define _HKI(x)
Definition page_info.cpp:40
Class to handle a set of BOARD_ITEMs.
PCBNEW_SETTINGS * pcbconfig()
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition pin_type.h:32
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:33
@ PT_NC
not connected (must be left open)
Definition pin_type.h:46
@ PT_OUTPUT
usual output
Definition pin_type.h:34
@ PT_TRISTATE
tri state bus pin
Definition pin_type.h:36
@ PT_NIC
not internally connected (may be connected to anything)
Definition pin_type.h:40
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:35
@ PT_OPENEMITTER
pin type open emitter
Definition pin_type.h:45
@ PT_POWER_OUT
output of a regulator: intended to be connected to power input pins
Definition pin_type.h:43
@ PT_OPENCOLLECTOR
pin type open collector
Definition pin_type.h:44
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:41
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:39
wxString GetCanonicalElectricalTypeName(ELECTRICAL_PINTYPE aType)
Definition pin_type.h:54
#define ELECTRICAL_PINTYPES_TOTAL
Definition pin_type.h:52
#define TYPE_HASH(x)
Macro to generate unique identifier for a type.
Definition property.h:74
#define ENUM_TO_WXANY(type)
Definition property.h:899
@ PT_DEGREE
Angle expressed in degrees.
Definition property.h:66
@ PT_RATIO
Definition property.h:68
@ PT_DECIDEGREE
Angle expressed in decidegrees.
Definition property.h:67
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
@ PT_TIME
Time expressed in ps.
Definition property.h:69
#define REGISTER_TYPE(x)
Helper macro to map type hashes to names.
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
LAYER_POLYGON_MAP m_effectivePolygons
Definition pad.h:1101
LAYER_SHAPE_MAP m_effectiveShapes
Definition pad.h:1099
std::shared_ptr< SHAPE_SEGMENT > m_effectiveHoleShape
Definition pad.h:1100
BOX2I m_effectiveBoundingBox
Definition pad.h:1098
PAD_DESC()
Definition pad.cpp:3616
int radius
int clearance
int delta
#define M_PI
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:709
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition zones.h:43
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46
@ THT_THERMAL
Thermal relief only for THT pads.
Definition zones.h:48
@ NONE
Pads are not covered.
Definition zones.h:45
@ FULL
pads are covered by copper
Definition zones.h:47
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition zones.h:31