KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 <macros.h>
37#include <pad.h>
38#include <pcb_marker.h>
39#include <pcb_group.h>
40#include <pcb_track.h>
41#include <pcb_dimension.h>
42#include <pcb_bitmap.h>
43#include <pcb_textbox.h>
44#include <pcb_field.h>
45#include <footprint.h>
46#include <zone.h>
47#include <view/view.h>
48#include <i18n_utility.h>
49#include <drc/drc_item.h>
55
56
59 m_boundingBoxCacheTimeStamp( 0 ),
60 m_visibleBBoxCacheTimeStamp( 0 ),
61 m_textExcludedBBoxCacheTimeStamp( 0 ),
62 m_hullCacheTimeStamp( 0 ),
63 m_initial_comments( nullptr ),
64 m_courtyard_cache_timestamp( 0 )
65{
66 m_attributes = 0;
67 m_layer = F_Cu;
70 m_arflag = 0;
71 m_link = 0;
77 m_zoneConnection = ZONE_CONNECTION::INHERITED;
79
80 // These are the mandatory fields for the editor to work
81 for( int i = 0; i < MANDATORY_FIELDS; i++ )
82 {
83 PCB_FIELD* field = new PCB_FIELD( this, i );
84 m_fields.push_back( field );
85
86 switch( i )
87 {
88 case REFERENCE_FIELD:
89 field->SetLayer( F_SilkS );
90 field->SetVisible( true );
91 break;
92 case VALUE_FIELD:
93 field->SetLayer( F_Fab );
94 field->SetVisible( true );
95 break;
96 default:
97 field->SetLayer( F_Fab );
98 field->SetVisible( false );
99 break;
100 }
101 }
102
103 m_3D_Drawings.clear();
104}
105
106
107FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
108 BOARD_ITEM_CONTAINER( aFootprint )
109{
110 m_pos = aFootprint.m_pos;
111 m_fpid = aFootprint.m_fpid;
112 m_attributes = aFootprint.m_attributes;
113 m_fpStatus = aFootprint.m_fpStatus;
114 m_orient = aFootprint.m_orient;
115 m_lastEditTime = aFootprint.m_lastEditTime;
116 m_link = aFootprint.m_link;
117 m_path = aFootprint.m_path;
118
125 m_cachedHull = aFootprint.m_cachedHull;
127
135
136 std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
137
138 // Copy fields
139 for( PCB_FIELD* field : aFootprint.Fields() )
140 {
141 PCB_FIELD* newField = static_cast<PCB_FIELD*>( field->Clone() );
142 ptrMap[field] = newField;
143 Add( newField, ADD_MODE::APPEND ); // Append to ensure indexes are identical
144 }
145
146 // Copy pads
147 for( PAD* pad : aFootprint.Pads() )
148 {
149 PAD* newPad = static_cast<PAD*>( pad->Clone() );
150 ptrMap[ pad ] = newPad;
151 Add( newPad, ADD_MODE::APPEND ); // Append to ensure indexes are identical
152 }
153
154 // Copy zones
155 for( ZONE* zone : aFootprint.Zones() )
156 {
157 ZONE* newZone = static_cast<ZONE*>( zone->Clone() );
158 ptrMap[ zone ] = newZone;
159 Add( newZone, ADD_MODE::APPEND ); // Append to ensure indexes are identical
160
161 // Ensure the net info is OK and especially uses the net info list
162 // living in the current board
163 // Needed when copying a fp from fp editor that has its own board
164 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
165 newZone->SetNetCode( -1 );
166 }
167
168 // Copy drawings
169 for( BOARD_ITEM* item : aFootprint.GraphicalItems() )
170 {
171 BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
172 ptrMap[ item ] = newItem;
173 Add( newItem, ADD_MODE::APPEND ); // Append to ensure indexes are identical
174 }
175
176 // Copy groups
177 for( PCB_GROUP* group : aFootprint.Groups() )
178 {
179 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
180 ptrMap[ group ] = newGroup;
181 Add( newGroup, ADD_MODE::APPEND ); // Append to ensure indexes are identical
182 }
183
184 // Rebuild groups
185 for( PCB_GROUP* group : aFootprint.Groups() )
186 {
187 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( ptrMap[ group ] );
188
189 newGroup->GetItems().clear();
190
191 for( BOARD_ITEM* member : group->GetItems() )
192 {
193 if( ptrMap.count( member ) )
194 newGroup->AddItem( ptrMap[ member ] );
195 }
196 }
197
198 // Copy auxiliary data
199 m_3D_Drawings = aFootprint.m_3D_Drawings;
201 m_keywords = aFootprint.m_keywords;
202 m_privateLayers = aFootprint.m_privateLayers;
203
204 m_arflag = 0;
205
207 new wxArrayString( *aFootprint.m_initial_comments ) : nullptr;
208}
209
210
212 BOARD_ITEM_CONTAINER( aFootprint )
213{
214 *this = std::move( aFootprint );
215}
216
217
219{
220 // Untangle group parents before doing any deleting
221 for( PCB_GROUP* group : m_groups )
222 {
223 for( BOARD_ITEM* item : group->GetItems() )
224 item->SetParentGroup( nullptr );
225 }
226
227 // Clean up the owned elements
228 delete m_initial_comments;
229
230 for( PCB_FIELD* f : m_fields )
231 delete f;
232
233 m_fields.clear();
234
235 for( PAD* p : m_pads )
236 delete p;
237
238 m_pads.clear();
239
240 for( ZONE* zone : m_zones )
241 delete zone;
242
243 m_zones.clear();
244
245 for( PCB_GROUP* group : m_groups )
246 delete group;
247
248 m_groups.clear();
249
250 for( BOARD_ITEM* d : m_drawings )
251 delete d;
252
253 m_drawings.clear();
254
255 if( BOARD* board = GetBoard() )
256 board->IncrementTimeStamp();
257}
258
259
261{
262 return m_fields[aFieldType];
263}
264
265
267{
268 return m_fields[aFieldType];
269}
270
271
273{
274 for( PCB_FIELD* field : m_fields )
275 {
276 if( field->GetId() == aFieldId )
277 return field;
278 }
279
280 return nullptr;
281}
282
283bool FOOTPRINT::HasFieldByName( const wxString& aFieldName ) const
284{
285 for( PCB_FIELD* field : m_fields )
286 {
287 if( field->GetCanonicalName() == aFieldName )
288 return true;
289 }
290
291 return false;
292}
293
294PCB_FIELD* FOOTPRINT::GetFieldByName( const wxString& aFieldName )
295{
296 for( PCB_FIELD* field : m_fields )
297 {
298 if( field->GetName() == aFieldName )
299 return field;
300 }
301
302 return nullptr;
303}
304
305
306wxString FOOTPRINT::GetFieldText( const wxString& aFieldName ) const
307{
308 for( const PCB_FIELD* field : m_fields )
309 {
310 if( aFieldName == field->GetName() || aFieldName == field->GetCanonicalName() )
311 return field->GetText();
312 }
313
314 return wxEmptyString;
315}
316
317
318void FOOTPRINT::GetFields( std::vector<PCB_FIELD*>& aVector, bool aVisibleOnly )
319{
320 for( PCB_FIELD* field : m_fields )
321 {
322 if( aVisibleOnly )
323 {
324 if( !field->IsVisible() || field->GetText().IsEmpty() )
325 continue;
326 }
327
328 aVector.push_back( field );
329 }
330}
331
332
334{
335 int newNdx = m_fields.size();
336
337 m_fields.push_back( new PCB_FIELD( aField ) );
338 return m_fields[newNdx];
339}
340
341
342void FOOTPRINT::RemoveField( const wxString& aFieldName )
343{
344 for( unsigned i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
345 {
346 if( aFieldName == m_fields[i]->GetName( false ) )
347 {
348 m_fields.erase( m_fields.begin() + i );
349 return;
350 }
351 }
352}
353
354
355void FOOTPRINT::ApplyDefaultSettings( const BOARD& board, bool aStyleFields,
356 bool aStyleTextAndGraphics )
357{
358 if( aStyleFields )
359 {
360 for( PCB_FIELD* field : m_fields )
361 field->StyleFromSettings( board.GetDesignSettings() );
362 }
363
364 if( aStyleTextAndGraphics )
365 {
366 for( BOARD_ITEM* item : m_drawings )
367 item->StyleFromSettings( board.GetDesignSettings() );
368 }
369}
370
371
373{
374 // replace null UUIDs if any by a valid uuid
375 std::vector< BOARD_ITEM* > item_list;
376
377 for( PCB_FIELD* field : m_fields )
378 item_list.push_back( field );
379
380 for( PAD* pad : m_pads )
381 item_list.push_back( pad );
382
383 for( BOARD_ITEM* gr_item : m_drawings )
384 item_list.push_back( gr_item );
385
386 // Note: one cannot fix null UUIDs inside the group, but it should not happen
387 // because null uuids can be found in old footprints, therefore without group
388 for( PCB_GROUP* group : m_groups )
389 item_list.push_back( group );
390
391 // Probably notneeded, because old fp do not have zones. But just in case.
392 for( ZONE* zone : m_zones )
393 item_list.push_back( zone );
394
395 bool changed = false;
396
397 for( BOARD_ITEM* item : item_list )
398 {
399 if( item->m_Uuid == niluuid )
400 {
401 const_cast<KIID&>( item->m_Uuid ) = KIID();
402 changed = true;
403 }
404 }
405
406 return changed;
407}
408
409
411{
412 BOARD_ITEM::operator=( aOther );
413
414 m_pos = aOther.m_pos;
415 m_fpid = aOther.m_fpid;
416 m_attributes = aOther.m_attributes;
417 m_fpStatus = aOther.m_fpStatus;
418 m_orient = aOther.m_orient;
419 m_lastEditTime = aOther.m_lastEditTime;
420 m_link = aOther.m_link;
421 m_path = aOther.m_path;
422
423 m_cachedBoundingBox = aOther.m_cachedBoundingBox;
424 m_boundingBoxCacheTimeStamp = aOther.m_boundingBoxCacheTimeStamp;
425 m_cachedVisibleBBox = aOther.m_cachedVisibleBBox;
426 m_visibleBBoxCacheTimeStamp = aOther.m_visibleBBoxCacheTimeStamp;
427 m_cachedTextExcludedBBox = aOther.m_cachedTextExcludedBBox;
428 m_textExcludedBBoxCacheTimeStamp = aOther.m_textExcludedBBoxCacheTimeStamp;
429 m_cachedHull = aOther.m_cachedHull;
430 m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp;
431
432 m_localClearance = aOther.m_localClearance;
433 m_localSolderMaskMargin = aOther.m_localSolderMaskMargin;
434 m_localSolderPasteMargin = aOther.m_localSolderPasteMargin;
435 m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio;
436 m_zoneConnection = aOther.m_zoneConnection;
437 m_netTiePadGroups = aOther.m_netTiePadGroups;
438
439 // Move the fields
440 m_fields.clear();
441
442 for( PCB_FIELD* field : aOther.Fields() )
443 Add( field );
444
445 // Move the pads
446 m_pads.clear();
447
448 for( PAD* pad : aOther.Pads() )
449 Add( pad );
450
451 aOther.Pads().clear();
452
453 // Move the zones
454 m_zones.clear();
455
456 for( ZONE* item : aOther.Zones() )
457 {
458 Add( item );
459
460 // Ensure the net info is OK and especially uses the net info list
461 // living in the current board
462 // Needed when copying a fp from fp editor that has its own board
463 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
464 item->SetNetCode( -1 );
465 }
466
467 aOther.Zones().clear();
468
469 // Move the drawings
470 m_drawings.clear();
471
472 for( BOARD_ITEM* item : aOther.GraphicalItems() )
473 Add( item );
474
475 aOther.GraphicalItems().clear();
476
477 // Move the groups
478 m_groups.clear();
479
480 for( PCB_GROUP* group : aOther.Groups() )
481 Add( group );
482
483 aOther.Groups().clear();
484
485 // Copy auxiliary data
486 m_3D_Drawings = aOther.m_3D_Drawings;
487 m_libDescription = aOther.m_libDescription;
488 m_keywords = aOther.m_keywords;
489 m_privateLayers = aOther.m_privateLayers;
490
491 m_initial_comments = aOther.m_initial_comments;
492
493 // Clear the other item's containers since this is a move
494 aOther.Fields().clear();
495 aOther.Pads().clear();
496 aOther.Zones().clear();
497 aOther.GraphicalItems().clear();
498 aOther.m_initial_comments = nullptr;
499
500 return *this;
501}
502
503
505{
506 BOARD_ITEM::operator=( aOther );
507
508 m_pos = aOther.m_pos;
509 m_fpid = aOther.m_fpid;
510 m_attributes = aOther.m_attributes;
511 m_fpStatus = aOther.m_fpStatus;
512 m_orient = aOther.m_orient;
514 m_link = aOther.m_link;
515 m_path = aOther.m_path;
516
523 m_cachedHull = aOther.m_cachedHull;
525
532
533 std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
534
535 // Copy fields
536 m_fields.clear();
537
538 for( PCB_FIELD* field : aOther.GetFields() )
539 {
540 PCB_FIELD* newField = new PCB_FIELD( *field );
541 ptrMap[field] = newField;
542 Add( newField );
543 }
544
545 // Copy pads
546 m_pads.clear();
547
548 for( PAD* pad : aOther.Pads() )
549 {
550 PAD* newPad = new PAD( *pad );
551 ptrMap[ pad ] = newPad;
552 Add( newPad );
553 }
554
555 // Copy zones
556 m_zones.clear();
557
558 for( ZONE* zone : aOther.Zones() )
559 {
560 ZONE* newZone = static_cast<ZONE*>( zone->Clone() );
561 ptrMap[ zone ] = newZone;
562 Add( newZone );
563
564 // Ensure the net info is OK and especially uses the net info list
565 // living in the current board
566 // Needed when copying a fp from fp editor that has its own board
567 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
568 newZone->SetNetCode( -1 );
569 }
570
571 // Copy drawings
572 m_drawings.clear();
573
574 for( BOARD_ITEM* item : aOther.GraphicalItems() )
575 {
576 BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
577 ptrMap[ item ] = newItem;
578 Add( newItem );
579 }
580
581 // Copy groups
582 m_groups.clear();
583
584 for( PCB_GROUP* group : aOther.Groups() )
585 {
586 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
587 newGroup->GetItems().clear();
588
589 for( BOARD_ITEM* member : group->GetItems() )
590 newGroup->AddItem( ptrMap[ member ] );
591
592 Add( newGroup );
593 }
594
595 // Copy auxiliary data
598 m_keywords = aOther.m_keywords;
600
602 new wxArrayString( *aOther.m_initial_comments ) : nullptr;
603
604 return *this;
605}
606
607
609{
610 return HasFlag( COURTYARD_CONFLICT );
611}
612
613
614void FOOTPRINT::GetContextualTextVars( wxArrayString* aVars ) const
615{
616 aVars->push_back( wxT( "REFERENCE" ) );
617 aVars->push_back( wxT( "VALUE" ) );
618 aVars->push_back( wxT( "LAYER" ) );
619 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
620 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
621 aVars->push_back( wxT( "SHORT_NET_NAME(<pad_number>)" ) );
622 aVars->push_back( wxT( "NET_NAME(<pad_number>)" ) );
623 aVars->push_back( wxT( "NET_CLASS(<pad_number>)" ) );
624 aVars->push_back( wxT( "PIN_NAME(<pad_number>)" ) );
625}
626
627
628bool FOOTPRINT::ResolveTextVar( wxString* token, int aDepth ) const
629{
630 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
631 return false;
632
633 if( token->IsSameAs( wxT( "REFERENCE" ) ) )
634 {
635 *token = Reference().GetShownText( false, aDepth + 1 );
636 return true;
637 }
638 else if( token->IsSameAs( wxT( "VALUE" ) ) )
639 {
640 *token = Value().GetShownText( false, aDepth + 1 );
641 return true;
642 }
643 else if( token->IsSameAs( wxT( "LAYER" ) ) )
644 {
645 *token = GetLayerName();
646 return true;
647 }
648 else if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
649 {
651 return true;
652 }
653 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
654 {
656 return true;
657 }
658 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) )
659 || token->StartsWith( wxT( "NET_NAME(" ) )
660 || token->StartsWith( wxT( "NET_CLASS(" ) )
661 || token->StartsWith( wxT( "PIN_NAME(" ) ) )
662 {
663 wxString padNumber = token->AfterFirst( '(' );
664 padNumber = padNumber.BeforeLast( ')' );
665
666 for( PAD* pad : Pads() )
667 {
668 if( pad->GetNumber() == padNumber )
669 {
670 if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
671 *token = pad->GetShortNetname();
672 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
673 *token = pad->GetNetname();
674 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
675 *token = pad->GetNetClassName();
676 else
677 *token = pad->GetPinFunction();
678
679 return true;
680 }
681 }
682 }
683 else if( HasFieldByName( *token ) )
684 {
685 *token = GetFieldText( *token );
686 return true;
687 }
688
689 if( GetBoard() && GetBoard()->ResolveTextVar( token, aDepth + 1 ) )
690 return true;
691
692 return false;
693}
694
695
697{
698 // Force the ORPHANED dummy net info for all pads.
699 // ORPHANED dummy net does not depend on a board
700 for( PAD* pad : m_pads )
701 pad->SetNetCode( NETINFO_LIST::ORPHANED );
702}
703
704
705void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode, bool aSkipConnectivity )
706{
707 switch( aBoardItem->Type() )
708 {
709 case PCB_FIELD_T:
710 // Always append fields
711 m_fields.push_back( static_cast<PCB_FIELD*>( aBoardItem ) );
712
713 break;
714
715 case PCB_TEXT_T:
717 case PCB_DIM_LEADER_T:
718 case PCB_DIM_CENTER_T:
719 case PCB_DIM_RADIAL_T:
721 case PCB_SHAPE_T:
722 case PCB_TEXTBOX_T:
723 case PCB_BITMAP_T:
724 if( aMode == ADD_MODE::APPEND )
725 m_drawings.push_back( aBoardItem );
726 else
727 m_drawings.push_front( aBoardItem );
728 break;
729
730 case PCB_PAD_T:
731 if( aMode == ADD_MODE::APPEND )
732 m_pads.push_back( static_cast<PAD*>( aBoardItem ) );
733 else
734 m_pads.push_front( static_cast<PAD*>( aBoardItem ) );
735 break;
736
737 case PCB_ZONE_T:
738 if( aMode == ADD_MODE::APPEND )
739 m_zones.push_back( static_cast<ZONE*>( aBoardItem ) );
740 else
741 m_zones.insert( m_zones.begin(), static_cast<ZONE*>( aBoardItem ) );
742 break;
743
744 case PCB_GROUP_T:
745 if( aMode == ADD_MODE::APPEND )
746 m_groups.push_back( static_cast<PCB_GROUP*>( aBoardItem ) );
747 else
748 m_groups.insert( m_groups.begin(), static_cast<PCB_GROUP*>( aBoardItem ) );
749 break;
750
751 default:
752 {
753 wxString msg;
754 msg.Printf( wxT( "FOOTPRINT::Add() needs work: BOARD_ITEM type (%d) not handled" ),
755 aBoardItem->Type() );
756 wxFAIL_MSG( msg );
757
758 return;
759 }
760 }
761
762 aBoardItem->ClearEditFlags();
763 aBoardItem->SetParent( this );
764}
765
766
767void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode )
768{
769 switch( aBoardItem->Type() )
770 {
771 case PCB_FIELD_T:
772 {
773 PCB_FIELD* field = static_cast<PCB_FIELD*>( aBoardItem );
774
775 // Only user text can be removed this way.
776 wxCHECK_RET( !field->IsMandatoryField(),
777 wxT( "Please report this bug: Invalid remove operation on required text" ) );
778 for( auto it = m_fields.begin(); it != m_fields.end(); ++it )
779 {
780 if( *it == aBoardItem )
781 {
782 m_fields.erase( it );
783 break;
784 }
785 }
786 }
787 break;
788
789 case PCB_TEXT_T:
791 case PCB_DIM_CENTER_T:
793 case PCB_DIM_RADIAL_T:
794 case PCB_DIM_LEADER_T:
795 case PCB_SHAPE_T:
796 case PCB_TEXTBOX_T:
797 case PCB_BITMAP_T:
798 for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
799 {
800 if( *it == aBoardItem )
801 {
802 m_drawings.erase( it );
803 break;
804 }
805 }
806
807 break;
808
809 case PCB_PAD_T:
810 for( auto it = m_pads.begin(); it != m_pads.end(); ++it )
811 {
812 if( *it == static_cast<PAD*>( aBoardItem ) )
813 {
814 m_pads.erase( it );
815 break;
816 }
817 }
818
819 break;
820
821 case PCB_ZONE_T:
822 for( auto it = m_zones.begin(); it != m_zones.end(); ++it )
823 {
824 if( *it == static_cast<ZONE*>( aBoardItem ) )
825 {
826 m_zones.erase( it );
827 break;
828 }
829 }
830
831 break;
832
833 case PCB_GROUP_T:
834 for( auto it = m_groups.begin(); it != m_groups.end(); ++it )
835 {
836 if( *it == static_cast<PCB_GROUP*>( aBoardItem ) )
837 {
838 m_groups.erase( it );
839 break;
840 }
841 }
842
843 break;
844
845 default:
846 {
847 wxString msg;
848 msg.Printf( wxT( "FOOTPRINT::Remove() needs work: BOARD_ITEM type (%d) not handled" ),
849 aBoardItem->Type() );
850 wxFAIL_MSG( msg );
851 }
852 }
853
854 aBoardItem->SetFlags( STRUCT_DELETED );
855
856 PCB_GROUP* parentGroup = aBoardItem->GetParentGroup();
857
858 if( parentGroup && !( parentGroup->GetFlags() & STRUCT_DELETED ) )
859 parentGroup->RemoveItem( aBoardItem );
860}
861
862
863double FOOTPRINT::GetArea( int aPadding ) const
864{
865 BOX2I bbox = GetBoundingBox( false, false );
866
867 double w = std::abs( static_cast<double>( bbox.GetWidth() ) ) + aPadding;
868 double h = std::abs( static_cast<double>( bbox.GetHeight() ) ) + aPadding;
869 return w * h;
870}
871
872
874{
875 int smd_count = 0;
876 int tht_count = 0;
877
878 for( PAD* pad : m_pads )
879 {
880 switch( pad->GetProperty() )
881 {
882 case PAD_PROP::FIDUCIAL_GLBL:
883 case PAD_PROP::FIDUCIAL_LOCAL:
884 continue;
885
886 case PAD_PROP::HEATSINK:
887 case PAD_PROP::CASTELLATED:
888 continue;
889
890 case PAD_PROP::NONE:
891 case PAD_PROP::BGA:
892 case PAD_PROP::TESTPOINT:
893 break;
894 }
895
896 switch( pad->GetAttribute() )
897 {
898 case PAD_ATTRIB::PTH:
899 tht_count++;
900 break;
901
902 case PAD_ATTRIB::SMD:
903 if( pad->IsOnCopperLayer() )
904 smd_count++;
905
906 break;
907
908 default:
909 break;
910 }
911 }
912
913 // Footprints with plated through-hole pads should usually be marked through hole even if they
914 // also have SMD because they might not be auto-placed. Exceptions to this might be shielded
915 if( tht_count > 0 )
916 return FP_THROUGH_HOLE;
917
918 if( smd_count > 0 )
919 return FP_SMD;
920
921 return 0;
922}
923
924
926{
927 if( ( m_attributes & FP_SMD ) == FP_SMD )
928 return _( "SMD" );
929
931 return _( "Through hole" );
932
933 return _( "Other" );
934}
935
936
938{
939 BOX2I bbox;
940
941 // We want the bounding box of the footprint pads at rot 0, not flipped
942 // Create such a image:
943 FOOTPRINT dummy( *this );
944
945 dummy.SetPosition( VECTOR2I( 0, 0 ) );
946 dummy.SetOrientation( ANGLE_0 );
947
948 if( dummy.IsFlipped() )
949 dummy.Flip( VECTOR2I( 0, 0 ), false );
950
951 for( PAD* pad : dummy.Pads() )
952 bbox.Merge( pad->GetBoundingBox() );
953
954 // Remove the parent and the group from the dummy footprint before deletion
955 dummy.SetParent( nullptr );
956 dummy.SetParentGroup( nullptr );
957
958 return bbox;
959}
960
961
963{
964 return GetBoundingBox( true, true );
965}
966
967
968const BOX2I FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const
969{
970 std::vector<PCB_TEXT*> texts;
971 const BOARD* board = GetBoard();
972 bool isFPEdit = board && board->IsFootprintHolder();
973
974 if( board )
975 {
976 if( aIncludeText && aIncludeInvisibleText )
977 {
979 return m_cachedBoundingBox;
980 }
981 else if( aIncludeText )
982 {
984 return m_cachedVisibleBBox;
985 }
986 else
987 {
990 }
991 }
992
993 BOX2I bbox( m_pos );
994 bbox.Inflate( pcbIUScale.mmToIU( 0.25 ) ); // Give a min size to the bbox
995
996 for( BOARD_ITEM* item : m_drawings )
997 {
998 if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
999 continue;
1000
1001 // We want the bitmap bounding box just in the footprint editor
1002 // so it will start with the correct initial zoom
1003 if( item->Type() == PCB_BITMAP_T && !isFPEdit )
1004 continue;
1005
1006 // Handle text separately
1007 if( item->Type() == PCB_TEXT_T )
1008 {
1009 texts.push_back( static_cast<PCB_TEXT*>( item ) );
1010 continue;
1011 }
1012
1013 // If we're not including text then drop annotations as well
1014 if( !aIncludeText )
1015 {
1016 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
1017 continue;
1018
1019 if( item->GetLayer() == Cmts_User || item->GetLayer() == Dwgs_User
1020 || item->GetLayer() == Eco1_User || item->GetLayer() == Eco2_User )
1021 {
1022 continue;
1023 }
1024 }
1025
1026 bbox.Merge( item->GetBoundingBox() );
1027 }
1028
1029 for( PCB_FIELD* field : m_fields )
1030 texts.push_back( field );
1031
1032 for( PAD* pad : m_pads )
1033 bbox.Merge( pad->GetBoundingBox() );
1034
1035 for( ZONE* zone : m_zones )
1036 bbox.Merge( zone->GetBoundingBox() );
1037
1038 bool noDrawItems = ( m_drawings.empty() && m_pads.empty() && m_zones.empty() );
1039
1040 // Groups do not contribute to the rect, only their members
1041 if( aIncludeText || noDrawItems )
1042 {
1043 // Only PCB_TEXT and PCB_FIELD items are independently selectable;
1044 // PCB_TEXTBOX items go in with other graphic items above.
1045 for( PCB_TEXT* text : texts )
1046 {
1047 if( !isFPEdit && m_privateLayers.test( text->GetLayer() ) )
1048 continue;
1049
1050 if( aIncludeInvisibleText || text->IsVisible() )
1051 bbox.Merge( text->GetBoundingBox() );
1052 }
1053
1054 // This can be further optimized when aIncludeInvisibleText is true, but currently
1055 // leaving this as is until it's determined there is a noticeable speed hit.
1056 bool valueLayerIsVisible = true;
1057 bool refLayerIsVisible = true;
1058
1059 if( board )
1060 {
1061 // The first "&&" conditional handles the user turning layers off as well as layers
1062 // not being present in the current PCB stackup. Values, references, and all
1063 // footprint text can also be turned off via the GAL meta-layers, so the 2nd and
1064 // 3rd "&&" conditionals handle that.
1065 valueLayerIsVisible = board->IsLayerVisible( Value().GetLayer() )
1067 && board->IsElementVisible( LAYER_FP_TEXT );
1068
1069 refLayerIsVisible = board->IsLayerVisible( Reference().GetLayer() )
1071 && board->IsElementVisible( LAYER_FP_TEXT );
1072 }
1073
1074
1075 if( ( Value().IsVisible() && valueLayerIsVisible )
1076 || aIncludeInvisibleText
1077 || noDrawItems )
1078 {
1079 bbox.Merge( Value().GetBoundingBox() );
1080 }
1081
1082 if( ( Reference().IsVisible() && refLayerIsVisible )
1083 || aIncludeInvisibleText
1084 || noDrawItems )
1085 {
1086 bbox.Merge( Reference().GetBoundingBox() );
1087 }
1088 }
1089
1090 if( board )
1091 {
1092 if( ( aIncludeText && aIncludeInvisibleText ) || noDrawItems )
1093 {
1095 m_cachedBoundingBox = bbox;
1096 }
1097 else if( aIncludeText )
1098 {
1100 m_cachedVisibleBBox = bbox;
1101 }
1102 else
1103 {
1106 }
1107 }
1108
1109 return bbox;
1110}
1111
1112
1114{
1115 std::vector<PCB_TEXT*> texts;
1116 const BOARD* board = GetBoard();
1117 bool isFPEdit = board && board->IsFootprintHolder();
1118
1119 // Start with an uninitialized bounding box
1120 BOX2I bbox;
1121
1122 for( BOARD_ITEM* item : m_drawings )
1123 {
1124 if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
1125 continue;
1126
1127 if( ( aLayers & item->GetLayerSet() ).none() )
1128 continue;
1129
1130 // We want the bitmap bounding box just in the footprint editor
1131 // so it will start with the correct initial zoom
1132 if( item->Type() == PCB_BITMAP_T && !isFPEdit )
1133 continue;
1134
1135 bbox.Merge( item->GetBoundingBox() );
1136 }
1137
1138 for( PAD* pad : m_pads )
1139 {
1140 if( ( aLayers & pad->GetLayerSet() ).none() )
1141 continue;
1142
1143 bbox.Merge( pad->GetBoundingBox() );
1144 }
1145
1146 for( ZONE* zone : m_zones )
1147 {
1148 if( ( aLayers & zone->GetLayerSet() ).none() )
1149 continue;
1150
1151 bbox.Merge( zone->GetBoundingBox() );
1152 }
1153
1154 return bbox;
1155}
1156
1157
1159{
1160 const BOARD* board = GetBoard();
1161 bool isFPEdit = board && board->IsFootprintHolder();
1162
1163 if( board )
1164 {
1165 if( m_hullCacheTimeStamp >= board->GetTimeStamp() )
1166 return m_cachedHull;
1167 }
1168
1169 SHAPE_POLY_SET rawPolys;
1170 SHAPE_POLY_SET hull;
1171
1172 for( BOARD_ITEM* item : m_drawings )
1173 {
1174 if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) )
1175 continue;
1176
1177 if( item->Type() != PCB_TEXT_T && item->Type() != PCB_BITMAP_T )
1178 {
1179 item->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
1180 ERROR_OUTSIDE );
1181 }
1182
1183 // We intentionally exclude footprint text from the bounding hull.
1184 }
1185
1186 for( PAD* pad : m_pads )
1187 {
1188 pad->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
1189 // In case hole is larger than pad
1190 pad->TransformHoleToPolygon( rawPolys, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
1191 }
1192
1193 for( ZONE* zone : m_zones )
1194 {
1195 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
1196 {
1197 const SHAPE_POLY_SET& layerPoly = *zone->GetFilledPolysList( layer );
1198
1199 for( int ii = 0; ii < layerPoly.OutlineCount(); ii++ )
1200 {
1201 const SHAPE_LINE_CHAIN& poly = layerPoly.COutline( ii );
1202 rawPolys.AddOutline( poly );
1203 }
1204 }
1205 }
1206
1207 // If there are some graphic items, build the actual hull.
1208 // However if no items, create a minimal polygon (can happen if a footprint
1209 // is created with no item: it contains only 2 texts.
1210 if( rawPolys.OutlineCount() == 0 )
1211 {
1212 // generate a small dummy rectangular outline around the anchor
1213 const int halfsize = pcbIUScale.mmToIU( 1.0 );
1214
1215 rawPolys.NewOutline();
1216
1217 // add a square:
1218 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y - halfsize );
1219 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y - halfsize );
1220 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y + halfsize );
1221 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y + halfsize );
1222 }
1223
1224 std::vector<VECTOR2I> convex_hull;
1225 BuildConvexHull( convex_hull, rawPolys );
1226
1229
1230 for( const VECTOR2I& pt : convex_hull )
1231 m_cachedHull.Append( pt );
1232
1233 if( board )
1235
1236 return m_cachedHull;
1237}
1238
1239
1240void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1241{
1242 wxString msg, msg2;
1243
1244 // Don't use GetShownText(); we want to see the variable references here
1245 aList.emplace_back( UnescapeString( Reference().GetText() ),
1246 UnescapeString( Value().GetText() ) );
1247
1248 if( aFrame->IsType( FRAME_FOOTPRINT_VIEWER )
1249 || aFrame->IsType( FRAME_FOOTPRINT_CHOOSER )
1250 || aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
1251 {
1252 size_t padCount = GetPadCount( DO_NOT_INCLUDE_NPTH );
1253
1254 aList.emplace_back( _( "Library" ), GetFPID().GetLibNickname().wx_str() );
1255
1256 aList.emplace_back( _( "Footprint Name" ), GetFPID().GetLibItemName().wx_str() );
1257
1258 aList.emplace_back( _( "Pads" ), wxString::Format( wxT( "%zu" ), padCount ) );
1259
1260 aList.emplace_back( wxString::Format( _( "Doc: %s" ), GetLibDescription() ),
1261 wxString::Format( _( "Keywords: %s" ), GetKeywords() ) );
1262
1263 return;
1264 }
1265
1266 // aFrame is the board editor:
1267 aList.emplace_back( _( "Board Side" ), IsFlipped() ? _( "Back (Flipped)" ) : _( "Front" ) );
1268
1269 auto addToken = []( wxString* aStr, const wxString& aAttr )
1270 {
1271 if( !aStr->IsEmpty() )
1272 *aStr += wxT( ", " );
1273
1274 *aStr += aAttr;
1275 };
1276
1277 wxString status;
1278 wxString attrs;
1279
1280 if( IsLocked() )
1281 addToken( &status, _( "Locked" ) );
1282
1283 if( m_fpStatus & FP_is_PLACED )
1284 addToken( &status, _( "autoplaced" ) );
1285
1287 addToken( &attrs, _( "not in schematic" ) );
1288
1290 addToken( &attrs, _( "exclude from pos files" ) );
1291
1293 addToken( &attrs, _( "exclude from BOM" ) );
1294
1295 if( m_attributes & FP_DNP )
1296 addToken( &attrs, _( "DNP" ) );
1297
1298 aList.emplace_back( _( "Status: " ) + status, _( "Attributes:" ) + wxS( " " ) + attrs );
1299
1300 aList.emplace_back( _( "Rotation" ), wxString::Format( wxT( "%.4g" ),
1301 GetOrientation().AsDegrees() ) );
1302
1303 msg.Printf( _( "Footprint: %s" ), m_fpid.GetUniStringLibId() );
1304 msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
1305 : m_3D_Drawings.front().m_Filename );
1306 aList.emplace_back( msg, msg2 );
1307
1308 msg.Printf( _( "Doc: %s" ), m_libDescription );
1309 msg2.Printf( _( "Keywords: %s" ), m_keywords );
1310 aList.emplace_back( msg, msg2 );
1311}
1312
1313
1315{
1316 // If we have any pads, fall back on normal checking
1317 for( PAD* pad : m_pads )
1318 {
1319 if( pad->IsOnLayer( aLayer ) )
1320 return true;
1321 }
1322
1323 for( ZONE* zone : m_zones )
1324 {
1325 if( zone->IsOnLayer( aLayer ) )
1326 return true;
1327 }
1328
1329 for( PCB_FIELD* field : m_fields )
1330 {
1331 if( field->IsOnLayer( aLayer ) )
1332 return true;
1333 }
1334
1335 for( BOARD_ITEM* item : m_drawings )
1336 {
1337 if( item->IsOnLayer( aLayer ) )
1338 return true;
1339 }
1340
1341 return false;
1342}
1343
1344
1345bool FOOTPRINT::HitTestOnLayer( const VECTOR2I& aPosition, PCB_LAYER_ID aLayer, int aAccuracy ) const
1346{
1347 for( PAD* pad : m_pads )
1348 {
1349 if( pad->IsOnLayer( aLayer ) && pad->HitTest( aPosition, aAccuracy ) )
1350 return true;
1351 }
1352
1353 for( ZONE* zone : m_zones )
1354 {
1355 if( zone->IsOnLayer( aLayer ) && zone->HitTest( aPosition, aAccuracy ) )
1356 return true;
1357 }
1358
1359 for( BOARD_ITEM* item : m_drawings )
1360 {
1361 if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer )
1362 && item->HitTest( aPosition, aAccuracy ) )
1363 {
1364 return true;
1365 }
1366 }
1367
1368 return false;
1369}
1370
1371
1372bool FOOTPRINT::HitTestOnLayer( const BOX2I& aRect, bool aContained, PCB_LAYER_ID aLayer, int aAccuracy ) const
1373{
1374 std::vector<BOARD_ITEM*> items;
1375
1376 for( PAD* pad : m_pads )
1377 {
1378 if( pad->IsOnLayer( aLayer ) )
1379 items.push_back( pad );
1380 }
1381
1382 for( ZONE* zone : m_zones )
1383 {
1384 if( zone->IsOnLayer( aLayer ) )
1385 items.push_back( zone );
1386 }
1387
1388 for( BOARD_ITEM* item : m_drawings )
1389 {
1390 if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer ) )
1391 items.push_back( item );
1392 }
1393
1394 // If we require the elements to be contained in the rect and any of them are not,
1395 // we can return false;
1396 // Conversely, if we just require any of the elements to have a hit, we can return true
1397 // when the first one is found.
1398 for( BOARD_ITEM* item : items )
1399 {
1400 if( !aContained && item->HitTest( aRect, aContained, aAccuracy ) )
1401 return true;
1402 else if( aContained && !item->HitTest( aRect, aContained, aAccuracy ) )
1403 return false;
1404 }
1405
1406 // If we didn't exit in the loop, that means that we did not return false for aContained or
1407 // we did not return true for !aContained. So we can just return the bool with a test of
1408 // whether there were any elements or not.
1409 return !items.empty() && aContained;
1410}
1411
1412
1413bool FOOTPRINT::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
1414{
1415 BOX2I rect = GetBoundingBox( false, false );
1416 return rect.Inflate( aAccuracy ).Contains( aPosition );
1417}
1418
1419
1420bool FOOTPRINT::HitTestAccurate( const VECTOR2I& aPosition, int aAccuracy ) const
1421{
1422 return GetBoundingHull().Collide( aPosition, aAccuracy );
1423}
1424
1425
1426bool FOOTPRINT::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1427{
1428 BOX2I arect = aRect;
1429 arect.Inflate( aAccuracy );
1430
1431 if( aContained )
1432 {
1433 return arect.Contains( GetBoundingBox( false, false ) );
1434 }
1435 else
1436 {
1437 // If the rect does not intersect the bounding box, skip any tests
1438 if( !aRect.Intersects( GetBoundingBox( false, false ) ) )
1439 return false;
1440
1441 // The empty footprint dummy rectangle intersects the selection area.
1442 if( m_pads.empty() && m_zones.empty() && m_drawings.empty() )
1443 return GetBoundingBox( true, false ).Intersects( arect );
1444
1445 // Determine if any elements in the FOOTPRINT intersect the rect
1446 for( PAD* pad : m_pads )
1447 {
1448 if( pad->HitTest( arect, false, 0 ) )
1449 return true;
1450 }
1451
1452 for( ZONE* zone : m_zones )
1453 {
1454 if( zone->HitTest( arect, false, 0 ) )
1455 return true;
1456 }
1457
1458 // PCB fields are selectable on their own, so they don't get tested
1459
1460 for( BOARD_ITEM* item : m_drawings )
1461 {
1462 // Text items are selectable on their own, and are therefore excluded from this
1463 // test. TextBox items are NOT selectable on their own, and so MUST be included
1464 // here. Bitmaps aren't selectable since they aren't displayed.
1465 if( item->Type() != PCB_TEXT_T && item->HitTest( arect, false, 0 ) )
1466 return true;
1467 }
1468
1469 // Groups are not hit-tested; only their members
1470
1471 // No items were hit
1472 return false;
1473 }
1474}
1475
1476
1477PAD* FOOTPRINT::FindPadByNumber( const wxString& aPadNumber, PAD* aSearchAfterMe ) const
1478{
1479 bool can_select = aSearchAfterMe ? false : true;
1480
1481 for( PAD* pad : m_pads )
1482 {
1483 if( !can_select && pad == aSearchAfterMe )
1484 {
1485 can_select = true;
1486 continue;
1487 }
1488
1489 if( can_select && pad->GetNumber() == aPadNumber )
1490 return pad;
1491 }
1492
1493 return nullptr;
1494}
1495
1496
1497PAD* FOOTPRINT::GetPad( const VECTOR2I& aPosition, LSET aLayerMask )
1498{
1499 for( PAD* pad : m_pads )
1500 {
1501 // ... and on the correct layer.
1502 if( !( pad->GetLayerSet() & aLayerMask ).any() )
1503 continue;
1504
1505 if( pad->HitTest( aPosition ) )
1506 return pad;
1507 }
1508
1509 return nullptr;
1510}
1511
1512
1513unsigned FOOTPRINT::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1514{
1515 if( aIncludeNPTH )
1516 return m_pads.size();
1517
1518 unsigned cnt = 0;
1519
1520 for( PAD* pad : m_pads )
1521 {
1522 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1523 continue;
1524
1525 cnt++;
1526 }
1527
1528 return cnt;
1529}
1530
1531
1532unsigned FOOTPRINT::GetUniquePadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1533{
1534 std::set<wxString> usedNumbers;
1535
1536 // Create a set of used pad numbers
1537 for( PAD* pad : m_pads )
1538 {
1539 // Skip pads not on copper layers (used to build complex
1540 // solder paste shapes for instance)
1541 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none() )
1542 continue;
1543
1544 // Skip pads with no name, because they are usually "mechanical"
1545 // pads, not "electrical" pads
1546 if( pad->GetNumber().IsEmpty() )
1547 continue;
1548
1549 if( !aIncludeNPTH )
1550 {
1551 // skip NPTH
1552 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1553 continue;
1554 }
1555
1556 usedNumbers.insert( pad->GetNumber() );
1557 }
1558
1559 return usedNumbers.size();
1560}
1561
1562
1564{
1565 if( nullptr == a3DModel )
1566 return;
1567
1568 if( !a3DModel->m_Filename.empty() )
1569 m_3D_Drawings.push_back( *a3DModel );
1570}
1571
1572
1573// see footprint.h
1574INSPECT_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData,
1575 const std::vector<KICAD_T>& aScanTypes )
1576{
1577#if 0 && defined(DEBUG)
1578 std::cout << GetClass().mb_str() << ' ';
1579#endif
1580
1581 bool drawingsScanned = false;
1582
1583 for( KICAD_T scanType : aScanTypes )
1584 {
1585 switch( scanType )
1586 {
1587 case PCB_FOOTPRINT_T:
1588 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
1589 return INSPECT_RESULT::QUIT;
1590
1591 break;
1592
1593 case PCB_PAD_T:
1594 if( IterateForward<PAD*>( m_pads, inspector, testData, { scanType } )
1595 == INSPECT_RESULT::QUIT )
1596 {
1597 return INSPECT_RESULT::QUIT;
1598 }
1599
1600 break;
1601
1602 case PCB_ZONE_T:
1603 if( IterateForward<ZONE*>( m_zones, inspector, testData, { scanType } )
1604 == INSPECT_RESULT::QUIT )
1605 {
1606 return INSPECT_RESULT::QUIT;
1607 }
1608
1609 break;
1610
1611 case PCB_FIELD_T:
1612 if( IterateForward<PCB_FIELD*>( m_fields, inspector, testData, { scanType } )
1613 == INSPECT_RESULT::QUIT )
1614 {
1615 return INSPECT_RESULT::QUIT;
1616 }
1617
1618 break;
1619
1620 case PCB_TEXT_T:
1621 case PCB_DIM_ALIGNED_T:
1622 case PCB_DIM_LEADER_T:
1623 case PCB_DIM_CENTER_T:
1624 case PCB_DIM_RADIAL_T:
1626 case PCB_SHAPE_T:
1627 case PCB_TEXTBOX_T:
1628 if( !drawingsScanned )
1629 {
1630 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, aScanTypes )
1631 == INSPECT_RESULT::QUIT )
1632 {
1633 return INSPECT_RESULT::QUIT;
1634 }
1635
1636 drawingsScanned = true;
1637 }
1638
1639 break;
1640
1641 case PCB_GROUP_T:
1642 if( IterateForward<PCB_GROUP*>( m_groups, inspector, testData, { scanType } )
1643 == INSPECT_RESULT::QUIT )
1644 {
1645 return INSPECT_RESULT::QUIT;
1646 }
1647
1648 break;
1649
1650 default:
1651 break;
1652 }
1653 }
1654
1655 return INSPECT_RESULT::CONTINUE;
1656}
1657
1658
1659wxString FOOTPRINT::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
1660{
1661 wxString reference = GetReference();
1662
1663 if( reference.IsEmpty() )
1664 reference = _( "<no reference designator>" );
1665
1666 return wxString::Format( _( "Footprint %s" ), reference );
1667}
1668
1669
1671{
1672 return BITMAPS::module;
1673}
1674
1675
1677{
1678 return new FOOTPRINT( *this );
1679}
1680
1681
1682void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM*)>& aFunction ) const
1683{
1684 try
1685 {
1686 for( PCB_FIELD* field : m_fields )
1687 aFunction( static_cast<PCB_FIELD*>( field ) );
1688
1689 for( PAD* pad : m_pads )
1690 aFunction( static_cast<BOARD_ITEM*>( pad ) );
1691
1692 for( ZONE* zone : m_zones )
1693 aFunction( static_cast<ZONE*>( zone ) );
1694
1695 for( PCB_GROUP* group : m_groups )
1696 aFunction( static_cast<PCB_GROUP*>( group ) );
1697
1698 for( BOARD_ITEM* drawing : m_drawings )
1699 aFunction( static_cast<BOARD_ITEM*>( drawing ) );
1700 }
1701 catch( std::bad_function_call& )
1702 {
1703 wxFAIL_MSG( wxT( "Error running FOOTPRINT::RunOnChildren" ) );
1704 }
1705}
1706
1707
1708void FOOTPRINT::ViewGetLayers( int aLayers[], int& aCount ) const
1709{
1710 aCount = 2;
1711 aLayers[0] = LAYER_ANCHOR;
1712
1713 switch( m_layer )
1714 {
1715 default:
1716 wxASSERT_MSG( false, wxT( "Illegal layer" ) ); // do you really have footprints placed
1717 // on other layers?
1719
1720 case F_Cu:
1721 aLayers[1] = LAYER_FOOTPRINTS_FR;
1722 break;
1723
1724 case B_Cu:
1725 aLayers[1] = LAYER_FOOTPRINTS_BK;
1726 break;
1727 }
1728
1729 if( IsLocked() )
1730 aLayers[ aCount++ ] = LAYER_LOCKED_ITEM_SHADOW;
1731
1732 if( IsConflicting() )
1733 aLayers[ aCount++ ] = LAYER_CONFLICTS_SHADOW;
1734
1735 // If there are no pads, and only drawings on a silkscreen layer, then report the silkscreen
1736 // layer as well so that the component can be edited with the silkscreen layer
1737 bool f_silk = false, b_silk = false, non_silk = false;
1738
1739 for( BOARD_ITEM* item : m_drawings )
1740 {
1741 if( item->GetLayer() == F_SilkS )
1742 f_silk = true;
1743 else if( item->GetLayer() == B_SilkS )
1744 b_silk = true;
1745 else
1746 non_silk = true;
1747 }
1748
1749 if( ( f_silk || b_silk ) && !non_silk && m_pads.empty() )
1750 {
1751 if( f_silk )
1752 aLayers[ aCount++ ] = F_SilkS;
1753
1754 if( b_silk )
1755 aLayers[ aCount++ ] = B_SilkS;
1756 }
1757}
1758
1759
1760double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1761{
1762 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
1763 {
1764 // The locked shadow shape is shown only if the footprint itself is visible
1765 if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
1766 return 0.0;
1767
1768 if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
1769 return 0.0;
1770
1771 return std::numeric_limits<double>::max();
1772 }
1773
1774 if( aLayer == LAYER_CONFLICTS_SHADOW && IsConflicting() )
1775 {
1776 // The locked shadow shape is shown only if the footprint itself is visible
1777 if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
1778 return 0.0;
1779
1780 if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
1781 return 0.0;
1782
1783 return std::numeric_limits<double>::max();
1784 }
1785
1786 int layer = ( m_layer == F_Cu ) ? LAYER_FOOTPRINTS_FR :
1788
1789 // Currently this is only pertinent for the anchor layer; everything else is drawn from the
1790 // children.
1791 // The "good" value is experimentally chosen.
1792 #define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY 1.5
1793
1794 if( aView->IsLayerVisible( layer ) )
1796
1797 return std::numeric_limits<double>::max();
1798}
1799
1800
1802{
1803 BOX2I area = GetBoundingBox( true, true );
1804
1805 // Inflate in case clearance lines are drawn around pads, etc.
1806 if( const BOARD* board = GetBoard() )
1807 {
1808 int biggest_clearance = board->GetMaxClearanceValue();
1809 area.Inflate( biggest_clearance );
1810 }
1811
1812 return area;
1813}
1814
1815
1816bool FOOTPRINT::IsLibNameValid( const wxString & aName )
1817{
1818 const wxChar * invalids = StringLibNameInvalidChars( false );
1819
1820 if( aName.find_first_of( invalids ) != std::string::npos )
1821 return false;
1822
1823 return true;
1824}
1825
1826
1827const wxChar* FOOTPRINT::StringLibNameInvalidChars( bool aUserReadable )
1828{
1829 // This list of characters is also duplicated in validators.cpp and
1830 // lib_id.cpp
1831 // TODO: Unify forbidden character lists - Warning, invalid filename characters are not the same
1832 // as invalid LIB_ID characters. We will need to separate the FP filenames from FP names before this
1833 // can be unified
1834 static const wxChar invalidChars[] = wxT("%$<>\t\n\r\"\\/:");
1835 static const wxChar invalidCharsReadable[] = wxT("% $ < > 'tab' 'return' 'line feed' \\ \" / :");
1836
1837 if( aUserReadable )
1838 return invalidCharsReadable;
1839 else
1840 return invalidChars;
1841}
1842
1843
1844void FOOTPRINT::Move( const VECTOR2I& aMoveVector )
1845{
1846 VECTOR2I newpos = m_pos + aMoveVector;
1847 SetPosition( newpos );
1848}
1849
1850
1851void FOOTPRINT::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1852{
1853 EDA_ANGLE orientation = GetOrientation();
1854 EDA_ANGLE newOrientation = orientation + aAngle;
1855 VECTOR2I newpos = m_pos;
1856 RotatePoint( newpos, aRotCentre, aAngle );
1857 SetPosition( newpos );
1858 SetOrientation( newOrientation );
1859
1860 for( PCB_FIELD* field : m_fields )
1861 field->KeepUpright( orientation, newOrientation );
1862
1863 for( BOARD_ITEM* item : m_drawings )
1864 {
1865 if( item->Type() == PCB_TEXT_T )
1866 static_cast<PCB_TEXT*>( item )->KeepUpright( orientation, newOrientation );
1867 }
1868
1874}
1875
1876
1878{
1879 wxASSERT( aLayer == F_Cu || aLayer == B_Cu );
1880
1881 if( aLayer != GetLayer() )
1882 Flip( GetPosition(), true );
1883}
1884
1885
1886void FOOTPRINT::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
1887{
1888 // Move footprint to its final position:
1889 VECTOR2I finalPos = m_pos;
1890
1891 // Now Flip the footprint.
1892 // Flipping a footprint is a specific transform: it is not mirrored like a text.
1893 // We have to change the side, and ensure the footprint rotation is modified according to the
1894 // transform, because this parameter is used in pick and place files, and when updating the
1895 // footprint from library.
1896 // When flipped around the X axis (Y coordinates changed) orientation is negated
1897 // When flipped around the Y axis (X coordinates changed) orientation is 180 - old orient.
1898 // Because it is specific to a footprint, we flip around the X axis, and after rotate 180 deg
1899
1900 MIRROR( finalPos.y, aCentre.y );
1901
1902 SetPosition( finalPos );
1903
1904 // Flip layer
1906
1907 // Calculate the new orientation, and then clear it for pad flipping.
1908 EDA_ANGLE newOrientation = -m_orient;
1909 newOrientation.Normalize180();
1910 m_orient = ANGLE_0;
1911
1912 // Mirror fields to other side of board.
1913 for( PCB_FIELD* field : m_fields )
1914 field->Flip( m_pos, false );
1915
1916 // Mirror pads to other side of board.
1917 for( PAD* pad : m_pads )
1918 pad->Flip( m_pos, false );
1919
1920 // Now set the new orientation.
1921 m_orient = newOrientation;
1922
1923 // Mirror zones to other side of board.
1924 for( ZONE* zone : m_zones )
1925 zone->Flip( m_pos, false );
1926
1927 // Reverse mirror footprint graphics and texts.
1928 for( BOARD_ITEM* item : m_drawings )
1929 item->Flip( m_pos, false );
1930
1931 // Now rotate 180 deg if required
1932 if( aFlipLeftRight )
1933 Rotate( aCentre, ANGLE_180 );
1934
1939
1940 m_cachedHull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos );
1941
1943}
1944
1945
1947{
1948 VECTOR2I delta = aPos - m_pos;
1949
1950 m_pos += delta;
1951
1952 for( PCB_FIELD* field : m_fields )
1953 field->EDA_TEXT::Offset( delta );
1954
1955 for( PAD* pad : m_pads )
1956 pad->SetPosition( pad->GetPosition() + delta );
1957
1958 for( ZONE* zone : m_zones )
1959 zone->Move( delta );
1960
1961 for( BOARD_ITEM* item : m_drawings )
1962 item->Move( delta );
1963
1970}
1971
1972
1973void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector )
1974{
1975 /*
1976 * Move the reference point of the footprint
1977 * the footprints elements (pads, outlines, edges .. ) are moved
1978 * but:
1979 * - the footprint position is not modified.
1980 * - the relative (local) coordinates of these items are modified
1981 * - Draw coordinates are updated
1982 */
1983
1984 // Update (move) the relative coordinates relative to the new anchor point.
1985 VECTOR2I moveVector = aMoveVector;
1986 RotatePoint( moveVector, -GetOrientation() );
1987
1988 // Update field local coordinates
1989 for( PCB_FIELD* field : m_fields )
1990 field->Move( moveVector );
1991
1992 // Update the pad local coordinates.
1993 for( PAD* pad : m_pads )
1994 pad->Move( moveVector );
1995
1996 // Update the draw element coordinates.
1997 for( BOARD_ITEM* item : GraphicalItems() )
1998 item->Move( moveVector );
1999
2000 // Update the keepout zones
2001 for( ZONE* zone : Zones() )
2002 zone->Move( moveVector );
2003
2004 // Update the 3D models
2005 for( FP_3DMODEL& model : Models() )
2006 {
2007 model.m_Offset.x += pcbIUScale.IUTomm( moveVector.x );
2008 model.m_Offset.y -= pcbIUScale.IUTomm( moveVector.y );
2009 }
2010
2011 m_cachedBoundingBox.Move( moveVector );
2012 m_cachedVisibleBBox.Move( moveVector );
2013 m_cachedTextExcludedBBox.Move( moveVector );
2014 m_cachedHull.Move( moveVector );
2015}
2016
2017
2018void FOOTPRINT::SetOrientation( const EDA_ANGLE& aNewAngle )
2019{
2020 EDA_ANGLE angleChange = aNewAngle - m_orient; // change in rotation
2021
2022 m_orient = aNewAngle;
2024
2025 for( PCB_FIELD* field : m_fields )
2026 field->Rotate( GetPosition(), angleChange );
2027
2028 for( PAD* pad : m_pads )
2029 pad->Rotate( GetPosition(), angleChange );
2030
2031 for( ZONE* zone : m_zones )
2032 zone->Rotate( GetPosition(), angleChange );
2033
2034 for( BOARD_ITEM* item : m_drawings )
2035 item->Rotate( GetPosition(), angleChange );
2036
2041
2042 m_cachedHull.Rotate( angleChange, GetPosition() );
2043}
2044
2045
2047{
2048 FOOTPRINT* dupe = static_cast<FOOTPRINT*>( BOARD_ITEM::Duplicate() );
2049
2050 dupe->RunOnChildren( [&]( BOARD_ITEM* child )
2051 {
2052 const_cast<KIID&>( child->m_Uuid ) = KIID();
2053 });
2054
2055 return dupe;
2056}
2057
2058
2059BOARD_ITEM* FOOTPRINT::DuplicateItem( const BOARD_ITEM* aItem, bool aAddToFootprint )
2060{
2061 BOARD_ITEM* new_item = nullptr;
2062
2063 switch( aItem->Type() )
2064 {
2065 case PCB_PAD_T:
2066 {
2067 PAD* new_pad = new PAD( *static_cast<const PAD*>( aItem ) );
2068 const_cast<KIID&>( new_pad->m_Uuid ) = KIID();
2069
2070 if( aAddToFootprint )
2071 m_pads.push_back( new_pad );
2072
2073 new_item = new_pad;
2074 break;
2075 }
2076
2077 case PCB_ZONE_T:
2078 {
2079 ZONE* new_zone = new ZONE( *static_cast<const ZONE*>( aItem ) );
2080 const_cast<KIID&>( new_zone->m_Uuid ) = KIID();
2081
2082 if( aAddToFootprint )
2083 m_zones.push_back( new_zone );
2084
2085 new_item = new_zone;
2086 break;
2087 }
2088
2089 case PCB_FIELD_T:
2090 case PCB_TEXT_T:
2091 {
2092 PCB_TEXT* new_text = new PCB_TEXT( *static_cast<const PCB_TEXT*>( aItem ) );
2093 const_cast<KIID&>( new_text->m_Uuid ) = KIID();
2094
2095 if( aItem->Type() == PCB_FIELD_T )
2096 {
2097 switch( static_cast<const PCB_FIELD*>( aItem )->GetId() )
2098 {
2099 case REFERENCE_FIELD: new_text->SetText( wxT( "${REFERENCE}" ) ); break;
2100
2101 case VALUE_FIELD: new_text->SetText( wxT( "${VALUE}" ) ); break;
2102
2103 case DATASHEET_FIELD: new_text->SetText( wxT( "${DATASHEET}" ) ); break;
2104
2105 case FOOTPRINT_FIELD: new_text->SetText( wxT( "${FOOTPRINT}" ) ); break;
2106 }
2107 }
2108
2109 if( aAddToFootprint )
2110 Add( new_text );
2111
2112 new_item = new_text;
2113 break;
2114 }
2115
2116 case PCB_SHAPE_T:
2117 {
2118 PCB_SHAPE* new_shape = new PCB_SHAPE( *static_cast<const PCB_SHAPE*>( aItem ) );
2119 const_cast<KIID&>( new_shape->m_Uuid ) = KIID();
2120
2121 if( aAddToFootprint )
2122 Add( new_shape );
2123
2124 new_item = new_shape;
2125 break;
2126 }
2127
2128 case PCB_TEXTBOX_T:
2129 {
2130 PCB_TEXTBOX* new_textbox = new PCB_TEXTBOX( *static_cast<const PCB_TEXTBOX*>( aItem ) );
2131 const_cast<KIID&>( new_textbox->m_Uuid ) = KIID();
2132
2133 if( aAddToFootprint )
2134 Add( new_textbox );
2135
2136 new_item = new_textbox;
2137 break;
2138 }
2139
2140 case PCB_DIM_ALIGNED_T:
2141 case PCB_DIM_LEADER_T:
2142 case PCB_DIM_CENTER_T:
2143 case PCB_DIM_RADIAL_T:
2145 {
2146 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( aItem->Duplicate() );
2147
2148 if( aAddToFootprint )
2149 Add( dimension );
2150
2151 new_item = dimension;
2152 break;
2153 }
2154
2155 case PCB_GROUP_T:
2156 new_item = static_cast<const PCB_GROUP*>( aItem )->DeepDuplicate();
2157 break;
2158
2159 case PCB_FOOTPRINT_T:
2160 // Ignore the footprint itself
2161 break;
2162
2163 default:
2164 // Un-handled item for duplication
2165 wxFAIL_MSG( wxT( "Duplication not supported for items of class " ) + aItem->GetClass() );
2166 break;
2167 }
2168
2169 return new_item;
2170}
2171
2172
2173wxString FOOTPRINT::GetNextPadNumber( const wxString& aLastPadNumber ) const
2174{
2175 std::set<wxString> usedNumbers;
2176
2177 // Create a set of used pad numbers
2178 for( PAD* pad : m_pads )
2179 usedNumbers.insert( pad->GetNumber() );
2180
2181 // Pad numbers aren't technically reference designators, but the formatting is close enough
2182 // for these to give us what we need.
2183 wxString prefix = UTIL::GetRefDesPrefix( aLastPadNumber );
2184 int num = GetTrailingInt( aLastPadNumber );
2185
2186 while( usedNumbers.count( wxString::Format( wxT( "%s%d" ), prefix, num ) ) )
2187 num++;
2188
2189 return wxString::Format( wxT( "%s%d" ), prefix, num );
2190}
2191
2192
2194{
2195 // Auto-position reference and value
2196 BOX2I bbox = GetBoundingBox( false, false );
2197 bbox.Inflate( pcbIUScale.mmToIU( 0.2 ) ); // Gap between graphics and text
2198
2199 if( Reference().GetPosition() == VECTOR2I( 0, 0 ) )
2200 {
2204
2205 Reference().SetX( bbox.GetCenter().x );
2206 Reference().SetY( bbox.GetTop() - Reference().GetTextSize().y / 2 );
2207 }
2208
2209 if( Value().GetPosition() == VECTOR2I( 0, 0 ) )
2210 {
2214
2215 Value().SetX( bbox.GetCenter().x );
2216 Value().SetY( bbox.GetBottom() + Value().GetTextSize().y / 2 );
2217 }
2218}
2219
2220
2222{
2223 const wxString& refdes = GetReference();
2224
2225 SetReference( wxString::Format( wxT( "%s%i" ),
2226 UTIL::GetRefDesPrefix( refdes ),
2227 GetTrailingInt( refdes ) + aDelta ) );
2228}
2229
2230
2231// Calculate the area of a PolySet, polygons with hole are allowed.
2232static double polygonArea( SHAPE_POLY_SET& aPolySet )
2233{
2234 // Ensure all outlines are closed, before calculating the SHAPE_POLY_SET area
2235 for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
2236 {
2237 SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
2238 outline.SetClosed( true );
2239
2240 for( int jj = 0; jj < aPolySet.HoleCount( ii ); jj++ )
2241 aPolySet.Hole( ii, jj ).SetClosed( true );
2242 }
2243
2244 return aPolySet.Area();
2245}
2246
2247
2248double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLECTOR& aCollector )
2249{
2250 int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
2251 SHAPE_POLY_SET poly;
2252
2253 if( aItem->Type() == PCB_MARKER_T )
2254 {
2255 const PCB_MARKER* marker = static_cast<const PCB_MARKER*>( aItem );
2256 SHAPE_LINE_CHAIN markerShape;
2257
2258 marker->ShapeToPolygon( markerShape );
2259 return markerShape.Area();
2260 }
2261 else if( aItem->Type() == PCB_GROUP_T )
2262 {
2263 double combinedArea = 0.0;
2264
2265 for( BOARD_ITEM* member : static_cast<const PCB_GROUP*>( aItem )->GetItems() )
2266 combinedArea += GetCoverageArea( member, aCollector );
2267
2268 return combinedArea;
2269 }
2270 if( aItem->Type() == PCB_FOOTPRINT_T )
2271 {
2272 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
2273
2274 poly = footprint->GetBoundingHull();
2275 }
2276 else if( aItem->Type() == PCB_FIELD_T || aItem->Type() == PCB_TEXT_T )
2277 {
2278 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
2279
2280 text->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
2281 }
2282 else if( aItem->Type() == PCB_TEXTBOX_T )
2283 {
2284 const PCB_TEXTBOX* tb = static_cast<const PCB_TEXTBOX*>( aItem );
2285
2286 tb->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
2287 }
2288 else if( aItem->Type() == PCB_SHAPE_T )
2289 {
2290 // Approximate "linear" shapes with just their width squared, as we don't want to consider
2291 // a linear shape as being much bigger than another for purposes of selection filtering
2292 // just because it happens to be really long.
2293
2294 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
2295
2296 switch( shape->GetShape() )
2297 {
2298 case SHAPE_T::SEGMENT:
2299 case SHAPE_T::ARC:
2300 case SHAPE_T::BEZIER:
2301 return shape->GetWidth() * shape->GetWidth();
2302
2303 case SHAPE_T::RECTANGLE:
2304 case SHAPE_T::CIRCLE:
2305 case SHAPE_T::POLY:
2306 {
2307 if( !shape->IsFilled() )
2308 return shape->GetWidth() * shape->GetWidth();
2309
2311 }
2312
2313 default:
2315 }
2316 }
2317 else if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2318 {
2319 double width = static_cast<const PCB_TRACK*>( aItem )->GetWidth();
2320 return width * width;
2321 }
2322 else
2323 {
2325 }
2326
2327 return polygonArea( poly );
2328}
2329
2330
2331double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
2332{
2333 int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
2334
2335 SHAPE_POLY_SET footprintRegion( GetBoundingHull() );
2336 SHAPE_POLY_SET coveredRegion;
2337
2339
2340 TransformFPShapesToPolySet( coveredRegion, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF,
2342 true, /* include text */
2343 false, /* include shapes */
2344 false /* include private items */ );
2345
2346 for( int i = 0; i < aCollector.GetCount(); ++i )
2347 {
2348 const BOARD_ITEM* item = aCollector[i];
2349
2350 switch( item->Type() )
2351 {
2352 case PCB_FIELD_T:
2353 case PCB_TEXT_T:
2354 case PCB_TEXTBOX_T:
2355 case PCB_SHAPE_T:
2356 case PCB_TRACE_T:
2357 case PCB_ARC_T:
2358 case PCB_VIA_T:
2359 if( item->GetParent() != this )
2360 {
2361 item->TransformShapeToPolygon( coveredRegion, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
2362 ERROR_OUTSIDE );
2363 }
2364 break;
2365
2366 case PCB_FOOTPRINT_T:
2367 if( item != this )
2368 {
2369 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( item );
2370 coveredRegion.AddOutline( footprint->GetBoundingHull().Outline( 0 ) );
2371 }
2372 break;
2373
2374 default:
2375 break;
2376 }
2377 }
2378
2379 double footprintRegionArea = polygonArea( footprintRegion );
2380 double uncoveredRegionArea = footprintRegionArea - polygonArea( coveredRegion );
2381 double coveredArea = footprintRegionArea - uncoveredRegionArea;
2382 double ratio = ( coveredArea / footprintRegionArea );
2383
2384 // Test for negative ratio (should not occur).
2385 // better to be conservative (this will result in the disambiguate dialog)
2386 if( ratio < 0.0 )
2387 return 1.0;
2388
2389 return std::min( ratio, 1.0 );
2390}
2391
2392
2393std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2394{
2395 std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
2396
2397 // There are several possible interpretations here:
2398 // 1) the bounding box (without or without invisible items)
2399 // 2) just the pads and "edges" (ie: non-text graphic items)
2400 // 3) the courtyard
2401
2402 // We'll go with (2) for now, unless the caller is clearly looking for (3)
2403
2404 if( aLayer == F_CrtYd || aLayer == B_CrtYd )
2405 {
2406 const SHAPE_POLY_SET& courtyard = GetCourtyard( aLayer );
2407
2408 if( courtyard.OutlineCount() == 0 ) // malformed/empty polygon
2409 return shape;
2410
2411 shape->AddShape( new SHAPE_SIMPLE( courtyard.COutline( 0 ) ) );
2412 }
2413 else
2414 {
2415 for( PAD* pad : Pads() )
2416 shape->AddShape( pad->GetEffectiveShape( aLayer, aFlash )->Clone() );
2417
2418 for( BOARD_ITEM* item : GraphicalItems() )
2419 {
2420 if( item->Type() == PCB_SHAPE_T )
2421 shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->Clone() );
2422 }
2423 }
2424
2425 return shape;
2426}
2427
2428
2430{
2431 if( GetBoard() && GetBoard()->GetTimeStamp() > m_courtyard_cache_timestamp )
2432 const_cast<FOOTPRINT*>( this )->BuildCourtyardCaches();
2433
2434 if( IsBackLayer( aLayer ) )
2436 else
2438}
2439
2440
2442{
2446
2448
2449 // Build the courtyard area from graphic items on the courtyard.
2450 // Only PCB_SHAPE_T have meaning, graphic texts are ignored.
2451 // Collect items:
2452 std::vector<PCB_SHAPE*> list_front;
2453 std::vector<PCB_SHAPE*> list_back;
2454
2455 for( BOARD_ITEM* item : GraphicalItems() )
2456 {
2457 if( item->GetLayer() == B_CrtYd && item->Type() == PCB_SHAPE_T )
2458 list_back.push_back( static_cast<PCB_SHAPE*>( item ) );
2459
2460 if( item->GetLayer() == F_CrtYd && item->Type() == PCB_SHAPE_T )
2461 list_front.push_back( static_cast<PCB_SHAPE*>( item ) );
2462 }
2463
2464 if( !list_front.size() && !list_back.size() )
2465 return;
2466
2467 int maxError = pcbIUScale.mmToIU( 0.02 ); // max error for polygonization
2468 int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt
2469
2470 if( ConvertOutlineToPolygon( list_front, m_courtyard_cache_front, maxError, chainingEpsilon,
2471 true, aErrorHandler ) )
2472 {
2473 // Touching courtyards, or courtyards -at- the clearance distance are legal.
2475
2477 }
2478 else
2479 {
2481 }
2482
2483 if( ConvertOutlineToPolygon( list_back, m_courtyard_cache_back, maxError, chainingEpsilon,
2484 true, aErrorHandler ) )
2485 {
2486 // Touching courtyards, or courtyards -at- the clearance distance are legal.
2488
2490 }
2491 else
2492 {
2494 }
2495}
2496
2497
2498std::map<wxString, int> FOOTPRINT::MapPadNumbersToNetTieGroups() const
2499{
2500 std::map<wxString, int> padNumberToGroupIdxMap;
2501
2502 for( const PAD* pad : m_pads )
2503 padNumberToGroupIdxMap[ pad->GetNumber() ] = -1;
2504
2505 auto processPad =
2506 [&]( wxString aPad, int aGroup )
2507 {
2508 aPad.Trim( true ).Trim( false );
2509
2510 if( !aPad.IsEmpty() )
2511 padNumberToGroupIdxMap[ aPad ] = aGroup;
2512 };
2513
2514 for( int ii = 0; ii < (int) m_netTiePadGroups.size(); ++ii )
2515 {
2516 wxString group( m_netTiePadGroups[ ii ] );
2517 bool esc = false;
2518 wxString pad;
2519
2520 for( wxUniCharRef ch : group )
2521 {
2522 if( esc )
2523 {
2524 esc = false;
2525 pad.Append( ch );
2526 continue;
2527 }
2528
2529 switch( static_cast<unsigned char>( ch ) )
2530 {
2531 case '\\':
2532 esc = true;
2533 break;
2534
2535 case ',':
2536 processPad( pad, ii );
2537 pad.Clear();
2538 break;
2539
2540 default:
2541 pad.Append( ch );
2542 break;
2543 }
2544 }
2545
2546 processPad( pad, ii );
2547 }
2548
2549 return padNumberToGroupIdxMap;
2550}
2551
2552
2553std::vector<PAD*> FOOTPRINT::GetNetTiePads( PAD* aPad ) const
2554{
2555 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
2556 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
2557
2558 std::map<wxString, int> padToNetTieGroupMap = MapPadNumbersToNetTieGroups();
2559 int groupIdx = padToNetTieGroupMap[ aPad->GetNumber() ];
2560 std::vector<PAD*> otherPads;
2561
2562 if( groupIdx >= 0 )
2563 {
2564 for( PAD* pad : m_pads )
2565 {
2566 if( padToNetTieGroupMap[ pad->GetNumber() ] == groupIdx )
2567 otherPads.push_back( pad );
2568 }
2569 }
2570
2571 return otherPads;
2572}
2573
2574
2575void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxString& )>& aErrorHandler )
2576{
2577 int likelyAttr = ( GetLikelyAttribute() & ( FP_SMD | FP_THROUGH_HOLE ) );
2578 int setAttr = ( GetAttributes() & ( FP_SMD | FP_THROUGH_HOLE ) );
2579
2580 if( setAttr && likelyAttr && setAttr != likelyAttr )
2581 {
2582 wxString msg;
2583
2584 switch( likelyAttr )
2585 {
2586 case FP_THROUGH_HOLE:
2587 msg.Printf( _( "(expected 'Through hole'; actual '%s')" ), GetTypeName() );
2588 break;
2589 case FP_SMD:
2590 msg.Printf( _( "(expected 'SMD'; actual '%s')" ), GetTypeName() );
2591 break;
2592 }
2593
2594 if( aErrorHandler )
2595 (aErrorHandler)( msg );
2596 }
2597}
2598
2599
2600void FOOTPRINT::CheckPads( const std::function<void( const PAD*, int,
2601 const wxString& )>& aErrorHandler )
2602{
2603 if( aErrorHandler == nullptr )
2604 return;
2605
2606 for( PAD* pad: Pads() )
2607 {
2608 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
2609 {
2610 if( pad->GetDrillSizeX() < 1 || pad->GetDrillSizeY() < 1 )
2611 (aErrorHandler)( pad, DRCE_PAD_TH_WITH_NO_HOLE, wxEmptyString );
2612 }
2613
2614 if( pad->GetAttribute() == PAD_ATTRIB::PTH )
2615 {
2616 if( !pad->IsOnCopperLayer() )
2617 {
2618 (aErrorHandler)( pad, DRCE_PADSTACK, _( "(PTH pad has no copper layers)" ) );
2619 }
2620 else
2621 {
2622 LSET lset = pad->GetLayerSet() & LSET::AllCuMask();
2623 PCB_LAYER_ID layer = lset.Seq().at( 0 );
2624 SHAPE_POLY_SET padOutline;
2625
2626 pad->TransformShapeToPolygon( padOutline, layer, 0, ARC_HIGH_DEF, ERROR_INSIDE );
2627
2628 std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
2629 SHAPE_POLY_SET holeOutline;
2630
2631 TransformOvalToPolygon( holeOutline, hole->GetSeg().A, hole->GetSeg().B,
2632 hole->GetWidth(), ARC_HIGH_DEF, ERROR_INSIDE );
2633
2634 padOutline.BooleanSubtract( holeOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2635
2636 if( padOutline.IsEmpty() )
2637 aErrorHandler( pad, DRCE_PADSTACK, _( "(PTH pad's hole leaves no copper)" ) );
2638 }
2639 }
2640
2641 if( pad->GetAttribute() == PAD_ATTRIB::SMD )
2642 {
2643 if( pad->IsOnLayer( F_Cu ) && pad->IsOnLayer( B_Cu ) )
2644 {
2645 aErrorHandler( pad, DRCE_PADSTACK,
2646 _( "(SMD pad appears on both front and back copper)" ) );
2647 }
2648 else if( pad->IsOnLayer( F_Cu ) )
2649 {
2650 if( pad->IsOnLayer( B_Mask ) )
2651 {
2652 aErrorHandler( pad, DRCE_PADSTACK,
2653 _( "(SMD pad copper and mask layers don't match)" ) );
2654 }
2655 else if( pad->IsOnLayer( B_Paste ) )
2656 {
2657 aErrorHandler( pad, DRCE_PADSTACK,
2658 _( "(SMD pad copper and paste layers don't match)" ) );
2659 }
2660 }
2661 else if( pad->IsOnLayer( B_Cu ) )
2662 {
2663 if( pad->IsOnLayer( F_Mask ) )
2664 {
2665 aErrorHandler( pad, DRCE_PADSTACK,
2666 _( "(SMD pad copper and mask layers don't match)" ) );
2667 }
2668 else if( pad->IsOnLayer( F_Paste ) )
2669 {
2670 aErrorHandler( pad, DRCE_PADSTACK,
2671 _( "(SMD pad copper and paste layers don't match)" ) );
2672 }
2673 }
2674 }
2675 }
2676}
2677
2678
2679void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const PAD*,
2680 const VECTOR2I& )>& aErrorHandler )
2681{
2682 std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
2683
2684 for( PAD* pad : Pads() )
2685 {
2686 std::vector<PAD*> netTiePads = GetNetTiePads( pad );
2687
2688 for( PAD* other : Pads() )
2689 {
2690 if( other == pad || pad->SameLogicalPadAs( other ) )
2691 continue;
2692
2693 if( alg::contains( netTiePads, other ) )
2694 continue;
2695
2696 if( !( ( pad->GetLayerSet() & other->GetLayerSet() ) & LSET::AllCuMask() ).any() )
2697 continue;
2698
2699 // store canonical order so we don't collide in both directions (a:b and b:a)
2700 PAD* a = pad;
2701 PAD* b = other;
2702
2703 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
2704 std::swap( a, b );
2705
2706 if( checkedPairs.find( { a, b } ) == checkedPairs.end() )
2707 {
2708 checkedPairs[ { a, b } ] = 1;
2709
2710 if( pad->GetBoundingBox().Intersects( other->GetBoundingBox() ) )
2711 {
2712 VECTOR2I pos;
2713 SHAPE* padShape = pad->GetEffectiveShape().get();
2714 SHAPE* otherShape = other->GetEffectiveShape().get();
2715
2716 if( padShape->Collide( otherShape, 0, nullptr, &pos ) )
2717 aErrorHandler( pad, other, pos );
2718 }
2719 }
2720 }
2721 }
2722}
2723
2724
2725void FOOTPRINT::CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
2726 const BOARD_ITEM* bItem,
2727 const BOARD_ITEM* cItem,
2728 const VECTOR2I& )>& aErrorHandler )
2729{
2730 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
2731 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
2732
2733 std::map<wxString, int> padNumberToGroupIdxMap = MapPadNumbersToNetTieGroups();
2734
2735 // Now collect all the footprint items which are on copper layers
2736
2737 std::vector<BOARD_ITEM*> copperItems;
2738
2739 for( BOARD_ITEM* item : m_drawings )
2740 {
2741 if( item->IsOnCopperLayer() )
2742 {
2743 copperItems.push_back( item );
2744 }
2745 else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( item ) )
2746 {
2747 group->RunOnDescendants( [&]( BOARD_ITEM* descendent )
2748 {
2749 if( descendent->IsOnCopperLayer() )
2750 copperItems.push_back( descendent );
2751 } );
2752 }
2753 }
2754
2755 for( ZONE* zone : m_zones )
2756 {
2757 if( !zone->GetIsRuleArea() && zone->IsOnCopperLayer() )
2758 copperItems.push_back( zone );
2759 }
2760
2761 for( PCB_FIELD* field : m_fields )
2762 {
2763 if( field->IsOnCopperLayer() )
2764 copperItems.push_back( field );
2765 }
2766
2767 for( PCB_LAYER_ID layer : { F_Cu, In1_Cu, B_Cu } )
2768 {
2769 // Next, build a polygon-set for the copper on this layer. We don't really care about
2770 // nets here, we just want to end up with a set of outlines describing the distinct
2771 // copper polygons of the footprint.
2772
2773 SHAPE_POLY_SET copperOutlines;
2774 std::map<int, std::vector<const PAD*>> outlineIdxToPadsMap;
2775
2776 for( BOARD_ITEM* item : copperItems )
2777 {
2778 if( item->IsOnLayer( layer ) )
2779 {
2780 item->TransformShapeToPolygon( copperOutlines, layer, 0, ARC_HIGH_DEF,
2781 ERROR_OUTSIDE );
2782 }
2783 }
2784
2785 copperOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );
2786
2787 // Index each pad to the outline in the set that it is part of.
2788
2789 for( const PAD* pad : m_pads )
2790 {
2791 for( int ii = 0; ii < copperOutlines.OutlineCount(); ++ii )
2792 {
2793 if( pad->GetEffectiveShape( layer )->Collide( &copperOutlines.Outline( ii ), 0 ) )
2794 outlineIdxToPadsMap[ ii ].emplace_back( pad );
2795 }
2796 }
2797
2798 // Finally, ensure that each outline which contains multiple pads has all its pads
2799 // listed in an allowed-shorting group.
2800
2801 for( const auto& [ outlineIdx, pads ] : outlineIdxToPadsMap )
2802 {
2803 if( pads.size() > 1 )
2804 {
2805 const PAD* firstPad = pads[0];
2806 int firstGroupIdx = padNumberToGroupIdxMap[ firstPad->GetNumber() ];
2807
2808 for( size_t ii = 1; ii < pads.size(); ++ii )
2809 {
2810 const PAD* thisPad = pads[ii];
2811 int thisGroupIdx = padNumberToGroupIdxMap[ thisPad->GetNumber() ];
2812
2813 if( thisGroupIdx < 0 || thisGroupIdx != firstGroupIdx )
2814 {
2815 BOARD_ITEM* shortingItem = nullptr;
2816 VECTOR2I pos = ( firstPad->GetPosition() + thisPad->GetPosition() ) / 2;
2817
2818 pos = copperOutlines.Outline( outlineIdx ).NearestPoint( pos );
2819
2820 for( BOARD_ITEM* item : copperItems )
2821 {
2822 if( item->HitTest( pos, 1 ) )
2823 {
2824 shortingItem = item;
2825 break;
2826 }
2827 }
2828
2829 if( shortingItem )
2830 aErrorHandler( shortingItem, firstPad, thisPad, pos );
2831 else
2832 aErrorHandler( firstPad, thisPad, nullptr, pos );
2833 }
2834 }
2835 }
2836 }
2837 }
2838}
2839
2840
2841void FOOTPRINT::CheckNetTiePadGroups( const std::function<void( const wxString& )>& aErrorHandler )
2842{
2843 std::set<wxString> padNumbers;
2844 wxString msg;
2845
2846 auto ret = MapPadNumbersToNetTieGroups();
2847
2848 for( auto [ padNumber, _ ] : ret )
2849 {
2850 const PAD* pad = FindPadByNumber( padNumber );
2851
2852 if( !pad )
2853 {
2854 msg.Printf( _( "(net-tie pad group contains unknown pad number %s)" ), padNumber );
2855 aErrorHandler( msg );
2856 }
2857 else if( !padNumbers.insert( pad->GetNumber() ).second )
2858 {
2859 msg.Printf( _( "(pad %s appears in more than one net-tie pad group)" ), padNumber );
2860 aErrorHandler( msg );
2861 }
2862 }
2863}
2864
2865
2867{
2868 wxASSERT( aImage->Type() == PCB_FOOTPRINT_T );
2869
2870 std::swap( *this, *static_cast<FOOTPRINT*>( aImage ) );
2871}
2872
2873
2875{
2876 for( PAD* pad : Pads() )
2877 {
2878 if( pad->GetAttribute() != PAD_ATTRIB::SMD )
2879 return true;
2880 }
2881
2882 return false;
2883}
2884
2885
2886#define TEST( a, b ) { if( a != b ) return a < b; }
2887#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; }
2888
2889
2890bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* itemA, const BOARD_ITEM* itemB ) const
2891{
2892 TEST( itemA->Type(), itemB->Type() );
2893 TEST( itemA->GetLayer(), itemB->GetLayer() );
2894
2895 if( itemA->Type() == PCB_SHAPE_T )
2896 {
2897 const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( itemA );
2898 const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( itemB );
2899
2900 TEST( dwgA->GetShape(), dwgB->GetShape() );
2901
2902 TEST_PT( dwgA->GetStart(), dwgB->GetStart() );
2903 TEST_PT( dwgA->GetEnd(), dwgB->GetEnd() );
2904
2905 if( dwgA->GetShape() == SHAPE_T::ARC )
2906 {
2907 TEST_PT( dwgA->GetCenter(), dwgB->GetCenter() );
2908 }
2909 else if( dwgA->GetShape() == SHAPE_T::BEZIER )
2910 {
2911 TEST_PT( dwgA->GetBezierC1(), dwgB->GetBezierC1() );
2912 TEST_PT( dwgA->GetBezierC2(), dwgB->GetBezierC2() );
2913 }
2914 else if( dwgA->GetShape() == SHAPE_T::POLY )
2915 {
2917
2918 for( int ii = 0; ii < dwgA->GetPolyShape().TotalVertices(); ++ii )
2919 TEST_PT( dwgA->GetPolyShape().CVertex( ii ), dwgB->GetPolyShape().CVertex( ii ) );
2920 }
2921
2922 TEST( dwgA->GetWidth(), dwgB->GetWidth() );
2923 }
2924
2925 TEST( itemA->m_Uuid, itemB->m_Uuid ); // should be always the case for valid boards
2926
2927 return itemA < itemB;
2928}
2929
2930
2931bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) const
2932{
2933 if( aFirst->GetNumber() != aSecond->GetNumber() )
2934 return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
2935
2936 TEST_PT( aFirst->GetFPRelativePosition(), aSecond->GetFPRelativePosition() );
2937 TEST_PT( aFirst->GetSize(), aSecond->GetSize() );
2938 TEST( aFirst->GetShape(), aSecond->GetShape() );
2939 TEST( aFirst->GetLayerSet().Seq(), aSecond->GetLayerSet().Seq() );
2940
2941 TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
2942
2943 return aFirst < aSecond;
2944}
2945
2946
2947bool FOOTPRINT::cmp_zones::operator()( const ZONE* aFirst, const ZONE* aSecond ) const
2948{
2949 TEST( aFirst->GetAssignedPriority(), aSecond->GetAssignedPriority() );
2950 TEST( aFirst->GetLayerSet().Seq(), aSecond->GetLayerSet().Seq() );
2951
2952 TEST( aFirst->Outline()->TotalVertices(), aSecond->Outline()->TotalVertices() );
2953
2954 for( int ii = 0; ii < aFirst->Outline()->TotalVertices(); ++ii )
2955 TEST_PT( aFirst->Outline()->CVertex( ii ), aSecond->Outline()->CVertex( ii ) );
2956
2957 TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
2958
2959 return aFirst < aSecond;
2960}
2961
2962
2963#undef TEST
2964
2965
2967 int aClearance, int aMaxError, ERROR_LOC aErrorLoc,
2968 bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads,
2969 bool aSkipNonPlatedPads ) const
2970{
2971 for( const PAD* pad : m_pads )
2972 {
2973 if( !pad->FlashLayer( aLayer ) )
2974 continue;
2975
2976 VECTOR2I clearance( aClearance, aClearance );
2977
2978 switch( aLayer )
2979 {
2980 case F_Cu:
2981 if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
2982 continue;
2983
2984 if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
2985 continue;
2986
2987 break;
2988
2989 case B_Cu:
2990 if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
2991 continue;
2992
2993 if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
2994 continue;
2995
2996 break;
2997
2998 case F_Mask:
2999 case B_Mask:
3000 clearance.x += pad->GetSolderMaskExpansion();
3001 clearance.y += pad->GetSolderMaskExpansion();
3002 break;
3003
3004 case F_Paste:
3005 case B_Paste:
3006 clearance += pad->GetSolderPasteMargin();
3007 break;
3008
3009 default:
3010 break;
3011 }
3012
3013 // Our standard TransformShapeToPolygon() routines can't handle differing x:y clearance
3014 // values (which get generated when a relative paste margin is used with an oblong pad).
3015 // So we apply this huge hack and fake a larger pad to run the transform on.
3016 // Of course being a hack it falls down when dealing with custom shape pads (where the
3017 // size is only the size of the anchor), so for those we punt and just use clearance.x.
3018
3019 if( ( clearance.x < 0 || clearance.x != clearance.y )
3020 && pad->GetShape() != PAD_SHAPE::CUSTOM )
3021 {
3022 VECTOR2I dummySize = pad->GetSize() + clearance + clearance;
3023
3024 if( dummySize.x <= 0 || dummySize.y <= 0 )
3025 continue;
3026
3027 PAD dummy( *pad );
3028 dummy.SetSize( dummySize );
3029 dummy.TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
3030 }
3031 else
3032 {
3033 pad->TransformShapeToPolygon( aBuffer, aLayer, clearance.x, aMaxError, aErrorLoc );
3034 }
3035 }
3036}
3037
3038
3040 int aClearance, int aError, ERROR_LOC aErrorLoc,
3041 bool aIncludeText, bool aIncludeShapes,
3042 bool aIncludePrivateItems ) const
3043{
3044 std::vector<const PCB_TEXT*> texts; // List of PCB_TEXTs to convert
3045
3046 for( BOARD_ITEM* item : GraphicalItems() )
3047 {
3048 if( GetPrivateLayers().test( item->GetLayer() ) && !aIncludePrivateItems )
3049 continue;
3050
3051 if( item->Type() == PCB_TEXT_T && aIncludeText )
3052 {
3053 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
3054
3055 if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer && text->IsVisible() )
3056 texts.push_back( text );
3057 }
3058
3059 if( item->Type() == PCB_TEXTBOX_T && aIncludeText )
3060 {
3061 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
3062
3063 if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer && textbox->IsVisible() )
3064 {
3065 // border
3066 if( textbox->IsBorderEnabled() )
3067 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aError, aErrorLoc );
3068 // text
3069 textbox->TransformTextToPolySet( aBuffer, 0, aError, aErrorLoc );
3070 }
3071 }
3072
3073 if( item->Type() == PCB_SHAPE_T && aIncludeShapes )
3074 {
3075 const PCB_SHAPE* outline = static_cast<PCB_SHAPE*>( item );
3076
3077 if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer )
3078 outline->TransformShapeToPolygon( aBuffer, aLayer, 0, aError, aErrorLoc );
3079 }
3080 }
3081
3082 if( aIncludeText )
3083 {
3084 for( const PCB_FIELD* field : m_fields )
3085 {
3086 if( field->GetLayer() == aLayer && field->IsVisible() )
3087 texts.push_back( field );
3088 }
3089 }
3090
3091 for( const PCB_TEXT* text : texts )
3092 text->TransformTextToPolySet( aBuffer, aClearance, aError, aErrorLoc );
3093}
3094
3095
3096static struct FOOTPRINT_DESC
3097{
3099 {
3101
3102 if( zcMap.Choices().GetCount() == 0 )
3103 {
3104 zcMap.Undefined( ZONE_CONNECTION::INHERITED );
3105 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
3106 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
3107 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
3108 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
3109 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
3110 }
3111
3113
3114 if( layerEnum.Choices().GetCount() == 0 )
3115 {
3116 layerEnum.Undefined( UNDEFINED_LAYER );
3117
3118 for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
3119 layerEnum.Map( *seq, LSET::Name( *seq ) );
3120 }
3121
3122 wxPGChoices fpLayers; // footprints might be placed only on F.Cu & B.Cu
3123 fpLayers.Add( LSET::Name( F_Cu ), F_Cu );
3124 fpLayers.Add( LSET::Name( B_Cu ), B_Cu );
3125
3132
3133 auto layer = new PROPERTY_ENUM<FOOTPRINT, PCB_LAYER_ID>( _HKI( "Layer" ),
3135 layer->SetChoices( fpLayers );
3136 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
3137
3138 propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Orientation" ),
3140 PROPERTY_DISPLAY::PT_DEGREE ) );
3141
3142 const wxString groupFootprint = _HKI( "Fields" );
3143
3144 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Reference" ),
3146 groupFootprint );
3147 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Value" ),
3149 groupFootprint );
3150
3151 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library link" ),
3153 groupFootprint );
3154 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library description" ),
3156 groupFootprint );
3157 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Keywords" ),
3159 groupFootprint );
3160
3161 const wxString groupAttributes = _HKI( "Attributes" );
3162
3163 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Not in schematic" ),
3164 &FOOTPRINT::SetBoardOnly, &FOOTPRINT::IsBoardOnly ), groupAttributes );
3165 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude from position files" ),
3167 groupAttributes );
3168 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude from bill of materials" ),
3170 groupAttributes );
3171 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Do not populate" ),
3173 groupAttributes );
3174
3175 const wxString groupOverrides = _HKI( "Overrides" );
3176
3178 _HKI( "Exempt from courtyard requirement" ),
3180 groupOverrides );
3181 propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Clearance Override" ),
3183 PROPERTY_DISPLAY::PT_SIZE ),
3184 groupOverrides );
3185 propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Solderpaste Margin Override" ),
3187 PROPERTY_DISPLAY::PT_SIZE ),
3188 groupOverrides );
3190 _HKI( "Solderpaste Margin Ratio Override" ),
3193 groupOverrides );
3195 _HKI( "Zone Connection Style" ),
3197 groupOverrides );
3198 }
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:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:204
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:91
PCB_LAYER_ID m_layer
Definition: board_item.h:361
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:204
void SetX(int aX)
Definition: board_item.h:117
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
Definition: board_item.cpp:192
void SetY(int aY)
Definition: board_item.h:123
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:238
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:45
VECTOR2I GetFPRelativePosition() const
Definition: board_item.cpp:261
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:182
virtual bool IsOnCopperLayer() const
Definition: board_item.h:142
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:102
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:271
bool IsFootprintHolder() const
Find out if the board is being used to hold a single footprint for editing/viewing.
Definition: board.h:301
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:680
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:620
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:731
int GetTimeStamp() const
Definition: board.h:294
const Vec GetCenter() const
Definition: box2.h:196
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:270
coord_type GetTop() const
Definition: box2.h:195
coord_type GetHeight() const
Definition: box2.h:189
coord_type GetWidth() const
Definition: box2.h:188
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:112
bool Contains(const Vec &aPoint) const
Definition: box2.h:142
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:507
coord_type GetBottom() const
Definition: box2.h:191
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:589
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:288
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:258
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
const KIID m_Uuid
Definition: eda_item.h:482
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:125
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:127
virtual wxString GetClass() const =0
Return the class name.
void ClearEditFlags()
Definition: eda_item.h:137
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:126
const VECTOR2I & GetBezierC2() const
Definition: eda_shape.h:183
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:256
bool IsFilled() const
Definition: eda_shape.h:91
SHAPE_T GetShape() const
Definition: eda_shape.h:117
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:149
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:124
const VECTOR2I & GetBezierC1() const
Definition: eda_shape.h:180
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:257
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:226
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:180
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:202
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:249
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:646
static ENUM_MAP< T > & Instance()
Definition: property.h:640
ENUM_MAP & Undefined(T aValue)
Definition: property.h:653
wxPGChoices & Choices()
Definition: property.h:689
bool FixUuids()
Old footprints do not always have a valid UUID (some can be set to null uuid) However null UUIDs,...
Definition: footprint.cpp:372
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:2679
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:1946
LIB_ID m_fpid
Definition: footprint.h:950
wxString GetLibDescription() const
Definition: footprint.h:236
KIID_PATH m_path
Definition: footprint.h:986
bool IsBoardOnly() const
Definition: footprint.h:683
BOX2I m_cachedTextExcludedBBox
Definition: footprint.h:969
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:2600
bool IsDNP() const
Definition: footprint.h:719
std::vector< PAD * > GetNetTiePads(PAD *aPad) const
Definition: footprint.cpp:2553
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
Definition: footprint.cpp:628
EDA_ANGLE GetOrientation() const
Definition: footprint.h:209
bool HasFieldByName(const wxString &aFieldName) const
Definition: footprint.cpp:283
ZONES & Zones()
Definition: footprint.h:194
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:767
ZONE_CONNECTION m_zoneConnection
Definition: footprint.h:978
BOX2I m_cachedBoundingBox
Definition: footprint.h:965
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
Definition: footprint.cpp:2248
bool IsExcludedFromBOM() const
Definition: footprint.h:701
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2018
PCB_FIELD * GetFieldByName(const wxString &aFieldName)
Return a field in this symbol.
Definition: footprint.cpp:294
void SetDNP(bool aDNP=true)
Definition: footprint.h:720
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:1816
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
Definition: footprint.cpp:1513
const BOX2I GetLayerBoundingBox(LSET aLayers) const
Return the bounding box of the footprint on a given set of layers.
Definition: footprint.cpp:1113
PCB_FIELD * AddField(const PCB_FIELD &aField)
Add a field to the symbol.
Definition: footprint.cpp:333
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:2725
void SetExcludedFromBOM(bool aExclude=true)
Definition: footprint.h:702
int m_fpStatus
Definition: footprint.h:952
PCB_FIELDS GetFields()
Return a vector of fields from the symbol.
Definition: footprint.h:650
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: footprint.cpp:1760
SHAPE_POLY_SET m_cachedHull
Definition: footprint.h:971
int GetLocalClearance() const
Definition: footprint.h:257
void SetAllowMissingCourtyard(bool aAllow=true)
Definition: footprint.h:711
int m_localSolderPasteMargin
Definition: footprint.h:981
int m_attributes
Definition: footprint.h:951
void ApplyDefaultSettings(const BOARD &board, bool aStyleFields, bool aStyleTextAndGraphics)
Apply default board settings to the footprint field text properties.
Definition: footprint.cpp:355
std::vector< FP_3DMODEL > m_3D_Drawings
Definition: footprint.h:995
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:2331
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:2059
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:2393
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: footprint.cpp:1670
double m_localSolderPasteMarginRatio
Definition: footprint.h:982
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:2966
wxArrayString * m_initial_comments
Definition: footprint.h:996
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1676
BOX2I m_cachedVisibleBBox
Definition: footprint.h:967
double GetLocalSolderPasteMarginRatio() const
Definition: footprint.h:271
BOX2I GetFpPadsLocalBbox() const
Return the bounding box containing pads when the footprint is on the front side, orientation 0,...
Definition: footprint.cpp:937
int m_visibleBBoxCacheTimeStamp
Definition: footprint.h:968
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:592
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: footprint.cpp:1851
void SetExcludedFromPosFiles(bool aExclude=true)
Definition: footprint.h:693
int m_localClearance
Definition: footprint.h:979
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: footprint.h:272
void SetOrientationDegrees(double aOrientation)
Definition: footprint.h:221
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2498
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:1973
FOOTPRINT & operator=(const FOOTPRINT &aOther)
Definition: footprint.cpp:504
int m_arflag
Definition: footprint.h:991
double GetOrientationDegrees() const
Definition: footprint.h:225
BOARD_ITEM * Duplicate() const override
Create a copy of this BOARD_ITEM.
Definition: footprint.cpp:2046
void SetLocalSolderPasteMargin(int aMargin)
Definition: footprint.h:269
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:1574
int GetAttributes() const
Definition: footprint.h:277
int m_localSolderMaskMargin
Definition: footprint.h:980
FOOTPRINT(BOARD *parent)
Definition: footprint.cpp:57
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:218
LSET GetPrivateLayers() const
Definition: footprint.h:125
wxString GetFPIDAsString() const
Definition: footprint.h:233
wxString GetValueAsString() const
Definition: footprint.h:586
bool AllowMissingCourtyard() const
Definition: footprint.h:710
bool IsFlipped() const
Definition: footprint.h:351
PADS & Pads()
Definition: footprint.h:188
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:1158
int GetLocalSolderPasteMargin() const
Definition: footprint.h:268
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:3039
wxString GetTypeName() const
Get the type of footprint.
Definition: footprint.cpp:925
DRAWINGS m_drawings
Definition: footprint.h:943
PCB_FIELD * GetFieldById(int aFieldId)
Return a field in this symbol.
Definition: footprint.cpp:272
SHAPE_POLY_SET m_courtyard_cache_back
Definition: footprint.h:1000
int m_textExcludedBBoxCacheTimeStamp
Definition: footprint.h:970
void SetLocalClearance(int aClearance)
Definition: footprint.h:258
const LIB_ID & GetFPID() const
Definition: footprint.h:230
void SetReference(const wxString &aReference)
Definition: footprint.h:562
bool IsLocked() const override
Definition: footprint.h:365
bool IsExcludedFromPosFiles() const
Definition: footprint.h:692
void SetLayerAndFlip(PCB_LAYER_ID aLayer)
Used as Layer property setter – performs a flip if necessary to set the footprint layer.
Definition: footprint.cpp:1877
ZONES m_zones
Definition: footprint.h:945
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with PCB_TEXTs.
Definition: footprint.cpp:318
int m_hullCacheTimeStamp
Definition: footprint.h:972
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
Definition: footprint.cpp:1532
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: footprint.cpp:1801
LSET m_privateLayers
Definition: footprint.h:993
int GetLikelyAttribute() const
Returns the most likely attribute based on pads Either FP_THROUGH_HOLE/FP_SMD/OTHER(0)
Definition: footprint.cpp:873
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: footprint.cpp:1844
wxString m_libDescription
Definition: footprint.h:984
bool HitTestOnLayer(const VECTOR2I &aPosition, PCB_LAYER_ID aLayer, int aAccuracy=0) const
Test if the point hits one or more of the footprint elements on a given layer.
Definition: footprint.cpp:1345
VECTOR2I m_pos
Definition: footprint.h:949
std::vector< wxString > m_netTiePadGroups
Definition: footprint.h:976
PAD * GetPad(const VECTOR2I &aPosition, LSET aLayerMask=LSET::AllLayersMask())
Get a pad at aPosition on aLayerMask in the footprint.
Definition: footprint.cpp:1497
void Add3DModel(FP_3DMODEL *a3DModel)
Add a3DModel definition to the end of the 3D model list.
Definition: footprint.cpp:1563
void SetValue(const wxString &aValue)
Definition: footprint.h:583
GROUPS m_groups
Definition: footprint.h:946
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:1240
PCB_FIELD & Reference()
Definition: footprint.h:593
wxString GetReferenceAsString() const
Definition: footprint.h:565
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars for this footprint.
Definition: footprint.cpp:614
SHAPE_POLY_SET m_courtyard_cache_front
Definition: footprint.h:999
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:705
void AutoPositionFields()
Position Reference and Value fields at the top and bottom of footprint's bounding box.
Definition: footprint.cpp:2193
wxString m_keywords
Definition: footprint.h:985
void ClearAllNets()
Clear (i.e.
Definition: footprint.cpp:696
void SetZoneConnection(ZONE_CONNECTION aType)
Definition: footprint.h:274
bool HasThroughHolePads() const
Definition: footprint.cpp:2874
void BuildCourtyardCaches(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:2441
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: footprint.cpp:1314
wxString GetFieldText(const wxString &aFieldName) const
Search for a field named aFieldName and returns text associated with this field.
Definition: footprint.cpp:306
EDA_ANGLE m_orient
Definition: footprint.h:948
bool HitTestAccurate(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if a point is inside the bounding polygon of the footprint.
Definition: footprint.cpp:1420
wxString GetClass() const override
Return the class name.
Definition: footprint.h:816
void IncrementReference(int aDelta)
Bump the current reference by aDelta.
Definition: footprint.cpp:2221
KIID m_link
Definition: footprint.h:992
void RemoveField(const wxString &aFieldName)
Remove a user field from the footprint.
Definition: footprint.cpp:342
GROUPS & Groups()
Definition: footprint.h:197
bool IsConflicting() const
Definition: footprint.cpp:608
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:202
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:1682
PCB_FIELDS & Fields()
Definition: footprint.h:185
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:1827
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1886
double GetArea(int aPadding=0) const
Definition: footprint.cpp:863
ZONE_CONNECTION GetZoneConnection() const
Definition: footprint.h:275
const wxString & GetReference() const
Definition: footprint.h:556
void CheckNetTiePadGroups(const std::function< void(const wxString &)> &aErrorHandler)
Sanity check net-tie pad groups.
Definition: footprint.cpp:2841
void SetBoardOnly(bool aIsBoardOnly=true)
Definition: footprint.h:684
PCB_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: footprint.cpp:260
timestamp_t m_lastEditTime
Definition: footprint.h:990
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2429
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:1708
int m_fileFormatVersionAtLoad
Definition: footprint.h:953
wxString GetKeywords() const
Definition: footprint.h:239
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:2575
PADS m_pads
Definition: footprint.h:944
virtual void swapData(BOARD_ITEM *aImage) override
Definition: footprint.cpp:2866
wxString GetNextPadNumber(const wxString &aLastPadName) const
Return the next available pad number in the footprint.
Definition: footprint.cpp:2173
int m_courtyard_cache_timestamp
Definition: footprint.h:1001
int m_boundingBoxCacheTimeStamp
Definition: footprint.h:966
VECTOR2I GetPosition() const override
Definition: footprint.h:206
DRAWINGS & GraphicalItems()
Definition: footprint.h:191
PCB_FIELDS m_fields
Definition: footprint.h:942
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:1413
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
Definition: footprint.cpp:1659
PAD * FindPadByNumber(const wxString &aPadNumber, PAD *aSearchAfterMe=nullptr) const
Return a PAD with a matching number.
Definition: footprint.cpp:1477
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:962
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:100
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:290
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:409
Definition: kiid.h:49
wxString GetUniStringLibId() const
Definition: lib_id.h:148
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition: lib_id.h:112
const wxString GetUniStringLibNickname() const
Definition: lib_id.h:88
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:513
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:552
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
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:391
Definition: pad.h:58
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:369
const wxString & GetNumber() const
Definition: pad.h:130
VECTOR2I GetPosition() const override
Definition: pad.h:197
PAD_SHAPE GetShape() const
Definition: pad.h:189
const VECTOR2I & GetSize() const
Definition: pad.h:243
Abstract dimension API.
bool IsMandatoryField() const
Definition: pcb_field.h:72
int GetId() const
Definition: pcb_field.h:112
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:87
bool AddItem(BOARD_ITEM *aItem)
Add item to group.
Definition: pcb_group.cpp:72
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:72
int GetWidth() const override
Definition: pcb_shape.cpp:149
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:568
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:67
bool IsBorderEnabled() const
Disables the border, this is done by changing the stroke internally.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
bool IsVisible() const override
Definition: pcb_textbox.h:85
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: pcb_text.cpp:78
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_text.cpp:284
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:74
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:76
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & 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 RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
@ CHAMFER_ACUTE_CORNERS
Acute angles are chamfered.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
double Area()
Return the area of this poly set.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
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
Return total number of vertices stored in the set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
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)
Return the reference to aIndex-th outline in the set.
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
int OutlineCount() const
Return the number of outlines in the set.
void Move(const VECTOR2I &aVector) override
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:42
An abstract shape on 2D plane.
Definition: shape.h:126
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:181
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
SHAPE_POLY_SET * Outline()
Definition: zone.h:325
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:129
unsigned GetAssignedPriority() const
Definition: zone.h:119
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, bool aAllowUseArcsInPolygons)
Function ConvertOutlineToPolygon build a polygon set (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:441
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:437
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 TEST_PT(a, b)
#define TEST(a, b)
#define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY
static struct FOOTPRINT_DESC _FOOTPRINT_DESC
static double polygonArea(SHAPE_POLY_SET &aPolySet)
Definition: footprint.cpp:2232
INCLUDE_NPTH_T
Definition: footprint.h:60
@ DO_NOT_INCLUDE_NPTH
Definition: footprint.h:61
@ FP_SMD
Definition: footprint.h:73
@ FP_DNP
Definition: footprint.h:80
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:74
@ FP_BOARD_ONLY
Definition: footprint.h:76
@ FP_EXCLUDE_FROM_BOM
Definition: footprint.h:75
@ FP_THROUGH_HOLE
Definition: footprint.h:72
#define FP_is_PLACED
In autoplace: footprint automatically placed.
Definition: footprint.h:360
#define FP_PADS_are_LOCKED
Definition: footprint.h:362
@ FRAME_FOOTPRINT_VIEWER
Definition: frame_type.h:43
@ FRAME_FOOTPRINT_CHOOSER
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:148
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:944
@ LAYER_LOCKED_ITEM_SHADOW
shadow layer for locked items
Definition: layer_ids.h:240
@ LAYER_CONFLICTS_SHADOW
shadow layer for items flagged conficting
Definition: layer_ids.h:242
@ LAYER_FOOTPRINTS_FR
show footprints on front
Definition: layer_ids.h:209
@ LAYER_FP_REFERENCES
show footprints references (when texts are visible)
Definition: layer_ids.h:212
@ LAYER_FP_TEXT
Definition: layer_ids.h:199
@ LAYER_FOOTPRINTS_BK
show footprints on back
Definition: layer_ids.h:210
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:202
@ LAYER_FP_VALUES
show footprints values (when texts are visible)
Definition: layer_ids.h:211
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:118
@ Dwgs_User
Definition: layer_ids.h:110
@ F_Paste
Definition: layer_ids.h:102
@ Cmts_User
Definition: layer_ids.h:111
@ B_Mask
Definition: layer_ids.h:107
@ B_Cu
Definition: layer_ids.h:96
@ Eco1_User
Definition: layer_ids.h:112
@ F_Mask
Definition: layer_ids.h:108
@ B_Paste
Definition: layer_ids.h:101
@ F_Fab
Definition: layer_ids.h:121
@ F_SilkS
Definition: layer_ids.h:105
@ B_CrtYd
Definition: layer_ids.h:117
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:113
@ In1_Cu
Definition: layer_ids.h:66
@ B_SilkS
Definition: layer_ids.h:104
@ F_Cu
Definition: layer_ids.h:65
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:426
Class to handle a set of BOARD_ITEMs.
#define TYPE_HASH(x)
Definition: property.h:64
#define NO_SETTER(owner, type)
Definition: property.h:751
#define REGISTER_TYPE(x)
Definition: property_mgr.h:356
Collection of utility functions for component reference designators (refdes)
std::vector< FAB_LAYER_COLOR > dummy
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.
wxString UnescapeString(const wxString &aSource)
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:2890
bool operator()(const PAD *aFirst, const PAD *aSecond) const
Definition: footprint.cpp:2931
bool operator()(const ZONE *aFirst, const ZONE *aSecond) const
Definition: footprint.cpp:2947
MANDATORY_FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ DATASHEET_FIELD
name of datasheet
@ FOOTPRINT_FIELD
Field Name Module PCB, i.e. "16DIP300".
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ MANDATORY_FIELDS
The first 5 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
constexpr int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_CENTER
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition: typeinfo.h:252
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:102
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:99
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:94
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:100
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:107
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:92
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:104
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:96
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:98
@ PCB_BITMAP_T
class PCB_BITMAP, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:95
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:97
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:93
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
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:588