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
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:
104
105 // Set layers mask to default for a standard thru hole pad.
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 ) :
121 BOARD_CONNECTED_ITEM( aOther.GetParent(), PCB_PAD_T ),
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() );
166 pad.set_type( ToProtoEnum<PAD_ATTRIB, PadType>( GetAttribute() ) );
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 );
192 SetAttribute( FromProtoEnum<PAD_ATTRIB>( pad.type() ) );
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
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
245 if( GetAttribute() == PAD_ATTRIB::NPTH )
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{
342 if( m_attribute == PAD_ATTRIB::SMD || m_attribute == PAD_ATTRIB::CONN || GetLayerSet().none() )
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 {
378 if( GetShape( layer ) == PAD_SHAPE::CIRCLE && GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
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
384 && GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
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 {
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
449 if( GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
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
543 if( GetAttribute() == PAD_ATTRIB::PTH || GetAttribute() == PAD_ATTRIB::NPTH )
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
555 if( GetAttribute() == PAD_ATTRIB::PTH )
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 {
569 if( GetAttribute() == PAD_ATTRIB::PTH )
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
608{
611
613}
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 {
680 case PAD_SHAPE::CIRCLE:
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
700 case PAD_SHAPE::RECTANGLE:
701 case PAD_SHAPE::TRAPEZOID:
702 case PAD_SHAPE::ROUNDRECT:
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
775 case PAD_SHAPE::CHAMFERED_RECT:
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
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{
1085 if( GetAttribute() == PAD_ATTRIB::NPTH )
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
1159 if( GetAttribute() == PAD_ATTRIB::NPTH )
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
1372 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
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
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 {
1444 if( GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
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 ) const
1477{
1478 VECTOR2I delta = aPosition - GetPosition();
1479 int boundingRadius = GetBoundingRadius() + aAccuracy;
1480
1481 if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) )
1482 return false;
1483
1484 bool contains = false;
1485
1487 [&]( PCB_LAYER_ID l )
1488 {
1489 if( contains )
1490 return;
1491
1492 if( GetEffectivePolygon( l, ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy ) )
1493 contains = true;
1494 } );
1495
1496 contains |= GetEffectiveHoleShape()->Collide( aPosition, aAccuracy );
1497
1498 return contains;
1499}
1500
1501
1502bool PAD::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1503{
1504 BOX2I arect = aRect;
1505 arect.Normalize();
1506 arect.Inflate( aAccuracy );
1507
1508 BOX2I bbox = GetBoundingBox();
1509
1510 if( aContained )
1511 {
1512 return arect.Contains( bbox );
1513 }
1514 else
1515 {
1516 // Fast test: if aRect is outside the polygon bounding box,
1517 // rectangles cannot intersect
1518 if( !arect.Intersects( bbox ) )
1519 return false;
1520
1521 bool hit = false;
1522
1524 [&]( PCB_LAYER_ID aLayer )
1525 {
1526 if( hit )
1527 return;
1528
1529 const std::shared_ptr<SHAPE_POLY_SET>& poly = GetEffectivePolygon( aLayer, ERROR_INSIDE );
1530
1531 int count = poly->TotalVertices();
1532
1533 for( int ii = 0; ii < count; ii++ )
1534 {
1535 VECTOR2I vertex = poly->CVertex( ii );
1536 VECTOR2I vertexNext = poly->CVertex( ( ii + 1 ) % count );
1537
1538 // Test if the point is within aRect
1539 if( arect.Contains( vertex ) )
1540 {
1541 hit = true;
1542 break;
1543 }
1544
1545 // Test if this edge intersects aRect
1546 if( arect.Intersects( vertex, vertexNext ) )
1547 {
1548 hit = true;
1549 break;
1550 }
1551 }
1552 } );
1553
1554 if( !hit )
1555 {
1556 SHAPE_RECT rect( arect );
1557 hit |= GetEffectiveHoleShape()->Collide( &rect );
1558 }
1559
1560 return hit;
1561 }
1562}
1563
1564
1565bool PAD::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
1566{
1567 SHAPE_COMPOUND effectiveShape;
1568
1569 // Add padstack shapes
1571 [&]( PCB_LAYER_ID aLayer )
1572 {
1573 effectiveShape.AddShape( GetEffectiveShape( aLayer ) );
1574 } );
1575
1576 // Add hole shape
1577 effectiveShape.AddShape( GetEffectiveHoleShape() );
1578
1579 return KIGEOM::ShapeHitTest( aPoly, effectiveShape, aContained );
1580}
1581
1582
1583int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
1584{
1585 int diff;
1586
1587 if( ( diff = static_cast<int>( aPadRef->m_attribute ) - static_cast<int>( aPadCmp->m_attribute ) ) != 0 )
1588 return diff;
1589
1590 return PADSTACK::Compare( &aPadRef->Padstack(), &aPadCmp->Padstack() );
1591}
1592
1593
1594void PAD::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1595{
1596 RotatePoint( m_pos, aRotCentre, aAngle );
1598
1599 SetDirty();
1600}
1601
1602
1603wxString PAD::ShowPadShape( PCB_LAYER_ID aLayer ) const
1604{
1605 switch( GetShape( aLayer ) )
1606 {
1607 case PAD_SHAPE::CIRCLE: return _( "Circle" );
1608 case PAD_SHAPE::OVAL: return _( "Oval" );
1609 case PAD_SHAPE::RECTANGLE: return _( "Rect" );
1610 case PAD_SHAPE::TRAPEZOID: return _( "Trap" );
1611 case PAD_SHAPE::ROUNDRECT: return _( "Roundrect" );
1612 case PAD_SHAPE::CHAMFERED_RECT: return _( "Chamferedrect" );
1613 case PAD_SHAPE::CUSTOM: return _( "CustomShape" );
1614 default: return wxT( "???" );
1615 }
1616}
1617
1618
1619wxString PAD::ShowPadAttr() const
1620{
1621 switch( GetAttribute() )
1622 {
1623 case PAD_ATTRIB::PTH: return _( "PTH" );
1624 case PAD_ATTRIB::SMD: return _( "SMD" );
1625 case PAD_ATTRIB::CONN: return _( "Conn" );
1626 case PAD_ATTRIB::NPTH: return _( "NPTH" );
1627 default: return wxT( "???" );
1628 }
1629}
1630
1631
1632wxString PAD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1633{
1634 FOOTPRINT* parentFP = GetParentFootprint();
1635
1636 // Don't report parent footprint info from footprint editor, viewer, etc.
1637 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
1638 parentFP = nullptr;
1639
1640 if( GetAttribute() == PAD_ATTRIB::NPTH )
1641 {
1642 if( parentFP )
1643 return wxString::Format( _( "NPTH pad of %s" ), parentFP->GetReference() );
1644 else
1645 return _( "NPTH pad" );
1646 }
1647 else if( GetNumber().IsEmpty() )
1648 {
1649 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1650 {
1651 if( parentFP )
1652 {
1653 return wxString::Format( _( "Pad %s of %s on %s" ),
1654 GetNetnameMsg(),
1655 parentFP->GetReference(),
1657 }
1658 else
1659 {
1660 return wxString::Format( _( "Pad on %s" ),
1662 }
1663 }
1664 else
1665 {
1666 if( parentFP )
1667 {
1668 return wxString::Format( _( "PTH pad %s of %s" ),
1669 GetNetnameMsg(),
1670 parentFP->GetReference() );
1671 }
1672 else
1673 {
1674 return _( "PTH pad" );
1675 }
1676 }
1677 }
1678 else
1679 {
1680 if( GetAttribute() == PAD_ATTRIB::SMD || GetAttribute() == PAD_ATTRIB::CONN )
1681 {
1682 if( parentFP )
1683 {
1684 return wxString::Format( _( "Pad %s %s of %s on %s" ),
1685 GetNumber(),
1686 GetNetnameMsg(),
1687 parentFP->GetReference(),
1689 }
1690 else
1691 {
1692 return wxString::Format( _( "Pad %s on %s" ),
1693 GetNumber(),
1695 }
1696 }
1697 else
1698 {
1699 if( parentFP )
1700 {
1701 return wxString::Format( _( "PTH pad %s %s of %s" ),
1702 GetNumber(),
1703 GetNetnameMsg(),
1704 parentFP->GetReference() );
1705 }
1706 else
1707 {
1708 return wxString::Format( _( "PTH pad %s" ),
1709 GetNumber() );
1710 }
1711 }
1712 }
1713}
1714
1715
1717{
1718 return BITMAPS::pad;
1719}
1720
1721
1723{
1724 PAD* cloned = new PAD( *this );
1725
1726 // Ensure the cloned primitives of the pad stack have the right parent
1727 cloned->Padstack().ForEachUniqueLayer(
1728 [&]( PCB_LAYER_ID aLayer )
1729 {
1730 for( std::shared_ptr<PCB_SHAPE>& primitive : cloned->m_padStack.Primitives( aLayer ) )
1731 primitive->SetParent( cloned );
1732 } );
1733
1734 return cloned;
1735}
1736
1737
1738std::vector<int> PAD::ViewGetLayers() const
1739{
1740 std::vector<int> layers;
1741 layers.reserve( 64 );
1742
1743 // These 2 types of pads contain a hole
1744 if( m_attribute == PAD_ATTRIB::PTH )
1745 {
1746 layers.push_back( LAYER_PAD_PLATEDHOLES );
1747 layers.push_back( LAYER_PAD_HOLEWALLS );
1748 }
1749
1750 if( m_attribute == PAD_ATTRIB::NPTH )
1751 layers.push_back( LAYER_NON_PLATEDHOLES );
1752
1753
1755 layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
1756
1757 LSET cuLayers = ( m_padStack.LayerSet() & LSET::AllCuMask() );
1758
1759 // Don't spend cycles rendering layers that aren't visible
1760 if( const BOARD* board = GetBoard() )
1761 cuLayers &= board->GetEnabledLayers();
1762
1763 if( cuLayers.count() > 1 )
1764 {
1765 // Multi layer pad
1766 for( PCB_LAYER_ID layer : cuLayers.Seq() )
1767 {
1768 layers.push_back( LAYER_PAD_COPPER_START + layer );
1769 layers.push_back( LAYER_CLEARANCE_START + layer );
1770 }
1771
1772 layers.push_back( LAYER_PAD_NETNAMES );
1773 }
1774 else if( IsOnLayer( F_Cu ) )
1775 {
1776 layers.push_back( LAYER_PAD_COPPER_START );
1777 layers.push_back( LAYER_CLEARANCE_START );
1778
1779 // Is this a PTH pad that has only front copper? If so, we need to also display the
1780 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1781 if( m_attribute == PAD_ATTRIB::PTH )
1782 layers.push_back( LAYER_PAD_NETNAMES );
1783 else
1784 layers.push_back( LAYER_PAD_FR_NETNAMES );
1785 }
1786 else if( IsOnLayer( B_Cu ) )
1787 {
1788 layers.push_back( LAYER_PAD_COPPER_START + B_Cu );
1789 layers.push_back( LAYER_CLEARANCE_START + B_Cu );
1790
1791 // Is this a PTH pad that has only back copper? If so, we need to also display the
1792 // net name on the PTH netname layer so that it isn't blocked by the drill hole.
1793 if( m_attribute == PAD_ATTRIB::PTH )
1794 layers.push_back( LAYER_PAD_NETNAMES );
1795 else
1796 layers.push_back( LAYER_PAD_BK_NETNAMES );
1797 }
1798
1799 // Check non-copper layers. This list should include all the layers that the
1800 // footprint editor allows a pad to be placed on.
1801 static const PCB_LAYER_ID layers_mech[] = { F_Mask, B_Mask, F_Paste, B_Paste,
1803
1804 for( PCB_LAYER_ID each_layer : layers_mech )
1805 {
1806 if( IsOnLayer( each_layer ) )
1807 layers.push_back( each_layer );
1808 }
1809
1810 return layers;
1811}
1812
1813
1814double PAD::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
1815{
1816 PCB_PAINTER& painter = static_cast<PCB_PAINTER&>( *aView->GetPainter() );
1817 PCB_RENDER_SETTINGS& renderSettings = *painter.GetSettings();
1818 const BOARD* board = GetBoard();
1819
1820 // Meta control for hiding all pads
1821 if( !aView->IsLayerVisible( LAYER_PADS ) )
1822 return LOD_HIDE;
1823
1824 // Handle Render tab switches
1825 //const PCB_LAYER_ID& pcbLayer = static_cast<PCB_LAYER_ID>( aLayer );
1826
1827 if( !IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
1828 return LOD_HIDE;
1829
1830 if( IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
1831 return LOD_HIDE;
1832
1833 if( IsHoleLayer( aLayer ) )
1834 {
1835 LSET visiblePhysical = board->GetVisibleLayers();
1836 visiblePhysical &= board->GetEnabledLayers();
1837 visiblePhysical &= LSET::PhysicalLayersMask();
1838
1839 if( !visiblePhysical.any() )
1840 return LOD_HIDE;
1841 }
1842 else if( IsNetnameLayer( aLayer ) )
1843 {
1844 if( renderSettings.GetHighContrast() )
1845 {
1846 // Hide netnames unless pad is flashed to a high-contrast layer
1847 if( !FlashLayer( renderSettings.GetPrimaryHighContrastLayer() ) )
1848 return LOD_HIDE;
1849 }
1850 else
1851 {
1852 LSET visible = board->GetVisibleLayers();
1853 visible &= board->GetEnabledLayers();
1854
1855 // Hide netnames unless pad is flashed to a visible layer
1856 if( !FlashLayer( visible ) )
1857 return LOD_HIDE;
1858 }
1859
1860 // Netnames will be shown only if zoom is appropriate
1861 const int minSize = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
1862
1863 return lodScaleForThreshold( aView, minSize, pcbIUScale.mmToIU( 0.5 ) );
1864 }
1865
1866 // Hole walls always need a repaint when zoom level changes after the last
1867 // LAYER_PAD_HOLEWALLS shape rebuild
1868 if( aLayer == LAYER_PAD_HOLEWALLS )
1869 {
1870 if( aView->GetGAL()->GetZoomFactor() != m_lastGalZoomLevel )
1871 {
1872 aView->Update( this, KIGFX::REPAINT );
1874 }
1875 }
1876
1877 VECTOR2L padSize = GetBoundingBox().GetSize();
1878 int64_t minSide = std::min( padSize.x, padSize.y );
1879
1880 if( minSide > 0 )
1881 return std::min( lodScaleForThreshold( aView, minSide, pcbIUScale.mmToIU( 0.2 ) ), 3.5 );
1882
1883 return LOD_SHOW;
1884}
1885
1886
1888{
1889 // Bounding box includes soldermask too. Remember mask and/or paste margins can be < 0
1890 int solderMaskMargin = 0;
1891 VECTOR2I solderPasteMargin;
1892
1894 [&]( PCB_LAYER_ID aLayer )
1895 {
1896 solderMaskMargin = std::max( solderMaskMargin, std::max( GetSolderMaskExpansion( aLayer ), 0 ) );
1897 VECTOR2I layerMargin = GetSolderPasteMargin( aLayer );
1898 solderPasteMargin.x = std::max( solderPasteMargin.x, layerMargin.x );
1899 solderPasteMargin.y = std::max( solderPasteMargin.y, layerMargin.y );
1900 } );
1901
1902 BOX2I bbox = GetBoundingBox();
1903 int clearance = 0;
1904
1905 // If we're drawing clearance lines then get the biggest possible clearance
1906 if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
1907 {
1908 if( cfg && cfg->m_Display.m_PadClearance && GetBoard() )
1910 }
1911
1912 // Look for the biggest possible bounding box
1913 int xMargin = std::max( solderMaskMargin, solderPasteMargin.x ) + clearance;
1914 int yMargin = std::max( solderMaskMargin, solderPasteMargin.y ) + clearance;
1915
1916 return BOX2I( VECTOR2I( bbox.GetOrigin() ) - VECTOR2I( xMargin, yMargin ),
1917 VECTOR2I( bbox.GetSize() ) + VECTOR2I( 2 * xMargin, 2 * yMargin ) );
1918}
1919
1920
1921void PAD::ImportSettingsFrom( const PAD& aMasterPad )
1922{
1923 SetPadstack( aMasterPad.Padstack() );
1924 // Layer Set should be updated before calling SetAttribute()
1925 SetLayerSet( aMasterPad.GetLayerSet() );
1926 SetAttribute( aMasterPad.GetAttribute() );
1927 // Unfortunately, SetAttribute() can change m_layerMask.
1928 // Be sure we keep the original mask by calling SetLayerSet() after SetAttribute()
1929 SetLayerSet( aMasterPad.GetLayerSet() );
1930 SetProperty( aMasterPad.GetProperty() );
1931
1932 // Must be after setting attribute and layerSet
1933 if( !CanHaveNumber() )
1934 SetNumber( wxEmptyString );
1935
1936 // I am not sure the m_LengthPadToDie should be imported, because this is a parameter
1937 // really specific to a given pad (JPC).
1938#if 0
1939 SetPadToDieLength( aMasterPad.GetPadToDieLength() );
1940 SetPadToDieDelay( aMasterPad.GetPadToDieDelay() );
1941#endif
1942
1943 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
1944 EDA_ANGLE pad_rot = aMasterPad.GetOrientation();
1945
1946 if( aMasterPad.GetParentFootprint() )
1947 pad_rot -= aMasterPad.GetParentFootprint()->GetOrientation();
1948
1949 if( GetParentFootprint() )
1950 pad_rot += GetParentFootprint()->GetOrientation();
1951
1952 SetOrientation( pad_rot );
1953
1955 [&]( PCB_LAYER_ID aLayer )
1956 {
1957 // Ensure that circles are circles
1958 if( aMasterPad.GetShape( aLayer ) == PAD_SHAPE::CIRCLE )
1959 SetSize( aLayer, VECTOR2I( GetSize( aLayer ).x, GetSize( aLayer ).x ) );
1960 } );
1961
1962 switch( aMasterPad.GetAttribute() )
1963 {
1964 case PAD_ATTRIB::SMD:
1965 case PAD_ATTRIB::CONN:
1966 // These pads do not have a hole (they are expected to be on one external copper layer)
1967 SetDrillSize( VECTOR2I( 0, 0 ) );
1968 break;
1969
1970 default:
1971 ;
1972 }
1973
1974 // copy also local settings:
1975 SetLocalClearance( aMasterPad.GetLocalClearance() );
1979
1984
1986
1988
1989 SetDirty();
1990}
1991
1992
1994{
1995 assert( aImage->Type() == PCB_PAD_T );
1996
1997 std::swap( *this, *static_cast<PAD*>( aImage ) );
1998}
1999
2000
2001bool PAD::TransformHoleToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
2002 ERROR_LOC aErrorLoc ) const
2003{
2004 VECTOR2I drillsize = GetDrillSize();
2005
2006 if( !drillsize.x || !drillsize.y )
2007 return false;
2008
2009 std::shared_ptr<SHAPE_SEGMENT> slot = GetEffectiveHoleShape();
2010
2011 TransformOvalToPolygon( aBuffer, slot->GetSeg().A, slot->GetSeg().B, slot->GetWidth() + aClearance * 2,
2012 aError, aErrorLoc );
2013
2014 return true;
2015}
2016
2017
2018void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
2019 int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
2020{
2021 wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for pads." ) );
2022 wxASSERT_MSG( aLayer != UNDEFINED_LAYER,
2023 wxT( "UNDEFINED_LAYER is no longer allowed for PAD::TransformShapeToPolygon" ) );
2024
2025 // minimal segment count to approximate a circle to create the polygonal pad shape
2026 // This minimal value is mainly for very small pads, like SM0402.
2027 // Most of time pads are using the segment count given by aError value.
2028 const int pad_min_seg_per_circle_count = 16;
2029 int dx = m_padStack.Size( aLayer ).x / 2;
2030 int dy = m_padStack.Size( aLayer ).y / 2;
2031
2032 VECTOR2I padShapePos = ShapePos( aLayer ); // Note: for pad having a shape offset, the pad
2033 // position is NOT the shape position
2034
2035 switch( PAD_SHAPE shape = GetShape( aLayer ) )
2036 {
2037 case PAD_SHAPE::CIRCLE:
2038 case PAD_SHAPE::OVAL:
2039 // Note: dx == dy is not guaranteed for circle pads in legacy boards
2040 if( dx == dy || ( shape == PAD_SHAPE::CIRCLE ) )
2041 {
2042 TransformCircleToPolygon( aBuffer, padShapePos, dx + aClearance, aMaxError, aErrorLoc,
2043 pad_min_seg_per_circle_count );
2044 }
2045 else
2046 {
2047 int half_width = std::min( dx, dy );
2048 VECTOR2I delta( dx - half_width, dy - half_width );
2049
2051
2052 TransformOvalToPolygon( aBuffer, padShapePos - delta, padShapePos + delta,
2053 ( half_width + aClearance ) * 2, aMaxError, aErrorLoc,
2054 pad_min_seg_per_circle_count );
2055 }
2056
2057 break;
2058
2059 case PAD_SHAPE::TRAPEZOID:
2060 case PAD_SHAPE::RECTANGLE:
2061 {
2062 const VECTOR2I& trapDelta = m_padStack.TrapezoidDeltaSize( aLayer );
2063 int ddx = shape == PAD_SHAPE::TRAPEZOID ? trapDelta.x / 2 : 0;
2064 int ddy = shape == PAD_SHAPE::TRAPEZOID ? trapDelta.y / 2 : 0;
2065
2066 SHAPE_POLY_SET outline;
2067 TransformTrapezoidToPolygon( outline, padShapePos, m_padStack.Size( aLayer ), GetOrientation(),
2068 ddx, ddy, aClearance, aMaxError, aErrorLoc );
2069 aBuffer.Append( outline );
2070 break;
2071 }
2072
2073 case PAD_SHAPE::CHAMFERED_RECT:
2074 case PAD_SHAPE::ROUNDRECT:
2075 {
2076 bool doChamfer = shape == PAD_SHAPE::CHAMFERED_RECT;
2077
2078 SHAPE_POLY_SET outline;
2079 TransformRoundChamferedRectToPolygon( outline, padShapePos, m_padStack.Size( aLayer ),
2081 doChamfer ? GetChamferRectRatio( aLayer ) : 0,
2082 doChamfer ? GetChamferPositions( aLayer ) : 0,
2083 aClearance, aMaxError, aErrorLoc );
2084 aBuffer.Append( outline );
2085 break;
2086 }
2087
2088 case PAD_SHAPE::CUSTOM:
2089 {
2090 SHAPE_POLY_SET outline;
2091 MergePrimitivesAsPolygon( aLayer, &outline, aErrorLoc );
2092 outline.Rotate( GetOrientation() );
2093 outline.Move( VECTOR2I( padShapePos ) );
2094
2095 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
2096 {
2097 if( aErrorLoc == ERROR_OUTSIDE )
2098 aClearance += aMaxError;
2099
2100 outline.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aMaxError );
2101 outline.Fracture();
2102 }
2103 else if( aClearance < 0 )
2104 {
2105 // Negative clearances are primarily for drawing solder paste layer, so we don't
2106 // worry ourselves overly about which side the error is on.
2107
2108 // aClearance is negative so this is actually a deflate
2109 outline.Inflate( aClearance, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, aMaxError );
2110 outline.Fracture();
2111 }
2112
2113 aBuffer.Append( outline );
2114 break;
2115 }
2116
2117 default:
2118 wxFAIL_MSG( wxT( "PAD::TransformShapeToPolygon no implementation for " )
2119 + wxString( std::string( magic_enum::enum_name( shape ) ) ) );
2120 break;
2121 }
2122}
2123
2124
2125std::vector<PCB_SHAPE*> PAD::Recombine( bool aIsDryRun, int maxError )
2126{
2127 FOOTPRINT* footprint = GetParentFootprint();
2128
2129 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2130 item->ClearFlags( SKIP_STRUCT );
2131
2132 auto findNext =
2133 [&]( PCB_LAYER_ID aLayer ) -> PCB_SHAPE*
2134 {
2135 SHAPE_POLY_SET padPoly;
2136 TransformShapeToPolygon( padPoly, aLayer, 0, maxError, ERROR_INSIDE );
2137
2138 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2139 {
2140 PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( item );
2141
2142 if( !shape || ( shape->GetFlags() & SKIP_STRUCT ) )
2143 continue;
2144
2145 if( shape->GetLayer() != aLayer )
2146 continue;
2147
2148 if( shape->IsProxyItem() ) // Pad number (and net name) box
2149 return shape;
2150
2151 SHAPE_POLY_SET drawPoly;
2152 shape->TransformShapeToPolygon( drawPoly, aLayer, 0, maxError, ERROR_INSIDE );
2153 drawPoly.BooleanIntersection( padPoly );
2154
2155 if( !drawPoly.IsEmpty() )
2156 return shape;
2157 }
2158
2159 return nullptr;
2160 };
2161
2162 auto findMatching =
2163 [&]( PCB_SHAPE* aShape ) -> std::vector<PCB_SHAPE*>
2164 {
2165 std::vector<PCB_SHAPE*> matching;
2166
2167 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2168 {
2169 PCB_SHAPE* other = dynamic_cast<PCB_SHAPE*>( item );
2170
2171 if( !other || ( other->GetFlags() & SKIP_STRUCT ) )
2172 continue;
2173
2174 if( GetLayerSet().test( other->GetLayer() ) && aShape->Compare( other ) == 0 )
2175 matching.push_back( other );
2176 }
2177
2178 return matching;
2179 };
2180
2181 PCB_LAYER_ID layer;
2182 std::vector<PCB_SHAPE*> mergedShapes;
2183
2184 if( IsOnLayer( F_Cu ) )
2185 layer = F_Cu;
2186 else if( IsOnLayer( B_Cu ) )
2187 layer = B_Cu;
2188 else
2189 layer = GetLayerSet().UIOrder().front();
2190
2191 PAD_SHAPE origShape = GetShape( layer );
2192
2193 // If there are intersecting items to combine, we need to first make sure the pad is a
2194 // custom-shape pad.
2195 if( !aIsDryRun && findNext( layer ) && origShape != PAD_SHAPE::CUSTOM )
2196 {
2197 if( origShape == PAD_SHAPE::CIRCLE || origShape == PAD_SHAPE::RECTANGLE )
2198 {
2199 // Use the existing pad as an anchor
2200 SetAnchorPadShape( layer, origShape );
2201 SetShape( layer, PAD_SHAPE::CUSTOM );
2202 }
2203 else
2204 {
2205 // Create a new circular anchor and convert existing pad to a polygon primitive
2206 SHAPE_POLY_SET existingOutline;
2207 TransformShapeToPolygon( existingOutline, layer, 0, maxError, ERROR_INSIDE );
2208
2209 int minExtent = std::min( GetSize( layer ).x, GetSize( layer ).y );
2210 SetAnchorPadShape( layer, PAD_SHAPE::CIRCLE );
2211 SetSize( layer, VECTOR2I( minExtent, minExtent ) );
2212 SetShape( layer, PAD_SHAPE::CUSTOM );
2213
2214 PCB_SHAPE* shape = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
2215 shape->SetFilled( true );
2216 shape->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
2217 shape->SetPolyShape( existingOutline );
2218 shape->Move( - ShapePos( layer ) );
2219 shape->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
2220 AddPrimitive( layer, shape );
2221 }
2222 }
2223
2224 while( PCB_SHAPE* fpShape = findNext( layer ) )
2225 {
2226 fpShape->SetFlags( SKIP_STRUCT );
2227
2228 mergedShapes.push_back( fpShape );
2229
2230 if( !aIsDryRun )
2231 {
2232 // If the editor was inside a group when the pad was exploded, the added exploded shapes
2233 // will be part of the group. Remove them here before duplicating; we don't want the
2234 // primitives to wind up in a group.
2235 if( EDA_GROUP* group = fpShape->GetParentGroup(); group )
2236 group->RemoveItem( fpShape );
2237
2238 PCB_SHAPE* primitive = static_cast<PCB_SHAPE*>( fpShape->Duplicate( IGNORE_PARENT_GROUP ) );
2239
2240 primitive->SetParent( nullptr );
2241
2242 // Convert any hatched fills to solid
2243 if( primitive->IsAnyFill() )
2244 primitive->SetFillMode( FILL_T::FILLED_SHAPE );
2245
2246 primitive->Move( - ShapePos( layer ) );
2247 primitive->Rotate( VECTOR2I( 0, 0 ), - GetOrientation() );
2248
2249 AddPrimitive( layer, primitive );
2250 }
2251
2252 // See if there are other shapes that match and mark them for delete. (KiCad won't
2253 // produce these, but old footprints from other vendors have them.)
2254 for( PCB_SHAPE* other : findMatching( fpShape ) )
2255 {
2256 other->SetFlags( SKIP_STRUCT );
2257 mergedShapes.push_back( other );
2258 }
2259 }
2260
2261 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2262 item->ClearFlags( SKIP_STRUCT );
2263
2264 if( !aIsDryRun )
2266
2267 return mergedShapes;
2268}
2269
2270
2271void PAD::CheckPad( UNITS_PROVIDER* aUnitsProvider, bool aForPadProperties,
2272 const std::function<void( int aErrorCode, const wxString& aMsg )>& aErrorHandler ) const
2273{
2275 [&]( PCB_LAYER_ID aLayer )
2276 {
2277 doCheckPad( aLayer, aUnitsProvider, aForPadProperties, aErrorHandler );
2278 } );
2279
2280 LSET padlayers_mask = GetLayerSet();
2281 VECTOR2I drill_size = GetDrillSize();
2282
2283 if( !padlayers_mask[F_Cu] && !padlayers_mask[B_Cu] )
2284 {
2285 if( ( drill_size.x || drill_size.y ) && GetAttribute() != PAD_ATTRIB::NPTH )
2286 {
2287 aErrorHandler( DRCE_PADSTACK, _( "(plated through holes normally have a copper pad on "
2288 "at least one outer layer)" ) );
2289 }
2290 }
2291
2292 if( ( GetProperty() == PAD_PROP::FIDUCIAL_GLBL || GetProperty() == PAD_PROP::FIDUCIAL_LOCAL )
2293 && GetAttribute() == PAD_ATTRIB::NPTH )
2294 {
2295 aErrorHandler( DRCE_PADSTACK, _( "('fiducial' property makes no sense on NPTH pads)" ) );
2296 }
2297
2298 if( GetProperty() == PAD_PROP::TESTPOINT && GetAttribute() == PAD_ATTRIB::NPTH )
2299 aErrorHandler( DRCE_PADSTACK, _( "('testpoint' property makes no sense on NPTH pads)" ) );
2300
2301 if( GetProperty() == PAD_PROP::HEATSINK && GetAttribute() == PAD_ATTRIB::NPTH )
2302 aErrorHandler( DRCE_PADSTACK, _( "('heatsink' property makes no sense on NPTH pads)" ) );
2303
2304 if( GetProperty() == PAD_PROP::CASTELLATED && GetAttribute() != PAD_ATTRIB::PTH )
2305 aErrorHandler( DRCE_PADSTACK, _( "('castellated' property is for PTH pads)" ) );
2306
2307 if( GetProperty() == PAD_PROP::BGA && GetAttribute() != PAD_ATTRIB::SMD )
2308 aErrorHandler( DRCE_PADSTACK, _( "('BGA' property is for SMD pads)" ) );
2309
2310 if( GetProperty() == PAD_PROP::MECHANICAL && GetAttribute() != PAD_ATTRIB::PTH )
2311 aErrorHandler( DRCE_PADSTACK, _( "('mechanical' property is for PTH pads)" ) );
2312
2313 if( GetProperty() == PAD_PROP::PRESSFIT
2314 && ( GetAttribute() != PAD_ATTRIB::PTH || !HasDrilledHole() ) )
2315 aErrorHandler( DRCE_PADSTACK, _( "('press-fit' property is for PTH pads with round holes)" ) );
2316
2317 switch( GetAttribute() )
2318 {
2319 case PAD_ATTRIB::NPTH: // Not plated, but through hole, a hole is expected
2320 case PAD_ATTRIB::PTH: // Pad through hole, a hole is also expected
2321 if( drill_size.x <= 0
2322 || ( drill_size.y <= 0 && GetDrillShape() == PAD_DRILL_SHAPE::OBLONG ) )
2323 {
2324 aErrorHandler( DRCE_PAD_TH_WITH_NO_HOLE, wxEmptyString );
2325 }
2326 break;
2327
2328 case PAD_ATTRIB::CONN: // Connector pads are smd pads, just they do not have solder paste.
2329 if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
2330 {
2331 aErrorHandler( DRCE_PADSTACK, _( "(connector pads normally have no solder paste; use a "
2332 "SMD pad instead)" ) );
2333 }
2335
2336 case PAD_ATTRIB::SMD: // SMD and Connector pads (One external copper layer only)
2337 {
2338 if( drill_size.x > 0 || drill_size.y > 0 )
2339 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(SMD pad has a hole)" ) );
2340
2341 LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
2342
2343 if( IsOnLayer( F_Cu ) && IsOnLayer( B_Cu ) )
2344 {
2345 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper on both sides of the board)" ) );
2346 }
2347 else if( IsOnLayer( F_Cu ) )
2348 {
2349 if( IsOnLayer( B_Mask ) )
2350 {
2351 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and mask layers on different "
2352 "sides of the board)" ) );
2353 }
2354 else if( IsOnLayer( B_Paste ) )
2355 {
2356 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and paste layers on different "
2357 "sides of the board)" ) );
2358 }
2359 }
2360 else if( IsOnLayer( B_Cu ) )
2361 {
2362 if( IsOnLayer( F_Mask ) )
2363 {
2364 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and mask layers on different "
2365 "sides of the board)" ) );
2366 }
2367 else if( IsOnLayer( F_Paste ) )
2368 {
2369 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has copper and paste layers on different "
2370 "sides of the board)" ) );
2371 }
2372 }
2373 else if( innerlayers_mask.count() != 0 )
2374 {
2375 aErrorHandler( DRCE_PADSTACK, _( "(SMD pad has no outer layers)" ) );
2376 }
2377
2378 break;
2379 }
2380 }
2381}
2382
2383
2384void PAD::doCheckPad( PCB_LAYER_ID aLayer, UNITS_PROVIDER* aUnitsProvider, bool aForPadProperties,
2385 const std::function<void( int aErrorCode, const wxString& aMsg )>& aErrorHandler ) const
2386{
2387 wxString msg;
2388
2389 VECTOR2I pad_size = GetSize( aLayer );
2390
2391 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2392 pad_size = GetBoundingBox().GetSize();
2393 else if( pad_size.x <= 0 || ( pad_size.y <= 0 && GetShape( aLayer ) != PAD_SHAPE::CIRCLE ) )
2394 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(Pad must have a positive size)" ) );
2395
2396 // Test hole against pad shape
2397 if( IsOnCopperLayer() && GetDrillSize().x > 0 )
2398 {
2399 // Ensure the drill size can be handled in next calculations.
2400 // Use min size = 4 IU to be able to build a polygon from a hole shape
2401 const int min_drill_size = 4;
2402
2403 if( GetDrillSizeX() <= min_drill_size || GetDrillSizeY() <= min_drill_size )
2404 {
2405 msg.Printf( _( "(PTH pad hole size must be larger than %s)" ),
2406 aUnitsProvider->StringFromValue( min_drill_size, true ) );
2407 aErrorHandler( DRCE_PADSTACK_INVALID, msg );
2408 }
2409
2410 SHAPE_POLY_SET padOutline;
2411
2412 TransformShapeToPolygon( padOutline, aLayer, 0, GetMaxError(), ERROR_INSIDE );
2413
2414 if( GetAttribute() == PAD_ATTRIB::PTH )
2415 {
2416 // Test if there is copper area outside hole
2417 std::shared_ptr<SHAPE_SEGMENT> hole = GetEffectiveHoleShape();
2418 SHAPE_POLY_SET holeOutline;
2419
2420 TransformOvalToPolygon( holeOutline, hole->GetSeg().A, hole->GetSeg().B, hole->GetWidth(),
2422
2423 SHAPE_POLY_SET copper = padOutline;
2424 copper.BooleanSubtract( holeOutline );
2425
2426 if( copper.IsEmpty() )
2427 {
2428 aErrorHandler( DRCE_PADSTACK, _( "(PTH pad hole leaves no copper)" ) );
2429 }
2430 else if( aForPadProperties )
2431 {
2432 // Test if the pad hole is fully inside the copper area. Note that we only run
2433 // this check for pad properties because we run the more complete annular ring
2434 // checker on the board (which handles multiple pads with the same name).
2435 holeOutline.BooleanSubtract( padOutline );
2436
2437 if( !holeOutline.IsEmpty() )
2438 aErrorHandler( DRCE_PADSTACK, _( "(PTH pad hole not fully inside copper)" ) );
2439 }
2440 }
2441 else
2442 {
2443 // Test only if the pad hole's centre is inside the copper area
2444 if( !padOutline.Collide( GetPosition() ) )
2445 aErrorHandler( DRCE_PADSTACK, _( "(pad hole not inside pad shape)" ) );
2446 }
2447 }
2448
2449 if( GetLocalClearance().value_or( 0 ) < 0 )
2450 aErrorHandler( DRCE_PADSTACK, _( "(negative local clearance values have no effect)" ) );
2451
2452 // Some pads need a negative solder mask clearance (mainly for BGA with small pads)
2453 // However the negative solder mask clearance must not create negative mask size
2454 // Therefore test for minimal acceptable negative value
2455 std::optional<int> solderMaskMargin = GetLocalSolderMaskMargin();
2456
2457 if( solderMaskMargin.has_value() && solderMaskMargin.value() < 0 )
2458 {
2459 int absMargin = abs( solderMaskMargin.value() );
2460
2461 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2462 {
2463 for( const std::shared_ptr<PCB_SHAPE>& shape : GetPrimitives( aLayer ) )
2464 {
2465 BOX2I shapeBBox = shape->GetBoundingBox();
2466
2467 if( absMargin > shapeBBox.GetWidth() || absMargin > shapeBBox.GetHeight() )
2468 {
2469 aErrorHandler( DRCE_PADSTACK, _( "(negative solder mask clearance is larger "
2470 "than some shape primitives; results may be "
2471 "surprising)" ) );
2472
2473 break;
2474 }
2475 }
2476 }
2477 else if( absMargin > pad_size.x || absMargin > pad_size.y )
2478 {
2479 aErrorHandler( DRCE_PADSTACK, _( "(negative solder mask clearance is larger than pad; "
2480 "no solder mask will be generated)" ) );
2481 }
2482 }
2483
2484 // Some pads need a positive solder paste clearance (mainly for BGA with small pads)
2485 // However, a positive value can create issues if the resulting shape is too big.
2486 // (like a solder paste creating a solder paste area on a neighbor pad or on the solder mask)
2487 // So we could ask for user to confirm the choice
2488 // For now we just check for disappearing paste
2489 wxSize paste_size;
2490 int paste_margin = GetLocalSolderPasteMargin().value_or( 0 );
2491 double paste_ratio = GetLocalSolderPasteMarginRatio().value_or( 0 );
2492
2493 paste_size.x = pad_size.x + paste_margin + KiROUND( pad_size.x * paste_ratio );
2494 paste_size.y = pad_size.y + paste_margin + KiROUND( pad_size.y * paste_ratio );
2495
2496 if( paste_size.x <= 0 || paste_size.y <= 0 )
2497 {
2498 aErrorHandler( DRCE_PADSTACK, _( "(negative solder paste margin is larger than pad; "
2499 "no solder paste mask will be generated)" ) );
2500 }
2501
2502 if( GetShape( aLayer ) == PAD_SHAPE::ROUNDRECT )
2503 {
2504 if( GetRoundRectRadiusRatio( aLayer ) < 0.0 )
2505 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(negative corner radius is not allowed)" ) );
2506 else if( GetRoundRectRadiusRatio( aLayer ) > 50.0 )
2507 aErrorHandler( DRCE_PADSTACK, _( "(corner size will make pad circular)" ) );
2508 }
2509 else if( GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT )
2510 {
2511 if( GetChamferRectRatio( aLayer ) < 0.0 )
2512 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(negative corner chamfer is not allowed)" ) );
2513 else if( GetChamferRectRatio( aLayer ) > 50.0 )
2514 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(corner chamfer is too large)" ) );
2515 }
2516 else if( GetShape( aLayer ) == PAD_SHAPE::TRAPEZOID )
2517 {
2518 if( ( GetDelta( aLayer ).x < 0 && GetDelta( aLayer ).x < -GetSize( aLayer ).y )
2519 || ( GetDelta( aLayer ).x > 0 && GetDelta( aLayer ).x > GetSize( aLayer ).y )
2520 || ( GetDelta( aLayer ).y < 0 && GetDelta( aLayer ).y < -GetSize( aLayer ).x )
2521 || ( GetDelta( aLayer ).y > 0 && GetDelta( aLayer ).y > GetSize( aLayer ).x ) )
2522 {
2523 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(trapezoid delta is too large)" ) );
2524 }
2525 }
2526
2527 if( GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
2528 {
2529 SHAPE_POLY_SET mergedPolygon;
2530 MergePrimitivesAsPolygon( aLayer, &mergedPolygon );
2531
2532 if( mergedPolygon.OutlineCount() > 1 )
2533 aErrorHandler( DRCE_PADSTACK_INVALID, _( "(custom pad shape must resolve to a single polygon)" ) );
2534 }
2535}
2536
2537
2538bool PAD::operator==( const BOARD_ITEM& aBoardItem ) const
2539{
2540 if( Type() != aBoardItem.Type() )
2541 return false;
2542
2543 if( m_parent && aBoardItem.GetParent() && m_parent->m_Uuid != aBoardItem.GetParent()->m_Uuid )
2544 return false;
2545
2546 const PAD& other = static_cast<const PAD&>( aBoardItem );
2547
2548 return *this == other;
2549}
2550
2551
2552bool PAD::operator==( const PAD& aOther ) const
2553{
2554 if( Padstack() != aOther.Padstack() )
2555 return false;
2556
2557 if( GetPosition() != aOther.GetPosition() )
2558 return false;
2559
2560 if( GetAttribute() != aOther.GetAttribute() )
2561 return false;
2562
2563 return true;
2564}
2565
2566
2567double PAD::Similarity( const BOARD_ITEM& aOther ) const
2568{
2569 if( aOther.Type() != Type() )
2570 return 0.0;
2571
2572 if( m_parent->m_Uuid != aOther.GetParent()->m_Uuid )
2573 return 0.0;
2574
2575 const PAD& other = static_cast<const PAD&>( aOther );
2576
2577 double similarity = 1.0;
2578
2579 if( GetPosition() != other.GetPosition() )
2580 similarity *= 0.9;
2581
2582 if( GetAttribute() != other.GetAttribute() )
2583 similarity *= 0.9;
2584
2585 similarity *= Padstack().Similarity( other.Padstack() );
2586
2587 return similarity;
2588}
2589
2590
2591void PAD::AddPrimitivePoly( PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPoly, int aThickness,
2592 bool aFilled )
2593{
2594 // If aPoly has holes, convert it to a polygon with no holes.
2595 SHAPE_POLY_SET poly_no_hole;
2596 poly_no_hole.Append( aPoly );
2597
2598 if( poly_no_hole.HasHoles() )
2599 poly_no_hole.Fracture();
2600
2601 // There should never be multiple shapes, but if there are, we split them into
2602 // primitives so that we can edit them both.
2603 for( int ii = 0; ii < poly_no_hole.OutlineCount(); ++ii )
2604 {
2605 SHAPE_POLY_SET poly_outline( poly_no_hole.COutline( ii ) );
2606 PCB_SHAPE* item = new PCB_SHAPE();
2607 item->SetShape( SHAPE_T::POLY );
2608 item->SetFilled( aFilled );
2609 item->SetPolyShape( poly_outline );
2610 item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
2611 item->SetParent( this );
2612 m_padStack.AddPrimitive( item, aLayer );
2613 }
2614
2615 SetDirty();
2616}
2617
2618
2619void PAD::AddPrimitivePoly( PCB_LAYER_ID aLayer, const std::vector<VECTOR2I>& aPoly, int aThickness,
2620 bool aFilled )
2621{
2622 PCB_SHAPE* item = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
2623 item->SetFilled( aFilled );
2624 item->SetPolyPoints( aPoly );
2625 item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
2626 item->SetParent( this );
2627 m_padStack.AddPrimitive( item, aLayer );
2628 SetDirty();
2629}
2630
2631
2632void PAD::ReplacePrimitives( PCB_LAYER_ID aLayer, const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList )
2633{
2634 // clear old list
2635 DeletePrimitivesList( aLayer );
2636
2637 // Import to the given shape list
2638 if( aPrimitivesList.size() )
2639 AppendPrimitives( aLayer, aPrimitivesList );
2640
2641 SetDirty();
2642}
2643
2644
2645void PAD::AppendPrimitives( PCB_LAYER_ID aLayer, const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList )
2646{
2647 // Add duplicates of aPrimitivesList to the pad primitives list:
2648 for( const std::shared_ptr<PCB_SHAPE>& prim : aPrimitivesList )
2649 AddPrimitive( aLayer, new PCB_SHAPE( *prim ) );
2650
2651 SetDirty();
2652}
2653
2654
2655void PAD::AddPrimitive( PCB_LAYER_ID aLayer, PCB_SHAPE* aPrimitive )
2656{
2657 aPrimitive->SetParent( this );
2658 m_padStack.AddPrimitive( aPrimitive, aLayer );
2659
2660 SetDirty();
2661}
2662
2663
2665{
2666 if( aLayer == UNDEFINED_LAYER )
2667 {
2669 [&]( PCB_LAYER_ID l )
2670 {
2672 } );
2673 }
2674 else
2675 {
2676 m_padStack.ClearPrimitives( aLayer);
2677 }
2678
2679 SetDirty();
2680}
2681
2682
2684 ERROR_LOC aErrorLoc ) const
2685{
2686 aMergedPolygon->RemoveAllContours();
2687
2688 // Add the anchor pad shape in aMergedPolygon, others in aux_polyset:
2689 // The anchor pad is always at 0,0
2690 VECTOR2I padSize = GetSize( aLayer );
2691
2692 switch( GetAnchorPadShape( aLayer ) )
2693 {
2694 case PAD_SHAPE::RECTANGLE:
2695 {
2696 SHAPE_RECT rect( -padSize.x / 2, -padSize.y / 2, padSize.x, padSize.y );
2697 aMergedPolygon->AddOutline( rect.Outline() );
2698 break;
2699 }
2700
2701 default:
2702 case PAD_SHAPE::CIRCLE:
2703 TransformCircleToPolygon( *aMergedPolygon, VECTOR2I( 0, 0 ), padSize.x / 2, GetMaxError(), aErrorLoc );
2704 break;
2705 }
2706
2707 SHAPE_POLY_SET polyset;
2708
2709 for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives( aLayer ) )
2710 {
2711 if( !primitive->IsProxyItem() )
2712 primitive->TransformShapeToPolygon( polyset, UNDEFINED_LAYER, 0, GetMaxError(), aErrorLoc );
2713 }
2714
2715 polyset.Simplify();
2716
2717 // Merge all polygons with the initial pad anchor shape
2718 if( polyset.OutlineCount() )
2719 {
2720 aMergedPolygon->BooleanAdd( polyset );
2721 aMergedPolygon->Fracture();
2722 }
2723}
2724
2725
2726static struct PAD_DESC
2727{
2729 {
2731 .Map( PAD_ATTRIB::PTH, _HKI( "Through-hole" ) )
2732 .Map( PAD_ATTRIB::SMD, _HKI( "SMD" ) )
2733 .Map( PAD_ATTRIB::CONN, _HKI( "Edge connector" ) )
2734 .Map( PAD_ATTRIB::NPTH, _HKI( "NPTH, mechanical" ) );
2735
2737 .Map( PAD_SHAPE::CIRCLE, _HKI( "Circle" ) )
2738 .Map( PAD_SHAPE::RECTANGLE, _HKI( "Rectangle" ) )
2739 .Map( PAD_SHAPE::OVAL, _HKI( "Oval" ) )
2740 .Map( PAD_SHAPE::TRAPEZOID, _HKI( "Trapezoid" ) )
2741 .Map( PAD_SHAPE::ROUNDRECT, _HKI( "Rounded rectangle" ) )
2742 .Map( PAD_SHAPE::CHAMFERED_RECT, _HKI( "Chamfered rectangle" ) )
2743 .Map( PAD_SHAPE::CUSTOM, _HKI( "Custom" ) );
2744
2746 .Map( PAD_PROP::NONE, _HKI( "None" ) )
2747 .Map( PAD_PROP::BGA, _HKI( "BGA pad" ) )
2748 .Map( PAD_PROP::FIDUCIAL_GLBL, _HKI( "Fiducial, global to board" ) )
2749 .Map( PAD_PROP::FIDUCIAL_LOCAL, _HKI( "Fiducial, local to footprint" ) )
2750 .Map( PAD_PROP::TESTPOINT, _HKI( "Test point pad" ) )
2751 .Map( PAD_PROP::HEATSINK, _HKI( "Heatsink pad" ) )
2752 .Map( PAD_PROP::CASTELLATED, _HKI( "Castellated pad" ) )
2753 .Map( PAD_PROP::MECHANICAL, _HKI( "Mechanical pad" ) )
2754 .Map( PAD_PROP::PRESSFIT, _HKI( "Press-fit pad" ) );
2755
2757 .Map( PAD_DRILL_SHAPE::CIRCLE, _HKI( "Round" ) )
2758 .Map( PAD_DRILL_SHAPE::OBLONG, _HKI( "Oblong" ) );
2759
2761
2762 if( zcMap.Choices().GetCount() == 0 )
2763 {
2764 zcMap.Undefined( ZONE_CONNECTION::INHERITED );
2765 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
2766 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
2767 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
2768 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
2769 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
2770 }
2771
2773 .Map( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL, _HKI( "All copper layers" ) )
2774 .Map( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL, _HKI( "Connected layers only" ) )
2776 _HKI( "Front, back and connected layers" ) )
2778 _HKI( "Start and end layers only" ) );
2779
2781 REGISTER_TYPE( PAD );
2783
2784 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
2785 propMgr.Mask( TYPE_HASH( PAD ), TYPE_HASH( BOARD_ITEM ), _HKI( "Locked" ) );
2786
2787 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Orientation" ),
2789 PROPERTY_DISPLAY::PT_DEGREE ) );
2790
2791 auto isCopperPad =
2792 []( INSPECTABLE* aItem ) -> bool
2793 {
2794 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2795 return pad->GetAttribute() != PAD_ATTRIB::NPTH;
2796
2797 return false;
2798 };
2799
2800 auto padCanHaveHole =
2801 []( INSPECTABLE* aItem ) -> bool
2802 {
2803 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2804 return pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH;
2805
2806 return false;
2807 };
2808
2809 auto hasNormalPadstack =
2810 []( INSPECTABLE* aItem ) -> bool
2811 {
2812 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2813 return pad->Padstack().Mode() == PADSTACK::MODE::NORMAL;
2814
2815 return true;
2816 };
2817
2819 isCopperPad );
2820 propMgr.OverrideAvailability( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net Class" ),
2821 isCopperPad );
2822
2823 const wxString groupPad = _HKI( "Pad Properties" );
2824
2825 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_ATTRIB>( _HKI( "Pad Type" ),
2826 &PAD::SetAttribute, &PAD::GetAttribute ), groupPad );
2827
2828 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_SHAPE>( _HKI( "Pad Shape" ),
2829 &PAD::SetFrontShape, &PAD::GetFrontShape ), groupPad )
2830 .SetAvailableFunc( hasNormalPadstack );
2831
2832 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pad Number" ),
2833 &PAD::SetNumber, &PAD::GetNumber ), groupPad )
2834 .SetAvailableFunc( isCopperPad );
2835
2836 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Name" ),
2839 propMgr.AddProperty( new PROPERTY<PAD, wxString>( _HKI( "Pin Type" ),
2840 &PAD::SetPinType, &PAD::GetPinType ), groupPad )
2842 .SetChoicesFunc( []( INSPECTABLE* aItem )
2843 {
2844 wxPGChoices choices;
2845
2846 for( int ii = 0; ii < ELECTRICAL_PINTYPES_TOTAL; ii++ )
2848
2849 return choices;
2850 } );
2851
2852 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size X" ),
2853 &PAD::SetSizeX, &PAD::GetSizeX, PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2854 .SetAvailableFunc( hasNormalPadstack );
2855 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Size Y" ),
2856 &PAD::SetSizeY, &PAD::GetSizeY, PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2857 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
2858 {
2859 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2860 {
2861 // Custom padstacks can't have size modified through panel
2862 if( pad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
2863 return false;
2864
2865 // Circle pads have no usable y-size
2866 return pad->GetShape( PADSTACK::ALL_LAYERS ) != PAD_SHAPE::CIRCLE;
2867 }
2868
2869 return true;
2870 } );
2871
2872 const auto hasRoundRadius =
2873 []( INSPECTABLE* aItem ) -> bool
2874 {
2875 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2876 {
2877 // Custom padstacks can't have this property modified through panel
2878 if( pad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
2879 return false;
2880
2882 }
2883
2884 return false;
2885 };
2886
2887 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Corner Radius Ratio" ),
2889 .SetAvailableFunc( hasRoundRadius );
2890
2891 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Corner Radius Size" ),
2893 groupPad )
2894 .SetAvailableFunc( hasRoundRadius );
2895
2896 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_DRILL_SHAPE>( _HKI( "Hole Shape" ),
2897 &PAD::SetDrillShape, &PAD::GetDrillShape ), groupPad )
2898 .SetWriteableFunc( padCanHaveHole );
2899
2900 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size X" ),
2901 &PAD::SetDrillSizeX, &PAD::GetDrillSizeX, PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2902 .SetWriteableFunc( padCanHaveHole )
2904
2905 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Hole Size Y" ),
2906 &PAD::SetDrillSizeY, &PAD::GetDrillSizeY, PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2907 .SetWriteableFunc( padCanHaveHole )
2909 .SetAvailableFunc( []( INSPECTABLE* aItem ) -> bool
2910 {
2911 // Circle holes have no usable y-size
2912 if( PAD* pad = dynamic_cast<PAD*>( aItem ) )
2913 return pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE;
2914
2915 return true;
2916 } );
2917
2918 propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_PROP>( _HKI( "Fabrication Property" ),
2919 &PAD::SetProperty, &PAD::GetProperty ), groupPad );
2920
2923
2924 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Pad To Die Length" ),
2925 &PAD::SetPadToDieLength, &PAD::GetPadToDieLength, PROPERTY_DISPLAY::PT_SIZE ), groupPad )
2926 .SetAvailableFunc( isCopperPad );
2927
2928 propMgr.AddProperty( new PROPERTY<PAD, int>( _HKI( "Pad To Die Delay" ),
2929 &PAD::SetPadToDieDelay, &PAD::GetPadToDieDelay, PROPERTY_DISPLAY::PT_TIME ), groupPad )
2930 .SetAvailableFunc( isCopperPad );
2931
2932 const wxString groupOverrides = _HKI( "Overrides" );
2933
2934 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Clearance Override" ),
2935 &PAD::SetLocalClearance, &PAD::GetLocalClearance, PROPERTY_DISPLAY::PT_SIZE ), groupOverrides );
2936
2937 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
2938 &PAD::SetLocalSolderMaskMargin, &PAD::GetLocalSolderMaskMargin, PROPERTY_DISPLAY::PT_SIZE ),
2939 groupOverrides );
2940
2941 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Solderpaste Margin Override" ),
2942 &PAD::SetLocalSolderPasteMargin, &PAD::GetLocalSolderPasteMargin, PROPERTY_DISPLAY::PT_SIZE ),
2943 groupOverrides );
2944
2945 propMgr.AddProperty( new PROPERTY<PAD, std::optional<double>>( _HKI( "Solderpaste Margin Ratio Override" ),
2947 PROPERTY_DISPLAY::PT_RATIO ), groupOverrides );
2948
2949 propMgr.AddProperty( new PROPERTY_ENUM<PAD, ZONE_CONNECTION>( _HKI( "Zone Connection Style" ),
2951
2952 constexpr int minZoneWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
2953
2954 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Thermal Relief Spoke Width" ),
2956 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2957 .SetValidator( PROPERTY_VALIDATORS::RangeIntValidator<minZoneWidth, INT_MAX> );
2958
2959 propMgr.AddProperty( new PROPERTY<PAD, double>( _HKI( "Thermal Relief Spoke Angle" ),
2961 PROPERTY_DISPLAY::PT_DEGREE ), groupOverrides );
2962
2963 propMgr.AddProperty( new PROPERTY<PAD, std::optional<int>>( _HKI( "Thermal Relief Gap" ),
2965 PROPERTY_DISPLAY::PT_SIZE ), groupOverrides )
2967
2968 // TODO delta, drill shape offset, layer set
2969 }
2971
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Definition: approximation.h:32
@ ERROR_OUTSIDE
Definition: approximation.h:33
@ ERROR_INSIDE
Definition: approximation.h:34
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
ZONE_LAYER_OVERRIDE
Conditionally flashed vias and pads that interact with zones of different priority can be very squirr...
Definition: board_item.h: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,...
wxString GetNetnameMsg() const
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
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
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
Definition: board_item.cpp:103
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.
Definition: board_item.cpp:79
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:97
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.
Definition: board_item.cpp:158
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
Definition: board_item.cpp:207
int GetMaxError() const
Definition: board_item.cpp:138
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:921
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition: board.cpp:1036
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1024
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:907
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:658
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:311
wxString GetName() const
Definition: drc_rule.h:168
MINOPTMAX< int > & Value()
Definition: drc_rule.h:161
MINOPTMAX< int > m_Value
Definition: drc_rule.h:202
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
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
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:329
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
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:345
virtual void SetFilled(bool aFlag)
Definition: eda_shape.h:136
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:167
bool IsAnyFill() const
Definition: eda_shape.h:112
void SetPolyPoints(const std::vector< VECTOR2I > &aPoints)
Definition: eda_shape.cpp:1780
void SetFillMode(FILL_T aFill)
Definition: eda_shape.cpp:540
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:703
static ENUM_MAP< T > & Instance()
Definition: property.h:697
ENUM_MAP & Undefined(T aValue)
Definition: property.h:710
wxPGChoices & Choices()
Definition: property.h:746
EDA_ANGLE GetOrientation() const
Definition: footprint.h:230
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:3250
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:239
bool IsNetTie() const
Definition: footprint.h:306
const wxString & GetReference() const
Definition: footprint.h:627
DRAWINGS & GraphicalItems()
Definition: footprint.h:212
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:37
double GetZoomFactor() const
Contains methods for drawing PCB-specific items.
Definition: pcb_painter.h:182
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
Definition: pcb_painter.h:187
PCB specific render settings.
Definition: pcb_painter.h:80
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
bool GetHighContrast() const
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition: view_item.cpp:39
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition: view_item.h: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
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1685
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:202
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
wxString AsString() const
Definition: kiid.cpp:246
std::string AsStdString() const
Definition: kiid.cpp:252
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
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:733
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()
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:381
std::optional< int > & Clearance(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1196
void AddPrimitive(PCB_SHAPE *aShape, PCB_LAYER_ID aLayer)
Adds a custom shape primitive to the padstack.
Definition: padstack.cpp:1322
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: padstack.cpp:212
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
int RoundRectRadius(PCB_LAYER_ID aLayer) const
Definition: padstack.cpp:1149
std::optional< double > & SolderPasteMarginRatio(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1235
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
void SetRoundRectRadiusRatio(double aRatio, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1143
void ClearPrimitives(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1347
std::optional< int > & ThermalSpokeWidth(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1261
std::optional< int > & SolderPasteMargin(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1222
void SetOrientation(EDA_ANGLE aAngle)
Definition: padstack.h:302
std::optional< int > & SolderMaskMargin(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1208
void SetChamferRatio(double aRatio, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1172
const LSET & LayerSet() const
Definition: padstack.h:282
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
void SetShape(PAD_SHAPE aShape, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1068
VECTOR2I & TrapezoidDeltaSize(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1125
VECTOR2I & Offset(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1101
void FlipLayers(int aCopperLayerCount)
Flips the padstack layers in the case that the pad's parent footprint is flipped to the other side of...
Definition: padstack.cpp:720
void SetChamferPositions(int aPositions, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1190
void SetRoundRectRadius(double aRadius, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1156
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
Definition: padstack.h:314
std::optional< int > & ThermalGap(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1273
PAD_SHAPE Shape(PCB_LAYER_ID aLayer) const
Definition: padstack.cpp:1062
DRILL_PROPS & Drill()
Definition: padstack.h:308
static int Compare(const PADSTACK *aPadstackRef, const PADSTACK *aPadstackCmp)
Compare two padstacks and return 0 if they are equal.
Definition: padstack.cpp:536
int & ChamferPositions(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1178
const VECTOR2I & Size(PCB_LAYER_ID aLayer) const
Definition: padstack.cpp:1083
@ NORMAL
Shape is the same on all layers.
UNCONNECTED_LAYER_MODE
! Whether or not to remove the copper shape for unconnected layers
Definition: padstack.h:152
PCB_LAYER_ID StartLayer() const
Definition: padstack.cpp:708
MODE Mode() const
Definition: padstack.h:295
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: padstack.cpp:414
void SetSize(const VECTOR2I &aSize, PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1074
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:145
EDA_ANGLE GetOrientation() const
Definition: padstack.h:301
void SetLayerSet(const LSET &aSet)
Definition: padstack.h:284
std::optional< ZONE_CONNECTION > & ZoneConnection(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1249
std::vector< std::shared_ptr< PCB_SHAPE > > & Primitives(PCB_LAYER_ID aLayer)
Definition: padstack.cpp:1310
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:2271
PAD(FOOTPRINT *parent)
Definition: pad.cpp:76
virtual void swapData(BOARD_ITEM *aImage) override
Definition: pad.cpp:1993
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:2384
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:2683
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:786
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:2591
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:1583
void SetUnconnectedLayerMode(PADSTACK::UNCONNECTED_LAYER_MODE aMode)
Definition: pad.h:756
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:1814
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:2125
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:1722
double GetOrientationDegrees() const
Definition: pad.h:416
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pad.cpp:1594
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:2664
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:2018
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:1619
void AddPrimitive(PCB_LAYER_ID aLayer, PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
Definition: pad.cpp:2655
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:1921
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:2567
bool IsOnCopperLayer() const override
Definition: pad.cpp:1083
void SetDrillSizeX(const int aX)
Definition: pad.cpp:445
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:2632
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:1887
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
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 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:1632
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:1476
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:761
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:1716
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:2645
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
void SetDrillSizeY(const int aY)
Definition: pad.h:308
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:2001
void SetPadToDieLength(int aLength)
Definition: pad.h:452
bool IsFlipped() const
Definition: pad.cpp:326
bool operator==(const PAD &aOther) const
Definition: pad.cpp:2552
wxString ShowPadShape(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1603
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:1738
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:564
bool IsProxyItem() const override
Definition: pcb_shape.h:116
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
Definition: pcb_shape.cpp:829
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:471
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:272
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:258
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition: property.h:283
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition: property.h:345
PROPERTY_BASE & SetIsHiddenFromLibraryEditors(bool aIsHidden=true)
Definition: property.h:329
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:74
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:76
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void OverrideAvailability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override availability functor for a base class property of a given derived class.
static VALIDATOR_RESULT PositiveIntValidator(const wxAny &&aValue, EDA_ITEM *aItem)
static SEG::ecoord Square(int a)
Definition: seg.h:123
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
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
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const SHAPE_LINE_CHAIN Outline() const
Definition: shape_rect.h:212
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:42
An abstract shape on 2D plane.
Definition: shape.h:126
Simple container to manage line stroke parameters.
Definition: stroke_params.h:94
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
void TransformTrapezoidToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aDeltaX, int aDeltaY, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle or trapezoid to a polygon.
static PCB_SHAPE * findNext(PCB_SHAPE *aShape, const VECTOR2I &aPoint, const KDTree &kdTree, const PCB_SHAPE_ENDPOINTS_ADAPTOR &adaptor, unsigned aLimit)
#define _HKI(x)
const int minSize
Push and Shove router track width and via size dialog.
@ DRCE_PADSTACK
Definition: drc_item.h:62
@ DRCE_PADSTACK_INVALID
Definition: drc_item.h:63
@ DRCE_PAD_TH_WITH_NO_HOLE
Definition: drc_item.h:84
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:51
@ 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
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:767
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:184
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:790
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:665
@ 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:332
@ 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:340
@ 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:856
bool IsHoleLayer(int aLayer)
Definition: layer_ids.h:726
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition: layer_ids.h:676
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Adhes
Definition: layer_ids.h:103
@ Edge_Cuts
Definition: layer_ids.h:112
@ Dwgs_User
Definition: layer_ids.h:107
@ F_Paste
Definition: layer_ids.h:104
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ Eco1_User
Definition: layer_ids.h:109
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ F_SilkS
Definition: layer_ids.h:100
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:110
@ B_SilkS
Definition: layer_ids.h:101
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:171
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:45
FLIP_DIRECTION
Definition: mirror.h:27
Message panel definition file.
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition: eda_units.h:166
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:58
bool PadHasMeaningfulRoundingRadius(const PAD &aPad, PCB_LAYER_ID aLayer)
Returns true if the pad's rounding ratio is valid (i.e.
Definition: pad_utils.cpp:44
double GetDefaultIpcRoundingRatio(const PAD &aPad, PCB_LAYER_ID aLayer)
Get a sensible default for a rounded rectangle pad's rounding ratio.
Definition: pad_utils.cpp:27
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition: api_utils.cpp: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
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: padstack.h:52
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition: padstack.h:98
Class to handle a set of BOARD_ITEMs.
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:72
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:799
#define REGISTER_TYPE(x)
Definition: property_mgr.h:351
wxString UnescapeString(const wxString &aSource)
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
PCB_LAYER_ID start
Definition: padstack.h:247
PCB_LAYER_ID end
Definition: padstack.h:248
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition: padstack.h:245
PAD_DRILL_SHAPE shape
Definition: padstack.h:246
PAD_DESC()
Definition: pad.cpp:2728
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
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition: zones.h:36