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 (C) 1992-2024 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, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <base_units.h>
27#include <bitmaps.h>
28#include <core/mirror.h>
29#include <math/util.h> // for KiROUND
30#include <eda_draw_frame.h>
34#include <geometry/shape_rect.h>
36#include <geometry/shape_null.h>
37#include <string_utils.h>
38#include <i18n_utility.h>
39#include <view/view.h>
40#include <board.h>
43#include <footprint.h>
44#include <pad.h>
45#include <pcb_shape.h>
47#include <eda_units.h>
49#include <widgets/msgpanel.h>
50#include <pcb_painter.h>
52#include <wx/log.h>
53#include <api/api_enums.h>
54#include <api/api_utils.h>
55#include <api/api_pcb_utils.h>
56#include <api/board/board_types.pb.h>
57
58#include <memory>
59#include <macros.h>
60#include <magic_enum.hpp>
61#include "kiface_base.h"
62#include "pcbnew_settings.h"
63
66
67
68PAD::PAD( FOOTPRINT* parent ) :
70{
71 m_size.x = m_size.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 60 ); // Default pad size 60 mils.
72 m_drill.x = m_drill.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 30 ); // Default drill size 30 mils.
75
78
79 SetShape( PAD_SHAPE::CIRCLE ); // Default pad shape is PAD_CIRCLE.
80 SetAnchorPadShape( PAD_SHAPE::CIRCLE ); // Default shape for custom shaped pads
81 // is PAD_CIRCLE.
82 SetDrillShape( PAD_DRILL_SHAPE_CIRCLE ); // Default pad drill shape is a circle.
83 m_attribute = PAD_ATTRIB::PTH; // Default pad type is plated through hole
84 SetProperty( PAD_PROP::NONE ); // no special fabrication property
85
86 // Parameters for round rect only:
87 m_roundedCornerScale = 0.25; // from IPC-7351C standard
88
89 // Parameters for chamfered rect only:
90 m_chamferScale = 0.2; // Size of chamfer: ratio of smallest of X,Y size
91 m_chamferPositions = RECT_NO_CHAMFER; // No chamfered corner
92
93 m_zoneConnection = ZONE_CONNECTION::INHERITED; // Use parent setting by default
94 m_thermalSpokeWidth = 0; // Use parent setting by default
95 m_thermalSpokeAngle = ANGLE_45; // Default for circular pads
96 m_thermalGap = 0; // Use parent setting by default
97
99
100 // Set layers mask to default for a standard thru hole pad.
102
103 SetSubRatsnest( 0 ); // used in ratsnest calculations
104
105 SetDirty();
109
111}
112
113
114PAD::PAD( const PAD& aOther ) :
115 BOARD_CONNECTED_ITEM( aOther.GetParent(), PCB_PAD_T )
116{
117 PAD::operator=( aOther );
118
119 const_cast<KIID&>( m_Uuid ) = aOther.m_Uuid;
120}
121
122
123PAD& PAD::operator=( const PAD &aOther )
124{
126
127 ImportSettingsFrom( aOther );
129 SetPosition( aOther.GetPosition() );
130 SetNumber( aOther.GetNumber() );
131 SetPinType( aOther.GetPinType() );
132 SetPinFunction( aOther.GetPinFunction() );
133 SetSubRatsnest( aOther.GetSubRatsnest() );
137
138 return *this;
139}
140
141
142void PAD::Serialize( google::protobuf::Any &aContainer ) const
143{
144 kiapi::board::types::Pad pad;
145
146 pad.mutable_id()->set_value( m_Uuid.AsStdString() );
147 kiapi::common::PackVector2( *pad.mutable_position(), GetPosition() );
148 pad.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
149 : kiapi::common::types::LockedState::LS_UNLOCKED );
150 pad.mutable_net()->mutable_code()->set_value( GetNetCode() );
151 pad.mutable_net()->set_name( GetNetname() );
152
153 kiapi::board::types::PadStack* padstack = pad.mutable_pad_stack();
154 padstack->set_type( kiapi::board::types::PadStackType::PST_THROUGH );
155 padstack->set_start_layer(
156 ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( m_layer ) );
157 padstack->set_end_layer(
158 ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( FlipLayer( m_layer ) ) );
159 kiapi::common::PackVector2( *padstack->mutable_drill_diameter(),
160 { GetDrillSizeX(), GetDrillSizeY() } );
161 padstack->mutable_angle()->set_value_degrees( GetOrientationDegrees() );
162
163 kiapi::board::types::PadStackLayer* stackLayer = padstack->add_layers();
164 kiapi::board::PackLayerSet( *stackLayer->mutable_layers(), GetLayerSet() );
165 kiapi::common::PackVector2( *stackLayer->mutable_size(),
166 { GetSizeX(), GetSizeY() } );
167 stackLayer->set_shape(
168 ToProtoEnum<PAD_SHAPE, kiapi::board::types::PadStackShape>( GetShape() ) );
169
170 kiapi::board::types::UnconnectedLayerRemoval ulr;
171
173 {
175 ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END;
176 else
177 ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE;
178 }
179 else
180 {
181 ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP;
182 }
183
184 padstack->set_unconnected_layer_removal( ulr );
185
186 kiapi::board::types::DesignRuleOverrides* overrides = pad.mutable_overrides();
187
188 if( GetLocalClearance().has_value() )
189 overrides->mutable_clearance()->set_value_nm( *GetLocalClearance() );
190
191 if( GetLocalSolderMaskMargin().has_value() )
192 overrides->mutable_solder_mask_margin()->set_value_nm( *GetLocalSolderMaskMargin() );
193
194 if( GetLocalSolderPasteMargin().has_value() )
195 overrides->mutable_solder_paste_margin()->set_value_nm( *GetLocalSolderPasteMargin() );
196
197 if( GetLocalSolderPasteMarginRatio().has_value() )
198 overrides->mutable_solder_paste_margin_ratio()->set_value( *GetLocalSolderPasteMarginRatio() );
199
200 overrides->set_zone_connection(
202 kiapi::board::types::ZoneConnectionStyle>( GetLocalZoneConnection() ) );
203
204 kiapi::board::types::ThermalSpokeSettings* thermals = pad.mutable_thermal_spokes();
205
206 thermals->set_width( GetThermalSpokeWidth() );
207 thermals->set_gap( GetThermalGap() );
208 thermals->mutable_angle()->set_value_degrees( GetThermalSpokeAngleDegrees() );
209
210 aContainer.PackFrom( pad );
211}
212
213
214bool PAD::Deserialize( const google::protobuf::Any &aContainer )
215{
216 kiapi::board::types::Pad pad;
217
218 if( !aContainer.UnpackTo( &pad ) )
219 return false;
220
221 const_cast<KIID&>( m_Uuid ) = KIID( pad.id().value() );
223 SetNetCode( pad.net().code().value() );
224 SetLocked( pad.locked() == kiapi::common::types::LockedState::LS_LOCKED );
225
226 const kiapi::board::types::PadStack& padstack = pad.pad_stack();
227
228 SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
229 padstack.start_layer() ) );
230
231 SetDrillSize( kiapi::common::UnpackVector2( padstack.drill_diameter() ) );
232 SetOrientationDegrees( padstack.angle().value_degrees() );
233
234 // We don't yet support complex padstacks
235 if( padstack.layers_size() == 1 )
236 {
237 const kiapi::board::types::PadStackLayer& layer = padstack.layers( 0 );
238 SetSize( kiapi::common::UnpackVector2( layer.size() ) );
239 SetLayerSet( kiapi::board::UnpackLayerSet( layer.layers() ) );
240 SetShape( FromProtoEnum<PAD_SHAPE>( layer.shape() ) );
241 }
242
243 switch( padstack.unconnected_layer_removal() )
244 {
245 case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE:
247 m_keepTopBottomLayer = false;
248 break;
249
250 case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END:
253 break;
254
255 default:
256 case kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP:
258 m_keepTopBottomLayer = false;
259 break;
260 }
261
262 const kiapi::board::types::DesignRuleOverrides& overrides = pad.overrides();
263
264 if( overrides.has_clearance() )
265 SetLocalClearance( overrides.clearance().value_nm() );
266 else
267 SetLocalClearance( std::nullopt );
268
269 if( overrides.has_solder_mask_margin() )
270 SetLocalSolderMaskMargin( overrides.solder_mask_margin().value_nm() );
271 else
272 SetLocalSolderMaskMargin( std::nullopt );
273
274 if( overrides.has_solder_paste_margin() )
275 SetLocalSolderPasteMargin( overrides.solder_paste_margin().value_nm() );
276 else
277 SetLocalSolderPasteMargin( std::nullopt );
278
279 if( overrides.has_solder_paste_margin_ratio() )
280 SetLocalSolderPasteMarginRatio( overrides.solder_paste_margin_ratio().value() );
281 else
282 SetLocalSolderPasteMarginRatio( std::nullopt );
283
284 SetLocalZoneConnection( FromProtoEnum<ZONE_CONNECTION>( overrides.zone_connection() ) );
285
286 const kiapi::board::types::ThermalSpokeSettings& thermals = pad.thermal_spokes();
287
288 SetThermalGap( thermals.gap() );
289 SetThermalSpokeWidth( thermals.width() );
290 SetThermalSpokeAngleDegrees( thermals.angle().value_degrees() );
291
292 return true;
293}
294
295
297{
298 // Aperture pads don't get a number
299 if( IsAperturePad() )
300 return false;
301
302 // NPTH pads don't get numbers
303 if( GetAttribute() == PAD_ATTRIB::NPTH )
304 return false;
305
306 return true;
307}
308
309
310bool PAD::IsLocked() const
311{
312 if( GetParent() && GetParent()->IsLocked() )
313 return true;
314
315 return BOARD_ITEM::IsLocked();
316};
317
318
319bool PAD::SharesNetTieGroup( const PAD* aOther ) const
320{
321 FOOTPRINT* parentFp = GetParentFootprint();
322
323 if( parentFp && parentFp->IsNetTie() && aOther->GetParentFootprint() == parentFp )
324 {
325 std::map<wxString, int> padToNetTieGroupMap = parentFp->MapPadNumbersToNetTieGroups();
326 int thisNetTieGroup = padToNetTieGroupMap[ GetNumber() ];
327 int otherNetTieGroup = padToNetTieGroupMap[ aOther->GetNumber() ];
328
329 return thisNetTieGroup >= 0 && thisNetTieGroup == otherNetTieGroup;
330 }
331
332 return false;
333}
334
335
337{
338 return m_pinType.Contains( wxT( "no_connect" ) );
339}
340
341
342bool PAD::IsFreePad() const
343{
344 return GetShortNetname().StartsWith( wxT( "unconnected-(" ) )
345 && m_pinType == wxT( "free" );
346}
347
348
350{
351 static LSET saved = LSET::AllCuMask() | LSET( 2, F_Mask, B_Mask );
352 return saved;
353}
354
355
357{
358 static LSET saved( 3, F_Cu, F_Paste, F_Mask );
359 return saved;
360}
361
362
364{
365 static LSET saved( 2, F_Cu, F_Mask );
366 return saved;
367}
368
369
371{
372 static LSET saved = LSET( 4, F_Cu, B_Cu, F_Mask, B_Mask );
373 return saved;
374}
375
376
378{
379 static LSET saved( 1, F_Paste );
380 return saved;
381}
382
383
384bool PAD::IsFlipped() const
385{
386 FOOTPRINT* parent = GetParentFootprint();
387
388 return ( parent && parent->GetLayer() == B_Cu );
389}
390
391
393{
394 return BOARD_ITEM::GetLayer();
395}
396
397
399{
400 if( m_attribute == PAD_ATTRIB::SMD || m_attribute == PAD_ATTRIB::CONN || GetLayerSet().none() )
401 return m_layer;
402 else
403 return GetLayerSet().Seq().front();
404
405}
406
407
408bool PAD::FlashLayer( LSET aLayers ) const
409{
410 for( PCB_LAYER_ID layer : aLayers.Seq() )
411 {
412 if( FlashLayer( layer ) )
413 return true;
414 }
415
416 return false;
417}
418
419
420bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
421{
422 if( aLayer == UNDEFINED_LAYER )
423 return true;
424
425 if( !IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) ) )
426 return false;
427
428 if( GetAttribute() == PAD_ATTRIB::NPTH && IsCopperLayer( aLayer ) )
429 {
430 if( GetShape() == PAD_SHAPE::CIRCLE && GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
431 {
432 if( GetOffset() == VECTOR2I( 0, 0 ) && GetDrillSize().x >= GetSize().x )
433 return false;
434 }
435 else if( GetShape() == PAD_SHAPE::OVAL && GetDrillShape() == PAD_DRILL_SHAPE_OBLONG )
436 {
437 if( GetOffset() == VECTOR2I( 0, 0 )
438 && GetDrillSize().x >= GetSize().x && GetDrillSize().y >= GetSize().y )
439 {
440 return false;
441 }
442 }
443 }
444
445 if( LSET::FrontBoardTechMask().test( aLayer ) )
446 aLayer = F_Cu;
447 else if( LSET::BackBoardTechMask().test( aLayer ) )
448 aLayer = B_Cu;
449
450 if( GetAttribute() == PAD_ATTRIB::PTH && IsCopperLayer( aLayer ) )
451 {
453 if( GetProperty() == PAD_PROP::HEATSINK )
454 return true;
455
457 return true;
458
459 // Plated through hole pads need copper on the top/bottom layers for proper soldering
460 // Unless the user has removed them in the pad dialog
461 if( m_keepTopBottomLayer && ( aLayer == F_Cu || aLayer == B_Cu ) )
462 return true;
463
464 if( const BOARD* board = GetBoard() )
465 {
466 // Must be static to keep from raising its ugly head in performance profiles
467 static std::initializer_list<KICAD_T> types = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
468 PCB_PAD_T };
469
470 if( m_zoneLayerOverrides[ aLayer ] == ZLO_FORCE_FLASHED )
471 return true;
472 else if( aOnlyCheckIfPermitted )
473 return true;
474 else
475 return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, types );
476 }
477 }
478
479 return true;
480}
481
482
484{
485 return KiROUND( std::min( m_size.x, m_size.y ) * m_roundedCornerScale );
486}
487
488
489void PAD::SetRoundRectCornerRadius( double aRadius )
490{
491 int min_r = std::min( m_size.x, m_size.y );
492
493 if( min_r > 0 )
494 SetRoundRectRadiusRatio( aRadius / min_r );
495}
496
497
498void PAD::SetRoundRectRadiusRatio( double aRadiusScale )
499{
500 m_roundedCornerScale = alg::clamp( 0.0, aRadiusScale, 0.5 );
501
502 SetDirty();
503}
504
505
506void PAD::SetChamferRectRatio( double aChamferScale )
507{
508 m_chamferScale = alg::clamp( 0.0, aChamferScale, 0.5 );
509
510 SetDirty();
511}
512
513
514const std::shared_ptr<SHAPE_POLY_SET>& PAD::GetEffectivePolygon( ERROR_LOC aErrorLoc ) const
515{
516 if( m_polyDirty[ aErrorLoc ] )
517 BuildEffectivePolygon( aErrorLoc );
518
519 return m_effectivePolygon[ aErrorLoc ];
520}
521
522
523std::shared_ptr<SHAPE> PAD::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING flashPTHPads ) const
524{
525 if( aLayer == Edge_Cuts )
526 {
527 if( GetAttribute() == PAD_ATTRIB::PTH || GetAttribute() == PAD_ATTRIB::NPTH )
528 return GetEffectiveHoleShape();
529 else
530 return std::make_shared<SHAPE_NULL>();
531 }
532
533 if( GetAttribute() == PAD_ATTRIB::PTH )
534 {
535 bool flash;
536
537 if( flashPTHPads == FLASHING::NEVER_FLASHED )
538 flash = false;
539 else if( flashPTHPads == FLASHING::ALWAYS_FLASHED )
540 flash = true;
541 else
542 flash = FlashLayer( aLayer );
543
544 if( !flash )
545 {
546 if( GetAttribute() == PAD_ATTRIB::PTH )
547 return GetEffectiveHoleShape();
548 else
549 return std::make_shared<SHAPE_NULL>();
550 }
551 }
552
553 if( m_shapesDirty )
554 BuildEffectiveShapes( aLayer );
555
556 return m_effectiveShape;
557}
558
559
560std::shared_ptr<SHAPE_SEGMENT> PAD::GetEffectiveHoleShape() const
561{
562 if( m_shapesDirty )
564
566}
567
568
570{
573
575}
576
577
579{
580 std::lock_guard<std::mutex> RAII_lock( m_shapesBuildingLock );
581
582 // If we had to wait for the lock then we were probably waiting for someone else to
583 // finish rebuilding the shapes. So check to see if they're clean now.
584 if( !m_shapesDirty )
585 return;
586
587 const BOARD* board = GetBoard();
588 int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
589
590 m_effectiveShape = std::make_shared<SHAPE_COMPOUND>();
591 m_effectiveHoleShape = nullptr;
592
593 auto add = [this]( SHAPE* aShape )
594 {
595 m_effectiveShape->AddShape( aShape );
596 };
597
598 VECTOR2I shapePos = ShapePos(); // Fetch only once; rotation involves trig
599 PAD_SHAPE effectiveShape = GetShape();
600
601 if( GetShape() == PAD_SHAPE::CUSTOM )
602 effectiveShape = GetAnchorPadShape();
603
604 switch( effectiveShape )
605 {
606 case PAD_SHAPE::CIRCLE:
607 add( new SHAPE_CIRCLE( shapePos, m_size.x / 2 ) );
608 break;
609
610 case PAD_SHAPE::OVAL:
611 if( m_size.x == m_size.y ) // the oval pad is in fact a circle
612 {
613 add( new SHAPE_CIRCLE( shapePos, m_size.x / 2 ) );
614 }
615 else
616 {
617 VECTOR2I half_size = m_size / 2;
618 int half_width = std::min( half_size.x, half_size.y );
619 VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
620 RotatePoint( half_len, m_orient );
621 add( new SHAPE_SEGMENT( shapePos - half_len, shapePos + half_len, half_width * 2 ) );
622 }
623
624 break;
625
626 case PAD_SHAPE::RECTANGLE:
627 case PAD_SHAPE::TRAPEZOID:
628 case PAD_SHAPE::ROUNDRECT:
629 {
630 int r = ( effectiveShape == PAD_SHAPE::ROUNDRECT ) ? GetRoundRectCornerRadius() : 0;
631 VECTOR2I half_size( m_size.x / 2, m_size.y / 2 );
632 VECTOR2I trap_delta( 0, 0 );
633
634 if( r )
635 {
636 half_size -= VECTOR2I( r, r );
637
638 // Avoid degenerated shapes (0 length segments) that always create issues
639 // For roundrect pad very near a circle, use only a circle
640 const int min_len = pcbIUScale.mmToIU( 0.0001);
641
642 if( half_size.x < min_len && half_size.y < min_len )
643 {
644 add( new SHAPE_CIRCLE( shapePos, r ) );
645 break;
646 }
647 }
648 else if( effectiveShape == PAD_SHAPE::TRAPEZOID )
649 {
650 trap_delta = m_deltaSize / 2;
651 }
652
653 SHAPE_LINE_CHAIN corners;
654
655 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
656 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
657 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
658 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
659
660 corners.Rotate( m_orient );
661 corners.Move( shapePos );
662
663 // GAL renders rectangles faster than 4-point polygons so it's worth checking if our
664 // body shape is a rectangle.
665 if( corners.PointCount() == 4
666 &&
667 ( ( corners.CPoint( 0 ).y == corners.CPoint( 1 ).y
668 && corners.CPoint( 1 ).x == corners.CPoint( 2 ).x
669 && corners.CPoint( 2 ).y == corners.CPoint( 3 ).y
670 && corners.CPoint( 3 ).x == corners.CPoint( 0 ).x )
671 ||
672 ( corners.CPoint( 0 ).x == corners.CPoint( 1 ).x
673 && corners.CPoint( 1 ).y == corners.CPoint( 2 ).y
674 && corners.CPoint( 2 ).x == corners.CPoint( 3 ).x
675 && corners.CPoint( 3 ).y == corners.CPoint( 0 ).y )
676 )
677 )
678 {
679 int width = std::abs( corners.CPoint( 2 ).x - corners.CPoint( 0 ).x );
680 int height = std::abs( corners.CPoint( 2 ).y - corners.CPoint( 0 ).y );
681 VECTOR2I pos( std::min( corners.CPoint( 2 ).x, corners.CPoint( 0 ).x ),
682 std::min( corners.CPoint( 2 ).y, corners.CPoint( 0 ).y ) );
683
684 add( new SHAPE_RECT( pos, width, height ) );
685 }
686 else
687 {
688 add( new SHAPE_SIMPLE( corners ) );
689 }
690
691 if( r )
692 {
693 add( new SHAPE_SEGMENT( corners.CPoint( 0 ), corners.CPoint( 1 ), r * 2 ) );
694 add( new SHAPE_SEGMENT( corners.CPoint( 1 ), corners.CPoint( 2 ), r * 2 ) );
695 add( new SHAPE_SEGMENT( corners.CPoint( 2 ), corners.CPoint( 3 ), r * 2 ) );
696 add( new SHAPE_SEGMENT( corners.CPoint( 3 ), corners.CPoint( 0 ), r * 2 ) );
697 }
698 }
699 break;
700
701 case PAD_SHAPE::CHAMFERED_RECT:
702 {
703 SHAPE_POLY_SET outline;
704
707 GetChamferPositions(), 0, maxError, ERROR_INSIDE );
708
709 add( new SHAPE_SIMPLE( outline.COutline( 0 ) ) );
710 }
711 break;
712
713 default:
714 wxFAIL_MSG( wxT( "PAD::buildEffectiveShapes: Unsupported pad shape: PAD_SHAPE::" )
715 + wxString( std::string( magic_enum::enum_name( effectiveShape ) ) ) );
716 break;
717 }
718
719 if( GetShape() == PAD_SHAPE::CUSTOM )
720 {
721 for( const std::shared_ptr<PCB_SHAPE>& primitive : m_editPrimitives )
722 {
723 if( !primitive->IsProxyItem() )
724 {
725 for( SHAPE* shape : primitive->MakeEffectiveShapes() )
726 {
727 shape->Rotate( m_orient );
728 shape->Move( shapePos );
729 add( shape );
730 }
731 }
732 }
733 }
734
736
737 // Hole shape
738 VECTOR2I half_size = m_drill / 2;
739 int half_width = std::min( half_size.x, half_size.y );
740 VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
741
742 RotatePoint( half_len, m_orient );
743
744 m_effectiveHoleShape = std::make_shared<SHAPE_SEGMENT>( m_pos - half_len, m_pos + half_len,
745 half_width * 2 );
747
748 // All done
749 m_shapesDirty = false;
750}
751
752
754{
755 std::lock_guard<std::mutex> RAII_lock( m_polyBuildingLock );
756
757 // If we had to wait for the lock then we were probably waiting for someone else to
758 // finish rebuilding the shapes. So check to see if they're clean now.
759 if( !m_polyDirty[ aErrorLoc ] )
760 return;
761
762 const BOARD* board = GetBoard();
763 int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
764
765 // Polygon
766 std::shared_ptr<SHAPE_POLY_SET>& effectivePolygon = m_effectivePolygon[ aErrorLoc ];
767
768 effectivePolygon = std::make_shared<SHAPE_POLY_SET>();
769 TransformShapeToPolygon( *effectivePolygon, UNDEFINED_LAYER, 0, maxError, aErrorLoc );
770
771 // Bounding radius
772 //
773 // PADSTACKS TODO: these will both need to cycle through all layers to get the largest
774 // values....
775 if( aErrorLoc == ERROR_OUTSIDE )
776 {
778
779 for( int cnt = 0; cnt < effectivePolygon->OutlineCount(); ++cnt )
780 {
781 const SHAPE_LINE_CHAIN& poly = effectivePolygon->COutline( cnt );
782
783 for( int ii = 0; ii < poly.PointCount(); ++ii )
784 {
785 int dist = KiROUND( ( poly.CPoint( ii ) - m_pos ).EuclideanNorm() );
787 }
788 }
789 }
790
791 // All done
792 m_polyDirty[ aErrorLoc ] = false;
793}
794
795
797{
798 if( m_shapesDirty )
800
802}
803
804
806{
807 if( m_attribute != aAttribute )
808 {
809 m_attribute = aAttribute;
810
811 switch( aAttribute )
812 {
813 case PAD_ATTRIB::PTH:
815 break;
816
817 case PAD_ATTRIB::SMD:
818 case PAD_ATTRIB::CONN:
819 if( m_layerMask.test( F_Cu ) )
820 {
821 m_layerMask &= ~LSET::AllCuMask();
822 m_layerMask.set( F_Cu );
823 }
824 else
825 {
826 m_layerMask &= ~LSET::AllCuMask();
827 m_layerMask.set( B_Cu );
828 }
829
830 m_drill = VECTOR2I( 0, 0 );
831 break;
832
833 case PAD_ATTRIB::NPTH:
834 m_number = wxEmptyString;
836 break;
837 }
838 }
839
840 SetDirty();
841}
842
843
844void PAD::SetProperty( PAD_PROP aProperty )
845{
846 m_property = aProperty;
847
848 SetDirty();
849}
850
851
852void PAD::SetOrientation( const EDA_ANGLE& aAngle )
853{
854 m_orient = aAngle;
856
857 SetDirty();
858}
859
860
862{
863 if( FOOTPRINT* parentFP = GetParentFootprint() )
864 SetOrientation( aAngle + parentFP->GetOrientation() );
865 else
866 SetOrientation( aAngle );
867}
868
869
871{
872 if( FOOTPRINT* parentFP = GetParentFootprint() )
873 return GetOrientation() - parentFP->GetOrientation();
874 else
875 return GetOrientation();
876}
877
878
879void PAD::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
880{
881 if( aFlipLeftRight )
882 {
883 MIRROR( m_pos.x, aCentre.x );
884 MIRROR( m_offset.x, 0 );
885 MIRROR( m_deltaSize.x, 0 );
886 }
887 else
888 {
889 MIRROR( m_pos.y, aCentre.y );
890 MIRROR( m_offset.y, 0 );
891 MIRROR( m_deltaSize.y, 0 );
892 }
893
895
896 auto mirrorBitFlags = []( int& aBitfield, int a, int b )
897 {
898 bool temp = aBitfield & a;
899
900 if( aBitfield & b )
901 aBitfield |= a;
902 else
903 aBitfield &= ~a;
904
905 if( temp )
906 aBitfield |= b;
907 else
908 aBitfield &= ~b;
909 };
910
911 if( aFlipLeftRight )
912 {
915 }
916 else
917 {
920 }
921
922 // flip pads layers
923 // PADS items are currently on all copper layers, or
924 // currently, only on Front or Back layers.
925 // So the copper layers count is not taken in account
927
928 // Flip the basic shapes, in custom pads
929 FlipPrimitives( aFlipLeftRight );
930
931 SetDirty();
932}
933
934
935void PAD::FlipPrimitives( bool aFlipLeftRight )
936{
937 for( std::shared_ptr<PCB_SHAPE>& primitive : m_editPrimitives )
938 primitive->Flip( VECTOR2I( 0, 0 ), aFlipLeftRight );
939
940 SetDirty();
941}
942
943
945{
946 if( m_offset.x == 0 && m_offset.y == 0 )
947 return m_pos;
948
949 VECTOR2I loc_offset = m_offset;
950
951 RotatePoint( loc_offset, m_orient );
952
953 VECTOR2I shape_pos = m_pos + loc_offset;
954
955 return shape_pos;
956}
957
958
960{
961 if( GetAttribute() == PAD_ATTRIB::NPTH )
962 {
963 // NPTH pads have no plated hole cylinder. If their annular ring size is 0 or
964 // negative, then they have no annular ring either.
965
966 switch( GetShape() )
967 {
968 case PAD_SHAPE::CIRCLE:
969 if( m_offset == VECTOR2I( 0, 0 ) && m_size.x <= m_drill.x )
970 return false;
971
972 break;
973
974 case PAD_SHAPE::OVAL:
975 if( m_offset == VECTOR2I( 0, 0 ) && m_size.x <= m_drill.x && m_size.y <= m_drill.y )
976 return false;
977
978 break;
979
980 default:
981 // We could subtract the hole polygon from the shape polygon for these, but it
982 // would be expensive and we're probably well out of the common use cases....
983 break;
984 }
985 }
986
987 return ( GetLayerSet() & LSET::AllCuMask() ).any();
988}
989
990
991std::optional<int> PAD::GetLocalClearance( wxString* aSource ) const
992{
993 if( m_clearance.has_value() && aSource )
994 *aSource = _( "pad" );
995
996 return m_clearance;
997}
998
999
1000std::optional<int> PAD::GetClearanceOverrides( wxString* aSource ) const
1001{
1002 if( m_clearance.has_value() )
1003 return GetLocalClearance( aSource );
1004
1005 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1006 return parentFootprint->GetClearanceOverrides( aSource );
1007
1008 return std::optional<int>();
1009}
1010
1011
1012int PAD::GetOwnClearance( PCB_LAYER_ID aLayer, wxString* aSource ) const
1013{
1015
1016 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
1017 {
1019
1020 if( GetAttribute() == PAD_ATTRIB::NPTH )
1021 c = bds.m_DRCEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, this, nullptr, aLayer );
1022 else
1023 c = bds.m_DRCEngine->EvalRules( CLEARANCE_CONSTRAINT, this, nullptr, aLayer );
1024 }
1025
1026 if( c.Value().HasMin() )
1027 {
1028 if( aSource )
1029 *aSource = c.GetName();
1030
1031 return c.Value().Min();
1032 }
1033
1034 return 0;
1035}
1036
1037
1039{
1040 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
1041 // defined by the pad settings only. ALL other pads, even those that don't actually have
1042 // any copper (such as NPTH pads with holes the same size as the pad) get mask expansion.
1043 if( ( m_layerMask & LSET::AllCuMask() ).none() )
1044 return 0;
1045
1046 std::optional<int> margin = m_solderMaskMargin;
1047
1048 if( !margin.has_value() )
1049 {
1050 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1051 margin = parentFootprint->GetLocalSolderMaskMargin();
1052 }
1053
1054 if( !margin.has_value() )
1055 {
1056 if( const BOARD* brd = GetBoard() )
1057 margin = brd->GetDesignSettings().m_SolderMaskExpansion;
1058 }
1059
1060 int marginValue = margin.value_or( 0 );
1061
1062 // ensure mask have a size always >= 0
1063 if( marginValue < 0 )
1064 {
1065 int minsize = -std::min( m_size.x, m_size.y ) / 2;
1066
1067 if( marginValue < minsize )
1068 marginValue = minsize;
1069 }
1070
1071 return marginValue;
1072}
1073
1074
1076{
1077 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
1078 // defined by the pad settings only. ALL other pads, even those that don't actually have
1079 // any copper (such as NPTH pads with holes the same size as the pad) get paste expansion.
1080 if( ( m_layerMask & LSET::AllCuMask() ).none() )
1081 return VECTOR2I( 0, 0 );
1082
1083 std::optional<int> margin = m_solderPasteMargin;
1084 std::optional<double> mratio = m_solderPasteMarginRatio;
1085
1086 if( !margin.has_value() )
1087 {
1088 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1089 margin = parentFootprint->GetLocalSolderPasteMargin();
1090 }
1091
1092 if( !margin.has_value() )
1093 {
1094 if( const BOARD* board = GetBoard() )
1095 margin = board->GetDesignSettings().m_SolderPasteMargin;
1096 }
1097
1098 if( !mratio.has_value() )
1099 {
1100 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1101 mratio = parentFootprint->GetLocalSolderPasteMarginRatio();
1102 }
1103
1104 if( !mratio.has_value() )
1105 {
1106 if( const BOARD* board = GetBoard() )
1107 mratio = board->GetDesignSettings().m_SolderPasteMarginRatio;
1108 }
1109
1110 VECTOR2I pad_margin;
1111 pad_margin.x = margin.value_or( 0 ) + KiROUND( m_size.x * mratio.value_or( 0 ) );
1112 pad_margin.y = margin.value_or( 0 ) + KiROUND( m_size.y * mratio.value_or( 0 ) );
1113
1114 // ensure mask have a size always >= 0
1115 if( m_padShape != PAD_SHAPE::CUSTOM )
1116 {
1117 if( pad_margin.x < -m_size.x / 2 )
1118 pad_margin.x = -m_size.x / 2;
1119
1120 if( pad_margin.y < -m_size.y / 2 )
1121 pad_margin.y = -m_size.y / 2;
1122 }
1123
1124 return pad_margin;
1125}
1126
1127
1129{
1130 ZONE_CONNECTION connection = m_zoneConnection;
1131
1132 if( connection != ZONE_CONNECTION::INHERITED )
1133 {
1134 if( aSource )
1135 *aSource = _( "pad" );
1136 }
1137
1138 if( connection == ZONE_CONNECTION::INHERITED )
1139 {
1140 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1141 connection = parentFootprint->GetZoneConnectionOverrides( aSource );
1142 }
1143
1144 return connection;
1145}
1146
1147
1148int PAD::GetLocalSpokeWidthOverride( wxString* aSource ) const
1149{
1150 if( m_thermalSpokeWidth > 0 && aSource )
1151 *aSource = _( "pad" );
1152
1153 return m_thermalSpokeWidth;
1154}
1155
1156
1157int PAD::GetLocalThermalGapOverride( wxString* aSource ) const
1158{
1159 if( m_thermalGap > 0 && aSource )
1160 *aSource = _( "pad" );
1161
1162 return m_thermalGap;
1163}
1164
1165
1166void PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1167{
1168 wxString msg;
1169 FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( m_parent );
1170
1171 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1172 {
1173 if( parentFootprint )
1174 aList.emplace_back( _( "Footprint" ), parentFootprint->GetReference() );
1175 }
1176
1177 aList.emplace_back( _( "Pad" ), m_number );
1178
1179 if( !GetPinFunction().IsEmpty() )
1180 aList.emplace_back( _( "Pin Name" ), GetPinFunction() );
1181
1182 if( !GetPinType().IsEmpty() )
1183 aList.emplace_back( _( "Pin Type" ), GetPinType() );
1184
1185 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1186 {
1187 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
1188
1189 aList.emplace_back( _( "Resolved Netclass" ),
1190 UnescapeString( GetEffectiveNetClass()->GetName() ) );
1191
1192 if( IsLocked() )
1193 aList.emplace_back( _( "Status" ), _( "Locked" ) );
1194 }
1195
1196 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1197 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
1198
1199 if( aFrame->GetName() == FOOTPRINT_EDIT_FRAME_NAME )
1200 {
1201 if( GetAttribute() == PAD_ATTRIB::SMD )
1202 {
1203 const std::shared_ptr<SHAPE_POLY_SET>& poly = PAD::GetEffectivePolygon();
1204 double area = poly->Area();
1205
1206 aList.emplace_back( _( "Area" ), aFrame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
1207 }
1208 }
1209
1210 // Show the pad shape, attribute and property
1211 wxString props = ShowPadAttr();
1212
1213 if( GetProperty() != PAD_PROP::NONE )
1214 props += ',';
1215
1216 switch( GetProperty() )
1217 {
1218 case PAD_PROP::NONE: break;
1219 case PAD_PROP::BGA: props += _( "BGA" ); break;
1220 case PAD_PROP::FIDUCIAL_GLBL: props += _( "Fiducial global" ); break;
1221 case PAD_PROP::FIDUCIAL_LOCAL: props += _( "Fiducial local" ); break;
1222 case PAD_PROP::TESTPOINT: props += _( "Test point" ); break;
1223 case PAD_PROP::HEATSINK: props += _( "Heat sink" ); break;
1224 case PAD_PROP::CASTELLATED: props += _( "Castellated" ); break;
1225 }
1226
1227 aList.emplace_back( ShowPadShape(), props );
1228
1229 if( ( GetShape() == PAD_SHAPE::CIRCLE || GetShape() == PAD_SHAPE::OVAL )
1230 && m_size.x == m_size.y )
1231 {
1232 aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( m_size.x ) );
1233 }
1234 else
1235 {
1236 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( m_size.x ) );
1237 aList.emplace_back( _( "Height" ), aFrame->MessageTextFromValue( m_size.y ) );
1238 }
1239
1240 EDA_ANGLE fp_orient = parentFootprint ? parentFootprint->GetOrientation() : ANGLE_0;
1241 EDA_ANGLE pad_orient = GetOrientation() - fp_orient;
1242 pad_orient.Normalize180();
1243
1244 if( !fp_orient.IsZero() )
1245 msg.Printf( wxT( "%g(+ %g)" ), pad_orient.AsDegrees(), fp_orient.AsDegrees() );
1246 else
1247 msg.Printf( wxT( "%g" ), GetOrientation().AsDegrees() );
1248
1249 aList.emplace_back( _( "Rotation" ), msg );
1250
1251 if( GetPadToDieLength() )
1252 {
1253 aList.emplace_back( _( "Length in Package" ),
1255 }
1256
1257 if( m_drill.x > 0 || m_drill.y > 0 )
1258 {
1260 {
1261 aList.emplace_back( _( "Hole" ),
1262 wxString::Format( wxT( "%s" ),
1263 aFrame->MessageTextFromValue( m_drill.x ) ) );
1264 }
1265 else
1266 {
1267 aList.emplace_back( _( "Hole X / Y" ),
1268 wxString::Format( wxT( "%s / %s" ),
1269 aFrame->MessageTextFromValue( m_drill.x ),
1270 aFrame->MessageTextFromValue( m_drill.y ) ) );
1271 }
1272 }
1273
1274 wxString source;
1275 int clearance = GetOwnClearance( UNDEFINED_LAYER, &source );
1276
1277 if( !source.IsEmpty() )
1278 {
1279 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
1280 aFrame->MessageTextFromValue( clearance ) ),
1281 wxString::Format( _( "(from %s)" ),
1282 source ) );
1283 }
1284#if 0
1285 // useful for debug only
1286 aList.emplace_back( wxT( "UUID" ), m_Uuid.AsString() );
1287#endif
1288}
1289
1290
1291bool PAD::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
1292{
1293 VECTOR2I delta = aPosition - GetPosition();
1294 int boundingRadius = GetBoundingRadius() + aAccuracy;
1295
1296 if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
1297 return false;
1298
1299 return GetEffectivePolygon( ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy );
1300}
1301
1302
1303bool PAD::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1304{
1305 BOX2I arect = aRect;
1306 arect.Normalize();
1307 arect.Inflate( aAccuracy );
1308
1309 BOX2I bbox = GetBoundingBox();
1310
1311 if( aContained )
1312 {
1313 return arect.Contains( bbox );
1314 }
1315 else
1316 {
1317 // Fast test: if aRect is outside the polygon bounding box,
1318 // rectangles cannot intersect
1319 if( !arect.Intersects( bbox ) )
1320 return false;
1321
1322 const std::shared_ptr<SHAPE_POLY_SET>& poly = GetEffectivePolygon( ERROR_INSIDE );
1323
1324 int count = poly->TotalVertices();
1325
1326 for( int ii = 0; ii < count; ii++ )
1327 {
1328 VECTOR2I vertex = poly->CVertex( ii );
1329 VECTOR2I vertexNext = poly->CVertex( ( ii + 1 ) % count );
1330
1331 // Test if the point is within aRect
1332 if( arect.Contains( vertex ) )
1333 return true;
1334
1335 // Test if this edge intersects aRect
1336 if( arect.Intersects( vertex, vertexNext ) )
1337 return true;
1338 }
1339
1340 return false;
1341 }
1342}
1343
1344
1345int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
1346{
1347 int diff;
1348
1349 if( ( diff = static_cast<int>( aPadRef->GetShape() ) -
1350 static_cast<int>( aPadCmp->GetShape() ) ) != 0 )
1351 return diff;
1352
1353 if( ( diff = static_cast<int>( aPadRef->m_attribute ) -
1354 static_cast<int>( aPadCmp->m_attribute ) ) != 0 )
1355 return diff;
1356
1357 if( ( diff = aPadRef->m_drillShape - aPadCmp->m_drillShape ) != 0 )
1358 return diff;
1359
1360 if( ( diff = aPadRef->m_drill.x - aPadCmp->m_drill.x ) != 0 )
1361 return diff;
1362
1363 if( ( diff = aPadRef->m_drill.y - aPadCmp->m_drill.y ) != 0 )
1364 return diff;
1365
1366 if( ( diff = aPadRef->m_size.x - aPadCmp->m_size.x ) != 0 )
1367 return diff;
1368
1369 if( ( diff = aPadRef->m_size.y - aPadCmp->m_size.y ) != 0 )
1370 return diff;
1371
1372 if( ( diff = aPadRef->m_offset.x - aPadCmp->m_offset.x ) != 0 )
1373 return diff;
1374
1375 if( ( diff = aPadRef->m_offset.y - aPadCmp->m_offset.y ) != 0 )
1376 return diff;
1377
1378 if( ( diff = aPadRef->m_deltaSize.x - aPadCmp->m_deltaSize.x ) != 0 )
1379 return diff;
1380
1381 if( ( diff = aPadRef->m_deltaSize.y - aPadCmp->m_deltaSize.y ) != 0 )
1382 return diff;
1383
1384 if( ( diff = aPadRef->m_roundedCornerScale - aPadCmp->m_roundedCornerScale ) != 0 )
1385 return diff;
1386
1387 if( ( diff = aPadRef->m_chamferPositions - aPadCmp->m_chamferPositions ) != 0 )
1388 return diff;
1389
1390 if( ( diff = aPadRef->m_chamferScale - aPadCmp->m_chamferScale ) != 0 )
1391 return diff;
1392
1393 if( ( diff = static_cast<int>( aPadRef->m_editPrimitives.size() ) -
1394 static_cast<int>( aPadCmp->m_editPrimitives.size() ) ) != 0 )
1395 return diff;
1396
1397 // @todo: Compare custom pad primitives for pads that have the same number of primitives
1398 // here. Currently there is no compare function for PCB_SHAPE objects.
1399
1400 // Dick: specctra_export needs this
1401 // Lorenzo: gencad also needs it to implement padstacks!
1402
1403#if __cplusplus >= 201103L
1404 long long d = aPadRef->m_layerMask.to_ullong() - aPadCmp->m_layerMask.to_ullong();
1405
1406 if( d < 0 )
1407 return -1;
1408 else if( d > 0 )
1409 return 1;
1410
1411 return 0;
1412#else
1413 // these strings are not typically constructed, since we don't get here often.
1414 std::string s1 = aPadRef->m_layerMask.to_string();
1415 std::string s2 = aPadCmp->m_layerMask.to_string();
1416 return s1.compare( s2 );
1417#endif
1418}
1419
1420
1421void PAD::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1422{
1423 RotatePoint( m_pos, aRotCentre, aAngle );
1424
1425 m_orient += aAngle;
1427
1428 SetDirty();
1429}
1430
1431
1432wxString PAD::ShowPadShape() const
1433{
1434 switch( GetShape() )
1435 {
1436 case PAD_SHAPE::CIRCLE: return _( "Circle" );
1437 case PAD_SHAPE::OVAL: return _( "Oval" );
1438 case PAD_SHAPE::RECTANGLE: return _( "Rect" );
1439 case PAD_SHAPE::TRAPEZOID: return _( "Trap" );
1440 case PAD_SHAPE::ROUNDRECT: return _( "Roundrect" );
1441 case PAD_SHAPE::CHAMFERED_RECT: return _( "Chamferedrect" );
1442 case PAD_SHAPE::CUSTOM: return _( "CustomShape" );
1443 default: return wxT( "???" );
1444 }
1445}
1446
1447
1448wxString PAD::ShowPadAttr() const
1449{
1450 switch( GetAttribute() )
1451 {
1452 case PAD_ATTRIB::PTH: return _( "PTH" );
1453 case PAD_ATTRIB::SMD: return _( "SMD" );
1454 case PAD_ATTRIB::CONN: return _( "Conn" );
1455 case PAD_ATTRIB::NPTH: return _( "NPTH" );
1456 default: return wxT( "???" );
1457 }
1458}
1459
1460
1461wxString PAD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
1462{
1463 if( GetNumber().IsEmpty() )
1464 {
1465 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1466 {
1467 return wxString::Format( _( "Pad %s of %s on %s" ),
1468 GetNetnameMsg(),
1469 GetParentFootprint()->GetReference(),
1471 }
1472 else if( GetAttribute() == PAD_ATTRIB::NPTH )
1473 {
1474 return wxString::Format( _( "NPTH pad of %s" ), GetParentFootprint()->GetReference() );
1475 }
1476 else
1477 {
1478 return wxString::Format( _( "PTH pad %s of %s" ),
1479 GetNetnameMsg(),
1480 GetParentFootprint()->GetReference() );
1481 }
1482 }
1483 else
1484 {
1485 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1486 {
1487 return wxString::Format( _( "Pad %s %s of %s on %s" ),
1488 GetNumber(),
1489 GetNetnameMsg(),
1490 GetParentFootprint()->GetReference(),
1492 }
1493 else if( GetAttribute() == PAD_ATTRIB::NPTH )
1494 {
1495 return wxString::Format( _( "NPTH of %s" ), GetParentFootprint()->GetReference() );
1496 }
1497 else
1498 {
1499 return wxString::Format( _( "PTH pad %s %s of %s" ),
1500 GetNumber(),
1501 GetNetnameMsg(),
1502 GetParentFootprint()->GetReference() );
1503 }
1504 }
1505}
1506
1507
1509{
1510 return BITMAPS::pad;
1511}
1512
1513
1515{
1516 return new PAD( *this );
1517}
1518
1519
1520void PAD::ViewGetLayers( int aLayers[], int& aCount ) const
1521{
1522 aCount = 0;
1523
1524 // These 2 types of pads contain a hole
1525 if( m_attribute == PAD_ATTRIB::PTH )
1526 {
1527 aLayers[aCount++] = LAYER_PAD_PLATEDHOLES;
1528 aLayers[aCount++] = LAYER_PAD_HOLEWALLS;
1529 }
1530
1531 if( m_attribute == PAD_ATTRIB::NPTH )
1532 aLayers[aCount++] = LAYER_NON_PLATEDHOLES;
1533
1534 if( IsOnLayer( F_Cu ) && IsOnLayer( B_Cu ) )
1535 {
1536 // Multi layer pad
1537 aLayers[aCount++] = LAYER_PADS_TH;
1538 aLayers[aCount++] = LAYER_PAD_NETNAMES;
1539 }
1540 else if( IsOnLayer( F_Cu ) )
1541 {
1542 aLayers[aCount++] = LAYER_PADS_SMD_FR;
1543
1544 // Is this a PTH pad that has only front copper? If so, we need to also display the
1545 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1546 if( m_attribute == PAD_ATTRIB::PTH )
1547 aLayers[aCount++] = LAYER_PAD_NETNAMES;
1548 else
1549 aLayers[aCount++] = LAYER_PAD_FR_NETNAMES;
1550 }
1551 else if( IsOnLayer( B_Cu ) )
1552 {
1553 aLayers[aCount++] = LAYER_PADS_SMD_BK;
1554
1555 // Is this a PTH pad that has only back copper? If so, we need to also display the
1556 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1557 if( m_attribute == PAD_ATTRIB::PTH )
1558 aLayers[aCount++] = LAYER_PAD_NETNAMES;
1559 else
1560 aLayers[aCount++] = LAYER_PAD_BK_NETNAMES;
1561 }
1562 else
1563 {
1564 // Internal layers only. (Not yet supported in GUI, but is being used by Python
1565 // footprint generators and will be needed anyway once pad stacks are supported.)
1566 for ( int internal = In1_Cu; internal < In30_Cu; ++internal )
1567 {
1568 if( IsOnLayer( (PCB_LAYER_ID) internal ) )
1569 aLayers[aCount++] = internal;
1570 }
1571 }
1572
1573 // Check non-copper layers. This list should include all the layers that the
1574 // footprint editor allows a pad to be placed on.
1575 static const PCB_LAYER_ID layers_mech[] = { F_Mask, B_Mask, F_Paste, B_Paste,
1577
1578 for( PCB_LAYER_ID each_layer : layers_mech )
1579 {
1580 if( IsOnLayer( each_layer ) )
1581 aLayers[aCount++] = each_layer;
1582 }
1583}
1584
1585
1586double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1587{
1588 constexpr double HIDE = std::numeric_limits<double>::max();
1589
1590 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
1591 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
1592 const BOARD* board = GetBoard();
1593
1594 // Meta control for hiding all pads
1595 if( !aView->IsLayerVisible( LAYER_PADS ) )
1596 return HIDE;
1597
1598 // Handle Render tab switches
1599 if( ( GetAttribute() == PAD_ATTRIB::PTH || GetAttribute() == PAD_ATTRIB::NPTH )
1600 && !aView->IsLayerVisible( LAYER_PADS_TH ) )
1601 {
1602 return HIDE;
1603 }
1604
1605 if( !IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
1606 return HIDE;
1607
1608 if( IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
1609 return HIDE;
1610
1611 if( IsFrontLayer( (PCB_LAYER_ID) aLayer ) && !aView->IsLayerVisible( LAYER_PADS_SMD_FR ) )
1612 return HIDE;
1613
1614 if( IsBackLayer( (PCB_LAYER_ID) aLayer ) && !aView->IsLayerVisible( LAYER_PADS_SMD_BK ) )
1615 return HIDE;
1616
1617 LSET visible = board->GetVisibleLayers() & board->GetEnabledLayers();
1618
1619 if( IsHoleLayer( aLayer ) )
1620 {
1621 if( !( visible & LSET::PhysicalLayersMask() ).any() )
1622 return HIDE;
1623 }
1624 else if( IsNetnameLayer( aLayer ) )
1625 {
1626 if( renderSettings->GetHighContrast() )
1627 {
1628 // Hide netnames unless pad is flashed to a high-contrast layer
1629 if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
1630 return HIDE;
1631 }
1632 else
1633 {
1634 // Hide netnames unless pad is flashed to a visible layer
1635 if( !FlashLayer( visible ) )
1636 return HIDE;
1637 }
1638
1639 // Netnames will be shown only if zoom is appropriate
1640 int divisor = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
1641
1642 // Pad sizes can be zero briefly when someone is typing a number like "0.5" in the pad
1643 // properties dialog
1644 if( divisor == 0 )
1645 return HIDE;
1646
1647 return ( double ) pcbIUScale.mmToIU( 5 ) / divisor;
1648 }
1649
1650 // Passed all tests; show.
1651 return 0.0;
1652}
1653
1654
1656{
1657 // Bounding box includes soldermask too. Remember mask and/or paste margins can be < 0
1658 int solderMaskMargin = std::max( GetSolderMaskExpansion(), 0 );
1659 VECTOR2I solderPasteMargin = VECTOR2D( GetSolderPasteMargin() );
1660 BOX2I bbox = GetBoundingBox();
1661 int clearance = 0;
1662
1663 // If we're drawing clearance lines then get the biggest possible clearance
1664 if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
1665 {
1666 if( cfg && cfg->m_Display.m_PadClearance && GetBoard() )
1667 clearance = GetBoard()->GetMaxClearanceValue();
1668 }
1669
1670 // Look for the biggest possible bounding box
1671 int xMargin = std::max( solderMaskMargin, solderPasteMargin.x ) + clearance;
1672 int yMargin = std::max( solderMaskMargin, solderPasteMargin.y ) + clearance;
1673
1674 return BOX2I( VECTOR2I( bbox.GetOrigin() ) - VECTOR2I( xMargin, yMargin ),
1675 VECTOR2I( bbox.GetSize() ) + VECTOR2I( 2 * xMargin, 2 * yMargin ) );
1676}
1677
1678
1679void PAD::ImportSettingsFrom( const PAD& aMasterPad )
1680{
1681 SetShape( aMasterPad.GetShape() );
1682 // Layer Set should be updated before calling SetAttribute()
1683 SetLayerSet( aMasterPad.GetLayerSet() );
1684 SetAttribute( aMasterPad.GetAttribute() );
1685 // Unfortunately, SetAttribute() can change m_layerMask.
1686 // Be sure we keep the original mask by calling SetLayerSet() after SetAttribute()
1687 SetLayerSet( aMasterPad.GetLayerSet() );
1688 SetProperty( aMasterPad.GetProperty() );
1689
1690 // Must be after setting attribute and layerSet
1691 if( !CanHaveNumber() )
1692 SetNumber( wxEmptyString );
1693
1694 // I am not sure the m_LengthPadToDie should be imported, because this is a parameter
1695 // really specific to a given pad (JPC).
1696#if 0
1697 SetPadToDieLength( aMasterPad.GetPadToDieLength() );
1698#endif
1699
1700 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
1701 EDA_ANGLE pad_rot = aMasterPad.GetOrientation();
1702
1703 if( aMasterPad.GetParentFootprint() )
1704 pad_rot -= aMasterPad.GetParentFootprint()->GetOrientation();
1705
1706 if( GetParentFootprint() )
1707 pad_rot += GetParentFootprint()->GetOrientation();
1708
1709 SetOrientation( pad_rot );
1710
1712 SetKeepTopBottom( aMasterPad.GetKeepTopBottom() );
1713
1714 SetSize( aMasterPad.GetSize() );
1715 SetDelta( VECTOR2I( 0, 0 ) );
1716 SetOffset( aMasterPad.GetOffset() );
1717 SetDrillSize( aMasterPad.GetDrillSize() );
1718 SetDrillShape( aMasterPad.GetDrillShape() );
1722
1723 switch( aMasterPad.GetShape() )
1724 {
1725 case PAD_SHAPE::TRAPEZOID:
1726 SetDelta( aMasterPad.GetDelta() );
1727 break;
1728
1729 case PAD_SHAPE::CIRCLE:
1730 // ensure size.y == size.x
1731 SetSize( VECTOR2I( GetSize().x, GetSize().x ) );
1732 break;
1733
1734 default:
1735 ;
1736 }
1737
1738 switch( aMasterPad.GetAttribute() )
1739 {
1740 case PAD_ATTRIB::SMD:
1741 case PAD_ATTRIB::CONN:
1742 // These pads do not have a hole (they are expected to be on one external copper layer)
1743 SetDrillSize( VECTOR2I( 0, 0 ) );
1744 break;
1745
1746 default:
1747 ;
1748 }
1749
1750 // copy also local settings:
1751 SetLocalClearance( aMasterPad.GetLocalClearance() );
1755
1759 SetThermalGap( aMasterPad.GetThermalGap() );
1760
1762
1764
1765 // Add or remove custom pad shapes:
1766 ReplacePrimitives( aMasterPad.GetPrimitives() );
1767 SetAnchorPadShape( aMasterPad.GetAnchorPadShape() );
1768
1769 SetDirty();
1770}
1771
1772
1774{
1775 assert( aImage->Type() == PCB_PAD_T );
1776
1777 std::swap( *this, *static_cast<PAD*>( aImage ) );
1778}
1779
1780
1781bool PAD::TransformHoleToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
1782 ERROR_LOC aErrorLoc ) const
1783{
1784 VECTOR2I drillsize = GetDrillSize();
1785
1786 if( !drillsize.x || !drillsize.y )
1787 return false;
1788
1789 std::shared_ptr<SHAPE_SEGMENT> slot = GetEffectiveHoleShape();
1790
1791 TransformOvalToPolygon( aBuffer, slot->GetSeg().A, slot->GetSeg().B,
1792 slot->GetWidth() + aClearance * 2, aError, aErrorLoc );
1793
1794 return true;
1795}
1796
1797
1798void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
1799 int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
1800{
1801 wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for pads." ) );
1802
1803 // minimal segment count to approximate a circle to create the polygonal pad shape
1804 // This minimal value is mainly for very small pads, like SM0402.
1805 // Most of time pads are using the segment count given by aError value.
1806 const int pad_min_seg_per_circle_count = 16;
1807 int dx = m_size.x / 2;
1808 int dy = m_size.y / 2;
1809
1810 VECTOR2I padShapePos = ShapePos(); // Note: for pad having a shape offset, the pad
1811 // position is NOT the shape position
1812
1813 switch( GetShape() )
1814 {
1815 case PAD_SHAPE::CIRCLE:
1816 case PAD_SHAPE::OVAL:
1817 // Note: dx == dy is not guaranteed for circle pads in legacy boards
1818 if( dx == dy || ( GetShape() == PAD_SHAPE::CIRCLE ) )
1819 {
1820 TransformCircleToPolygon( aBuffer, padShapePos, dx + aClearance, aMaxError, aErrorLoc,
1821 pad_min_seg_per_circle_count );
1822 }
1823 else
1824 {
1825 int half_width = std::min( dx, dy );
1826 VECTOR2I delta( dx - half_width, dy - half_width );
1827
1829
1830 TransformOvalToPolygon( aBuffer, padShapePos - delta, padShapePos + delta,
1831 ( half_width + aClearance ) * 2, aMaxError, aErrorLoc,
1832 pad_min_seg_per_circle_count );
1833 }
1834
1835 break;
1836
1837 case PAD_SHAPE::TRAPEZOID:
1838 case PAD_SHAPE::RECTANGLE:
1839 {
1840 int ddx = GetShape() == PAD_SHAPE::TRAPEZOID ? m_deltaSize.x / 2 : 0;
1841 int ddy = GetShape() == PAD_SHAPE::TRAPEZOID ? m_deltaSize.y / 2 : 0;
1842
1843 SHAPE_POLY_SET outline;
1844 TransformTrapezoidToPolygon( outline, padShapePos, m_size, m_orient, ddx, ddy, aClearance,
1845 aMaxError, aErrorLoc );
1846 aBuffer.Append( outline );
1847 break;
1848 }
1849
1850 case PAD_SHAPE::CHAMFERED_RECT:
1851 case PAD_SHAPE::ROUNDRECT:
1852 {
1853 bool doChamfer = GetShape() == PAD_SHAPE::CHAMFERED_RECT;
1854
1855 SHAPE_POLY_SET outline;
1858 doChamfer ? GetChamferRectRatio() : 0,
1859 doChamfer ? GetChamferPositions() : 0,
1860 aClearance, aMaxError, aErrorLoc );
1861 aBuffer.Append( outline );
1862 break;
1863 }
1864
1865 case PAD_SHAPE::CUSTOM:
1866 {
1867 SHAPE_POLY_SET outline;
1868 MergePrimitivesAsPolygon( &outline, aErrorLoc );
1869 outline.Rotate( m_orient );
1870 outline.Move( VECTOR2I( padShapePos ) );
1871
1872 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
1873 {
1874 if( aErrorLoc == ERROR_OUTSIDE )
1875 aClearance += aMaxError;
1876
1877 outline.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aMaxError );
1879 }
1880 else if( aClearance < 0 )
1881 {
1882 // Negative clearances are primarily for drawing solder paste layer, so we don't
1883 // worry ourselves overly about which side the error is on.
1884
1885 // aClearance is negative so this is actually a deflate
1886 outline.Inflate( aClearance, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, aMaxError );
1888 }
1889
1890 aBuffer.Append( outline );
1891 break;
1892 }
1893
1894 default:
1895 wxFAIL_MSG( wxT( "PAD::TransformShapeToPolygon no implementation for " )
1896 + wxString( std::string( magic_enum::enum_name( GetShape() ) ) ) );
1897 break;
1898 }
1899}
1900
1901
1902bool PAD::operator==( const BOARD_ITEM& aOther ) const
1903{
1904 if( Type() != aOther.Type() )
1905 return false;
1906
1907 if( m_parent && aOther.GetParent() && m_parent->m_Uuid != aOther.GetParent()->m_Uuid )
1908 return false;
1909
1910 const PAD& other = static_cast<const PAD&>( aOther );
1911
1912 if( GetShape() != other.GetShape() )
1913 return false;
1914
1915 if( GetPosition() != other.GetPosition() )
1916 return false;
1917
1918 if( GetAttribute() != other.GetAttribute() )
1919 return false;
1920
1921 if( GetSize() != other.GetSize() )
1922 return false;
1923
1924 if( GetOffset() != other.GetOffset() )
1925 return false;
1926
1927 if( GetDrillSize() != other.GetDrillSize() )
1928 return false;
1929
1930 if( GetDrillShape() != other.GetDrillShape() )
1931 return false;
1932
1934 return false;
1935
1936 if( GetChamferRectRatio() != other.GetChamferRectRatio() )
1937 return false;
1938
1939 if( GetChamferPositions() != other.GetChamferPositions() )
1940 return false;
1941
1942 if( GetOrientation() != other.GetOrientation() )
1943 return false;
1944
1946 return false;
1947
1949 return false;
1950
1952 return false;
1953
1954 if( GetThermalGap() != other.GetThermalGap() )
1955 return false;
1956
1958 return false;
1959
1960 if( GetPrimitives().size() != other.GetPrimitives().size() )
1961 return false;
1962
1963 for( size_t ii = 0; ii < GetPrimitives().size(); ii++ )
1964 {
1965 if( GetPrimitives()[ii] != other.GetPrimitives()[ii] )
1966 return false;
1967 }
1968
1969 if( GetAnchorPadShape() != other.GetAnchorPadShape() )
1970 return false;
1971
1972 if( GetLocalClearance() != other.GetLocalClearance() )
1973 return false;
1974
1976 return false;
1977
1979 return false;
1980
1982 return false;
1983
1985 return false;
1986
1987 if( GetLayerSet() != other.GetLayerSet() )
1988 return false;
1989
1990 return true;
1991}
1992
1993
1994double PAD::Similarity( const BOARD_ITEM& aOther ) const
1995{
1996 if( aOther.Type() != Type() )
1997 return 0.0;
1998
1999 if( m_parent->m_Uuid != aOther.GetParent()->m_Uuid )
2000 return 0.0;
2001
2002 const PAD& other = static_cast<const PAD&>( aOther );
2003
2004 double similarity = 1.0;
2005
2006 if( GetShape() != other.GetShape() )
2007 similarity *= 0.9;
2008
2009 if( GetPosition() != other.GetPosition() )
2010 similarity *= 0.9;
2011
2012 if( GetAttribute() != other.GetAttribute() )
2013 similarity *= 0.9;
2014
2015 if( GetSize() != other.GetSize() )
2016 similarity *= 0.9;
2017
2018 if( GetOffset() != other.GetOffset() )
2019 similarity *= 0.9;
2020
2021 if( GetDrillSize() != other.GetDrillSize() )
2022 similarity *= 0.9;
2023
2024 if( GetDrillShape() != other.GetDrillShape() )
2025 similarity *= 0.9;
2026
2028 similarity *= 0.9;
2029
2030 if( GetChamferRectRatio() != other.GetChamferRectRatio() )
2031 similarity *= 0.9;
2032
2033 if( GetChamferPositions() != other.GetChamferPositions() )
2034 similarity *= 0.9;
2035
2036 if( GetOrientation() != other.GetOrientation() )
2037 similarity *= 0.9;
2038
2040 similarity *= 0.9;
2041
2043 similarity *= 0.9;
2044
2046 similarity *= 0.9;
2047
2048 if( GetThermalGap() != other.GetThermalGap() )
2049 similarity *= 0.9;
2050
2052 similarity *= 0.9;
2053
2054 if( GetPrimitives().size() != other.GetPrimitives().size() )
2055 similarity *= 0.9;
2056
2057 if( GetAnchorPadShape() != other.GetAnchorPadShape() )
2058 similarity *= 0.9;
2059
2060 if( GetLocalClearance() != other.GetLocalClearance() )
2061 similarity *= 0.9;
2062
2064 similarity *= 0.9;
2065
2067 similarity *= 0.9;
2068
2070 similarity *= 0.9;
2071
2073 similarity *= 0.9;
2074
2075 if( GetLayerSet() != other.GetLayerSet() )
2076 similarity *= 0.9;
2077
2078 return similarity;
2079}
2080
2081
2082static struct PAD_DESC
2083{
2085 {
2087 .Map( PAD_ATTRIB::PTH, _HKI( "Through-hole" ) )
2088 .Map( PAD_ATTRIB::SMD, _HKI( "SMD" ) )
2089 .Map( PAD_ATTRIB::CONN, _HKI( "Edge connector" ) )
2090 .Map( PAD_ATTRIB::NPTH, _HKI( "NPTH, mechanical" ) );
2091
2093 .Map( PAD_SHAPE::CIRCLE, _HKI( "Circle" ) )
2094 .Map( PAD_SHAPE::RECTANGLE, _HKI( "Rectangle" ) )
2095 .Map( PAD_SHAPE::OVAL, _HKI( "Oval" ) )
2096 .Map( PAD_SHAPE::TRAPEZOID, _HKI( "Trapezoid" ) )
2097 .Map( PAD_SHAPE::ROUNDRECT, _HKI( "Rounded rectangle" ) )
2098 .Map( PAD_SHAPE::CHAMFERED_RECT, _HKI( "Chamfered rectangle" ) )
2099 .Map( PAD_SHAPE::CUSTOM, _HKI( "Custom" ) );
2100
2102 .Map( PAD_PROP::NONE, _HKI( "None" ) )
2103 .Map( PAD_PROP::BGA, _HKI( "BGA pad" ) )
2104 .Map( PAD_PROP::FIDUCIAL_GLBL, _HKI( "Fiducial, global to board" ) )
2105 .Map( PAD_PROP::FIDUCIAL_LOCAL, _HKI( "Fiducial, local to footprint" ) )
2106 .Map( PAD_PROP::TESTPOINT, _HKI( "Test point pad" ) )
2107 .Map( PAD_PROP::HEATSINK, _HKI( "Heatsink pad" ) )
2108 .Map( PAD_PROP::CASTELLATED, _HKI( "Castellated pad" ) );
2109
2111
2112 if( zcMap.Choices().GetCount() == 0 )
2113 {
2114 zcMap.Undefined( ZONE_CONNECTION::INHERITED );
2115 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
2116 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
2117 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
2118 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
2119 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
2120 }
2121
2123 REGISTER_TYPE( PAD );
2125
2126 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
2127
2128 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Orientation" ),
2130 PROPERTY_DISPLAY::PT_DEGREE ) );
2131
2132 auto isCopperPad =
2133 []( INSPECTABLE* aItem ) -> bool
2134 {
2135 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2136 return pad->GetAttribute() != PAD_ATTRIB::NPTH;
2137
2138 return false;
2139 };
2140
2141 auto padCanHaveHole =
2142 []( INSPECTABLE* aItem ) -> bool
2143 {
2144 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2145 {
2146 return pad->GetAttribute() == PAD_ATTRIB::PTH
2147 || pad->GetAttribute() == PAD_ATTRIB::NPTH;
2148 }
2149
2150 return false;
2151 };
2152
2154 _HKI( "Net" ), isCopperPad );
2156 _HKI( "Net Class" ), isCopperPad );
2157
2158 const wxString groupPad = _HKI( "Pad Properties" );
2159
2160 auto padType = new PROPERTY_ENUM<PAD, PAD_ATTRIB>( _HKI( "Pad Type" ),
2162 propMgr.AddProperty( padType, groupPad );
2163
2164 auto shape = new PROPERTY_ENUM<PAD, PAD_SHAPE>( _HKI( "Pad Shape" ),
2166 propMgr.AddProperty( shape, groupPad );
2167
2168 auto padNumber = new PROPERTY<PAD, wxString>( _HKI( "Pad Number" ),
2170 padNumber->SetAvailableFunc( isCopperPad );
2171 propMgr.AddProperty( padNumber, groupPad );
2172
2173 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Name" ),
2174 NO_SETTER( PAD, wxString ), &PAD::GetPinFunction ), groupPad )
2176 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Type" ),
2177 NO_SETTER( PAD, wxString ), &PAD::GetPinType ), groupPad )
2179
2180 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size X" ),
2182 PROPERTY_DISPLAY::PT_SIZE ), groupPad );
2183 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size Y" ),
2185 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2187 [=]( INSPECTABLE* aItem ) -> bool
2188 {
2189 // Circle pads have no usable y-size
2190 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2191 return pad->GetShape() != PAD_SHAPE::CIRCLE;
2192
2193 return true;
2194 } );
2195
2196 auto roundRadiusRatio = new PROPERTY<PAD, double>( _HKI( "Corner Radius Ratio" ),
2198 roundRadiusRatio->SetAvailableFunc(
2199 [=]( INSPECTABLE* aItem ) -> bool
2200 {
2201 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2202 return pad->GetShape() == PAD_SHAPE::ROUNDRECT;
2203
2204 return false;
2205 } );
2206 propMgr.AddProperty( roundRadiusRatio, groupPad );
2207
2208 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size X" ),
2210 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2211 .SetWriteableFunc( padCanHaveHole )
2213
2214 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size Y" ),
2216 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2217 .SetWriteableFunc( padCanHaveHole )
2219
2220 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_PROP>( _HKI( "Fabrication Property" ),
2221 &PAD::SetProperty, &PAD::GetProperty ), groupPad );
2222
2223 auto padToDie = new PROPERTY<PAD, int>( _HKI( "Pad To Die Length" ),
2225 PROPERTY_DISPLAY::PT_SIZE );
2226 padToDie->SetAvailableFunc( isCopperPad );
2227 propMgr.AddProperty( padToDie, groupPad );
2228
2229 const wxString groupOverrides = _HKI( "Overrides" );
2230
2231 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2232 _HKI( "Clearance Override" ),
2234 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2235
2236 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2237 _HKI( "Soldermask Margin Override" ),
2239 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2240
2241 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2242 _HKI( "Solderpaste Margin Override" ),
2244 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2245
2246 propMgr.AddProperty( new PROPERTY<PAD, std::optional<double>>(
2247 _HKI( "Solderpaste Margin Ratio Override" ),
2249 PROPERTY_DISPLAY::PT_RATIO ),
2250 groupOverrides );
2251
2253 _HKI( "Zone Connection Style" ),
2255
2256 constexpr int minZoneWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
2257
2258 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Thermal Relief Spoke Width" ),
2260 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2261 .SetValidator( PROPERTY_VALIDATORS::RangeIntValidator<minZoneWidth, INT_MAX> );
2262
2263 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Thermal Relief Spoke Angle" ),
2265 PROPERTY_DISPLAY::PT_DEGREE ), groupOverrides );
2266
2267 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Thermal Relief Gap" ),
2269 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2271
2272 // TODO delta, drill shape offset, layer set
2273 }
2275
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
Definition: api_enums.cpp:94
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
@ ZLO_NONE
Definition: board_item.h:65
@ ZLO_FORCE_FLASHED
Definition: board_item.h:66
BOX2< VECTOR2I > BOX2I
Definition: box2.h:887
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
wxString GetNetnameMsg() const
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
TEARDROP_PARAMETERS m_teardropParams
Not all BOARD_CONNECTED_ITEMs support teardrops, but we want those that do to share a single section ...
wxString GetShortNetname() const
Container for design settings for a BOARD object.
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:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:226
virtual void SetLocked(bool aLocked)
Definition: board_item.h:300
PCB_LAYER_ID m_layer
Definition: board_item.h:388
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:260
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
virtual bool IsLocked() const
Definition: board_item.cpp:74
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:204
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:115
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:680
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:694
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition: board.h:1157
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:797
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:136
const Vec & GetOrigin() const
Definition: box2.h:200
const SizeVec & GetSize() const
Definition: box2.h:196
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:294
bool Contains(const Vec &aPoint) const
Definition: box2.h:158
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:623
wxString GetName() const
Definition: drc_rule.h:149
MINOPTMAX< int > & Value()
Definition: drc_rule.h:142
EDA_ANGLE Normalize()
Definition: eda_angle.h:255
double AsDegrees() const
Definition: eda_angle.h:155
bool IsZero() const
Definition: eda_angle.h:175
EDA_ANGLE Normalize180()
Definition: eda_angle.h:294
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:242
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition: eda_item.cpp:258
const KIID m_Uuid
Definition: eda_item.h:485
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
EDA_ITEM * m_parent
Linked list: Link (parent struct)
Definition: eda_item.h:488
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:669
static ENUM_MAP< T > & Instance()
Definition: property.h:663
ENUM_MAP & Undefined(T aValue)
Definition: property.h:676
wxPGChoices & Choices()
Definition: property.h:712
EDA_ANGLE GetOrientation() const
Definition: footprint.h:212
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2911
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:221
bool IsNetTie() const
Definition: footprint.h:283
const wxString & GetReference() const
Definition: footprint.h:588
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:36
Contains methods for drawing PCB-specific items.
Definition: pcb_painter.h:164
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
Definition: pcb_painter.h:169
PCB specific render settings.
Definition: pcb_painter.h:77
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
bool GetHighContrast() const
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:412
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
Definition: kiid.h:49
wxString AsString() const
Definition: kiid.cpp:257
std::string AsStdString() const
Definition: kiid.cpp:263
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:575
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
static LSET FrontBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on front side.
Definition: lset.cpp:924
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:960
static LSET BackBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on Back side.
Definition: lset.cpp:911
T Min() const
Definition: minoptmax.h:33
bool HasMin() const
Definition: minoptmax.h:37
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:375
Definition: pad.h:59
PAD_DRILL_SHAPE_T m_drillShape
Definition: pad.h:792
bool IsAperturePad() const
Definition: pad.h:384
void SetAttribute(PAD_ATTRIB aAttribute)
Definition: pad.cpp:805
int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const override
Return the pad's "own" clearance in internal units.
Definition: pad.cpp:1012
void SetLayerSet(LSET aLayers) override
Definition: pad.h:373
PAD(FOOTPRINT *parent)
Definition: pad.cpp:68
virtual void swapData(BOARD_ITEM *aImage) override
Definition: pad.cpp:1773
PAD_PROP GetProperty() const
Definition: pad.h:380
bool GetRemoveUnconnected() const
Definition: pad.h:600
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: pad.h:359
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: pad.cpp:142
std::optional< int > GetClearanceOverrides(wxString *aSource) const override
Return any clearance overrides set in the "classic" (ie: pre-rule) system.
Definition: pad.cpp:1000
void SetPinType(const wxString &aType)
Set the pad electrical type.
Definition: pad.h:150
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:374
CUST_PAD_SHAPE_IN_ZONE m_customShapeClearanceArea
Definition: pad.h:854
int GetSizeX() const
Definition: pad.h:249
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:420
VECTOR2I m_size
Definition: pad.h:790
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:1166
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition: pad.cpp:796
VECTOR2I m_drill
Definition: pad.h:789
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:621
int GetSolderMaskExpansion() const
Definition: pad.cpp:1038
int m_chamferPositions
Definition: pad.h:798
VECTOR2I m_offset
Definition: pad.h:810
int GetDrillSizeY() const
Definition: pad.h:261
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: pad.h:401
const wxString & GetPinType() const
Definition: pad.h:151
const VECTOR2I & GetDrillSize() const
Definition: pad.h:257
PAD_ATTRIB GetAttribute() const
Definition: pad.h:377
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:349
static int Compare(const PAD *aPadRef, const PAD *aPadCmp)
Compare two pads and return 0 if they are equal.
Definition: pad.cpp:1345
VECTOR2I m_deltaSize
Definition: pad.h:815
void SetRemoveUnconnected(bool aSet)
Set the unconnected removal property.
Definition: pad.h:599
const wxString & GetPinFunction() const
Definition: pad.h:145
void BuildEffectiveShapes(PCB_LAYER_ID aLayer) const
Rebuild the effective shape cache (and bounding box and radius) for the pad and clears the dirty bit.
Definition: pad.cpp:578
std::mutex m_shapesBuildingLock
Definition: pad.h:776
void SetThermalGap(int aGap)
Definition: pad.h:544
std::shared_ptr< SHAPE_POLY_SET > m_effectivePolygon[2]
Definition: pad.h:783
bool CanHaveNumber() const
Indicates whether or not the pad can have a number.
Definition: pad.cpp:296
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition: pad.h:531
wxString m_pinType
Definition: pad.h:760
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: pad.cpp:214
double m_roundedCornerScale
Definition: pad.h:794
const wxString & GetNumber() const
Definition: pad.h:134
EDA_ANGLE m_orient
Definition: pad.h:823
void FlipPrimitives(bool aFlipLeftRight)
Flip (mirror) the primitives left to right or top to bottom, around the anchor position in custom pad...
Definition: pad.cpp:935
void MergePrimitivesAsPolygon(SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
int GetRoundRectCornerRadius() const
Definition: pad.cpp:483
std::vector< std::shared_ptr< PCB_SHAPE > > m_editPrimitives
Definition: pad.h:772
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: pad.h:402
PAD & operator=(const PAD &aOther)
Definition: pad.cpp:123
std::shared_ptr< SHAPE_SEGMENT > m_effectiveHoleShape
Definition: pad.h:779
std::optional< int > m_solderMaskMargin
Definition: pad.h:844
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
Definition: pad.cpp:1461
bool IsLocked() const override
Definition: pad.cpp:310
void SetDrillShape(PAD_DRILL_SHAPE_T aShape)
Definition: pad.h:358
VECTOR2I GetPosition() const override
Definition: pad.h:201
void SetProperty(PAD_PROP aProperty)
Definition: pad.cpp:844
void SetThermalSpokeAngleDegrees(double aAngle)
Definition: pad.h:535
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:304
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:532
bool operator==(const BOARD_ITEM &aOther) const override
Definition: pad.cpp:1902
void SetOffset(const VECTOR2I &aOffset)
Definition: pad.h:263
PAD_ATTRIB m_attribute
Definition: pad.h:819
PCB_LAYER_ID GetPrincipalLayer() const
Definition: pad.cpp:398
void SetChamferRectRatio(double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition: pad.cpp:506
void SetDirty()
Definition: pad.h:366
const VECTOR2I & GetOffset() const
Definition: pad.h:264
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pad.cpp:370
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pad.cpp:1514
double GetOrientationDegrees() const
Definition: pad.h:353
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pad.cpp:1421
void SetRoundRectCornerRadius(double aRadius)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:489
bool IsNoConnectPad() const
Definition: pad.cpp:336
int GetDrillSizeX() const
Definition: pad.h:259
PAD_PROP m_property
Definition: pad.h:821
void SetKeepTopBottom(bool aSet)
Set whether we keep the top and bottom connections even if they are not connected.
Definition: pad.h:605
VECTOR2I ShapePos() const
Definition: pad.cpp:944
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition: pad.cpp:1798
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition: pad.h:133
std::optional< int > m_solderPasteMargin
Definition: pad.h:845
int GetLocalThermalGapOverride(wxString *aSource=nullptr) const
Definition: pad.cpp:1157
wxString ShowPadAttr() const
Definition: pad.cpp:1448
wxString ShowPadShape() const
Definition: pad.cpp:1432
int m_effectiveBoundingRadius
Definition: pad.h:784
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: pad.h:396
LSET m_layerMask
Definition: pad.h:812
bool GetKeepTopBottom() const
Definition: pad.h:606
int m_thermalGap
Definition: pad.h:860
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:514
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:404
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: pad.h:211
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.h:392
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition: pad.cpp:1679
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:1994
ZONE_CONNECTION m_zoneConnection
Definition: pad.h:856
void SetDelta(const VECTOR2I &aSize)
Definition: pad.h:253
bool IsOnCopperLayer() const override
Definition: pad.cpp:959
void SetDrillSizeX(const int aX)
Definition: pad.h:258
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:195
int m_thermalSpokeWidth
Definition: pad.h:857
VECTOR2I m_pos
Definition: pad.h:762
const VECTOR2I & GetDelta() const
Definition: pad.h:254
void BuildEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:753
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition: pad.cpp:363
void SetDrillSize(const VECTOR2I &aSize)
Definition: pad.h:256
bool IsFreePad() const
Definition: pad.cpp:342
PAD_SHAPE GetShape() const
Definition: pad.h:193
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:345
EDA_ANGLE GetFPRelativeOrientation()
Definition: pad.cpp:870
void Flip(const VECTOR2I &VECTOR2I, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: pad.cpp:879
VECTOR2I GetSolderPasteMargin() const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition: pad.cpp:1075
static LSET ApertureMask()
layer set for an aperture pad
Definition: pad.cpp:377
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pad.cpp:1655
bool m_shapesDirty
Definition: pad.h:775
std::mutex m_polyBuildingLock
Definition: pad.h:782
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:356
std::optional< int > GetLocalSolderPasteMargin() const
Definition: pad.h:398
double m_chamferScale
Definition: pad.h:796
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pad.h:395
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: pad.h:399
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:184
int GetSizeY() const
Definition: pad.h:251
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pad.cpp:392
int GetThermalSpokeWidth() const
Definition: pad.h:522
void SetPinFunction(const wxString &aName)
Set the pad function (pin name in schematic)
Definition: pad.h:144
bool m_polyDirty[2]
Definition: pad.h:781
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:1291
void SetFPRelativeOrientation(const EDA_ANGLE &aAngle)
Definition: pad.cpp:861
std::optional< int > m_clearance
Definition: pad.h:843
PAD_SHAPE m_padShape
Definition: pad.h:764
int GetBoundingRadius() const
Return the radius of a minimum sized circle which fully encloses this pad.
Definition: pad.cpp:569
void SetCustomShapeInZoneOpt(CUST_PAD_SHAPE_IN_ZONE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones.
Definition: pad.h:221
void SetRoundRectRadiusRatio(double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:498
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:232
std::array< ZONE_LAYER_OVERRIDE, MAX_CU_LAYERS > m_zoneLayerOverrides
Definition: pad.h:863
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition: pad.cpp:852
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: pad.cpp:1508
int GetChamferPositions() const
Definition: pad.h:585
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
Definition: pad.cpp:1520
void ReplacePrimitives(const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Clear the current custom shape primitives list and import a new list.
wxString m_number
Definition: pad.h:758
std::optional< double > m_solderPasteMarginRatio
Definition: pad.h:846
bool m_removeUnconnectedLayer
< If true, the pad copper is removed for layers that are not connected.
Definition: pad.h:828
void SetLocalClearance(std::optional< int > aClearance)
Definition: pad.h:393
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pad.cpp:523
int GetSubRatsnest() const
Definition: pad.h:590
void SetSizeX(const int aX)
Definition: pad.h:248
bool m_keepTopBottomLayer
Definition: pad.h:831
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: pad.h:405
int m_lengthPadToDie
Definition: pad.h:825
void SetThermalSpokeWidth(int aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: pad.h:521
void SetSize(const VECTOR2I &aSize)
Definition: pad.h:246
void SetDrillSizeY(const int aY)
Definition: pad.h:260
double GetThermalSpokeAngleDegrees() const
Definition: pad.h:539
double GetRoundRectRadiusRatio() const
Definition: pad.h:566
int GetThermalGap() const
Definition: pad.h:545
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:560
void SetOrientationDegrees(double aOrientation)
Definition: pad.h:349
ZONE_CONNECTION GetZoneConnectionOverrides(wxString *aSource=nullptr) const
Definition: pad.cpp:1128
bool SharesNetTieGroup(const PAD *aOther) const
Definition: pad.cpp:319
const VECTOR2I & GetSize() const
Definition: pad.h:247
EDA_ANGLE m_thermalSpokeAngle
Definition: pad.h:858
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: pad.cpp:1586
void SetSubRatsnest(int aSubRatsnest)
Definition: pad.h:591
std::shared_ptr< SHAPE_COMPOUND > m_effectiveShape
Definition: pad.h:778
void SetChamferPositions(int aPositions)
Has meaning only for chamfered rectangular pads.
Definition: pad.h:584
int GetLocalSpokeWidthOverride(wxString *aSource=nullptr) const
Definition: pad.cpp:1148
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:206
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:1781
double GetChamferRectRatio() const
Definition: pad.h:575
void SetPadToDieLength(int aLength)
Definition: pad.h:389
bool IsFlipped() const
Definition: pad.cpp:384
void SetSizeY(const int aY)
Definition: pad.h:250
int GetPadToDieLength() const
Definition: pad.h:390
BOX2I m_effectiveBoundingBox
Definition: pad.h:777
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:257
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition: property.h:268
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition: property.h:330
PROPERTY_BASE & SetIsHiddenFromLibraryEditors(bool aIsHidden=true)
Definition: property.h:314
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
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()
Definition: property_mgr.h:87
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.
static VALIDATOR_RESULT PositiveIntValidator(const wxAny &&aValue, EDA_ITEM *aItem)
static SEG::ecoord Square(int a)
Definition: seg.h:123
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 Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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 Move(const VECTOR2I &aVector) override
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:42
An abstract shape on 2D plane.
Definition: shape.h:126
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
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.
#define _HKI(x)
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:47
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:48
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
static constexpr EDA_ANGLE ANGLE_45
Definition: eda_angle.h:436
#define FOOTPRINT_EDIT_FRAME_NAME
#define PCB_EDIT_FRAME_NAME
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
Some functions to handle hotkeys in KiCad.
@ LAYER_PAD_FR_NETNAMES
Additional netnames layers (not associated with a PCB layer)
Definition: layer_ids.h:167
@ LAYER_PAD_BK_NETNAMES
Definition: layer_ids.h:168
@ LAYER_PAD_NETNAMES
Definition: layer_ids.h:169
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition: layer_ids.h:955
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:149
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:978
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:881
@ LAYER_FOOTPRINTS_FR
show footprints on front
Definition: layer_ids.h:212
@ LAYER_NON_PLATEDHOLES
handle color for not plated holes (holes, not pads)
Definition: layer_ids.h:201
@ LAYER_PADS
Meta control for all pads opacity/visibility (color ignored)
Definition: layer_ids.h:234
@ LAYER_PAD_PLATEDHOLES
to draw pad holes (plated)
Definition: layer_ids.h:218
@ LAYER_FOOTPRINTS_BK
show footprints on back
Definition: layer_ids.h:213
@ LAYER_PADS_SMD_BK
smd pads, back layer
Definition: layer_ids.h:207
@ LAYER_PADS_TH
multilayer pads, usually with holes
Definition: layer_ids.h:217
@ LAYER_PADS_SMD_FR
smd pads, front layer
Definition: layer_ids.h:206
@ LAYER_PAD_HOLEWALLS
Definition: layer_ids.h:237
bool IsNetnameLayer(int aLayer)
Test whether a layer is a netname layer.
Definition: layer_ids.h:1045
bool IsHoleLayer(int aLayer)
Definition: layer_ids.h:920
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ In30_Cu
Definition: layer_ids.h:94
@ B_Adhes
Definition: layer_ids.h:97
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_SilkS
Definition: layer_ids.h:104
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:112
@ In1_Cu
Definition: layer_ids.h:65
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint.
Definition: lset.cpp:680
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:634
This file contains miscellaneous commonly used macros and functions.
void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:40
Message panel definition file.
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition: eda_units.h:157
T clamp(T min, T value, T max)
Definition: kicad_algo.h:205
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
LSET UnpackLayerSet(const google::protobuf::RepeatedField< int > &aProtoLayerSet)
void PackVector2(kiapi::common::types::Vector2 &aOutput, const VECTOR2I aInput)
Definition: api_utils.cpp:69
VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition: api_utils.cpp:75
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
static struct PAD_DESC _PAD_DESC
@ CUST_PAD_SHAPE_IN_ZONE_OUTLINE
Definition: pad.h:45
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: pad_shapes.h:65
@ PAD_DRILL_SHAPE_CIRCLE
Definition: pad_shapes.h:54
@ PAD_DRILL_SHAPE_OBLONG
Definition: pad_shapes.h:55
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: pad_shapes.h:35
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition: pad_shapes.h:81
#define TYPE_HASH(x)
Definition: property.h:71
#define NO_SETTER(owner, type)
Definition: property.h:774
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:765
#define REGISTER_TYPE(x)
Definition: property_mgr.h:366
wxString UnescapeString(const wxString &aSource)
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
PAD_DESC()
Definition: pad.cpp:2084
constexpr int delta
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:228
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition: zones.h:36