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