KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <dick@softplc.com>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, 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 <math/util.h> // for KiROUND
29#include <eda_draw_frame.h>
33#include <geometry/shape_rect.h>
35#include <geometry/shape_null.h>
36#include <layer_range.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 <pad_utils.h>
47#include <pcb_shape.h>
49#include <eda_units.h>
51#include <widgets/msgpanel.h>
52#include <pcb_painter.h>
54#include <wx/log.h>
55#include <api/api_enums.h>
56#include <api/api_utils.h>
57#include <api/api_pcb_utils.h>
58#include <api/board/board_types.pb.h>
59
60#include <memory>
61#include <macros.h>
62#include <magic_enum.hpp>
63#include <drc/drc_item.h>
64#include "kiface_base.h"
65#include "pcbnew_settings.h"
66
67#include <pcb_group.h>
69
72
73
74PAD::PAD( FOOTPRINT* parent ) :
76 m_padStack( this )
77{
78 VECTOR2I& drill = m_padStack.Drill().size;
82 drill.x = drill.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 30 ); // Default drill size 30 mils.
84
87
88 SetShape( F_Cu, PAD_SHAPE::CIRCLE ); // Default pad shape is PAD_CIRCLE.
89 SetAnchorPadShape( F_Cu, PAD_SHAPE::CIRCLE ); // Default shape for custom shaped pads
90 // is PAD_CIRCLE.
91 SetDrillShape( PAD_DRILL_SHAPE::CIRCLE ); // Default pad drill shape is a circle.
92 m_attribute = PAD_ATTRIB::PTH; // Default pad type is plated through hole
93 SetProperty( PAD_PROP::NONE ); // no special fabrication property
94
95 // Parameters for round rect only:
96 m_padStack.SetRoundRectRadiusRatio( 0.25, F_Cu ); // from IPC-7351C standard
97
98 // Parameters for chamfered rect only:
101
102 // Set layers mask to default for a standard thru hole pad.
104
105 SetSubRatsnest( 0 ); // used in ratsnest calculations
106
107 SetDirty();
109
112
113 m_lastGalZoomLevel = 0.0;
114}
115
116
117PAD::PAD( const PAD& aOther ) :
118 BOARD_CONNECTED_ITEM( aOther.GetParent(), PCB_PAD_T ),
119 m_padStack( this )
120{
121 PAD::operator=( aOther );
122
123 const_cast<KIID&>( m_Uuid ) = aOther.m_Uuid;
124}
125
126
127PAD& PAD::operator=( const PAD &aOther )
128{
130
131 ImportSettingsFrom( aOther );
133 SetPosition( aOther.GetPosition() );
134 SetNumber( aOther.GetNumber() );
135 SetPinType( aOther.GetPinType() );
136 SetPinFunction( aOther.GetPinFunction() );
137 SetSubRatsnest( aOther.GetSubRatsnest() );
139
140 return *this;
141}
142
143
144void PAD::CopyFrom( const BOARD_ITEM* aOther )
145{
146 wxCHECK( aOther && aOther->Type() == PCB_PAD_T, /* void */ );
147 *this = *static_cast<const PAD*>( aOther );
148}
149
150
151void PAD::Serialize( google::protobuf::Any &aContainer ) const
152{
153 using namespace kiapi::board::types;
154 Pad pad;
155
156 pad.mutable_id()->set_value( m_Uuid.AsStdString() );
157 kiapi::common::PackVector2( *pad.mutable_position(), GetPosition() );
158 pad.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
159 : kiapi::common::types::LockedState::LS_UNLOCKED );
160 pad.mutable_net()->mutable_code()->set_value( GetNetCode() );
161 pad.mutable_net()->set_name( GetNetname() );
162 pad.set_number( GetNumber().ToUTF8() );
163 pad.set_type( ToProtoEnum<PAD_ATTRIB, PadType>( GetAttribute() ) );
164
165 google::protobuf::Any padStackMsg;
166 m_padStack.Serialize( padStackMsg );
167 padStackMsg.UnpackTo( pad.mutable_pad_stack() );
168
169 if( GetLocalClearance().has_value() )
170 pad.mutable_copper_clearance_override()->set_value_nm( *GetLocalClearance() );
171
172 aContainer.PackFrom( pad );
173}
174
175
176bool PAD::Deserialize( const google::protobuf::Any &aContainer )
177{
178 kiapi::board::types::Pad pad;
179
180 if( !aContainer.UnpackTo( &pad ) )
181 return false;
182
183 const_cast<KIID&>( m_Uuid ) = KIID( pad.id().value() );
185 SetNetCode( pad.net().code().value() );
186 SetLocked( pad.locked() == kiapi::common::types::LockedState::LS_LOCKED );
187 SetAttribute( FromProtoEnum<PAD_ATTRIB>( pad.type() ) );
188 SetNumber( wxString::FromUTF8( pad.number() ) );
189
190 google::protobuf::Any padStackWrapper;
191 padStackWrapper.PackFrom( pad.pad_stack() );
192 m_padStack.Deserialize( padStackWrapper );
193
195
196 if( pad.has_copper_clearance_override() )
197 SetLocalClearance( pad.copper_clearance_override().value_nm() );
198 else
199 SetLocalClearance( std::nullopt );
200
201 return true;
202}
203
204
206{
207 std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
208
211}
212
213
215{
216 std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
217
218 static const ZONE_LAYER_OVERRIDE defaultOverride = ZLO_NONE;
219 auto it = m_zoneLayerOverrides.find( aLayer );
220 return it != m_zoneLayerOverrides.end() ? it->second : defaultOverride;
221}
222
223
225{
226 std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
227 m_zoneLayerOverrides[aLayer] = aOverride;
228}
229
230
232{
233 // Aperture pads don't get a number
234 if( IsAperturePad() )
235 return false;
236
237 // NPTH pads don't get numbers
238 if( GetAttribute() == PAD_ATTRIB::NPTH )
239 return false;
240
241 return true;
242}
243
244
245bool PAD::IsLocked() const
246{
247 if( GetParent() && GetParent()->IsLocked() )
248 return true;
249
250 return BOARD_ITEM::IsLocked();
251};
252
253
254bool PAD::SharesNetTieGroup( const PAD* aOther ) const
255{
256 FOOTPRINT* parentFp = GetParentFootprint();
257
258 if( parentFp && parentFp->IsNetTie() && aOther->GetParentFootprint() == parentFp )
259 {
260 std::map<wxString, int> padToNetTieGroupMap = parentFp->MapPadNumbersToNetTieGroups();
261 int thisNetTieGroup = padToNetTieGroupMap[ GetNumber() ];
262 int otherNetTieGroup = padToNetTieGroupMap[ aOther->GetNumber() ];
263
264 return thisNetTieGroup >= 0 && thisNetTieGroup == otherNetTieGroup;
265 }
266
267 return false;
268}
269
270
272{
273 return m_pinType.Contains( wxT( "no_connect" ) );
274}
275
276
277bool PAD::IsFreePad() const
278{
279 return GetShortNetname().StartsWith( wxT( "unconnected-(" ) )
280 && m_pinType == wxT( "free" );
281}
282
283
285{
286 static LSET saved = LSET::AllCuMask() | LSET( { F_Mask, B_Mask } );
287 return saved;
288}
289
290
292{
293 static LSET saved( { F_Cu, F_Paste, F_Mask } );
294 return saved;
295}
296
297
299{
300 static LSET saved( { F_Cu, F_Mask } );
301 return saved;
302}
303
304
306{
307 static LSET saved = LSET( { F_Cu, B_Cu, F_Mask, B_Mask } );
308 return saved;
309}
310
311
313{
314 static LSET saved( { F_Paste } );
315 return saved;
316}
317
318
319bool PAD::IsFlipped() const
320{
321 FOOTPRINT* parent = GetParentFootprint();
322
323 return ( parent && parent->GetLayer() == B_Cu );
324}
325
326
328{
329 return BOARD_ITEM::GetLayer();
330}
331
332
334{
335 if( m_attribute == PAD_ATTRIB::SMD || m_attribute == PAD_ATTRIB::CONN || GetLayerSet().none() )
336 return m_layer;
337 else
338 return GetLayerSet().Seq().front();
339
340}
341
342
343bool PAD::FlashLayer( const LSET& aLayers ) const
344{
345 for( PCB_LAYER_ID layer : aLayers.Seq() )
346 {
347 if( FlashLayer( layer ) )
348 return true;
349 }
350
351 return false;
352}
353
354
355bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
356{
357 if( aLayer == UNDEFINED_LAYER )
358 return true;
359
360 // Sometimes this is called with GAL layers and should just return true
361 if( aLayer > PCB_LAYER_ID_COUNT )
362 return true;
363
364 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer );
365
366 if( !IsOnLayer( layer ) )
367 return false;
368
369 if( GetAttribute() == PAD_ATTRIB::NPTH && IsCopperLayer( aLayer ) )
370 {
371 if( GetShape( layer ) == PAD_SHAPE::CIRCLE && GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
372 {
373 if( GetOffset( layer ) == VECTOR2I( 0, 0 ) && GetDrillSize().x >= GetSize( layer ).x )
374 return false;
375 }
376 else if( GetShape( layer ) == PAD_SHAPE::OVAL
377 && GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
378 {
379 if( GetOffset( layer ) == VECTOR2I( 0, 0 )
380 && GetDrillSize().x >= GetSize( layer ).x
381 && GetDrillSize().y >= GetSize( layer ).y )
382 {
383 return false;
384 }
385 }
386 }
387
388 if( LSET::FrontBoardTechMask().test( aLayer ) )
389 aLayer = F_Cu;
390 else if( LSET::BackBoardTechMask().test( aLayer ) )
391 aLayer = B_Cu;
392
393 if( GetAttribute() == PAD_ATTRIB::PTH && IsCopperLayer( aLayer ) )
394 {
396
398 return true;
399
400 // Plated through hole pads need copper on the top/bottom layers for proper soldering
401 // Unless the user has removed them in the pad dialog
403 && ( aLayer == F_Cu || aLayer == B_Cu ) )
404 {
405 return true;
406 }
407
408 if( const BOARD* board = GetBoard() )
409 {
411 {
412 return true;
413 }
414 else if( aOnlyCheckIfPermitted )
415 {
416 return true;
417 }
418 else
419 {
420 // Must be static to keep from raising its ugly head in performance profiles
421 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T,
423
424 return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, nonZoneTypes );
425 }
426 }
427 }
428
429 return true;
430}
431
432
433void PAD::SetDrillSizeX( const int aX )
434{
435 m_padStack.Drill().size.x = aX;
436
437 if( GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
438 SetDrillSizeY( aX );
439
440 SetDirty();
441}
442
443
445{
446 m_padStack.Drill().shape = aShape;
447
448 if( aShape == PAD_DRILL_SHAPE::CIRCLE )
450
451 m_shapesDirty = true;
452}
453
454
456{
457 return m_padStack.RoundRectRadius( aLayer );
458}
459
460
461void PAD::SetRoundRectCornerRadius( PCB_LAYER_ID aLayer, double aRadius )
462{
463 m_padStack.SetRoundRectRadius( aRadius, aLayer );
464}
465
466
467void PAD::SetRoundRectRadiusRatio( PCB_LAYER_ID aLayer, double aRadiusScale )
468{
469 m_padStack.SetRoundRectRadiusRatio( std::clamp( aRadiusScale, 0.0, 0.5 ), aLayer );
470
471 SetDirty();
472}
473
474
475void PAD::SetFrontRoundRectRadiusRatio( double aRadiusScale )
476{
477 wxASSERT_MSG( m_padStack.Mode() == PADSTACK::MODE::NORMAL,
478 "Set front radius only meaningful for normal padstacks" );
479
480 m_padStack.SetRoundRectRadiusRatio( std::clamp( aRadiusScale, 0.0, 0.5 ), F_Cu );
481 SetDirty();
482}
483
484
486{
487 const VECTOR2I size = m_padStack.Size( F_Cu );
488 const int minSize = std::min( size.x, size.y );
489 const double newRatio = aRadius / double( minSize );
490
492}
493
494
496{
497 const VECTOR2I size = m_padStack.Size( F_Cu );
498 const int minSize = std::min( size.x, size.y );
499 const double ratio = GetFrontRoundRectRadiusRatio();
500
501 return KiROUND( ratio * minSize );
502}
503
504
505void PAD::SetChamferRectRatio( PCB_LAYER_ID aLayer, double aChamferScale )
506{
507 m_padStack.SetChamferRatio( std::clamp( aChamferScale, 0.0, 0.5 ), aLayer );
508
509 SetDirty();
510}
511
512
513const std::shared_ptr<SHAPE_POLY_SET>& PAD::GetEffectivePolygon( PCB_LAYER_ID aLayer,
514 ERROR_LOC aErrorLoc ) const
515{
516 if( m_polyDirty[ aErrorLoc ] )
517 BuildEffectivePolygon( aErrorLoc );
518
519 aLayer = Padstack().EffectiveLayerFor( aLayer );
520
521 return m_effectivePolygons[ aLayer ][ aErrorLoc ];
522}
523
524
525std::shared_ptr<SHAPE> PAD::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING flashPTHPads ) const
526{
527 if( aLayer == Edge_Cuts )
528 {
529 std::shared_ptr<SHAPE_COMPOUND> effective_compund = std::make_shared<SHAPE_COMPOUND>();
530
531 if( GetAttribute() == PAD_ATTRIB::PTH || GetAttribute() == PAD_ATTRIB::NPTH )
532 {
533 effective_compund->AddShape( GetEffectiveHoleShape() );
534 return effective_compund;
535 }
536 else
537 {
538 effective_compund->AddShape( std::make_shared<SHAPE_NULL>() );
539 return effective_compund;
540 }
541 }
542
543 if( GetAttribute() == PAD_ATTRIB::PTH )
544 {
545 bool flash;
546 std::shared_ptr<SHAPE_COMPOUND> effective_compund = std::make_shared<SHAPE_COMPOUND>();
547
548 if( flashPTHPads == FLASHING::NEVER_FLASHED )
549 flash = false;
550 else if( flashPTHPads == FLASHING::ALWAYS_FLASHED )
551 flash = true;
552 else
553 flash = FlashLayer( aLayer );
554
555 if( !flash )
556 {
557 if( GetAttribute() == PAD_ATTRIB::PTH )
558 {
559 effective_compund->AddShape( GetEffectiveHoleShape() );
560 return effective_compund;
561 }
562 else
563 {
564 effective_compund->AddShape( std::make_shared<SHAPE_NULL>() );
565 return effective_compund;
566 }
567 }
568 }
569
570 if( m_shapesDirty )
572
573 aLayer = Padstack().EffectiveLayerFor( aLayer );
574
575 wxCHECK_MSG( m_effectiveShapes.contains( aLayer ) && m_effectiveShapes.at( aLayer ), nullptr,
576 wxT( "Null shape in PAD::GetEffectiveShape!" ) );
577
578 return m_effectiveShapes[aLayer];
579}
580
581
582std::shared_ptr<SHAPE_SEGMENT> PAD::GetEffectiveHoleShape() const
583{
584 if( m_shapesDirty )
586
588}
589
590
592{
595
597}
598
599
601{
602 std::lock_guard<std::mutex> RAII_lock( m_shapesBuildingLock );
603
604 // If we had to wait for the lock then we were probably waiting for someone else to
605 // finish rebuilding the shapes. So check to see if they're clean now.
606 if( !m_shapesDirty )
607 return;
608
610
612 [&]( PCB_LAYER_ID aLayer )
613 {
614 const SHAPE_COMPOUND& layerShape = buildEffectiveShape( aLayer );
615 m_effectiveBoundingBox.Merge( layerShape.BBox() );
616 } );
617
618 // Hole shape
619 m_effectiveHoleShape = nullptr;
620
621 VECTOR2I half_size = m_padStack.Drill().size / 2;
622 int half_width;
623 VECTOR2I half_len;
624
625 if( m_padStack.Drill().shape == PAD_DRILL_SHAPE::CIRCLE )
626 {
627 half_width = half_size.x;
628 }
629 else
630 {
631 half_width = std::min( half_size.x, half_size.y );
632 half_len = VECTOR2I( half_size.x - half_width, half_size.y - half_width );
633 }
634
635 RotatePoint( half_len, GetOrientation() );
636
637 m_effectiveHoleShape = std::make_shared<SHAPE_SEGMENT>( m_pos - half_len, m_pos + half_len,
638 half_width * 2 );
640
641 // All done
642 m_shapesDirty = false;
643}
644
645
647{
648 const BOARD* board = GetBoard();
649 int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
650
651 m_effectiveShapes[aLayer] = std::make_shared<SHAPE_COMPOUND>();
652
653 auto add = [this, aLayer]( SHAPE* aShape )
654 {
655 m_effectiveShapes[aLayer]->AddShape( aShape );
656 };
657
658 VECTOR2I shapePos = ShapePos( aLayer ); // Fetch only once; rotation involves trig
659 PAD_SHAPE effectiveShape = GetShape( aLayer );
660 const VECTOR2I& size = m_padStack.Size( aLayer );
661
662 if( effectiveShape == PAD_SHAPE::CUSTOM )
663 effectiveShape = GetAnchorPadShape( aLayer );
664
665 switch( effectiveShape )
666 {
667 case PAD_SHAPE::CIRCLE:
668 add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
669 break;
670
671 case PAD_SHAPE::OVAL:
672 if( size.x == size.y ) // the oval pad is in fact a circle
673 {
674 add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
675 }
676 else
677 {
678 VECTOR2I half_size = 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 RotatePoint( half_len, GetOrientation() );
682 add( new SHAPE_SEGMENT( shapePos - half_len, shapePos + half_len, half_width * 2 ) );
683 }
684
685 break;
686
687 case PAD_SHAPE::RECTANGLE:
688 case PAD_SHAPE::TRAPEZOID:
689 case PAD_SHAPE::ROUNDRECT:
690 {
691 int r = ( effectiveShape == PAD_SHAPE::ROUNDRECT ) ? GetRoundRectCornerRadius( aLayer ) : 0;
692 VECTOR2I half_size( size.x / 2, size.y / 2 );
693 VECTOR2I trap_delta( 0, 0 );
694
695 if( r )
696 {
697 half_size -= VECTOR2I( r, r );
698
699 // Avoid degenerated shapes (0 length segments) that always create issues
700 // For roundrect pad very near a circle, use only a circle
701 const int min_len = pcbIUScale.mmToIU( 0.0001 );
702
703 if( half_size.x < min_len && half_size.y < min_len )
704 {
705 add( new SHAPE_CIRCLE( shapePos, r ) );
706 break;
707 }
708 }
709 else if( effectiveShape == PAD_SHAPE::TRAPEZOID )
710 {
711 trap_delta = m_padStack.TrapezoidDeltaSize( aLayer ) / 2;
712 }
713
714 SHAPE_LINE_CHAIN corners;
715
716 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
717 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
718 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
719 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
720
721 corners.Rotate( GetOrientation() );
722 corners.Move( shapePos );
723
724 // GAL renders rectangles faster than 4-point polygons so it's worth checking if our
725 // body shape is a rectangle.
726 if( corners.PointCount() == 4
727 &&
728 ( ( corners.CPoint( 0 ).y == corners.CPoint( 1 ).y
729 && corners.CPoint( 1 ).x == corners.CPoint( 2 ).x
730 && corners.CPoint( 2 ).y == corners.CPoint( 3 ).y
731 && corners.CPoint( 3 ).x == corners.CPoint( 0 ).x )
732 ||
733 ( corners.CPoint( 0 ).x == corners.CPoint( 1 ).x
734 && corners.CPoint( 1 ).y == corners.CPoint( 2 ).y
735 && corners.CPoint( 2 ).x == corners.CPoint( 3 ).x
736 && corners.CPoint( 3 ).y == corners.CPoint( 0 ).y )
737 )
738 )
739 {
740 int width = std::abs( corners.CPoint( 2 ).x - corners.CPoint( 0 ).x );
741 int height = std::abs( corners.CPoint( 2 ).y - corners.CPoint( 0 ).y );
742 VECTOR2I pos( std::min( corners.CPoint( 2 ).x, corners.CPoint( 0 ).x ),
743 std::min( corners.CPoint( 2 ).y, corners.CPoint( 0 ).y ) );
744
745 add( new SHAPE_RECT( pos, width, height ) );
746 }
747 else
748 {
749 add( new SHAPE_SIMPLE( corners ) );
750 }
751
752 if( r )
753 {
754 add( new SHAPE_SEGMENT( corners.CPoint( 0 ), corners.CPoint( 1 ), r * 2 ) );
755 add( new SHAPE_SEGMENT( corners.CPoint( 1 ), corners.CPoint( 2 ), r * 2 ) );
756 add( new SHAPE_SEGMENT( corners.CPoint( 2 ), corners.CPoint( 3 ), r * 2 ) );
757 add( new SHAPE_SEGMENT( corners.CPoint( 3 ), corners.CPoint( 0 ), r * 2 ) );
758 }
759 }
760 break;
761
762 case PAD_SHAPE::CHAMFERED_RECT:
763 {
764 SHAPE_POLY_SET outline;
765
766 TransformRoundChamferedRectToPolygon( outline, shapePos, GetSize( aLayer ),
768 GetChamferRectRatio( aLayer ),
769 GetChamferPositions( aLayer ), 0, maxError,
770 ERROR_INSIDE );
771
772 add( new SHAPE_SIMPLE( outline.COutline( 0 ) ) );
773 }
774 break;
775
776 default:
777 wxFAIL_MSG( wxT( "PAD::buildEffectiveShapes: Unsupported pad shape: PAD_SHAPE::" )
778 + wxString( std::string( magic_enum::enum_name( effectiveShape ) ) ) );
779 break;
780 }
781
782 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
783 {
784 for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives( aLayer ) )
785 {
786 if( !primitive->IsProxyItem() )
787 {
788 for( SHAPE* shape : primitive->MakeEffectiveShapes() )
789 {
790 shape->Rotate( GetOrientation() );
791 shape->Move( shapePos );
792 add( shape );
793 }
794 }
795 }
796 }
797
798 return *m_effectiveShapes[aLayer];
799}
800
801
803{
804 std::lock_guard<std::mutex> RAII_lock( m_polyBuildingLock );
805
806 // If we had to wait for the lock then we were probably waiting for someone else to
807 // finish rebuilding the shapes. So check to see if they're clean now.
808 if( !m_polyDirty[ aErrorLoc ] )
809 return;
810
811 const BOARD* board = GetBoard();
812 int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
813
815 [&]( PCB_LAYER_ID aLayer )
816 {
817 // Polygon
818 std::shared_ptr<SHAPE_POLY_SET>& effectivePolygon =
819 m_effectivePolygons[ aLayer ][ aErrorLoc ];
820
821 effectivePolygon = std::make_shared<SHAPE_POLY_SET>();
822 TransformShapeToPolygon( *effectivePolygon, aLayer, 0, maxError, aErrorLoc );
823
824 // Bounding radius
825
826 if( aErrorLoc == ERROR_OUTSIDE )
827 {
829
830 for( int cnt = 0; cnt < effectivePolygon->OutlineCount(); ++cnt )
831 {
832 const SHAPE_LINE_CHAIN& poly = effectivePolygon->COutline( cnt );
833
834 for( int ii = 0; ii < poly.PointCount(); ++ii )
835 {
836 int dist = KiROUND( ( poly.CPoint( ii ) - m_pos ).EuclideanNorm() );
838 }
839 }
840 }
841
842 } );
843
844 // All done
845 m_polyDirty[ aErrorLoc ] = false;
846}
847
848
850{
851 if( m_shapesDirty )
853
855}
856
857
859{
860 if( m_attribute != aAttribute )
861 {
862 m_attribute = aAttribute;
863
864 LSET& layerMask = m_padStack.LayerSet();
865
866 switch( aAttribute )
867 {
868 case PAD_ATTRIB::PTH:
869 // Plump up to all copper layers
870 layerMask |= LSET::AllCuMask();
871 break;
872
873 case PAD_ATTRIB::SMD:
874 case PAD_ATTRIB::CONN:
875 {
876 // Trim down to no more than one copper layer
877 LSET copperLayers = layerMask & LSET::AllCuMask();
878
879 if( copperLayers.count() > 1 )
880 {
881 layerMask &= ~LSET::AllCuMask();
882
883 if( copperLayers.test( B_Cu ) )
884 layerMask.set( B_Cu );
885 else
886 layerMask.set( copperLayers.Seq().front() );
887 }
888
889 // No hole
890 m_padStack.Drill().size = VECTOR2I( 0, 0 );
891 break;
892 }
893
894 case PAD_ATTRIB::NPTH:
895 // No number; no net
896 m_number = wxEmptyString;
898 break;
899 }
900 }
901
902 SetDirty();
903}
904
905
907{
908 const bool wasRoundable = PAD_UTILS::PadHasMeaningfulRoundingRadius( *this, F_Cu );
909
910 m_padStack.SetShape( aShape, F_Cu );
911
912 const bool isRoundable = PAD_UTILS::PadHasMeaningfulRoundingRadius( *this, F_Cu );
913
914 // If we have become roundable, set a sensible rounding default using the IPC rules.
915 if( !wasRoundable && isRoundable )
916 {
917 const double ipcRadiusRatio = PAD_UTILS::GetDefaultIpcRoundingRatio( *this, F_Cu );
918 m_padStack.SetRoundRectRadiusRatio( ipcRadiusRatio, F_Cu );
919 }
920
921 SetDirty();
922}
923
924
925void PAD::SetProperty( PAD_PROP aProperty )
926{
927 m_property = aProperty;
928
929 SetDirty();
930}
931
932
933void PAD::SetOrientation( const EDA_ANGLE& aAngle )
934{
935 m_padStack.SetOrientation( aAngle );
936 SetDirty();
937}
938
939
941{
942 if( FOOTPRINT* parentFP = GetParentFootprint() )
943 SetOrientation( aAngle + parentFP->GetOrientation() );
944 else
945 SetOrientation( aAngle );
946}
947
948
950{
951 if( FOOTPRINT* parentFP = GetParentFootprint() )
952 return GetOrientation() - parentFP->GetOrientation();
953 else
954 return GetOrientation();
955}
956
957
958void PAD::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
959{
960 MIRROR( m_pos, aCentre, aFlipDirection );
961
963 [&]( PCB_LAYER_ID aLayer )
964 {
965 MIRROR( m_padStack.Offset( aLayer ), VECTOR2I{ 0, 0 }, aFlipDirection );
966 MIRROR( m_padStack.TrapezoidDeltaSize( aLayer ), VECTOR2I{ 0, 0 }, aFlipDirection );
967 } );
968
970
971 auto mirrorBitFlags = []( int& aBitfield, int a, int b )
972 {
973 bool temp = aBitfield & a;
974
975 if( aBitfield & b )
976 aBitfield |= a;
977 else
978 aBitfield &= ~a;
979
980 if( temp )
981 aBitfield |= b;
982 else
983 aBitfield &= ~b;
984 };
985
987 [&]( PCB_LAYER_ID aLayer )
988 {
989 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
990 {
991 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_TOP_LEFT,
993 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_BOTTOM_LEFT,
995 }
996 else
997 {
998 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_TOP_LEFT,
1000 mirrorBitFlags( m_padStack.ChamferPositions( aLayer ), RECT_CHAMFER_TOP_RIGHT,
1002 }
1003 } );
1004
1005 // Flip padstack geometry
1006 int copperLayerCount = BoardCopperLayerCount();
1007
1008 m_padStack.FlipLayers( copperLayerCount );
1009
1010 // Flip pads layers after padstack geometry
1011 LSET flipped;
1012
1013 for( PCB_LAYER_ID layer : m_padStack.LayerSet() )
1014 flipped.set( GetBoard()->FlipLayer( layer ) );
1015
1016 SetLayerSet( flipped );
1017
1018 // Flip the basic shapes, in custom pads
1019 FlipPrimitives( aFlipDirection );
1020
1021 SetDirty();
1022}
1023
1024
1026{
1028 [&]( PCB_LAYER_ID aLayer )
1029 {
1030 for( std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives( aLayer ) )
1031 {
1032 // Ensure the primitive parent is up to date. Flip uses GetBoard() that
1033 // imply primitive parent is valid
1034 primitive->SetParent(this);
1035 primitive->Flip( VECTOR2I( 0, 0 ), aFlipDirection );
1036 }
1037 } );
1038
1039 SetDirty();
1040}
1041
1042
1044{
1045 VECTOR2I loc_offset = m_padStack.Offset( aLayer );
1046
1047 if( loc_offset.x == 0 && loc_offset.y == 0 )
1048 return m_pos;
1049
1050 RotatePoint( loc_offset, GetOrientation() );
1051
1052 VECTOR2I shape_pos = m_pos + loc_offset;
1053
1054 return shape_pos;
1055}
1056
1057
1059{
1060 if( GetAttribute() == PAD_ATTRIB::NPTH )
1061 {
1062 // NPTH pads have no plated hole cylinder. If their annular ring size is 0 or
1063 // negative, then they have no annular ring either.
1064 bool hasAnnularRing = true;
1065
1067 [&]( PCB_LAYER_ID aLayer )
1068 {
1069 switch( GetShape( aLayer ) )
1070 {
1071 case PAD_SHAPE::CIRCLE:
1072 if( m_padStack.Offset( aLayer ) == VECTOR2I( 0, 0 )
1073 && m_padStack.Size( aLayer ).x <= m_padStack.Drill().size.x )
1074 {
1075 hasAnnularRing = false;
1076 }
1077
1078 break;
1079
1080 case PAD_SHAPE::OVAL:
1081 if( m_padStack.Offset( aLayer ) == VECTOR2I( 0, 0 )
1082 && m_padStack.Size( aLayer ).x <= m_padStack.Drill().size.x
1083 && m_padStack.Size( aLayer ).y <= m_padStack.Drill().size.y )
1084 {
1085 hasAnnularRing = false;
1086 }
1087
1088 break;
1089
1090 default:
1091 // We could subtract the hole polygon from the shape polygon for these, but it
1092 // would be expensive and we're probably well out of the common use cases....
1093 break;
1094 }
1095 } );
1096
1097 if( !hasAnnularRing )
1098 return false;
1099 }
1100
1101 return ( GetLayerSet() & LSET::AllCuMask() ).any();
1102}
1103
1104
1105std::optional<int> PAD::GetLocalClearance( wxString* aSource ) const
1106{
1107 if( m_padStack.Clearance().has_value() && aSource )
1108 *aSource = _( "pad" );
1109
1110 return m_padStack.Clearance();
1111}
1112
1113
1114std::optional<int> PAD::GetClearanceOverrides( wxString* aSource ) const
1115{
1116 if( m_padStack.Clearance().has_value() )
1117 return GetLocalClearance( aSource );
1118
1119 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1120 return parentFootprint->GetClearanceOverrides( aSource );
1121
1122 return std::optional<int>();
1123}
1124
1125
1126int PAD::GetOwnClearance( PCB_LAYER_ID aLayer, wxString* aSource ) const
1127{
1129
1130 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
1131 {
1133
1134 if( GetAttribute() == PAD_ATTRIB::NPTH )
1135 c = bds.m_DRCEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, this, nullptr, aLayer );
1136 else
1137 c = bds.m_DRCEngine->EvalRules( CLEARANCE_CONSTRAINT, this, nullptr, aLayer );
1138 }
1139
1140 if( c.Value().HasMin() )
1141 {
1142 if( aSource )
1143 *aSource = c.GetName();
1144
1145 return c.Value().Min();
1146 }
1147
1148 return 0;
1149}
1150
1151
1153{
1154 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
1155 // defined by the pad settings only. ALL other pads, even those that don't actually have
1156 // any copper (such as NPTH pads with holes the same size as the pad) get mask expansion.
1157 if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
1158 return 0;
1159
1160 if( IsFrontLayer( aLayer ) )
1161 aLayer = F_Mask;
1162 else if( IsBackLayer( aLayer ) )
1163 aLayer = B_Mask;
1164 else
1165 return 0;
1166
1167 std::optional<int> margin = m_padStack.SolderMaskMargin( aLayer );
1168
1169 if( !margin.has_value() )
1170 {
1171 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1172 margin = parentFootprint->GetLocalSolderMaskMargin();
1173 }
1174
1175 if( !margin.has_value() )
1176 {
1177 if( const BOARD* brd = GetBoard() )
1178 margin = brd->GetDesignSettings().m_SolderMaskExpansion;
1179 }
1180
1181 int marginValue = margin.value_or( 0 );
1182
1183 PCB_LAYER_ID cuLayer = ( aLayer == B_Mask ) ? B_Cu : F_Cu;
1184
1185 // ensure mask have a size always >= 0
1186 if( marginValue < 0 )
1187 {
1188 int minsize = -std::min( m_padStack.Size( cuLayer ).x, m_padStack.Size( cuLayer ).y ) / 2;
1189
1190 if( marginValue < minsize )
1191 marginValue = minsize;
1192 }
1193
1194 return marginValue;
1195}
1196
1197
1199{
1200 // Pads defined only on mask layers (and perhaps on other tech layers) use the shape
1201 // defined by the pad settings only. ALL other pads, even those that don't actually have
1202 // any copper (such as NPTH pads with holes the same size as the pad) get paste expansion.
1203 if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
1204 return VECTOR2I( 0, 0 );
1205
1206 if( IsFrontLayer( aLayer ) )
1207 aLayer = F_Paste;
1208 else if( IsBackLayer( aLayer ) )
1209 aLayer = B_Paste;
1210 else
1211 return VECTOR2I( 0, 0 );
1212
1213 std::optional<int> margin = m_padStack.SolderPasteMargin( aLayer );
1214 std::optional<double> mratio = m_padStack.SolderPasteMarginRatio( aLayer );
1215
1216 if( !margin.has_value() )
1217 {
1218 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1219 margin = parentFootprint->GetLocalSolderPasteMargin();
1220 }
1221
1222 if( !margin.has_value() )
1223 {
1224 if( const BOARD* board = GetBoard() )
1225 margin = board->GetDesignSettings().m_SolderPasteMargin;
1226 }
1227
1228 if( !mratio.has_value() )
1229 {
1230 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1231 mratio = parentFootprint->GetLocalSolderPasteMarginRatio();
1232 }
1233
1234 if( !mratio.has_value() )
1235 {
1236 if( const BOARD* board = GetBoard() )
1237 mratio = board->GetDesignSettings().m_SolderPasteMarginRatio;
1238 }
1239
1240 PCB_LAYER_ID cuLayer = ( aLayer == B_Paste ) ? B_Cu : F_Cu;
1241 VECTOR2I padSize = m_padStack.Size( cuLayer );
1242
1243 VECTOR2I pad_margin;
1244 pad_margin.x = margin.value_or( 0 ) + KiROUND( padSize.x * mratio.value_or( 0 ) );
1245 pad_margin.y = margin.value_or( 0 ) + KiROUND( padSize.y * mratio.value_or( 0 ) );
1246
1247 // ensure mask have a size always >= 0
1248 if( m_padStack.Shape( aLayer ) != PAD_SHAPE::CUSTOM )
1249 {
1250 if( pad_margin.x < -padSize.x / 2 )
1251 pad_margin.x = -padSize.x / 2;
1252
1253 if( pad_margin.y < -padSize.y / 2 )
1254 pad_margin.y = -padSize.y / 2;
1255 }
1256
1257 return pad_margin;
1258}
1259
1260
1262{
1263 ZONE_CONNECTION connection = m_padStack.ZoneConnection().value_or( ZONE_CONNECTION::INHERITED );
1264
1265 if( connection != ZONE_CONNECTION::INHERITED )
1266 {
1267 if( aSource )
1268 *aSource = _( "pad" );
1269 }
1270
1271 if( connection == ZONE_CONNECTION::INHERITED )
1272 {
1273 if( FOOTPRINT* parentFootprint = GetParentFootprint() )
1274 connection = parentFootprint->GetZoneConnectionOverrides( aSource );
1275 }
1276
1277 return connection;
1278}
1279
1280
1281int PAD::GetLocalSpokeWidthOverride( wxString* aSource ) const
1282{
1283 if( m_padStack.ThermalSpokeWidth().has_value() && aSource )
1284 *aSource = _( "pad" );
1285
1286 return m_padStack.ThermalSpokeWidth().value_or( 0 );
1287}
1288
1289
1290int PAD::GetLocalThermalGapOverride( wxString* aSource ) const
1291{
1292 if( m_padStack.ThermalGap().has_value() && aSource )
1293 *aSource = _( "pad" );
1294
1295 return GetLocalThermalGapOverride().value_or( 0 );
1296}
1297
1298
1299void PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1300{
1301 wxString msg;
1302 FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( m_parent );
1303
1304 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1305 {
1306 if( parentFootprint )
1307 aList.emplace_back( _( "Footprint" ), parentFootprint->GetReference() );
1308 }
1309
1310 aList.emplace_back( _( "Pad" ), m_number );
1311
1312 if( !GetPinFunction().IsEmpty() )
1313 aList.emplace_back( _( "Pin Name" ), GetPinFunction() );
1314
1315 if( !GetPinType().IsEmpty() )
1316 aList.emplace_back( _( "Pin Type" ), GetPinType() );
1317
1318 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1319 {
1320 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
1321
1322 aList.emplace_back( _( "Resolved Netclass" ),
1323 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
1324
1325 if( IsLocked() )
1326 aList.emplace_back( _( "Status" ), _( "Locked" ) );
1327 }
1328
1329 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1330 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
1331
1332 if( aFrame->GetName() == FOOTPRINT_EDIT_FRAME_NAME )
1333 {
1334 if( GetAttribute() == PAD_ATTRIB::SMD )
1335 {
1336 // TOOD(JE) padstacks
1337 const std::shared_ptr<SHAPE_POLY_SET>& poly = GetEffectivePolygon( PADSTACK::ALL_LAYERS );
1338 double area = poly->Area();
1339
1340 aList.emplace_back( _( "Area" ), aFrame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
1341 }
1342 }
1343
1344 // Show the pad shape, attribute and property
1345 wxString props = ShowPadAttr();
1346
1347 if( GetProperty() != PAD_PROP::NONE )
1348 props += ',';
1349
1350 switch( GetProperty() )
1351 {
1352 case PAD_PROP::NONE: break;
1353 case PAD_PROP::BGA: props += _( "BGA" ); break;
1354 case PAD_PROP::FIDUCIAL_GLBL: props += _( "Fiducial global" ); break;
1355 case PAD_PROP::FIDUCIAL_LOCAL: props += _( "Fiducial local" ); break;
1356 case PAD_PROP::TESTPOINT: props += _( "Test point" ); break;
1357 case PAD_PROP::HEATSINK: props += _( "Heat sink" ); break;
1358 case PAD_PROP::CASTELLATED: props += _( "Castellated" ); break;
1359 case PAD_PROP::MECHANICAL: props += _( "Mechanical" ); break;
1360 }
1361
1362 // TODO(JE) How to show complex padstack info in the message panel
1363 aList.emplace_back( ShowPadShape( PADSTACK::ALL_LAYERS ), props );
1364
1367
1368 if( ( padShape == PAD_SHAPE::CIRCLE || padShape == PAD_SHAPE::OVAL )
1369 && padSize.x == padSize.y )
1370 {
1371 aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( padSize.x ) );
1372 }
1373 else
1374 {
1375 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( padSize.x ) );
1376 aList.emplace_back( _( "Height" ), aFrame->MessageTextFromValue( padSize.y ) );
1377 }
1378
1379 EDA_ANGLE fp_orient = parentFootprint ? parentFootprint->GetOrientation() : ANGLE_0;
1380 EDA_ANGLE pad_orient = GetOrientation() - fp_orient;
1381 pad_orient.Normalize180();
1382
1383 if( !fp_orient.IsZero() )
1384 msg.Printf( wxT( "%g(+ %g)" ), pad_orient.AsDegrees(), fp_orient.AsDegrees() );
1385 else
1386 msg.Printf( wxT( "%g" ), GetOrientation().AsDegrees() );
1387
1388 aList.emplace_back( _( "Rotation" ), msg );
1389
1390 if( GetPadToDieLength() )
1391 {
1392 aList.emplace_back( _( "Length in Package" ),
1394 }
1395
1396 const VECTOR2I& drill = m_padStack.Drill().size;
1397
1398 if( drill.x > 0 || drill.y > 0 )
1399 {
1400 if( GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
1401 {
1402 aList.emplace_back( _( "Hole" ),
1403 wxString::Format( wxT( "%s" ),
1404 aFrame->MessageTextFromValue( drill.x ) ) );
1405 }
1406 else
1407 {
1408 aList.emplace_back( _( "Hole X / Y" ),
1409 wxString::Format( wxT( "%s / %s" ),
1410 aFrame->MessageTextFromValue( drill.x ),
1411 aFrame->MessageTextFromValue( drill.y ) ) );
1412 }
1413 }
1414
1415 wxString source;
1416 int clearance = GetOwnClearance( UNDEFINED_LAYER, &source );
1417
1418 if( !source.IsEmpty() )
1419 {
1420 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
1421 aFrame->MessageTextFromValue( clearance ) ),
1422 wxString::Format( _( "(from %s)" ),
1423 source ) );
1424 }
1425#if 0
1426 // useful for debug only
1427 aList.emplace_back( wxT( "UUID" ), m_Uuid.AsString() );
1428#endif
1429}
1430
1431
1432bool PAD::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
1433{
1434 VECTOR2I delta = aPosition - GetPosition();
1435 int boundingRadius = GetBoundingRadius() + aAccuracy;
1436
1437 if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
1438 return false;
1439
1440 bool contains = false;
1441
1443 [&]( PCB_LAYER_ID l )
1444 {
1445 if( contains )
1446 return;
1447
1448 if( GetEffectivePolygon( l, ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy ) )
1449 contains = true;
1450 } );
1451
1452 return contains;
1453}
1454
1455
1456bool PAD::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1457{
1458 BOX2I arect = aRect;
1459 arect.Normalize();
1460 arect.Inflate( aAccuracy );
1461
1462 BOX2I bbox = GetBoundingBox();
1463
1464 if( aContained )
1465 {
1466 return arect.Contains( bbox );
1467 }
1468 else
1469 {
1470 // Fast test: if aRect is outside the polygon bounding box,
1471 // rectangles cannot intersect
1472 if( !arect.Intersects( bbox ) )
1473 return false;
1474
1475 bool hit = false;
1476
1478 [&]( PCB_LAYER_ID aLayer )
1479 {
1480 if( hit )
1481 return;
1482
1483 const std::shared_ptr<SHAPE_POLY_SET>& poly =
1485
1486 int count = poly->TotalVertices();
1487
1488 for( int ii = 0; ii < count; ii++ )
1489 {
1490 VECTOR2I vertex = poly->CVertex( ii );
1491 VECTOR2I vertexNext = poly->CVertex( ( ii + 1 ) % count );
1492
1493 // Test if the point is within aRect
1494 if( arect.Contains( vertex ) )
1495 {
1496 hit = true;
1497 break;
1498 }
1499
1500 // Test if this edge intersects aRect
1501 if( arect.Intersects( vertex, vertexNext ) )
1502 {
1503 hit = true;
1504 break;
1505 }
1506 }
1507 } );
1508
1509 return hit;
1510 }
1511}
1512
1513
1514int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
1515{
1516 int diff;
1517
1518 if( ( diff = static_cast<int>( aPadRef->m_attribute ) -
1519 static_cast<int>( aPadCmp->m_attribute ) ) != 0 )
1520 return diff;
1521
1522 // Dick: specctra_export needs this
1523 // Lorenzo: gencad also needs it to implement padstacks!
1524
1525 return PADSTACK::Compare( &aPadRef->Padstack(), &aPadCmp->Padstack() );
1526}
1527
1528
1529void PAD::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1530{
1531 RotatePoint( m_pos, aRotCentre, aAngle );
1533
1534 SetDirty();
1535}
1536
1537
1538wxString PAD::ShowPadShape( PCB_LAYER_ID aLayer ) const
1539{
1540 switch( GetShape( aLayer ) )
1541 {
1542 case PAD_SHAPE::CIRCLE: return _( "Circle" );
1543 case PAD_SHAPE::OVAL: return _( "Oval" );
1544 case PAD_SHAPE::RECTANGLE: return _( "Rect" );
1545 case PAD_SHAPE::TRAPEZOID: return _( "Trap" );
1546 case PAD_SHAPE::ROUNDRECT: return _( "Roundrect" );
1547 case PAD_SHAPE::CHAMFERED_RECT: return _( "Chamferedrect" );
1548 case PAD_SHAPE::CUSTOM: return _( "CustomShape" );
1549 default: return wxT( "???" );
1550 }
1551}
1552
1553
1554wxString PAD::ShowPadAttr() const
1555{
1556 switch( GetAttribute() )
1557 {
1558 case PAD_ATTRIB::PTH: return _( "PTH" );
1559 case PAD_ATTRIB::SMD: return _( "SMD" );
1560 case PAD_ATTRIB::CONN: return _( "Conn" );
1561 case PAD_ATTRIB::NPTH: return _( "NPTH" );
1562 default: return wxT( "???" );
1563 }
1564}
1565
1566
1567wxString PAD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1568{
1569 FOOTPRINT* parentFP = GetParentFootprint();
1570
1571 // Don't report parent footprint info from footprint editor, viewer, etc.
1572 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
1573 parentFP = nullptr;
1574
1575 if( GetAttribute() == PAD_ATTRIB::NPTH )
1576 {
1577 if( parentFP )
1578 {
1579 return wxString::Format( _( "NPTH pad of %s" ),
1580 parentFP->GetReference() );
1581 }
1582 else
1583 {
1584 return _( "NPTH pad" );
1585 }
1586 }
1587 else if( GetNumber().IsEmpty() )
1588 {
1589 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1590 {
1591 if( parentFP )
1592 {
1593 return wxString::Format( _( "Pad %s of %s on %s" ),
1594 GetNetnameMsg(),
1595 parentFP->GetReference(),
1597 }
1598 else
1599 {
1600 return wxString::Format( _( "Pad on %s" ),
1602 }
1603 }
1604 else
1605 {
1606 if( parentFP )
1607 {
1608 return wxString::Format( _( "PTH pad %s of %s" ),
1609 GetNetnameMsg(),
1610 parentFP->GetReference() );
1611 }
1612 else
1613 {
1614 return _( "PTH pad" );
1615 }
1616 }
1617 }
1618 else
1619 {
1620 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1621 {
1622 if( parentFP )
1623 {
1624 return wxString::Format( _( "Pad %s %s of %s on %s" ),
1625 GetNumber(),
1626 GetNetnameMsg(),
1627 parentFP->GetReference(),
1629 }
1630 else
1631 {
1632 return wxString::Format( _( "Pad %s on %s" ),
1633 GetNumber(),
1635 }
1636 }
1637 else
1638 {
1639 if( parentFP )
1640 {
1641 return wxString::Format( _( "PTH pad %s %s of %s" ),
1642 GetNumber(),
1643 GetNetnameMsg(),
1644 parentFP->GetReference() );
1645 }
1646 else
1647 {
1648 return wxString::Format( _( "PTH pad %s" ),
1649 GetNumber() );
1650 }
1651 }
1652 }
1653}
1654
1655
1657{
1658 return BITMAPS::pad;
1659}
1660
1661
1663{
1664 PAD* cloned = new PAD( *this );
1665
1666 // Ensure the cloned primitives of the pad stack have the right parent
1667 cloned->Padstack().ForEachUniqueLayer(
1668 [&]( PCB_LAYER_ID aLayer )
1669 {
1670 for( std::shared_ptr<PCB_SHAPE>& primitive : cloned->m_padStack.Primitives( aLayer ) )
1671 {
1672 primitive->SetParent( cloned );
1673 }
1674 } );
1675
1676 return cloned;
1677}
1678
1679
1680std::vector<int> PAD::ViewGetLayers() const
1681{
1682 std::vector<int> layers;
1683 layers.reserve( 64 );
1684
1685 // These 2 types of pads contain a hole
1686 if( m_attribute == PAD_ATTRIB::PTH )
1687 {
1688 layers.push_back( LAYER_PAD_PLATEDHOLES );
1689 layers.push_back( LAYER_PAD_HOLEWALLS );
1690 }
1691
1692 if( m_attribute == PAD_ATTRIB::NPTH )
1693 layers.push_back( LAYER_NON_PLATEDHOLES );
1694
1695 LSET cuLayers = ( m_padStack.LayerSet() & LSET::AllCuMask() );
1696
1697 // Don't spend cycles rendering layers that aren't visible
1698 if( const BOARD* board = GetBoard() )
1699 cuLayers &= board->GetEnabledLayers();
1700
1701 if( cuLayers.count() > 1 )
1702 {
1703 // Multi layer pad
1704 for( PCB_LAYER_ID layer : cuLayers.Seq() )
1705 {
1706 layers.push_back( LAYER_PAD_COPPER_START + layer );
1707 layers.push_back( LAYER_CLEARANCE_START + layer );
1708 }
1709
1710 layers.push_back( LAYER_PAD_NETNAMES );
1711 }
1712 else if( IsOnLayer( F_Cu ) )
1713 {
1714 layers.push_back( LAYER_PAD_COPPER_START );
1715 layers.push_back( LAYER_CLEARANCE_START );
1716
1717 // Is this a PTH pad that has only front copper? If so, we need to also display the
1718 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1719 if( m_attribute == PAD_ATTRIB::PTH )
1720 layers.push_back( LAYER_PAD_NETNAMES );
1721 else
1722 layers.push_back( LAYER_PAD_FR_NETNAMES );
1723 }
1724 else if( IsOnLayer( B_Cu ) )
1725 {
1726 layers.push_back( LAYER_PAD_COPPER_START + B_Cu );
1727 layers.push_back( LAYER_CLEARANCE_START + B_Cu );
1728
1729 // Is this a PTH pad that has only back copper? If so, we need to also display the
1730 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1731 if( m_attribute == PAD_ATTRIB::PTH )
1732 layers.push_back( LAYER_PAD_NETNAMES );
1733 else
1734 layers.push_back( LAYER_PAD_BK_NETNAMES );
1735 }
1736
1737 // Check non-copper layers. This list should include all the layers that the
1738 // footprint editor allows a pad to be placed on.
1739 static const PCB_LAYER_ID layers_mech[] = { F_Mask, B_Mask, F_Paste, B_Paste,
1741
1742 for( PCB_LAYER_ID each_layer : layers_mech )
1743 {
1744 if( IsOnLayer( each_layer ) )
1745 layers.push_back( each_layer );
1746 }
1747
1748 return layers;
1749}
1750
1751
1752double PAD::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
1753{
1754 PCB_PAINTER& painter = static_cast<PCB_PAINTER&>( *aView->GetPainter() );
1755 PCB_RENDER_SETTINGS& renderSettings = *painter.GetSettings();
1756 const BOARD* board = GetBoard();
1757
1758 // Meta control for hiding all pads
1759 if( !aView->IsLayerVisible( LAYER_PADS ) )
1760 return LOD_HIDE;
1761
1762 // Handle Render tab switches
1763 const PCB_LAYER_ID& pcbLayer = static_cast<PCB_LAYER_ID>( aLayer );
1764
1765 if( !IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
1766 return LOD_HIDE;
1767
1768 if( IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
1769 return LOD_HIDE;
1770
1771 LSET visible = board->GetVisibleLayers() & board->GetEnabledLayers();
1772
1773 if( IsHoleLayer( aLayer ) )
1774 {
1775 if( !( visible & LSET::PhysicalLayersMask() ).any() )
1776 return LOD_HIDE;
1777 }
1778 else if( IsNetnameLayer( aLayer ) )
1779 {
1780 if( renderSettings.GetHighContrast() )
1781 {
1782 // Hide netnames unless pad is flashed to a high-contrast layer
1783 if( !FlashLayer( renderSettings.GetPrimaryHighContrastLayer() ) )
1784 return LOD_HIDE;
1785 }
1786 else
1787 {
1788 // Hide netnames unless pad is flashed to a visible layer
1789 if( !FlashLayer( visible ) )
1790 return LOD_HIDE;
1791 }
1792
1793 // Netnames will be shown only if zoom is appropriate
1794 const int minSize = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
1795
1796 return lodScaleForThreshold( aView, minSize, pcbIUScale.mmToIU( 0.5 ) );
1797 }
1798
1799 // Hole walls always need a repaint when zoom level changes after the last
1800 // LAYER_PAD_HOLEWALLS shape rebuild
1801 if( aLayer == LAYER_PAD_HOLEWALLS )
1802 {
1803 if( aView->GetGAL()->GetZoomFactor() != m_lastGalZoomLevel )
1804 {
1805 aView->Update( this, KIGFX::REPAINT );
1807 }
1808 }
1809
1810 VECTOR2L padSize = GetShape( pcbLayer ) != PAD_SHAPE::CUSTOM
1811 ? VECTOR2L( GetSize( pcbLayer ) ) : GetBoundingBox().GetSize();
1812
1813 int64_t minSide = std::min( padSize.x, padSize.y );
1814
1815 if( minSide > 0 )
1816 return std::min( lodScaleForThreshold( aView, minSide, pcbIUScale.mmToIU( 0.2 ) ), 3.5 );
1817
1818 return LOD_SHOW;
1819}
1820
1821
1823{
1824 // Bounding box includes soldermask too. Remember mask and/or paste margins can be < 0
1825 int solderMaskMargin = 0;
1826 VECTOR2I solderPasteMargin;
1827
1829 [&]( PCB_LAYER_ID aLayer )
1830 {
1831 solderMaskMargin = std::max( solderMaskMargin,
1832 std::max( GetSolderMaskExpansion( aLayer ), 0 ) );
1833 VECTOR2I layerMargin = GetSolderPasteMargin( aLayer );
1834 solderPasteMargin.x = std::max( solderPasteMargin.x, layerMargin.x );
1835 solderPasteMargin.y = std::max( solderPasteMargin.y, layerMargin.y );
1836 } );
1837
1838 BOX2I bbox = GetBoundingBox();
1839 int clearance = 0;
1840
1841 // If we're drawing clearance lines then get the biggest possible clearance
1842 if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
1843 {
1844 if( cfg && cfg->m_Display.m_PadClearance && GetBoard() )
1846 }
1847
1848 // Look for the biggest possible bounding box
1849 int xMargin = std::max( solderMaskMargin, solderPasteMargin.x ) + clearance;
1850 int yMargin = std::max( solderMaskMargin, solderPasteMargin.y ) + clearance;
1851
1852 return BOX2I( VECTOR2I( bbox.GetOrigin() ) - VECTOR2I( xMargin, yMargin ),
1853 VECTOR2I( bbox.GetSize() ) + VECTOR2I( 2 * xMargin, 2 * yMargin ) );
1854}
1855
1856
1857void PAD::ImportSettingsFrom( const PAD& aMasterPad )
1858{
1859 SetPadstack( aMasterPad.Padstack() );
1860 // Layer Set should be updated before calling SetAttribute()
1861 SetLayerSet( aMasterPad.GetLayerSet() );
1862 SetAttribute( aMasterPad.GetAttribute() );
1863 // Unfortunately, SetAttribute() can change m_layerMask.
1864 // Be sure we keep the original mask by calling SetLayerSet() after SetAttribute()
1865 SetLayerSet( aMasterPad.GetLayerSet() );
1866 SetProperty( aMasterPad.GetProperty() );
1867
1868 // Must be after setting attribute and layerSet
1869 if( !CanHaveNumber() )
1870 SetNumber( wxEmptyString );
1871
1872 // I am not sure the m_LengthPadToDie should be imported, because this is a parameter
1873 // really specific to a given pad (JPC).
1874#if 0
1875 SetPadToDieLength( aMasterPad.GetPadToDieLength() );
1876#endif
1877
1878 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
1879 EDA_ANGLE pad_rot = aMasterPad.GetOrientation();
1880
1881 if( aMasterPad.GetParentFootprint() )
1882 pad_rot -= aMasterPad.GetParentFootprint()->GetOrientation();
1883
1884 if( GetParentFootprint() )
1885 pad_rot += GetParentFootprint()->GetOrientation();
1886
1887 SetOrientation( pad_rot );
1888
1890 [&]( PCB_LAYER_ID aLayer )
1891 {
1892 if( aMasterPad.GetShape( aLayer ) == PAD_SHAPE::CIRCLE )
1895 } );
1896
1897 switch( aMasterPad.GetAttribute() )
1898 {
1899 case PAD_ATTRIB::SMD:
1900 case PAD_ATTRIB::CONN:
1901 // These pads do not have a hole (they are expected to be on one external copper layer)
1902 SetDrillSize( VECTOR2I( 0, 0 ) );
1903 break;
1904
1905 default:
1906 ;
1907 }
1908
1909 // copy also local settings:
1910 SetLocalClearance( aMasterPad.GetLocalClearance() );
1914
1919
1921
1923
1924 SetDirty();
1925}
1926
1927
1929{
1930 assert( aImage->Type() == PCB_PAD_T );
1931
1932 std::swap( *this, *static_cast<PAD*>( aImage ) );
1933}
1934
1935
1936bool PAD::TransformHoleToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
1937 ERROR_LOC aErrorLoc ) const
1938{
1939 VECTOR2I drillsize = GetDrillSize();
1940
1941 if( !drillsize.x || !drillsize.y )
1942 return false;
1943
1944 std::shared_ptr<SHAPE_SEGMENT> slot = GetEffectiveHoleShape();
1945
1946 TransformOvalToPolygon( aBuffer, slot->GetSeg().A, slot->GetSeg().B,
1947 slot->GetWidth() + aClearance * 2, aError, aErrorLoc );
1948
1949 return true;
1950}
1951
1952
1953void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
1954 int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
1955{
1956 wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for pads." ) );
1957 wxASSERT_MSG( aLayer != UNDEFINED_LAYER,
1958 wxT( "UNDEFINED_LAYER is no longer allowed for PAD::TransformShapeToPolygon" ) );
1959
1960 // minimal segment count to approximate a circle to create the polygonal pad shape
1961 // This minimal value is mainly for very small pads, like SM0402.
1962 // Most of time pads are using the segment count given by aError value.
1963 const int pad_min_seg_per_circle_count = 16;
1964 int dx = m_padStack.Size( aLayer ).x / 2;
1965 int dy = m_padStack.Size( aLayer ).y / 2;
1966
1967 VECTOR2I padShapePos = ShapePos( aLayer ); // Note: for pad having a shape offset, the pad
1968 // position is NOT the shape position
1969
1970 switch( PAD_SHAPE shape = GetShape( aLayer ) )
1971 {
1972 case PAD_SHAPE::CIRCLE:
1973 case PAD_SHAPE::OVAL:
1974 // Note: dx == dy is not guaranteed for circle pads in legacy boards
1975 if( dx == dy || ( shape == PAD_SHAPE::CIRCLE ) )
1976 {
1977 TransformCircleToPolygon( aBuffer, padShapePos, dx + aClearance, aMaxError, aErrorLoc,
1978 pad_min_seg_per_circle_count );
1979 }
1980 else
1981 {
1982 int half_width = std::min( dx, dy );
1983 VECTOR2I delta( dx - half_width, dy - half_width );
1984
1986
1987 TransformOvalToPolygon( aBuffer, padShapePos - delta, padShapePos + delta,
1988 ( half_width + aClearance ) * 2, aMaxError, aErrorLoc,
1989 pad_min_seg_per_circle_count );
1990 }
1991
1992 break;
1993
1994 case PAD_SHAPE::TRAPEZOID:
1995 case PAD_SHAPE::RECTANGLE:
1996 {
1997 const VECTOR2I& trapDelta = m_padStack.TrapezoidDeltaSize( aLayer );
1998 int ddx = shape == PAD_SHAPE::TRAPEZOID ? trapDelta.x / 2 : 0;
1999 int ddy = shape == PAD_SHAPE::TRAPEZOID ? trapDelta.y / 2 : 0;
2000
2001 SHAPE_POLY_SET outline;
2002 TransformTrapezoidToPolygon( outline, padShapePos, m_padStack.Size( aLayer ),
2003 GetOrientation(), ddx, ddy, aClearance, aMaxError, aErrorLoc );
2004 aBuffer.Append( outline );
2005 break;
2006 }
2007
2008 case PAD_SHAPE::CHAMFERED_RECT:
2009 case PAD_SHAPE::ROUNDRECT:
2010 {
2011 bool doChamfer = shape == PAD_SHAPE::CHAMFERED_RECT;
2012
2013 SHAPE_POLY_SET outline;
2014 TransformRoundChamferedRectToPolygon( outline, padShapePos, m_padStack.Size( aLayer ),
2016 doChamfer ? GetChamferRectRatio( aLayer ) : 0,
2017 doChamfer ? GetChamferPositions( aLayer ) : 0,
2018 aClearance, aMaxError, aErrorLoc );
2019 aBuffer.Append( outline );
2020 break;
2021 }
2022
2023 case PAD_SHAPE::CUSTOM:
2024 {
2025 SHAPE_POLY_SET outline;
2026 MergePrimitivesAsPolygon( aLayer, &outline, aErrorLoc );
2027 outline.Rotate( GetOrientation() );
2028 outline.Move( VECTOR2I( padShapePos ) );
2029
2030 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
2031 {
2032 if( aErrorLoc == ERROR_OUTSIDE )
2033 aClearance += aMaxError;
2034
2035 outline.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aMaxError );
2036 outline.Fracture();
2037 }
2038 else if( aClearance < 0 )
2039 {
2040 // Negative clearances are primarily for drawing solder paste layer, so we don't
2041 // worry ourselves overly about which side the error is on.
2042
2043 // aClearance is negative so this is actually a deflate
2044 outline.Inflate( aClearance, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, aMaxError );
2045 outline.Fracture();
2046 }
2047
2048 aBuffer.Append( outline );
2049 break;
2050 }
2051
2052 default:
2053 wxFAIL_MSG( wxT( "PAD::TransformShapeToPolygon no implementation for " )
2054 + wxString( std::string( magic_enum::enum_name( shape ) ) ) );
2055 break;
2056 }
2057}
2058
2059
2060std::vector<PCB_SHAPE*> PAD::Recombine( bool aIsDryRun, int maxError )
2061{
2062 FOOTPRINT* footprint = GetParentFootprint();
2063
2064 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2065 item->ClearFlags( SKIP_STRUCT );
2066
2067 auto findNext =
2068 [&]( PCB_LAYER_ID aLayer ) -> PCB_SHAPE*
2069 {
2070 SHAPE_POLY_SET padPoly;
2071 TransformShapeToPolygon( padPoly, aLayer, 0, maxError, ERROR_INSIDE );
2072
2073 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2074 {
2075 PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( item );
2076
2077 if( !shape || ( shape->GetFlags() & SKIP_STRUCT ) )
2078 continue;
2079
2080 if( shape->GetLayer() != aLayer )
2081 continue;
2082
2083 if( shape->IsProxyItem() ) // Pad number (and net name) box
2084 return shape;
2085
2086 SHAPE_POLY_SET drawPoly;
2087 shape->TransformShapeToPolygon( drawPoly, aLayer, 0, maxError, ERROR_INSIDE );
2088 drawPoly.BooleanIntersection( padPoly );
2089
2090 if( !drawPoly.IsEmpty() )
2091 return shape;
2092 }
2093
2094 return nullptr;
2095 };
2096
2097 auto findMatching =
2098 [&]( PCB_SHAPE* aShape ) -> std::vector<PCB_SHAPE*>
2099 {
2100 std::vector<PCB_SHAPE*> matching;
2101
2102 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2103 {
2104 PCB_SHAPE* other = dynamic_cast<PCB_SHAPE*>( item );
2105
2106 if( !other || ( other->GetFlags() & SKIP_STRUCT ) )
2107 continue;
2108
2109 if( GetLayerSet().test( other->GetLayer() )
2110 && aShape->Compare( other ) == 0 )
2111 {
2112 matching.push_back( other );
2113 }
2114 }
2115
2116 return matching;
2117 };
2118
2119 PCB_LAYER_ID layer;
2120 std::vector<PCB_SHAPE*> mergedShapes;
2121
2122 if( IsOnLayer( F_Cu ) )
2123 layer = F_Cu;
2124 else if( IsOnLayer( B_Cu ) )
2125 layer = B_Cu;
2126 else
2127 layer = GetLayerSet().UIOrder().front();
2128
2129 PAD_SHAPE origShape = GetShape( layer );
2130
2131 // If there are intersecting items to combine, we need to first make sure the pad is a
2132 // custom-shape pad.
2133 if( !aIsDryRun && findNext( layer ) && origShape != PAD_SHAPE::CUSTOM )
2134 {
2135 if( origShape == PAD_SHAPE::CIRCLE || origShape == PAD_SHAPE::RECTANGLE )
2136 {
2137 // Use the existing pad as an anchor
2138 SetAnchorPadShape( layer, origShape );
2139 SetShape( layer, PAD_SHAPE::CUSTOM );
2140 }
2141 else
2142 {
2143 // Create a new circular anchor and convert existing pad to a polygon primitive
2144 SHAPE_POLY_SET existingOutline;
2145 TransformShapeToPolygon( existingOutline, layer, 0, maxError, ERROR_INSIDE );
2146
2147 int minExtent = std::min( GetSize( layer ).x, GetSize( layer ).y );
2148 SetAnchorPadShape( layer, PAD_SHAPE::CIRCLE );
2149 SetSize( layer, VECTOR2I( minExtent, minExtent ) );
2150 SetShape( layer, PAD_SHAPE::CUSTOM );
2151
2152 PCB_SHAPE* shape = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
2153 shape->SetFilled( true );
2154 shape->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
2155 shape->SetPolyShape( existingOutline );
2156 shape->Move( - ShapePos( layer ) );
2157 shape->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
2158 AddPrimitive( layer, shape );
2159 }
2160 }
2161
2162 while( PCB_SHAPE* fpShape = findNext( layer ) )
2163 {
2164 fpShape->SetFlags( SKIP_STRUCT );
2165
2166 mergedShapes.push_back( fpShape );
2167
2168 if( !aIsDryRun )
2169 {
2170 // If the editor was inside a group when the pad was exploded, the added exploded shapes
2171 // will be part of the group. Remove them here before duplicating; we don't want the
2172 // primitives to wind up in a group.
2173 if( PCB_GROUP* group = fpShape->GetParentGroup(); group )
2174 group->RemoveItem( fpShape );
2175
2176 PCB_SHAPE* primitive = static_cast<PCB_SHAPE*>( fpShape->Duplicate() );
2177
2178 primitive->SetParent( nullptr );
2179
2180 // Convert any hatched fills to solid
2181 if( primitive->IsAnyFill() )
2182 primitive->SetFillMode( FILL_T::FILLED_SHAPE );
2183
2184 primitive->Move( - ShapePos( layer ) );
2185 primitive->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
2186
2187 AddPrimitive( layer, primitive );
2188 }
2189
2190 // See if there are other shapes that match and mark them for delete. (KiCad won't
2191 // produce these, but old footprints from other vendors have them.)
2192 for( PCB_SHAPE* other : findMatching( fpShape ) )
2193 {
2194 other->SetFlags( SKIP_STRUCT );
2195 mergedShapes.push_back( other );
2196 }
2197 }
2198
2199 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2200 item->ClearFlags( SKIP_STRUCT );
2201
2202 if( !aIsDryRun )
2204
2205 return mergedShapes;
2206}
2207
2208
2209void PAD::CheckPad( UNITS_PROVIDER* aUnitsProvider, bool aForPadProperties,
2210 const std::function<void( int aErrorCode,
2211 const wxString& aMsg )>& aErrorHandler ) const
2212{
2214 [&]( PCB_LAYER_ID aLayer )
2215 {
2216 doCheckPad( aLayer, aUnitsProvider, aForPadProperties, aErrorHandler );
2217 } );
2218
2219 LSET padlayers_mask = GetLayerSet();
2220 VECTOR2I drill_size = GetDrillSize();
2221
2222 if( !padlayers_mask[F_Cu] && !padlayers_mask[B_Cu] )
2223 {
2224 if( ( drill_size.x || drill_size.y ) && GetAttribute() != PAD_ATTRIB::NPTH )
2225 {
2226 aErrorHandler( DRCE_PADSTACK, _( "(plated through holes normally have a copper pad on "
2227 "at least one outer layer)" ) );
2228 }
2229 }
2230
2231 if( ( GetProperty() == PAD_PROP::FIDUCIAL_GLBL || GetProperty() == PAD_PROP::FIDUCIAL_LOCAL )
2232 && GetAttribute() == PAD_ATTRIB::NPTH )
2233 {
2234 aErrorHandler( DRCE_PADSTACK, _( "('fiducial' property makes no sense on NPTH pads)" ) );
2235 }
2236
2237 if( GetProperty() == PAD_PROP::TESTPOINT && GetAttribute() == PAD_ATTRIB::NPTH )
2238 aErrorHandler( DRCE_PADSTACK, _( "('testpoint' property makes no sense on NPTH pads)" ) );
2239
2240 if( GetProperty() == PAD_PROP::HEATSINK && GetAttribute() == PAD_ATTRIB::NPTH )
2241 aErrorHandler( DRCE_PADSTACK, _( "('heatsink' property makes no sense of NPTH pads)" ) );
2242
2243 if( GetProperty() == PAD_PROP::CASTELLATED && GetAttribute() != PAD_ATTRIB::PTH )
2244 aErrorHandler( DRCE_PADSTACK, _( "('castellated' property is for PTH pads)" ) );
2245
2246 if( GetProperty() == PAD_PROP::BGA && GetAttribute() != PAD_ATTRIB::SMD )
2247 aErrorHandler( DRCE_PADSTACK, _( "('BGA' property is for SMD pads)" ) );
2248
2249 if( GetProperty() == PAD_PROP::MECHANICAL && GetAttribute() != PAD_ATTRIB::PTH )
2250 aErrorHandler( DRCE_PADSTACK, _( "('mechanical' property is for PTH pads)" ) );
2251
2252 switch( GetAttribute() )
2253 {
2254 case PAD_ATTRIB::NPTH: // Not plated, but through hole, a hole is expected
2255 case PAD_ATTRIB::PTH: // Pad through hole, a hole is also expected
2256 if( drill_size.x <= 0
2257 || ( drill_size.y <= 0 && GetDrillShape() == PAD_DRILL_SHAPE::OBLONG ) )
2258 {
2259 aErrorHandler( DRCE_PAD_TH_WITH_NO_HOLE, wxEmptyString );
2260 }
2261 break;
2262
2263 case PAD_ATTRIB::CONN: // Connector pads are smd pads, just they do not have solder paste.
2264 if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
2265 {
2266 aErrorHandler( DRCE_PADSTACK, _( "(connector pads normally have no solder paste; use a "
2267 "SMD pad instead)" ) );
2268 }
2270
2271 case PAD_ATTRIB::SMD: // SMD and Connector pads (One external copper layer only)
2272 {
2273 if( drill_size.x > 0 || drill_size.y > 0 )
2274 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(SMD pad has a hole)" ) );
2275
2276 LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
2277
2278 if( IsOnLayer( F_Cu ) && IsOnLayer( B_Cu ) )
2279 {
2280 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper on both sides of the board)" ) );
2281 }
2282 else if( IsOnLayer( F_Cu ) )
2283 {
2284 if( IsOnLayer( B_Mask ) )
2285 {
2286 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and mask layers on different "
2287 "sides of the board)" ) );
2288 }
2289 else if( IsOnLayer( B_Paste ) )
2290 {
2291 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and paste layers on different "
2292 "sides of the board)" ) );
2293 }
2294 }
2295 else if( IsOnLayer( B_Cu ) )
2296 {
2297 if( IsOnLayer( F_Mask ) )
2298 {
2299 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and mask layers on different "
2300 "sides of the board)" ) );
2301 }
2302 else if( IsOnLayer( F_Paste ) )
2303 {
2304 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and paste layers on different "
2305 "sides of the board)" ) );
2306 }
2307 }
2308 else if( innerlayers_mask.count() != 0 )
2309 {
2310 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has no outer layers)" ) );
2311 }
2312
2313 break;
2314 }
2315 }
2316}
2317
2318
2319void PAD::doCheckPad( PCB_LAYER_ID aLayer, UNITS_PROVIDER* aUnitsProvider, bool aForPadProperties,
2320 const std::function<void( int aErrorCode,
2321 const wxString& aMsg )>& aErrorHandler ) const
2322{
2323 wxString msg;
2324
2325 VECTOR2I pad_size = GetSize( aLayer );
2326
2327 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2328 pad_size = GetBoundingBox().GetSize();
2329 else if( pad_size.x <= 0 || ( pad_size.y <= 0 && GetShape( aLayer ) != PAD_SHAPE::CIRCLE ) )
2330 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(Pad must have a positive size)" ) );
2331
2332 // Test hole against pad shape
2333 if( IsOnCopperLayer() && GetDrillSize().x > 0 )
2334 {
2335 // Ensure the drill size can be handled in next calculations.
2336 // Use min size = 4 IU to be able to build a polygon from a hole shape
2337 const int min_drill_size = 4;
2338
2339 if( GetDrillSizeX() <= min_drill_size || GetDrillSizeY() <= min_drill_size )
2340 {
2341 msg.Printf( _( "(PTH pad hole size must be larger than %s)" ),
2342 aUnitsProvider->StringFromValue( min_drill_size, true ) );
2343 aErrorHandler( DRCE_PADSTACK_INVALID, msg );
2344 }
2345
2346 int maxError = GetBoard()->GetDesignSettings().m_MaxError;
2347 SHAPE_POLY_SET padOutline;
2348
2349 TransformShapeToPolygon( padOutline, aLayer, 0, maxError, ERROR_INSIDE );
2350
2351 if( GetAttribute() == PAD_ATTRIB::PTH )
2352 {
2353 // Test if there is copper area outside hole
2354 std::shared_ptr<SHAPE_SEGMENT> hole = GetEffectiveHoleShape();
2355 SHAPE_POLY_SET holeOutline;
2356
2357 TransformOvalToPolygon( holeOutline, hole->GetSeg().A, hole->GetSeg().B,
2358 hole->GetWidth(), ARC_HIGH_DEF, ERROR_OUTSIDE );
2359
2360 SHAPE_POLY_SET copper = padOutline;
2361 copper.BooleanSubtract( holeOutline );
2362
2363 if( copper.IsEmpty() )
2364 {
2365 aErrorHandler( DRCE_PADSTACK, _( "(PTH pad hole leaves no copper)" ) );
2366 }
2367 else if( aForPadProperties )
2368 {
2369 // Test if the pad hole is fully inside the copper area. Note that we only run
2370 // this check for pad properties because we run the more complete annular ring
2371 // checker on the board (which handles multiple pads with the same name).
2372 holeOutline.BooleanSubtract( padOutline );
2373
2374 if( !holeOutline.IsEmpty() )
2375 aErrorHandler( DRCE_PADSTACK, _( "(PTH pad hole not fully inside copper)" ) );
2376 }
2377 }
2378 else
2379 {
2380 // Test only if the pad hole's centre is inside the copper area
2381 if( !padOutline.Collide( GetPosition() ) )
2382 aErrorHandler( DRCE_PADSTACK, _( "(pad hole not inside pad shape)" ) );
2383 }
2384 }
2385
2386 if( GetLocalClearance().value_or( 0 ) < 0 )
2387 aErrorHandler( DRCE_PADSTACK, _( "(negative local clearance values have no effect)" ) );
2388
2389 // Some pads need a negative solder mask clearance (mainly for BGA with small pads)
2390 // However the negative solder mask clearance must not create negative mask size
2391 // Therefore test for minimal acceptable negative value
2392 std::optional<int> solderMaskMargin = GetLocalSolderMaskMargin();
2393
2394 if( solderMaskMargin.has_value() && solderMaskMargin.value() < 0 )
2395 {
2396 int absMargin = abs( solderMaskMargin.value() );
2397
2398 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2399 {
2400 for( const std::shared_ptr<PCB_SHAPE>& shape : GetPrimitives( aLayer ) )
2401 {
2402 BOX2I shapeBBox = shape->GetBoundingBox();
2403
2404 if( absMargin > shapeBBox.GetWidth() || absMargin > shapeBBox.GetHeight() )
2405 {
2406 aErrorHandler( DRCE_PADSTACK, _( "(negative solder mask clearance is larger "
2407 "than some shape primitives; results may be "
2408 "surprising)" ) );
2409
2410 break;
2411 }
2412 }
2413 }
2414 else if( absMargin > pad_size.x || absMargin > pad_size.y )
2415 {
2416 aErrorHandler( DRCE_PADSTACK, _( "(negative solder mask clearance is larger than pad; "
2417 "no solder mask will be generated)" ) );
2418 }
2419 }
2420
2421 // Some pads need a positive solder paste clearance (mainly for BGA with small pads)
2422 // However, a positive value can create issues if the resulting shape is too big.
2423 // (like a solder paste creating a solder paste area on a neighbor pad or on the solder mask)
2424 // So we could ask for user to confirm the choice
2425 // For now we just check for disappearing paste
2426 wxSize paste_size;
2427 int paste_margin = GetLocalSolderPasteMargin().value_or( 0 );
2428 double paste_ratio = GetLocalSolderPasteMarginRatio().value_or( 0 );
2429
2430 paste_size.x = pad_size.x + paste_margin + KiROUND( pad_size.x * paste_ratio );
2431 paste_size.y = pad_size.y + paste_margin + KiROUND( pad_size.y * paste_ratio );
2432
2433 if( paste_size.x <= 0 || paste_size.y <= 0 )
2434 {
2435 aErrorHandler( DRCE_PADSTACK, _( "(negative solder paste margin is larger than pad; "
2436 "no solder paste mask will be generated)" ) );
2437 }
2438
2439 if( GetShape( aLayer ) == PAD_SHAPE::ROUNDRECT )
2440 {
2441 if( GetRoundRectRadiusRatio( aLayer ) < 0.0 )
2442 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(negative corner radius is not allowed)" ) );
2443 else if( GetRoundRectRadiusRatio( aLayer ) > 50.0 )
2444 aErrorHandler( DRCE_PADSTACK, _( "(corner size will make pad circular)" ) );
2445 }
2446 else if( GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT )
2447 {
2448 if( GetChamferRectRatio( aLayer ) < 0.0 )
2449 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(negative corner chamfer is not allowed)" ) );
2450 else if( GetChamferRectRatio( aLayer ) > 50.0 )
2451 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(corner chamfer is too large)" ) );
2452 }
2453 else if( GetShape( aLayer ) == PAD_SHAPE::TRAPEZOID )
2454 {
2455 if( ( GetDelta( aLayer ).x < 0 && GetDelta( aLayer ).x < -GetSize( aLayer ).y )
2456 || ( GetDelta( aLayer ).x > 0 && GetDelta( aLayer ).x > GetSize( aLayer ).y )
2457 || ( GetDelta( aLayer ).y < 0 && GetDelta( aLayer ).y < -GetSize( aLayer ).x )
2458 || ( GetDelta( aLayer ).y > 0 && GetDelta( aLayer ).y > GetSize( aLayer ).x ) )
2459 {
2460 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(trapezoid delta is too large)" ) );
2461 }
2462 }
2463
2464 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2465 {
2466 SHAPE_POLY_SET mergedPolygon;
2467 MergePrimitivesAsPolygon( aLayer, &mergedPolygon );
2468
2469 if( mergedPolygon.OutlineCount() > 1 )
2470 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(custom pad shape must resolve to a single polygon)" ) );
2471 }
2472}
2473
2474
2475bool PAD::operator==( const BOARD_ITEM& aBoardItem ) const
2476{
2477 if( Type() != aBoardItem.Type() )
2478 return false;
2479
2480 if( m_parent && aBoardItem.GetParent() && m_parent->m_Uuid != aBoardItem.GetParent()->m_Uuid )
2481 return false;
2482
2483 const PAD& other = static_cast<const PAD&>( aBoardItem );
2484
2485 return *this == other;
2486}
2487
2488
2489bool PAD::operator==( const PAD& aOther ) const
2490{
2491 if( Padstack() != aOther.Padstack() )
2492 return false;
2493
2494 if( GetPosition() != aOther.GetPosition() )
2495 return false;
2496
2497 if( GetAttribute() != aOther.GetAttribute() )
2498 return false;
2499
2500 return true;
2501}
2502
2503
2504double PAD::Similarity( const BOARD_ITEM& aOther ) const
2505{
2506 if( aOther.Type() != Type() )
2507 return 0.0;
2508
2509 if( m_parent->m_Uuid != aOther.GetParent()->m_Uuid )
2510 return 0.0;
2511
2512 const PAD& other = static_cast<const PAD&>( aOther );
2513
2514 double similarity = 1.0;
2515
2516 if( GetPosition() != other.GetPosition() )
2517 similarity *= 0.9;
2518
2519 if( GetAttribute() != other.GetAttribute() )
2520 similarity *= 0.9;
2521
2522 similarity *= Padstack().Similarity( other.Padstack() );
2523
2524 return similarity;
2525}
2526
2527
2528void PAD::AddPrimitivePoly( PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPoly, int aThickness,
2529 bool aFilled )
2530{
2531 // If aPoly has holes, convert it to a polygon with no holes.
2532 SHAPE_POLY_SET poly_no_hole;
2533 poly_no_hole.Append( aPoly );
2534
2535 if( poly_no_hole.HasHoles() )
2536 poly_no_hole.Fracture();
2537
2538 // There should never be multiple shapes, but if there are, we split them into
2539 // primitives so that we can edit them both.
2540 for( int ii = 0; ii < poly_no_hole.OutlineCount(); ++ii )
2541 {
2542 SHAPE_POLY_SET poly_outline( poly_no_hole.COutline( ii ) );
2543 PCB_SHAPE* item = new PCB_SHAPE();
2544 item->SetShape( SHAPE_T::POLY );
2545 item->SetFilled( aFilled );
2546 item->SetPolyShape( poly_outline );
2547 item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
2548 item->SetParent( this );
2549 m_padStack.AddPrimitive( item, aLayer );
2550 }
2551
2552 SetDirty();
2553}
2554
2555
2556void PAD::AddPrimitivePoly( PCB_LAYER_ID aLayer, const std::vector<VECTOR2I>& aPoly, int aThickness,
2557 bool aFilled )
2558{
2559 PCB_SHAPE* item = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
2560 item->SetFilled( aFilled );
2561 item->SetPolyPoints( aPoly );
2562 item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
2563 item->SetParent( this );
2564 m_padStack.AddPrimitive( item, aLayer );
2565 SetDirty();
2566}
2567
2568
2569void PAD::ReplacePrimitives( PCB_LAYER_ID aLayer, const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList )
2570{
2571 // clear old list
2572 DeletePrimitivesList( aLayer );
2573
2574 // Import to the given shape list
2575 if( aPrimitivesList.size() )
2576 AppendPrimitives( aLayer, aPrimitivesList );
2577
2578 SetDirty();
2579}
2580
2581
2582void PAD::AppendPrimitives( PCB_LAYER_ID aLayer, const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList )
2583{
2584 // Add duplicates of aPrimitivesList to the pad primitives list:
2585 for( const std::shared_ptr<PCB_SHAPE>& prim : aPrimitivesList )
2586 AddPrimitive( aLayer, new PCB_SHAPE( *prim ) );
2587
2588 SetDirty();
2589}
2590
2591
2592void PAD::AddPrimitive( PCB_LAYER_ID aLayer, PCB_SHAPE* aPrimitive )
2593{
2594 aPrimitive->SetParent( this );
2595 m_padStack.AddPrimitive( aPrimitive, aLayer );
2596
2597 SetDirty();
2598}
2599
2600
2602{
2603 if( aLayer == UNDEFINED_LAYER )
2604 {
2606 [&]( PCB_LAYER_ID l )
2607 {
2609 } );
2610 }
2611 else
2612 {
2613 m_padStack.ClearPrimitives( aLayer);
2614 }
2615
2616 SetDirty();
2617}
2618
2619
2621 ERROR_LOC aErrorLoc ) const
2622{
2623 const BOARD* board = GetBoard();
2624 int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
2625
2626 aMergedPolygon->RemoveAllContours();
2627
2628 // Add the anchor pad shape in aMergedPolygon, others in aux_polyset:
2629 // The anchor pad is always at 0,0
2630 VECTOR2I padSize = GetSize( aLayer );
2631
2632 switch( GetAnchorPadShape( aLayer ) )
2633 {
2634 case PAD_SHAPE::RECTANGLE:
2635 {
2636 SHAPE_RECT rect( -padSize.x / 2, -padSize.y / 2, padSize.x, padSize.y );
2637 aMergedPolygon->AddOutline( rect.Outline() );
2638 break;
2639 }
2640
2641 default:
2642 case PAD_SHAPE::CIRCLE:
2643 TransformCircleToPolygon( *aMergedPolygon, VECTOR2I( 0, 0 ), padSize.x / 2, maxError,
2644 aErrorLoc );
2645 break;
2646 }
2647
2648 SHAPE_POLY_SET polyset;
2649
2650 for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives( aLayer ) )
2651 {
2652 if( !primitive->IsProxyItem() )
2653 primitive->TransformShapeToPolygon( polyset, UNDEFINED_LAYER, 0, maxError, aErrorLoc );
2654 }
2655
2656 polyset.Simplify();
2657
2658 // Merge all polygons with the initial pad anchor shape
2659 if( polyset.OutlineCount() )
2660 {
2661 aMergedPolygon->BooleanAdd( polyset );
2662 aMergedPolygon->Fracture();
2663 }
2664}
2665
2666
2667static struct PAD_DESC
2668{
2670 {
2672 .Map( PAD_ATTRIB::PTH, _HKI( "Through-hole" ) )
2673 .Map( PAD_ATTRIB::SMD, _HKI( "SMD" ) )
2674 .Map( PAD_ATTRIB::CONN, _HKI( "Edge connector" ) )
2675 .Map( PAD_ATTRIB::NPTH, _HKI( "NPTH, mechanical" ) );
2676
2678 .Map( PAD_SHAPE::CIRCLE, _HKI( "Circle" ) )
2679 .Map( PAD_SHAPE::RECTANGLE, _HKI( "Rectangle" ) )
2680 .Map( PAD_SHAPE::OVAL, _HKI( "Oval" ) )
2681 .Map( PAD_SHAPE::TRAPEZOID, _HKI( "Trapezoid" ) )
2682 .Map( PAD_SHAPE::ROUNDRECT, _HKI( "Rounded rectangle" ) )
2683 .Map( PAD_SHAPE::CHAMFERED_RECT, _HKI( "Chamfered rectangle" ) )
2684 .Map( PAD_SHAPE::CUSTOM, _HKI( "Custom" ) );
2685
2687 .Map( PAD_PROP::NONE, _HKI( "None" ) )
2688 .Map( PAD_PROP::BGA, _HKI( "BGA pad" ) )
2689 .Map( PAD_PROP::FIDUCIAL_GLBL, _HKI( "Fiducial, global to board" ) )
2690 .Map( PAD_PROP::FIDUCIAL_LOCAL, _HKI( "Fiducial, local to footprint" ) )
2691 .Map( PAD_PROP::TESTPOINT, _HKI( "Test point pad" ) )
2692 .Map( PAD_PROP::HEATSINK, _HKI( "Heatsink pad" ) )
2693 .Map( PAD_PROP::CASTELLATED, _HKI( "Castellated pad" ) )
2694 .Map( PAD_PROP::MECHANICAL, _HKI( "Mechanical pad" ) );
2695
2697 .Map( PAD_DRILL_SHAPE::CIRCLE, _HKI( "Round" ) )
2698 .Map( PAD_DRILL_SHAPE::OBLONG, _HKI( "Oblong" ) );
2699
2701
2702 if( zcMap.Choices().GetCount() == 0 )
2703 {
2704 zcMap.Undefined( ZONE_CONNECTION::INHERITED );
2705 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
2706 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
2707 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
2708 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
2709 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
2710 }
2711
2713 .Map( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL, _HKI( "All copper layers" ) )
2714 .Map( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL, _HKI( "Connected layers only" ) )
2716 _HKI( "Front, back and connected layers" ) );
2717
2719 REGISTER_TYPE( PAD );
2721
2722 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
2723 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_ITEM ), _HKI( "Locked" ) );
2724
2725 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Orientation" ),
2727 PROPERTY_DISPLAY::PT_DEGREE ) );
2728
2729 auto isCopperPad =
2730 []( INSPECTABLE* aItem ) -> bool
2731 {
2732 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2733 return pad->GetAttribute() != PAD_ATTRIB::NPTH;
2734
2735 return false;
2736 };
2737
2738 auto padCanHaveHole =
2739 []( INSPECTABLE* aItem ) -> bool
2740 {
2741 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2742 {
2743 return pad->GetAttribute() == PAD_ATTRIB::PTH
2744 || pad->GetAttribute() == PAD_ATTRIB::NPTH;
2745 }
2746
2747 return false;
2748 };
2749
2750 auto hasNormalPadstack =
2751 []( INSPECTABLE* aItem ) -> bool
2752 {
2753 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2754 return pad->Padstack().Mode() == PADSTACK::MODE::NORMAL;
2755
2756 return true;
2757 };
2758
2760 _HKI( "Net" ), isCopperPad );
2762 _HKI( "Net Class" ), isCopperPad );
2763
2764 const wxString groupPad = _HKI( "Pad Properties" );
2765
2766 auto padType = new PROPERTY_ENUM<PAD, PAD_ATTRIB>( _HKI( "Pad Type" ),
2768 propMgr.AddProperty( padType, groupPad );
2769
2770 auto shape = new PROPERTY_ENUM<PAD, PAD_SHAPE>( _HKI( "Pad Shape" ),
2772 propMgr.AddProperty( shape, groupPad )
2773 .SetAvailableFunc( hasNormalPadstack );
2774
2775 auto padNumber = new PROPERTY<PAD, wxString>( _HKI( "Pad Number" ),
2777 padNumber->SetAvailableFunc( isCopperPad );
2778 propMgr.AddProperty( padNumber, groupPad );
2779
2780 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Name" ),
2781 NO_SETTER( PAD, wxString ), &PAD::GetPinFunction ), groupPad )
2783 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Type" ),
2784 NO_SETTER( PAD, wxString ), &PAD::GetPinType ), groupPad )
2786
2787 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size X" ),
2789 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2790 .SetAvailableFunc( hasNormalPadstack );
2791 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size Y" ),
2793 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2795 [=]( INSPECTABLE* aItem ) -> bool
2796 {
2797 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2798 {
2799 // Custom padstacks can't have size modified through panel
2800 if( pad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
2801 return false;
2802
2803 // Circle pads have no usable y-size
2804 return pad->GetShape( PADSTACK::ALL_LAYERS ) != PAD_SHAPE::CIRCLE;
2805 }
2806
2807 return true;
2808 } );
2809
2810 const auto hasRoundRadius = [=]( INSPECTABLE* aItem ) -> bool
2811 {
2812 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2813 {
2814 // Custom padstacks can't have this property modified through panel
2815 if( pad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
2816 return false;
2817
2819 }
2820
2821 return false;
2822 };
2823
2824 auto roundRadiusRatio = new PROPERTY<PAD, double>( _HKI( "Corner Radius Ratio" ),
2826 roundRadiusRatio->SetAvailableFunc( hasRoundRadius );
2827 propMgr.AddProperty( roundRadiusRatio, groupPad );
2828
2829 auto roundRadiusSize = new PROPERTY<PAD, int>( _HKI( "Corner Radius Size" ),
2831 PROPERTY_DISPLAY::PT_SIZE );
2832 roundRadiusSize->SetAvailableFunc( hasRoundRadius );
2833 propMgr.AddProperty( roundRadiusSize, groupPad );
2834
2835 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_DRILL_SHAPE>( _HKI( "Hole Shape" ),
2836 &PAD::SetDrillShape, &PAD::GetDrillShape ), groupPad )
2837 .SetWriteableFunc( padCanHaveHole );
2838
2839 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size X" ),
2841 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2842 .SetWriteableFunc( padCanHaveHole )
2844
2845 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size Y" ),
2847 PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2848 .SetWriteableFunc( padCanHaveHole )
2851 [=]( INSPECTABLE* aItem ) -> bool
2852 {
2853 // Circle holes have no usable y-size
2854 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2855 return pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE;
2856
2857 return true;
2858 } );
2859
2860 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_PROP>( _HKI( "Fabrication Property" ),
2861 &PAD::SetProperty, &PAD::GetProperty ), groupPad );
2862
2864 _HKI( "Copper Layers" ),
2866 propMgr.AddProperty( layerMode, groupPad );
2867
2868 auto padToDie = new PROPERTY<PAD, int>( _HKI( "Pad To Die Length" ),
2870 PROPERTY_DISPLAY::PT_SIZE );
2871 padToDie->SetAvailableFunc( isCopperPad );
2872 propMgr.AddProperty( padToDie, groupPad );
2873
2874 const wxString groupOverrides = _HKI( "Overrides" );
2875
2876 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2877 _HKI( "Clearance Override" ),
2879 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2880
2881 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2882 _HKI( "Soldermask Margin Override" ),
2884 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2885
2886 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2887 _HKI( "Solderpaste Margin Override" ),
2889 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2890
2891 propMgr.AddProperty( new PROPERTY<PAD, std::optional<double>>(
2892 _HKI( "Solderpaste Margin Ratio Override" ),
2894 PROPERTY_DISPLAY::PT_RATIO ),
2895 groupOverrides );
2896
2898 _HKI( "Zone Connection Style" ),
2900
2901 constexpr int minZoneWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
2902
2903 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2904 _HKI( "Thermal Relief Spoke Width" ),
2906 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2907 .SetValidator( PROPERTY_VALIDATORS::RangeIntValidator<minZoneWidth, INT_MAX> );
2908
2910 _HKI( "Thermal Relief Spoke Angle" ),
2912 PROPERTY_DISPLAY::PT_DEGREE ), groupOverrides );
2913
2914 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>(
2915 _HKI( "Thermal Relief Gap" ),
2917 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2919
2920 // TODO delta, drill shape offset, layer set
2921 }
2923
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Definition: approximation.h:32
@ ERROR_OUTSIDE
Definition: approximation.h:33
@ ERROR_INSIDE
Definition: approximation.h:34
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
ZONE_LAYER_OVERRIDE
Conditionally flashed vias and pads that interact with zones of different priority can be very squirr...
Definition: board_item.h:66
@ ZLO_NONE
Definition: board_item.h:67
@ ZLO_FORCE_FLASHED
Definition: board_item.h:68
BOX2< VECTOR2I > BOX2I
Definition: box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
BASE_SET & set(size_t pos)
Definition: base_set.h:116
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:78
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:235
virtual void SetLocked(bool aLocked)
Definition: board_item.h:326
PCB_LAYER_ID m_layer
Definition: board_item.h:451
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:286
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:54
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:305
virtual bool IsLocked() const
Definition: board_item.cpp:82
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:213
virtual int BoardCopperLayerCount() const
Return the total number of copper layers for the board that this item resides on.
Definition: board_item.cpp:124
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:173
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:297
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:829
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:843
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition: board.cpp:958
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:946
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:658
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:311
wxString GetName() const
Definition: drc_rule.h:160
MINOPTMAX< int > & Value()
Definition: drc_rule.h:153
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:95
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:248
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition: eda_item.cpp:300
const KIID m_Uuid
Definition: eda_item.h:494
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:107
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:133
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:110
EDA_ITEM * m_parent
Linked list: Link (parent struct).
Definition: eda_item.h:506
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:134
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:345
virtual void SetFilled(bool aFlag)
Definition: eda_shape.h:136
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:167
bool IsAnyFill() const
Definition: eda_shape.h:112
void SetPolyPoints(const std::vector< VECTOR2I > &aPoints)
Definition: eda_shape.cpp:1708
void SetFillMode(FILL_T aFill)
Definition: eda_shape.cpp:536
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:686
static ENUM_MAP< T > & Instance()
Definition: property.h:680
ENUM_MAP & Undefined(T aValue)
Definition: property.h:693
wxPGChoices & Choices()
Definition: property.h:729
EDA_ANGLE GetOrientation() const
Definition: footprint.h:232
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:3179
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:241
bool IsNetTie() const
Definition: footprint.h:302
const wxString & GetReference() const
Definition: footprint.h:619
DRAWINGS & GraphicalItems()
Definition: footprint.h:214
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:37
double GetZoomFactor() const
Contains methods for drawing PCB-specific items.
Definition: pcb_painter.h:181
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:186
PCB specific render settings.
Definition: pcb_painter.h:79
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
bool GetHighContrast() const
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition: view_item.cpp:39
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition: view_item.h:174
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition: view_item.h:179
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1673
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:198
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:216
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:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition: lset.cpp:712
static LSET FrontBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on front side.
Definition: lset.cpp:629
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:561
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:572
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:658
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:297
static LSET BackBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on Back side.
Definition: lset.cpp:615
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
std::optional< int > & Clearance(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1181
void AddPrimitive(PCB_SHAPE *aShape, PCB_LAYER_ID aLayer)
Adds a custom shape primitive to the padstack.
Definition: padstack.cpp:1307
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: padstack.cpp:211
double Similarity(const PADSTACK &aOther) const
Return a measure of how likely the other object is to represent the same object.
Definition: padstack.cpp:614
int RoundRectRadius(PCB_LAYER_ID aLayer) const
Definition: padstack.cpp:1134
std::optional< double > & SolderPasteMarginRatio(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1220
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
Definition: padstack.cpp:879
void SetRoundRectRadiusRatio(double aRatio, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1128
void ClearPrimitives(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1332
std::optional< int > & ThermalSpokeWidth(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1246
std::optional< int > & SolderPasteMargin(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1207
void SetOrientation(EDA_ANGLE aAngle)
Definition: padstack.h:300
std::optional< int > & SolderMaskMargin(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1193
void SetChamferRatio(double aRatio, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1157
const LSET & LayerSet() const
Definition: padstack.h:280
PCB_LAYER_ID EffectiveLayerFor(PCB_LAYER_ID aLayer) const
Determines which geometry layer should be used for the given input layer.
Definition: padstack.cpp:931
void SetShape(PAD_SHAPE aShape, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1053
VECTOR2I & TrapezoidDeltaSize(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1110
VECTOR2I & Offset(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1086
void FlipLayers(int aCopperLayerCount)
Flips the padstack layers in the case that the pad's parent footprint is flipped to the other side of...
Definition: padstack.cpp:717
void SetChamferPositions(int aPositions, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1175
void SetRoundRectRadius(double aRadius, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1141
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
Definition: padstack.h:312
std::optional< int > & ThermalGap(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1258
PAD_SHAPE Shape(PCB_LAYER_ID aLayer) const
Definition: padstack.cpp:1047
DRILL_PROPS & Drill()
Definition: padstack.h:306
static int Compare(const PADSTACK *aPadstackRef, const PADSTACK *aPadstackCmp)
Compare two padstacks and return 0 if they are equal.
Definition: padstack.cpp:535
int & ChamferPositions(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1163
const VECTOR2I & Size(PCB_LAYER_ID aLayer) const
Definition: padstack.cpp:1068
@ NORMAL
Shape is the same on all layers.
UNCONNECTED_LAYER_MODE
! Whether or not to remove the copper shape for unconnected layers
Definition: padstack.h:151
PCB_LAYER_ID StartLayer() const
Definition: padstack.cpp:705
MODE Mode() const
Definition: padstack.h:293
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: padstack.cpp:413
void SetSize(const VECTOR2I &aSize, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1059
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:144
EDA_ANGLE GetOrientation() const
Definition: padstack.h:299
void SetLayerSet(const LSET &aSet)
Definition: padstack.h:282
std::optional< ZONE_CONNECTION > & ZoneConnection(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1234
std::vector< std::shared_ptr< PCB_SHAPE > > & Primitives(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1295
Definition: pad.h:54
void SetAnchorPadShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:242
bool IsAperturePad() const
Definition: pad.h:447
void SetAttribute(PAD_ATTRIB aAttribute)
Definition: pad.cpp:858
int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const override
Return the pad's "own" clearance in internal units.
Definition: pad.cpp:1126
void CheckPad(UNITS_PROVIDER *aUnitsProvider, bool aForPadProperties, const std::function< void(int aErrorCode, const wxString &aMsg)> &aErrorHandler) const
Definition: pad.cpp:2209
PAD(FOOTPRINT *parent)
Definition: pad.cpp:74
virtual void swapData(BOARD_ITEM *aImage) override
Definition: pad.cpp:1928
PAD_PROP GetProperty() const
Definition: pad.h:443
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: pad.cpp:151
double GetFrontRoundRectRadiusRatio() const
Definition: pad.h:675
void doCheckPad(PCB_LAYER_ID aLayer, UNITS_PROVIDER *aUnitsProvider, bool aForPadProperties, const std::function< void(int aErrorCode, const wxString &aMsg)> &aErrorHandler) const
Definition: pad.cpp:2319
std::optional< int > GetClearanceOverrides(wxString *aSource) const override
Return any clearance overrides set in the "classic" (ie: pre-rule) system.
Definition: pad.cpp:1114
void SetPinType(const wxString &aType)
Set the pad electrical type.
Definition: pad.h:152
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:437
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:365
const ZONE_LAYER_OVERRIDE & GetZoneLayerOverride(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:214
int GetSizeX() const
Definition: pad.h:280
void MergePrimitivesAsPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
Definition: pad.cpp:2620
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:455
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:355
void SetLocalThermalGapOverride(const std::optional< int > &aOverride)
Definition: pad.h:646
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pad.cpp:525
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:1299
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition: pad.cpp:849
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:785
int GetDrillSizeY() const
Definition: pad.h:309
void AddPrimitivePoly(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPoly, int aThickness, bool aFilled)
Has meaning only for custom shape pads.
Definition: pad.cpp:2528
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: pad.h:472
void SetFrontShape(PAD_SHAPE aShape)
Definition: pad.cpp:906
const wxString & GetPinType() const
Definition: pad.h:153
void SetZoneLayerOverride(PCB_LAYER_ID aLayer, ZONE_LAYER_OVERRIDE aOverride)
Definition: pad.cpp:224
const VECTOR2I & GetDrillSize() const
Definition: pad.h:305
PAD_ATTRIB GetAttribute() const
Definition: pad.h:440
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:284
static int Compare(const PAD *aPadRef, const PAD *aPadCmp)
Compare two pads and return 0 if they are equal.
Definition: pad.cpp:1514
void SetUnconnectedLayerMode(PADSTACK::UNCONNECTED_LAYER_MODE aMode)
Definition: pad.h:753
const wxString & GetPinFunction() const
Definition: pad.h:147
std::mutex m_shapesBuildingLock
Definition: pad.h:940
bool CanHaveNumber() const
Indicates whether or not the pad can have a number.
Definition: pad.cpp:231
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition: pad.h:618
wxString m_pinType
Definition: pad.h:931
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: pad.cpp:176
const wxString & GetNumber() const
Definition: pad.h:136
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: pad.cpp:1752
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition: pad.h:299
void SetFrontRoundRectRadiusRatio(double aRadiusScale)
Definition: pad.cpp:475
void BuildEffectiveShapes() const
Rebuild the effective shape cache (and bounding box and radius) for the pad and clears the dirty bit.
Definition: pad.cpp:600
PAD_SHAPE GetFrontShape() const
Definition: pad.h:200
void CopyFrom(const BOARD_ITEM *aOther) override
Definition: pad.cpp:144
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: pad.h:476
PAD & operator=(const PAD &aOther)
Definition: pad.cpp:127
void SetLocalThermalSpokeWidthOverride(std::optional< int > aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: pad.h:602
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:186
std::shared_ptr< SHAPE_SEGMENT > m_effectiveHoleShape
Definition: pad.h:943
bool IsLocked() const override
Definition: pad.cpp:245
VECTOR2I GetPosition() const override
Definition: pad.h:208
void SetProperty(PAD_PROP aProperty)
Definition: pad.cpp:925
void SetThermalSpokeAngleDegrees(double aAngle)
Definition: pad.h:628
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:622
std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > m_zoneLayerOverrides
Definition: pad.h:964
PAD_ATTRIB m_attribute
Definition: pad.h:957
void Flip(const VECTOR2I &VECTOR2I, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition: pad.cpp:958
std::vector< PCB_SHAPE * > Recombine(bool aIsDryRun, int aMaxError)
Recombines the pad with other graphical shapes in the footprint.
Definition: pad.cpp:2060
PCB_LAYER_ID GetPrincipalLayer() const
Definition: pad.cpp:333
void SetDirty()
Definition: pad.h:429
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pad.cpp:305
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pad.cpp:1662
double GetOrientationDegrees() const
Definition: pad.h:416
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pad.cpp:1529
PADSTACK m_padStack
Definition: pad.h:935
void FlipPrimitives(FLIP_DIRECTION aFlipDirection)
Flip (mirror) the primitives left to right or top to bottom, around the anchor position in custom pad...
Definition: pad.cpp:1025
LAYER_SHAPE_MAP m_effectiveShapes
Definition: pad.h:942
bool IsNoConnectPad() const
Definition: pad.cpp:271
int GetDrillSizeX() const
Definition: pad.h:307
PAD_PROP m_property
Definition: pad.h:959
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
Definition: pad.h:668
void DeletePrimitivesList(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Clear the basic shapes list.
Definition: pad.cpp:2601
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:195
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:1953
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition: pad.h:135
void SetFrontRoundRectRadiusSize(int aRadius)
Definition: pad.cpp:485
wxString ShowPadAttr() const
Definition: pad.cpp:1554
void AddPrimitive(PCB_LAYER_ID aLayer, PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
Definition: pad.cpp:2592
void SetDrillShape(PAD_DRILL_SHAPE aShape)
Definition: pad.cpp:444
int m_effectiveBoundingRadius
Definition: pad.h:949
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: pad.h:459
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:482
void SetChamferRectRatio(PCB_LAYER_ID aLayer, double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition: pad.cpp:505
int GetSolderMaskExpansion(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1152
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.h:455
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition: pad.cpp:1857
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:2504
bool IsOnCopperLayer() const override
Definition: pad.cpp:1058
void SetDrillSizeX(const int aX)
Definition: pad.cpp:433
void SetPadstack(const PADSTACK &aPadstack)
Definition: pad.h:323
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:202
const SHAPE_COMPOUND & buildEffectiveShape(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:646
const PADSTACK & Padstack() const
Definition: pad.h:321
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition: pad.h:317
VECTOR2I m_pos
Definition: pad.h:933
double m_lastGalZoomLevel
Definition: pad.h:952
void BuildEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:802
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition: pad.cpp:298
void SetDrillSize(const VECTOR2I &aSize)
Definition: pad.h:304
bool IsFreePad() const
Definition: pad.cpp:277
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:408
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition: pad.h:259
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition: pad.h:221
PAD_DRILL_SHAPE GetDrillShape() const
Definition: pad.h:422
void ReplacePrimitives(PCB_LAYER_ID aLayer, const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Clear the current custom shape primitives list and import a new list.
Definition: pad.cpp:2569
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition: pad.h:708
static LSET ApertureMask()
layer set for an aperture pad
Definition: pad.cpp:312
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pad.cpp:1822
bool m_shapesDirty
Definition: pad.h:939
std::mutex m_polyBuildingLock
Definition: pad.h:947
void SetRoundRectCornerRadius(PCB_LAYER_ID aLayer, double aRadius)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:461
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:291
std::optional< int > GetLocalSolderPasteMargin() const
Definition: pad.h:465
int GetFrontRoundRectRadiusSize() const
Definition: pad.cpp:495
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:513
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pad.h:458
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: pad.h:466
int GetSizeY() const
Definition: pad.h:291
std::optional< int > GetLocalThermalGapOverride() const
Definition: pad.h:642
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pad.cpp:327
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition: pad.cpp:1567
void SetPinFunction(const wxString &aName)
Set the pad function (pin name in schematic)
Definition: pad.h:146
EDA_ANGLE GetFPRelativeOrientation() const
Definition: pad.cpp:949
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition: pad.h:691
bool m_polyDirty[2]
Definition: pad.h:946
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:1432
void SetFPRelativeOrientation(const EDA_ANGLE &aAngle)
Definition: pad.cpp:940
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:231
int GetBoundingRadius() const
Return the radius of a minimum sized circle which fully encloses this pad.
Definition: pad.cpp:591
void ClearZoneLayerOverrides()
Definition: pad.cpp:205
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition: pad.cpp:933
std::mutex m_zoneLayerOverridesMutex
Definition: pad.h:963
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition: pad.h:606
PADSTACK::UNCONNECTED_LAYER_MODE GetUnconnectedLayerMode() const
Definition: pad.h:758
VECTOR2I GetSolderPasteMargin(PCB_LAYER_ID aLayer) const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition: pad.cpp:1198
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: pad.cpp:1656
void AppendPrimitives(PCB_LAYER_ID aLayer, const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Import a custom shape primitive list (composed of basic shapes) and add items to the current list.
Definition: pad.cpp:2582
wxString m_number
Definition: pad.h:929
LAYER_POLYGON_MAP m_effectivePolygons
Definition: pad.h:948
void SetLocalClearance(std::optional< int > aClearance)
Definition: pad.h:456
int GetSubRatsnest() const
Definition: pad.h:716
void SetSizeX(const int aX)
Definition: pad.h:271
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: pad.h:483
int m_lengthPadToDie
Definition: pad.h:961
void SetDrillSizeY(const int aY)
Definition: pad.h:308
double GetThermalSpokeAngleDegrees() const
Definition: pad.h:632
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1043
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:582
void SetOrientationDegrees(double aOrientation)
Definition: pad.h:412
ZONE_CONNECTION GetZoneConnectionOverrides(wxString *aSource=nullptr) const
Definition: pad.cpp:1261
int GetLocalThermalGapOverride(wxString *aSource) const
Definition: pad.cpp:1290
void SetLayerSet(const LSET &aLayers) override
Definition: pad.h:436
bool SharesNetTieGroup(const PAD *aOther) const
Definition: pad.cpp:254
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:213
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:467
void SetSubRatsnest(int aSubRatsnest)
Definition: pad.h:717
int GetLocalSpokeWidthOverride(wxString *aSource=nullptr) const
Definition: pad.cpp:1281
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:1936
void SetPadToDieLength(int aLength)
Definition: pad.h:452
bool IsFlipped() const
Definition: pad.cpp:319
bool operator==(const PAD &aOther) const
Definition: pad.cpp:2489
wxString ShowPadShape(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1538
void SetSizeY(const int aY)
Definition: pad.h:282
int GetPadToDieLength() const
Definition: pad.h:453
BOX2I m_effectiveBoundingBox
Definition: pad.h:941
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:264
virtual std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
Definition: pad.cpp:1680
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:554
bool IsProxyItem() const override
Definition: pcb_shape.h:116
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:845
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:461
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:92
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:71
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
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
bool HasHoles() const
Return true if the polygon set has any holes.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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 Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
void Move(const VECTOR2I &aVector) override
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const SHAPE_LINE_CHAIN Outline() const
Definition: shape_rect.h:212
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:94
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)
const int minSize
Push and Shove router track width and via size dialog.
@ DRCE_PADSTACK
Definition: drc_item.h:62
@ DRCE_PADSTACK_INVALID
Definition: drc_item.h:63
@ DRCE_PAD_TH_WITH_NO_HOLE
Definition: drc_item.h:84
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:51
#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
Some functions to handle hotkeys in KiCad.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: layer_id.cpp:169
@ LAYER_PAD_FR_NETNAMES
Additional netnames layers (not associated with a PCB layer).
Definition: layer_ids.h:200
@ LAYER_PAD_BK_NETNAMES
Definition: layer_ids.h:201
@ LAYER_PAD_NETNAMES
Definition: layer_ids.h:202
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition: layer_ids.h:765
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:184
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:788
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:663
@ LAYER_PAD_COPPER_START
Virtual layers for pad copper on a given copper layer.
Definition: layer_ids.h:331
@ LAYER_FOOTPRINTS_FR
Show footprints on front.
Definition: layer_ids.h:258
@ LAYER_NON_PLATEDHOLES
Draw usual through hole vias.
Definition: layer_ids.h:238
@ LAYER_PADS
Meta control for all pads opacity/visibility (color ignored).
Definition: layer_ids.h:291
@ LAYER_PAD_PLATEDHOLES
to draw pad holes (plated)
Definition: layer_ids.h:270
@ LAYER_CLEARANCE_START
Virtual layers for pad/via/track clearance outlines for a given copper layer.
Definition: layer_ids.h:339
@ LAYER_FOOTPRINTS_BK
Show footprints on back.
Definition: layer_ids.h:259
@ LAYER_PAD_HOLEWALLS
Definition: layer_ids.h:296
bool IsNetnameLayer(int aLayer)
Test whether a layer is a netname layer.
Definition: layer_ids.h:854
bool IsHoleLayer(int aLayer)
Definition: layer_ids.h:724
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Adhes
Definition: layer_ids.h:103
@ Edge_Cuts
Definition: layer_ids.h:112
@ Dwgs_User
Definition: layer_ids.h:107
@ F_Paste
Definition: layer_ids.h:104
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ Eco1_User
Definition: layer_ids.h:109
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ F_SilkS
Definition: layer_ids.h:100
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:110
@ B_SilkS
Definition: layer_ids.h:101
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:171
@ 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
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:45
FLIP_DIRECTION
Definition: mirror.h:27
Message panel definition file.
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition: eda_units.h:159
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:58
bool PadHasMeaningfulRoundingRadius(const PAD &aPad, PCB_LAYER_ID aLayer)
Returns true if the pad's rounding ratio is valid (i.e.
Definition: pad_utils.cpp:44
double GetDefaultIpcRoundingRatio(const PAD &aPad, PCB_LAYER_ID aLayer)
Get a sensible default for a rounded rectangle pad's rounding ratio.
Definition: pad_utils.cpp:27
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition: api_utils.cpp:84
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput)
Definition: api_utils.cpp:77
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
static struct PAD_DESC _PAD_DESC
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition: padstack.h:69
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: padstack.h:81
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: padstack.h:52
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition: padstack.h:98
Class to handle a set of BOARD_ITEMs.
#define TYPE_HASH(x)
Definition: property.h:71
#define NO_SETTER(owner, type)
Definition: property.h:791
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:782
#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:243
PAD_DRILL_SHAPE shape
Definition: padstack.h:244
PAD_DESC()
Definition: pad.cpp:2669
int clearance
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:229
@ 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
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< int64_t > VECTOR2L
Definition: vector2d.h:696
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition: zones.h:36