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 <lset.h>
45#include <pad.h>
46#include <pcb_shape.h>
48#include <eda_units.h>
50#include <widgets/msgpanel.h>
51#include <pcb_painter.h>
53#include <wx/log.h>
54#include <api/api_enums.h>
55#include <api/api_utils.h>
56#include <api/api_pcb_utils.h>
57#include <api/board/board_types.pb.h>
58
59#include <memory>
60#include <macros.h>
61#include <magic_enum.hpp>
62#include <drc/drc_item.h>
63#include "kiface_base.h"
64#include "pcbnew_settings.h"
65
68
69
70PAD::PAD( FOOTPRINT* parent ) :
72 m_padStack( this )
73{
74 VECTOR2I& drill = m_padStack.Drill().size;
75 VECTOR2I& size = m_padStack.Size();
76 size.x = size.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 60 ); // Default pad size 60 mils.
77 drill.x = drill.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 30 ); // Default drill size 30 mils.
79
82
83 SetShape( PAD_SHAPE::CIRCLE ); // Default pad shape is PAD_CIRCLE.
84 SetAnchorPadShape( PAD_SHAPE::CIRCLE ); // Default shape for custom shaped pads
85 // is PAD_CIRCLE.
86 SetDrillShape( PAD_DRILL_SHAPE::CIRCLE ); // Default pad drill shape is a circle.
87 m_attribute = PAD_ATTRIB::PTH; // Default pad type is plated through hole
88 SetProperty( PAD_PROP::NONE ); // no special fabrication property
89
90 // Parameters for round rect only:
91 m_padStack.SetRoundRectRadiusRatio( 0.25 ); // from IPC-7351C standard
92
93 // Parameters for chamfered rect only:
96
97 // Set layers mask to default for a standard thru hole pad.
99
100 SetSubRatsnest( 0 ); // used in ratsnest calculations
101
102 SetDirty();
104
106}
107
108
109PAD::PAD( const PAD& aOther ) :
110 BOARD_CONNECTED_ITEM( aOther.GetParent(), PCB_PAD_T ),
111 m_padStack( this )
112{
113 PAD::operator=( aOther );
114
115 const_cast<KIID&>( m_Uuid ) = aOther.m_Uuid;
116}
117
118
119PAD& PAD::operator=( const PAD &aOther )
120{
122
123 ImportSettingsFrom( aOther );
125 SetPosition( aOther.GetPosition() );
126 SetNumber( aOther.GetNumber() );
127 SetPinType( aOther.GetPinType() );
128 SetPinFunction( aOther.GetPinFunction() );
129 SetSubRatsnest( aOther.GetSubRatsnest() );
131
132 return *this;
133}
134
135
136void PAD::Serialize( google::protobuf::Any &aContainer ) const
137{
138 using namespace kiapi::board::types;
139 Pad pad;
140
141 pad.mutable_id()->set_value( m_Uuid.AsStdString() );
142 kiapi::common::PackVector2( *pad.mutable_position(), GetPosition() );
143 pad.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
144 : kiapi::common::types::LockedState::LS_UNLOCKED );
145 pad.mutable_net()->mutable_code()->set_value( GetNetCode() );
146 pad.mutable_net()->set_name( GetNetname() );
147 pad.set_type( ToProtoEnum<PAD_ATTRIB, PadType>( GetAttribute() ) );
148
149 google::protobuf::Any padStackMsg;
150 m_padStack.Serialize( padStackMsg );
151 padStackMsg.UnpackTo( pad.mutable_pad_stack() );
152
153 DesignRuleOverrides* overrides = pad.mutable_overrides();
154
155 if( GetLocalClearance().has_value() )
156 overrides->mutable_clearance()->set_value_nm( *GetLocalClearance() );
157
158 if( GetLocalSolderMaskMargin().has_value() )
159 overrides->mutable_solder_mask_margin()->set_value_nm( *GetLocalSolderMaskMargin() );
160
161 if( GetLocalSolderPasteMargin().has_value() )
162 overrides->mutable_solder_paste_margin()->set_value_nm( *GetLocalSolderPasteMargin() );
163
164 if( GetLocalSolderPasteMarginRatio().has_value() )
165 overrides->mutable_solder_paste_margin_ratio()->set_value( *GetLocalSolderPasteMarginRatio() );
166
167 overrides->set_zone_connection(
168 ToProtoEnum<ZONE_CONNECTION, ZoneConnectionStyle>( GetLocalZoneConnection() ) );
169
170 ThermalSpokeSettings* thermals = pad.mutable_thermal_spokes();
171
172 thermals->set_width( GetThermalSpokeWidth() );
173 thermals->set_gap( GetThermalGap() );
174 thermals->mutable_angle()->set_value_degrees( GetThermalSpokeAngleDegrees() );
175
176 aContainer.PackFrom( pad );
177}
178
179
180bool PAD::Deserialize( const google::protobuf::Any &aContainer )
181{
182 kiapi::board::types::Pad pad;
183
184 if( !aContainer.UnpackTo( &pad ) )
185 return false;
186
187 const_cast<KIID&>( m_Uuid ) = KIID( pad.id().value() );
189 SetNetCode( pad.net().code().value() );
190 SetLocked( pad.locked() == kiapi::common::types::LockedState::LS_LOCKED );
191 SetAttribute( FromProtoEnum<PAD_ATTRIB>( pad.type() ) );
192
193 google::protobuf::Any padStackWrapper;
194 padStackWrapper.PackFrom( pad.pad_stack() );
195 m_padStack.Deserialize( padStackWrapper );
196
198
199 const kiapi::board::types::DesignRuleOverrides& overrides = pad.overrides();
200
201 if( overrides.has_clearance() )
202 SetLocalClearance( overrides.clearance().value_nm() );
203 else
204 SetLocalClearance( std::nullopt );
205
206 if( overrides.has_solder_mask_margin() )
207 SetLocalSolderMaskMargin( overrides.solder_mask_margin().value_nm() );
208 else
209 SetLocalSolderMaskMargin( std::nullopt );
210
211 if( overrides.has_solder_paste_margin() )
212 SetLocalSolderPasteMargin( overrides.solder_paste_margin().value_nm() );
213 else
214 SetLocalSolderPasteMargin( std::nullopt );
215
216 if( overrides.has_solder_paste_margin_ratio() )
217 SetLocalSolderPasteMarginRatio( overrides.solder_paste_margin_ratio().value() );
218 else
219 SetLocalSolderPasteMarginRatio( std::nullopt );
220
221 SetLocalZoneConnection( FromProtoEnum<ZONE_CONNECTION>( overrides.zone_connection() ) );
222
223 const kiapi::board::types::ThermalSpokeSettings& thermals = pad.thermal_spokes();
224
225 SetThermalGap( thermals.gap() );
226 SetThermalSpokeWidth( thermals.width() );
227 SetThermalSpokeAngleDegrees( thermals.angle().value_degrees() );
228
229 return true;
230}
231
232
234{
235 // Aperture pads don't get a number
236 if( IsAperturePad() )
237 return false;
238
239 // NPTH pads don't get numbers
240 if( GetAttribute() == PAD_ATTRIB::NPTH )
241 return false;
242
243 return true;
244}
245
246
247bool PAD::IsLocked() const
248{
249 if( GetParent() && GetParent()->IsLocked() )
250 return true;
251
252 return BOARD_ITEM::IsLocked();
253};
254
255
256bool PAD::SharesNetTieGroup( const PAD* aOther ) const
257{
258 FOOTPRINT* parentFp = GetParentFootprint();
259
260 if( parentFp && parentFp->IsNetTie() && aOther->GetParentFootprint() == parentFp )
261 {
262 std::map<wxString, int> padToNetTieGroupMap = parentFp->MapPadNumbersToNetTieGroups();
263 int thisNetTieGroup = padToNetTieGroupMap[ GetNumber() ];
264 int otherNetTieGroup = padToNetTieGroupMap[ aOther->GetNumber() ];
265
266 return thisNetTieGroup >= 0 && thisNetTieGroup == otherNetTieGroup;
267 }
268
269 return false;
270}
271
272
274{
275 return m_pinType.Contains( wxT( "no_connect" ) );
276}
277
278
279bool PAD::IsFreePad() const
280{
281 return GetShortNetname().StartsWith( wxT( "unconnected-(" ) )
282 && m_pinType == wxT( "free" );
283}
284
285
287{
288 static LSET saved = LSET::AllCuMask() | LSET( { F_Mask, B_Mask } );
289 return saved;
290}
291
292
294{
295 static LSET saved( { F_Cu, F_Paste, F_Mask } );
296 return saved;
297}
298
299
301{
302 static LSET saved( { F_Cu, F_Mask } );
303 return saved;
304}
305
306
308{
309 static LSET saved = LSET( { F_Cu, B_Cu, F_Mask, B_Mask } );
310 return saved;
311}
312
313
315{
316 static LSET saved( F_Paste );
317 return saved;
318}
319
320
321bool PAD::IsFlipped() const
322{
323 FOOTPRINT* parent = GetParentFootprint();
324
325 return ( parent && parent->GetLayer() == B_Cu );
326}
327
328
330{
331 return BOARD_ITEM::GetLayer();
332}
333
334
336{
337 if( m_attribute == PAD_ATTRIB::SMD || m_attribute == PAD_ATTRIB::CONN || GetLayerSet().none() )
338 return m_layer;
339 else
340 return GetLayerSet().Seq().front();
341
342}
343
344
345bool PAD::FlashLayer( LSET aLayers ) const
346{
347 for( PCB_LAYER_ID layer : aLayers.Seq() )
348 {
349 if( FlashLayer( layer ) )
350 return true;
351 }
352
353 return false;
354}
355
356
357bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
358{
359 if( aLayer == UNDEFINED_LAYER )
360 return true;
361
362 if( !IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) ) )
363 return false;
364
365 if( GetAttribute() == PAD_ATTRIB::NPTH && IsCopperLayer( aLayer ) )
366 {
367 if( GetShape() == PAD_SHAPE::CIRCLE && GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
368 {
369 if( GetOffset() == VECTOR2I( 0, 0 ) && GetDrillSize().x >= GetSize().x )
370 return false;
371 }
372 else if( GetShape() == PAD_SHAPE::OVAL && GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
373 {
374 if( GetOffset() == VECTOR2I( 0, 0 )
375 && GetDrillSize().x >= GetSize().x && GetDrillSize().y >= GetSize().y )
376 {
377 return false;
378 }
379 }
380 }
381
382 if( LSET::FrontBoardTechMask().test( aLayer ) )
383 aLayer = F_Cu;
384 else if( LSET::BackBoardTechMask().test( aLayer ) )
385 aLayer = B_Cu;
386
387 if( GetAttribute() == PAD_ATTRIB::PTH && IsCopperLayer( aLayer ) )
388 {
390 if( GetProperty() == PAD_PROP::HEATSINK )
391 return true;
392
394
396 return true;
397
398 // Plated through hole pads need copper on the top/bottom layers for proper soldering
399 // Unless the user has removed them in the pad dialog
401 && ( aLayer == F_Cu || aLayer == B_Cu ) )
402 {
403 return true;
404 }
405
406 if( const BOARD* board = GetBoard() )
407 {
408 // Must be static to keep from raising its ugly head in performance profiles
409 static std::initializer_list<KICAD_T> types = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
410 PCB_PAD_T };
411
412 if( m_zoneLayerOverrides[ aLayer ] == ZLO_FORCE_FLASHED )
413 return true;
414 else if( aOnlyCheckIfPermitted )
415 return true;
416 else
417 return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, types );
418 }
419 }
420
421 return true;
422}
423
424
426{
428}
429
430
431void PAD::SetRoundRectCornerRadius( double aRadius )
432{
434}
435
436
437void PAD::SetRoundRectRadiusRatio( double aRadiusScale )
438{
439 m_padStack.SetRoundRectRadiusRatio( alg::clamp( 0.0, aRadiusScale, 0.5 ) );
440
441 SetDirty();
442}
443
444
445void PAD::SetChamferRectRatio( double aChamferScale )
446{
447 m_padStack.SetChamferRatio( alg::clamp( 0.0, aChamferScale, 0.5 ) );
448
449 SetDirty();
450}
451
452
453const std::shared_ptr<SHAPE_POLY_SET>& PAD::GetEffectivePolygon( ERROR_LOC aErrorLoc ) const
454{
455 if( m_polyDirty[ aErrorLoc ] )
456 BuildEffectivePolygon( aErrorLoc );
457
458 return m_effectivePolygon[ aErrorLoc ];
459}
460
461
462std::shared_ptr<SHAPE> PAD::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING flashPTHPads ) const
463{
464 if( aLayer == Edge_Cuts )
465 {
466 if( GetAttribute() == PAD_ATTRIB::PTH || GetAttribute() == PAD_ATTRIB::NPTH )
467 return GetEffectiveHoleShape();
468 else
469 return std::make_shared<SHAPE_NULL>();
470 }
471
472 if( GetAttribute() == PAD_ATTRIB::PTH )
473 {
474 bool flash;
475
476 if( flashPTHPads == FLASHING::NEVER_FLASHED )
477 flash = false;
478 else if( flashPTHPads == FLASHING::ALWAYS_FLASHED )
479 flash = true;
480 else
481 flash = FlashLayer( aLayer );
482
483 if( !flash )
484 {
485 if( GetAttribute() == PAD_ATTRIB::PTH )
486 return GetEffectiveHoleShape();
487 else
488 return std::make_shared<SHAPE_NULL>();
489 }
490 }
491
492 if( m_shapesDirty )
493 BuildEffectiveShapes( aLayer );
494
495 return m_effectiveShape;
496}
497
498
499std::shared_ptr<SHAPE_SEGMENT> PAD::GetEffectiveHoleShape() const
500{
501 if( m_shapesDirty )
503
505}
506
507
509{
512
514}
515
516
518{
519 std::lock_guard<std::mutex> RAII_lock( m_shapesBuildingLock );
520
521 // If we had to wait for the lock then we were probably waiting for someone else to
522 // finish rebuilding the shapes. So check to see if they're clean now.
523 if( !m_shapesDirty )
524 return;
525
526 const BOARD* board = GetBoard();
527 int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
528
529 m_effectiveShape = std::make_shared<SHAPE_COMPOUND>();
530 m_effectiveHoleShape = nullptr;
531
532 auto add = [this]( SHAPE* aShape )
533 {
534 m_effectiveShape->AddShape( aShape );
535 };
536
537 VECTOR2I shapePos = ShapePos(); // Fetch only once; rotation involves trig
538 PAD_SHAPE effectiveShape = GetShape();
539 const VECTOR2I& size = m_padStack.Size( aLayer );
540
541 if( GetShape() == PAD_SHAPE::CUSTOM )
542 effectiveShape = GetAnchorPadShape();
543
544 switch( effectiveShape )
545 {
546 case PAD_SHAPE::CIRCLE:
547 add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
548 break;
549
550 case PAD_SHAPE::OVAL:
551 if( size.x == size.y ) // the oval pad is in fact a circle
552 {
553 add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
554 }
555 else
556 {
557 VECTOR2I half_size = size / 2;
558 int half_width = std::min( half_size.x, half_size.y );
559 VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
560 RotatePoint( half_len, GetOrientation() );
561 add( new SHAPE_SEGMENT( shapePos - half_len, shapePos + half_len, half_width * 2 ) );
562 }
563
564 break;
565
566 case PAD_SHAPE::RECTANGLE:
567 case PAD_SHAPE::TRAPEZOID:
568 case PAD_SHAPE::ROUNDRECT:
569 {
570 int r = ( effectiveShape == PAD_SHAPE::ROUNDRECT ) ? GetRoundRectCornerRadius() : 0;
571 VECTOR2I half_size( size.x / 2, size.y / 2 );
572 VECTOR2I trap_delta( 0, 0 );
573
574 if( r )
575 {
576 half_size -= VECTOR2I( r, r );
577
578 // Avoid degenerated shapes (0 length segments) that always create issues
579 // For roundrect pad very near a circle, use only a circle
580 const int min_len = pcbIUScale.mmToIU( 0.0001);
581
582 if( half_size.x < min_len && half_size.y < min_len )
583 {
584 add( new SHAPE_CIRCLE( shapePos, r ) );
585 break;
586 }
587 }
588 else if( effectiveShape == PAD_SHAPE::TRAPEZOID )
589 {
590 trap_delta = m_padStack.TrapezoidDeltaSize( aLayer ) / 2;
591 }
592
593 SHAPE_LINE_CHAIN corners;
594
595 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
596 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
597 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
598 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
599
600 corners.Rotate( GetOrientation() );
601 corners.Move( shapePos );
602
603 // GAL renders rectangles faster than 4-point polygons so it's worth checking if our
604 // body shape is a rectangle.
605 if( corners.PointCount() == 4
606 &&
607 ( ( corners.CPoint( 0 ).y == corners.CPoint( 1 ).y
608 && corners.CPoint( 1 ).x == corners.CPoint( 2 ).x
609 && corners.CPoint( 2 ).y == corners.CPoint( 3 ).y
610 && corners.CPoint( 3 ).x == corners.CPoint( 0 ).x )
611 ||
612 ( corners.CPoint( 0 ).x == corners.CPoint( 1 ).x
613 && corners.CPoint( 1 ).y == corners.CPoint( 2 ).y
614 && corners.CPoint( 2 ).x == corners.CPoint( 3 ).x
615 && corners.CPoint( 3 ).y == corners.CPoint( 0 ).y )
616 )
617 )
618 {
619 int width = std::abs( corners.CPoint( 2 ).x - corners.CPoint( 0 ).x );
620 int height = std::abs( corners.CPoint( 2 ).y - corners.CPoint( 0 ).y );
621 VECTOR2I pos( std::min( corners.CPoint( 2 ).x, corners.CPoint( 0 ).x ),
622 std::min( corners.CPoint( 2 ).y, corners.CPoint( 0 ).y ) );
623
624 add( new SHAPE_RECT( pos, width, height ) );
625 }
626 else
627 {
628 add( new SHAPE_SIMPLE( corners ) );
629 }
630
631 if( r )
632 {
633 add( new SHAPE_SEGMENT( corners.CPoint( 0 ), corners.CPoint( 1 ), r * 2 ) );
634 add( new SHAPE_SEGMENT( corners.CPoint( 1 ), corners.CPoint( 2 ), r * 2 ) );
635 add( new SHAPE_SEGMENT( corners.CPoint( 2 ), corners.CPoint( 3 ), r * 2 ) );
636 add( new SHAPE_SEGMENT( corners.CPoint( 3 ), corners.CPoint( 0 ), r * 2 ) );
637 }
638 }
639 break;
640
641 case PAD_SHAPE::CHAMFERED_RECT:
642 {
643 SHAPE_POLY_SET outline;
644
647 GetChamferPositions(), 0, maxError, ERROR_INSIDE );
648
649 add( new SHAPE_SIMPLE( outline.COutline( 0 ) ) );
650 }
651 break;
652
653 default:
654 wxFAIL_MSG( wxT( "PAD::buildEffectiveShapes: Unsupported pad shape: PAD_SHAPE::" )
655 + wxString( std::string( magic_enum::enum_name( effectiveShape ) ) ) );
656 break;
657 }
658
659 if( GetShape() == PAD_SHAPE::CUSTOM )
660 {
661 for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives() )
662 {
663 if( !primitive->IsProxyItem() )
664 {
665 for( SHAPE* shape : primitive->MakeEffectiveShapes() )
666 {
667 shape->Rotate( GetOrientation() );
668 shape->Move( shapePos );
669 add( shape );
670 }
671 }
672 }
673 }
674
676
677 // Hole shape
678 VECTOR2I half_size = m_padStack.Drill().size / 2;
679 int half_width = std::min( half_size.x, half_size.y );
680 VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
681
682 RotatePoint( half_len, GetOrientation() );
683
684 m_effectiveHoleShape = std::make_shared<SHAPE_SEGMENT>( m_pos - half_len, m_pos + half_len,
685 half_width * 2 );
687
688 // All done
689 m_shapesDirty = false;
690}
691
692
694{
695 std::lock_guard<std::mutex> RAII_lock( m_polyBuildingLock );
696
697 // If we had to wait for the lock then we were probably waiting for someone else to
698 // finish rebuilding the shapes. So check to see if they're clean now.
699 if( !m_polyDirty[ aErrorLoc ] )
700 return;
701
702 const BOARD* board = GetBoard();
703 int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
704
705 // Polygon
706 std::shared_ptr<SHAPE_POLY_SET>& effectivePolygon = m_effectivePolygon[ aErrorLoc ];
707
708 effectivePolygon = std::make_shared<SHAPE_POLY_SET>();
709 TransformShapeToPolygon( *effectivePolygon, UNDEFINED_LAYER, 0, maxError, aErrorLoc );
710
711 // Bounding radius
712 //
713 // PADSTACKS TODO: these will both need to cycle through all layers to get the largest
714 // values....
715 if( aErrorLoc == ERROR_OUTSIDE )
716 {
718
719 for( int cnt = 0; cnt < effectivePolygon->OutlineCount(); ++cnt )
720 {
721 const SHAPE_LINE_CHAIN& poly = effectivePolygon->COutline( cnt );
722
723 for( int ii = 0; ii < poly.PointCount(); ++ii )
724 {
725 int dist = KiROUND( ( poly.CPoint( ii ) - m_pos ).EuclideanNorm() );
727 }
728 }
729 }
730
731 // All done
732 m_polyDirty[ aErrorLoc ] = false;
733}
734
735
737{
738 if( m_shapesDirty )
740
742}
743
744
746{
747 if( m_attribute != aAttribute )
748 {
749 m_attribute = aAttribute;
750
751 LSET& layerMask = m_padStack.LayerSet();
752
753 switch( aAttribute )
754 {
755 case PAD_ATTRIB::PTH:
756 // Plump up to all copper layers
757 layerMask |= LSET::AllCuMask();
758 break;
759
760 case PAD_ATTRIB::SMD:
761 case PAD_ATTRIB::CONN:
762 {
763 // Trim down to no more than one copper layer
764 LSET copperLayers = layerMask & LSET::AllCuMask();
765
766 if( copperLayers.count() > 1 )
767 {
768 layerMask &= ~LSET::AllCuMask();
769
770 if( copperLayers.test( B_Cu ) )
771 layerMask.set( B_Cu );
772 else
773 layerMask.set( copperLayers.Seq().front() );
774 }
775
776 // No hole
777 m_padStack.Drill().size = VECTOR2I( 0, 0 );
778 break;
779 }
780
781 case PAD_ATTRIB::NPTH:
782 // No number; no net
783 m_number = wxEmptyString;
785 break;
786 }
787 }
788
789 SetDirty();
790}
791
792
793void PAD::SetProperty( PAD_PROP aProperty )
794{
795 m_property = aProperty;
796
797 SetDirty();
798}
799
800
801void PAD::SetOrientation( const EDA_ANGLE& aAngle )
802{
803 m_padStack.SetOrientation( aAngle );
804 SetDirty();
805}
806
807
809{
810 if( FOOTPRINT* parentFP = GetParentFootprint() )
811 SetOrientation( aAngle + parentFP->GetOrientation() );
812 else
813 SetOrientation( aAngle );
814}
815
816
818{
819 if( FOOTPRINT* parentFP = GetParentFootprint() )
820 return GetOrientation() - parentFP->GetOrientation();
821 else
822 return GetOrientation();
823}
824
825
826void PAD::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
827{
828 if( aFlipLeftRight )
829 {
830 MIRROR( m_pos.x, aCentre.x );
831 MIRROR( m_padStack.Offset().x, 0 );
833 }
834 else
835 {
836 MIRROR( m_pos.y, aCentre.y );
837 MIRROR( m_padStack.Offset().y, 0 );
839 }
840
842
843 auto mirrorBitFlags = []( int& aBitfield, int a, int b )
844 {
845 bool temp = aBitfield & a;
846
847 if( aBitfield & b )
848 aBitfield |= a;
849 else
850 aBitfield &= ~a;
851
852 if( temp )
853 aBitfield |= b;
854 else
855 aBitfield &= ~b;
856 };
857
858 if( aFlipLeftRight )
859 {
864 }
865 else
866 {
871 }
872
873 // flip pads layers
874 // PADS items are currently on all copper layers, or
875 // currently, only on Front or Back layers.
876 // So the copper layers count is not taken in account
877 LSET layerSet = m_padStack.LayerSet();
878 SetLayerSet( layerSet.Flip() );
879
880 // Flip the basic shapes, in custom pads
881 FlipPrimitives( aFlipLeftRight );
882
883 SetDirty();
884}
885
886
887void PAD::FlipPrimitives( bool aFlipLeftRight )
888{
889 for( std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives() )
890 primitive->Flip( VECTOR2I( 0, 0 ), aFlipLeftRight );
891
892 SetDirty();
893}
894
895
897{
898 if( m_padStack.Offset().x == 0 && m_padStack.Offset().y == 0 )
899 return m_pos;
900
901 VECTOR2I loc_offset = m_padStack.Offset();
902
903 RotatePoint( loc_offset, GetOrientation() );
904
905 VECTOR2I shape_pos = m_pos + loc_offset;
906
907 return shape_pos;
908}
909
910
912{
913 if( GetAttribute() == PAD_ATTRIB::NPTH )
914 {
915 // NPTH pads have no plated hole cylinder. If their annular ring size is 0 or
916 // negative, then they have no annular ring either.
917
918 switch( GetShape() )
919 {
920 case PAD_SHAPE::CIRCLE:
921 if( m_padStack.Offset() == VECTOR2I( 0, 0 )
923 {
924 return false;
925 }
926
927 break;
928
929 case PAD_SHAPE::OVAL:
930 if( m_padStack.Offset() == VECTOR2I( 0, 0 )
933 {
934 return false;
935 }
936
937 break;
938
939 default:
940 // We could subtract the hole polygon from the shape polygon for these, but it
941 // would be expensive and we're probably well out of the common use cases....
942 break;
943 }
944 }
945
946 return ( GetLayerSet() & LSET::AllCuMask() ).any();
947}
948
949
950std::optional<int> PAD::GetLocalClearance( wxString* aSource ) const
951{
952 if( m_padStack.Clearance().has_value() && aSource )
953 *aSource = _( "pad" );
954
955 return m_padStack.Clearance();
956}
957
958
959std::optional<int> PAD::GetClearanceOverrides( wxString* aSource ) const
960{
961 if( m_padStack.Clearance().has_value() )
962 return GetLocalClearance( aSource );
963
964 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
965 return parentFootprint->GetClearanceOverrides( aSource );
966
967 return std::optional<int>();
968}
969
970
971int PAD::GetOwnClearance( PCB_LAYER_ID aLayer, wxString* aSource ) const
972{
974
975 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
976 {
978
979 if( GetAttribute() == PAD_ATTRIB::NPTH )
980 c = bds.m_DRCEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, this, nullptr, aLayer );
981 else
982 c = bds.m_DRCEngine->EvalRules( CLEARANCE_CONSTRAINT, this, nullptr, aLayer );
983 }
984
985 if( c.Value().HasMin() )
986 {
987 if( aSource )
988 *aSource = c.GetName();
989
990 return c.Value().Min();
991 }
992
993 return 0;
994}
995
996
998{
999 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
1000 // defined by the pad settings only. ALL other pads, even those that don't actually have
1001 // any copper (such as NPTH pads with holes the same size as the pad) get mask expansion.
1002 if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
1003 return 0;
1004
1005 std::optional<int> margin = m_padStack.SolderMaskMargin();
1006
1007 if( !margin.has_value() )
1008 {
1009 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1010 margin = parentFootprint->GetLocalSolderMaskMargin();
1011 }
1012
1013 if( !margin.has_value() )
1014 {
1015 if( const BOARD* brd = GetBoard() )
1016 margin = brd->GetDesignSettings().m_SolderMaskExpansion;
1017 }
1018
1019 int marginValue = margin.value_or( 0 );
1020
1021 // ensure mask have a size always >= 0
1022 if( marginValue < 0 )
1023 {
1024 int minsize = -std::min( m_padStack.Size().x, m_padStack.Size().y ) / 2;
1025
1026 if( marginValue < minsize )
1027 marginValue = minsize;
1028 }
1029
1030 return marginValue;
1031}
1032
1033
1035{
1036 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
1037 // defined by the pad settings only. ALL other pads, even those that don't actually have
1038 // any copper (such as NPTH pads with holes the same size as the pad) get paste expansion.
1039 if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
1040 return VECTOR2I( 0, 0 );
1041
1042 std::optional<int> margin = m_padStack.SolderPasteMargin();
1043 std::optional<double> mratio = m_padStack.SolderPasteMarginRatio();
1044
1045 if( !margin.has_value() )
1046 {
1047 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1048 margin = parentFootprint->GetLocalSolderPasteMargin();
1049 }
1050
1051 if( !margin.has_value() )
1052 {
1053 if( const BOARD* board = GetBoard() )
1054 margin = board->GetDesignSettings().m_SolderPasteMargin;
1055 }
1056
1057 if( !mratio.has_value() )
1058 {
1059 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1060 mratio = parentFootprint->GetLocalSolderPasteMarginRatio();
1061 }
1062
1063 if( !mratio.has_value() )
1064 {
1065 if( const BOARD* board = GetBoard() )
1066 mratio = board->GetDesignSettings().m_SolderPasteMarginRatio;
1067 }
1068
1069 VECTOR2I pad_margin;
1070 pad_margin.x = margin.value_or( 0 ) + KiROUND( m_padStack.Size().x * mratio.value_or( 0 ) );
1071 pad_margin.y = margin.value_or( 0 ) + KiROUND( m_padStack.Size().y * mratio.value_or( 0 ) );
1072
1073 // ensure mask have a size always >= 0
1074 if( m_padStack.Shape() != PAD_SHAPE::CUSTOM )
1075 {
1076 if( pad_margin.x < -m_padStack.Size().x / 2 )
1077 pad_margin.x = -m_padStack.Size().x / 2;
1078
1079 if( pad_margin.y < -m_padStack.Size().y / 2 )
1080 pad_margin.y = -m_padStack.Size().y / 2;
1081 }
1082
1083 return pad_margin;
1084}
1085
1086
1088{
1089 ZONE_CONNECTION connection = m_padStack.ZoneConnection().value_or( ZONE_CONNECTION::INHERITED );
1090
1091 if( connection != ZONE_CONNECTION::INHERITED )
1092 {
1093 if( aSource )
1094 *aSource = _( "pad" );
1095 }
1096
1097 if( connection == ZONE_CONNECTION::INHERITED )
1098 {
1099 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1100 connection = parentFootprint->GetZoneConnectionOverrides( aSource );
1101 }
1102
1103 return connection;
1104}
1105
1106
1107int PAD::GetLocalSpokeWidthOverride( wxString* aSource ) const
1108{
1109 if( m_padStack.ThermalSpokeWidth().has_value() && aSource )
1110 *aSource = _( "pad" );
1111
1112 return m_padStack.ThermalSpokeWidth().value_or( 0 );
1113}
1114
1115
1116int PAD::GetLocalThermalGapOverride( wxString* aSource ) const
1117{
1118 if( m_padStack.ThermalGap().has_value() && aSource )
1119 *aSource = _( "pad" );
1120
1121 return m_padStack.ThermalGap().value_or( 0 );
1122}
1123
1124
1125void PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1126{
1127 wxString msg;
1128 FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( m_parent );
1129
1130 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1131 {
1132 if( parentFootprint )
1133 aList.emplace_back( _( "Footprint" ), parentFootprint->GetReference() );
1134 }
1135
1136 aList.emplace_back( _( "Pad" ), m_number );
1137
1138 if( !GetPinFunction().IsEmpty() )
1139 aList.emplace_back( _( "Pin Name" ), GetPinFunction() );
1140
1141 if( !GetPinType().IsEmpty() )
1142 aList.emplace_back( _( "Pin Type" ), GetPinType() );
1143
1144 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1145 {
1146 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
1147
1148 aList.emplace_back( _( "Resolved Netclass" ),
1149 UnescapeString( GetEffectiveNetClass()->GetName() ) );
1150
1151 if( IsLocked() )
1152 aList.emplace_back( _( "Status" ), _( "Locked" ) );
1153 }
1154
1155 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1156 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
1157
1158 if( aFrame->GetName() == FOOTPRINT_EDIT_FRAME_NAME )
1159 {
1160 if( GetAttribute() == PAD_ATTRIB::SMD )
1161 {
1162 const std::shared_ptr<SHAPE_POLY_SET>& poly = PAD::GetEffectivePolygon();
1163 double area = poly->Area();
1164
1165 aList.emplace_back( _( "Area" ), aFrame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
1166 }
1167 }
1168
1169 // Show the pad shape, attribute and property
1170 wxString props = ShowPadAttr();
1171
1172 if( GetProperty() != PAD_PROP::NONE )
1173 props += ',';
1174
1175 switch( GetProperty() )
1176 {
1177 case PAD_PROP::NONE: break;
1178 case PAD_PROP::BGA: props += _( "BGA" ); break;
1179 case PAD_PROP::FIDUCIAL_GLBL: props += _( "Fiducial global" ); break;
1180 case PAD_PROP::FIDUCIAL_LOCAL: props += _( "Fiducial local" ); break;
1181 case PAD_PROP::TESTPOINT: props += _( "Test point" ); break;
1182 case PAD_PROP::HEATSINK: props += _( "Heat sink" ); break;
1183 case PAD_PROP::CASTELLATED: props += _( "Castellated" ); break;
1184 case PAD_PROP::MECHANICAL: props += _( "Mechanical" ); break;
1185 }
1186
1187 aList.emplace_back( ShowPadShape(), props );
1188
1189 if( ( GetShape() == PAD_SHAPE::CIRCLE || GetShape() == PAD_SHAPE::OVAL )
1190 && m_padStack.Size().x == m_padStack.Size().y )
1191 {
1192 aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( m_padStack.Size().x ) );
1193 }
1194 else
1195 {
1196 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( m_padStack.Size().x ) );
1197 aList.emplace_back( _( "Height" ), aFrame->MessageTextFromValue( m_padStack.Size().y ) );
1198 }
1199
1200 EDA_ANGLE fp_orient = parentFootprint ? parentFootprint->GetOrientation() : ANGLE_0;
1201 EDA_ANGLE pad_orient = GetOrientation() - fp_orient;
1202 pad_orient.Normalize180();
1203
1204 if( !fp_orient.IsZero() )
1205 msg.Printf( wxT( "%g(+ %g)" ), pad_orient.AsDegrees(), fp_orient.AsDegrees() );
1206 else
1207 msg.Printf( wxT( "%g" ), GetOrientation().AsDegrees() );
1208
1209 aList.emplace_back( _( "Rotation" ), msg );
1210
1211 if( GetPadToDieLength() )
1212 {
1213 aList.emplace_back( _( "Length in Package" ),
1215 }
1216
1217 const VECTOR2I& drill = m_padStack.Drill().size;
1218
1219 if( drill.x > 0 || drill.y > 0 )
1220 {
1221 if( GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
1222 {
1223 aList.emplace_back( _( "Hole" ),
1224 wxString::Format( wxT( "%s" ),
1225 aFrame->MessageTextFromValue( drill.x ) ) );
1226 }
1227 else
1228 {
1229 aList.emplace_back( _( "Hole X / Y" ),
1230 wxString::Format( wxT( "%s / %s" ),
1231 aFrame->MessageTextFromValue( drill.x ),
1232 aFrame->MessageTextFromValue( drill.y ) ) );
1233 }
1234 }
1235
1236 wxString source;
1237 int clearance = GetOwnClearance( UNDEFINED_LAYER, &source );
1238
1239 if( !source.IsEmpty() )
1240 {
1241 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
1242 aFrame->MessageTextFromValue( clearance ) ),
1243 wxString::Format( _( "(from %s)" ),
1244 source ) );
1245 }
1246#if 0
1247 // useful for debug only
1248 aList.emplace_back( wxT( "UUID" ), m_Uuid.AsString() );
1249#endif
1250}
1251
1252
1253bool PAD::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
1254{
1255 VECTOR2I delta = aPosition - GetPosition();
1256 int boundingRadius = GetBoundingRadius() + aAccuracy;
1257
1258 if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
1259 return false;
1260
1261 return GetEffectivePolygon( ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy );
1262}
1263
1264
1265bool PAD::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1266{
1267 BOX2I arect = aRect;
1268 arect.Normalize();
1269 arect.Inflate( aAccuracy );
1270
1271 BOX2I bbox = GetBoundingBox();
1272
1273 if( aContained )
1274 {
1275 return arect.Contains( bbox );
1276 }
1277 else
1278 {
1279 // Fast test: if aRect is outside the polygon bounding box,
1280 // rectangles cannot intersect
1281 if( !arect.Intersects( bbox ) )
1282 return false;
1283
1284 const std::shared_ptr<SHAPE_POLY_SET>& poly = GetEffectivePolygon( ERROR_INSIDE );
1285
1286 int count = poly->TotalVertices();
1287
1288 for( int ii = 0; ii < count; ii++ )
1289 {
1290 VECTOR2I vertex = poly->CVertex( ii );
1291 VECTOR2I vertexNext = poly->CVertex( ( ii + 1 ) % count );
1292
1293 // Test if the point is within aRect
1294 if( arect.Contains( vertex ) )
1295 return true;
1296
1297 // Test if this edge intersects aRect
1298 if( arect.Intersects( vertex, vertexNext ) )
1299 return true;
1300 }
1301
1302 return false;
1303 }
1304}
1305
1306
1307int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
1308{
1309 int diff;
1310
1311 // TODO(JE) move padstack comparision into PADSTACK
1312
1313 if( ( diff = static_cast<int>( aPadRef->GetShape() ) -
1314 static_cast<int>( aPadCmp->GetShape() ) ) != 0 )
1315 return diff;
1316
1317 if( ( diff = static_cast<int>( aPadRef->m_attribute ) -
1318 static_cast<int>( aPadCmp->m_attribute ) ) != 0 )
1319 return diff;
1320
1321 if( ( diff = static_cast<int>( aPadRef->GetDrillShape() ) -
1322 static_cast<int>( aPadCmp->GetDrillShape() ) ) != 0 )
1323 return diff;
1324
1325 if( ( diff = aPadRef->Padstack().Drill().size.x - aPadCmp->Padstack().Drill().size.x ) != 0 )
1326 return diff;
1327
1328 if( ( diff = aPadRef->Padstack().Drill().size.y - aPadCmp->Padstack().Drill().size.y ) != 0 )
1329 return diff;
1330
1331 if( ( diff = aPadRef->m_padStack.Size().x - aPadCmp->m_padStack.Size().x ) != 0 )
1332 return diff;
1333
1334 if( ( diff = aPadRef->m_padStack.Size().y - aPadCmp->m_padStack.Size().y ) != 0 )
1335 return diff;
1336
1337 if( ( diff = aPadRef->m_padStack.Offset().x - aPadCmp->m_padStack.Offset().x ) != 0 )
1338 return diff;
1339
1340 if( ( diff = aPadRef->m_padStack.Offset().y - aPadCmp->m_padStack.Offset().y ) != 0 )
1341 return diff;
1342
1343 if( ( diff = aPadRef->m_padStack.TrapezoidDeltaSize().x
1344 - aPadCmp->m_padStack.TrapezoidDeltaSize().x )
1345 != 0 )
1346 {
1347 return diff;
1348 }
1349
1350 if( ( diff = aPadRef->m_padStack.TrapezoidDeltaSize().y
1351 - aPadCmp->m_padStack.TrapezoidDeltaSize().y )
1352 != 0 )
1353 {
1354 return diff;
1355 }
1356
1357 if( ( diff = aPadRef->m_padStack.RoundRectRadiusRatio()
1358 - aPadCmp->m_padStack.RoundRectRadiusRatio() )
1359 != 0 )
1360 {
1361 return diff;
1362 }
1363
1364 if( ( diff = aPadRef->m_padStack.ChamferPositions() - aPadCmp->m_padStack.ChamferPositions() ) != 0 )
1365 return diff;
1366
1367 if( ( diff = aPadRef->m_padStack.ChamferRatio() - aPadCmp->m_padStack.ChamferRatio() ) != 0 )
1368 return diff;
1369
1370 if( ( diff = static_cast<int>( aPadRef->m_padStack.Primitives().size() ) -
1371 static_cast<int>( aPadCmp->m_padStack.Primitives().size() ) ) != 0 )
1372 return diff;
1373
1374 // @todo: Compare custom pad primitives for pads that have the same number of primitives
1375 // here. Currently there is no compare function for PCB_SHAPE objects.
1376
1377 // Dick: specctra_export needs this
1378 // Lorenzo: gencad also needs it to implement padstacks!
1379
1380 return aPadRef->GetLayerSet().compare( aPadCmp->GetLayerSet() );
1381}
1382
1383
1384void PAD::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1385{
1386 RotatePoint( m_pos, aRotCentre, aAngle );
1388
1389 SetDirty();
1390}
1391
1392
1393wxString PAD::ShowPadShape() const
1394{
1395 switch( GetShape() )
1396 {
1397 case PAD_SHAPE::CIRCLE: return _( "Circle" );
1398 case PAD_SHAPE::OVAL: return _( "Oval" );
1399 case PAD_SHAPE::RECTANGLE: return _( "Rect" );
1400 case PAD_SHAPE::TRAPEZOID: return _( "Trap" );
1401 case PAD_SHAPE::ROUNDRECT: return _( "Roundrect" );
1402 case PAD_SHAPE::CHAMFERED_RECT: return _( "Chamferedrect" );
1403 case PAD_SHAPE::CUSTOM: return _( "CustomShape" );
1404 default: return wxT( "???" );
1405 }
1406}
1407
1408
1409wxString PAD::ShowPadAttr() const
1410{
1411 switch( GetAttribute() )
1412 {
1413 case PAD_ATTRIB::PTH: return _( "PTH" );
1414 case PAD_ATTRIB::SMD: return _( "SMD" );
1415 case PAD_ATTRIB::CONN: return _( "Conn" );
1416 case PAD_ATTRIB::NPTH: return _( "NPTH" );
1417 default: return wxT( "???" );
1418 }
1419}
1420
1421
1422wxString PAD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1423{
1424 FOOTPRINT* parentFP = nullptr;
1425
1426 if( EDA_DRAW_FRAME* frame = dynamic_cast<EDA_DRAW_FRAME*>( aUnitsProvider ) )
1427 {
1428 if( frame->GetName() == PCB_EDIT_FRAME_NAME )
1429 parentFP = GetParentFootprint();
1430 }
1431
1432 if( GetAttribute() == PAD_ATTRIB::NPTH )
1433 {
1434 if( parentFP )
1435 {
1436 return wxString::Format( _( "NPTH pad of %s" ),
1437 parentFP->GetReference() );
1438 }
1439 else
1440 {
1441 return _( "NPTH pad" );
1442 }
1443 }
1444 else if( GetNumber().IsEmpty() )
1445 {
1446 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1447 {
1448 if( parentFP )
1449 {
1450 return wxString::Format( _( "Pad %s of %s on %s" ),
1451 GetNetnameMsg(),
1452 parentFP->GetReference(),
1454 }
1455 else
1456 {
1457 return wxString::Format( _( "Pad on %s" ),
1459 }
1460 }
1461 else
1462 {
1463 if( parentFP )
1464 {
1465 return wxString::Format( _( "PTH pad %s of %s" ),
1466 GetNetnameMsg(),
1467 parentFP->GetReference() );
1468 }
1469 else
1470 {
1471 return _( "PTH pad" );
1472 }
1473 }
1474 }
1475 else
1476 {
1477 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1478 {
1479 if( parentFP )
1480 {
1481 return wxString::Format( _( "Pad %s %s of %s on %s" ),
1482 GetNumber(),
1483 GetNetnameMsg(),
1484 parentFP->GetReference(),
1486 }
1487 else
1488 {
1489 return wxString::Format( _( "Pad %s on %s" ),
1490 GetNumber(),
1492 }
1493 }
1494 else
1495 {
1496 if( parentFP )
1497 {
1498 return wxString::Format( _( "PTH pad %s %s of %s" ),
1499 GetNumber(),
1500 GetNetnameMsg(),
1501 parentFP->GetReference() );
1502 }
1503 else
1504 {
1505 return wxString::Format( _( "PTH pad %s" ),
1506 GetNumber() );
1507 }
1508 }
1509 }
1510}
1511
1512
1514{
1515 return BITMAPS::pad;
1516}
1517
1518
1520{
1521 return new PAD( *this );
1522}
1523
1524
1525void PAD::ViewGetLayers( int aLayers[], int& aCount ) const
1526{
1527 aCount = 0;
1528
1529 // These 2 types of pads contain a hole
1530 if( m_attribute == PAD_ATTRIB::PTH )
1531 {
1532 aLayers[aCount++] = LAYER_PAD_PLATEDHOLES;
1533 aLayers[aCount++] = LAYER_PAD_HOLEWALLS;
1534 }
1535
1536 if( m_attribute == PAD_ATTRIB::NPTH )
1537 aLayers[aCount++] = LAYER_NON_PLATEDHOLES;
1538
1539 if( IsOnLayer( F_Cu ) && IsOnLayer( B_Cu ) )
1540 {
1541 // Multi layer pad
1542 aLayers[aCount++] = LAYER_PADS_TH;
1543 aLayers[aCount++] = LAYER_PAD_NETNAMES;
1544 }
1545 else if( IsOnLayer( F_Cu ) )
1546 {
1547 aLayers[aCount++] = LAYER_PADS_SMD_FR;
1548
1549 // Is this a PTH pad that has only front copper? If so, we need to also display the
1550 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1551 if( m_attribute == PAD_ATTRIB::PTH )
1552 aLayers[aCount++] = LAYER_PAD_NETNAMES;
1553 else
1554 aLayers[aCount++] = LAYER_PAD_FR_NETNAMES;
1555 }
1556 else if( IsOnLayer( B_Cu ) )
1557 {
1558 aLayers[aCount++] = LAYER_PADS_SMD_BK;
1559
1560 // Is this a PTH pad that has only back copper? If so, we need to also display the
1561 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1562 if( m_attribute == PAD_ATTRIB::PTH )
1563 aLayers[aCount++] = LAYER_PAD_NETNAMES;
1564 else
1565 aLayers[aCount++] = LAYER_PAD_BK_NETNAMES;
1566 }
1567 else
1568 {
1569 // Internal layers only. (Not yet supported in GUI, but is being used by Python
1570 // footprint generators and will be needed anyway once pad stacks are supported.)
1571 for ( int internal = In1_Cu; internal < In30_Cu; ++internal )
1572 {
1573 if( IsOnLayer( (PCB_LAYER_ID) internal ) )
1574 aLayers[aCount++] = internal;
1575 }
1576 }
1577
1578 // Check non-copper layers. This list should include all the layers that the
1579 // footprint editor allows a pad to be placed on.
1580 static const PCB_LAYER_ID layers_mech[] = { F_Mask, B_Mask, F_Paste, B_Paste,
1582
1583 for( PCB_LAYER_ID each_layer : layers_mech )
1584 {
1585 if( IsOnLayer( each_layer ) )
1586 aLayers[aCount++] = each_layer;
1587 }
1588}
1589
1590
1591double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1592{
1593 constexpr double HIDE = std::numeric_limits<double>::max();
1594
1595 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
1596 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
1597 const BOARD* board = GetBoard();
1598
1599 // Meta control for hiding all pads
1600 if( !aView->IsLayerVisible( LAYER_PADS ) )
1601 return HIDE;
1602
1603 // Handle Render tab switches
1604 if( ( GetAttribute() == PAD_ATTRIB::PTH || GetAttribute() == PAD_ATTRIB::NPTH )
1605 && !aView->IsLayerVisible( LAYER_PADS_TH ) )
1606 {
1607 return HIDE;
1608 }
1609
1610 if( !IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
1611 return HIDE;
1612
1613 if( IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
1614 return HIDE;
1615
1616 if( IsFrontLayer( (PCB_LAYER_ID) aLayer ) && !aView->IsLayerVisible( LAYER_PADS_SMD_FR ) )
1617 return HIDE;
1618
1619 if( IsBackLayer( (PCB_LAYER_ID) aLayer ) && !aView->IsLayerVisible( LAYER_PADS_SMD_BK ) )
1620 return HIDE;
1621
1622 LSET visible = board->GetVisibleLayers() & board->GetEnabledLayers();
1623
1624 if( IsHoleLayer( aLayer ) )
1625 {
1626 if( !( visible & LSET::PhysicalLayersMask() ).any() )
1627 return HIDE;
1628 }
1629 else if( IsNetnameLayer( aLayer ) )
1630 {
1631 if( renderSettings->GetHighContrast() )
1632 {
1633 // Hide netnames unless pad is flashed to a high-contrast layer
1634 if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
1635 return HIDE;
1636 }
1637 else
1638 {
1639 // Hide netnames unless pad is flashed to a visible layer
1640 if( !FlashLayer( visible ) )
1641 return HIDE;
1642 }
1643
1644 // Netnames will be shown only if zoom is appropriate
1645 int divisor = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
1646
1647 // Pad sizes can be zero briefly when someone is typing a number like "0.5" in the pad
1648 // properties dialog
1649 if( divisor == 0 )
1650 return HIDE;
1651
1652 return ( double ) pcbIUScale.mmToIU( 5 ) / divisor;
1653 }
1654
1655 VECTOR2L padSize =
1656 GetShape() != PAD_SHAPE::CUSTOM ? VECTOR2L( GetSize() ) : GetBoundingBox().GetSize();
1657
1658 int64_t minSide = std::min( padSize.x, padSize.y );
1659
1660 if( minSide > 0 )
1661 return std::min( (double) pcbIUScale.mmToIU( 0.2 ) / minSide, 3.5 );
1662 else
1663 return 0;
1664}
1665
1666
1668{
1669 // Bounding box includes soldermask too. Remember mask and/or paste margins can be < 0
1670 int solderMaskMargin = std::max( GetSolderMaskExpansion(), 0 );
1671 VECTOR2I solderPasteMargin = VECTOR2D( GetSolderPasteMargin() );
1672 BOX2I bbox = GetBoundingBox();
1673 int clearance = 0;
1674
1675 // If we're drawing clearance lines then get the biggest possible clearance
1676 if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
1677 {
1678 if( cfg && cfg->m_Display.m_PadClearance && GetBoard() )
1679 clearance = GetBoard()->GetMaxClearanceValue();
1680 }
1681
1682 // Look for the biggest possible bounding box
1683 int xMargin = std::max( solderMaskMargin, solderPasteMargin.x ) + clearance;
1684 int yMargin = std::max( solderMaskMargin, solderPasteMargin.y ) + clearance;
1685
1686 return BOX2I( VECTOR2I( bbox.GetOrigin() ) - VECTOR2I( xMargin, yMargin ),
1687 VECTOR2I( bbox.GetSize() ) + VECTOR2I( 2 * xMargin, 2 * yMargin ) );
1688}
1689
1690
1691void PAD::ImportSettingsFrom( const PAD& aMasterPad )
1692{
1693 SetPadstack( aMasterPad.Padstack() );
1694 SetShape( aMasterPad.GetShape() );
1695 // Layer Set should be updated before calling SetAttribute()
1696 SetLayerSet( aMasterPad.GetLayerSet() );
1697 SetAttribute( aMasterPad.GetAttribute() );
1698 // Unfortunately, SetAttribute() can change m_layerMask.
1699 // Be sure we keep the original mask by calling SetLayerSet() after SetAttribute()
1700 SetLayerSet( aMasterPad.GetLayerSet() );
1701 SetProperty( aMasterPad.GetProperty() );
1702
1703 // Must be after setting attribute and layerSet
1704 if( !CanHaveNumber() )
1705 SetNumber( wxEmptyString );
1706
1707 // I am not sure the m_LengthPadToDie should be imported, because this is a parameter
1708 // really specific to a given pad (JPC).
1709#if 0
1710 SetPadToDieLength( aMasterPad.GetPadToDieLength() );
1711#endif
1712
1713 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
1714 EDA_ANGLE pad_rot = aMasterPad.GetOrientation();
1715
1716 if( aMasterPad.GetParentFootprint() )
1717 pad_rot -= aMasterPad.GetParentFootprint()->GetOrientation();
1718
1719 if( GetParentFootprint() )
1720 pad_rot += GetParentFootprint()->GetOrientation();
1721
1722 SetOrientation( pad_rot );
1723
1724 SetSize( aMasterPad.GetSize() );
1725 SetDelta( VECTOR2I( 0, 0 ) );
1726 SetOffset( aMasterPad.GetOffset() );
1727 SetDrillSize( aMasterPad.GetDrillSize() );
1728 SetDrillShape( aMasterPad.GetDrillShape() );
1732
1733 switch( aMasterPad.GetShape() )
1734 {
1735 case PAD_SHAPE::TRAPEZOID:
1736 SetDelta( aMasterPad.GetDelta() );
1737 break;
1738
1739 case PAD_SHAPE::CIRCLE:
1740 // ensure size.y == size.x
1741 SetSize( VECTOR2I( GetSize().x, GetSize().x ) );
1742 break;
1743
1744 default:
1745 ;
1746 }
1747
1748 switch( aMasterPad.GetAttribute() )
1749 {
1750 case PAD_ATTRIB::SMD:
1751 case PAD_ATTRIB::CONN:
1752 // These pads do not have a hole (they are expected to be on one external copper layer)
1753 SetDrillSize( VECTOR2I( 0, 0 ) );
1754 break;
1755
1756 default:
1757 ;
1758 }
1759
1760 // copy also local settings:
1761 SetLocalClearance( aMasterPad.GetLocalClearance() );
1765
1769 SetThermalGap( aMasterPad.GetThermalGap() );
1770
1772
1774
1775 // Add or remove custom pad shapes:
1776 ReplacePrimitives( aMasterPad.GetPrimitives() );
1777 SetAnchorPadShape( aMasterPad.GetAnchorPadShape() );
1778
1779 SetDirty();
1780}
1781
1782
1784{
1785 assert( aImage->Type() == PCB_PAD_T );
1786
1787 std::swap( *this, *static_cast<PAD*>( aImage ) );
1788}
1789
1790
1791bool PAD::TransformHoleToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
1792 ERROR_LOC aErrorLoc ) const
1793{
1794 VECTOR2I drillsize = GetDrillSize();
1795
1796 if( !drillsize.x || !drillsize.y )
1797 return false;
1798
1799 std::shared_ptr<SHAPE_SEGMENT> slot = GetEffectiveHoleShape();
1800
1801 TransformOvalToPolygon( aBuffer, slot->GetSeg().A, slot->GetSeg().B,
1802 slot->GetWidth() + aClearance * 2, aError, aErrorLoc );
1803
1804 return true;
1805}
1806
1807
1808void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
1809 int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
1810{
1811 wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for pads." ) );
1812
1813 // minimal segment count to approximate a circle to create the polygonal pad shape
1814 // This minimal value is mainly for very small pads, like SM0402.
1815 // Most of time pads are using the segment count given by aError value.
1816 const int pad_min_seg_per_circle_count = 16;
1817 int dx = m_padStack.Size().x / 2;
1818 int dy = m_padStack.Size().y / 2;
1819
1820 VECTOR2I padShapePos = ShapePos(); // Note: for pad having a shape offset, the pad
1821 // position is NOT the shape position
1822
1823 switch( GetShape() )
1824 {
1825 case PAD_SHAPE::CIRCLE:
1826 case PAD_SHAPE::OVAL:
1827 // Note: dx == dy is not guaranteed for circle pads in legacy boards
1828 if( dx == dy || ( GetShape() == PAD_SHAPE::CIRCLE ) )
1829 {
1830 TransformCircleToPolygon( aBuffer, padShapePos, dx + aClearance, aMaxError, aErrorLoc,
1831 pad_min_seg_per_circle_count );
1832 }
1833 else
1834 {
1835 int half_width = std::min( dx, dy );
1836 VECTOR2I delta( dx - half_width, dy - half_width );
1837
1839
1840 TransformOvalToPolygon( aBuffer, padShapePos - delta, padShapePos + delta,
1841 ( half_width + aClearance ) * 2, aMaxError, aErrorLoc,
1842 pad_min_seg_per_circle_count );
1843 }
1844
1845 break;
1846
1847 case PAD_SHAPE::TRAPEZOID:
1848 case PAD_SHAPE::RECTANGLE:
1849 {
1850 int ddx = GetShape() == PAD_SHAPE::TRAPEZOID ? m_padStack.TrapezoidDeltaSize().x / 2 : 0;
1851 int ddy = GetShape() == PAD_SHAPE::TRAPEZOID ? m_padStack.TrapezoidDeltaSize().y / 2 : 0;
1852
1853 SHAPE_POLY_SET outline;
1854 TransformTrapezoidToPolygon( outline, padShapePos, m_padStack.Size(), GetOrientation(), ddx,
1855 ddy, aClearance, aMaxError, aErrorLoc );
1856 aBuffer.Append( outline );
1857 break;
1858 }
1859
1860 case PAD_SHAPE::CHAMFERED_RECT:
1861 case PAD_SHAPE::ROUNDRECT:
1862 {
1863 bool doChamfer = GetShape() == PAD_SHAPE::CHAMFERED_RECT;
1864
1865 SHAPE_POLY_SET outline;
1866 TransformRoundChamferedRectToPolygon( outline, padShapePos, m_padStack.Size(),
1868 doChamfer ? GetChamferRectRatio() : 0,
1869 doChamfer ? GetChamferPositions() : 0,
1870 aClearance, aMaxError, aErrorLoc );
1871 aBuffer.Append( outline );
1872 break;
1873 }
1874
1875 case PAD_SHAPE::CUSTOM:
1876 {
1877 SHAPE_POLY_SET outline;
1878 MergePrimitivesAsPolygon( &outline, aErrorLoc );
1879 outline.Rotate( GetOrientation() );
1880 outline.Move( VECTOR2I( padShapePos ) );
1881
1882 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
1883 {
1884 if( aErrorLoc == ERROR_OUTSIDE )
1885 aClearance += aMaxError;
1886
1887 outline.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aMaxError );
1889 }
1890 else if( aClearance < 0 )
1891 {
1892 // Negative clearances are primarily for drawing solder paste layer, so we don't
1893 // worry ourselves overly about which side the error is on.
1894
1895 // aClearance is negative so this is actually a deflate
1896 outline.Inflate( aClearance, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, aMaxError );
1898 }
1899
1900 aBuffer.Append( outline );
1901 break;
1902 }
1903
1904 default:
1905 wxFAIL_MSG( wxT( "PAD::TransformShapeToPolygon no implementation for " )
1906 + wxString( std::string( magic_enum::enum_name( GetShape() ) ) ) );
1907 break;
1908 }
1909}
1910
1911
1912std::vector<PCB_SHAPE*> PAD::Recombine( bool aIsDryRun, int maxError )
1913{
1914 FOOTPRINT* footprint = GetParentFootprint();
1915
1916 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1917 item->ClearFlags( SKIP_STRUCT );
1918
1919 auto findNext =
1920 [&]( PCB_LAYER_ID aLayer ) -> PCB_SHAPE*
1921 {
1922 SHAPE_POLY_SET padPoly;
1923 TransformShapeToPolygon( padPoly, aLayer, 0, maxError, ERROR_INSIDE );
1924
1925 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1926 {
1927 PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( item );
1928
1929 if( !shape || ( shape->GetFlags() & SKIP_STRUCT ) )
1930 continue;
1931
1932 if( shape->GetLayer() != aLayer )
1933 continue;
1934
1935 if( shape->IsProxyItem() ) // Pad number (and net name) box
1936 return shape;
1937
1938 SHAPE_POLY_SET drawPoly;
1939 shape->TransformShapeToPolygon( drawPoly, aLayer, 0, maxError, ERROR_INSIDE );
1940 drawPoly.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST );
1941
1942 if( !drawPoly.IsEmpty() )
1943 return shape;
1944 }
1945
1946 return nullptr;
1947 };
1948
1949 auto findMatching =
1950 [&]( PCB_SHAPE* aShape ) -> std::vector<PCB_SHAPE*>
1951 {
1952 std::vector<PCB_SHAPE*> matching;
1953
1954 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1955 {
1956 PCB_SHAPE* other = dynamic_cast<PCB_SHAPE*>( item );
1957
1958 if( !other || ( other->GetFlags() & SKIP_STRUCT ) )
1959 continue;
1960
1961 if( GetLayerSet().test( other->GetLayer() )
1962 && aShape->Compare( other ) == 0 )
1963 {
1964 matching.push_back( other );
1965 }
1966 }
1967
1968 return matching;
1969 };
1970
1971 PCB_LAYER_ID layer;
1972 std::vector<PCB_SHAPE*> mergedShapes;
1973
1974 if( IsOnLayer( F_Cu ) )
1975 layer = F_Cu;
1976 else if( IsOnLayer( B_Cu ) )
1977 layer = B_Cu;
1978 else
1979 layer = GetLayerSet().UIOrder().front();
1980
1981 // If there are intersecting items to combine, we need to first make sure the pad is a
1982 // custom-shape pad.
1983 if( !aIsDryRun && findNext( layer ) && GetShape() != PAD_SHAPE::CUSTOM )
1984 {
1985 if( GetShape() == PAD_SHAPE::CIRCLE || GetShape() == PAD_SHAPE::RECTANGLE )
1986 {
1987 // Use the existing pad as an anchor
1989 SetShape( PAD_SHAPE::CUSTOM );
1990 }
1991 else
1992 {
1993 // Create a new circular anchor and convert existing pad to a polygon primitive
1994 SHAPE_POLY_SET existingOutline;
1995 TransformShapeToPolygon( existingOutline, layer, 0, maxError, ERROR_INSIDE );
1996
1997 int minExtent = std::min( GetSize().x, GetSize().y );
1998 SetAnchorPadShape( PAD_SHAPE::CIRCLE );
1999 SetSize( VECTOR2I( minExtent, minExtent ) );
2000 SetShape( PAD_SHAPE::CUSTOM );
2001
2002 PCB_SHAPE* shape = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
2003 shape->SetFilled( true );
2004 shape->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
2005 shape->SetPolyShape( existingOutline );
2006 shape->Move( - ShapePos() );
2007 shape->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
2008 AddPrimitive( shape );
2009 }
2010 }
2011
2012 while( PCB_SHAPE* fpShape = findNext( layer ) )
2013 {
2014 fpShape->SetFlags( SKIP_STRUCT );
2015
2016 mergedShapes.push_back( fpShape );
2017
2018 if( !aIsDryRun )
2019 {
2020 PCB_SHAPE* primitive = static_cast<PCB_SHAPE*>( fpShape->Duplicate() );
2021
2022 primitive->SetParent( nullptr );
2023 primitive->Move( - ShapePos() );
2024 primitive->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
2025
2026 AddPrimitive( primitive );
2027 }
2028
2029 // See if there are other shapes that match and mark them for delete. (KiCad won't
2030 // produce these, but old footprints from other vendors have them.)
2031 for( PCB_SHAPE* other : findMatching( fpShape ) )
2032 {
2033 other->SetFlags( SKIP_STRUCT );
2034 mergedShapes.push_back( other );
2035 }
2036 }
2037
2038 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2039 item->ClearFlags( SKIP_STRUCT );
2040
2041 if( !aIsDryRun )
2043
2044 return mergedShapes;
2045}
2046
2047
2048void PAD::CheckPad( UNITS_PROVIDER* aUnitsProvider,
2049 const std::function<void( int aErrorCode,
2050 const wxString& aMsg )>& aErrorHandler ) const
2051{
2052 VECTOR2I pad_size = GetSize();
2053 VECTOR2I drill_size = GetDrillSize();
2054 wxString msg;
2055
2056 if( GetShape() == PAD_SHAPE::CUSTOM )
2057 pad_size = GetBoundingBox().GetSize();
2058 else if( pad_size.x <= 0 || ( pad_size.y <= 0 && GetShape() != PAD_SHAPE::CIRCLE ) )
2059 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(Pad must have a positive size)" ) );
2060
2061 // Test hole against pad shape
2062 if( IsOnCopperLayer() && GetDrillSize().x > 0 )
2063 {
2064 // Ensure the drill size can be handled in next calculations.
2065 // Use min size = 4 IU to be able to build a polygon from a hole shape
2066 const int min_drill_size = 4;
2067
2068 if( GetDrillSizeX() <= min_drill_size || GetDrillSizeY() <= min_drill_size )
2069 {
2070 msg.Printf( _( "(PTH pad hole size must be larger than %s)" ),
2071 aUnitsProvider->StringFromValue( min_drill_size, true ) );
2072 aErrorHandler( DRCE_PADSTACK_INVALID, msg );
2073 }
2074
2075 int maxError = GetBoard()->GetDesignSettings().m_MaxError;
2076 SHAPE_POLY_SET padOutline;
2077
2078 TransformShapeToPolygon( padOutline, UNDEFINED_LAYER, 0, maxError, ERROR_INSIDE );
2079
2080 if( GetAttribute() == PAD_ATTRIB::PTH )
2081 {
2082 // Test if there is copper area outside hole
2083 std::shared_ptr<SHAPE_SEGMENT> hole = GetEffectiveHoleShape();
2084 SHAPE_POLY_SET holeOutline;
2085
2086 TransformOvalToPolygon( holeOutline, hole->GetSeg().A, hole->GetSeg().B,
2087 hole->GetWidth(), ARC_HIGH_DEF, ERROR_OUTSIDE );
2088
2089 SHAPE_POLY_SET copper = padOutline;
2091
2092 if( copper.IsEmpty() )
2093 {
2094 aErrorHandler( DRCE_PADSTACK, _( "(PTH pad hole leaves no copper)" ) );
2095 }
2096 else
2097 {
2098 // Test if the pad hole is fully inside the copper area
2099 holeOutline.BooleanSubtract( padOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2100
2101 if( !holeOutline.IsEmpty() )
2102 aErrorHandler( DRCE_PADSTACK, _( "(PTH pad hole non fully inside copper)" ) );
2103 }
2104 }
2105 else
2106 {
2107 // Test only if the pad hole's centre is inside the copper area
2108 if( !padOutline.Collide( GetPosition() ) )
2109 aErrorHandler( DRCE_PADSTACK, _( "(pad hole not inside pad shape)" ) );
2110 }
2111 }
2112
2113 if( GetLocalClearance().value_or( 0 ) < 0 )
2114 aErrorHandler( DRCE_PADSTACK, _( "(negative local clearance values have no effect)" ) );
2115
2116 // Some pads need a negative solder mask clearance (mainly for BGA with small pads)
2117 // However the negative solder mask clearance must not create negative mask size
2118 // Therefore test for minimal acceptable negative value
2119 std::optional<int> solderMaskMargin = GetLocalSolderMaskMargin();
2120
2121 if( solderMaskMargin.has_value() && solderMaskMargin.value() < 0 )
2122 {
2123 int absMargin = abs( solderMaskMargin.value() );
2124
2125 if( GetShape() == PAD_SHAPE::CUSTOM )
2126 {
2127 for( const std::shared_ptr<PCB_SHAPE>& shape : GetPrimitives() )
2128 {
2129 BOX2I shapeBBox = shape->GetBoundingBox();
2130
2131 if( absMargin > shapeBBox.GetWidth() || absMargin > shapeBBox.GetHeight() )
2132 {
2133 aErrorHandler( DRCE_PADSTACK, _( "(negative solder mask clearance is larger "
2134 "than some shape primitives; results may be "
2135 "surprising)" ) );
2136
2137 break;
2138 }
2139 }
2140 }
2141 else if( absMargin > pad_size.x || absMargin > pad_size.y )
2142 {
2143 aErrorHandler( DRCE_PADSTACK, _( "(negative solder mask clearance is larger than pad; "
2144 "no solder mask will be generated)" ) );
2145 }
2146 }
2147
2148 // Some pads need a positive solder paste clearance (mainly for BGA with small pads)
2149 // However, a positive value can create issues if the resulting shape is too big.
2150 // (like a solder paste creating a solder paste area on a neighbor pad or on the solder mask)
2151 // So we could ask for user to confirm the choice
2152 // For now we just check for disappearing paste
2153 wxSize paste_size;
2154 int paste_margin = GetLocalSolderPasteMargin().value_or( 0 );
2155 double paste_ratio = GetLocalSolderPasteMarginRatio().value_or( 0 );
2156
2157 paste_size.x = pad_size.x + paste_margin + KiROUND( pad_size.x * paste_ratio );
2158 paste_size.y = pad_size.y + paste_margin + KiROUND( pad_size.y * paste_ratio );
2159
2160 if( paste_size.x <= 0 || paste_size.y <= 0 )
2161 {
2162 aErrorHandler( DRCE_PADSTACK, _( "(negative solder paste margin is larger than pad; "
2163 "no solder paste mask will be generated)" ) );
2164 }
2165
2166 LSET padlayers_mask = GetLayerSet();
2167
2168 if( padlayers_mask == 0 )
2169 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(Pad has no layer)" ) );
2170
2171 if( GetAttribute() == PAD_ATTRIB::PTH && !IsOnCopperLayer() )
2172 aErrorHandler( DRCE_PADSTACK, _( "(PTH pad has no copper layers)" ) );
2173
2174 if( !padlayers_mask[F_Cu] && !padlayers_mask[B_Cu] )
2175 {
2176 if( ( drill_size.x || drill_size.y ) && GetAttribute() != PAD_ATTRIB::NPTH )
2177 {
2178 aErrorHandler( DRCE_PADSTACK, _( "(plated through holes normally have a copper pad on "
2179 "at least one layer)" ) );
2180 }
2181 }
2182
2183 switch( GetAttribute() )
2184 {
2185 case PAD_ATTRIB::NPTH: // Not plated, but through hole, a hole is expected
2186 case PAD_ATTRIB::PTH: // Pad through hole, a hole is also expected
2187 if( drill_size.x <= 0
2188 || ( drill_size.y <= 0 && GetDrillShape() == PAD_DRILL_SHAPE::OBLONG ) )
2189 {
2190 aErrorHandler( DRCE_PAD_TH_WITH_NO_HOLE, wxEmptyString );
2191 }
2192 break;
2193
2194 case PAD_ATTRIB::CONN: // Connector pads are smd pads, just they do not have solder paste.
2195 if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
2196 {
2197 aErrorHandler( DRCE_PADSTACK, _( "(connector pads normally have no solder paste; use a "
2198 "SMD pad instead)" ) );
2199 }
2201
2202 case PAD_ATTRIB::SMD: // SMD and Connector pads (One external copper layer only)
2203 {
2204 if( drill_size.x > 0 || drill_size.y > 0 )
2205 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(SMD pad has a hole)" ) );
2206
2207 LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
2208
2209 if( IsOnLayer( F_Cu ) && IsOnLayer( B_Cu ) )
2210 {
2211 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper on both sides of the board)" ) );
2212 }
2213 else if( IsOnLayer( F_Cu ) )
2214 {
2215 if( IsOnLayer( B_Mask ) )
2216 {
2217 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and mask layers on different "
2218 "sides of the board)" ) );
2219 }
2220 else if( IsOnLayer( B_Paste ) )
2221 {
2222 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and paste layers on different "
2223 "sides of the board)" ) );
2224 }
2225 }
2226 else if( IsOnLayer( B_Cu ) )
2227 {
2228 if( IsOnLayer( F_Mask ) )
2229 {
2230 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and mask layers on different "
2231 "sides of the board)" ) );
2232 }
2233 else if( IsOnLayer( F_Paste ) )
2234 {
2235 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and paste layers on different "
2236 "sides of the board)" ) );
2237 }
2238 }
2239 else if( innerlayers_mask.count() != 0 )
2240 {
2241 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has no outer layers)" ) );
2242 }
2243
2244 break;
2245 }
2246 }
2247
2248 if( ( GetProperty() == PAD_PROP::FIDUCIAL_GLBL || GetProperty() == PAD_PROP::FIDUCIAL_LOCAL )
2249 && GetAttribute() == PAD_ATTRIB::NPTH )
2250 {
2251 aErrorHandler( DRCE_PADSTACK, _( "('fiducial' property makes no sense on NPTH pads)" ) );
2252 }
2253
2254 if( GetProperty() == PAD_PROP::TESTPOINT && GetAttribute() == PAD_ATTRIB::NPTH )
2255 aErrorHandler( DRCE_PADSTACK, _( "('testpoint' property makes no sense on NPTH pads)" ) );
2256
2257 if( GetProperty() == PAD_PROP::HEATSINK && GetAttribute() == PAD_ATTRIB::NPTH )
2258 aErrorHandler( DRCE_PADSTACK, _( "('heatsink' property makes no sense of NPTH pads)" ) );
2259
2260 if( GetProperty() == PAD_PROP::CASTELLATED && GetAttribute() != PAD_ATTRIB::PTH )
2261 aErrorHandler( DRCE_PADSTACK, _( "('castellated' property is for PTH pads)" ) );
2262
2263 if( GetProperty() == PAD_PROP::BGA && GetAttribute() != PAD_ATTRIB::SMD )
2264 aErrorHandler( DRCE_PADSTACK, _( "('BGA' property is for SMD pads)" ) );
2265
2266 if( GetProperty() == PAD_PROP::MECHANICAL && GetAttribute() != PAD_ATTRIB::PTH )
2267 aErrorHandler( DRCE_PADSTACK, _( "('mechanical' property is for PTH pads)" ) );
2268
2269 if( GetShape() == PAD_SHAPE::ROUNDRECT )
2270 {
2271 if( GetRoundRectRadiusRatio() < 0.0 )
2272 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(negative corner radius is not allowed)" ) );
2273 else if( GetRoundRectRadiusRatio() > 50.0 )
2274 aErrorHandler( DRCE_PADSTACK, _( "(corner size will make pad circular)" ) );
2275 }
2276 else if( GetShape() == PAD_SHAPE::CHAMFERED_RECT )
2277 {
2278 if( GetChamferRectRatio() < 0.0 )
2279 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(negative corner chamfer is not allowed)" ) );
2280 else if( GetChamferRectRatio() > 50.0 )
2281 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(corner chamfer is too large)" ) );
2282 }
2283 else if( GetShape() == PAD_SHAPE::TRAPEZOID )
2284 {
2285 if( ( GetDelta().x < 0 && GetDelta().x < -GetSize().y )
2286 || ( GetDelta().x > 0 && GetDelta().x > GetSize().y )
2287 || ( GetDelta().y < 0 && GetDelta().y < -GetSize().x )
2288 || ( GetDelta().y > 0 && GetDelta().y > GetSize().x ) )
2289 {
2290 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(trapazoid delta is too large)" ) );
2291 }
2292 }
2293
2294 // PADSTACKS TODO: this will need to check each layer in the pad...
2295 if( GetShape() == PAD_SHAPE::CUSTOM )
2296 {
2297 SHAPE_POLY_SET mergedPolygon;
2298 MergePrimitivesAsPolygon( &mergedPolygon );
2299
2300 if( mergedPolygon.OutlineCount() > 1 )
2301 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(custom pad shape must resolve to a single polygon)" ) );
2302 }
2303}
2304
2305
2306bool PAD::operator==( const BOARD_ITEM& aBoardItem ) const
2307{
2308 if( Type() != aBoardItem.Type() )
2309 return false;
2310
2311 if( m_parent && aBoardItem.GetParent() && m_parent->m_Uuid != aBoardItem.GetParent()->m_Uuid )
2312 return false;
2313
2314 const PAD& other = static_cast<const PAD&>( aBoardItem );
2315
2316 return *this == other;
2317}
2318
2319
2320bool PAD::operator==( const PAD& aOther ) const
2321{
2322 if( GetShape() != aOther.GetShape() )
2323 return false;
2324
2325 if( GetPosition() != aOther.GetPosition() )
2326 return false;
2327
2328 if( GetAttribute() != aOther.GetAttribute() )
2329 return false;
2330
2331 if( GetSize() != aOther.GetSize() )
2332 return false;
2333
2334 if( GetOffset() != aOther.GetOffset() )
2335 return false;
2336
2337 if( GetDrillSize() != aOther.GetDrillSize() )
2338 return false;
2339
2340 if( GetDrillShape() != aOther.GetDrillShape() )
2341 return false;
2342
2344 return false;
2345
2346 if( GetChamferRectRatio() != aOther.GetChamferRectRatio() )
2347 return false;
2348
2349 if( GetChamferPositions() != aOther.GetChamferPositions() )
2350 return false;
2351
2352 if( GetOrientation() != aOther.GetOrientation() )
2353 return false;
2354
2356 return false;
2357
2358 if( GetThermalSpokeWidth() != aOther.GetThermalSpokeWidth() )
2359 return false;
2360
2361 if( GetThermalSpokeAngle() != aOther.GetThermalSpokeAngle() )
2362 return false;
2363
2364 if( GetThermalGap() != aOther.GetThermalGap() )
2365 return false;
2366
2368 return false;
2369
2370 if( GetPrimitives().size() != aOther.GetPrimitives().size() )
2371 return false;
2372
2373 for( size_t ii = 0; ii < GetPrimitives().size(); ii++ )
2374 {
2375 if( *GetPrimitives()[ii] != *aOther.GetPrimitives()[ii] )
2376 return false;
2377 }
2378
2379 if( GetAnchorPadShape() != aOther.GetAnchorPadShape() )
2380 return false;
2381
2382 if( GetLocalClearance() != aOther.GetLocalClearance() )
2383 return false;
2384
2386 return false;
2387
2389 return false;
2390
2392 return false;
2393
2395 return false;
2396
2397 if( GetLayerSet() != aOther.GetLayerSet() )
2398 return false;
2399
2400 return true;
2401}
2402
2403
2404double PAD::Similarity( const BOARD_ITEM& aOther ) const
2405{
2406 if( aOther.Type() != Type() )
2407 return 0.0;
2408
2409 if( m_parent->m_Uuid != aOther.GetParent()->m_Uuid )
2410 return 0.0;
2411
2412 const PAD& other = static_cast<const PAD&>( aOther );
2413
2414 double similarity = 1.0;
2415
2416 if( GetShape() != other.GetShape() )
2417 similarity *= 0.9;
2418
2419 if( GetPosition() != other.GetPosition() )
2420 similarity *= 0.9;
2421
2422 if( GetAttribute() != other.GetAttribute() )
2423 similarity *= 0.9;
2424
2425 if( GetSize() != other.GetSize() )
2426 similarity *= 0.9;
2427
2428 if( GetOffset() != other.GetOffset() )
2429 similarity *= 0.9;
2430
2431 if( GetDrillSize() != other.GetDrillSize() )
2432 similarity *= 0.9;
2433
2434 if( GetDrillShape() != other.GetDrillShape() )
2435 similarity *= 0.9;
2436
2438 similarity *= 0.9;
2439
2440 if( GetChamferRectRatio() != other.GetChamferRectRatio() )
2441 similarity *= 0.9;
2442
2443 if( GetChamferPositions() != other.GetChamferPositions() )
2444 similarity *= 0.9;
2445
2446 if( GetOrientation() != other.GetOrientation() )
2447 similarity *= 0.9;
2448
2450 similarity *= 0.9;
2451
2453 similarity *= 0.9;
2454
2456 similarity *= 0.9;
2457
2458 if( GetThermalGap() != other.GetThermalGap() )
2459 similarity *= 0.9;
2460
2462 similarity *= 0.9;
2463
2464 if( GetPrimitives().size() != other.GetPrimitives().size() )
2465 similarity *= 0.9;
2466
2467 if( GetAnchorPadShape() != other.GetAnchorPadShape() )
2468 similarity *= 0.9;
2469
2470 if( GetLocalClearance() != other.GetLocalClearance() )
2471 similarity *= 0.9;
2472
2474 similarity *= 0.9;
2475
2477 similarity *= 0.9;
2478
2480 similarity *= 0.9;
2481
2483 similarity *= 0.9;
2484
2485 if( GetLayerSet() != other.GetLayerSet() )
2486 similarity *= 0.9;
2487
2488 return similarity;
2489}
2490
2491
2492static struct PAD_DESC
2493{
2495 {
2497 .Map( PAD_ATTRIB::PTH, _HKI( "Through-hole" ) )
2498 .Map( PAD_ATTRIB::SMD, _HKI( "SMD" ) )
2499 .Map( PAD_ATTRIB::CONN, _HKI( "Edge connector" ) )
2500 .Map( PAD_ATTRIB::NPTH, _HKI( "NPTH, mechanical" ) );
2501
2503 .Map( PAD_SHAPE::CIRCLE, _HKI( "Circle" ) )
2504 .Map( PAD_SHAPE::RECTANGLE, _HKI( "Rectangle" ) )
2505 .Map( PAD_SHAPE::OVAL, _HKI( "Oval" ) )
2506 .Map( PAD_SHAPE::TRAPEZOID, _HKI( "Trapezoid" ) )
2507 .Map( PAD_SHAPE::ROUNDRECT, _HKI( "Rounded rectangle" ) )
2508 .Map( PAD_SHAPE::CHAMFERED_RECT, _HKI( "Chamfered rectangle" ) )
2509 .Map( PAD_SHAPE::CUSTOM, _HKI( "Custom" ) );
2510
2512 .Map( PAD_PROP::NONE, _HKI( "None" ) )
2513 .Map( PAD_PROP::BGA, _HKI( "BGA pad" ) )
2514 .Map( PAD_PROP::FIDUCIAL_GLBL, _HKI( "Fiducial, global to board" ) )
2515 .Map( PAD_PROP::FIDUCIAL_LOCAL, _HKI( "Fiducial, local to footprint" ) )
2516 .Map( PAD_PROP::TESTPOINT, _HKI( "Test point pad" ) )
2517 .Map( PAD_PROP::HEATSINK, _HKI( "Heatsink pad" ) )
2518 .Map( PAD_PROP::CASTELLATED, _HKI( "Castellated pad" ) )
2519 .Map( PAD_PROP::MECHANICAL, _HKI( "Mechanical pad" ) );
2520
2522
2523 if( zcMap.Choices().GetCount() == 0 )
2524 {
2525 zcMap.Undefined( ZONE_CONNECTION::INHERITED );
2526 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
2527 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
2528 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
2529 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
2530 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
2531 }
2532
2534 .Map( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL, _HKI( "All copper layers" ) )
2535 .Map( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL, _HKI( "Connected layers only" ) )
2537 _HKI( "Front, back and connected layers" ) );
2538
2540 REGISTER_TYPE( PAD );
2542
2543 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
2544
2545 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Orientation" ),
2547 PROPERTY_DISPLAY::PT_DEGREE ) );
2548
2549 auto isCopperPad =
2550 []( INSPECTABLE* aItem ) -> bool
2551 {
2552 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2553 return pad->GetAttribute() != PAD_ATTRIB::NPTH;
2554
2555 return false;
2556 };
2557
2558 auto padCanHaveHole =
2559 []( INSPECTABLE* aItem ) -> bool
2560 {
2561 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2562 {
2563 return pad->GetAttribute() == PAD_ATTRIB::PTH
2564 || pad->GetAttribute() == PAD_ATTRIB::NPTH;
2565 }
2566
2567 return false;
2568 };
2569
2571 _HKI( "Net" ), isCopperPad );
2573 _HKI( "Net Class" ), isCopperPad );
2574
2575 const wxString groupPad = _HKI( "Pad Properties" );
2576
2577 auto padType = new PROPERTY_ENUM<PAD, PAD_ATTRIB>( _HKI( "Pad Type" ),
2579 propMgr.AddProperty( padType, groupPad );
2580
2581 auto shape = new PROPERTY_ENUM<PAD, PAD_SHAPE>( _HKI( "Pad Shape" ),
2583 propMgr.AddProperty( shape, groupPad );
2584
2585 auto padNumber = new PROPERTY<PAD, wxString>( _HKI( "Pad Number" ),
2587 padNumber->SetAvailableFunc( isCopperPad );
2588 propMgr.AddProperty( padNumber, groupPad );
2589
2590 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Name" ),
2591 NO_SETTER( PAD, wxString ), &PAD::GetPinFunction ), groupPad )
2593 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Type" ),
2594 NO_SETTER( PAD, wxString ), &PAD::GetPinType ), groupPad )
2596
2597 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size X" ),
2599 PROPERTY_DISPLAY::PT_SIZE ), groupPad );
2600 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size Y" ),
2602 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2604 [=]( INSPECTABLE* aItem ) -> bool
2605 {
2606 // Circle pads have no usable y-size
2607 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2608 return pad->GetShape() != PAD_SHAPE::CIRCLE;
2609
2610 return true;
2611 } );
2612
2613 auto roundRadiusRatio = new PROPERTY<PAD, double>( _HKI( "Corner Radius Ratio" ),
2615 roundRadiusRatio->SetAvailableFunc(
2616 [=]( INSPECTABLE* aItem ) -> bool
2617 {
2618 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2619 return pad->GetShape() == PAD_SHAPE::ROUNDRECT;
2620
2621 return false;
2622 } );
2623 propMgr.AddProperty( roundRadiusRatio, groupPad );
2624
2625 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size X" ),
2627 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2628 .SetWriteableFunc( padCanHaveHole )
2630
2631 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size Y" ),
2633 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2634 .SetWriteableFunc( padCanHaveHole )
2636
2637 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_PROP>( _HKI( "Fabrication Property" ),
2638 &PAD::SetProperty, &PAD::GetProperty ), groupPad );
2639
2641 _HKI( "Copper Layers" ),
2643 propMgr.AddProperty( layerMode, groupPad );
2644
2645 auto padToDie = new PROPERTY<PAD, int>( _HKI( "Pad To Die Length" ),
2647 PROPERTY_DISPLAY::PT_SIZE );
2648 padToDie->SetAvailableFunc( isCopperPad );
2649 propMgr.AddProperty( padToDie, groupPad );
2650
2651 const wxString groupOverrides = _HKI( "Overrides" );
2652
2653 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2654 _HKI( "Clearance Override" ),
2656 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2657
2658 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2659 _HKI( "Soldermask Margin Override" ),
2661 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2662
2663 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2664 _HKI( "Solderpaste Margin Override" ),
2666 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2667
2668 propMgr.AddProperty( new PROPERTY<PAD, std::optional<double>>(
2669 _HKI( "Solderpaste Margin Ratio Override" ),
2671 PROPERTY_DISPLAY::PT_RATIO ),
2672 groupOverrides );
2673
2675 _HKI( "Zone Connection Style" ),
2677
2678 constexpr int minZoneWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
2679
2680 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Thermal Relief Spoke Width" ),
2682 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2683 .SetValidator( PROPERTY_VALIDATORS::RangeIntValidator<minZoneWidth, INT_MAX> );
2684
2685 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Thermal Relief Spoke Angle" ),
2687 PROPERTY_DISPLAY::PT_DEGREE ), groupOverrides );
2688
2689 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Thermal Relief Gap" ),
2691 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2693
2694 // TODO delta, drill shape offset, layer set
2695 }
2697
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:67
@ ZLO_FORCE_FLASHED
Definition: board_item.h:68
BOX2< VECTOR2I > BOX2I
Definition: box2.h:877
BASE_SET & set(size_t pos=std::numeric_limits< size_t >::max(), bool value=true)
Definition: base_set.h:61
bool test(size_t pos) const
Definition: base_set.h:47
int compare(const BASE_SET &other) const
Definition: base_set.h:116
size_t count() const
Definition: base_set.h:106
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 ...
const 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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:240
virtual void SetLocked(bool aLocked)
Definition: board_item.h:316
PCB_LAYER_ID m_layer
Definition: board_item.h:409
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:276
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:47
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:264
virtual bool IsLocked() const
Definition: board_item.cpp:75
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:218
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:131
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:289
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:757
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:771
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition: board.cpp:880
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:874
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
size_type GetHeight() const
Definition: box2.h:205
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:294
size_type GetWidth() const
Definition: box2.h:204
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:150
MINOPTMAX< int > & Value()
Definition: drc_rule.h:143
double AsDegrees() const
Definition: eda_angle.h:113
bool IsZero() const
Definition: eda_angle.h:133
EDA_ANGLE Normalize180()
Definition: eda_angle.h:260
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:89
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:243
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:489
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:129
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:104
EDA_ITEM * m_parent
Linked list: Link (parent struct)
Definition: eda_item.h:500
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:130
void SetFilled(bool aFlag)
Definition: eda_shape.h:101
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:287
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:216
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2967
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:225
bool IsNetTie() const
Definition: footprint.h:286
const wxString & GetReference() const
Definition: footprint.h:591
DRAWINGS & GraphicalItems()
Definition: footprint.h:198
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:175
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:180
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:418
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
Definition: kiid.h:49
wxString AsString() const
Definition: kiid.cpp:246
std::string AsStdString() const
Definition: kiid.cpp:252
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:35
LSET & Flip(int aCopperLayersCount=0)
Flip the layers in this set.
Definition: lset.cpp:608
LSEQ UIOrder() const
Definition: lset.cpp:865
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:392
static LSET FrontBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on front side.
Definition: lset.cpp:793
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:721
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:732
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:822
static LSET BackBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on Back side.
Definition: lset.cpp:780
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:381
void SetRoundRectRadius(double aRadius, PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:352
std::optional< int > & Clearance(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:392
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: padstack.cpp:89
void SetChamferRatio(double aRatio, PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:368
std::vector< std::shared_ptr< PCB_SHAPE > > & Primitives(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:498
void SetChamferPositions(int aPositions, PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:386
std::optional< double > & SolderPasteMarginRatio(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:431
void SetRoundRectRadiusRatio(double aRatio, PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:339
std::optional< int > & ThermalSpokeWidth(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:456
std::optional< int > & SolderPasteMargin(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:418
void SetOrientation(EDA_ANGLE aAngle)
Definition: padstack.h:260
std::optional< int > & SolderMaskMargin(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:404
const LSET & LayerSet() const
Definition: padstack.h:246
int RoundRectRadius(PCB_LAYER_ID aLayer=F_Cu) const
Definition: padstack.cpp:345
int & ChamferPositions(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:374
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
Definition: padstack.h:272
std::optional< int > & ThermalGap(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:468
DRILL_PROPS & Drill()
Definition: padstack.h:266
double RoundRectRadiusRatio(PCB_LAYER_ID aLayer=F_Cu) const
Definition: padstack.cpp:333
VECTOR2I & TrapezoidDeltaSize(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:321
VECTOR2I & Offset(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:297
VECTOR2I & Size(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:273
UNCONNECTED_LAYER_MODE
! Whether or not to remove the copper shape for unconnected layers
Definition: padstack.h:137
PCB_LAYER_ID StartLayer() const
Definition: padstack.cpp:201
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: padstack.cpp:153
double ChamferRatio(PCB_LAYER_ID aLayer=F_Cu) const
Definition: padstack.cpp:362
PAD_SHAPE Shape(PCB_LAYER_ID aLayer=F_Cu) const
Definition: padstack.cpp:261
EDA_ANGLE GetOrientation() const
Definition: padstack.h:259
void SetLayerSet(const LSET &aSet)
Definition: padstack.h:248
std::optional< ZONE_CONNECTION > & ZoneConnection(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:444
Definition: pad.h:54
bool IsAperturePad() const
Definition: pad.h:402
void SetAttribute(PAD_ATTRIB aAttribute)
Definition: pad.cpp:745
int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const override
Return the pad's "own" clearance in internal units.
Definition: pad.cpp:971
void SetLayerSet(LSET aLayers) override
Definition: pad.h:391
PAD(FOOTPRINT *parent)
Definition: pad.cpp:70
virtual void swapData(BOARD_ITEM *aImage) override
Definition: pad.cpp:1783
PAD_PROP GetProperty() const
Definition: pad.h:398
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: pad.cpp:136
std::optional< int > GetClearanceOverrides(wxString *aSource) const override
Return any clearance overrides set in the "classic" (ie: pre-rule) system.
Definition: pad.cpp:959
void SetPinType(const wxString &aType)
Set the pad electrical type.
Definition: pad.h:150
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:392
int GetSizeX() const
Definition: pad.h:259
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:357
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:1125
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition: pad.cpp:736
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:698
int GetSolderMaskExpansion() const
Definition: pad.cpp:997
int GetDrillSizeY() const
Definition: pad.h:271
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: pad.h:425
const wxString & GetPinType() const
Definition: pad.h:151
const VECTOR2I & GetDrillSize() const
Definition: pad.h:267
PAD_ATTRIB GetAttribute() const
Definition: pad.h:395
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:286
static int Compare(const PAD *aPadRef, const PAD *aPadCmp)
Compare two pads and return 0 if they are equal.
Definition: pad.cpp:1307
void SetUnconnectedLayerMode(PADSTACK::UNCONNECTED_LAYER_MODE aMode)
Definition: pad.h:666
const wxString & GetPinFunction() const
Definition: pad.h:145
void BuildEffectiveShapes(PCB_LAYER_ID aLayer) const
Rebuild the effective shape cache (and bounding box and radius) for the pad and clears the dirty bit.
Definition: pad.cpp:517
std::mutex m_shapesBuildingLock
Definition: pad.h:859
void SetThermalGap(int aGap)
Definition: pad.h:583
std::shared_ptr< SHAPE_POLY_SET > m_effectivePolygon[2]
Definition: pad.h:866
bool CanHaveNumber() const
Indicates whether or not the pad can have a number.
Definition: pad.cpp:233
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition: pad.h:564
wxString m_pinType
Definition: pad.h:851
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: pad.cpp:180
const wxString & GetNumber() const
Definition: pad.h:134
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:887
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:425
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: pad.h:429
PAD & operator=(const PAD &aOther)
Definition: pad.cpp:119
std::shared_ptr< SHAPE_SEGMENT > m_effectiveHoleShape
Definition: pad.h:862
bool IsLocked() const override
Definition: pad.cpp:247
VECTOR2I GetPosition() const override
Definition: pad.h:201
void SetProperty(PAD_PROP aProperty)
Definition: pad.cpp:793
void SetThermalSpokeAngleDegrees(double aAngle)
Definition: pad.h:574
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:318
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:568
void SetOffset(const VECTOR2I &aOffset)
Definition: pad.h:273
PAD_ATTRIB m_attribute
Definition: pad.h:872
std::vector< PCB_SHAPE * > Recombine(bool aIsDryRun, int aMaxError)
Recombines the pad with other graphical shapes in the footprint.
Definition: pad.cpp:1912
PCB_LAYER_ID GetPrincipalLayer() const
Definition: pad.cpp:335
void SetChamferRectRatio(double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition: pad.cpp:445
void SetDirty()
Definition: pad.h:384
const VECTOR2I & GetOffset() const
Definition: pad.h:274
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pad.cpp:307
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pad.cpp:1519
double GetOrientationDegrees() const
Definition: pad.h:367
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pad.cpp:1384
PADSTACK m_padStack
Definition: pad.h:855
void SetRoundRectCornerRadius(double aRadius)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:431
bool IsNoConnectPad() const
Definition: pad.cpp:273
int GetDrillSizeX() const
Definition: pad.h:269
PAD_PROP m_property
Definition: pad.h:874
VECTOR2I ShapePos() const
Definition: pad.cpp:896
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:1808
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition: pad.h:133
int GetLocalThermalGapOverride(wxString *aSource=nullptr) const
Definition: pad.cpp:1116
wxString ShowPadAttr() const
Definition: pad.cpp:1409
wxString ShowPadShape() const
Definition: pad.cpp:1393
void SetDrillShape(PAD_DRILL_SHAPE aShape)
Definition: pad.h:372
int m_effectiveBoundingRadius
Definition: pad.h:867
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: pad.h:414
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:453
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:434
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.h:410
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition: pad.cpp:1691
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:2404
void SetDelta(const VECTOR2I &aSize)
Definition: pad.h:263
bool IsOnCopperLayer() const override
Definition: pad.cpp:911
void SetDrillSizeX(const int aX)
Definition: pad.h:268
void SetPadstack(const PADSTACK &aPadstack)
Definition: pad.h:280
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:195
const PADSTACK & Padstack() const
Definition: pad.h:278
VECTOR2I m_pos
Definition: pad.h:853
const VECTOR2I & GetDelta() const
Definition: pad.h:264
void BuildEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:693
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition: pad.cpp:300
void SetDrillSize(const VECTOR2I &aSize)
Definition: pad.h:266
bool IsFreePad() const
Definition: pad.cpp:279
PAD_SHAPE GetShape() const
Definition: pad.h:193
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:359
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition: pad.h:214
PAD_DRILL_SHAPE GetDrillShape() const
Definition: pad.h:377
void Flip(const VECTOR2I &VECTOR2I, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: pad.cpp:826
VECTOR2I GetSolderPasteMargin() const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition: pad.cpp:1034
static LSET ApertureMask()
layer set for an aperture pad
Definition: pad.cpp:314
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pad.cpp:1667
bool m_shapesDirty
Definition: pad.h:858
std::mutex m_polyBuildingLock
Definition: pad.h:865
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:293
std::optional< int > GetLocalSolderPasteMargin() const
Definition: pad.h:419
void CheckPad(UNITS_PROVIDER *aUnitsProvider, const std::function< void(int aErrorCode, const wxString &aMsg)> &aErrorHandler) const
Definition: pad.cpp:2048
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pad.h:413
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: pad.h:420
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:184
int GetSizeY() const
Definition: pad.h:261
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pad.cpp:329
int GetThermalSpokeWidth() const
Definition: pad.h:555
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition: pad.cpp:1422
void SetPinFunction(const wxString &aName)
Set the pad function (pin name in schematic)
Definition: pad.h:144
EDA_ANGLE GetFPRelativeOrientation() const
Definition: pad.cpp:817
bool m_polyDirty[2]
Definition: pad.h:864
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:1253
void SetFPRelativeOrientation(const EDA_ANGLE &aAngle)
Definition: pad.cpp:808
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:224
int GetBoundingRadius() const
Return the radius of a minimum sized circle which fully encloses this pad.
Definition: pad.cpp:508
void SetRoundRectRadiusRatio(double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:437
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:235
std::array< ZONE_LAYER_OVERRIDE, MAX_CU_LAYERS > m_zoneLayerOverrides
Definition: pad.h:879
void AddPrimitive(PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition: pad.cpp:801
PADSTACK::UNCONNECTED_LAYER_MODE GetUnconnectedLayerMode() const
Definition: pad.h:671
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: pad.cpp:1513
int GetChamferPositions() const
Definition: pad.h:624
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:1525
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:849
void SetLocalClearance(std::optional< int > aClearance)
Definition: pad.h:411
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:462
int GetSubRatsnest() const
Definition: pad.h:629
void SetSizeX(const int aX)
Definition: pad.h:258
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: pad.h:435
int m_lengthPadToDie
Definition: pad.h:876
void SetThermalSpokeWidth(int aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: pad.h:554
void SetSize(const VECTOR2I &aSize)
Definition: pad.h:251
void SetDrillSizeY(const int aY)
Definition: pad.h:270
double GetThermalSpokeAngleDegrees() const
Definition: pad.h:578
double GetRoundRectRadiusRatio() const
Definition: pad.h:605
int GetThermalGap() const
Definition: pad.h:584
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:499
void SetOrientationDegrees(double aOrientation)
Definition: pad.h:363
ZONE_CONNECTION GetZoneConnectionOverrides(wxString *aSource=nullptr) const
Definition: pad.cpp:1087
bool SharesNetTieGroup(const PAD *aOther) const
Definition: pad.cpp:256
const VECTOR2I & GetSize() const
Definition: pad.h:256
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: pad.cpp:1591
void SetSubRatsnest(int aSubRatsnest)
Definition: pad.h:630
std::shared_ptr< SHAPE_COMPOUND > m_effectiveShape
Definition: pad.h:861
void SetChamferPositions(int aPositions)
Has meaning only for chamfered rectangular pads.
Definition: pad.h:623
int GetLocalSpokeWidthOverride(wxString *aSource=nullptr) const
Definition: pad.cpp:1107
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:206
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
Definition: pad.cpp:1791
double GetChamferRectRatio() const
Definition: pad.h:614
void SetPadToDieLength(int aLength)
Definition: pad.h:407
bool IsFlipped() const
Definition: pad.cpp:321
bool operator==(const PAD &aOther) const
Definition: pad.cpp:2320
void SetSizeY(const int aY)
Definition: pad.h:260
int GetPadToDieLength() const
Definition: pad.h:408
BOX2I m_effectiveBoundingBox
Definition: pad.h:860
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:526
bool IsProxyItem() const override
Definition: pcb_shape.h:110
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
Definition: pcb_shape.cpp:821
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:455
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:86
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:70
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 BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
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)
int OutlineCount() const
Return the number of outlines in the set.
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
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
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.
static PCB_SHAPE * findNext(PCB_SHAPE *aShape, const VECTOR2I &aPoint, const std::vector< PCB_SHAPE * > &aList, unsigned aLimit)
Search for a PCB_SHAPE matching a given end point or start point in a list.
#define _HKI(x)
@ DRCE_PADSTACK
Definition: drc_item.h:59
@ DRCE_PADSTACK_INVALID
Definition: drc_item.h:60
@ DRCE_PAD_TH_WITH_NO_HOLE
Definition: drc_item.h:80
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:48
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
#define FOOTPRINT_EDIT_FRAME_NAME
#define PCB_EDIT_FRAME_NAME
#define ENTERED
indicates a group has been entered
#define SKIP_STRUCT
flag indicating that the structure should be ignored
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:605
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:628
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
@ 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:684
bool IsHoleLayer(int aLayer)
Definition: layer_ids.h:570
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
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
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 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:390
static struct PAD_DESC _PAD_DESC
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: padstack.h:74
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: padstack.h:46
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition: padstack.h:91
#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:226
PAD_DESC()
Definition: pad.cpp:2494
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:121
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673
VECTOR2< double > VECTOR2D
Definition: vector2d.h:672
VECTOR2< int64_t > VECTOR2L
Definition: vector2d.h:674
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition: zones.h:36