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