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