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