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