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