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