KiCad PCB EDA Suite
footprint.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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2015 Wayne Stambaugh <[email protected]>
7 * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <core/mirror.h>
28#include <confirm.h>
29#include <refdes_utils.h>
30#include <bitmaps.h>
31#include <unordered_set>
32#include <string_utils.h>
33#include <pcb_edit_frame.h>
34#include <board.h>
36#include <fp_shape.h>
37#include <macros.h>
38#include <pad.h>
39#include <pcb_marker.h>
40#include <pcb_group.h>
41#include <pcb_track.h>
42#include <pcb_dimension.h>
43#include <footprint.h>
44#include <zone.h>
45#include <view/view.h>
46#include <i18n_utility.h>
47#include <drc/drc_item.h>
52#include "fp_textbox.h"
54
57 m_boundingBoxCacheTimeStamp( 0 ),
58 m_visibleBBoxCacheTimeStamp( 0 ),
59 m_textExcludedBBoxCacheTimeStamp( 0 ),
60 m_hullCacheTimeStamp( 0 ),
61 m_initial_comments( nullptr ),
62 m_courtyard_cache_timestamp( 0 )
63{
64 m_attributes = 0;
65 m_layer = F_Cu;
68 m_arflag = 0;
69 m_link = 0;
77
78 // These are special and mandatory text fields
81
82 m_3D_Drawings.clear();
83}
84
85
86FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
87 BOARD_ITEM_CONTAINER( aFootprint )
88{
89 m_pos = aFootprint.m_pos;
90 m_fpid = aFootprint.m_fpid;
91 m_attributes = aFootprint.m_attributes;
92 m_fpStatus = aFootprint.m_fpStatus;
93 m_orient = aFootprint.m_orient;
94 m_lastEditTime = aFootprint.m_lastEditTime;
95 m_link = aFootprint.m_link;
96 m_path = aFootprint.m_path;
97
104 m_cachedHull = aFootprint.m_cachedHull;
106
114
115 std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
116
117 // Copy reference and value.
118 m_reference = new FP_TEXT( *aFootprint.m_reference );
119 m_reference->SetParent( this );
120 ptrMap[ aFootprint.m_reference ] = m_reference;
121
122 m_value = new FP_TEXT( *aFootprint.m_value );
123 m_value->SetParent( this );
124 ptrMap[ aFootprint.m_value ] = m_value;
125
126 // Copy pads
127 for( PAD* pad : aFootprint.Pads() )
128 {
129 PAD* newPad = static_cast<PAD*>( pad->Clone() );
130 ptrMap[ pad ] = newPad;
131 Add( newPad, ADD_MODE::APPEND ); // Append to ensure indexes are identical
132 }
133
134 // Copy zones
135 for( FP_ZONE* zone : aFootprint.Zones() )
136 {
137 FP_ZONE* newZone = static_cast<FP_ZONE*>( zone->Clone() );
138 ptrMap[ zone ] = newZone;
139 Add( newZone, ADD_MODE::APPEND ); // Append to ensure indexes are identical
140
141 // Ensure the net info is OK and especially uses the net info list
142 // living in the current board
143 // Needed when copying a fp from fp editor that has its own board
144 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
145 newZone->SetNetCode( -1 );
146 }
147
148 // Copy drawings
149 for( BOARD_ITEM* item : aFootprint.GraphicalItems() )
150 {
151 BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
152 ptrMap[ item ] = newItem;
153 Add( newItem, ADD_MODE::APPEND ); // Append to ensure indexes are identical
154 }
155
156 // Copy groups
157 for( PCB_GROUP* group : aFootprint.Groups() )
158 {
159 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
160 ptrMap[ group ] = newGroup;
161 Add( newGroup, ADD_MODE::APPEND ); // Append to ensure indexes are identical
162 }
163
164 // Rebuild groups
165 for( PCB_GROUP* group : aFootprint.Groups() )
166 {
167 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( ptrMap[ group ] );
168
169 newGroup->GetItems().clear();
170
171 for( BOARD_ITEM* member : group->GetItems() )
172 {
173 if( ptrMap.count( member ) )
174 newGroup->AddItem( ptrMap[ member ] );
175 }
176 }
177
178 // Copy auxiliary data
179 m_3D_Drawings = aFootprint.m_3D_Drawings;
180 m_doc = aFootprint.m_doc;
181 m_keywords = aFootprint.m_keywords;
182 m_properties = aFootprint.m_properties;
183 m_privateLayers = aFootprint.m_privateLayers;
184
185 m_arflag = 0;
186
188 new wxArrayString( *aFootprint.m_initial_comments ) : nullptr;
189}
190
191
193 BOARD_ITEM_CONTAINER( aFootprint )
194{
195 *this = std::move( aFootprint );
196}
197
198
200{
201 // Untangle group parents before doing any deleting
202 for( PCB_GROUP* group : m_fp_groups )
203 {
204 for( BOARD_ITEM* item : group->GetItems() )
205 item->SetParentGroup( nullptr );
206 }
207
208 // Clean up the owned elements
209 delete m_reference;
210 delete m_value;
211 delete m_initial_comments;
212
213 for( PAD* p : m_pads )
214 delete p;
215
216 m_pads.clear();
217
218 for( FP_ZONE* zone : m_fp_zones )
219 delete zone;
220
221 m_fp_zones.clear();
222
223 for( PCB_GROUP* group : m_fp_groups )
224 delete group;
225
226 m_fp_groups.clear();
227
228 for( BOARD_ITEM* d : m_drawings )
229 delete d;
230
231 m_drawings.clear();
232}
233
234
236{
237 // replace null UUIDs if any by a valid uuid
238 std::vector< BOARD_ITEM* > item_list;
239
240 item_list.push_back( m_reference );
241 item_list.push_back( m_value );
242
243 for( PAD* pad : m_pads )
244 item_list.push_back( pad );
245
246 for( BOARD_ITEM* gr_item : m_drawings )
247 item_list.push_back( gr_item );
248
249 // Note: one cannot fix null UUIDs inside the group, but it should not happen
250 // because null uuids can be found in old footprints, therefore without group
251 for( PCB_GROUP* group : m_fp_groups )
252 item_list.push_back( group );
253
254 // Probably notneeded, because old fp do not have zones. But just in case.
255 for( FP_ZONE* zone : m_fp_zones )
256 item_list.push_back( zone );
257
258 bool changed = false;
259
260 for( BOARD_ITEM* item : item_list )
261 {
262 if( item->m_Uuid == niluuid )
263 {
264 const_cast<KIID&>( item->m_Uuid ) = KIID();
265 changed = true;
266 }
267 }
268
269 return changed;
270}
271
272
274{
275 BOARD_ITEM::operator=( aOther );
276
277 m_pos = aOther.m_pos;
278 m_fpid = aOther.m_fpid;
279 m_attributes = aOther.m_attributes;
280 m_fpStatus = aOther.m_fpStatus;
281 m_orient = aOther.m_orient;
282 m_lastEditTime = aOther.m_lastEditTime;
283 m_link = aOther.m_link;
284 m_path = aOther.m_path;
285
286 m_cachedBoundingBox = aOther.m_cachedBoundingBox;
287 m_boundingBoxCacheTimeStamp = aOther.m_boundingBoxCacheTimeStamp;
288 m_cachedVisibleBBox = aOther.m_cachedVisibleBBox;
289 m_visibleBBoxCacheTimeStamp = aOther.m_visibleBBoxCacheTimeStamp;
290 m_cachedTextExcludedBBox = aOther.m_cachedTextExcludedBBox;
291 m_textExcludedBBoxCacheTimeStamp = aOther.m_textExcludedBBoxCacheTimeStamp;
292 m_cachedHull = aOther.m_cachedHull;
293 m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp;
294
295 m_localClearance = aOther.m_localClearance;
296 m_localSolderMaskMargin = aOther.m_localSolderMaskMargin;
297 m_localSolderPasteMargin = aOther.m_localSolderPasteMargin;
298 m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio;
299 m_zoneConnection = aOther.m_zoneConnection;
300 m_netTiePadGroups = aOther.m_netTiePadGroups;
301
302 // Move reference and value
303 m_reference = aOther.m_reference;
304 m_reference->SetParent( this );
305 m_value = aOther.m_value;
306 m_value->SetParent( this );
307
308
309 // Move the pads
310 m_pads.clear();
311
312 for( PAD* pad : aOther.Pads() )
313 Add( pad );
314
315 aOther.Pads().clear();
316
317 // Move the zones
318 m_fp_zones.clear();
319
320 for( FP_ZONE* item : aOther.Zones() )
321 {
322 Add( item );
323
324 // Ensure the net info is OK and especially uses the net info list
325 // living in the current board
326 // Needed when copying a fp from fp editor that has its own board
327 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
328 item->SetNetCode( -1 );
329 }
330
331 aOther.Zones().clear();
332
333 // Move the drawings
334 m_drawings.clear();
335
336 for( BOARD_ITEM* item : aOther.GraphicalItems() )
337 Add( item );
338
339 aOther.GraphicalItems().clear();
340
341 // Move the groups
342 m_fp_groups.clear();
343
344 for( PCB_GROUP* group : aOther.Groups() )
345 Add( group );
346
347 aOther.Groups().clear();
348
349 // Copy auxiliary data
350 m_3D_Drawings = aOther.m_3D_Drawings;
351 m_doc = aOther.m_doc;
352 m_keywords = aOther.m_keywords;
353 m_properties = aOther.m_properties;
354 m_privateLayers = aOther.m_privateLayers;
355
356 m_initial_comments = aOther.m_initial_comments;
357
358 // Clear the other item's containers since this is a move
359 aOther.Pads().clear();
360 aOther.Zones().clear();
361 aOther.GraphicalItems().clear();
362 aOther.m_value = nullptr;
363 aOther.m_reference = nullptr;
364 aOther.m_initial_comments = nullptr;
365
366 return *this;
367}
368
369
371{
372 BOARD_ITEM::operator=( aOther );
373
374 m_pos = aOther.m_pos;
375 m_fpid = aOther.m_fpid;
376 m_attributes = aOther.m_attributes;
377 m_fpStatus = aOther.m_fpStatus;
378 m_orient = aOther.m_orient;
380 m_link = aOther.m_link;
381 m_path = aOther.m_path;
382
389 m_cachedHull = aOther.m_cachedHull;
391
398
399 // Copy reference and value
400 *m_reference = *aOther.m_reference;
401 m_reference->SetParent( this );
402 *m_value = *aOther.m_value;
403 m_value->SetParent( this );
404
405 std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
406
407 // Copy pads
408 m_pads.clear();
409
410 for( PAD* pad : aOther.Pads() )
411 {
412 PAD* newPad = new PAD( *pad );
413 ptrMap[ pad ] = newPad;
414 Add( newPad );
415 }
416
417 // Copy zones
418 m_fp_zones.clear();
419
420 for( FP_ZONE* zone : aOther.Zones() )
421 {
422 FP_ZONE* newZone = static_cast<FP_ZONE*>( zone->Clone() );
423 ptrMap[ zone ] = newZone;
424 Add( newZone );
425
426 // Ensure the net info is OK and especially uses the net info list
427 // living in the current board
428 // Needed when copying a fp from fp editor that has its own board
429 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
430 newZone->SetNetCode( -1 );
431 }
432
433 // Copy drawings
434 m_drawings.clear();
435
436 for( BOARD_ITEM* item : aOther.GraphicalItems() )
437 {
438 BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
439 ptrMap[ item ] = newItem;
440 Add( newItem );
441 }
442
443 // Copy groups
444 m_fp_groups.clear();
445
446 for( PCB_GROUP* group : aOther.Groups() )
447 {
448 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
449 newGroup->GetItems().clear();
450
451 for( BOARD_ITEM* member : group->GetItems() )
452 newGroup->AddItem( ptrMap[ member ] );
453
454 Add( newGroup );
455 }
456
457 // Copy auxiliary data
459 m_doc = aOther.m_doc;
460 m_keywords = aOther.m_keywords;
461 m_properties = aOther.m_properties;
463
465 new wxArrayString( *aOther.m_initial_comments ) : nullptr;
466
467 return *this;
468}
469
470
472{
473 return HasFlag( COURTYARD_CONFLICT );
474}
475
476
477void FOOTPRINT::GetContextualTextVars( wxArrayString* aVars ) const
478{
479 aVars->push_back( wxT( "REFERENCE" ) );
480 aVars->push_back( wxT( "VALUE" ) );
481 aVars->push_back( wxT( "LAYER" ) );
482 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
483 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
484 aVars->push_back( wxT( "NET_NAME(<pad_number>)" ) );
485 aVars->push_back( wxT( "NET_CLASS(<pad_number>)" ) );
486 aVars->push_back( wxT( "PIN_NAME(<pad_number>)" ) );
487}
488
489
490bool FOOTPRINT::ResolveTextVar( wxString* token, int aDepth ) const
491{
492 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
493 return false;
494
495 if( token->IsSameAs( wxT( "REFERENCE" ) ) )
496 {
497 *token = m_reference->GetShownText( aDepth + 1 );
498 return true;
499 }
500 else if( token->IsSameAs( wxT( "VALUE" ) ) )
501 {
502 *token = m_value->GetShownText( aDepth + 1 );
503 return true;
504 }
505 else if( token->IsSameAs( wxT( "LAYER" ) ) )
506 {
507 *token = GetLayerName();
508 return true;
509 }
510 else if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
511 {
512 *token = m_fpid.GetLibNickname();
513 return true;
514 }
515 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
516 {
517 *token = m_fpid.GetLibItemName();
518 return true;
519 }
520 else if( token->StartsWith( wxT( "NET_NAME(" ) )
521 || token->StartsWith( wxT( "NET_CLASS(" ) )
522 || token->StartsWith( wxT( "PIN_NAME(" ) ) )
523 {
524 wxString padNumber = token->AfterFirst( '(' );
525 padNumber = padNumber.BeforeLast( ')' );
526
527 for( PAD* pad : Pads() )
528 {
529 if( pad->GetNumber() == padNumber )
530 {
531 if( token->StartsWith( wxT( "NET_NAME" ) ) )
532 *token = pad->GetNetname();
533 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
534 *token = pad->GetNetClassName();
535 else
536 *token = pad->GetPinFunction();
537
538 return true;
539 }
540 }
541 }
542 else if( m_properties.count( *token ) )
543 {
544 *token = m_properties.at( *token );
545 return true;
546 }
547
548 return false;
549}
550
551
553{
554 // Force the ORPHANED dummy net info for all pads.
555 // ORPHANED dummy net does not depend on a board
556 for( PAD* pad : m_pads )
557 pad->SetNetCode( NETINFO_LIST::ORPHANED );
558}
559
560
561void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode, bool aSkipConnectivity )
562{
563 switch( aBoardItem->Type() )
564 {
565 case PCB_FP_TEXT_T:
566 // Only user text can be added this way.
567 wxASSERT( static_cast<FP_TEXT*>( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS );
569
575 case PCB_FP_SHAPE_T:
576 case PCB_FP_TEXTBOX_T:
577 case PCB_BITMAP_T:
578 if( aMode == ADD_MODE::APPEND )
579 m_drawings.push_back( aBoardItem );
580 else
581 m_drawings.push_front( aBoardItem );
582 break;
583
584 case PCB_PAD_T:
585 if( aMode == ADD_MODE::APPEND )
586 m_pads.push_back( static_cast<PAD*>( aBoardItem ) );
587 else
588 m_pads.push_front( static_cast<PAD*>( aBoardItem ) );
589 break;
590
591 case PCB_FP_ZONE_T:
592 if( aMode == ADD_MODE::APPEND )
593 m_fp_zones.push_back( static_cast<FP_ZONE*>( aBoardItem ) );
594 else
595 m_fp_zones.insert( m_fp_zones.begin(), static_cast<FP_ZONE*>( aBoardItem ) );
596 break;
597
598 case PCB_GROUP_T:
599 if( aMode == ADD_MODE::APPEND )
600 m_fp_groups.push_back( static_cast<PCB_GROUP*>( aBoardItem ) );
601 else
602 m_fp_groups.insert( m_fp_groups.begin(), static_cast<PCB_GROUP*>( aBoardItem ) );
603 break;
604
605 default:
606 {
607 wxString msg;
608 msg.Printf( wxT( "FOOTPRINT::Add() needs work: BOARD_ITEM type (%d) not handled" ),
609 aBoardItem->Type() );
610 wxFAIL_MSG( msg );
611
612 return;
613 }
614 }
615
616 aBoardItem->ClearEditFlags();
617 aBoardItem->SetParent( this );
618}
619
620
621void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode )
622{
623 switch( aBoardItem->Type() )
624 {
625 case PCB_FP_TEXT_T:
626 // Only user text can be removed this way.
627 wxCHECK_RET( static_cast<FP_TEXT*>( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS,
628 wxT( "Please report this bug: Invalid remove operation on required text" ) );
630
636 case PCB_FP_SHAPE_T:
637 case PCB_FP_TEXTBOX_T:
638 for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
639 {
640 if( *it == aBoardItem )
641 {
642 m_drawings.erase( it );
643 break;
644 }
645 }
646
647 break;
648
649 case PCB_PAD_T:
650 for( auto it = m_pads.begin(); it != m_pads.end(); ++it )
651 {
652 if( *it == static_cast<PAD*>( aBoardItem ) )
653 {
654 m_pads.erase( it );
655 break;
656 }
657 }
658
659 break;
660
661 case PCB_FP_ZONE_T:
662 for( auto it = m_fp_zones.begin(); it != m_fp_zones.end(); ++it )
663 {
664 if( *it == static_cast<FP_ZONE*>( aBoardItem ) )
665 {
666 m_fp_zones.erase( it );
667 break;
668 }
669 }
670
671 break;
672
673 case PCB_GROUP_T:
674 for( auto it = m_fp_groups.begin(); it != m_fp_groups.end(); ++it )
675 {
676 if( *it == static_cast<PCB_GROUP*>( aBoardItem ) )
677 {
678 m_fp_groups.erase( it );
679 break;
680 }
681 }
682
683 break;
684
685 default:
686 {
687 wxString msg;
688 msg.Printf( wxT( "FOOTPRINT::Remove() needs work: BOARD_ITEM type (%d) not handled" ),
689 aBoardItem->Type() );
690 wxFAIL_MSG( msg );
691 }
692 }
693
694 aBoardItem->SetFlags( STRUCT_DELETED );
695
696 PCB_GROUP* parentGroup = aBoardItem->GetParentGroup();
697
698 if( parentGroup && !( parentGroup->GetFlags() & STRUCT_DELETED ) )
699 parentGroup->RemoveItem( aBoardItem );
700}
701
702
703double FOOTPRINT::GetArea( int aPadding ) const
704{
705 BOX2I bbox = GetBoundingBox( false, false );
706
707 double w = std::abs( static_cast<double>( bbox.GetWidth() ) ) + aPadding;
708 double h = std::abs( static_cast<double>( bbox.GetHeight() ) ) + aPadding;
709 return w * h;
710}
711
712
714{
715 int smd_count = 0;
716 int tht_count = 0;
717
718 for( PAD* pad : m_pads )
719 {
720 switch( pad->GetProperty() )
721 {
724 continue;
725
728 continue;
729
730 case PAD_PROP::NONE:
731 case PAD_PROP::BGA:
733 break;
734 }
735
736 switch( pad->GetAttribute() )
737 {
738 case PAD_ATTRIB::PTH:
739 tht_count++;
740 break;
741
742 case PAD_ATTRIB::SMD:
743 smd_count++;
744 break;
745
746 default:
747 break;
748 }
749 }
750
751 if( tht_count > 0 )
752 return FP_THROUGH_HOLE;
753
754 if( smd_count > 0 )
755 return FP_SMD;
756
757 return 0;
758}
759
760
762{
763 if( ( m_attributes & FP_SMD ) == FP_SMD )
764 return _( "SMD" );
765
767 return _( "Through hole" );
768
769 return _( "Other" );
770}
771
772
774{
775 BOX2I bbox;
776
777 // We want the bounding box of the footprint pads at rot 0, not flipped
778 // Create such a image:
779 FOOTPRINT dummy( *this );
780
781 dummy.SetPosition( VECTOR2I( 0, 0 ) );
782 dummy.SetOrientation( ANGLE_0 );
783
784 if( dummy.IsFlipped() )
785 dummy.Flip( VECTOR2I( 0, 0 ), false );
786
787 for( PAD* pad : dummy.Pads() )
788 bbox.Merge( pad->GetBoundingBox() );
789
790 return bbox;
791}
792
793
795{
796 return GetBoundingBox( true, true );
797}
798
799
800const BOX2I FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const
801{
802 const BOARD* board = GetBoard();
803 bool isFPEdit = board && board->IsFootprintHolder();
804
805 if( board )
806 {
807 if( aIncludeText && aIncludeInvisibleText )
808 {
810 return m_cachedBoundingBox;
811 }
812 else if( aIncludeText )
813 {
815 return m_cachedVisibleBBox;
816 }
817 else
818 {
821 }
822 }
823
824 BOX2I bbox( m_pos );
825 bbox.Inflate( pcbIUScale.mmToIU( 0.25 ) ); // Give a min size to the bbox
826
827 for( BOARD_ITEM* item : m_drawings )
828 {
829 if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
830 continue;
831
832 // We want the bitmap bounding box just in the footprint editor
833 // so it will start with the correct initial zoom
834 if( item->Type() == PCB_BITMAP_T && !isFPEdit )
835 continue;
836
837 // Handle text separately
838 if( item->Type() == PCB_FP_TEXT_T )
839 continue;
840
841 bbox.Merge( item->GetBoundingBox() );
842 }
843
844 for( PAD* pad : m_pads )
845 bbox.Merge( pad->GetBoundingBox() );
846
847 for( FP_ZONE* zone : m_fp_zones )
848 bbox.Merge( zone->GetBoundingBox() );
849
850 bool noDrawItems = ( m_drawings.empty() && m_pads.empty() && m_fp_zones.empty() );
851
852 // Groups do not contribute to the rect, only their members
853 if( aIncludeText || noDrawItems )
854 {
855 for( BOARD_ITEM* item : m_drawings )
856 {
857 if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) )
858 continue;
859
860 // Only FP_TEXT items are independently selectable; FP_TEXTBOX items go in with
861 // other graphic items above.
862 if( item->Type() == PCB_FP_TEXT_T )
863 bbox.Merge( item->GetBoundingBox() );
864 }
865
866 // This can be further optimized when aIncludeInvisibleText is true, but currently
867 // leaving this as is until it's determined there is a noticeable speed hit.
868 bool valueLayerIsVisible = true;
869 bool refLayerIsVisible = true;
870
871 if( board )
872 {
873 // The first "&&" conditional handles the user turning layers off as well as layers
874 // not being present in the current PCB stackup. Values, references, and all
875 // footprint text can also be turned off via the GAL meta-layers, so the 2nd and
876 // 3rd "&&" conditionals handle that.
877 valueLayerIsVisible = board->IsLayerVisible( m_value->GetLayer() )
879 && board->IsElementVisible( LAYER_MOD_TEXT );
880
881 refLayerIsVisible = board->IsLayerVisible( m_reference->GetLayer() )
883 && board->IsElementVisible( LAYER_MOD_TEXT );
884 }
885
886
887 if( ( m_value->IsVisible() && valueLayerIsVisible )
888 || aIncludeInvisibleText
889 || noDrawItems )
890 {
891 bbox.Merge( m_value->GetBoundingBox() );
892 }
893
894 if( ( m_reference->IsVisible() && refLayerIsVisible )
895 || aIncludeInvisibleText
896 || noDrawItems )
897 {
899 }
900 }
901
902 if( board )
903 {
904 if( ( aIncludeText && aIncludeInvisibleText ) || noDrawItems )
905 {
907 m_cachedBoundingBox = bbox;
908 }
909 else if( aIncludeText )
910 {
912 m_cachedVisibleBBox = bbox;
913 }
914 else
915 {
918 }
919 }
920
921 return bbox;
922}
923
924
926{
927 const BOARD* board = GetBoard();
928 bool isFPEdit = board && board->IsFootprintHolder();
929
930 if( board )
931 {
932 if( m_hullCacheTimeStamp >= board->GetTimeStamp() )
933 return m_cachedHull;
934 }
935
936 SHAPE_POLY_SET rawPolys;
937 SHAPE_POLY_SET hull;
938
939 for( BOARD_ITEM* item : m_drawings )
940 {
941 if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) )
942 continue;
943
944 if( item->Type() != PCB_FP_TEXT_T && item->Type() != PCB_BITMAP_T )
945 {
946 item->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
948 }
949
950 // We intentionally exclude footprint text from the bounding hull.
951 }
952
953 for( PAD* pad : m_pads )
954 {
955 pad->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
956 // In case hole is larger than pad
957 pad->TransformHoleToPolygon( rawPolys, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
958 }
959
960 for( FP_ZONE* zone : m_fp_zones )
961 {
962 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
963 {
964 const SHAPE_POLY_SET& layerPoly = *zone->GetFilledPolysList( layer );
965
966 for( int ii = 0; ii < layerPoly.OutlineCount(); ii++ )
967 {
968 const SHAPE_LINE_CHAIN& poly = layerPoly.COutline( ii );
969 rawPolys.AddOutline( poly );
970 }
971 }
972 }
973
974 // If there are some graphic items, build the actual hull.
975 // However if no items, create a minimal polygon (can happen if a footprint
976 // is created with no item: it contains only 2 texts.
977 if( rawPolys.OutlineCount() == 0 )
978 {
979 // generate a small dummy rectangular outline around the anchor
980 const int halfsize = pcbIUScale.mmToIU( 1.0 );
981
982 rawPolys.NewOutline();
983
984 // add a square:
985 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y - halfsize );
986 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y - halfsize );
987 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y + halfsize );
988 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y + halfsize );
989 }
990
991 std::vector<VECTOR2I> convex_hull;
992 BuildConvexHull( convex_hull, rawPolys );
993
996
997 for( const VECTOR2I& pt : convex_hull )
998 m_cachedHull.Append( pt );
999
1000 if( board )
1002
1003 return m_cachedHull;
1004}
1005
1006
1007void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1008{
1009 wxString msg, msg2;
1010
1011 aList.emplace_back( m_reference->GetShownText(), m_value->GetShownText() );
1012
1013 if( aFrame->IsType( FRAME_FOOTPRINT_VIEWER )
1015 || aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
1016 {
1017 wxDateTime date( static_cast<time_t>( m_lastEditTime ) );
1018
1019 // Date format: see http://www.cplusplus.com/reference/ctime/strftime
1020 if( m_lastEditTime && date.IsValid() )
1021 msg = date.Format( wxT( "%b %d, %Y" ) ); // Abbreviated_month_name Day, Year
1022 else
1023 msg = _( "Unknown" );
1024
1025 aList.emplace_back( _( "Last Change" ), msg );
1026 }
1027 else if( aFrame->IsType( FRAME_PCB_EDITOR ) )
1028 {
1029 aList.emplace_back( _( "Board Side" ), IsFlipped() ? _( "Back (Flipped)" ) : _( "Front" ) );
1030 }
1031
1032 auto addToken = []( wxString* aStr, const wxString& aAttr )
1033 {
1034 if( !aStr->IsEmpty() )
1035 *aStr += wxT( ", " );
1036
1037 *aStr += aAttr;
1038 };
1039
1040 wxString status;
1041 wxString attrs;
1042
1043 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
1044 addToken( &status, _( "Locked" ) );
1045
1046 if( m_fpStatus & FP_is_PLACED )
1047 addToken( &status, _( "autoplaced" ) );
1048
1050 addToken( &attrs, _( "not in schematic" ) );
1051
1053 addToken( &attrs, _( "exclude from pos files" ) );
1054
1056 addToken( &attrs, _( "exclude from BOM" ) );
1057
1058 aList.emplace_back( _( "Status: " ) + status, _( "Attributes:" ) + wxS( " " ) + attrs );
1059
1060 aList.emplace_back( _( "Rotation" ), wxString::Format( wxT( "%.4g" ),
1061 GetOrientation().AsDegrees() ) );
1062
1063 msg.Printf( _( "Footprint: %s" ), m_fpid.GetUniStringLibId() );
1064 msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
1065 : m_3D_Drawings.front().m_Filename );
1066 aList.emplace_back( msg, msg2 );
1067
1068 msg.Printf( _( "Doc: %s" ), m_doc );
1069 msg2.Printf( _( "Keywords: %s" ), m_keywords );
1070 aList.emplace_back( msg, msg2 );
1071}
1072
1073
1075{
1076 // If we have any pads, fall back on normal checking
1077 if( !m_pads.empty() )
1078 return m_layer == aLayer;
1079
1080 // No pads? Check if this entire footprint exists on the given layer
1081 for( FP_ZONE* zone : m_fp_zones )
1082 {
1083 if( !zone->IsOnLayer( aLayer ) )
1084 return false;
1085 }
1086
1087 for( BOARD_ITEM* item : m_drawings )
1088 {
1089 if( !item->IsOnLayer( aLayer ) )
1090 return false;
1091 }
1092
1093 return true;
1094}
1095
1096
1097bool FOOTPRINT::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
1098{
1099 BOX2I rect = GetBoundingBox( false, false );
1100 return rect.Inflate( aAccuracy ).Contains( aPosition );
1101}
1102
1103
1104bool FOOTPRINT::HitTestAccurate( const VECTOR2I& aPosition, int aAccuracy ) const
1105{
1106 return GetBoundingHull().Collide( aPosition, aAccuracy );
1107}
1108
1109
1110bool FOOTPRINT::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1111{
1112 BOX2I arect = aRect;
1113 arect.Inflate( aAccuracy );
1114
1115 if( aContained )
1116 {
1117 return arect.Contains( GetBoundingBox( false, false ) );
1118 }
1119 else
1120 {
1121 // If the rect does not intersect the bounding box, skip any tests
1122 if( !aRect.Intersects( GetBoundingBox( false, false ) ) )
1123 return false;
1124
1125 // The empty footprint dummy rectangle intersects the selection area.
1126 if( m_pads.empty() && m_fp_zones.empty() && m_drawings.empty() )
1127 return GetBoundingBox( true, false ).Intersects( arect );
1128
1129 // Determine if any elements in the FOOTPRINT intersect the rect
1130 for( PAD* pad : m_pads )
1131 {
1132 if( pad->HitTest( arect, false, 0 ) )
1133 return true;
1134 }
1135
1136 for( FP_ZONE* zone : m_fp_zones )
1137 {
1138 if( zone->HitTest( arect, false, 0 ) )
1139 return true;
1140 }
1141
1142 for( BOARD_ITEM* item : m_drawings )
1143 {
1144 // Text items are selectable on their own, and are therefore excluded from this
1145 // test. TextBox items are NOT selectable on their own, and so MUST be included
1146 // here. Bitmaps aren't selectable since they aren't displayed.
1147 if( item->Type() != PCB_FP_TEXT_T && item->Type() != PCB_FP_TEXT_T
1148 && item->HitTest( arect, false, 0 ) )
1149 {
1150 return true;
1151 }
1152 }
1153
1154 // Groups are not hit-tested; only their members
1155
1156 // No items were hit
1157 return false;
1158 }
1159}
1160
1161
1162PAD* FOOTPRINT::FindPadByNumber( const wxString& aPadNumber, PAD* aSearchAfterMe ) const
1163{
1164 bool can_select = aSearchAfterMe ? false : true;
1165
1166 for( PAD* pad : m_pads )
1167 {
1168 if( !can_select && pad == aSearchAfterMe )
1169 {
1170 can_select = true;
1171 continue;
1172 }
1173
1174 if( can_select && pad->GetNumber() == aPadNumber )
1175 return pad;
1176 }
1177
1178 return nullptr;
1179}
1180
1181
1182PAD* FOOTPRINT::GetPad( const VECTOR2I& aPosition, LSET aLayerMask )
1183{
1184 for( PAD* pad : m_pads )
1185 {
1186 // ... and on the correct layer.
1187 if( !( pad->GetLayerSet() & aLayerMask ).any() )
1188 continue;
1189
1190 if( pad->HitTest( aPosition ) )
1191 return pad;
1192 }
1193
1194 return nullptr;
1195}
1196
1197
1198unsigned FOOTPRINT::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1199{
1200 if( aIncludeNPTH )
1201 return m_pads.size();
1202
1203 unsigned cnt = 0;
1204
1205 for( PAD* pad : m_pads )
1206 {
1207 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1208 continue;
1209
1210 cnt++;
1211 }
1212
1213 return cnt;
1214}
1215
1216
1217unsigned FOOTPRINT::GetUniquePadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1218{
1219 std::set<wxString> usedNumbers;
1220
1221 // Create a set of used pad numbers
1222 for( PAD* pad : m_pads )
1223 {
1224 // Skip pads not on copper layers (used to build complex
1225 // solder paste shapes for instance)
1226 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none() )
1227 continue;
1228
1229 // Skip pads with no name, because they are usually "mechanical"
1230 // pads, not "electrical" pads
1231 if( pad->GetNumber().IsEmpty() )
1232 continue;
1233
1234 if( !aIncludeNPTH )
1235 {
1236 // skip NPTH
1237 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1238 continue;
1239 }
1240
1241 usedNumbers.insert( pad->GetNumber() );
1242 }
1243
1244 return usedNumbers.size();
1245}
1246
1247
1249{
1250 if( nullptr == a3DModel )
1251 return;
1252
1253 if( !a3DModel->m_Filename.empty() )
1254 m_3D_Drawings.push_back( *a3DModel );
1255}
1256
1257
1258// see footprint.h
1259INSPECT_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData,
1260 const std::vector<KICAD_T>& aScanTypes )
1261{
1262#if 0 && defined(DEBUG)
1263 std::cout << GetClass().mb_str() << ' ';
1264#endif
1265
1266 bool drawingsScanned = false;
1267
1268 for( KICAD_T scanType : aScanTypes )
1269 {
1270 switch( scanType )
1271 {
1272 case PCB_FOOTPRINT_T:
1273 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
1274 return INSPECT_RESULT::QUIT;
1275
1276 break;
1277
1278 case PCB_PAD_T:
1279 if( IterateForward<PAD*>( m_pads, inspector, testData, { scanType } )
1281 {
1282 return INSPECT_RESULT::QUIT;
1283 }
1284
1285 break;
1286
1287 case PCB_FP_ZONE_T:
1288 if( IterateForward<FP_ZONE*>( m_fp_zones, inspector, testData, { scanType } )
1290 {
1291 return INSPECT_RESULT::QUIT;
1292 }
1293
1294 break;
1295
1296 case PCB_FP_TEXT_T:
1297 if( inspector( m_reference, testData ) == INSPECT_RESULT::QUIT )
1298 return INSPECT_RESULT::QUIT;
1299
1300 if( inspector( m_value, testData ) == INSPECT_RESULT::QUIT )
1301 return INSPECT_RESULT::QUIT;
1302
1303 // Intentionally fall through since m_Drawings can hold PCB_FP_TEXT_T also
1305
1311 case PCB_FP_SHAPE_T:
1312 case PCB_FP_TEXTBOX_T:
1313 if( !drawingsScanned )
1314 {
1315 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, aScanTypes )
1317 {
1318 return INSPECT_RESULT::QUIT;
1319 }
1320
1321 drawingsScanned = true;
1322 }
1323
1324 break;
1325
1326 case PCB_GROUP_T:
1327 if( IterateForward<PCB_GROUP*>( m_fp_groups, inspector, testData, { scanType } )
1329 {
1330 return INSPECT_RESULT::QUIT;
1331 }
1332
1333 break;
1334
1335 default:
1336 break;
1337 }
1338 }
1339
1341}
1342
1343
1344wxString FOOTPRINT::GetSelectMenuText( UNITS_PROVIDER* aUnitsProvider ) const
1345{
1346 wxString reference = GetReference();
1347
1348 if( reference.IsEmpty() )
1349 reference = _( "<no reference designator>" );
1350
1351 return wxString::Format( _( "Footprint %s" ), reference );
1352}
1353
1354
1356{
1357 return BITMAPS::module;
1358}
1359
1360
1362{
1363 return new FOOTPRINT( *this );
1364}
1365
1366
1367void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM*)>& aFunction ) const
1368{
1369 try
1370 {
1371 for( PAD* pad : m_pads )
1372 aFunction( static_cast<BOARD_ITEM*>( pad ) );
1373
1374 for( FP_ZONE* zone : m_fp_zones )
1375 aFunction( static_cast<FP_ZONE*>( zone ) );
1376
1377 for( PCB_GROUP* group : m_fp_groups )
1378 aFunction( static_cast<PCB_GROUP*>( group ) );
1379
1380 for( BOARD_ITEM* drawing : m_drawings )
1381 aFunction( static_cast<BOARD_ITEM*>( drawing ) );
1382
1383 aFunction( static_cast<BOARD_ITEM*>( m_reference ) );
1384 aFunction( static_cast<BOARD_ITEM*>( m_value ) );
1385 }
1386 catch( std::bad_function_call& )
1387 {
1388 wxFAIL_MSG( wxT( "Error running FOOTPRINT::RunOnChildren" ) );
1389 }
1390}
1391
1392
1393void FOOTPRINT::ViewGetLayers( int aLayers[], int& aCount ) const
1394{
1395 aCount = 2;
1396 aLayers[0] = LAYER_ANCHOR;
1397
1398 switch( m_layer )
1399 {
1400 default:
1401 wxASSERT_MSG( false, wxT( "Illegal layer" ) ); // do you really have footprints placed
1402 // on other layers?
1404
1405 case F_Cu:
1406 aLayers[1] = LAYER_MOD_FR;
1407 break;
1408
1409 case B_Cu:
1410 aLayers[1] = LAYER_MOD_BK;
1411 break;
1412 }
1413
1414 if( IsLocked() )
1415 aLayers[ aCount++ ] = LAYER_LOCKED_ITEM_SHADOW;
1416
1417 if( IsConflicting() )
1418 aLayers[ aCount++ ] = LAYER_CONFLICTS_SHADOW;
1419
1420 // If there are no pads, and only drawings on a silkscreen layer, then report the silkscreen
1421 // layer as well so that the component can be edited with the silkscreen layer
1422 bool f_silk = false, b_silk = false, non_silk = false;
1423
1424 for( BOARD_ITEM* item : m_drawings )
1425 {
1426 if( item->GetLayer() == F_SilkS )
1427 f_silk = true;
1428 else if( item->GetLayer() == B_SilkS )
1429 b_silk = true;
1430 else
1431 non_silk = true;
1432 }
1433
1434 if( ( f_silk || b_silk ) && !non_silk && m_pads.empty() )
1435 {
1436 if( f_silk )
1437 aLayers[ aCount++ ] = F_SilkS;
1438
1439 if( b_silk )
1440 aLayers[ aCount++ ] = B_SilkS;
1441 }
1442}
1443
1444
1445double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1446{
1447 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
1448 {
1449 // The locked shadow shape is shown only if the footprint itself is visible
1450 if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_MOD_FR ) )
1451 return 0.0;
1452
1453 if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_MOD_BK ) )
1454 return 0.0;
1455
1456 return std::numeric_limits<double>::max();
1457 }
1458
1459 if( aLayer == LAYER_CONFLICTS_SHADOW && IsConflicting() )
1460 {
1461 // The locked shadow shape is shown only if the footprint itself is visible
1462 if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_MOD_FR ) )
1463 return 0.0;
1464
1465 if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_MOD_BK ) )
1466 return 0.0;
1467
1468 return std::numeric_limits<double>::max();
1469 }
1470
1471 int layer = ( m_layer == F_Cu ) ? LAYER_MOD_FR :
1473
1474 // Currently this is only pertinent for the anchor layer; everything else is drawn from the
1475 // children.
1476 // The "good" value is experimentally chosen.
1477 #define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY 1.5
1478
1479 if( aView->IsLayerVisible( layer ) )
1481
1482 return std::numeric_limits<double>::max();
1483}
1484
1485
1487{
1488 BOX2I area = GetBoundingBox( true, true );
1489
1490 // Add the Clearance shape size: (shape around the pads when the clearance is shown. Not
1491 // optimized, but the draw cost is small (perhaps smaller than optimization).
1492 const BOARD* board = GetBoard();
1493
1494 if( board )
1495 {
1496 int biggest_clearance = board->GetDesignSettings().GetBiggestClearanceValue();
1497 area.Inflate( biggest_clearance );
1498 }
1499
1500 return area;
1501}
1502
1503
1504bool FOOTPRINT::IsLibNameValid( const wxString & aName )
1505{
1506 const wxChar * invalids = StringLibNameInvalidChars( false );
1507
1508 if( aName.find_first_of( invalids ) != std::string::npos )
1509 return false;
1510
1511 return true;
1512}
1513
1514
1515const wxChar* FOOTPRINT::StringLibNameInvalidChars( bool aUserReadable )
1516{
1517 // This list of characters is also duplicated in validators.cpp and
1518 // lib_id.cpp
1519 // TODO: Unify forbidden character lists - Warning, invalid filename characters are not the same
1520 // as invalid LIB_ID characters. We will need to separate the FP filenames from FP names before this
1521 // can be unified
1522 static const wxChar invalidChars[] = wxT("%$<>\t\n\r\"\\/:");
1523 static const wxChar invalidCharsReadable[] = wxT("% $ < > 'tab' 'return' 'line feed' \\ \" / :");
1524
1525 if( aUserReadable )
1526 return invalidCharsReadable;
1527 else
1528 return invalidChars;
1529}
1530
1531
1532void FOOTPRINT::Move( const VECTOR2I& aMoveVector )
1533{
1534 VECTOR2I newpos = m_pos + aMoveVector;
1535 SetPosition( newpos );
1536}
1537
1538
1539void FOOTPRINT::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1540{
1541 EDA_ANGLE orientation = GetOrientation();
1542 EDA_ANGLE newOrientation = orientation + aAngle;
1543 VECTOR2I newpos = m_pos;
1544 RotatePoint( newpos, aRotCentre, aAngle );
1545 SetPosition( newpos );
1546 SetOrientation( newOrientation );
1547
1548 m_reference->KeepUpright( orientation, newOrientation );
1549 m_value->KeepUpright( orientation, newOrientation );
1550
1551 for( BOARD_ITEM* item : m_drawings )
1552 {
1553 if( item->Type() == PCB_FP_TEXT_T )
1554 static_cast<FP_TEXT*>( item )->KeepUpright( orientation, newOrientation );
1555 }
1556
1562}
1563
1564
1566{
1567 wxASSERT( aLayer == F_Cu || aLayer == B_Cu );
1568
1569 if( aLayer != GetLayer() )
1570 Flip( GetPosition(), true );
1571}
1572
1573
1574void FOOTPRINT::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
1575{
1576 // Move footprint to its final position:
1577 VECTOR2I finalPos = m_pos;
1578
1579 // Now Flip the footprint.
1580 // Flipping a footprint is a specific transform: it is not mirrored like a text.
1581 // We have to change the side, and ensure the footprint rotation is modified according to the
1582 // transform, because this parameter is used in pick and place files, and when updating the
1583 // footprint from library.
1584 // When flipped around the X axis (Y coordinates changed) orientation is negated
1585 // When flipped around the Y axis (X coordinates changed) orientation is 180 - old orient.
1586 // Because it is specific to a footprint, we flip around the X axis, and after rotate 180 deg
1587
1588 MIRROR( finalPos.y, aCentre.y );
1589
1590 SetPosition( finalPos );
1591
1592 // Flip layer
1594
1595 // Reverse mirror orientation.
1596 m_orient = -m_orient;
1598
1599 // Mirror pads to other side of board.
1600 for( PAD* pad : m_pads )
1601 pad->Flip( m_pos, false );
1602
1603 // Mirror zones to other side of board.
1604 for( ZONE* zone : m_fp_zones )
1605 zone->Flip( m_pos, false );
1606
1607 // Mirror reference and value.
1608 m_reference->Flip( m_pos, false );
1609 m_value->Flip( m_pos, false );
1610
1611 // Reverse mirror footprint graphics and texts.
1612 for( BOARD_ITEM* item : m_drawings )
1613 {
1614 switch( item->Type() )
1615 {
1616 case PCB_FP_SHAPE_T:
1617 static_cast<FP_SHAPE*>( item )->Flip( m_pos, false );
1618 break;
1619
1620 case PCB_FP_TEXT_T:
1621 static_cast<FP_TEXT*>( item )->Flip( m_pos, false );
1622 break;
1623
1624 case PCB_FP_TEXTBOX_T:
1625 static_cast<FP_TEXTBOX*>( item )->Flip( m_pos, false );
1626 break;
1627
1633 static_cast<PCB_DIMENSION_BASE*>( item )->Flip( m_pos, false );
1634 break;
1635
1636 default:
1637 wxMessageBox( wxString::Format( wxT( "FOOTPRINT::Flip() error: Unknown Draw Type %d" ),
1638 (int)item->Type() ) );
1639 break;
1640 }
1641 }
1642
1643 // Now rotate 180 deg if required
1644 if( aFlipLeftRight )
1645 Rotate( aCentre, ANGLE_180 );
1646
1651
1652 m_cachedHull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos );
1653
1655}
1656
1657
1659{
1660 VECTOR2I delta = aPos - m_pos;
1661
1662 m_pos += delta;
1663
1664 m_reference->EDA_TEXT::Offset( delta );
1665 m_value->EDA_TEXT::Offset( delta );
1666
1667 for( PAD* pad : m_pads )
1668 pad->SetPosition( pad->GetPosition() + delta );
1669
1670 for( ZONE* zone : m_fp_zones )
1671 zone->Move( delta );
1672
1673 for( BOARD_ITEM* item : m_drawings )
1674 {
1675 switch( item->Type() )
1676 {
1677 case PCB_FP_SHAPE_T:
1678 case PCB_FP_TEXTBOX_T:
1679 {
1680 FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1681 shape->SetDrawCoord();
1682 break;
1683 }
1684
1685 case PCB_FP_TEXT_T:
1686 {
1687 FP_TEXT* text = static_cast<FP_TEXT*>( item );
1688 text->EDA_TEXT::Offset( delta );
1689 break;
1690 }
1691
1697 case PCB_BITMAP_T:
1698 item->Move( delta );
1699 break;
1700
1701 default:
1702 wxMessageBox( wxT( "Draw type undefined." ) );
1703 break;
1704 }
1705 }
1706
1713}
1714
1715
1716void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector )
1717{
1718 /*
1719 * Move the reference point of the footprint
1720 * the footprints elements (pads, outlines, edges .. ) are moved
1721 * but:
1722 * - the footprint position is not modified.
1723 * - the relative (local) coordinates of these items are modified
1724 * - Draw coordinates are updated
1725 */
1726
1727 // Update (move) the relative coordinates relative to the new anchor point.
1728 VECTOR2I moveVector = aMoveVector;
1729 RotatePoint( moveVector, -GetOrientation() );
1730
1731 // Update of the reference and value.
1732 m_reference->SetPos0( m_reference->GetPos0() + moveVector );
1734 m_value->SetPos0( m_value->GetPos0() + moveVector );
1736
1737 // Update the pad local coordinates.
1738 for( PAD* pad : m_pads )
1739 {
1740 pad->SetPos0( pad->GetPos0() + moveVector );
1741 pad->SetDrawCoord();
1742 }
1743
1744 // Update the draw element coordinates.
1745 for( BOARD_ITEM* item : GraphicalItems() )
1746 {
1747 switch( item->Type() )
1748 {
1749 case PCB_FP_SHAPE_T:
1750 case PCB_FP_TEXTBOX_T:
1751 {
1752 FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1753 shape->Move( moveVector );
1754 break;
1755 }
1756
1757 case PCB_FP_TEXT_T:
1758 {
1759 FP_TEXT* text = static_cast<FP_TEXT*>( item );
1760 text->SetPos0( text->GetPos0() + moveVector );
1761 text->SetDrawCoord();
1762 break;
1763 }
1764
1765 default:
1766 break;
1767 }
1768 }
1769
1770 // Update the keepout zones
1771 for( ZONE* zone : Zones() )
1772 {
1773 zone->Move( moveVector );
1774 }
1775
1776 // Update the 3D models
1777 for( FP_3DMODEL& model : Models() )
1778 {
1779 model.m_Offset.x += pcbIUScale.IUTomm( moveVector.x );
1780 model.m_Offset.y -= pcbIUScale.IUTomm( moveVector.y );
1781 }
1782
1783 m_cachedBoundingBox.Move( moveVector );
1784 m_cachedVisibleBBox.Move( moveVector );
1785 m_cachedTextExcludedBBox.Move( moveVector );
1786 m_cachedHull.Move( moveVector );
1787}
1788
1789
1790void FOOTPRINT::SetOrientation( const EDA_ANGLE& aNewAngle )
1791{
1792 EDA_ANGLE angleChange = aNewAngle - m_orient; // change in rotation
1793
1794 m_orient = aNewAngle;
1796
1797 for( PAD* pad : m_pads )
1798 {
1799 pad->SetOrientation( pad->GetOrientation() + angleChange );
1800 pad->SetDrawCoord();
1801 }
1802
1803 for( ZONE* zone : m_fp_zones )
1804 zone->Rotate( GetPosition(), angleChange );
1805
1806 for( BOARD_ITEM* item : m_drawings )
1807 {
1808 if( PCB_DIMENSION_BASE* dimension = dynamic_cast<PCB_DIMENSION_BASE*>( item ) )
1809 dimension->Rotate( GetPosition(), angleChange );
1810 }
1811
1812 // Update of the reference and value.
1815
1816 // Displace contours and text of the footprint.
1817 for( BOARD_ITEM* item : m_drawings )
1818 {
1819 switch( item->Type() )
1820 {
1821 case PCB_FP_SHAPE_T:
1822 case PCB_FP_TEXTBOX_T:
1823 static_cast<FP_SHAPE*>( item )->SetDrawCoord();
1824 break;
1825
1826 case PCB_FP_TEXT_T:
1827 static_cast<FP_TEXT*>( item )->SetDrawCoord();
1828 break;
1829
1830 default:
1831 break;
1832 }
1833 }
1834
1839
1840 m_cachedHull.Rotate( angleChange, GetPosition() );
1841}
1842
1843
1845{
1846 FOOTPRINT* dupe = static_cast<FOOTPRINT*>( BOARD_ITEM::Duplicate() );
1847
1848 dupe->RunOnChildren( [&]( BOARD_ITEM* child )
1849 {
1850 const_cast<KIID&>( child->m_Uuid ) = KIID();
1851 });
1852
1853 return dupe;
1854}
1855
1856
1857BOARD_ITEM* FOOTPRINT::DuplicateItem( const BOARD_ITEM* aItem, bool aAddToFootprint )
1858{
1859 BOARD_ITEM* new_item = nullptr;
1860 FP_ZONE* new_zone = nullptr;
1861
1862 switch( aItem->Type() )
1863 {
1864 case PCB_PAD_T:
1865 {
1866 PAD* new_pad = new PAD( *static_cast<const PAD*>( aItem ) );
1867 const_cast<KIID&>( new_pad->m_Uuid ) = KIID();
1868
1869 if( aAddToFootprint )
1870 m_pads.push_back( new_pad );
1871
1872 new_item = new_pad;
1873 break;
1874 }
1875
1876 case PCB_FP_ZONE_T:
1877 {
1878 new_zone = new FP_ZONE( *static_cast<const FP_ZONE*>( aItem ) );
1879 const_cast<KIID&>( new_zone->m_Uuid ) = KIID();
1880
1881 if( aAddToFootprint )
1882 m_fp_zones.push_back( new_zone );
1883
1884 new_item = new_zone;
1885 break;
1886 }
1887
1888 case PCB_FP_TEXT_T:
1889 {
1890 FP_TEXT* new_text = new FP_TEXT( *static_cast<const FP_TEXT*>( aItem ) );
1891 const_cast<KIID&>( new_text->m_Uuid ) = KIID();
1892
1893 if( new_text->GetType() == FP_TEXT::TEXT_is_REFERENCE )
1894 {
1895 new_text->SetText( wxT( "${REFERENCE}" ) );
1896 new_text->SetType( FP_TEXT::TEXT_is_DIVERS );
1897 }
1898 else if( new_text->GetType() == FP_TEXT::TEXT_is_VALUE )
1899 {
1900 new_text->SetText( wxT( "${VALUE}" ) );
1901 new_text->SetType( FP_TEXT::TEXT_is_DIVERS );
1902 }
1903
1904 if( aAddToFootprint )
1905 Add( new_text );
1906
1907 new_item = new_text;
1908
1909 break;
1910 }
1911
1912 case PCB_FP_SHAPE_T:
1913 {
1914 FP_SHAPE* new_shape = new FP_SHAPE( *static_cast<const FP_SHAPE*>( aItem ) );
1915 const_cast<KIID&>( new_shape->m_Uuid ) = KIID();
1916
1917 if( aAddToFootprint )
1918 Add( new_shape );
1919
1920 new_item = new_shape;
1921 break;
1922 }
1923
1924 case PCB_FP_TEXTBOX_T:
1925 {
1926 FP_TEXTBOX* new_textbox = new FP_TEXTBOX( *static_cast<const FP_TEXTBOX*>( aItem ) );
1927 const_cast<KIID&>( new_textbox->m_Uuid ) = KIID();
1928
1929 if( aAddToFootprint )
1930 Add( new_textbox );
1931
1932 new_item = new_textbox;
1933 break;
1934 }
1935
1941 {
1942 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( aItem->Duplicate() );
1943
1944 if( aAddToFootprint )
1945 Add( dimension );
1946
1947 new_item = dimension;
1948 break;
1949 }
1950
1951 case PCB_GROUP_T:
1952 new_item = static_cast<const PCB_GROUP*>( aItem )->DeepDuplicate();
1953 break;
1954
1955 case PCB_FOOTPRINT_T:
1956 // Ignore the footprint itself
1957 break;
1958
1959 default:
1960 // Un-handled item for duplication
1961 wxFAIL_MSG( wxT( "Duplication not supported for items of class " ) + aItem->GetClass() );
1962 break;
1963 }
1964
1965 return new_item;
1966}
1967
1968
1969wxString FOOTPRINT::GetNextPadNumber( const wxString& aLastPadNumber ) const
1970{
1971 std::set<wxString> usedNumbers;
1972
1973 // Create a set of used pad numbers
1974 for( PAD* pad : m_pads )
1975 usedNumbers.insert( pad->GetNumber() );
1976
1977 // Pad numbers aren't technically reference designators, but the formatting is close enough
1978 // for these to give us what we need.
1979 wxString prefix = UTIL::GetRefDesPrefix( aLastPadNumber );
1980 int num = GetTrailingInt( aLastPadNumber );
1981
1982 while( usedNumbers.count( wxString::Format( wxT( "%s%d" ), prefix, num ) ) )
1983 num++;
1984
1985 return wxString::Format( wxT( "%s%d" ), prefix, num );
1986}
1987
1988
1990{
1991 const wxString& refdes = GetReference();
1992
1993 SetReference( wxString::Format( wxT( "%s%i" ),
1994 UTIL::GetRefDesPrefix( refdes ),
1995 GetTrailingInt( refdes ) + aDelta ) );
1996}
1997
1998
1999// Calculate the area of a PolySet, polygons with hole are allowed.
2000static double polygonArea( SHAPE_POLY_SET& aPolySet )
2001{
2002 // Ensure all outlines are closed, before calculating the SHAPE_POLY_SET area
2003 for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
2004 {
2005 SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
2006 outline.SetClosed( true );
2007
2008 for( int jj = 0; jj < aPolySet.HoleCount( ii ); jj++ )
2009 aPolySet.Hole( ii, jj ).SetClosed( true );
2010 }
2011
2012 return aPolySet.Area();
2013}
2014
2015
2016double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLECTOR& aCollector )
2017{
2018 int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
2019 SHAPE_POLY_SET poly;
2020
2021 if( aItem->Type() == PCB_MARKER_T )
2022 {
2023 const PCB_MARKER* marker = static_cast<const PCB_MARKER*>( aItem );
2024 SHAPE_LINE_CHAIN markerShape;
2025
2026 marker->ShapeToPolygon( markerShape );
2027 return markerShape.Area();
2028 }
2029 else if( aItem->Type() == PCB_GROUP_T )
2030 {
2031 double combinedArea = 0.0;
2032
2033 for( BOARD_ITEM* member : static_cast<const PCB_GROUP*>( aItem )->GetItems() )
2034 combinedArea += GetCoverageArea( member, aCollector );
2035
2036 return combinedArea;
2037 }
2038 if( aItem->Type() == PCB_FOOTPRINT_T )
2039 {
2040 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
2041
2042 poly = footprint->GetBoundingHull();
2043 }
2044 else if( aItem->Type() == PCB_FP_TEXT_T )
2045 {
2046 const FP_TEXT* text = static_cast<const FP_TEXT*>( aItem );
2047
2048 text->TransformTextToPolySet( poly, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE );
2049 }
2050 else if( aItem->Type() == PCB_FP_TEXTBOX_T )
2051 {
2052 const FP_TEXTBOX* tb = static_cast<const FP_TEXTBOX*>( aItem );
2053
2055 }
2056 else if( aItem->Type() == PCB_SHAPE_T )
2057 {
2058 // Approximate "linear" shapes with just their width squared, as we don't want to consider
2059 // a linear shape as being much bigger than another for purposes of selection filtering
2060 // just because it happens to be really long.
2061
2062 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
2063
2064 switch( shape->GetShape() )
2065 {
2066 case SHAPE_T::SEGMENT:
2067 case SHAPE_T::ARC:
2068 case SHAPE_T::BEZIER:
2069 return shape->GetWidth() * shape->GetWidth();
2070
2071 case SHAPE_T::RECT:
2072 case SHAPE_T::CIRCLE:
2073 case SHAPE_T::POLY:
2074 {
2075 if( !shape->IsFilled() )
2076 return shape->GetWidth() * shape->GetWidth();
2077
2079 }
2080
2081 default:
2083 }
2084 }
2085 else if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2086 {
2087 double width = static_cast<const PCB_TRACK*>( aItem )->GetWidth();
2088 return width * width;
2089 }
2090 else
2091 {
2093 }
2094
2095 return polygonArea( poly );
2096}
2097
2098
2099double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
2100{
2101 int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
2102
2103 SHAPE_POLY_SET footprintRegion( GetBoundingHull() );
2104 SHAPE_POLY_SET coveredRegion;
2105
2107
2108 TransformFPShapesToPolySet( coveredRegion, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF,
2110 true, /* include text */
2111 false, /* include shapes */
2112 false /* include private items */ );
2113
2114 for( int i = 0; i < aCollector.GetCount(); ++i )
2115 {
2116 const BOARD_ITEM* item = aCollector[i];
2117
2118 switch( item->Type() )
2119 {
2120 case PCB_FP_TEXT_T:
2121 case PCB_FP_TEXTBOX_T:
2122 case PCB_FP_SHAPE_T:
2123 if( item->GetParent() != this )
2124 {
2125 item->TransformShapeToPolygon( coveredRegion, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
2126 ERROR_OUTSIDE );
2127 }
2128 break;
2129
2130 case PCB_TEXT_T:
2131 case PCB_TEXTBOX_T:
2132 case PCB_SHAPE_T:
2133 case PCB_TRACE_T:
2134 case PCB_ARC_T:
2135 case PCB_VIA_T:
2136 item->TransformShapeToPolygon( coveredRegion, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
2137 ERROR_OUTSIDE );
2138 break;
2139
2140 case PCB_FOOTPRINT_T:
2141 if( item != this )
2142 {
2143 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( item );
2144 coveredRegion.AddOutline( footprint->GetBoundingHull().Outline( 0 ) );
2145 }
2146 break;
2147
2148 default:
2149 break;
2150 }
2151 }
2152
2153 double footprintRegionArea = polygonArea( footprintRegion );
2154 double uncoveredRegionArea = footprintRegionArea - polygonArea( coveredRegion );
2155 double coveredArea = footprintRegionArea - uncoveredRegionArea;
2156 double ratio = ( coveredArea / footprintRegionArea );
2157
2158 // Test for negative ratio (should not occur).
2159 // better to be conservative (this will result in the disambiguate dialog)
2160 if( ratio < 0.0 )
2161 return 1.0;
2162
2163 return std::min( ratio, 1.0 );
2164}
2165
2166
2167std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2168{
2169 std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
2170
2171 // There are several possible interpretations here:
2172 // 1) the bounding box (without or without invisible items)
2173 // 2) just the pads and "edges" (ie: non-text graphic items)
2174 // 3) the courtyard
2175
2176 // We'll go with (2) for now, unless the caller is clearly looking for (3)
2177
2178 if( aLayer == F_CrtYd || aLayer == B_CrtYd )
2179 {
2180 const SHAPE_POLY_SET& courtyard = GetCourtyard( aLayer );
2181
2182 if( courtyard.OutlineCount() == 0 ) // malformed/empty polygon
2183 return shape;
2184
2185 shape->AddShape( new SHAPE_SIMPLE( courtyard.COutline( 0 ) ) );
2186 }
2187 else
2188 {
2189 for( PAD* pad : Pads() )
2190 shape->AddShape( pad->GetEffectiveShape( aLayer, aFlash )->Clone() );
2191
2192 for( BOARD_ITEM* item : GraphicalItems() )
2193 {
2194 if( item->Type() == PCB_FP_SHAPE_T )
2195 shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->Clone() );
2196 }
2197 }
2198
2199 return shape;
2200}
2201
2202
2204{
2205 if( GetBoard() && GetBoard()->GetTimeStamp() > m_courtyard_cache_timestamp )
2206 const_cast<FOOTPRINT*>( this )->BuildCourtyardCaches();
2207
2208 if( IsBackLayer( aLayer ) )
2210 else
2212}
2213
2214
2216{
2220
2222
2223 // Build the courtyard area from graphic items on the courtyard.
2224 // Only PCB_FP_SHAPE_T have meaning, graphic texts are ignored.
2225 // Collect items:
2226 std::vector<PCB_SHAPE*> list_front;
2227 std::vector<PCB_SHAPE*> list_back;
2228
2229 for( BOARD_ITEM* item : GraphicalItems() )
2230 {
2231 if( item->GetLayer() == B_CrtYd && item->Type() == PCB_FP_SHAPE_T )
2232 list_back.push_back( static_cast<PCB_SHAPE*>( item ) );
2233
2234 if( item->GetLayer() == F_CrtYd && item->Type() == PCB_FP_SHAPE_T )
2235 list_front.push_back( static_cast<PCB_SHAPE*>( item ) );
2236 }
2237
2238 if( !list_front.size() && !list_back.size() )
2239 return;
2240
2241 int errorMax = pcbIUScale.mmToIU( 0.02 ); // max error for polygonization
2242 int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt
2243
2244 if( ConvertOutlineToPolygon( list_front, m_courtyard_cache_front, errorMax, chainingEpsilon,
2245 true, aErrorHandler ) )
2246 {
2247 // Touching courtyards, or courtyards -at- the clearance distance are legal.
2249
2251 }
2252 else
2253 {
2255 }
2256
2257 if( ConvertOutlineToPolygon( list_back, m_courtyard_cache_back, errorMax, chainingEpsilon,
2258 true, aErrorHandler ) )
2259 {
2260 // Touching courtyards, or courtyards -at- the clearance distance are legal.
2262
2264 }
2265 else
2266 {
2268 }
2269}
2270
2271
2272std::map<wxString, int> FOOTPRINT::MapPadNumbersToNetTieGroups() const
2273{
2274 std::map<wxString, int> padNumberToGroupIdxMap;
2275
2276 for( const PAD* pad : m_pads )
2277 padNumberToGroupIdxMap[ pad->GetNumber() ] = -1;
2278
2279 for( size_t ii = 0; ii < m_netTiePadGroups.size(); ++ii )
2280 {
2281 wxStringTokenizer groupParser( m_netTiePadGroups[ ii ], "," );
2282 std::vector<wxString> numbersInGroup;
2283
2284 while( groupParser.HasMoreTokens() )
2285 padNumberToGroupIdxMap[ groupParser.GetNextToken().Trim( false ).Trim( true ) ] = ii;
2286 }
2287
2288 return padNumberToGroupIdxMap;
2289}
2290
2291
2292std::vector<PAD*> FOOTPRINT::GetNetTiePads( PAD* aPad ) const
2293{
2294 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
2295 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
2296
2297 std::map<wxString, int> padToNetTieGroupMap = MapPadNumbersToNetTieGroups();
2298 int groupIdx = padToNetTieGroupMap[ aPad->GetNumber() ];
2299 std::vector<PAD*> otherPads;
2300
2301 if( groupIdx >= 0 )
2302 {
2303 for( PAD* pad : m_pads )
2304 {
2305 if( padToNetTieGroupMap[ pad->GetNumber() ] == groupIdx )
2306 otherPads.push_back( pad );
2307 }
2308 }
2309
2310 return otherPads;
2311}
2312
2313
2314void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxString& )>& aErrorHandler )
2315{
2316 int likelyAttr = ( GetLikelyAttribute() & ( FP_SMD | FP_THROUGH_HOLE ) );
2317 int setAttr = ( GetAttributes() & ( FP_SMD | FP_THROUGH_HOLE ) );
2318
2319 if( setAttr && likelyAttr && setAttr != likelyAttr )
2320 {
2321 wxString msg;
2322
2323 switch( likelyAttr )
2324 {
2325 case FP_THROUGH_HOLE:
2326 msg.Printf( _( "(expected 'Through hole'; actual '%s')" ), GetTypeName() );
2327 break;
2328 case FP_SMD:
2329 msg.Printf( _( "(expected 'SMD'; actual '%s')" ), GetTypeName() );
2330 break;
2331 }
2332
2333 if( aErrorHandler )
2334 (aErrorHandler)( msg );
2335 }
2336}
2337
2338
2339void FOOTPRINT::CheckPads( const std::function<void( const PAD*, int,
2340 const wxString& )>& aErrorHandler )
2341{
2342 if( aErrorHandler == nullptr )
2343 return;
2344
2345 for( PAD* pad: Pads() )
2346 {
2347 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
2348 {
2349 if( pad->GetDrillSizeX() < 1 || pad->GetDrillSizeY() < 1 )
2350 (aErrorHandler)( pad, DRCE_PAD_TH_WITH_NO_HOLE, wxEmptyString );
2351 }
2352
2353 if( pad->GetAttribute() == PAD_ATTRIB::PTH )
2354 {
2355 if( !pad->IsOnCopperLayer() )
2356 {
2357 (aErrorHandler)( pad, DRCE_PADSTACK, _( "(PTH pad has no copper layers)" ) );
2358 }
2359 else
2360 {
2361 LSET lset = pad->GetLayerSet() & LSET::AllCuMask();
2362 PCB_LAYER_ID layer = lset.Seq().at( 0 );
2363 SHAPE_POLY_SET padOutline;
2364
2365 pad->TransformShapeToPolygon( padOutline, layer, 0, ARC_HIGH_DEF, ERROR_INSIDE );
2366
2367 std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
2368 SHAPE_POLY_SET holeOutline;
2369
2370 TransformOvalToPolygon( holeOutline, hole->GetSeg().A, hole->GetSeg().B,
2371 hole->GetWidth(), ARC_HIGH_DEF, ERROR_INSIDE );
2372
2373 padOutline.BooleanSubtract( holeOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2374
2375 if( padOutline.IsEmpty() )
2376 aErrorHandler( pad, DRCE_PADSTACK, _( "(PTH pad's hole leaves no copper)" ) );
2377 }
2378 }
2379
2380 if( pad->GetAttribute() == PAD_ATTRIB::SMD )
2381 {
2382 if( pad->IsOnLayer( F_Cu ) && pad->IsOnLayer( B_Cu ) )
2383 {
2384 aErrorHandler( pad, DRCE_PADSTACK,
2385 _( "(SMD pad appears on both front and back copper)" ) );
2386 }
2387 else if( pad->IsOnLayer( F_Cu ) )
2388 {
2389 if( pad->IsOnLayer( B_Mask ) )
2390 {
2391 aErrorHandler( pad, DRCE_PADSTACK,
2392 _( "(SMD pad copper and mask layers don't match)" ) );
2393 }
2394 else if( pad->IsOnLayer( B_Paste ) )
2395 {
2396 aErrorHandler( pad, DRCE_PADSTACK,
2397 _( "(SMD pad copper and paste layers don't match)" ) );
2398 }
2399 }
2400 else if( pad->IsOnLayer( B_Cu ) )
2401 {
2402 if( pad->IsOnLayer( F_Mask ) )
2403 {
2404 aErrorHandler( pad, DRCE_PADSTACK,
2405 _( "(SMD pad copper and mask layers don't match)" ) );
2406 }
2407 else if( pad->IsOnLayer( F_Paste ) )
2408 {
2409 aErrorHandler( pad, DRCE_PADSTACK,
2410 _( "(SMD pad copper and paste layers don't match)" ) );
2411 }
2412 }
2413 }
2414 }
2415}
2416
2417
2418void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const PAD*,
2419 const VECTOR2I& )>& aErrorHandler )
2420{
2421 std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
2422
2423 for( PAD* pad : Pads() )
2424 {
2425 std::vector<PAD*> netTiePads = GetNetTiePads( pad );
2426
2427 for( PAD* other : Pads() )
2428 {
2429 if( other == pad || pad->SameLogicalPadAs( other ) )
2430 continue;
2431
2432 if( alg::contains( netTiePads, other ) )
2433 continue;
2434
2435 if( !( ( pad->GetLayerSet() & other->GetLayerSet() ) & LSET::AllCuMask() ).any() )
2436 continue;
2437
2438 // store canonical order so we don't collide in both directions (a:b and b:a)
2439 PAD* a = pad;
2440 PAD* b = other;
2441
2442 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
2443 std::swap( a, b );
2444
2445 if( checkedPairs.find( { a, b } ) == checkedPairs.end() )
2446 {
2447 checkedPairs[ { a, b } ] = 1;
2448
2449 if( pad->GetBoundingBox().Intersects( other->GetBoundingBox() ) )
2450 {
2451 VECTOR2I pos;
2452 SHAPE* padShape = pad->GetEffectiveShape().get();
2453 SHAPE* otherShape = other->GetEffectiveShape().get();
2454
2455 if( padShape->Collide( otherShape, 0, nullptr, &pos ) )
2456 aErrorHandler( pad, other, pos );
2457 }
2458 }
2459 }
2460 }
2461}
2462
2463
2464void FOOTPRINT::CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
2465 const BOARD_ITEM* bItem,
2466 const BOARD_ITEM* cItem,
2467 const VECTOR2I& )>& aErrorHandler )
2468{
2469 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
2470 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
2471
2472 std::map<wxString, int> padNumberToGroupIdxMap = MapPadNumbersToNetTieGroups();
2473
2474 // Now collect all the footprint items which are on copper layers
2475
2476 std::vector<BOARD_ITEM*> copperItems;
2477
2478 for( BOARD_ITEM* item : m_drawings )
2479 {
2480 if( item->IsOnCopperLayer() )
2481 copperItems.push_back( item );
2482 }
2483
2484 for( ZONE* zone : m_fp_zones )
2485 {
2486 if( !zone->GetIsRuleArea() && zone->IsOnCopperLayer() )
2487 copperItems.push_back( zone );
2488 }
2489
2491 copperItems.push_back( m_reference );
2492
2493 if( m_value->IsOnCopperLayer() )
2494 copperItems.push_back( m_value );
2495
2496 for( PCB_LAYER_ID layer : { F_Cu, In1_Cu, B_Cu } )
2497 {
2498 // Next, build a polygon-set for the copper on this layer. We don't really care about
2499 // nets here, we just want to end up with a set of outlines describing the distinct
2500 // copper polygons of the footprint.
2501
2502 SHAPE_POLY_SET copperOutlines;
2503 std::map<int, std::vector<const PAD*>> outlineIdxToPadsMap;
2504
2505 for( BOARD_ITEM* item : copperItems )
2506 {
2507 if( item->IsOnLayer( layer ) )
2508 {
2509 item->TransformShapeToPolygon( copperOutlines, layer, 0, ARC_HIGH_DEF,
2510 ERROR_OUTSIDE );
2511 }
2512 }
2513
2514 copperOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );
2515
2516 // Index each pad to the outline in the set that it is part of.
2517
2518 for( const PAD* pad : m_pads )
2519 {
2520 for( int ii = 0; ii < copperOutlines.OutlineCount(); ++ii )
2521 {
2522 if( pad->GetEffectiveShape( layer )->Collide( &copperOutlines.Outline( ii ), 0 ) )
2523 outlineIdxToPadsMap[ ii ].emplace_back( pad );
2524 }
2525 }
2526
2527 // Finally, ensure that each outline which contains multiple pads has all its pads
2528 // listed in an allowed-shorting group.
2529
2530 for( const auto& [ outlineIdx, pads ] : outlineIdxToPadsMap )
2531 {
2532 if( pads.size() > 1 )
2533 {
2534 const PAD* firstPad = pads[0];
2535 int firstGroupIdx = padNumberToGroupIdxMap[ firstPad->GetNumber() ];
2536
2537 for( size_t ii = 1; ii < pads.size(); ++ii )
2538 {
2539 const PAD* thisPad = pads[ii];
2540 int thisGroupIdx = padNumberToGroupIdxMap[ thisPad->GetNumber() ];
2541
2542 if( thisGroupIdx < 0 || thisGroupIdx != firstGroupIdx )
2543 {
2544 BOARD_ITEM* shortingItem = nullptr;
2545 VECTOR2I pos = ( firstPad->GetPosition() + thisPad->GetPosition() ) / 2;
2546
2547 pos = copperOutlines.Outline( outlineIdx ).NearestPoint( pos );
2548
2549 for( BOARD_ITEM* item : copperItems )
2550 {
2551 if( item->HitTest( pos, 1 ) )
2552 {
2553 shortingItem = item;
2554 break;
2555 }
2556 }
2557
2558 if( shortingItem )
2559 aErrorHandler( shortingItem, firstPad, thisPad, pos );
2560 else
2561 aErrorHandler( firstPad, thisPad, nullptr, pos );
2562 }
2563 }
2564 }
2565 }
2566 }
2567}
2568
2569
2570void FOOTPRINT::CheckNetTiePadGroups( const std::function<void( const wxString& )>& aErrorHandler )
2571{
2572 std::set<wxString> padNumbers;
2573 wxString msg;
2574
2575 for( size_t ii = 0; ii < m_netTiePadGroups.size(); ++ii )
2576 {
2577 wxStringTokenizer groupParser( m_netTiePadGroups[ ii ], "," );
2578
2579 while( groupParser.HasMoreTokens() )
2580 {
2581 wxString padNumber( groupParser.GetNextToken().Trim( false ).Trim( true ) );
2582 const PAD* pad = FindPadByNumber( padNumber );
2583
2584 if( !pad )
2585 {
2586 msg.Printf( _( "(net-tie pad group contains unknown pad number %s)" ), padNumber );
2587 aErrorHandler( msg );
2588 }
2589 else if( !padNumbers.insert( pad->GetNumber() ).second )
2590 {
2591 msg.Printf( _( "(pad %s appears in more than one net-tie pad group)" ), padNumber );
2592 aErrorHandler( msg );
2593 }
2594 }
2595 }
2596}
2597
2598
2600{
2601 wxASSERT( aImage->Type() == PCB_FOOTPRINT_T );
2602
2603 std::swap( *this, *static_cast<FOOTPRINT*>( aImage ) );
2604}
2605
2606
2608{
2609 for( PAD* pad : Pads() )
2610 {
2611 if( pad->GetAttribute() != PAD_ATTRIB::SMD )
2612 return true;
2613 }
2614
2615 return false;
2616}
2617
2618
2619#define TEST( a, b ) { if( a != b ) return a < b; }
2620#define TEST_PT( a, b ) { if( a.x != b.x ) return a.x < b.x; if( a.y != b.y ) return a.y < b.y; }
2621
2622
2623bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* itemA, const BOARD_ITEM* itemB ) const
2624{
2625 TEST( itemA->Type(), itemB->Type() );
2626 TEST( itemA->GetLayer(), itemB->GetLayer() );
2627
2628 if( itemA->Type() == PCB_FP_SHAPE_T )
2629 {
2630 const FP_SHAPE* dwgA = static_cast<const FP_SHAPE*>( itemA );
2631 const FP_SHAPE* dwgB = static_cast<const FP_SHAPE*>( itemB );
2632
2633 TEST( dwgA->GetShape(), dwgB->GetShape() );
2634
2635 TEST_PT( dwgA->GetStart0(), dwgB->GetStart0() );
2636 TEST_PT( dwgA->GetEnd0(), dwgB->GetEnd0() );
2637
2638 if( dwgA->GetShape() == SHAPE_T::ARC )
2639 {
2640 TEST_PT( dwgA->GetCenter0(), dwgB->GetCenter0() );
2641 }
2642 else if( dwgA->GetShape() == SHAPE_T::BEZIER )
2643 {
2644 TEST_PT( dwgA->GetBezierC1_0(), dwgB->GetBezierC1_0() );
2645 TEST_PT( dwgA->GetBezierC2_0(), dwgB->GetBezierC2_0() );
2646 }
2647 else if( dwgA->GetShape() == SHAPE_T::POLY )
2648 {
2650
2651 for( int ii = 0; ii < dwgA->GetPolyShape().TotalVertices(); ++ii )
2652 TEST_PT( dwgA->GetPolyShape().CVertex( ii ), dwgB->GetPolyShape().CVertex( ii ) );
2653 }
2654
2655 TEST( dwgA->GetWidth(), dwgB->GetWidth() );
2656 }
2657
2658 TEST( itemA->m_Uuid, itemB->m_Uuid ); // should be always the case for valid boards
2659
2660 return itemA < itemB;
2661}
2662
2663
2664bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) const
2665{
2666 if( aFirst->GetNumber() != aSecond->GetNumber() )
2667 return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
2668
2669 TEST_PT( aFirst->GetPos0(), aSecond->GetPos0() );
2670 TEST_PT( aFirst->GetSize(), aSecond->GetSize() );
2671 TEST( aFirst->GetShape(), aSecond->GetShape() );
2672 TEST( aFirst->GetLayerSet().Seq(), aSecond->GetLayerSet().Seq() );
2673
2674 TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
2675
2676 return aFirst < aSecond;
2677}
2678
2679
2680bool FOOTPRINT::cmp_zones::operator()( const FP_ZONE* aFirst, const FP_ZONE* aSecond ) const
2681{
2682 TEST( aFirst->GetAssignedPriority(), aSecond->GetAssignedPriority() );
2683 TEST( aFirst->GetLayerSet().Seq(), aSecond->GetLayerSet().Seq() );
2684
2685 TEST( aFirst->Outline()->TotalVertices(), aSecond->Outline()->TotalVertices() );
2686
2687 for( int ii = 0; ii < aFirst->Outline()->TotalVertices(); ++ii )
2688 TEST_PT( aFirst->Outline()->CVertex( ii ), aSecond->Outline()->CVertex( ii ) );
2689
2690 TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
2691
2692 return aFirst < aSecond;
2693}
2694
2695
2696#undef TEST
2697
2698
2700 int aClearance, int aMaxError, ERROR_LOC aErrorLoc,
2701 bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads,
2702 bool aSkipNonPlatedPads ) const
2703{
2704 for( const PAD* pad : m_pads )
2705 {
2706 if( !pad->FlashLayer( aLayer ) )
2707 continue;
2708
2709 VECTOR2I clearance( aClearance, aClearance );
2710
2711 switch( aLayer )
2712 {
2713 case F_Cu:
2714 if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
2715 continue;
2716
2717 if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
2718 continue;
2719
2720 break;
2721
2722 case B_Cu:
2723 if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
2724 continue;
2725
2726 if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
2727 continue;
2728
2729 break;
2730
2731 case F_Mask:
2732 case B_Mask:
2733 clearance.x += pad->GetSolderMaskExpansion();
2734 clearance.y += pad->GetSolderMaskExpansion();
2735 break;
2736
2737 case F_Paste:
2738 case B_Paste:
2739 clearance += pad->GetSolderPasteMargin();
2740 break;
2741
2742 default:
2743 break;
2744 }
2745
2746 // Our standard TransformShapeToPolygon() routines can't handle differing x:y clearance
2747 // values (which get generated when a relative paste margin is used with an oblong pad).
2748 // So we apply this huge hack and fake a larger pad to run the transform on.
2749 // Of course being a hack it falls down when dealing with custom shape pads (where the
2750 // size is only the size of the anchor), so for those we punt and just use clearance.x.
2751
2752 if( ( clearance.x < 0 || clearance.x != clearance.y )
2753 && pad->GetShape() != PAD_SHAPE::CUSTOM )
2754 {
2755 VECTOR2I dummySize = pad->GetSize() + clearance + clearance;
2756
2757 if( dummySize.x <= 0 || dummySize.y <= 0 )
2758 continue;
2759
2760 PAD dummy( *pad );
2761 dummy.SetSize( dummySize );
2762 dummy.TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
2763 }
2764 else
2765 {
2766 pad->TransformShapeToPolygon( aBuffer, aLayer, clearance.x, aMaxError, aErrorLoc );
2767 }
2768 }
2769}
2770
2771
2773 int aClearance, int aError, ERROR_LOC aErrorLoc,
2774 bool aIncludeText, bool aIncludeShapes,
2775 bool aIncludePrivateItems ) const
2776{
2777 std::vector<FP_TEXT*> texts; // List of FP_TEXT to convert
2778
2779 for( BOARD_ITEM* item : GraphicalItems() )
2780 {
2781 if( GetPrivateLayers().test( item->GetLayer() ) && !aIncludePrivateItems )
2782 continue;
2783
2784 if( item->Type() == PCB_FP_TEXT_T && aIncludeText )
2785 {
2786 FP_TEXT* text = static_cast<FP_TEXT*>( item );
2787
2788 if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer && text->IsVisible() )
2789 texts.push_back( text );
2790 }
2791
2792 if( item->Type() == PCB_FP_TEXTBOX_T && aIncludeText )
2793 {
2794 FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( item );
2795
2796 if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer && textbox->IsVisible() )
2797 textbox->TransformShapeToPolygon( aBuffer, aLayer, 0, aError, aErrorLoc );
2798 }
2799
2800 if( item->Type() == PCB_FP_SHAPE_T && aIncludeShapes )
2801 {
2802 const FP_SHAPE* outline = static_cast<FP_SHAPE*>( item );
2803
2804 if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer )
2805 outline->TransformShapeToPolygon( aBuffer, aLayer, 0, aError, aErrorLoc );
2806 }
2807 }
2808
2809 if( aIncludeText )
2810 {
2811 if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
2812 texts.push_back( &Reference() );
2813
2814 if( Value().GetLayer() == aLayer && Value().IsVisible() )
2815 texts.push_back( &Value() );
2816 }
2817
2818 for( const FP_TEXT* text : texts )
2819 text->TransformTextToPolySet( aBuffer, aLayer, aClearance, aError, aErrorLoc );
2820}
2821
2822
2823static struct FOOTPRINT_DESC
2824{
2826 {
2828
2829 if( zcMap.Choices().GetCount() == 0 )
2830 {
2832 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
2833 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
2834 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
2835 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
2836 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
2837 }
2838
2840
2841 if( layerEnum.Choices().GetCount() == 0 )
2842 {
2843 layerEnum.Undefined( UNDEFINED_LAYER );
2844
2845 for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
2846 layerEnum.Map( *seq, LSET::Name( *seq ) );
2847 }
2848
2849 wxPGChoices fpLayers; // footprints might be placed only on F.Cu & B.Cu
2850 fpLayers.Add( LSET::Name( F_Cu ), F_Cu );
2851 fpLayers.Add( LSET::Name( B_Cu ), B_Cu );
2852
2859
2860 auto layer = new PROPERTY_ENUM<FOOTPRINT, PCB_LAYER_ID>( _HKI( "Layer" ),
2862 layer->SetChoices( fpLayers );
2863 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
2864
2865 propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Orientation" ),
2868
2869 const wxString groupFootprint = _( "Footprint Properties" );
2870
2871 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Reference" ),
2873 groupFootprint );
2874 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Value" ),
2876 groupFootprint );
2877
2878 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library link" ),
2880 groupFootprint );
2881 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Description" ),
2883 groupFootprint );
2884 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Keywords" ),
2886 groupFootprint );
2887
2888 const wxString groupAttributes = _( "Fabrication Attributes" );
2889
2890 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Not in schematic" ),
2891 &FOOTPRINT::SetBoardOnly, &FOOTPRINT::IsBoardOnly ), groupAttributes );
2892 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude from position files" ),
2894 groupAttributes );
2895 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude from BOM" ),
2897 groupAttributes );
2898
2899 const wxString groupOverrides = _( "Overrides" );
2900
2902 _HKI( "Exempt from courtyard requirement" ),
2904 groupOverrides );
2905 propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Clearance Override" ),
2908 groupOverrides );
2909 propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Solderpaste Margin Override" ),
2912 groupOverrides );
2914 _HKI( "Solderpaste Margin Ratio Override" ),
2917 groupOverrides );
2919 _HKI( "Zone Connection Style" ),
2921 groupOverrides );
2922 }
constexpr int ARC_HIGH_DEF
Definition: base_units.h:121
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
constexpr int ARC_LOW_DEF
Definition: base_units.h:120
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:180
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:72
PCB_LAYER_ID m_layer
Definition: board_item.h:329
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Definition: board_item.cpp:196
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
Definition: board_item.cpp:184
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:214
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:43
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:163
virtual bool IsOnCopperLayer() const
Definition: board_item.h:123
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:94
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
bool IsFootprintHolder() const
Find out if the board is being used to hold a single footprint for editing/viewing.
Definition: board.h:295
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:592
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:532
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:643
int GetTimeStamp() const
Definition: board.h:288
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:111
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:588
virtual double OnePixelInIU() const =0
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
EDA_ANGLE Normalize180()
Definition: eda_angle.h:271
bool IsType(FRAME_T aType) const
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition: eda_item.cpp:240
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:252
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:142
const KIID m_Uuid
Definition: eda_item.h:494
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
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:100
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:145
virtual wxString GetClass() const =0
Return the class name.
void ClearEditFlags()
Definition: eda_item.h:160
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:144
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:247
bool IsFilled() const
Definition: eda_shape.h:90
SHAPE_T GetShape() const
Definition: eda_shape.h:113
int GetWidth() const
Definition: eda_shape.h:109
virtual bool IsVisible() const
Definition: eda_text.h:129
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:163
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:552
static ENUM_MAP< T > & Instance()
Definition: property.h:546
ENUM_MAP & Undefined(T aValue)
Definition: property.h:559
wxPGChoices & Choices()
Definition: property.h:595
bool FixUuids()
Old footprints do not always have a valid UUID (some can be set to null uuid) However null UUIDs,...
Definition: footprint.cpp:235
void CheckShortingPads(const std::function< void(const PAD *, const PAD *, const VECTOR2I &)> &aErrorHandler)
Check for overlapping, different-numbered, non-net-tie pads.
Definition: footprint.cpp:2418
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:1658
LIB_ID m_fpid
Definition: footprint.h:837
KIID_PATH m_path
Definition: footprint.h:873
bool IsBoardOnly() const
Definition: footprint.h:583
BOX2I m_cachedTextExcludedBBox
Definition: footprint.h:856
void CheckPads(const std::function< void(const PAD *, int, const wxString &)> &aErrorHandler)
Run non-board-specific DRC checks on footprint's pads.
Definition: footprint.cpp:2339
std::vector< PAD * > GetNetTiePads(PAD *aPad) const
Definition: footprint.cpp:2292
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
Definition: footprint.cpp:490
EDA_ANGLE GetOrientation() const
Definition: footprint.h:191
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:621
ZONE_CONNECTION m_zoneConnection
Definition: footprint.h:865
BOX2I m_cachedBoundingBox
Definition: footprint.h:852
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
Return the initial comments block or NULL if none, without transfer of ownership.
Definition: footprint.cpp:2016
bool IsExcludedFromBOM() const
Definition: footprint.h:601
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:1790
FP_ZONES m_fp_zones
Definition: footprint.h:830
static bool IsLibNameValid(const wxString &aName)
Test for validity of a name of a footprint to be used in a footprint library ( no spaces,...
Definition: footprint.cpp:1504
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
Definition: footprint.cpp:1198
void CheckNetTies(const std::function< void(const BOARD_ITEM *aItem, const BOARD_ITEM *bItem, const BOARD_ITEM *cItem, const VECTOR2I &)> &aErrorHandler)
Check for un-allowed shorting of pads in net-tie footprints.
Definition: footprint.cpp:2464
void SetExcludedFromBOM(bool aExclude=true)
Definition: footprint.h:602
int m_fpStatus
Definition: footprint.h:839
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: footprint.cpp:1445
SHAPE_POLY_SET m_cachedHull
Definition: footprint.h:858
int GetLocalClearance() const
Definition: footprint.h:230
void SetAllowMissingCourtyard(bool aAllow=true)
Definition: footprint.h:611
int m_localSolderPasteMargin
Definition: footprint.h:868
int m_attributes
Definition: footprint.h:838
std::vector< FP_3DMODEL > m_3D_Drawings
Definition: footprint.h:879
double CoverageRatio(const GENERAL_COLLECTOR &aCollector) const
Calculate the ratio of total area of the footprint pads and graphical items to the area of the footpr...
Definition: footprint.cpp:2099
BOARD_ITEM * DuplicateItem(const BOARD_ITEM *aItem, bool aAddToFootprint=false)
Duplicate a given item within the footprint, optionally adding it to the board.
Definition: footprint.cpp:1857
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: footprint.cpp:2167
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: footprint.cpp:1355
double m_localSolderPasteMarginRatio
Definition: footprint.h:869
void TransformPadsToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool aSkipNPTHPadsWihNoCopper=false, bool aSkipPlatedPads=false, bool aSkipNonPlatedPads=false) const
Generate pads shapes on layer aLayer as polygons and adds these polygons to aBuffer.
Definition: footprint.cpp:2699
wxArrayString * m_initial_comments
Definition: footprint.h:881
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1361
wxString GetDescription() const
Definition: footprint.h:218
BOX2I m_cachedVisibleBBox
Definition: footprint.h:854
double GetLocalSolderPasteMarginRatio() const
Definition: footprint.h:244
BOX2I GetFpPadsLocalBbox() const
Return the bounding box containing pads when the footprint is on the front side, orientation 0,...
Definition: footprint.cpp:773
int m_visibleBBoxCacheTimeStamp
Definition: footprint.h:855
std::map< wxString, wxString > m_properties
Definition: footprint.h:880
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: footprint.cpp:1539
void SetExcludedFromPosFiles(bool aExclude=true)
Definition: footprint.h:593
int m_localClearance
Definition: footprint.h:866
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: footprint.h:245
void SetOrientationDegrees(double aOrientation)
Definition: footprint.h:203
FP_GROUPS & Groups()
Definition: footprint.h:179
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2272
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:1716
FOOTPRINT & operator=(const FOOTPRINT &aOther)
Definition: footprint.cpp:370
int m_arflag
Definition: footprint.h:875
double GetOrientationDegrees() const
Definition: footprint.h:207
BOARD_ITEM * Duplicate() const override
Create a copy of this BOARD_ITEM.
Definition: footprint.cpp:1844
void SetLocalSolderPasteMargin(int aMargin)
Definition: footprint.h:242
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition: footprint.cpp:1259
int GetAttributes() const
Definition: footprint.h:250
int m_localSolderMaskMargin
Definition: footprint.h:867
FOOTPRINT(BOARD *parent)
Definition: footprint.cpp:55
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:200
LSET GetPrivateLayers() const
Definition: footprint.h:120
wxString GetFPIDAsString() const
Definition: footprint.h:215
wxString GetValueAsString() const
Definition: footprint.h:561
bool AllowMissingCourtyard() const
Definition: footprint.h:610
bool IsFlipped() const
Definition: footprint.h:324
PADS & Pads()
Definition: footprint.h:170
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:925
int GetLocalSolderPasteMargin() const
Definition: footprint.h:241
void TransformFPShapesToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIncludeText=true, bool aIncludeShapes=true, bool aIncludePrivateItems=false) const
Generate shapes of graphic items (outlines) on layer aLayer as polygons and adds these polygons to aB...
Definition: footprint.cpp:2772
wxString GetTypeName() const
Get the type of footprint.
Definition: footprint.cpp:761
DRAWINGS m_drawings
Definition: footprint.h:828
SHAPE_POLY_SET m_courtyard_cache_back
Definition: footprint.h:885
int m_textExcludedBBoxCacheTimeStamp
Definition: footprint.h:857
void SetLocalClearance(int aClearance)
Definition: footprint.h:231
void SetReference(const wxString &aReference)
Definition: footprint.h:528
bool IsLocked() const override
Definition: footprint.h:340
bool IsExcludedFromPosFiles() const
Definition: footprint.h:592
void SetLayerAndFlip(PCB_LAYER_ID aLayer)
Used as Layer property setter – performs a flip if necessary to set the footprint layer.
Definition: footprint.cpp:1565
int m_hullCacheTimeStamp
Definition: footprint.h:859
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
Definition: footprint.cpp:1217
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: footprint.cpp:1486
LSET m_privateLayers
Definition: footprint.h:877
int GetLikelyAttribute() const
Returns the most likely attribute based on pads Either FP_THROUGH_HOLE/FP_SMD/OTHER(0)
Definition: footprint.cpp:713
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: footprint.cpp:1532
VECTOR2I m_pos
Definition: footprint.h:834
std::vector< wxString > m_netTiePadGroups
Definition: footprint.h:863
PAD * GetPad(const VECTOR2I &aPosition, LSET aLayerMask=LSET::AllLayersMask())
Get a pad at aPosition on aLayerMask in the footprint.
Definition: footprint.cpp:1182
void Add3DModel(FP_3DMODEL *a3DModel)
Add a3DModel definition to the end of the 3D model list.
Definition: footprint.cpp:1248
void SetValue(const wxString &aValue)
Definition: footprint.h:555
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: footprint.cpp:1007
wxString GetReferenceAsString() const
Definition: footprint.h:534
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:567
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars for this footprint.
Definition: footprint.cpp:477
SHAPE_POLY_SET m_courtyard_cache_front
Definition: footprint.h:884
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:561
wxString m_keywords
Definition: footprint.h:872
void ClearAllNets()
Clear (i.e.
Definition: footprint.cpp:552
void SetZoneConnection(ZONE_CONNECTION aType)
Definition: footprint.h:247
bool HasThroughHolePads() const
Definition: footprint.cpp:2607
void BuildCourtyardCaches(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:2215
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
A special IsOnLayer for footprints: return true if the footprint contains only items on the given lay...
Definition: footprint.cpp:1074
EDA_ANGLE m_orient
Definition: footprint.h:833
bool HitTestAccurate(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if a point is inside the bounding polygon of the footprint.
Definition: footprint.cpp:1104
wxString GetClass() const override
Return the class name.
Definition: footprint.h:702
void IncrementReference(int aDelta)
Bump the current reference by aDelta.
Definition: footprint.cpp:1989
KIID m_link
Definition: footprint.h:876
bool IsConflicting() const
Definition: footprint.cpp:471
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:184
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invoke a function on all BOARD_ITEMs that belong to the footprint (pads, drawings,...
Definition: footprint.cpp:1367
static const wxChar * StringLibNameInvalidChars(bool aUserReadable)
Test for validity of the name in a library of the footprint ( no spaces, dir separators ....
Definition: footprint.cpp:1515
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1574
wxString GetSelectMenuText(UNITS_PROVIDER *aUnitsProvider) const override
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: footprint.cpp:1344
double GetArea(int aPadding=0) const
Definition: footprint.cpp:703
FP_TEXT * m_value
Definition: footprint.h:836
ZONE_CONNECTION GetZoneConnection() const
Definition: footprint.h:248
const wxString & GetReference() const
Definition: footprint.h:519
void CheckNetTiePadGroups(const std::function< void(const wxString &)> &aErrorHandler)
Sanity check net-tie pad groups.
Definition: footprint.cpp:2570
void SetBoardOnly(bool aIsBoardOnly=true)
Definition: footprint.h:584
timestamp_t m_lastEditTime
Definition: footprint.h:874
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2203
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
Definition: footprint.cpp:1393
int m_fileFormatVersionAtLoad
Definition: footprint.h:840
wxString m_doc
Definition: footprint.h:871
FP_ZONES & Zones()
Definition: footprint.h:176
wxString GetKeywords() const
Definition: footprint.h:221
void CheckFootprintAttributes(const std::function< void(const wxString &)> &aErrorHandler)
Test if footprint attributes for type (SMD/Through hole/Other) match the expected type based on the p...
Definition: footprint.cpp:2314
PADS m_pads
Definition: footprint.h:829
virtual void swapData(BOARD_ITEM *aImage) override
Definition: footprint.cpp:2599
wxString GetNextPadNumber(const wxString &aLastPadName) const
Return the next available pad number in the footprint.
Definition: footprint.cpp:1969
int m_courtyard_cache_timestamp
Definition: footprint.h:886
int m_boundingBoxCacheTimeStamp
Definition: footprint.h:853
VECTOR2I GetPosition() const override
Definition: footprint.h:188
DRAWINGS & GraphicalItems()
Definition: footprint.h:173
FP_GROUPS m_fp_groups
Definition: footprint.h:831
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: footprint.cpp:1097
FP_TEXT & Reference()
Definition: footprint.h:568
PAD * FindPadByNumber(const wxString &aPadNumber, PAD *aSearchAfterMe=nullptr) const
Return a PAD with a matching number.
Definition: footprint.cpp:1162
FP_TEXT * m_reference
Definition: footprint.h:835
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:794
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:95
const VECTOR2I & GetBezierC1_0() const
Definition: fp_shape.h:98
const VECTOR2I & GetEnd0() const
Definition: fp_shape.h:95
const VECTOR2I & GetBezierC2_0() const
Definition: fp_shape.h:101
virtual void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:80
VECTOR2I GetCenter0() const
Definition: fp_shape.cpp:144
const VECTOR2I & GetStart0() const
Definition: fp_shape.h:92
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: fp_shape.cpp:355
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
Definition: fp_textbox.cpp:486
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc) const
Definition: fp_textbox.cpp:446
const BOX2I GetBoundingBox() const override
Set absolute coordinates.
Definition: fp_text.cpp:235
const VECTOR2I & GetPos0() const
Definition: fp_text.h:124
void SetType(TEXT_TYPE aType)
Definition: fp_text.h:119
void SetDrawCoord()
Set relative coordinates.
Definition: fp_text.cpp:203
@ TEXT_is_REFERENCE
Definition: fp_text.h:49
@ TEXT_is_DIVERS
Definition: fp_text.h:51
@ TEXT_is_VALUE
Definition: fp_text.h:50
void KeepUpright(const EDA_ANGLE &aOldOrientation, const EDA_ANGLE &aNewOrientation)
Called when rotating the parent footprint.
Definition: fp_text.cpp:101
void SetPos0(const VECTOR2I &aPos)
Definition: fp_text.h:123
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip entity during footprint flip.
Definition: fp_text.cpp:137
virtual wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const override
Return the string actually shown after processing of the base text.
Definition: fp_text.cpp:415
TEXT_TYPE GetType() const
Definition: fp_text.h:120
A specialization of ZONE for use in footprints.
Definition: zone.h:910
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
const COLLECTORS_GUIDE * GetGuide() const
Definition: collectors.h:295
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:410
Definition: kiid.h:48
wxString GetUniStringLibId() const
Definition: lib_id.h:141
const UTF8 & GetLibItemName() const
Definition: lib_id.h:101
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:87
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:491
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET AllLayersMask()
Definition: lset.cpp:808
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:82
void ShapeToPolygon(SHAPE_LINE_CHAIN &aPolygon, int aScale=-1) const
Return the shape polygon in internal units in a SHAPE_LINE_CHAIN the coordinates are relatives to the...
static const int ORPHANED
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition: netinfo.h:377
Definition: pad.h:59
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:392
const wxString & GetNumber() const
Definition: pad.h:135
VECTOR2I GetPosition() const override
Definition: pad.h:197
PAD_SHAPE GetShape() const
Definition: pad.h:189
const VECTOR2I & GetPos0() const
Definition: pad.h:246
const VECTOR2I & GetSize() const
Definition: pad.h:252
Abstract dimension API.
Definition: pcb_dimension.h:96
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
bool RemoveItem(BOARD_ITEM *aItem)
Remove item from group.
Definition: pcb_group.cpp:95
bool AddItem(BOARD_ITEM *aItem)
Add item to group.
Definition: pcb_group.cpp:80
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:388
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:67
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:69
void AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
double Area(bool aAbsolute=true) const
Return the area of this chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
@ CHAMFER_ACUTE_CORNERS
Acute angles are chamfered.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
double Area()
Count the number of arc shapes present.
bool IsEmpty() const
void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
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,...
int TotalVertices() const
Delete aIdx-th polygon from the set.
void Inflate(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
void Simplify(POLYGON_MODE aFastMode)
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
SHAPE_LINE_CHAIN & Outline(int aIndex)
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
int NewOutline()
Creates a new hole in a given outline.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the aGlobalIndex-th vertex in the poly set.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void Move(const VECTOR2I &aVector) override
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:42
An abstract shape on 2D plane.
Definition: shape.h:123
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition: shape.h:178
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
SHAPE_POLY_SET * Outline()
Definition: zone.h:312
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:122
unsigned GetAssignedPriority() const
Definition: zone.h:112
This file is part of the common library.
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.
bool ConvertOutlineToPolygon(std::vector< PCB_SHAPE * > &aShapeList, SHAPE_POLY_SET &aPolygons, int aErrorMax, int aChainingEpsilon, bool aAllowDisjoint, OUTLINE_ERROR_HANDLER *aErrorHandler)
Function ConvertOutlineToPolygon Build a polygon (with holes) from a PCB_SHAPE list,...
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const VECTOR2I &pt)> OUTLINE_ERROR_HANDLER
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
Definition: convex_hull.cpp:87
#define _HKI(x)
@ DRCE_PADSTACK
Definition: drc_item.h:59
@ DRCE_PAD_TH_WITH_NO_HOLE
Definition: drc_item.h:78
#define _(s)
static constexpr EDA_ANGLE & ANGLE_180
Definition: eda_angle.h:416
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:412
#define PCB_EDIT_FRAME_NAME
INSPECT_RESULT
Definition: eda_item.h:42
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:78
#define COURTYARD_CONFLICT
temporary set when moving footprints having courtyard overlapping
#define MALFORMED_F_COURTYARD
#define MALFORMED_B_COURTYARD
#define STRUCT_DELETED
flag indication structures to be erased
#define MALFORMED_COURTYARDS
#define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY
#define TEST_PT(a, b)
Definition: footprint.cpp:2620
#define TEST(a, b)
Definition: footprint.cpp:2619
static struct FOOTPRINT_DESC _FOOTPRINT_DESC
static double polygonArea(SHAPE_POLY_SET &aPolySet)
Definition: footprint.cpp:2000
INCLUDE_NPTH_T
Definition: footprint.h:56
@ FP_SMD
Definition: footprint.h:69
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:70
@ FP_BOARD_ONLY
Definition: footprint.h:72
@ FP_EXCLUDE_FROM_BOM
Definition: footprint.h:71
@ FP_THROUGH_HOLE
Definition: footprint.h:68
#define FP_is_PLACED
In autoplace: footprint automatically placed.
Definition: footprint.h:335
#define FP_PADS_are_LOCKED
Definition: footprint.h:337
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
@ FRAME_FOOTPRINT_VIEWER_MODAL
Definition: frame_type.h:43
@ FRAME_FOOTPRINT_VIEWER
Definition: frame_type.h:42
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:41
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_OUTSIDE
@ ERROR_INSIDE
Some functions to handle hotkeys in KiCad.
KIID niluuid(0)
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:147
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:922
@ LAYER_LOCKED_ITEM_SHADOW
shadow layer for locked items
Definition: layer_ids.h:239
@ LAYER_CONFLICTS_SHADOW
shadow layer for items flagged conficting
Definition: layer_ids.h:241
@ LAYER_MOD_TEXT
Definition: layer_ids.h:198
@ LAYER_MOD_FR
show footprints on front
Definition: layer_ids.h:208
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:201
@ LAYER_MOD_VALUES
show footprints values (when texts are visible)
Definition: layer_ids.h:210
@ LAYER_MOD_BK
show footprints on back
Definition: layer_ids.h:209
@ LAYER_MOD_REFERENCES
show footprints references (when texts are visible)
Definition: layer_ids.h:211
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ F_CrtYd
Definition: layer_ids.h:117
@ F_Paste
Definition: layer_ids.h:101
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_SilkS
Definition: layer_ids.h:104
@ B_CrtYd
Definition: layer_ids.h:116
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ In1_Cu
Definition: layer_ids.h:65
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:544
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:40
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:99
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
@ NPTH
like PAD_PTH, but not plated
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
@ NONE
no special fabrication property
@ TESTPOINT
a test point pad
@ CASTELLATED
a pad with a castellated through hole
@ BGA
Smd pad, used in BGA footprints.
#define TYPE_HASH(x)
Definition: property.h:61
#define NO_SETTER(owner, type)
Definition: property.h:657
@ PT_DEGREE
Angle expressed in degrees.
Definition: property.h:56
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition: property.h:54
#define REGISTER_TYPE(x)
Definition: property_mgr.h:292
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
Collection of utility functions for component reference designators (refdes)
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:74
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
int GetTrailingInt(const wxString &aStr)
Gets the trailing int, if any, from a string.
constexpr double IUTomm(int iu) const
Definition: base_units.h:87
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
bool operator()(const BOARD_ITEM *itemA, const BOARD_ITEM *itemB) const
Definition: footprint.cpp:2623
bool operator()(const PAD *aFirst, const PAD *aSecond) const
Definition: footprint.cpp:2664
bool operator()(const FP_ZONE *aFirst, const FP_ZONE *aSecond) const
Definition: footprint.cpp:2680
constexpr int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_FP_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:95
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
Definition: typeinfo.h:93
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:91
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:90
@ PCB_FP_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:97
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:104
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_BITMAP_T
class PCB_BITMAP, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:103
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:101
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618
@ THERMAL
Use thermal relief for pads.
@ THT_THERMAL
Thermal relief only for THT pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper