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 The 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 <wx/log.h>
31#include <wx/debug.h>
32
33#include <bitmaps.h>
34#include <board.h>
36#include <confirm.h>
41#include <drc/drc_item.h>
42#include <embedded_files.h>
43#include <font/font.h>
44#include <font/outline_font.h>
45#include <footprint.h>
50#include <i18n_utility.h>
51#include <lset.h>
52#include <macros.h>
53#include <pad.h>
54#include <pcb_dimension.h>
55#include <pcb_edit_frame.h>
56#include <pcb_field.h>
57#include <pcb_group.h>
58#include <pcb_marker.h>
59#include <pcb_point.h>
60#include <pcb_reference_image.h>
61#include <pcb_textbox.h>
62#include <pcb_track.h>
63#include <pcb_barcode.h>
64#include <refdes_utils.h>
65#include <string_utils.h>
66#include <view/view.h>
67#include <zone.h>
68
69#include <google/protobuf/any.pb.h>
70#include <api/board/board_types.pb.h>
71#include <api/api_enums.h>
72#include <api/api_utils.h>
73#include <api/api_pcb_utils.h>
74
75
79 m_attributes( 0 ),
91 m_lastEditTime( 0 ),
92 m_arflag( 0 ),
93 m_link( 0 ),
94 m_initial_comments( nullptr ),
96{
97 m_layer = F_Cu;
98 m_embedFonts = false;
99
100 auto addField =
101 [this]( FIELD_T id, PCB_LAYER_ID layer, bool visible )
102 {
103 PCB_FIELD* field = new PCB_FIELD( this, id );
104 field->SetLayer( layer );
105 field->SetVisible( visible );
106 m_fields.push_back( field );
107 };
108
109 addField( FIELD_T::REFERENCE, F_SilkS, true );
110 addField( FIELD_T::VALUE, F_Fab, true );
111 addField( FIELD_T::DATASHEET, F_Fab, false );
112 addField( FIELD_T::DESCRIPTION, F_Fab, false );
113
114 m_3D_Drawings.clear();
115}
116
117
118FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
119 BOARD_ITEM_CONTAINER( aFootprint ),
120 EMBEDDED_FILES( aFootprint ),
122{
123 m_orient = aFootprint.m_orient;
124 m_pos = aFootprint.m_pos;
125 m_fpid = aFootprint.m_fpid;
126 m_attributes = aFootprint.m_attributes;
127 m_fpStatus = aFootprint.m_fpStatus;
129
134 m_cachedHull = aFootprint.m_cachedHull;
136
142
144 m_clearance = aFootprint.m_clearance;
148
149 m_stackupLayers = aFootprint.m_stackupLayers;
150 m_stackupMode = aFootprint.m_stackupMode;
151
153 m_keywords = aFootprint.m_keywords;
154 m_path = aFootprint.m_path;
155 m_sheetname = aFootprint.m_sheetname;
156 m_sheetfile = aFootprint.m_sheetfile;
157 m_filters = aFootprint.m_filters;
158 m_lastEditTime = aFootprint.m_lastEditTime;
159 m_arflag = 0;
160 m_link = aFootprint.m_link;
161 m_privateLayers = aFootprint.m_privateLayers;
162
163 m_3D_Drawings = aFootprint.m_3D_Drawings;
164 m_initial_comments = aFootprint.m_initial_comments ? new wxArrayString( *aFootprint.m_initial_comments )
165 : nullptr;
166
167 m_embedFonts = aFootprint.m_embedFonts;
168
169 std::map<EDA_ITEM*, EDA_ITEM*> ptrMap;
170
171 // Copy fields
172 for( PCB_FIELD* field : aFootprint.m_fields )
173 {
174 if( field->IsMandatory() )
175 {
176 PCB_FIELD* existingField = GetField( field->GetId() );
177 ptrMap[field] = existingField;
178 *existingField = *field;
179 existingField->SetParent( this );
180 }
181 else
182 {
183 PCB_FIELD* newField = static_cast<PCB_FIELD*>( field->Clone() );
184 ptrMap[field] = newField;
185 Add( newField );
186 }
187 }
188
189 // Copy pads
190 for( PAD* pad : aFootprint.Pads() )
191 {
192 PAD* newPad = static_cast<PAD*>( pad->Clone() );
193 ptrMap[ pad ] = newPad;
194 Add( newPad, ADD_MODE::APPEND ); // Append to ensure indexes are identical
195 }
196
197 // Copy zones
198 for( ZONE* zone : aFootprint.Zones() )
199 {
200 ZONE* newZone = static_cast<ZONE*>( zone->Clone() );
201 ptrMap[ zone ] = newZone;
202 Add( newZone, ADD_MODE::APPEND ); // Append to ensure indexes are identical
203
204 // Ensure the net info is OK and especially uses the net info list
205 // living in the current board
206 // Needed when copying a fp from fp editor that has its own board
207 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
208 newZone->SetNetCode( -1 );
209 }
210
211 // Copy drawings
212 for( BOARD_ITEM* item : aFootprint.GraphicalItems() )
213 {
214 BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
215 ptrMap[ item ] = newItem;
216 Add( newItem, ADD_MODE::APPEND ); // Append to ensure indexes are identical
217 }
218
219 // Copy groups
220 for( PCB_GROUP* group : aFootprint.Groups() )
221 {
222 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
223 ptrMap[ group ] = newGroup;
224 Add( newGroup, ADD_MODE::APPEND ); // Append to ensure indexes are identical
225 }
226
227 for( PCB_POINT* point : aFootprint.Points() )
228 {
229 PCB_POINT* newPoint = static_cast<PCB_POINT*>( point->Clone() );
230 ptrMap[ point ] = newPoint;
231 Add( newPoint, ADD_MODE::APPEND ); // Append to ensure indexes are identical
232 }
233
234 // Rebuild groups
235 for( PCB_GROUP* group : aFootprint.Groups() )
236 {
237 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( ptrMap[ group ] );
238
239 newGroup->GetItems().clear();
240
241 for( EDA_ITEM* member : group->GetItems() )
242 {
243 if( ptrMap.count( member ) )
244 newGroup->AddItem( ptrMap[ member ] );
245 }
246 }
247
248 for( auto& [ name, file ] : aFootprint.EmbeddedFileMap() )
250}
251
252
254 BOARD_ITEM_CONTAINER( aFootprint )
255{
256 *this = std::move( aFootprint );
257}
258
259
261{
262 // Clean up the owned elements
263 delete m_initial_comments;
264
265 for( PCB_FIELD* f : m_fields )
266 delete f;
267
268 m_fields.clear();
269
270 for( PAD* p : m_pads )
271 delete p;
272
273 m_pads.clear();
274
275 for( ZONE* zone : m_zones )
276 delete zone;
277
278 m_zones.clear();
279
280 for( PCB_GROUP* group : m_groups )
281 delete group;
282
283 m_groups.clear();
284
285 for( PCB_POINT* point : m_points )
286 delete point;
287
288 m_points.clear();
289
290 for( BOARD_ITEM* d : m_drawings )
291 delete d;
292
293 m_drawings.clear();
294
295 if( BOARD* board = GetBoard() )
296 board->IncrementTimeStamp();
297}
298
299
300void FOOTPRINT::Serialize( google::protobuf::Any &aContainer ) const
301{
302 using namespace kiapi::board;
303 types::FootprintInstance footprint;
304
305 footprint.mutable_id()->set_value( m_Uuid.AsStdString() );
306 footprint.mutable_position()->set_x_nm( GetPosition().x );
307 footprint.mutable_position()->set_y_nm( GetPosition().y );
308 footprint.mutable_orientation()->set_value_degrees( GetOrientationDegrees() );
309 footprint.set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( GetLayer() ) );
310 footprint.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
311 : kiapi::common::types::LockedState::LS_UNLOCKED );
312
313 google::protobuf::Any buf;
315 buf.UnpackTo( footprint.mutable_reference_field() );
317 buf.UnpackTo( footprint.mutable_value_field() );
319 buf.UnpackTo( footprint.mutable_datasheet_field() );
321 buf.UnpackTo( footprint.mutable_description_field() );
322
323 types::FootprintAttributes* attrs = footprint.mutable_attributes();
324
325 attrs->set_not_in_schematic( IsBoardOnly() );
326 attrs->set_exclude_from_position_files( IsExcludedFromPosFiles() );
327 attrs->set_exclude_from_bill_of_materials( IsExcludedFromBOM() );
328 attrs->set_exempt_from_courtyard_requirement( AllowMissingCourtyard() );
329 attrs->set_do_not_populate( IsDNP() );
330 attrs->set_allow_soldermask_bridges( AllowSolderMaskBridges() );
331
333 attrs->set_mounting_style( types::FootprintMountingStyle::FMS_THROUGH_HOLE );
334 else if( m_attributes & FP_SMD )
335 attrs->set_mounting_style( types::FootprintMountingStyle::FMS_SMD );
336 else
337 attrs->set_mounting_style( types::FootprintMountingStyle::FMS_UNSPECIFIED );
338
339 types::Footprint* def = footprint.mutable_definition();
340
341 def->mutable_id()->CopyFrom( kiapi::common::LibIdToProto( GetFPID() ) );
342 // anchor?
343 def->mutable_attributes()->set_description( GetLibDescription().ToStdString() );
344 def->mutable_attributes()->set_keywords( GetKeywords().ToStdString() );
345
346 // TODO: serialize library mandatory fields
347
348 types::FootprintDesignRuleOverrides* overrides = footprint.mutable_overrides();
349
350 if( GetLocalClearance().has_value() )
351 overrides->mutable_copper_clearance()->set_value_nm( *GetLocalClearance() );
352
353 if( GetLocalSolderMaskMargin().has_value() )
354 overrides->mutable_solder_mask()->mutable_solder_mask_margin()->set_value_nm( *GetLocalSolderMaskMargin() );
355
356 if( GetLocalSolderPasteMargin().has_value() )
357 overrides->mutable_solder_paste()->mutable_solder_paste_margin()->set_value_nm( *GetLocalSolderPasteMargin() );
358
359 if( GetLocalSolderPasteMarginRatio().has_value() )
360 overrides->mutable_solder_paste()->mutable_solder_paste_margin_ratio()->set_value( *GetLocalSolderPasteMarginRatio() );
361
362 overrides->set_zone_connection(
364
365 for( const wxString& group : GetNetTiePadGroups() )
366 {
367 types::NetTieDefinition* netTie = def->add_net_ties();
368 wxStringTokenizer tokenizer( group, ", \t\r\n", wxTOKEN_STRTOK );
369
370 while( tokenizer.HasMoreTokens() )
371 netTie->add_pad_number( tokenizer.GetNextToken().ToStdString() );
372 }
373
374 for( PCB_LAYER_ID layer : GetPrivateLayers().Seq() )
375 def->add_private_layers( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
376
377 for( const PCB_FIELD* item : m_fields )
378 {
379 if( item->IsMandatory() )
380 continue;
381
382 google::protobuf::Any* itemMsg = def->add_items();
383 item->Serialize( *itemMsg );
384 }
385
386 for( const PAD* item : Pads() )
387 {
388 google::protobuf::Any* itemMsg = def->add_items();
389 item->Serialize( *itemMsg );
390 }
391
392 for( const BOARD_ITEM* item : GraphicalItems() )
393 {
394 google::protobuf::Any* itemMsg = def->add_items();
395 item->Serialize( *itemMsg );
396 }
397
398 for( const ZONE* item : Zones() )
399 {
400 google::protobuf::Any* itemMsg = def->add_items();
401 item->Serialize( *itemMsg );
402 }
403
404 for( const FP_3DMODEL& model : Models() )
405 {
406 google::protobuf::Any* itemMsg = def->add_items();
407 types::Footprint3DModel modelMsg;
408 modelMsg.set_filename( model.m_Filename.ToUTF8() );
409 kiapi::common::PackVector3D( *modelMsg.mutable_scale(), model.m_Scale );
410 kiapi::common::PackVector3D( *modelMsg.mutable_rotation(), model.m_Rotation );
411 kiapi::common::PackVector3D( *modelMsg.mutable_offset(), model.m_Offset );
412 modelMsg.set_visible( model.m_Show );
413 modelMsg.set_opacity( model.m_Opacity );
414 itemMsg->PackFrom( modelMsg );
415 }
416
417 kiapi::common::PackSheetPath( *footprint.mutable_symbol_path(), m_path );
418
419 footprint.set_symbol_sheet_name( m_sheetname.ToUTF8() );
420 footprint.set_symbol_sheet_filename( m_sheetfile.ToUTF8() );
421 footprint.set_symbol_footprint_filters( m_filters.ToUTF8() );
422
423 aContainer.PackFrom( footprint );
424}
425
426
427bool FOOTPRINT::Deserialize( const google::protobuf::Any &aContainer )
428{
429 using namespace kiapi::board;
430 types::FootprintInstance footprint;
431
432 if( !aContainer.UnpackTo( &footprint ) )
433 return false;
434
435 const_cast<KIID&>( m_Uuid ) = KIID( footprint.id().value() );
436 SetPosition( VECTOR2I( footprint.position().x_nm(), footprint.position().y_nm() ) );
437 SetOrientationDegrees( footprint.orientation().value_degrees() );
439 SetLocked( footprint.locked() == kiapi::common::types::LockedState::LS_LOCKED );
440
441 google::protobuf::Any buf;
442 types::Field mandatoryField;
443
444 if( footprint.has_reference_field() )
445 {
446 mandatoryField = footprint.reference_field();
447 mandatoryField.mutable_id()->set_id( (int) FIELD_T::REFERENCE );
448 buf.PackFrom( mandatoryField );
450 }
451
452 if( footprint.has_value_field() )
453 {
454 mandatoryField = footprint.value_field();
455 mandatoryField.mutable_id()->set_id( (int) FIELD_T::VALUE );
456 buf.PackFrom( mandatoryField );
458 }
459
460 if( footprint.has_datasheet_field() )
461 {
462 mandatoryField = footprint.datasheet_field();
463 mandatoryField.mutable_id()->set_id( (int) FIELD_T::DATASHEET );
464 buf.PackFrom( mandatoryField );
466 }
467
468 if( footprint.has_description_field() )
469 {
470 mandatoryField = footprint.description_field();
471 mandatoryField.mutable_id()->set_id( (int) FIELD_T::DESCRIPTION );
472 buf.PackFrom( mandatoryField );
474 }
475
476 m_attributes = 0;
477
478 switch( footprint.attributes().mounting_style() )
479 {
480 case types::FootprintMountingStyle::FMS_THROUGH_HOLE:
482 break;
483
484 case types::FootprintMountingStyle::FMS_SMD:
486 break;
487
488 default:
489 break;
490 }
491
492 SetBoardOnly( footprint.attributes().not_in_schematic() );
493 SetExcludedFromBOM( footprint.attributes().exclude_from_bill_of_materials() );
494 SetExcludedFromPosFiles( footprint.attributes().exclude_from_position_files() );
495 SetAllowMissingCourtyard( footprint.attributes().exempt_from_courtyard_requirement() );
496 SetDNP( footprint.attributes().do_not_populate() );
497 SetAllowSolderMaskBridges( footprint.attributes().allow_soldermask_bridges() );
498
499 // Definition
500 SetFPID( kiapi::common::LibIdFromProto( footprint.definition().id() ) );
501 // TODO: how should anchor be handled?
502 SetLibDescription( footprint.definition().attributes().description() );
503 SetKeywords( footprint.definition().attributes().keywords() );
504
505 const types::FootprintDesignRuleOverrides& overrides = footprint.overrides();
506
507 if( overrides.has_copper_clearance() )
508 SetLocalClearance( overrides.copper_clearance().value_nm() );
509 else
510 SetLocalClearance( std::nullopt );
511
512 if( overrides.has_solder_mask() && overrides.solder_mask().has_solder_mask_margin() )
513 SetLocalSolderMaskMargin( overrides.solder_mask().solder_mask_margin().value_nm() );
514 else
515 SetLocalSolderMaskMargin( std::nullopt );
516
517 if( overrides.has_solder_paste() )
518 {
519 const types::SolderPasteOverrides& pasteSettings = overrides.solder_paste();
520
521 if( pasteSettings.has_solder_paste_margin() )
522 SetLocalSolderPasteMargin( pasteSettings.solder_paste_margin().value_nm() );
523 else
524 SetLocalSolderPasteMargin( std::nullopt );
525
526 if( pasteSettings.has_solder_paste_margin_ratio() )
527 SetLocalSolderPasteMarginRatio( pasteSettings.solder_paste_margin_ratio().value() );
528 else
529 SetLocalSolderPasteMarginRatio( std::nullopt );
530 }
531
532 SetLocalZoneConnection( FromProtoEnum<ZONE_CONNECTION>( overrides.zone_connection() ) );
533
534 for( const types::NetTieDefinition& netTieMsg : footprint.definition().net_ties() )
535 {
536 wxString group;
537
538 for( const std::string& pad : netTieMsg.pad_number() )
539 group.Append( wxString::Format( wxT( "%s " ), pad ) );
540
541 group.Trim();
543 }
544
545 LSET privateLayers;
546
547 for( int layerMsg : footprint.definition().private_layers() )
548 {
549 auto layer = FromProtoEnum<PCB_LAYER_ID, types::BoardLayer>( static_cast<types::BoardLayer>( layerMsg ) );
550
551 if( layer > UNDEFINED_LAYER )
552 privateLayers.set( layer );
553 }
554
555 SetPrivateLayers( privateLayers );
556
557 m_path = kiapi::common::UnpackSheetPath( footprint.symbol_path() );
558 m_sheetname = wxString::FromUTF8( footprint.symbol_sheet_name() );
559 m_sheetfile = wxString::FromUTF8( footprint.symbol_sheet_filename() );
560 m_filters = wxString::FromUTF8( footprint.symbol_footprint_filters() );
561
562 // Footprint items
563 for( PCB_FIELD* field : m_fields )
564 {
565 if( !field->IsMandatory() )
566 Remove( field );
567 }
568
569 Pads().clear();
570 GraphicalItems().clear();
571 Zones().clear();
572 Groups().clear();
573 Models().clear();
574 Points().clear();
575
576 for( const google::protobuf::Any& itemMsg : footprint.definition().items() )
577 {
578 std::optional<KICAD_T> type = kiapi::common::TypeNameFromAny( itemMsg );
579
580 if( !type )
581 {
582 // Bit of a hack here, but eventually 3D models should be promoted to a first-class
583 // object, at which point they can get their own serialization
584 if( itemMsg.type_url() == "type.googleapis.com/kiapi.board.types.Footprint3DModel" )
585 {
586 types::Footprint3DModel modelMsg;
587
588 if( !itemMsg.UnpackTo( &modelMsg ) )
589 continue;
590
592
593 model.m_Filename = wxString::FromUTF8( modelMsg.filename() );
594 model.m_Show = modelMsg.visible();
595 model.m_Opacity = modelMsg.opacity();
596 model.m_Scale = kiapi::common::UnpackVector3D( modelMsg.scale() );
597 model.m_Rotation = kiapi::common::UnpackVector3D( modelMsg.rotation() );
598 model.m_Offset = kiapi::common::UnpackVector3D( modelMsg.offset() );
599
600 Models().push_back( std::move( model ) );
601 }
602 else
603 {
604 wxLogTrace( traceApi, wxString::Format( wxS( "Attempting to unpack unknown type %s "
605 "from footprint message, skipping" ),
606 itemMsg.type_url() ) );
607 }
608
609 continue;
610 }
611
612 std::unique_ptr<BOARD_ITEM> item = CreateItemForType( *type, this );
613
614 if( item && item->Deserialize( itemMsg ) )
615 Add( item.release(), ADD_MODE::APPEND );
616 }
617
618 return true;
619}
620
621
623{
624 for( PCB_FIELD* field : m_fields )
625 {
626 if( field->GetId() == aFieldType )
627 return field;
628 }
629
630 PCB_FIELD* field = new PCB_FIELD( this, aFieldType );
631 m_fields.push_back( field );
632
633 return field;
634}
635
636
637const PCB_FIELD* FOOTPRINT::GetField( FIELD_T aFieldType ) const
638{
639 for( const PCB_FIELD* field : m_fields )
640 {
641 if( field->GetId() == aFieldType )
642 return field;
643 }
644
645 return nullptr;
646}
647
648
649bool FOOTPRINT::HasField( const wxString& aFieldName ) const
650{
651 return GetField( aFieldName ) != nullptr;
652}
653
654
655PCB_FIELD* FOOTPRINT::GetField( const wxString& aFieldName ) const
656{
657 for( PCB_FIELD* field : m_fields )
658 {
659 if( field->GetName() == aFieldName )
660 return field;
661 }
662
663 return nullptr;
664}
665
666
667void FOOTPRINT::GetFields( std::vector<PCB_FIELD*>& aVector, bool aVisibleOnly ) const
668{
669 aVector.clear();
670
671 for( PCB_FIELD* field : m_fields )
672 {
673 if( aVisibleOnly )
674 {
675 if( !field->IsVisible() || field->GetText().IsEmpty() )
676 continue;
677 }
678
679 aVector.push_back( field );
680 }
681
682 std::sort( aVector.begin(), aVector.end(),
683 []( PCB_FIELD* lhs, PCB_FIELD* rhs )
684 {
685 return lhs->GetOrdinal() < rhs->GetOrdinal();
686 } );
687}
688
689
691{
692 int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T id
693
694 for( const PCB_FIELD* field : m_fields )
695 ordinal = std::max( ordinal, field->GetOrdinal() + 1 );
696
697 return ordinal;
698}
699
700
701void FOOTPRINT::ApplyDefaultSettings( const BOARD& board, bool aStyleFields, bool aStyleText,
702 bool aStyleShapes, bool aStyleDimensions, bool aStyleBarcodes )
703{
704 if( aStyleFields )
705 {
706 for( PCB_FIELD* field : m_fields )
707 field->StyleFromSettings( board.GetDesignSettings(), true );
708 }
709
710 for( BOARD_ITEM* item : m_drawings )
711 {
712 switch( item->Type() )
713 {
714 case PCB_TEXT_T:
715 case PCB_TEXTBOX_T:
716 if( aStyleText )
717 item->StyleFromSettings( board.GetDesignSettings(), true );
718
719 break;
720
721 case PCB_SHAPE_T:
722 if( aStyleShapes && !item->IsOnCopperLayer() )
723 item->StyleFromSettings( board.GetDesignSettings(), true );
724
725 break;
726
728 case PCB_DIM_LEADER_T:
729 case PCB_DIM_CENTER_T:
730 case PCB_DIM_RADIAL_T:
732 if( aStyleDimensions )
733 item->StyleFromSettings( board.GetDesignSettings(), true );
734
735 break;
736
737 case PCB_BARCODE_T:
738 if( aStyleBarcodes )
739 item->StyleFromSettings( board.GetDesignSettings(), true );
740 break;
741
742 default:
743 break;
744 }
745 }
746}
747
748
750{
751 // replace null UUIDs if any by a valid uuid
752 std::vector< BOARD_ITEM* > item_list;
753
754 for( PCB_FIELD* field : m_fields )
755 item_list.push_back( field );
756
757 for( PAD* pad : m_pads )
758 item_list.push_back( pad );
759
760 for( BOARD_ITEM* gr_item : m_drawings )
761 item_list.push_back( gr_item );
762
763 // Note: one cannot fix null UUIDs inside the group, but it should not happen
764 // because null uuids can be found in old footprints, therefore without group
765 for( PCB_GROUP* group : m_groups )
766 item_list.push_back( group );
767
768 // Probably not needed, because old fp do not have zones. But just in case.
769 for( ZONE* zone : m_zones )
770 item_list.push_back( zone );
771
772 // Ditto
773 for( PCB_POINT* point : m_points )
774 item_list.push_back( point );
775
776 bool changed = false;
777
778 for( BOARD_ITEM* item : item_list )
779 {
780 if( item->m_Uuid == niluuid )
781 {
782 const_cast<KIID&>( item->m_Uuid ) = KIID();
783 changed = true;
784 }
785 }
786
787 return changed;
788}
789
790
792{
793 BOARD_ITEM::operator=( aOther );
794
795 m_pos = aOther.m_pos;
796 m_fpid = aOther.m_fpid;
797 m_attributes = aOther.m_attributes;
798 m_fpStatus = aOther.m_fpStatus;
799 m_orient = aOther.m_orient;
800 m_lastEditTime = aOther.m_lastEditTime;
801 m_link = aOther.m_link;
802 m_path = aOther.m_path;
803
804 m_cachedBoundingBox = aOther.m_cachedBoundingBox;
805 m_boundingBoxCacheTimeStamp = aOther.m_boundingBoxCacheTimeStamp;
806 m_cachedTextExcludedBBox = aOther.m_cachedTextExcludedBBox;
807 m_textExcludedBBoxCacheTimeStamp = aOther.m_textExcludedBBoxCacheTimeStamp;
808 m_cachedHull = aOther.m_cachedHull;
809 m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp;
810
811 m_clearance = aOther.m_clearance;
812 m_solderMaskMargin = aOther.m_solderMaskMargin;
813 m_solderPasteMargin = aOther.m_solderPasteMargin;
814 m_solderPasteMarginRatio = aOther.m_solderPasteMarginRatio;
815 m_zoneConnection = aOther.m_zoneConnection;
816 m_netTiePadGroups = aOther.m_netTiePadGroups;
817 m_duplicatePadNumbersAreJumpers = aOther.m_duplicatePadNumbersAreJumpers;
818 m_jumperPadGroups = aOther.m_jumperPadGroups;
819
820 // Move the fields
821 for( PCB_FIELD* field : m_fields )
822 delete field;
823
824 m_fields.clear();
825
826 for( PCB_FIELD* field : aOther.m_fields )
827 Add( field );
828
829 aOther.m_fields.clear();
830
831 // Move the pads
832 for( PAD* pad : m_pads )
833 delete pad;
834
835 m_pads.clear();
836
837 for( PAD* pad : aOther.Pads() )
838 Add( pad );
839
840 aOther.Pads().clear();
841
842 // Move the zones
843 for( ZONE* zone : m_zones )
844 delete zone;
845
846 m_zones.clear();
847
848 for( ZONE* item : aOther.Zones() )
849 {
850 Add( item );
851
852 // Ensure the net info is OK and especially uses the net info list
853 // living in the current board
854 // Needed when copying a fp from fp editor that has its own board
855 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
856 item->SetNetCode( -1 );
857 }
858
859 aOther.Zones().clear();
860
861 // Move the drawings
862 for( BOARD_ITEM* item : m_drawings )
863 delete item;
864
865 m_drawings.clear();
866
867 for( BOARD_ITEM* item : aOther.GraphicalItems() )
868 Add( item );
869
870 aOther.GraphicalItems().clear();
871
872 // Move the groups
873 for( PCB_GROUP* group : m_groups )
874 delete group;
875
876 m_groups.clear();
877
878 for( PCB_GROUP* group : aOther.Groups() )
879 Add( group );
880
881 aOther.Groups().clear();
882
883 // Move the points
884 for( PCB_POINT* point : m_points )
885 delete point;
886
887 m_groups.clear();
888
889 for( PCB_POINT* point : aOther.Points() )
890 Add( point );
891
892 aOther.Points().clear();
893
894 EMBEDDED_FILES::operator=( std::move( aOther ) );
895
896 // Copy auxiliary data
897 m_3D_Drawings = aOther.m_3D_Drawings;
898 m_libDescription = aOther.m_libDescription;
899 m_keywords = aOther.m_keywords;
900 m_privateLayers = aOther.m_privateLayers;
901
902 m_initial_comments = aOther.m_initial_comments;
903
904 // Clear the other item's containers since this is a move
905 aOther.m_fields.clear();
906 aOther.Pads().clear();
907 aOther.Zones().clear();
908 aOther.GraphicalItems().clear();
909 aOther.m_initial_comments = nullptr;
910
911 return *this;
912}
913
914
916{
917 BOARD_ITEM::operator=( aOther );
918
919 m_pos = aOther.m_pos;
920 m_fpid = aOther.m_fpid;
921 m_attributes = aOther.m_attributes;
922 m_fpStatus = aOther.m_fpStatus;
923 m_orient = aOther.m_orient;
925 m_link = aOther.m_link;
926 m_path = aOther.m_path;
927
932 m_cachedHull = aOther.m_cachedHull;
934
935 m_clearance = aOther.m_clearance;
941
942 std::map<EDA_ITEM*, EDA_ITEM*> ptrMap;
943
944 // Copy fields
945 m_fields.clear();
946
947 for( PCB_FIELD* field : aOther.m_fields )
948 {
949 PCB_FIELD* newField = new PCB_FIELD( *field );
950 ptrMap[field] = newField;
951 Add( newField );
952 }
953
954 // Copy pads
955 m_pads.clear();
956
957 for( PAD* pad : aOther.Pads() )
958 {
959 PAD* newPad = new PAD( *pad );
960 ptrMap[ pad ] = newPad;
961 Add( newPad );
962 }
963
964 // Copy zones
965 m_zones.clear();
966
967 for( ZONE* zone : aOther.Zones() )
968 {
969 ZONE* newZone = static_cast<ZONE*>( zone->Clone() );
970 ptrMap[ zone ] = newZone;
971 Add( newZone );
972
973 // Ensure the net info is OK and especially uses the net info list
974 // living in the current board
975 // Needed when copying a fp from fp editor that has its own board
976 // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
977 newZone->SetNetCode( -1 );
978 }
979
980 // Copy drawings
981 m_drawings.clear();
982
983 for( BOARD_ITEM* item : aOther.GraphicalItems() )
984 {
985 BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
986 ptrMap[ item ] = newItem;
987 Add( newItem );
988 }
989
990 // Copy groups
991 m_groups.clear();
992
993 for( PCB_GROUP* group : aOther.Groups() )
994 {
995 PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
996 newGroup->GetItems().clear();
997
998 for( EDA_ITEM* member : group->GetItems() )
999 newGroup->AddItem( ptrMap[ member ] );
1000
1001 Add( newGroup );
1002 }
1003
1004 // Copy drawings
1005 m_points.clear();
1006
1007 for( PCB_POINT* point : aOther.Points() )
1008 {
1009 BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( point->Clone() );
1010 ptrMap[ point ] = newItem;
1011 Add( newItem );
1012 }
1013
1014 // Copy auxiliary data
1017 m_keywords = aOther.m_keywords;
1019
1021 new wxArrayString( *aOther.m_initial_comments ) : nullptr;
1022
1023 EMBEDDED_FILES::operator=( aOther );
1024
1025 return *this;
1026}
1027
1028
1029void FOOTPRINT::CopyFrom( const BOARD_ITEM* aOther )
1030{
1031 wxCHECK( aOther && aOther->Type() == PCB_FOOTPRINT_T, /* void */ );
1032 *this = *static_cast<const FOOTPRINT*>( aOther );
1033
1034 for( PAD* pad : m_pads )
1035 pad->SetDirty();
1036}
1037
1038
1048
1049
1051{
1052 return HasFlag( COURTYARD_CONFLICT );
1053}
1054
1055
1056void FOOTPRINT::GetContextualTextVars( wxArrayString* aVars ) const
1057{
1058 aVars->push_back( wxT( "REFERENCE" ) );
1059 aVars->push_back( wxT( "VALUE" ) );
1060 aVars->push_back( wxT( "LAYER" ) );
1061 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
1062 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
1063 aVars->push_back( wxT( "SHORT_NET_NAME(<pad_number>)" ) );
1064 aVars->push_back( wxT( "NET_NAME(<pad_number>)" ) );
1065 aVars->push_back( wxT( "NET_CLASS(<pad_number>)" ) );
1066 aVars->push_back( wxT( "PIN_NAME(<pad_number>)" ) );
1067}
1068
1069
1070bool FOOTPRINT::ResolveTextVar( wxString* token, int aDepth ) const
1071{
1072 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
1073 return false;
1074
1075 if( token->IsSameAs( wxT( "REFERENCE" ) ) )
1076 {
1077 *token = Reference().GetShownText( false, aDepth + 1 );
1078 return true;
1079 }
1080 else if( token->IsSameAs( wxT( "VALUE" ) ) )
1081 {
1082 *token = Value().GetShownText( false, aDepth + 1 );
1083 return true;
1084 }
1085 else if( token->IsSameAs( wxT( "LAYER" ) ) )
1086 {
1087 *token = GetLayerName();
1088 return true;
1089 }
1090 else if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
1091 {
1092 *token = m_fpid.GetUniStringLibNickname();
1093 return true;
1094 }
1095 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
1096 {
1097 *token = m_fpid.GetUniStringLibItemName();
1098 return true;
1099 }
1100 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) )
1101 || token->StartsWith( wxT( "NET_NAME(" ) )
1102 || token->StartsWith( wxT( "NET_CLASS(" ) )
1103 || token->StartsWith( wxT( "PIN_NAME(" ) ) )
1104 {
1105 wxString padNumber = token->AfterFirst( '(' );
1106 padNumber = padNumber.BeforeLast( ')' );
1107
1108 for( PAD* pad : Pads() )
1109 {
1110 if( pad->GetNumber() == padNumber )
1111 {
1112 if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
1113 *token = pad->GetShortNetname();
1114 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
1115 *token = pad->GetNetname();
1116 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
1117 *token = pad->GetNetClassName();
1118 else
1119 *token = pad->GetPinFunction();
1120
1121 return true;
1122 }
1123 }
1124 }
1125 else if( PCB_FIELD* field = GetField( *token ) )
1126 {
1127 *token = field->GetText();
1128 return true;
1129 }
1130
1131 if( GetBoard() && GetBoard()->ResolveTextVar( token, aDepth + 1 ) )
1132 return true;
1133
1134 return false;
1135}
1136
1137
1139{
1140 // Force the ORPHANED dummy net info for all pads.
1141 // ORPHANED dummy net does not depend on a board
1142 for( PAD* pad : m_pads )
1143 pad->SetNetCode( NETINFO_LIST::ORPHANED );
1144}
1145
1146
1147void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode, bool aSkipConnectivity )
1148{
1149 switch( aBoardItem->Type() )
1150 {
1151 case PCB_FIELD_T:
1152 m_fields.push_back( static_cast<PCB_FIELD*>( aBoardItem ) );
1153 break;
1154
1155 case PCB_BARCODE_T:
1156 case PCB_TEXT_T:
1157 case PCB_DIM_ALIGNED_T:
1158 case PCB_DIM_LEADER_T:
1159 case PCB_DIM_CENTER_T:
1160 case PCB_DIM_RADIAL_T:
1162 case PCB_SHAPE_T:
1163 case PCB_TEXTBOX_T:
1164 case PCB_TABLE_T:
1166 if( aMode == ADD_MODE::APPEND )
1167 m_drawings.push_back( aBoardItem );
1168 else
1169 m_drawings.push_front( aBoardItem );
1170
1171 break;
1172
1173 case PCB_PAD_T:
1174 if( aMode == ADD_MODE::APPEND )
1175 m_pads.push_back( static_cast<PAD*>( aBoardItem ) );
1176 else
1177 m_pads.push_front( static_cast<PAD*>( aBoardItem ) );
1178
1179 break;
1180
1181 case PCB_ZONE_T:
1182 if( aMode == ADD_MODE::APPEND )
1183 m_zones.push_back( static_cast<ZONE*>( aBoardItem ) );
1184 else
1185 m_zones.insert( m_zones.begin(), static_cast<ZONE*>( aBoardItem ) );
1186
1187 break;
1188
1189 case PCB_GROUP_T:
1190 if( aMode == ADD_MODE::APPEND )
1191 m_groups.push_back( static_cast<PCB_GROUP*>( aBoardItem ) );
1192 else
1193 m_groups.insert( m_groups.begin(), static_cast<PCB_GROUP*>( aBoardItem ) );
1194
1195 break;
1196
1197 case PCB_MARKER_T:
1198 wxFAIL_MSG( wxT( "FOOTPRINT::Add(): Markers go at the board level, even in the footprint editor" ) );
1199 return;
1200
1201 case PCB_FOOTPRINT_T:
1202 wxFAIL_MSG( wxT( "FOOTPRINT::Add(): Nested footprints not supported" ) );
1203 return;
1204
1205 case PCB_POINT_T:
1206 if( aMode == ADD_MODE::APPEND )
1207 m_points.push_back( static_cast<PCB_POINT*>( aBoardItem ) );
1208 else
1209 m_points.insert( m_points.begin(), static_cast<PCB_POINT*>( aBoardItem ) );
1210
1211 break;
1212
1213 default:
1214 wxFAIL_MSG( wxString::Format( wxT( "FOOTPRINT::Add(): BOARD_ITEM type (%d) not handled" ),
1215 aBoardItem->Type() ) );
1216
1217 return;
1218 }
1219
1220 aBoardItem->ClearEditFlags();
1221 aBoardItem->SetParent( this );
1222
1224}
1225
1226
1227void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode )
1228{
1229 switch( aBoardItem->Type() )
1230 {
1231 case PCB_FIELD_T:
1232 for( auto it = m_fields.begin(); it != m_fields.end(); ++it )
1233 {
1234 if( *it == aBoardItem )
1235 {
1236 m_fields.erase( it );
1237 break;
1238 }
1239 }
1240
1241 break;
1242
1243 case PCB_BARCODE_T:
1244 case PCB_TEXT_T:
1245 case PCB_DIM_ALIGNED_T:
1246 case PCB_DIM_CENTER_T:
1248 case PCB_DIM_RADIAL_T:
1249 case PCB_DIM_LEADER_T:
1250 case PCB_SHAPE_T:
1251 case PCB_TEXTBOX_T:
1252 case PCB_TABLE_T:
1254 for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
1255 {
1256 if( *it == aBoardItem )
1257 {
1258 m_drawings.erase( it );
1259 break;
1260 }
1261 }
1262
1263 break;
1264
1265 case PCB_PAD_T:
1266 for( auto it = m_pads.begin(); it != m_pads.end(); ++it )
1267 {
1268 if( *it == static_cast<PAD*>( aBoardItem ) )
1269 {
1270 m_pads.erase( it );
1271 break;
1272 }
1273 }
1274
1275 break;
1276
1277 case PCB_ZONE_T:
1278 for( auto it = m_zones.begin(); it != m_zones.end(); ++it )
1279 {
1280 if( *it == static_cast<ZONE*>( aBoardItem ) )
1281 {
1282 m_zones.erase( it );
1283 break;
1284 }
1285 }
1286
1287 break;
1288
1289 case PCB_GROUP_T:
1290 for( auto it = m_groups.begin(); it != m_groups.end(); ++it )
1291 {
1292 if( *it == static_cast<PCB_GROUP*>( aBoardItem ) )
1293 {
1294 m_groups.erase( it );
1295 break;
1296 }
1297 }
1298
1299 break;
1300
1301 case PCB_POINT_T:
1302 for( auto it = m_points.begin(); it != m_points.end(); ++it )
1303 {
1304 if( *it == static_cast<PCB_POINT*>( aBoardItem ) )
1305 {
1306 m_points.erase( it );
1307 break;
1308 }
1309 }
1310
1311 break;
1312
1313 default:
1314 {
1315 wxString msg;
1316 msg.Printf( wxT( "FOOTPRINT::Remove() needs work: BOARD_ITEM type (%d) not handled" ),
1317 aBoardItem->Type() );
1318 wxFAIL_MSG( msg );
1319 }
1320 }
1321
1322 aBoardItem->SetFlags( STRUCT_DELETED );
1323
1325}
1326
1327
1328double FOOTPRINT::GetArea( int aPadding ) const
1329{
1330 BOX2I bbox = GetBoundingBox( false );
1331
1332 double w = std::abs( static_cast<double>( bbox.GetWidth() ) ) + aPadding;
1333 double h = std::abs( static_cast<double>( bbox.GetHeight() ) ) + aPadding;
1334 return w * h;
1335}
1336
1337
1339{
1340 int smd_count = 0;
1341 int tht_count = 0;
1342
1343 for( PAD* pad : m_pads )
1344 {
1345 switch( pad->GetProperty() )
1346 {
1349 continue;
1350
1351 case PAD_PROP::HEATSINK:
1354 continue;
1355
1356 case PAD_PROP::NONE:
1357 case PAD_PROP::BGA:
1359 case PAD_PROP::PRESSFIT:
1360 break;
1361 }
1362
1363 switch( pad->GetAttribute() )
1364 {
1365 case PAD_ATTRIB::PTH:
1366 tht_count++;
1367 break;
1368
1369 case PAD_ATTRIB::SMD:
1370 if( pad->IsOnCopperLayer() )
1371 smd_count++;
1372
1373 break;
1374
1375 default:
1376 break;
1377 }
1378 }
1379
1380 // Footprints with plated through-hole pads should usually be marked through hole even if they
1381 // also have SMD because they might not be auto-placed. Exceptions to this might be shielded
1382 if( tht_count > 0 )
1383 return FP_THROUGH_HOLE;
1384
1385 if( smd_count > 0 )
1386 return FP_SMD;
1387
1388 return 0;
1389}
1390
1391
1393{
1394 if( ( m_attributes & FP_SMD ) == FP_SMD )
1395 return _( "SMD" );
1396
1398 return _( "Through hole" );
1399
1400 return _( "Other" );
1401}
1402
1403
1405{
1406 BOX2I bbox;
1407
1408 // We want the bounding box of the footprint pads at rot 0, not flipped
1409 // Create such a image:
1410 FOOTPRINT dummy( *this );
1411
1412 dummy.SetPosition( VECTOR2I( 0, 0 ) );
1413 dummy.SetOrientation( ANGLE_0 );
1414
1415 if( dummy.IsFlipped() )
1416 dummy.Flip( VECTOR2I( 0, 0 ), FLIP_DIRECTION::TOP_BOTTOM );
1417
1418 for( PAD* pad : dummy.Pads() )
1419 bbox.Merge( pad->GetBoundingBox() );
1420
1421 return bbox;
1422}
1423
1424
1426{
1427 for( BOARD_ITEM* item : m_drawings )
1428 {
1429 if( m_privateLayers.test( item->GetLayer() ) )
1430 continue;
1431
1432 if( item->Type() != PCB_FIELD_T && item->Type() != PCB_TEXT_T )
1433 return false;
1434 }
1435
1436 return true;
1437}
1438
1439
1441{
1442 return GetBoundingBox( true );
1443}
1444
1445
1446const BOX2I FOOTPRINT::GetBoundingBox( bool aIncludeText ) const
1447{
1448 const BOARD* board = GetBoard();
1449
1450 if( board )
1451 {
1452 if( aIncludeText )
1453 {
1454 if( m_boundingBoxCacheTimeStamp >= board->GetTimeStamp() )
1455 return m_cachedBoundingBox;
1456 }
1457 else
1458 {
1459 if( m_textExcludedBBoxCacheTimeStamp >= board->GetTimeStamp() )
1461 }
1462 }
1463
1464 std::vector<PCB_TEXT*> texts;
1465 bool isFPEdit = board && board->IsFootprintHolder();
1466
1467 BOX2I bbox( m_pos );
1468 bbox.Inflate( pcbIUScale.mmToIU( 0.25 ) ); // Give a min size to the bbox
1469
1470 // Calculate the footprint side
1471 PCB_LAYER_ID footprintSide = GetSide();
1472
1473 for( BOARD_ITEM* item : m_drawings )
1474 {
1475 if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
1476 continue;
1477
1478 // We want the bitmap bounding box just in the footprint editor
1479 // so it will start with the correct initial zoom
1480 if( item->Type() == PCB_REFERENCE_IMAGE_T && !isFPEdit )
1481 continue;
1482
1483 // Handle text separately
1484 if( item->Type() == PCB_TEXT_T )
1485 {
1486 texts.push_back( static_cast<PCB_TEXT*>( item ) );
1487 continue;
1488 }
1489
1490 // If we're not including text then drop annotations as well -- unless, of course, it's
1491 // an unsided footprint -- in which case it's likely to be nothing *but* annotations.
1492 if( !aIncludeText && footprintSide != UNDEFINED_LAYER )
1493 {
1494 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
1495 continue;
1496
1497 if( item->GetLayer() == Cmts_User || item->GetLayer() == Dwgs_User
1498 || item->GetLayer() == Eco1_User || item->GetLayer() == Eco2_User )
1499 {
1500 continue;
1501 }
1502 }
1503
1504 bbox.Merge( item->GetBoundingBox() );
1505 }
1506
1507 for( PCB_FIELD* field : m_fields )
1508 {
1509 // Reference and value get their own processing
1510 if( field->IsReference() || field->IsValue() )
1511 continue;
1512
1513 texts.push_back( field );
1514 }
1515
1516 for( PAD* pad : m_pads )
1517 bbox.Merge( pad->GetBoundingBox() );
1518
1519 for( ZONE* zone : m_zones )
1520 bbox.Merge( zone->GetBoundingBox() );
1521
1522 for( PCB_POINT* point : m_points )
1523 bbox.Merge( point->GetBoundingBox() );
1524
1525 bool noDrawItems = ( m_drawings.empty() && m_pads.empty() && m_zones.empty() );
1526
1527 // Groups do not contribute to the rect, only their members
1528 if( aIncludeText || noDrawItems )
1529 {
1530 // Only PCB_TEXT and PCB_FIELD items are independently selectable; PCB_TEXTBOX items go
1531 // in with other graphic items above.
1532 for( PCB_TEXT* text : texts )
1533 {
1534 if( !isFPEdit && m_privateLayers.test( text->GetLayer() ) )
1535 continue;
1536
1537 if( text->Type() == PCB_FIELD_T && !text->IsVisible() )
1538 continue;
1539
1540 bbox.Merge( text->GetBoundingBox() );
1541 }
1542
1543 // This can be further optimized when aIncludeInvisibleText is true, but currently
1544 // leaving this as is until it's determined there is a noticeable speed hit.
1545 bool valueLayerIsVisible = true;
1546 bool refLayerIsVisible = true;
1547
1548 if( board )
1549 {
1550 // The first "&&" conditional handles the user turning layers off as well as layers
1551 // not being present in the current PCB stackup. Values, references, and all
1552 // footprint text can also be turned off via the GAL meta-layers, so the 2nd and
1553 // 3rd "&&" conditionals handle that.
1554 valueLayerIsVisible = board->IsLayerVisible( Value().GetLayer() )
1555 && board->IsElementVisible( LAYER_FP_VALUES )
1556 && board->IsElementVisible( LAYER_FP_TEXT );
1557
1558 refLayerIsVisible = board->IsLayerVisible( Reference().GetLayer() )
1559 && board->IsElementVisible( LAYER_FP_REFERENCES )
1560 && board->IsElementVisible( LAYER_FP_TEXT );
1561 }
1562
1563
1564 if( ( Value().IsVisible() && valueLayerIsVisible ) || noDrawItems )
1565 {
1566 bbox.Merge( Value().GetBoundingBox() );
1567 }
1568
1569 if( ( Reference().IsVisible() && refLayerIsVisible ) || noDrawItems )
1570 {
1571 bbox.Merge( Reference().GetBoundingBox() );
1572 }
1573 }
1574
1575 if( board )
1576 {
1577 if( aIncludeText || noDrawItems )
1578 {
1579 m_boundingBoxCacheTimeStamp = board->GetTimeStamp();
1580 m_cachedBoundingBox = bbox;
1581 }
1582 else
1583 {
1584 m_textExcludedBBoxCacheTimeStamp = board->GetTimeStamp();
1586 }
1587 }
1588
1589 return bbox;
1590}
1591
1592
1593const BOX2I FOOTPRINT::GetLayerBoundingBox( const LSET& aLayers ) const
1594{
1595 std::vector<PCB_TEXT*> texts;
1596 const BOARD* board = GetBoard();
1597 bool isFPEdit = board && board->IsFootprintHolder();
1598
1599 // Start with an uninitialized bounding box
1600 BOX2I bbox;
1601
1602 for( BOARD_ITEM* item : m_drawings )
1603 {
1604 if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
1605 continue;
1606
1607 if( ( aLayers & item->GetLayerSet() ).none() )
1608 continue;
1609
1610 // We want the bitmap bounding box just in the footprint editor
1611 // so it will start with the correct initial zoom
1612 if( item->Type() == PCB_REFERENCE_IMAGE_T && !isFPEdit )
1613 continue;
1614
1615 bbox.Merge( item->GetBoundingBox() );
1616 }
1617
1618 for( PAD* pad : m_pads )
1619 {
1620 if( ( aLayers & pad->GetLayerSet() ).none() )
1621 continue;
1622
1623 bbox.Merge( pad->GetBoundingBox() );
1624 }
1625
1626 for( ZONE* zone : m_zones )
1627 {
1628 if( ( aLayers & zone->GetLayerSet() ).none() )
1629 continue;
1630
1631 bbox.Merge( zone->GetBoundingBox() );
1632 }
1633
1634 for( PCB_POINT* point : m_points )
1635 {
1636 if( m_privateLayers.test( point->GetLayer() ) && !isFPEdit )
1637 continue;
1638
1639 if( ( aLayers & point->GetLayerSet() ).none() )
1640 continue;
1641
1642 bbox.Merge( point->GetBoundingBox() );
1643 }
1644
1645 return bbox;
1646}
1647
1648
1650{
1651 const BOARD* board = GetBoard();
1652 bool isFPEdit = board && board->IsFootprintHolder();
1653
1654 if( board )
1655 {
1656 if( m_hullCacheTimeStamp >= board->GetTimeStamp() )
1657 return m_cachedHull;
1658 }
1659
1660 SHAPE_POLY_SET rawPolys;
1661
1662 for( BOARD_ITEM* item : m_drawings )
1663 {
1664 if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) )
1665 continue;
1666
1667 if( item->Type() != PCB_FIELD_T && item->Type() != PCB_REFERENCE_IMAGE_T )
1668 {
1669 item->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
1670 ERROR_OUTSIDE );
1671 }
1672
1673 // We intentionally exclude footprint fields from the bounding hull.
1674 }
1675
1676 for( PAD* pad : m_pads )
1677 {
1678 pad->Padstack().ForEachUniqueLayer(
1679 [&]( PCB_LAYER_ID aLayer )
1680 {
1681 pad->TransformShapeToPolygon( rawPolys, aLayer, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
1682 } );
1683
1684 // In case hole is larger than pad
1685 pad->TransformHoleToPolygon( rawPolys, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
1686 }
1687
1688 for( ZONE* zone : m_zones )
1689 {
1690 for( PCB_LAYER_ID layer : zone->GetLayerSet() )
1691 {
1692 const SHAPE_POLY_SET& layerPoly = *zone->GetFilledPolysList( layer );
1693
1694 for( int ii = 0; ii < layerPoly.OutlineCount(); ii++ )
1695 {
1696 const SHAPE_LINE_CHAIN& poly = layerPoly.COutline( ii );
1697 rawPolys.AddOutline( poly );
1698 }
1699 }
1700 }
1701
1702 // If there are some graphic items, build the actual hull.
1703 // However if no items, create a minimal polygon (can happen if a footprint
1704 // is created with no item: it contains only 2 texts.
1705 if( rawPolys.OutlineCount() == 0 || rawPolys.FullPointCount() < 3 )
1706 {
1707 // generate a small dummy rectangular outline around the anchor
1708 const int halfsize = pcbIUScale.mmToIU( 1.0 );
1709
1710 rawPolys.NewOutline();
1711
1712 // add a square:
1713 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y - halfsize );
1714 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y - halfsize );
1715 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y + halfsize );
1716 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y + halfsize );
1717 }
1718
1719 std::vector<VECTOR2I> convex_hull;
1720 BuildConvexHull( convex_hull, rawPolys );
1721
1722 m_cachedHull.RemoveAllContours();
1723 m_cachedHull.NewOutline();
1724
1725 for( const VECTOR2I& pt : convex_hull )
1726 m_cachedHull.Append( pt );
1727
1728 if( board )
1729 m_hullCacheTimeStamp = board->GetTimeStamp();
1730
1731 return m_cachedHull;
1732}
1733
1734
1736{
1737 const BOARD* board = GetBoard();
1738 bool isFPEdit = board && board->IsFootprintHolder();
1739
1740 SHAPE_POLY_SET rawPolys;
1741 SHAPE_POLY_SET hull;
1742
1743 for( BOARD_ITEM* item : m_drawings )
1744 {
1745 if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) )
1746 continue;
1747
1748 if( item->IsOnLayer( aLayer ) )
1749 {
1750 if( item->Type() != PCB_FIELD_T && item->Type() != PCB_REFERENCE_IMAGE_T )
1751 {
1752 item->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
1753 ERROR_OUTSIDE );
1754 }
1755
1756 // We intentionally exclude footprint fields from the bounding hull.
1757 }
1758 }
1759
1760 for( PAD* pad : m_pads )
1761 {
1762 if( pad->IsOnLayer( aLayer ) )
1763 pad->TransformShapeToPolygon( rawPolys, aLayer, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
1764 }
1765
1766 for( ZONE* zone : m_zones )
1767 {
1768 if( zone->GetIsRuleArea() )
1769 continue;
1770
1771 if( zone->IsOnLayer( aLayer ) )
1772 {
1773 const std::shared_ptr<SHAPE_POLY_SET>& layerPoly = zone->GetFilledPolysList( aLayer );
1774
1775 for( int ii = 0; ii < layerPoly->OutlineCount(); ii++ )
1776 rawPolys.AddOutline( layerPoly->COutline( ii ) );
1777 }
1778 }
1779
1780 std::vector<VECTOR2I> convex_hull;
1781 BuildConvexHull( convex_hull, rawPolys );
1782
1783 hull.NewOutline();
1784
1785 for( const VECTOR2I& pt : convex_hull )
1786 hull.Append( pt );
1787
1788 return hull;
1789}
1790
1791
1792void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1793{
1794 wxString msg, msg2;
1795
1796 // Don't use GetShownText(); we want to see the variable references here
1797 aList.emplace_back( UnescapeString( Reference().GetText() ),
1798 UnescapeString( Value().GetText() ) );
1799
1800 if( aFrame->IsType( FRAME_FOOTPRINT_VIEWER )
1801 || aFrame->IsType( FRAME_FOOTPRINT_CHOOSER )
1802 || aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
1803 {
1804 size_t padCount = GetPadCount( DO_NOT_INCLUDE_NPTH );
1805
1806 aList.emplace_back( _( "Library" ), GetFPID().GetLibNickname().wx_str() );
1807
1808 aList.emplace_back( _( "Footprint Name" ), GetFPID().GetLibItemName().wx_str() );
1809
1810 aList.emplace_back( _( "Pads" ), wxString::Format( wxT( "%zu" ), padCount ) );
1811
1812 aList.emplace_back( wxString::Format( _( "Doc: %s" ), GetLibDescription() ),
1813 wxString::Format( _( "Keywords: %s" ), GetKeywords() ) );
1814
1815 return;
1816 }
1817
1818 // aFrame is the board editor:
1819
1820 switch( GetSide() )
1821 {
1822 case F_Cu: aList.emplace_back( _( "Board Side" ), _( "Front" ) ); break;
1823 case B_Cu: aList.emplace_back( _( "Board Side" ), _( "Back (Flipped)" ) ); break;
1824 default: /* unsided: user-layers only, etc. */ break;
1825 }
1826
1827 auto addToken = []( wxString* aStr, const wxString& aAttr )
1828 {
1829 if( !aStr->IsEmpty() )
1830 *aStr += wxT( ", " );
1831
1832 *aStr += aAttr;
1833 };
1834
1835 wxString status;
1836 wxString attrs;
1837
1838 if( IsLocked() )
1839 addToken( &status, _( "Locked" ) );
1840
1841 if( m_fpStatus & FP_is_PLACED )
1842 addToken( &status, _( "autoplaced" ) );
1843
1845 addToken( &attrs, _( "not in schematic" ) );
1846
1848 addToken( &attrs, _( "exclude from pos files" ) );
1849
1851 addToken( &attrs, _( "exclude from BOM" ) );
1852
1853 if( m_attributes & FP_DNP )
1854 addToken( &attrs, _( "DNP" ) );
1855
1856 aList.emplace_back( _( "Status: " ) + status, _( "Attributes:" ) + wxS( " " ) + attrs );
1857
1858 aList.emplace_back( _( "Rotation" ), wxString::Format( wxT( "%.4g" ),
1859 GetOrientation().AsDegrees() ) );
1860
1861 if( !m_componentClassCacheProxy->GetComponentClass()->IsEmpty() )
1862 {
1863 aList.emplace_back(
1864 _( "Component Class" ),
1865 m_componentClassCacheProxy->GetComponentClass()->GetHumanReadableName() );
1866 }
1867
1868 msg.Printf( _( "Footprint: %s" ), m_fpid.GetUniStringLibId() );
1869 msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
1870 : m_3D_Drawings.front().m_Filename );
1871 aList.emplace_back( msg, msg2 );
1872
1873 msg.Printf( _( "Doc: %s" ), m_libDescription );
1874 msg2.Printf( _( "Keywords: %s" ), m_keywords );
1875 aList.emplace_back( msg, msg2 );
1876}
1877
1878
1880{
1881 if( const BOARD* board = GetBoard() )
1882 {
1883 if( board->IsFootprintHolder() )
1884 return UNDEFINED_LAYER;
1885 }
1886
1887 // Test pads first; they're the most likely to return a quick answer.
1888 for( PAD* pad : m_pads )
1889 {
1890 if( ( LSET::SideSpecificMask() & pad->GetLayerSet() ).any() )
1891 return GetLayer();
1892 }
1893
1894 for( BOARD_ITEM* item : m_drawings )
1895 {
1896 if( LSET::SideSpecificMask().test( item->GetLayer() ) )
1897 return GetLayer();
1898 }
1899
1900 for( ZONE* zone : m_zones )
1901 {
1902 if( ( LSET::SideSpecificMask() & zone->GetLayerSet() ).any() )
1903 return GetLayer();
1904 }
1905
1906 return UNDEFINED_LAYER;
1907}
1908
1909
1911{
1912 // If we have any pads, fall back on normal checking
1913 for( PAD* pad : m_pads )
1914 {
1915 if( pad->IsOnLayer( aLayer ) )
1916 return true;
1917 }
1918
1919 for( ZONE* zone : m_zones )
1920 {
1921 if( zone->IsOnLayer( aLayer ) )
1922 return true;
1923 }
1924
1925 for( PCB_FIELD* field : m_fields )
1926 {
1927 if( field->IsOnLayer( aLayer ) )
1928 return true;
1929 }
1930
1931 for( BOARD_ITEM* item : m_drawings )
1932 {
1933 if( item->IsOnLayer( aLayer ) )
1934 return true;
1935 }
1936
1937 return false;
1938}
1939
1940
1941bool FOOTPRINT::HitTestOnLayer( const VECTOR2I& aPosition, PCB_LAYER_ID aLayer, int aAccuracy ) const
1942{
1943 for( PAD* pad : m_pads )
1944 {
1945 if( pad->IsOnLayer( aLayer ) && pad->HitTest( aPosition, aAccuracy ) )
1946 return true;
1947 }
1948
1949 for( ZONE* zone : m_zones )
1950 {
1951 if( zone->IsOnLayer( aLayer ) && zone->HitTest( aPosition, aAccuracy ) )
1952 return true;
1953 }
1954
1955 for( BOARD_ITEM* item : m_drawings )
1956 {
1957 if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer )
1958 && item->HitTest( aPosition, aAccuracy ) )
1959 {
1960 return true;
1961 }
1962 }
1963
1964 return false;
1965}
1966
1967
1968bool FOOTPRINT::HitTestOnLayer( const BOX2I& aRect, bool aContained, PCB_LAYER_ID aLayer, int aAccuracy ) const
1969{
1970 std::vector<BOARD_ITEM*> items;
1971
1972 for( PAD* pad : m_pads )
1973 {
1974 if( pad->IsOnLayer( aLayer ) )
1975 items.push_back( pad );
1976 }
1977
1978 for( ZONE* zone : m_zones )
1979 {
1980 if( zone->IsOnLayer( aLayer ) )
1981 items.push_back( zone );
1982 }
1983
1984 for( BOARD_ITEM* item : m_drawings )
1985 {
1986 if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer ) )
1987 items.push_back( item );
1988 }
1989
1990 // If we require the elements to be contained in the rect and any of them are not,
1991 // we can return false;
1992 // Conversely, if we just require any of the elements to have a hit, we can return true
1993 // when the first one is found.
1994 for( BOARD_ITEM* item : items )
1995 {
1996 if( !aContained && item->HitTest( aRect, aContained, aAccuracy ) )
1997 return true;
1998 else if( aContained && !item->HitTest( aRect, aContained, aAccuracy ) )
1999 return false;
2000 }
2001
2002 // If we didn't exit in the loop, that means that we did not return false for aContained or
2003 // we did not return true for !aContained. So we can just return the bool with a test of
2004 // whether there were any elements or not.
2005 return !items.empty() && aContained;
2006}
2007
2008
2009bool FOOTPRINT::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2010{
2011 BOX2I rect = GetBoundingBox( false );
2012 return rect.Inflate( aAccuracy ).Contains( aPosition );
2013}
2014
2015
2016bool FOOTPRINT::HitTestAccurate( const VECTOR2I& aPosition, int aAccuracy ) const
2017{
2018 return GetBoundingHull().Collide( aPosition, aAccuracy );
2019}
2020
2021
2022bool FOOTPRINT::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2023{
2024 BOX2I arect = aRect;
2025 arect.Inflate( aAccuracy );
2026
2027 if( aContained )
2028 {
2029 return arect.Contains( GetBoundingBox( false ) );
2030 }
2031 else
2032 {
2033 // If the rect does not intersect the bounding box, skip any tests
2034 if( !aRect.Intersects( GetBoundingBox( false ) ) )
2035 return false;
2036
2037 // If there are no pads, zones, or drawings, allow intersection with text
2038 if( m_pads.empty() && m_zones.empty() && m_drawings.empty() )
2039 return GetBoundingBox( true ).Intersects( arect );
2040
2041 // Determine if any elements in the FOOTPRINT intersect the rect
2042 for( PAD* pad : m_pads )
2043 {
2044 if( pad->HitTest( arect, false, 0 ) )
2045 return true;
2046 }
2047
2048 for( ZONE* zone : m_zones )
2049 {
2050 if( zone->HitTest( arect, false, 0 ) )
2051 return true;
2052 }
2053
2054 for( PCB_POINT* point : m_points )
2055 {
2056 if( point->HitTest( arect, false, 0 ) )
2057 return true;
2058 }
2059
2060 // PCB fields are selectable on their own, so they don't get tested
2061
2062 for( BOARD_ITEM* item : m_drawings )
2063 {
2064 // Text items are selectable on their own, and are therefore excluded from this
2065 // test. TextBox items are NOT selectable on their own, and so MUST be included
2066 // here. Bitmaps aren't selectable since they aren't displayed.
2067 if( item->Type() != PCB_TEXT_T && item->HitTest( arect, false, 0 ) )
2068 return true;
2069 }
2070
2071 // Groups are not hit-tested; only their members
2072
2073 // No items were hit
2074 return false;
2075 }
2076}
2077
2078
2079bool FOOTPRINT::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
2080{
2081 using std::ranges::all_of;
2082 using std::ranges::any_of;
2083
2084 // If there are no pads, zones, or drawings, test footprint text instead.
2085 if( m_pads.empty() && m_zones.empty() && m_drawings.empty() )
2086 return KIGEOM::BoxHitTest( aPoly, GetBoundingBox( true ), aContained );
2087
2088 auto hitTest =
2089 [&]( const auto* aItem )
2090 {
2091 return aItem && aItem->HitTest( aPoly, aContained );
2092 };
2093
2094 // Filter out text items from the drawings, since they are selectable on their own,
2095 // and we don't want to select the whole footprint when text is hit. TextBox items are NOT
2096 // selectable on their own, so they are not excluded here.
2097 auto drawings = m_drawings | std::views::filter( []( const auto* aItem )
2098 {
2099 return aItem && aItem->Type() != PCB_TEXT_T;
2100 } );
2101
2102 // Test pads, zones and drawings with text excluded. PCB fields are also selectable
2103 // on their own, so they don't get tested. Groups are not hit-tested, only their members.
2104 // Bitmaps aren't selectable since they aren't displayed.
2105 if( aContained )
2106 {
2107 // All items must be contained in the selection poly.
2108 return all_of( drawings, hitTest )
2109 && all_of( m_pads, hitTest )
2110 && all_of( m_zones, hitTest );
2111 }
2112 else
2113 {
2114 // Any item intersecting the selection poly is sufficient.
2115 return any_of( drawings, hitTest )
2116 || any_of( m_pads, hitTest )
2117 || any_of( m_zones, hitTest );
2118 }
2119}
2120
2121
2122PAD* FOOTPRINT::FindPadByNumber( const wxString& aPadNumber, PAD* aSearchAfterMe ) const
2123{
2124 bool can_select = aSearchAfterMe ? false : true;
2125
2126 for( PAD* pad : m_pads )
2127 {
2128 if( !can_select && pad == aSearchAfterMe )
2129 {
2130 can_select = true;
2131 continue;
2132 }
2133
2134 if( can_select && pad->GetNumber() == aPadNumber )
2135 return pad;
2136 }
2137
2138 return nullptr;
2139}
2140
2141
2142PAD* FOOTPRINT::GetPad( const VECTOR2I& aPosition, const LSET& aLayerMask )
2143{
2144 for( PAD* pad : m_pads )
2145 {
2146 // ... and on the correct layer.
2147 if( !( pad->GetLayerSet() & aLayerMask ).any() )
2148 continue;
2149
2150 if( pad->HitTest( aPosition ) )
2151 return pad;
2152 }
2153
2154 return nullptr;
2155}
2156
2157
2158std::vector<const PAD*> FOOTPRINT::GetPads( const wxString& aPadNumber, const PAD* aIgnore ) const
2159{
2160 std::vector<const PAD*> retv;
2161
2162 for( const PAD* pad : m_pads )
2163 {
2164 if( ( aIgnore && aIgnore == pad ) || ( pad->GetNumber() != aPadNumber ) )
2165 continue;
2166
2167 retv.push_back( pad );
2168 }
2169
2170 return retv;
2171}
2172
2173
2174unsigned FOOTPRINT::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
2175{
2176 if( aIncludeNPTH )
2177 return m_pads.size();
2178
2179 unsigned cnt = 0;
2180
2181 for( PAD* pad : m_pads )
2182 {
2183 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
2184 continue;
2185
2186 cnt++;
2187 }
2188
2189 return cnt;
2190}
2191
2192
2193std::set<wxString> FOOTPRINT::GetUniquePadNumbers( INCLUDE_NPTH_T aIncludeNPTH ) const
2194{
2195 std::set<wxString> usedNumbers;
2196
2197 // Create a set of used pad numbers
2198 for( PAD* pad : m_pads )
2199 {
2200 // Skip pads not on copper layers (used to build complex
2201 // solder paste shapes for instance)
2202 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none() )
2203 continue;
2204
2205 // Skip pads with no name, because they are usually "mechanical"
2206 // pads, not "electrical" pads
2207 if( pad->GetNumber().IsEmpty() )
2208 continue;
2209
2210 if( !aIncludeNPTH )
2211 {
2212 // skip NPTH
2213 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
2214 continue;
2215 }
2216
2217 usedNumbers.insert( pad->GetNumber() );
2218 }
2219
2220 return usedNumbers;
2221}
2222
2223
2224unsigned FOOTPRINT::GetUniquePadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
2225{
2226 return GetUniquePadNumbers( aIncludeNPTH ).size();
2227}
2228
2229
2231{
2232 if( nullptr == a3DModel )
2233 return;
2234
2235 if( !a3DModel->m_Filename.empty() )
2236 m_3D_Drawings.push_back( *a3DModel );
2237}
2238
2239
2240bool FOOTPRINT::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
2241{
2242 if( aSearchData.searchMetadata )
2243 {
2244 if( EDA_ITEM::Matches( GetFPIDAsString(), aSearchData ) )
2245 return true;
2246
2247 if( EDA_ITEM::Matches( GetLibDescription(), aSearchData ) )
2248 return true;
2249
2250 if( EDA_ITEM::Matches( GetKeywords(), aSearchData ) )
2251 return true;
2252 }
2253
2254 return false;
2255}
2256
2257
2258// see footprint.h
2259INSPECT_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData,
2260 const std::vector<KICAD_T>& aScanTypes )
2261{
2262#if 0 && defined(DEBUG)
2263 std::cout << GetClass().mb_str() << ' ';
2264#endif
2265
2266 bool drawingsScanned = false;
2267
2268 for( KICAD_T scanType : aScanTypes )
2269 {
2270 switch( scanType )
2271 {
2272 case PCB_FOOTPRINT_T:
2273 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
2274 return INSPECT_RESULT::QUIT;
2275
2276 break;
2277
2278 case PCB_PAD_T:
2279 if( IterateForward<PAD*>( m_pads, inspector, testData, { scanType } )
2281 {
2282 return INSPECT_RESULT::QUIT;
2283 }
2284
2285 break;
2286
2287 case PCB_ZONE_T:
2288 if( IterateForward<ZONE*>( m_zones, inspector, testData, { scanType } )
2290 {
2291 return INSPECT_RESULT::QUIT;
2292 }
2293
2294 break;
2295
2296 case PCB_FIELD_T:
2297 if( IterateForward<PCB_FIELD*>( m_fields, inspector, testData, { scanType } )
2299 {
2300 return INSPECT_RESULT::QUIT;
2301 }
2302
2303 break;
2304
2305 case PCB_TEXT_T:
2306 case PCB_DIM_ALIGNED_T:
2307 case PCB_DIM_LEADER_T:
2308 case PCB_DIM_CENTER_T:
2309 case PCB_DIM_RADIAL_T:
2311 case PCB_SHAPE_T:
2312 case PCB_BARCODE_T:
2313 case PCB_TEXTBOX_T:
2314 case PCB_TABLE_T:
2315 case PCB_TABLECELL_T:
2316 if( !drawingsScanned )
2317 {
2318 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, aScanTypes )
2320 {
2321 return INSPECT_RESULT::QUIT;
2322 }
2323
2324 drawingsScanned = true;
2325 }
2326
2327 break;
2328
2329 case PCB_GROUP_T:
2330 if( IterateForward<PCB_GROUP*>( m_groups, inspector, testData, { scanType } )
2332 {
2333 return INSPECT_RESULT::QUIT;
2334 }
2335
2336 break;
2337
2338 case PCB_POINT_T:
2339 if( IterateForward<PCB_POINT*>( m_points, inspector, testData, { scanType } )
2341 {
2342 return INSPECT_RESULT::QUIT;
2343 }
2344
2345 break;
2346
2347 default:
2348 break;
2349 }
2350 }
2351
2353}
2354
2355
2356wxString FOOTPRINT::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
2357{
2358 wxString reference = GetReference();
2359
2360 if( reference.IsEmpty() )
2361 reference = _( "<no reference designator>" );
2362
2363 return wxString::Format( _( "Footprint %s" ), reference );
2364}
2365
2366
2368{
2369 return BITMAPS::module;
2370}
2371
2372
2374{
2375 return new FOOTPRINT( *this );
2376}
2377
2378
2379void FOOTPRINT::RunOnChildren( const std::function<void( BOARD_ITEM* )>& aFunction, RECURSE_MODE aMode ) const
2380{
2381 try
2382 {
2383 for( PCB_FIELD* field : m_fields )
2384 aFunction( field );
2385
2386 for( PAD* pad : m_pads )
2387 aFunction( pad );
2388
2389 for( ZONE* zone : m_zones )
2390 aFunction( zone );
2391
2392 for( PCB_GROUP* group : m_groups )
2393 aFunction( group );
2394
2395 for( PCB_POINT* point : m_points )
2396 aFunction( point );
2397
2398 for( BOARD_ITEM* drawing : m_drawings )
2399 {
2400 aFunction( drawing );
2401
2402 if( aMode == RECURSE_MODE::RECURSE )
2403 drawing->RunOnChildren( aFunction, RECURSE_MODE::RECURSE );
2404 }
2405 }
2406 catch( std::bad_function_call& )
2407 {
2408 wxFAIL_MSG( wxT( "Error running FOOTPRINT::RunOnChildren" ) );
2409 }
2410}
2411
2412
2413std::vector<int> FOOTPRINT::ViewGetLayers() const
2414{
2415 std::vector<int> layers;
2416
2417 layers.reserve( 6 );
2418 layers.push_back( LAYER_ANCHOR );
2419
2420 switch( m_layer )
2421 {
2422 default:
2423 wxASSERT_MSG( false, wxT( "Illegal layer" ) ); // do you really have footprints placed
2424 // on other layers?
2426
2427 case F_Cu:
2428 layers.push_back( LAYER_FOOTPRINTS_FR );
2429 break;
2430
2431 case B_Cu:
2432 layers.push_back( LAYER_FOOTPRINTS_BK );
2433 break;
2434 }
2435
2436 if( IsConflicting() )
2437 layers.push_back( LAYER_CONFLICTS_SHADOW );
2438
2439 // If there are no pads, and only drawings on a silkscreen layer, then report the silkscreen
2440 // layer as well so that the component can be edited with the silkscreen layer
2441 bool f_silk = false, b_silk = false, non_silk = false;
2442
2443 for( BOARD_ITEM* item : m_drawings )
2444 {
2445 if( item->GetLayer() == F_SilkS )
2446 f_silk = true;
2447 else if( item->GetLayer() == B_SilkS )
2448 b_silk = true;
2449 else
2450 non_silk = true;
2451 }
2452
2453 if( ( f_silk || b_silk ) && !non_silk && m_pads.empty() )
2454 {
2455 if( f_silk )
2456 layers.push_back( F_SilkS );
2457
2458 if( b_silk )
2459 layers.push_back( B_SilkS );
2460 }
2461
2462 return layers;
2463}
2464
2465
2466double FOOTPRINT::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
2467{
2468 if( aLayer == LAYER_CONFLICTS_SHADOW && IsConflicting() )
2469 {
2470 // The locked shadow shape is shown only if the footprint itself is visible
2471 if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
2472 return LOD_SHOW;
2473
2474 if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
2475 return LOD_SHOW;
2476
2477 return LOD_HIDE;
2478 }
2479
2480 // Only show anchors if the layer the footprint is on is visible
2481 if( aLayer == LAYER_ANCHOR && !aView->IsLayerVisible( m_layer ) )
2482 return LOD_HIDE;
2483
2484 int layer = ( m_layer == F_Cu ) ? LAYER_FOOTPRINTS_FR :
2486
2487 // Currently this is only pertinent for the anchor layer; everything else is drawn from the
2488 // children.
2489 // The "good" value is experimentally chosen.
2490 constexpr double MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY = 1.5;
2491
2492 if( aView->IsLayerVisible( layer ) )
2493 return MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY;
2494
2495 return LOD_HIDE;
2496}
2497
2498
2500{
2501 BOX2I area = GetBoundingBox( true );
2502
2503 // Inflate in case clearance lines are drawn around pads, etc.
2504 if( const BOARD* board = GetBoard() )
2505 {
2506 int biggest_clearance = board->GetMaxClearanceValue();
2507 area.Inflate( biggest_clearance );
2508 }
2509
2510 return area;
2511}
2512
2513
2514bool FOOTPRINT::IsLibNameValid( const wxString & aName )
2515{
2516 const wxChar * invalids = StringLibNameInvalidChars( false );
2517
2518 if( aName.find_first_of( invalids ) != std::string::npos )
2519 return false;
2520
2521 return true;
2522}
2523
2524
2525const wxChar* FOOTPRINT::StringLibNameInvalidChars( bool aUserReadable )
2526{
2527 // This list of characters is also duplicated in validators.cpp and
2528 // lib_id.cpp
2529 // TODO: Unify forbidden character lists - Warning, invalid filename characters are not the same
2530 // as invalid LIB_ID characters. We will need to separate the FP filenames from FP names before this
2531 // can be unified
2532 static const wxChar invalidChars[] = wxT("%$<>\t\n\r\"\\/:");
2533 static const wxChar invalidCharsReadable[] = wxT("% $ < > 'tab' 'return' 'line feed' \\ \" / :");
2534
2535 if( aUserReadable )
2536 return invalidCharsReadable;
2537 else
2538 return invalidChars;
2539}
2540
2541
2542void FOOTPRINT::Move( const VECTOR2I& aMoveVector )
2543{
2544 if( aMoveVector.x == 0 && aMoveVector.y == 0 )
2545 return;
2546
2547 VECTOR2I newpos = m_pos + aMoveVector;
2548 SetPosition( newpos );
2549}
2550
2551
2552void FOOTPRINT::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
2553{
2554 if( aAngle == ANGLE_0 )
2555 return;
2556
2557 EDA_ANGLE orientation = GetOrientation();
2558 EDA_ANGLE newOrientation = orientation + aAngle;
2559 VECTOR2I newpos = m_pos;
2560 RotatePoint( newpos, aRotCentre, aAngle );
2561 SetPosition( newpos );
2562 SetOrientation( newOrientation );
2563
2564 for( PCB_FIELD* field : m_fields )
2565 field->KeepUpright();
2566
2567 for( BOARD_ITEM* item : m_drawings )
2568 {
2569 if( item->Type() == PCB_TEXT_T )
2570 static_cast<PCB_TEXT*>( item )->KeepUpright();
2571 }
2572}
2573
2574
2576{
2577 wxASSERT( aLayer == F_Cu || aLayer == B_Cu );
2578
2579 if( aLayer != GetLayer() )
2581}
2582
2583
2584void FOOTPRINT::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
2585{
2586 // Move footprint to its final position:
2587 VECTOR2I finalPos = m_pos;
2588
2589 // Now Flip the footprint.
2590 // Flipping a footprint is a specific transform: it is not mirrored like a text.
2591 // We have to change the side, and ensure the footprint rotation is modified according to the
2592 // transform, because this parameter is used in pick and place files, and when updating the
2593 // footprint from library.
2594 // When flipped around the X axis (Y coordinates changed) orientation is negated
2595 // When flipped around the Y axis (X coordinates changed) orientation is 180 - old orient.
2596 // Because it is specific to a footprint, we flip around the X axis, and after rotate 180 deg
2597
2598 MIRROR( finalPos.y, aCentre.y );
2599
2600 SetPosition( finalPos );
2601
2602 // Flip layer
2604
2605 // Calculate the new orientation, and then clear it for pad flipping.
2606 EDA_ANGLE newOrientation = -m_orient;
2607 newOrientation.Normalize180();
2608 m_orient = ANGLE_0;
2609
2610 // Mirror fields to other side of board.
2611 for( PCB_FIELD* field : m_fields )
2612 field->Flip( m_pos, FLIP_DIRECTION::TOP_BOTTOM );
2613
2614 // Mirror pads to other side of board.
2615 for( PAD* pad : m_pads )
2617
2618 // Now set the new orientation.
2619 m_orient = newOrientation;
2620
2621 // Mirror zones to other side of board.
2622 for( ZONE* zone : m_zones )
2623 zone->Flip( m_pos, FLIP_DIRECTION::TOP_BOTTOM );
2624
2625 // Reverse mirror footprint graphics and texts.
2626 for( BOARD_ITEM* item : m_drawings )
2627 item->Flip( m_pos, FLIP_DIRECTION::TOP_BOTTOM );
2628
2629 // Points move but don't flip layer
2630 for( PCB_POINT* point : m_points )
2631 point->Flip( m_pos, FLIP_DIRECTION::TOP_BOTTOM );
2632
2633 // Now rotate 180 deg if required
2634 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
2635 Rotate( aCentre, ANGLE_180 );
2636
2639
2640 m_cachedHull.Mirror( m_pos, aFlipDirection );
2641
2642 // The courtyard caches must be rebuilt after geometry change
2644}
2645
2646
2648{
2649 VECTOR2I delta = aPos - m_pos;
2650
2651 m_pos += delta;
2652
2653 for( PCB_FIELD* field : m_fields )
2654 field->EDA_TEXT::Offset( delta );
2655
2656 for( PAD* pad : m_pads )
2657 pad->SetPosition( pad->GetPosition() + delta );
2658
2659 for( ZONE* zone : m_zones )
2660 zone->Move( delta );
2661
2662 for( BOARD_ITEM* item : m_drawings )
2663 item->Move( delta );
2664
2665 for( PCB_POINT* point : m_points )
2666 point->Move( delta );
2667
2668 m_cachedBoundingBox.Move( delta );
2670 m_cachedHull.Move( delta );
2671
2672 // The geometry work has been conserved by using Move(). But the hashes
2673 // need to be updated, otherwise the cached polygons will still be rebuild.
2678}
2679
2680
2681void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector )
2682{
2683 /*
2684 * Move the reference point of the footprint
2685 * the footprints elements (pads, outlines, edges .. ) are moved
2686 * but:
2687 * - the footprint position is not modified.
2688 * - the relative (local) coordinates of these items are modified
2689 * - Draw coordinates are updated
2690 */
2691
2692 // Update (move) the relative coordinates relative to the new anchor point.
2693 VECTOR2I moveVector = aMoveVector;
2694 RotatePoint( moveVector, -GetOrientation() );
2695
2696 // Update field local coordinates
2697 for( PCB_FIELD* field : m_fields )
2698 field->Move( moveVector );
2699
2700 // Update the pad local coordinates.
2701 for( PAD* pad : m_pads )
2702 pad->Move( moveVector );
2703
2704 // Update the draw element coordinates.
2705 for( BOARD_ITEM* item : GraphicalItems() )
2706 item->Move( moveVector );
2707
2708 // Update the keepout zones
2709 for( ZONE* zone : Zones() )
2710 zone->Move( moveVector );
2711
2712 // Update the 3D models
2713 for( FP_3DMODEL& model : Models() )
2714 {
2715 model.m_Offset.x += pcbIUScale.IUTomm( moveVector.x );
2716 model.m_Offset.y -= pcbIUScale.IUTomm( moveVector.y );
2717 }
2718
2719 m_cachedBoundingBox.Move( moveVector );
2720 m_cachedTextExcludedBBox.Move( moveVector );
2721 m_cachedHull.Move( moveVector );
2722
2723 // The geometry work have been conserved by using Move(). But the hashes
2724 // need to be updated, otherwise the cached polygons will still be rebuild.
2725 m_courtyard_cache_back.Move( moveVector );
2727 m_courtyard_cache_front.Move( moveVector );
2729}
2730
2731
2732void FOOTPRINT::SetOrientation( const EDA_ANGLE& aNewAngle )
2733{
2734 EDA_ANGLE angleChange = aNewAngle - m_orient; // change in rotation
2735
2736 m_orient = aNewAngle;
2737 m_orient.Normalize180();
2738
2739 for( PCB_FIELD* field : m_fields )
2740 field->Rotate( GetPosition(), angleChange );
2741
2742 for( PAD* pad : m_pads )
2743 pad->Rotate( GetPosition(), angleChange );
2744
2745 for( ZONE* zone : m_zones )
2746 zone->Rotate( GetPosition(), angleChange );
2747
2748 for( BOARD_ITEM* item : m_drawings )
2749 item->Rotate( GetPosition(), angleChange );
2750
2751 for( PCB_POINT* point : m_points )
2752 point->Rotate( GetPosition(), angleChange );
2753
2757
2758 // The courtyard caches need to be rebuilt, as the geometry has changed
2760}
2761
2762
2763BOARD_ITEM* FOOTPRINT::Duplicate( bool addToParentGroup, BOARD_COMMIT* aCommit ) const
2764{
2765 FOOTPRINT* dupe = static_cast<FOOTPRINT*>( BOARD_ITEM::Duplicate( addToParentGroup, aCommit ) );
2766
2767 dupe->RunOnChildren( [&]( BOARD_ITEM* child )
2768 {
2769 const_cast<KIID&>( child->m_Uuid ) = KIID();
2770 },
2772
2773 return dupe;
2774}
2775
2776
2777BOARD_ITEM* FOOTPRINT::DuplicateItem( bool addToParentGroup, BOARD_COMMIT* aCommit,
2778 const BOARD_ITEM* aItem, bool addToFootprint )
2779{
2780 BOARD_ITEM* new_item = nullptr;
2781
2782 switch( aItem->Type() )
2783 {
2784 case PCB_PAD_T:
2785 {
2786 PAD* new_pad = new PAD( *static_cast<const PAD*>( aItem ) );
2787 const_cast<KIID&>( new_pad->m_Uuid ) = KIID();
2788
2789 if( addToFootprint )
2790 m_pads.push_back( new_pad );
2791
2792 new_item = new_pad;
2793 break;
2794 }
2795
2796 case PCB_ZONE_T:
2797 {
2798 ZONE* new_zone = new ZONE( *static_cast<const ZONE*>( aItem ) );
2799 const_cast<KIID&>( new_zone->m_Uuid ) = KIID();
2800
2801 if( addToFootprint )
2802 m_zones.push_back( new_zone );
2803
2804 new_item = new_zone;
2805 break;
2806 }
2807
2808 case PCB_POINT_T:
2809 {
2810 PCB_POINT* new_point = new PCB_POINT( *static_cast<const PCB_POINT*>( aItem ) );
2811 const_cast<KIID&>( new_point->m_Uuid ) = KIID();
2812
2813 if( addToFootprint )
2814 m_points.push_back( new_point );
2815
2816 new_item = new_point;
2817 break;
2818 }
2819
2820 case PCB_FIELD_T:
2821 case PCB_TEXT_T:
2822 {
2823 PCB_TEXT* new_text = new PCB_TEXT( *static_cast<const PCB_TEXT*>( aItem ) );
2824 const_cast<KIID&>( new_text->m_Uuid ) = KIID();
2825
2826 if( aItem->Type() == PCB_FIELD_T )
2827 {
2828 switch( static_cast<const PCB_FIELD*>( aItem )->GetId() )
2829 {
2830 case FIELD_T::REFERENCE: new_text->SetText( wxT( "${REFERENCE}" ) ); break;
2831 case FIELD_T::VALUE: new_text->SetText( wxT( "${VALUE}" ) ); break;
2832 case FIELD_T::DATASHEET: new_text->SetText( wxT( "${DATASHEET}" ) ); break;
2833 default: break;
2834 }
2835 }
2836
2837 if( addToFootprint )
2838 Add( new_text );
2839
2840 new_item = new_text;
2841 break;
2842 }
2843
2844 case PCB_SHAPE_T:
2845 {
2846 PCB_SHAPE* new_shape = new PCB_SHAPE( *static_cast<const PCB_SHAPE*>( aItem ) );
2847 const_cast<KIID&>( new_shape->m_Uuid ) = KIID();
2848
2849 if( addToFootprint )
2850 Add( new_shape );
2851
2852 new_item = new_shape;
2853 break;
2854 }
2855
2856 case PCB_BARCODE_T:
2857 {
2858 PCB_BARCODE* new_barcode = new PCB_BARCODE( *static_cast<const PCB_BARCODE*>( aItem ) );
2859 const_cast<KIID&>( new_barcode->m_Uuid ) = KIID();
2860
2861 if( addToFootprint )
2862 Add( new_barcode );
2863
2864 new_item = new_barcode;
2865 break;
2866 }
2867
2869 {
2870 PCB_REFERENCE_IMAGE* new_image = new PCB_REFERENCE_IMAGE( *static_cast<const PCB_REFERENCE_IMAGE*>( aItem ) );
2871 const_cast<KIID&>( new_image->m_Uuid ) = KIID();
2872
2873 if( addToFootprint )
2874 Add( new_image );
2875
2876 new_item = new_image;
2877 break;
2878 }
2879
2880 case PCB_TEXTBOX_T:
2881 {
2882 PCB_TEXTBOX* new_textbox = new PCB_TEXTBOX( *static_cast<const PCB_TEXTBOX*>( aItem ) );
2883 const_cast<KIID&>( new_textbox->m_Uuid ) = KIID();
2884
2885 if( addToFootprint )
2886 Add( new_textbox );
2887
2888 new_item = new_textbox;
2889 break;
2890 }
2891
2892 case PCB_DIM_ALIGNED_T:
2893 case PCB_DIM_LEADER_T:
2894 case PCB_DIM_CENTER_T:
2895 case PCB_DIM_RADIAL_T:
2897 {
2898 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( aItem->Duplicate( addToParentGroup,
2899 aCommit ) );
2900
2901 if( addToFootprint )
2902 Add( dimension );
2903
2904 new_item = dimension;
2905 break;
2906 }
2907
2908 case PCB_GROUP_T:
2909 {
2910 PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem )->DeepDuplicate( addToParentGroup, aCommit );
2911
2912 if( addToFootprint )
2913 {
2914 group->RunOnChildren(
2915 [&]( BOARD_ITEM* aCurrItem )
2916 {
2917 Add( aCurrItem );
2918 },
2920
2921 Add( group );
2922 }
2923
2924 new_item = group;
2925 break;
2926 }
2927
2928 case PCB_FOOTPRINT_T:
2929 // Ignore the footprint itself
2930 break;
2931
2932 default:
2933 // Un-handled item for duplication
2934 wxFAIL_MSG( wxT( "Duplication not supported for items of class " ) + aItem->GetClass() );
2935 break;
2936 }
2937
2938 return new_item;
2939}
2940
2941
2942wxString FOOTPRINT::GetNextPadNumber( const wxString& aLastPadNumber ) const
2943{
2944 std::set<wxString> usedNumbers;
2945
2946 // Create a set of used pad numbers
2947 for( PAD* pad : m_pads )
2948 usedNumbers.insert( pad->GetNumber() );
2949
2950 // Pad numbers aren't technically reference designators, but the formatting is close enough
2951 // for these to give us what we need.
2952 wxString prefix = UTIL::GetRefDesPrefix( aLastPadNumber );
2953 int num = GetTrailingInt( aLastPadNumber );
2954
2955 while( usedNumbers.count( wxString::Format( wxT( "%s%d" ), prefix, num ) ) )
2956 num++;
2957
2958 return wxString::Format( wxT( "%s%d" ), prefix, num );
2959}
2960
2961
2962std::optional<const std::set<wxString>> FOOTPRINT::GetJumperPadGroup( const wxString& aPadNumber ) const
2963{
2964 for( const std::set<wxString>& group : m_jumperPadGroups )
2965 {
2966 if( group.contains( aPadNumber ) )
2967 return group;
2968 }
2969
2970 return std::nullopt;
2971}
2972
2973
2975{
2976 // Auto-position reference and value
2977 BOX2I bbox = GetBoundingBox( false );
2978 bbox.Inflate( pcbIUScale.mmToIU( 0.2 ) ); // Gap between graphics and text
2979
2980 if( Reference().GetPosition() == VECTOR2I( 0, 0 ) )
2981 {
2985
2986 Reference().SetX( bbox.GetCenter().x );
2987 Reference().SetY( bbox.GetTop() - Reference().GetTextSize().y / 2 );
2988 }
2989
2990 if( Value().GetPosition() == VECTOR2I( 0, 0 ) )
2991 {
2995
2996 Value().SetX( bbox.GetCenter().x );
2997 Value().SetY( bbox.GetBottom() + Value().GetTextSize().y / 2 );
2998 }
2999}
3000
3001
3003{
3004 const wxString& refdes = GetReference();
3005
3006 SetReference( wxString::Format( wxT( "%s%i" ),
3007 UTIL::GetRefDesPrefix( refdes ),
3008 GetTrailingInt( refdes ) + aDelta ) );
3009}
3010
3011
3012// Calculate the area of a PolySet, polygons with hole are allowed.
3013static double polygonArea( SHAPE_POLY_SET& aPolySet )
3014{
3015 // Ensure all outlines are closed, before calculating the SHAPE_POLY_SET area
3016 for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
3017 {
3018 SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
3019 outline.SetClosed( true );
3020
3021 for( int jj = 0; jj < aPolySet.HoleCount( ii ); jj++ )
3022 aPolySet.Hole( ii, jj ).SetClosed( true );
3023 }
3024
3025 return aPolySet.Area();
3026}
3027
3028
3029double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLECTOR& aCollector )
3030{
3031 int textMargin = aCollector.GetGuide()->Accuracy();
3032 SHAPE_POLY_SET poly;
3033
3034 if( aItem->Type() == PCB_MARKER_T )
3035 {
3036 const PCB_MARKER* marker = static_cast<const PCB_MARKER*>( aItem );
3037 SHAPE_LINE_CHAIN markerShape;
3038
3039 marker->ShapeToPolygon( markerShape );
3040 return markerShape.Area();
3041 }
3042 else if( aItem->Type() == PCB_GROUP_T || aItem->Type() == PCB_GENERATOR_T )
3043 {
3044 double combinedArea = 0.0;
3045
3046 for( BOARD_ITEM* member : static_cast<const PCB_GROUP*>( aItem )->GetBoardItems() )
3047 combinedArea += GetCoverageArea( member, aCollector );
3048
3049 return combinedArea;
3050 }
3051 if( aItem->Type() == PCB_FOOTPRINT_T )
3052 {
3053 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
3054
3055 poly = footprint->GetBoundingHull();
3056 }
3057 else if( aItem->Type() == PCB_FIELD_T || aItem->Type() == PCB_TEXT_T )
3058 {
3059 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
3060
3061 text->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
3062 }
3063 else if( aItem->Type() == PCB_TEXTBOX_T )
3064 {
3065 const PCB_TEXTBOX* tb = static_cast<const PCB_TEXTBOX*>( aItem );
3066
3067 tb->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
3068 }
3069 else if( aItem->Type() == PCB_SHAPE_T )
3070 {
3071 // Approximate "linear" shapes with just their width squared, as we don't want to consider
3072 // a linear shape as being much bigger than another for purposes of selection filtering
3073 // just because it happens to be really long.
3074
3075 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
3076
3077 switch( shape->GetShape() )
3078 {
3079 case SHAPE_T::SEGMENT:
3080 case SHAPE_T::ARC:
3081 case SHAPE_T::BEZIER:
3082 return shape->GetWidth() * shape->GetWidth();
3083
3084 case SHAPE_T::RECTANGLE:
3085 case SHAPE_T::CIRCLE:
3086 case SHAPE_T::POLY:
3087 {
3088 if( !shape->IsAnyFill() )
3089 return shape->GetWidth() * shape->GetWidth();
3090
3092 }
3093
3094 default:
3096 }
3097 }
3098 else if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
3099 {
3100 double width = static_cast<const PCB_TRACK*>( aItem )->GetWidth();
3101 return width * width;
3102 }
3103 else if( aItem->Type() == PCB_PAD_T )
3104 {
3105 static_cast<const PAD*>( aItem )->Padstack().ForEachUniqueLayer(
3106 [&]( PCB_LAYER_ID aLayer )
3107 {
3108 SHAPE_POLY_SET layerPoly;
3109 aItem->TransformShapeToPolygon( layerPoly, aLayer, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
3110 poly.BooleanAdd( layerPoly );
3111 } );
3112 }
3113 else
3114 {
3116 }
3117
3118 return polygonArea( poly );
3119}
3120
3121
3122double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
3123{
3124 int textMargin = aCollector.GetGuide()->Accuracy();
3125
3126 SHAPE_POLY_SET footprintRegion( GetBoundingHull() );
3127 SHAPE_POLY_SET coveredRegion;
3128
3130
3131 TransformFPShapesToPolySet( coveredRegion, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF,
3133 true, /* include text */
3134 false, /* include shapes */
3135 false /* include private items */ );
3136
3137 for( int i = 0; i < aCollector.GetCount(); ++i )
3138 {
3139 const BOARD_ITEM* item = aCollector[i];
3140
3141 switch( item->Type() )
3142 {
3143 case PCB_FIELD_T:
3144 case PCB_TEXT_T:
3145 case PCB_TEXTBOX_T:
3146 case PCB_SHAPE_T:
3147 case PCB_BARCODE_T:
3148 case PCB_TRACE_T:
3149 case PCB_ARC_T:
3150 case PCB_VIA_T:
3151 if( item->GetParent() != this )
3152 {
3153 item->TransformShapeToPolygon( coveredRegion, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
3154 ERROR_OUTSIDE );
3155 }
3156 break;
3157
3158 case PCB_FOOTPRINT_T:
3159 if( item != this )
3160 {
3161 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( item );
3162 coveredRegion.AddOutline( footprint->GetBoundingHull().Outline( 0 ) );
3163 }
3164 break;
3165
3166 default:
3167 break;
3168 }
3169 }
3170
3171 coveredRegion.BooleanIntersection( footprintRegion );
3172
3173 double footprintRegionArea = polygonArea( footprintRegion );
3174 double uncoveredRegionArea = footprintRegionArea - polygonArea( coveredRegion );
3175 double coveredArea = footprintRegionArea - uncoveredRegionArea;
3176
3177 // Avoid div-by-zero (this will result in the disambiguate dialog)
3178 if( footprintRegionArea == 0 )
3179 return 1.0;
3180
3181 double ratio = coveredArea / footprintRegionArea;
3182
3183 // Test for negative ratio (should not occur).
3184 // better to be conservative (this will result in the disambiguate dialog)
3185 if( ratio < 0.0 )
3186 return 1.0;
3187
3188 return std::min( ratio, 1.0 );
3189}
3190
3191
3192std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
3193{
3194 std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
3195
3196 // There are several possible interpretations here:
3197 // 1) the bounding box (without or without invisible items)
3198 // 2) just the pads and "edges" (ie: non-text graphic items)
3199 // 3) the courtyard
3200
3201 // We'll go with (2) for now, unless the caller is clearly looking for (3)
3202
3203 if( aLayer == F_CrtYd || aLayer == B_CrtYd )
3204 {
3205 const SHAPE_POLY_SET& courtyard = GetCourtyard( aLayer );
3206
3207 if( courtyard.OutlineCount() == 0 ) // malformed/empty polygon
3208 return shape;
3209
3210 shape->AddShape( new SHAPE_SIMPLE( courtyard.COutline( 0 ) ) );
3211 }
3212 else
3213 {
3214 for( PAD* pad : Pads() )
3215 shape->AddShape( pad->GetEffectiveShape( aLayer, aFlash )->Clone() );
3216
3217 for( BOARD_ITEM* item : GraphicalItems() )
3218 {
3219 if( item->Type() == PCB_SHAPE_T )
3220 shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->Clone() );
3221 else if( item->Type() == PCB_BARCODE_T )
3222 shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->Clone() );
3223 }
3224 }
3225
3226 return shape;
3227}
3228
3229
3231{
3232 std::lock_guard<std::mutex> lock( m_courtyard_cache_mutex );
3233
3236 {
3237 const_cast<FOOTPRINT*>(this)->BuildCourtyardCaches();
3238 }
3239
3240 return GetCachedCourtyard( aLayer );
3241}
3242
3243
3245{
3246 if( IsBackLayer( aLayer ) )
3248 else
3250}
3251
3252
3254{
3255 m_courtyard_cache_front.RemoveAllContours();
3256 m_courtyard_cache_back.RemoveAllContours();
3258
3259 // Build the courtyard area from graphic items on the courtyard.
3260 // Only PCB_SHAPE_T have meaning, graphic texts are ignored.
3261 // Collect items:
3262 std::vector<PCB_SHAPE*> list_front;
3263 std::vector<PCB_SHAPE*> list_back;
3264 std::map<int, int> front_width_histogram;
3265 std::map<int, int> back_width_histogram;
3266
3267 for( BOARD_ITEM* item : GraphicalItems() )
3268 {
3269 if( item->GetLayer() == B_CrtYd && item->Type() == PCB_SHAPE_T )
3270 {
3271 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
3272 list_back.push_back( shape );
3273 back_width_histogram[ shape->GetStroke().GetWidth() ]++;
3274 }
3275
3276 if( item->GetLayer() == F_CrtYd && item->Type() == PCB_SHAPE_T )
3277 {
3278 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
3279 list_front.push_back( shape );
3280 front_width_histogram[ shape->GetStroke().GetWidth() ]++;
3281 }
3282 }
3283
3284 if( !list_front.size() && !list_back.size() )
3285 return;
3286
3287 int maxError = pcbIUScale.mmToIU( 0.005 ); // max error for polygonization
3288 int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt
3289
3290 if( ConvertOutlineToPolygon( list_front, m_courtyard_cache_front, maxError, chainingEpsilon,
3291 true, aErrorHandler ) )
3292 {
3293 int width = 0;
3294
3295 // Touching courtyards, or courtyards -at- the clearance distance are legal.
3296 // Use maxError here because that is the allowed deviation when transforming arcs/circles to
3297 // polygons.
3299
3300 m_courtyard_cache_front.CacheTriangulation( false );
3301 auto max = std::max_element( front_width_histogram.begin(), front_width_histogram.end(),
3302 []( const std::pair<int, int>& a, const std::pair<int, int>& b )
3303 {
3304 return a.second < b.second;
3305 } );
3306
3307 if( max != front_width_histogram.end() )
3308 width = max->first;
3309
3310 if( width == 0 )
3311 width = pcbIUScale.mmToIU( DEFAULT_COURTYARD_WIDTH );
3312
3313 if( m_courtyard_cache_front.OutlineCount() > 0 )
3314 m_courtyard_cache_front.Outline( 0 ).SetWidth( width );
3315 }
3316 else
3317 {
3319 }
3320
3321 if( ConvertOutlineToPolygon( list_back, m_courtyard_cache_back, maxError, chainingEpsilon, true,
3322 aErrorHandler ) )
3323 {
3324 int width = 0;
3325
3326 // Touching courtyards, or courtyards -at- the clearance distance are legal.
3327 m_courtyard_cache_back.Inflate( -maxError, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, maxError );
3328
3329 m_courtyard_cache_back.CacheTriangulation( false );
3330 auto max = std::max_element( back_width_histogram.begin(), back_width_histogram.end(),
3331 []( const std::pair<int, int>& a, const std::pair<int, int>& b )
3332 {
3333 return a.second < b.second;
3334 } );
3335
3336 if( max != back_width_histogram.end() )
3337 width = max->first;
3338
3339 if( width == 0 )
3340 width = pcbIUScale.mmToIU( DEFAULT_COURTYARD_WIDTH );
3341
3342 if( m_courtyard_cache_back.OutlineCount() > 0 )
3343 m_courtyard_cache_back.Outline( 0 ).SetWidth( width );
3344 }
3345 else
3346 {
3348 }
3349
3352}
3353
3354
3356{
3357 m_netTieCache.clear();
3358 std::map<wxString, int> map = MapPadNumbersToNetTieGroups();
3359 std::map<PCB_LAYER_ID, std::vector<PCB_SHAPE*>> layer_shapes;
3360 BOARD* board = GetBoard();
3361
3362 std::for_each( m_drawings.begin(), m_drawings.end(),
3363 [&]( BOARD_ITEM* item )
3364 {
3365 if( item->Type() != PCB_SHAPE_T )
3366 return;
3367
3368 for( PCB_LAYER_ID layer : item->GetLayerSet() )
3369 {
3370 if( !IsCopperLayer( layer ) )
3371 continue;
3372
3373 if( board && !board->GetEnabledLayers().Contains( layer ) )
3374 continue;
3375
3376 layer_shapes[layer].push_back( static_cast<PCB_SHAPE*>( item ) );
3377 }
3378 } );
3379
3380 for( size_t ii = 0; ii < m_pads.size(); ++ii )
3381 {
3382 PAD* pad = m_pads[ ii ];
3383 bool has_nettie = false;
3384
3385 auto it = map.find( pad->GetNumber() );
3386
3387 if( it == map.end() || it->second < 0 )
3388 continue;
3389
3390 for( size_t jj = ii + 1; jj < m_pads.size(); ++jj )
3391 {
3392 PAD* other = m_pads[ jj ];
3393
3394 auto it2 = map.find( other->GetNumber() );
3395
3396 if( it2 == map.end() || it2->second < 0 )
3397 continue;
3398
3399 if( it2->second == it->second )
3400 {
3401 m_netTieCache[pad].insert( pad->GetNetCode() );
3402 m_netTieCache[pad].insert( other->GetNetCode() );
3403 m_netTieCache[other].insert( other->GetNetCode() );
3404 m_netTieCache[other].insert( pad->GetNetCode() );
3405 has_nettie = true;
3406 }
3407 }
3408
3409 if( !has_nettie )
3410 continue;
3411
3412 for( auto& [ layer, shapes ] : layer_shapes )
3413 {
3414 auto pad_shape = pad->GetEffectiveShape( layer );
3415
3416 for( auto other_shape : shapes )
3417 {
3418 auto shape = other_shape->GetEffectiveShape( layer );
3419
3420 if( pad_shape->Collide( shape.get() ) )
3421 {
3422 std::set<int>& nettie = m_netTieCache[pad];
3423 m_netTieCache[other_shape].insert( nettie.begin(), nettie.end() );
3424 }
3425 }
3426 }
3427 }
3428}
3429
3430
3431std::map<wxString, int> FOOTPRINT::MapPadNumbersToNetTieGroups() const
3432{
3433 std::map<wxString, int> padNumberToGroupIdxMap;
3434
3435 for( const PAD* pad : m_pads )
3436 padNumberToGroupIdxMap[ pad->GetNumber() ] = -1;
3437
3438 auto processPad =
3439 [&]( wxString aPad, int aGroup )
3440 {
3441 aPad.Trim( true ).Trim( false );
3442
3443 if( !aPad.IsEmpty() )
3444 padNumberToGroupIdxMap[ aPad ] = aGroup;
3445 };
3446
3447 for( int ii = 0; ii < (int) m_netTiePadGroups.size(); ++ii )
3448 {
3449 wxString group( m_netTiePadGroups[ ii ] );
3450 bool esc = false;
3451 wxString pad;
3452
3453 for( wxUniCharRef ch : group )
3454 {
3455 if( esc )
3456 {
3457 esc = false;
3458 pad.Append( ch );
3459 continue;
3460 }
3461
3462 switch( static_cast<unsigned char>( ch ) )
3463 {
3464 case '\\':
3465 esc = true;
3466 break;
3467
3468 case ',':
3469 processPad( pad, ii );
3470 pad.Clear();
3471 break;
3472
3473 default:
3474 pad.Append( ch );
3475 break;
3476 }
3477 }
3478
3479 processPad( pad, ii );
3480 }
3481
3482 return padNumberToGroupIdxMap;
3483}
3484
3485
3486std::vector<PAD*> FOOTPRINT::GetNetTiePads( PAD* aPad ) const
3487{
3488 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
3489 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
3490
3491 std::map<wxString, int> padToNetTieGroupMap = MapPadNumbersToNetTieGroups();
3492 int groupIdx = padToNetTieGroupMap[ aPad->GetNumber() ];
3493 std::vector<PAD*> otherPads;
3494
3495 if( groupIdx >= 0 )
3496 {
3497 for( PAD* pad : m_pads )
3498 {
3499 if( padToNetTieGroupMap[ pad->GetNumber() ] == groupIdx )
3500 otherPads.push_back( pad );
3501 }
3502 }
3503
3504 return otherPads;
3505}
3506
3507
3508void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxString& )>& aErrorHandler )
3509{
3510 int likelyAttr = ( GetLikelyAttribute() & ( FP_SMD | FP_THROUGH_HOLE ) );
3511 int setAttr = ( GetAttributes() & ( FP_SMD | FP_THROUGH_HOLE ) );
3512
3513 if( setAttr && likelyAttr && setAttr != likelyAttr )
3514 {
3515 wxString msg;
3516
3517 switch( likelyAttr )
3518 {
3519 case FP_THROUGH_HOLE:
3520 msg.Printf( _( "(expected 'Through hole'; actual '%s')" ), GetTypeName() );
3521 break;
3522 case FP_SMD:
3523 msg.Printf( _( "(expected 'SMD'; actual '%s')" ), GetTypeName() );
3524 break;
3525 }
3526
3527 if( aErrorHandler )
3528 (aErrorHandler)( msg );
3529 }
3530}
3531
3532
3534 const std::function<void( const PAD*, int,
3535 const wxString& )>& aErrorHandler )
3536{
3537 if( aErrorHandler == nullptr )
3538 return;
3539
3540 for( PAD* pad: Pads() )
3541 {
3542 pad->CheckPad( aUnitsProvider, false,
3543 [&]( int errorCode, const wxString& msg )
3544 {
3545 aErrorHandler( pad, errorCode, msg );
3546 } );
3547 }
3548}
3549
3550
3551void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const PAD*,
3552 int aErrorCode,
3553 const VECTOR2I& )>& aErrorHandler )
3554{
3555 std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
3556
3557 for( PAD* pad : Pads() )
3558 {
3559 std::vector<PAD*> netTiePads = GetNetTiePads( pad );
3560
3561 for( PAD* other : Pads() )
3562 {
3563 if( other == pad )
3564 continue;
3565
3566 // store canonical order so we don't collide in both directions (a:b and b:a)
3567 PAD* a = pad;
3568 PAD* b = other;
3569
3570 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
3571 std::swap( a, b );
3572
3573 if( checkedPairs.find( { a, b } ) == checkedPairs.end() )
3574 {
3575 checkedPairs[ { a, b } ] = 1;
3576
3577 if( pad->HasDrilledHole() && other->HasDrilledHole() )
3578 {
3579 VECTOR2I pos = pad->GetPosition();
3580
3581 if( pad->GetPosition() == other->GetPosition() )
3582 {
3583 aErrorHandler( pad, other, DRCE_DRILLED_HOLES_COLOCATED, pos );
3584 }
3585 else
3586 {
3587 std::shared_ptr<SHAPE_SEGMENT> holeA = pad->GetEffectiveHoleShape();
3588 std::shared_ptr<SHAPE_SEGMENT> holeB = other->GetEffectiveHoleShape();
3589
3590 if( holeA->Collide( holeB->GetSeg(), 0 ) )
3591 aErrorHandler( pad, other, DRCE_DRILLED_HOLES_TOO_CLOSE, pos );
3592 }
3593 }
3594
3595 if( pad->SameLogicalPadAs( other ) || alg::contains( netTiePads, other ) )
3596 continue;
3597
3598 if( !( ( pad->GetLayerSet() & other->GetLayerSet() ) & LSET::AllCuMask() ).any() )
3599 continue;
3600
3601 if( pad->GetBoundingBox().Intersects( other->GetBoundingBox() ) )
3602 {
3603 VECTOR2I pos;
3604
3605 for( PCB_LAYER_ID l : pad->Padstack().RelevantShapeLayers( other->Padstack() ) )
3606 {
3607 SHAPE* padShape = pad->GetEffectiveShape( l ).get();
3608 SHAPE* otherShape = other->GetEffectiveShape( l ).get();
3609
3610 if( padShape->Collide( otherShape, 0, nullptr, &pos ) )
3611 aErrorHandler( pad, other, DRCE_SHORTING_ITEMS, pos );
3612 }
3613 }
3614 }
3615 }
3616 }
3617}
3618
3619
3620void FOOTPRINT::CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
3621 const BOARD_ITEM* bItem,
3622 const BOARD_ITEM* cItem,
3623 const VECTOR2I& )>& aErrorHandler )
3624{
3625 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
3626 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
3627
3628 std::map<wxString, int> padNumberToGroupIdxMap = MapPadNumbersToNetTieGroups();
3629
3630 // Now collect all the footprint items which are on copper layers
3631
3632 std::vector<BOARD_ITEM*> copperItems;
3633
3634 for( BOARD_ITEM* item : m_drawings )
3635 {
3636 if( item->IsOnCopperLayer() )
3637 copperItems.push_back( item );
3638
3639 item->RunOnChildren(
3640 [&]( BOARD_ITEM* descendent )
3641 {
3642 if( descendent->IsOnCopperLayer() )
3643 copperItems.push_back( descendent );
3644 },
3646 }
3647
3648 for( ZONE* zone : m_zones )
3649 {
3650 if( !zone->GetIsRuleArea() && zone->IsOnCopperLayer() )
3651 copperItems.push_back( zone );
3652 }
3653
3654 for( PCB_FIELD* field : m_fields )
3655 {
3656 if( field->IsOnCopperLayer() )
3657 copperItems.push_back( field );
3658 }
3659
3660 for( PCB_LAYER_ID layer : { F_Cu, In1_Cu, B_Cu } )
3661 {
3662 // Next, build a polygon-set for the copper on this layer. We don't really care about
3663 // nets here, we just want to end up with a set of outlines describing the distinct
3664 // copper polygons of the footprint.
3665
3666 SHAPE_POLY_SET copperOutlines;
3667 std::map<int, std::vector<const PAD*>> outlineIdxToPadsMap;
3668
3669 for( BOARD_ITEM* item : copperItems )
3670 {
3671 if( item->IsOnLayer( layer ) )
3672 item->TransformShapeToPolygon( copperOutlines, layer, 0, GetMaxError(), ERROR_OUTSIDE );
3673 }
3674
3675 copperOutlines.Simplify();
3676
3677 // Index each pad to the outline in the set that it is part of.
3678
3679 for( const PAD* pad : m_pads )
3680 {
3681 for( int ii = 0; ii < copperOutlines.OutlineCount(); ++ii )
3682 {
3683 if( pad->GetEffectiveShape( layer )->Collide( &copperOutlines.Outline( ii ), 0 ) )
3684 outlineIdxToPadsMap[ ii ].emplace_back( pad );
3685 }
3686 }
3687
3688 // Finally, ensure that each outline which contains multiple pads has all its pads
3689 // listed in an allowed-shorting group.
3690
3691 for( const auto& [ outlineIdx, pads ] : outlineIdxToPadsMap )
3692 {
3693 if( pads.size() > 1 )
3694 {
3695 const PAD* firstPad = pads[0];
3696 int firstGroupIdx = padNumberToGroupIdxMap[ firstPad->GetNumber() ];
3697
3698 for( size_t ii = 1; ii < pads.size(); ++ii )
3699 {
3700 const PAD* thisPad = pads[ii];
3701 int thisGroupIdx = padNumberToGroupIdxMap[ thisPad->GetNumber() ];
3702
3703 if( thisGroupIdx < 0 || thisGroupIdx != firstGroupIdx )
3704 {
3705 BOARD_ITEM* shortingItem = nullptr;
3706 VECTOR2I pos = ( firstPad->GetPosition() + thisPad->GetPosition() ) / 2;
3707
3708 pos = copperOutlines.Outline( outlineIdx ).NearestPoint( pos );
3709
3710 for( BOARD_ITEM* item : copperItems )
3711 {
3712 if( item->HitTest( pos, 1 ) )
3713 {
3714 shortingItem = item;
3715 break;
3716 }
3717 }
3718
3719 if( shortingItem )
3720 aErrorHandler( shortingItem, firstPad, thisPad, pos );
3721 else
3722 aErrorHandler( firstPad, thisPad, nullptr, pos );
3723 }
3724 }
3725 }
3726 }
3727 }
3728}
3729
3730
3731void FOOTPRINT::CheckNetTiePadGroups( const std::function<void( const wxString& )>& aErrorHandler )
3732{
3733 std::set<wxString> padNumbers;
3734 wxString msg;
3735
3736 for( const auto& [ padNumber, _ ] : MapPadNumbersToNetTieGroups() )
3737 {
3738 const PAD* pad = FindPadByNumber( padNumber );
3739
3740 if( !pad )
3741 {
3742 msg.Printf( _( "(net-tie pad group contains unknown pad number %s)" ), padNumber );
3743 aErrorHandler( msg );
3744 }
3745 else if( !padNumbers.insert( pad->GetNumber() ).second )
3746 {
3747 msg.Printf( _( "(pad %s appears in more than one net-tie pad group)" ), padNumber );
3748 aErrorHandler( msg );
3749 }
3750 }
3751}
3752
3753
3754void FOOTPRINT::CheckClippedSilk( const std::function<void( BOARD_ITEM* aItemA,
3755 BOARD_ITEM* aItemB,
3756 const VECTOR2I& aPt )>& aErrorHandler )
3757{
3758 auto checkColliding =
3759 [&]( BOARD_ITEM* item, BOARD_ITEM* other )
3760 {
3761 for( PCB_LAYER_ID silk : { F_SilkS, B_SilkS } )
3762 {
3763 PCB_LAYER_ID mask = silk == F_SilkS ? F_Mask : B_Mask;
3764
3765 if( !item->IsOnLayer( silk ) || !other->IsOnLayer( mask ) )
3766 continue;
3767
3768 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( silk );
3769 std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( mask );
3770 int actual;
3771 VECTOR2I pos;
3772
3773 if( itemShape->Collide( otherShape.get(), 0, &actual, &pos ) )
3774 aErrorHandler( item, other, pos );
3775 }
3776 };
3777
3778 for( BOARD_ITEM* item : m_drawings )
3779 {
3780 for( BOARD_ITEM* other : m_drawings )
3781 {
3782 if( other != item )
3783 checkColliding( item, other );
3784 }
3785
3786 for( PAD* pad : m_pads )
3787 checkColliding( item, pad );
3788 }
3789}
3790
3791
3793{
3794 wxASSERT( aImage->Type() == PCB_FOOTPRINT_T );
3795
3796 FOOTPRINT* image = static_cast<FOOTPRINT*>( aImage );
3797
3798 std::swap( *this, *image );
3799
3801 [&]( BOARD_ITEM* child )
3802 {
3803 child->SetParent( this );
3804 },
3806
3807 image->RunOnChildren(
3808 [&]( BOARD_ITEM* child )
3809 {
3810 child->SetParent( image );
3811 },
3813}
3814
3815
3817{
3818 for( PAD* pad : Pads() )
3819 {
3820 if( pad->GetAttribute() != PAD_ATTRIB::SMD )
3821 return true;
3822 }
3823
3824 return false;
3825}
3826
3827
3828bool FOOTPRINT::operator==( const BOARD_ITEM& aOther ) const
3829{
3830 if( aOther.Type() != PCB_FOOTPRINT_T )
3831 return false;
3832
3833 const FOOTPRINT& other = static_cast<const FOOTPRINT&>( aOther );
3834
3835 return *this == other;
3836}
3837
3838
3839bool FOOTPRINT::operator==( const FOOTPRINT& aOther ) const
3840{
3841 if( m_pads.size() != aOther.m_pads.size() )
3842 return false;
3843
3844 for( size_t ii = 0; ii < m_pads.size(); ++ii )
3845 {
3846 if( !( *m_pads[ii] == *aOther.m_pads[ii] ) )
3847 return false;
3848 }
3849
3850 if( m_drawings.size() != aOther.m_drawings.size() )
3851 return false;
3852
3853 for( size_t ii = 0; ii < m_drawings.size(); ++ii )
3854 {
3855 if( !( *m_drawings[ii] == *aOther.m_drawings[ii] ) )
3856 return false;
3857 }
3858
3859 if( m_zones.size() != aOther.m_zones.size() )
3860 return false;
3861
3862 for( size_t ii = 0; ii < m_zones.size(); ++ii )
3863 {
3864 if( !( *m_zones[ii] == *aOther.m_zones[ii] ) )
3865 return false;
3866 }
3867
3868 if( m_points.size() != aOther.m_points.size() )
3869 return false;
3870
3871 // Compare fields in ordinally-sorted order
3872 std::vector<PCB_FIELD*> fields, otherFields;
3873
3874 GetFields( fields, false );
3875 aOther.GetFields( otherFields, false );
3876
3877 if( fields.size() != otherFields.size() )
3878 return false;
3879
3880 for( size_t ii = 0; ii < fields.size(); ++ii )
3881 {
3882 if( fields[ii] )
3883 {
3884 if( !( *fields[ii] == *otherFields[ii] ) )
3885 return false;
3886 }
3887 }
3888
3889 return true;
3890}
3891
3892
3893double FOOTPRINT::Similarity( const BOARD_ITEM& aOther ) const
3894{
3895 if( aOther.Type() != PCB_FOOTPRINT_T )
3896 return 0.0;
3897
3898 const FOOTPRINT& other = static_cast<const FOOTPRINT&>( aOther );
3899
3900 double similarity = 1.0;
3901
3902 for( const PAD* pad : m_pads)
3903 {
3904 const PAD* otherPad = other.FindPadByNumber( pad->GetNumber() );
3905
3906 if( !otherPad )
3907 continue;
3908
3909 similarity *= pad->Similarity( *otherPad );
3910 }
3911
3912 return similarity;
3913}
3914
3915
3919static constexpr std::optional<bool> cmp_points_opt( const VECTOR2I& aPtA, const VECTOR2I& aPtB )
3920{
3921 if( aPtA.x != aPtB.x )
3922 return aPtA.x < aPtB.x;
3923
3924 if( aPtA.y != aPtB.y )
3925 return aPtA.y < aPtB.y;
3926
3927 return std::nullopt;
3928}
3929
3930
3931bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* itemA, const BOARD_ITEM* itemB ) const
3932{
3933 if( itemA->Type() != itemB->Type() )
3934 return itemA->Type() < itemB->Type();
3935
3936 if( itemA->GetLayer() != itemB->GetLayer() )
3937 return itemA->GetLayer() < itemB->GetLayer();
3938
3939 switch( itemA->Type() )
3940 {
3941 case PCB_SHAPE_T:
3942 {
3943 const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( itemA );
3944 const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( itemB );
3945
3946 if( dwgA->GetShape() != dwgB->GetShape() )
3947 return dwgA->GetShape() < dwgB->GetShape();
3948
3949 // GetStart() and GetEnd() have no meaning with polygons.
3950 // We cannot use them for sorting polygons
3951 if( dwgA->GetShape() != SHAPE_T::POLY )
3952 {
3953 if( std::optional<bool> cmp = cmp_points_opt( dwgA->GetStart(), dwgB->GetStart() ) )
3954 return *cmp;
3955
3956 if( std::optional<bool> cmp = cmp_points_opt( dwgA->GetEnd(), dwgB->GetEnd() ) )
3957 return *cmp;
3958 }
3959
3960 if( dwgA->GetShape() == SHAPE_T::ARC )
3961 {
3962 if( std::optional<bool> cmp = cmp_points_opt( dwgA->GetCenter(), dwgB->GetCenter() ) )
3963 return *cmp;
3964 }
3965 else if( dwgA->GetShape() == SHAPE_T::BEZIER )
3966 {
3967 if( std::optional<bool> cmp = cmp_points_opt( dwgA->GetBezierC1(), dwgB->GetBezierC1() ) )
3968 return *cmp;
3969
3970 if( std::optional<bool> cmp = cmp_points_opt( dwgA->GetBezierC2(), dwgB->GetBezierC2() ) )
3971 return *cmp;
3972 }
3973 else if( dwgA->GetShape() == SHAPE_T::POLY )
3974 {
3975 if( dwgA->GetPolyShape().TotalVertices() != dwgB->GetPolyShape().TotalVertices() )
3976 return dwgA->GetPolyShape().TotalVertices() < dwgB->GetPolyShape().TotalVertices();
3977
3978 for( int ii = 0; ii < dwgA->GetPolyShape().TotalVertices(); ++ii )
3979 {
3980 if( std::optional<bool> cmp =
3981 cmp_points_opt( dwgA->GetPolyShape().CVertex( ii ), dwgB->GetPolyShape().CVertex( ii ) ) )
3982 {
3983 return *cmp;
3984 }
3985 }
3986 }
3987
3988 if( dwgA->GetWidth() != dwgB->GetWidth() )
3989 return dwgA->GetWidth() < dwgB->GetWidth();
3990
3991 break;
3992 }
3993 case PCB_TEXT_T:
3994 {
3995 const PCB_TEXT& textA = static_cast<const PCB_TEXT&>( *itemA );
3996 const PCB_TEXT& textB = static_cast<const PCB_TEXT&>( *itemB );
3997
3998 if( std::optional<bool> cmp = cmp_points_opt( textA.GetPosition(), textB.GetPosition() ) )
3999 return *cmp;
4000
4001 if( textA.GetTextAngle() != textB.GetTextAngle() )
4002 return textA.GetTextAngle() < textB.GetTextAngle();
4003
4004 if( std::optional<bool> cmp = cmp_points_opt( textA.GetTextSize(), textB.GetTextSize() ) )
4005 return *cmp;
4006
4007 if( textA.GetTextThickness() != textB.GetTextThickness() )
4008 return textA.GetTextThickness() < textB.GetTextThickness();
4009
4010 if( textA.IsBold() != textB.IsBold() )
4011 return textA.IsBold() < textB.IsBold();
4012
4013 if( textA.IsItalic() != textB.IsItalic() )
4014 return textA.IsItalic() < textB.IsItalic();
4015
4016 if( textA.IsMirrored() != textB.IsMirrored() )
4017 return textA.IsMirrored() < textB.IsMirrored();
4018
4019 if( textA.GetLineSpacing() != textB.GetLineSpacing() )
4020 return textA.GetLineSpacing() < textB.GetLineSpacing();
4021
4022 if( textA.GetText() != textB.GetText() )
4023 return textA.GetText().Cmp( textB.GetText() ) < 0;
4024
4025 break;
4026 }
4027 default:
4028 {
4029 // These items don't have their own specific sorting criteria.
4030 break;
4031 }
4032 }
4033
4034 if( itemA->m_Uuid != itemB->m_Uuid )
4035 return itemA->m_Uuid < itemB->m_Uuid;
4036
4037 return itemA < itemB;
4038}
4039
4040
4041bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) const
4042{
4043 if( aFirst->GetNumber() != aSecond->GetNumber() )
4044 return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
4045
4046 if( std::optional<bool> cmp = cmp_points_opt( aFirst->GetFPRelativePosition(), aSecond->GetFPRelativePosition() ) )
4047 return *cmp;
4048
4049 std::optional<bool> padCopperMatches;
4050
4051 // Pick the "most complex" padstack to iterate
4052 const PAD* checkPad = aFirst;
4053
4054 if( aSecond->Padstack().Mode() == PADSTACK::MODE::CUSTOM
4055 || ( aSecond->Padstack().Mode() == PADSTACK::MODE::FRONT_INNER_BACK &&
4056 aFirst->Padstack().Mode() == PADSTACK::MODE::NORMAL ) )
4057 {
4058 checkPad = aSecond;
4059 }
4060
4061 checkPad->Padstack().ForEachUniqueLayer(
4062 [&]( PCB_LAYER_ID aLayer )
4063 {
4064 if( aFirst->GetSize( aLayer ).x != aSecond->GetSize( aLayer ).x )
4065 padCopperMatches = aFirst->GetSize( aLayer ).x < aSecond->GetSize( aLayer ).x;
4066 else if( aFirst->GetSize( aLayer ).y != aSecond->GetSize( aLayer ).y )
4067 padCopperMatches = aFirst->GetSize( aLayer ).y < aSecond->GetSize( aLayer ).y;
4068 else if( aFirst->GetShape( aLayer ) != aSecond->GetShape( aLayer ) )
4069 padCopperMatches = aFirst->GetShape( aLayer ) < aSecond->GetShape( aLayer );
4070 } );
4071
4072 if( padCopperMatches.has_value() )
4073 return *padCopperMatches;
4074
4075 if( aFirst->GetLayerSet() != aSecond->GetLayerSet() )
4076 return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
4077
4078 if( aFirst->m_Uuid != aSecond->m_Uuid )
4079 return aFirst->m_Uuid < aSecond->m_Uuid;
4080
4081 return aFirst < aSecond;
4082}
4083
4084
4085#if 0
4086bool FOOTPRINT::cmp_padstack::operator()( const PAD* aFirst, const PAD* aSecond ) const
4087{
4088 if( aFirst->GetSize().x != aSecond->GetSize().x )
4089 return aFirst->GetSize().x < aSecond->GetSize().x;
4090 if( aFirst->GetSize().y != aSecond->GetSize().y )
4091 return aFirst->GetSize().y < aSecond->GetSize().y;
4092
4093 if( aFirst->GetShape() != aSecond->GetShape() )
4094 return aFirst->GetShape() < aSecond->GetShape();
4095
4096 if( aFirst->GetLayerSet() != aSecond->GetLayerSet() )
4097 return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
4098
4099 if( aFirst->GetDrillSizeX() != aSecond->GetDrillSizeX() )
4100 return aFirst->GetDrillSizeX() < aSecond->GetDrillSizeX();
4101
4102 if( aFirst->GetDrillSizeY() != aSecond->GetDrillSizeY() )
4103 return aFirst->GetDrillSizeY() < aSecond->GetDrillSizeY();
4104
4105 if( aFirst->GetDrillShape() != aSecond->GetDrillShape() )
4106 return aFirst->GetDrillShape() < aSecond->GetDrillShape();
4107
4108 if( aFirst->GetAttribute() != aSecond->GetAttribute() )
4109 return aFirst->GetAttribute() < aSecond->GetAttribute();
4110
4111 if( aFirst->GetOrientation() != aSecond->GetOrientation() )
4112 return aFirst->GetOrientation() < aSecond->GetOrientation();
4113
4114 if( aFirst->GetSolderMaskExpansion() != aSecond->GetSolderMaskExpansion() )
4115 return aFirst->GetSolderMaskExpansion() < aSecond->GetSolderMaskExpansion();
4116
4117 if( aFirst->GetSolderPasteMargin() != aSecond->GetSolderPasteMargin() )
4118 return aFirst->GetSolderPasteMargin() < aSecond->GetSolderPasteMargin();
4119
4120 if( aFirst->GetLocalSolderMaskMargin() != aSecond->GetLocalSolderMaskMargin() )
4121 return aFirst->GetLocalSolderMaskMargin() < aSecond->GetLocalSolderMaskMargin();
4122
4123 const std::shared_ptr<SHAPE_POLY_SET>& firstShape = aFirst->GetEffectivePolygon( ERROR_INSIDE );
4124 const std::shared_ptr<SHAPE_POLY_SET>& secondShape = aSecond->GetEffectivePolygon( ERROR_INSIDE );
4125
4126 if( firstShape->VertexCount() != secondShape->VertexCount() )
4127 return firstShape->VertexCount() < secondShape->VertexCount();
4128
4129 for( int ii = 0; ii < firstShape->VertexCount(); ++ii )
4130 {
4131 if( std::optional<bool> cmp = cmp_points_opt( firstShape->CVertex( ii ), secondShape->CVertex( ii ) ) )
4132 {
4133 return *cmp;
4134 }
4135 }
4136
4137 return false;
4138}
4139#endif
4140
4141
4142bool FOOTPRINT::cmp_zones::operator()( const ZONE* aFirst, const ZONE* aSecond ) const
4143{
4144 if( aFirst->GetAssignedPriority() != aSecond->GetAssignedPriority() )
4145 return aFirst->GetAssignedPriority() < aSecond->GetAssignedPriority();
4146
4147 if( aFirst->GetLayerSet() != aSecond->GetLayerSet() )
4148 return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
4149
4150 if( aFirst->Outline()->TotalVertices() != aSecond->Outline()->TotalVertices() )
4151 return aFirst->Outline()->TotalVertices() < aSecond->Outline()->TotalVertices();
4152
4153 for( int ii = 0; ii < aFirst->Outline()->TotalVertices(); ++ii )
4154 {
4155 if( std::optional<bool> cmp =
4156 cmp_points_opt( aFirst->Outline()->CVertex( ii ), aSecond->Outline()->CVertex( ii ) ) )
4157 {
4158 return *cmp;
4159 }
4160 }
4161
4162 if( aFirst->m_Uuid != aSecond->m_Uuid )
4163 return aFirst->m_Uuid < aSecond->m_Uuid;
4164
4165 return aFirst < aSecond;
4166}
4167
4168
4170 int aMaxError, ERROR_LOC aErrorLoc ) const
4171{
4172 auto processPad =
4173 [&]( const PAD* pad, PCB_LAYER_ID padLayer )
4174 {
4175 VECTOR2I clearance( aClearance, aClearance );
4176
4177 switch( aLayer )
4178 {
4179 case F_Mask:
4180 case B_Mask:
4181 clearance.x += pad->GetSolderMaskExpansion( padLayer );
4182 clearance.y += pad->GetSolderMaskExpansion( padLayer );
4183 break;
4184
4185 case F_Paste:
4186 case B_Paste:
4187 clearance += pad->GetSolderPasteMargin( padLayer );
4188 break;
4189
4190 default:
4191 break;
4192 }
4193
4194 // Our standard TransformShapeToPolygon() routines can't handle differing x:y clearance
4195 // values (which get generated when a relative paste margin is used with an oblong pad).
4196 // So we apply this huge hack and fake a larger pad to run the transform on.
4197 // Of course being a hack it falls down when dealing with custom shape pads (where the
4198 // size is only the size of the anchor), so for those we punt and just use clearance.x.
4199
4200 if( ( clearance.x < 0 || clearance.x != clearance.y )
4201 && pad->GetShape( padLayer ) != PAD_SHAPE::CUSTOM )
4202 {
4203 VECTOR2I dummySize = pad->GetSize( padLayer ) + clearance + clearance;
4204
4205 if( dummySize.x <= 0 || dummySize.y <= 0 )
4206 return;
4207
4208 PAD dummy( *pad );
4209 dummy.SetSize( padLayer, dummySize );
4210 dummy.TransformShapeToPolygon( aBuffer, padLayer, 0, aMaxError, aErrorLoc );
4211 }
4212 else
4213 {
4214 pad->TransformShapeToPolygon( aBuffer, padLayer, clearance.x, aMaxError, aErrorLoc );
4215 }
4216 };
4217
4218 for( const PAD* pad : m_pads )
4219 {
4220 if( !pad->FlashLayer( aLayer ) )
4221 continue;
4222
4223 if( aLayer == UNDEFINED_LAYER )
4224 {
4225 pad->Padstack().ForEachUniqueLayer(
4226 [&]( PCB_LAYER_ID l )
4227 {
4228 processPad( pad, l );
4229 } );
4230 }
4231 else
4232 {
4233 processPad( pad, aLayer );
4234 }
4235 }
4236}
4237
4238
4240 int aError, ERROR_LOC aErrorLoc, bool aIncludeText,
4241 bool aIncludeShapes, bool aIncludePrivateItems ) const
4242{
4243 for( BOARD_ITEM* item : GraphicalItems() )
4244 {
4245 if( GetPrivateLayers().test( item->GetLayer() ) && !aIncludePrivateItems )
4246 continue;
4247
4248 if( item->Type() == PCB_TEXT_T && aIncludeText )
4249 {
4250 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
4251
4252 if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer )
4253 text->TransformTextToPolySet( aBuffer, aClearance, aError, aErrorLoc );
4254 }
4255
4256 if( item->Type() == PCB_TEXTBOX_T && aIncludeText )
4257 {
4258 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
4259
4260 if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer )
4261 {
4262 // border
4263 if( textbox->IsBorderEnabled() )
4264 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aError, aErrorLoc );
4265
4266 // text
4267 textbox->TransformTextToPolySet( aBuffer, 0, aError, aErrorLoc );
4268 }
4269 }
4270
4271 if( item->Type() == PCB_SHAPE_T && aIncludeShapes )
4272 {
4273 const PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
4274
4275 if( aLayer != UNDEFINED_LAYER && shape->GetLayer() == aLayer )
4276 shape->TransformShapeToPolySet( aBuffer, aLayer, 0, aError, aErrorLoc );
4277 }
4278
4279 if( item->Type() == PCB_BARCODE_T && aIncludeShapes )
4280 {
4281 const PCB_BARCODE* barcode = static_cast<PCB_BARCODE*>( item );
4282
4283 if( aLayer != UNDEFINED_LAYER && barcode->GetLayer() == aLayer )
4284 barcode->TransformShapeToPolySet( aBuffer, aLayer, 0, aError, aErrorLoc );
4285 }
4286 }
4287
4288 if( aIncludeText )
4289 {
4290 for( const PCB_FIELD* field : m_fields )
4291 {
4292 if( field->GetLayer() == aLayer && field->IsVisible() )
4293 field->TransformTextToPolySet( aBuffer, aClearance, aError, aErrorLoc );
4294 }
4295 }
4296}
4297
4298
4299std::set<KIFONT::OUTLINE_FONT*> FOOTPRINT::GetFonts() const
4300{
4302
4303 std::set<KIFONT::OUTLINE_FONT*> fonts;
4304
4305 auto processItem =
4306 [&]( BOARD_ITEM* item )
4307 {
4308 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
4309 {
4310 KIFONT::FONT* font = text->GetFont();
4311
4312 if( font && font->IsOutline() )
4313 {
4314 KIFONT::OUTLINE_FONT* outlineFont = static_cast<KIFONT::OUTLINE_FONT*>( font );
4315 PERMISSION permission = outlineFont->GetEmbeddingPermission();
4316
4317 if( permission == PERMISSION::EDITABLE || permission == PERMISSION::INSTALLABLE )
4318 fonts.insert( outlineFont );
4319 }
4320 }
4321 };
4322
4323 for( BOARD_ITEM* item : GraphicalItems() )
4324 processItem( item );
4325
4326 for( PCB_FIELD* field : GetFields() )
4327 processItem( field );
4328
4329 return fonts;
4330}
4331
4332
4334{
4335 for( KIFONT::OUTLINE_FONT* font : GetFonts() )
4336 {
4337 EMBEDDED_FILES::EMBEDDED_FILE* file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
4339 }
4340}
4341
4342
4344{
4345 m_componentClassCacheProxy->SetStaticComponentClass( aClass );
4346}
4347
4348
4350{
4351 return m_componentClassCacheProxy->GetStaticComponentClass();
4352}
4353
4354
4356{
4357 m_componentClassCacheProxy->RecomputeComponentClass();
4358}
4359
4360
4362{
4363 return m_componentClassCacheProxy->GetComponentClass();
4364}
4365
4366
4368{
4369 if( !m_componentClassCacheProxy->GetComponentClass()->IsEmpty() )
4370 return m_componentClassCacheProxy->GetComponentClass()->GetName();
4371
4372 return wxEmptyString;
4373}
4374
4375
4377 const std::unordered_set<wxString>& aComponentClassNames )
4378{
4379 const COMPONENT_CLASS* componentClass =
4380 aBoard->GetComponentClassManager().GetEffectiveStaticComponentClass( aComponentClassNames );
4381 SetStaticComponentClass( componentClass );
4382}
4383
4384
4386{
4387 m_componentClassCacheProxy->InvalidateCache();
4388}
4389
4390
4392{
4393 m_stackupMode = aMode;
4394
4396 {
4397 // Reset the stackup layers to the default values
4399 }
4400}
4401
4402
4404{
4405 wxCHECK2( m_stackupMode == FOOTPRINT_STACKUP::CUSTOM_LAYERS, /*void*/ );
4406
4408 m_stackupLayers = std::move( aLayers );
4409}
4410
4411
4413{
4414 if( !aBoard )
4415 return;
4416
4418 return;
4419
4420 const LSET boardCopper = LSET::AllCuMask( aBoard->GetCopperLayerCount() );
4421
4422 for( PAD* pad : Pads() )
4423 {
4424 if( pad->GetAttribute() == PAD_ATTRIB::PTH )
4425 {
4426 LSET padLayers = pad->GetLayerSet();
4427 padLayers |= boardCopper;
4428 pad->SetLayerSet( padLayers );
4429 }
4430 }
4431}
4432
4433
4434static struct FOOTPRINT_DESC
4435{
4437 {
4439
4440 if( zcMap.Choices().GetCount() == 0 )
4441 {
4443 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
4444 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
4445 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
4446 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
4447 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
4448 }
4449
4451
4452 if( layerEnum.Choices().GetCount() == 0 )
4453 {
4454 layerEnum.Undefined( UNDEFINED_LAYER );
4455
4456 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
4457 layerEnum.Map( layer, LSET::Name( layer ) );
4458 }
4459
4460 wxPGChoices fpLayers; // footprints might be placed only on F.Cu & B.Cu
4461 fpLayers.Add( LSET::Name( F_Cu ), F_Cu );
4462 fpLayers.Add( LSET::Name( B_Cu ), B_Cu );
4463
4470
4471 auto isNotFootprintHolder =
4472 []( INSPECTABLE* aItem ) -> bool
4473 {
4474 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aItem ) )
4475 {
4476 if( BOARD* board = footprint->GetBoard() )
4477 return !board->IsFootprintHolder();
4478 }
4479 return true;
4480 };
4481
4482 auto layer = new PROPERTY_ENUM<FOOTPRINT, PCB_LAYER_ID>( _HKI( "Layer" ),
4484 layer->SetChoices( fpLayers );
4485 layer->SetAvailableFunc( isNotFootprintHolder );
4486 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
4487
4488 propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Orientation" ),
4491 .SetAvailableFunc( isNotFootprintHolder );
4492
4493 const wxString groupFields = _HKI( "Fields" );
4494
4495 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Reference" ),
4497 groupFields );
4498 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Value" ),
4500 groupFields );
4501
4502 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library Link" ),
4504 groupFields );
4505 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library Description" ),
4507 groupFields );
4508 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Keywords" ),
4510 groupFields );
4511
4512 // Note: Also used by DRC engine
4513 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Component Class" ),
4515 groupFields )
4517
4518 const wxString groupAttributes = _HKI( "Attributes" );
4519
4520 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Not in Schematic" ),
4521 &FOOTPRINT::SetBoardOnly, &FOOTPRINT::IsBoardOnly ), groupAttributes );
4522 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude From Position Files" ),
4524 groupAttributes );
4525 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude From Bill of Materials" ),
4527 groupAttributes );
4528 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Do not Populate" ),
4530 groupAttributes );
4531
4532 const wxString groupOverrides = _HKI( "Overrides" );
4533
4534 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exempt From Courtyard Requirement" ),
4536 groupOverrides );
4537 propMgr.AddProperty( new PROPERTY<FOOTPRINT, std::optional<int>>( _HKI( "Clearance Override" ),
4540 groupOverrides );
4541 propMgr.AddProperty( new PROPERTY<FOOTPRINT, std::optional<int>>( _HKI( "Solderpaste Margin Override" ),
4544 groupOverrides );
4545 propMgr.AddProperty( new PROPERTY<FOOTPRINT, std::optional<double>>( _HKI( "Solderpaste Margin Ratio Override" ),
4549 groupOverrides );
4550 propMgr.AddProperty( new PROPERTY_ENUM<FOOTPRINT, ZONE_CONNECTION>( _HKI( "Zone Connection Style" ),
4552 groupOverrides );
4553 }
const char * name
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
Definition api_enums.cpp:97
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:36
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...
@ ERROR_OUTSIDE
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
constexpr int ARC_LOW_DEF
Definition base_units.h:128
BITMAPS
A list of all bitmap identifiers.
@ FPHOLDER
Definition board.h:314
#define DEFAULT_COURTYARD_WIDTH
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
BASE_SET & set(size_t pos)
Definition base_set.h:116
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
Abstract interface for BOARD_ITEMs capable of storing other items inside.
BOARD_ITEM_CONTAINER(BOARD_ITEM *aParent, KICAD_T aType)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:85
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:236
virtual BOARD_ITEM * Duplicate(bool addToParentGroup, BOARD_COMMIT *aCommit=nullptr) const
Create a copy of this BOARD_ITEM.
PCB_LAYER_ID m_layer
Definition board_item.h:458
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.
void SetX(int aX)
Definition board_item.h:121
void SetY(int aY)
Definition board_item.h:127
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:318
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:284
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
VECTOR2I GetFPRelativePosition() const
virtual void TransformShapeToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const
Convert the item shape to a polyset.
Definition board_item.h:429
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:214
virtual bool IsOnCopperLayer() const
Definition board_item.h:155
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
int GetMaxError() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
int GetCopperLayerCount() const
Definition board.cpp:906
COMPONENT_CLASS_MANAGER & GetComponentClassManager()
Gets the component class manager.
Definition board.h:1366
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 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:83
COMPONENT_CLASS * GetEffectiveStaticComponentClass(const std::unordered_set< wxString > &classNames)
Gets an effective component class for the given constituent class names.
A lightweight representation of a component class.
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
bool IsType(FRAME_T aType) const
The base class for create windows for drawing purpose.
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:54
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition eda_group.cpp:27
virtual void ClearEditFlags()
Definition eda_item.h:156
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition eda_item.cpp:328
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:142
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:144
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:401
static INSPECT_RESULT IterateForward(std::deque< T > &aList, INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &scanTypes)
This changes first parameter to avoid the DList and use the main queue instead.
Definition eda_item.h:325
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:146
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:258
SHAPE_POLY_SET & GetPolyShape()
Definition eda_shape.h:336
SHAPE_T GetShape() const
Definition eda_shape.h:168
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:215
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:173
bool IsAnyFill() const
Definition eda_shape.h:112
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:255
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:80
bool IsItalic() const
Definition eda_text.h:169
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:147
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:425
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:394
double GetLineSpacing() const
Definition eda_text.h:258
bool IsMirrored() const
Definition eda_text.h:190
bool IsBold() const
Definition eda_text.h:184
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:278
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:307
int GetTextThickness() const
Definition eda_text.h:128
VECTOR2I GetTextSize() const
Definition eda_text.h:261
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:417
EMBEDDED_FILES & operator=(EMBEDDED_FILES &&other) noexcept
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
EMBEDDED_FILES()=default
const std::map< wxString, EMBEDDED_FILE * > & EmbeddedFileMap() const
bool m_embedFonts
If set, fonts will be embedded in the element on save.
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:727
static ENUM_MAP< T > & Instance()
Definition property.h:721
ENUM_MAP & Undefined(T aValue)
Definition property.h:734
wxPGChoices & Choices()
Definition property.h:770
bool FixUuids()
Old footprints do not always have a valid UUID (some can be set to null uuid) However null UUIDs,...
void EmbedFonts() override
bool AllowSolderMaskBridges() const
Definition footprint.h:333
void SetPosition(const VECTOR2I &aPos) override
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:270
LIB_ID m_fpid
Definition footprint.h:1121
wxString GetLibDescription() const
Definition footprint.h:278
ZONE_CONNECTION GetLocalZoneConnection() const
Definition footprint.h:309
KIID_PATH m_path
Definition footprint.h:1175
std::deque< BOARD_ITEM * > m_drawings
Definition footprint.h:1113
void SetStackupLayers(LSET aLayers)
If the footprint has a non-default stackup, set the layers that should be used for the stackup.
bool IsBoardOnly() const
Definition footprint.h:762
BOX2I m_cachedTextExcludedBBox
Definition footprint.h:1138
void InvalidateComponentClassCache() const
Forces deferred (on next access) recalculation of the component class for this footprint.
bool IsDNP() const
Definition footprint.h:789
void SetLocked(bool isLocked) override
Set the #MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition footprint.h:464
HASH_128 m_courtyard_cache_back_hash
Definition footprint.h:1190
std::vector< PAD * > GetNetTiePads(PAD *aPad) const
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
EDA_ANGLE GetOrientation() const
Definition footprint.h:248
ZONES & Zones()
Definition footprint.h:230
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
std::deque< PCB_POINT * > m_points
Definition footprint.h:1117
void CheckClippedSilk(const std::function< void(BOARD_ITEM *aItemA, BOARD_ITEM *aItemB, const VECTOR2I &aPt)> &aErrorHandler)
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
ZONE_CONNECTION m_zoneConnection
Definition footprint.h:1162
BOX2I m_cachedBoundingBox
Definition footprint.h:1136
int GetNextFieldOrdinal() const
Return the next ordinal for a user field for this footprint.
PCB_POINTS & Points()
Definition footprint.h:236
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
bool IsExcludedFromBOM() const
Definition footprint.h:780
void SetOrientation(const EDA_ANGLE &aNewAngle)
std::optional< double > m_solderPasteMarginRatio
Definition footprint.h:1166
void SetDNP(bool aDNP=true)
Definition footprint.h:790
void SetAllowSolderMaskBridges(bool aAllow)
Definition footprint.h:334
void RecomputeComponentClass() const
Forces immediate recalculation of the component class for this footprint.
std::vector< ZONE * > m_zones
Definition footprint.h:1115
static bool IsLibNameValid(const wxString &aName)
Test for validity of a name of a footprint to be used in a footprint library ( no spaces,...
void SetStackupMode(FOOTPRINT_STACKUP aMode)
Set the stackup mode for this footprint.
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition footprint.h:306
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
std::optional< int > m_clearance
Definition footprint.h:1163
bool m_duplicatePadNumbersAreJumpers
Flag that this footprint should automatically treat sets of two or more pads with the same number as ...
Definition footprint.h:1156
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.
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.
void SetExcludedFromBOM(bool aExclude=true)
Definition footprint.h:781
int m_fpStatus
Definition footprint.h:1123
SHAPE_POLY_SET m_cachedHull
Definition footprint.h:1140
std::set< wxString > GetUniquePadNumbers(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the names of the unique, non-blank pads.
void SetKeywords(const wxString &aKeywords)
Definition footprint.h:282
void SetStaticComponentClass(const COMPONENT_CLASS *aClass) const
Sets the component class object pointer for this footprint.
int m_attributes
Definition footprint.h:1122
PCB_LAYER_ID GetSide() const
Use instead of IsFlipped() when you also need to account for unsided footprints (those purely on user...
const BOX2I GetLayerBoundingBox(const LSET &aLayers) const
Return the bounding box of the footprint on a given set of layers.
std::vector< FP_3DMODEL > m_3D_Drawings
Definition footprint.h:1183
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...
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const override
Invoke a function on all children.
bool m_allowMissingCourtyard
Definition footprint.h:1158
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.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
std::optional< int > GetLocalSolderPasteMargin() const
Definition footprint.h:302
std::unique_ptr< COMPONENT_CLASS_CACHE_PROXY > m_componentClassCacheProxy
Definition footprint.h:1194
wxArrayString * m_initial_comments
Definition footprint.h:1184
EDA_ITEM * Clone() const override
Invoke a function on all children.
BOX2I GetFpPadsLocalBbox() const
Return the bounding box containing pads when the footprint is on the front side, orientation 0,...
std::deque< PCB_FIELD * > m_fields
Definition footprint.h:1112
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:697
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
std::optional< int > m_solderPasteMargin
Definition footprint.h:1165
std::mutex m_courtyard_cache_mutex
Definition footprint.h:1191
void SetExcludedFromPosFiles(bool aExclude=true)
Definition footprint.h:772
void SetOrientationDegrees(double aOrientation)
Definition footprint.h:260
std::optional< const std::set< wxString > > GetJumperPadGroup(const wxString &aPadNumber) const
Retrieves the jumper group containing the specified pad number, if one exists.
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
std::optional< int > GetLocalClearance() const
Definition footprint.h:296
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
bool m_allowSolderMaskBridges
Definition footprint.h:1159
FOOTPRINT & operator=(const FOOTPRINT &aOther)
bool HasField(const wxString &aFieldName) const
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
void TransformPadsToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Generate pads shapes on layer aLayer as polygons and adds these polygons to aBuffer.
double GetOrientationDegrees() const
Definition footprint.h:264
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...
std::deque< PAD * > & Pads()
Definition footprint.h:224
void ResolveComponentClassNames(BOARD *aBoard, const std::unordered_set< wxString > &aComponentClassNames)
Resolves a set of component class names to this footprint's actual component class.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
int GetAttributes() const
Definition footprint.h:327
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
const COMPONENT_CLASS * GetComponentClass() const
Returns the component class for this footprint.
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition footprint.h:308
BOARD_ITEM * DuplicateItem(bool addToParentGroup, BOARD_COMMIT *aCommit, const BOARD_ITEM *aItem, bool addToFootprint=false)
Duplicate a given item within the footprint, optionally adding it to the board.
FOOTPRINT(BOARD *parent)
Definition footprint.cpp:76
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:257
LSET GetPrivateLayers() const
Definition footprint.h:164
wxString GetFPIDAsString() const
Definition footprint.h:275
wxString GetValueAsString() const
Definition footprint.h:691
bool AllowMissingCourtyard() const
Definition footprint.h:330
wxString GetComponentClassAsString() const
Used for display in the properties panel.
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
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...
wxString GetTypeName() const
Get the type of footprint.
SHAPE_POLY_SET m_courtyard_cache_back
Definition footprint.h:1188
int m_textExcludedBBoxCacheTimeStamp
Definition footprint.h:1139
const std::vector< wxString > & GetNetTiePadGroups() const
Definition footprint.h:382
const LIB_ID & GetFPID() const
Definition footprint.h:269
void SetReference(const wxString &aReference)
Definition footprint.h:667
bool IsLocked() const override
Definition footprint.h:454
bool IsExcludedFromPosFiles() const
Definition footprint.h:771
void SetLayerAndFlip(PCB_LAYER_ID aLayer)
Used as Layer property setter – performs a flip if necessary to set the footprint layer.
int m_hullCacheTimeStamp
Definition footprint.h:1141
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
void AddNetTiePadGroup(const wxString &aGroup)
Definition footprint.h:389
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
LSET m_privateLayers
Definition footprint.h:1171
const std::deque< PCB_FIELD * > & GetFields() const
Return a reference to the deque holding the footprint's fields.
Definition footprint.h:735
int GetLikelyAttribute() const
Returns the most likely attribute based on pads Either FP_THROUGH_HOLE/FP_SMD/OTHER(0)
std::deque< PCB_GROUP * > m_groups
Definition footprint.h:1116
void Move(const VECTOR2I &aMoveVector) override
Move this object.
wxString m_libDescription
Definition footprint.h:1173
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.
VECTOR2I m_pos
Definition footprint.h:1120
void ApplyDefaultSettings(const BOARD &board, bool aStyleFields, bool aStyleText, bool aStyleShapes, bool aStyleDimensions, bool aStyleBarcodes)
Apply default board settings to the footprint field text properties.
std::vector< wxString > m_netTiePadGroups
Definition footprint.h:1145
void InvalidateGeometryCaches()
Resets the caches for this footprint, for example if it was modified via the API.
virtual std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
std::set< KIFONT::OUTLINE_FONT * > GetFonts() const override
Get a list of outline fonts referenced in the footprint.
void Add3DModel(FP_3DMODEL *a3DModel)
Add a3DModel definition to the end of the 3D model list.
void SetValue(const wxString &aValue)
Definition footprint.h:688
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.
FOOTPRINT_STACKUP m_stackupMode
Definition footprint.h:1170
PCB_FIELD & Reference()
Definition footprint.h:698
std::vector< std::set< wxString > > m_jumperPadGroups
A list of jumper pad groups, each of which is a set of pad numbers that should be jumpered together (...
Definition footprint.h:1152
wxString GetReferenceAsString() const
Definition footprint.h:670
wxString m_sheetfile
Definition footprint.h:1177
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars for this footprint.
std::optional< int > m_solderMaskMargin
Definition footprint.h:1164
SHAPE_POLY_SET m_courtyard_cache_front
Definition footprint.h:1187
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
std::vector< const PAD * > GetPads(const wxString &aPadNumber, const PAD *aIgnore=nullptr) const
void AutoPositionFields()
Position Reference and Value fields at the top and bottom of footprint's bounding box.
wxString m_keywords
Definition footprint.h:1174
void ClearAllNets()
Clear (i.e.
std::deque< PAD * > m_pads
Definition footprint.h:1114
bool HasThroughHolePads() const
void BuildCourtyardCaches(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
EDA_ANGLE m_orient
Definition footprint.h:1119
bool HitTestAccurate(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if a point is inside the bounding polygon of the footprint.
wxString GetClass() const override
Return the class name.
Definition footprint.h:909
void IncrementReference(int aDelta)
Bump the current reference by aDelta.
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition footprint.h:305
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
KIID m_link
Definition footprint.h:1181
GROUPS & Groups()
Definition footprint.h:233
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
void SetAllowMissingCourtyard(bool aAllow)
Definition footprint.h:331
void BuildNetTieCache()
Cache the pads that are allowed to connect to each other in the footprint.
bool IsConflicting() const
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:241
BOARD_ITEM * Duplicate(bool addToParentGroup, BOARD_COMMIT *aCommit=nullptr) const override
Create a copy of this BOARD_ITEM.
const SHAPE_POLY_SET & GetCachedCourtyard(PCB_LAYER_ID aLayer) const
Return the cached courtyard area.
static const wxChar * StringLibNameInvalidChars(bool aUserReadable)
Test for validity of the name in a library of the footprint ( no spaces, dir separators ....
void SetLibDescription(const wxString &aDesc)
Definition footprint.h:279
bool TextOnly() const
const COMPONENT_CLASS * GetStaticComponentClass() const
Returns the component class for this footprint.
void FixUpPadsForBoard(BOARD *aBoard)
Used post-loading of a footprint to adjust the layers on pads to match board inner layers.
void CheckShortingPads(const std::function< void(const PAD *, const PAD *, int aErrorCode, const VECTOR2I &)> &aErrorHandler)
Check for overlapping, different-numbered, non-net-tie pads.
double GetArea(int aPadding=0) const
wxString m_filters
Definition footprint.h:1178
const wxString & GetReference() const
Definition footprint.h:661
void CopyFrom(const BOARD_ITEM *aOther) override
void CheckNetTiePadGroups(const std::function< void(const wxString &)> &aErrorHandler)
Sanity check net-tie pad groups.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
void SetBoardOnly(bool aIsBoardOnly=true)
Definition footprint.h:763
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition footprint.h:300
timestamp_t m_lastEditTime
Definition footprint.h:1179
PAD * GetPad(const VECTOR2I &aPosition, const LSET &aLayerMask=LSET::AllLayersMask())
Get a pad at aPosition on aLayerMask in the footprint.
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
std::map< const BOARD_ITEM *, std::set< int > > m_netTieCache
Definition footprint.h:1148
wxString m_sheetname
Definition footprint.h:1176
LSET m_stackupLayers
Definition footprint.h:1169
int m_fileFormatVersionAtLoad
Definition footprint.h:1124
void SetLocalClearance(std::optional< int > aClearance)
Definition footprint.h:297
void SetPrivateLayers(const LSET &aLayers)
Adds an item to the container.
Definition footprint.h:165
std::optional< int > GetLocalSolderMaskMargin() const
Definition footprint.h:299
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition footprint.h:303
wxString GetKeywords() const
Definition footprint.h:281
bool operator==(const BOARD_ITEM &aOther) const override
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition footprint.h:1014
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...
FOOTPRINT_STACKUP GetStackupMode() const
Definition footprint.h:318
virtual void swapData(BOARD_ITEM *aImage) override
wxString GetNextPadNumber(const wxString &aLastPadName) const
Return the next available pad number in the footprint.
int m_boundingBoxCacheTimeStamp
Definition footprint.h:1137
VECTOR2I GetPosition() const override
Definition footprint.h:245
DRAWINGS & GraphicalItems()
Definition footprint.h:227
HASH_128 m_courtyard_cache_front_hash
Definition footprint.h:1189
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
PAD * FindPadByNumber(const wxString &aPadNumber, PAD *aSearchAfterMe=nullptr) const
Return a PAD with a matching number.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
wxString m_Filename
The 3D shape filename in 3D library.
Definition footprint.h:121
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
const COLLECTORS_GUIDE * GetGuide() const
Definition collectors.h:293
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:37
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:131
virtual bool IsOutline() const
Definition font.h:139
Class OUTLINE_FONT implements outline font drawing.
EMBEDDING_PERMISSION GetEmbeddingPermission() const
virtual wxString GetClass() const =0
Return the class name.
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:180
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:185
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition view.h:422
Definition kiid.h:49
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & SideSpecificMask()
Definition lset.cpp:719
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:296
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static const LSET & AllLayersMask()
Definition lset.cpp:624
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
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:251
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::...
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:171
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:173
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:172
MODE Mode() const
Definition padstack.h:322
Definition pad.h:55
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:555
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition pad.cpp:931
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition pad.cpp:1302
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition pad.h:901
int GetDrillSizeY() const
Definition pad.h:316
PAD_ATTRIB GetAttribute() const
Definition pad.h:558
const wxString & GetNumber() const
Definition pad.h:137
VECTOR2I GetPosition() const override
Definition pad.h:209
int GetDrillSizeX() const
Definition pad.h:314
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:196
int GetSolderMaskExpansion(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1612
const PADSTACK & Padstack() const
Definition pad.h:328
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.h:415
PAD_DRILL_SHAPE GetDrillShape() const
Definition pad.h:432
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:919
std::optional< int > GetLocalSolderMaskMargin() const
Definition pad.h:579
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:1667
bool HasDrilledHole() const override
Definition pad.h:112
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1033
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition pad.h:264
Abstract dimension API.
bool IsMandatory() const
FIELD_T GetId() const
Definition pcb_field.h:110
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition pcb_field.cpp:60
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition pcb_field.cpp:76
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
A PCB_POINT is a 0-dimensional point that is used to mark a position on a PCB, or more usually a foot...
Definition pcb_point.h:43
Object to handle a bitmap image that can be inserted in a PCB.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:81
int GetWidth() const override
void TransformShapeToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const override
Convert the item shape to a polyset.
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.
STROKE_PARAMS GetStroke() const override
Definition pcb_shape.h:91
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:71
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...
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition pcb_text.cpp:139
virtual VECTOR2I GetPosition() const override
Definition pcb_text.h:82
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
PROPERTY_BASE & SetIsHiddenFromLibraryEditors(bool aIsHidden=true)
Definition property.h:333
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
double Area(bool aAbsolute=true) const
Return the area of this chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
double Area()
Return the area of this poly set.
bool 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.
int FullPointCount() const
Return the number of points in the shape poly set.
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()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
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 BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
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.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
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
Handle a list of polygons defining a copper zone.
Definition zone.h:74
SHAPE_POLY_SET * Outline()
Definition zone.h:331
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
unsigned GetAssignedPriority() const
Definition zone.h:126
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.
@ CHAMFER_ACUTE_CORNERS
Acute angles are chamfered.
@ DRCE_DRILLED_HOLES_TOO_CLOSE
Definition drc_item.h:53
@ DRCE_SHORTING_ITEMS
Definition drc_item.h:41
@ DRCE_DRILLED_HOLES_COLOCATED
Definition drc_item.h:54
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
RECURSE_MODE
Definition eda_item.h:50
@ RECURSE
Definition eda_item.h:51
@ NO_RECURSE
Definition eda_item.h:52
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
#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
@ SEGMENT
Definition eda_shape.h:45
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
static struct FOOTPRINT_DESC _FOOTPRINT_DESC
static double polygonArea(SHAPE_POLY_SET &aPolySet)
static constexpr std::optional< bool > cmp_points_opt(const VECTOR2I &aPtA, const VECTOR2I &aPtB)
Compare two points, returning std::nullopt if they are identical.
INCLUDE_NPTH_T
Definition footprint.h:69
@ DO_NOT_INCLUDE_NPTH
Definition footprint.h:70
@ FP_SMD
Definition footprint.h:82
@ FP_DNP
Definition footprint.h:87
@ FP_EXCLUDE_FROM_POS_FILES
Definition footprint.h:83
@ FP_BOARD_ONLY
Definition footprint.h:85
@ FP_EXCLUDE_FROM_BOM
Definition footprint.h:84
@ FP_THROUGH_HOLE
Definition footprint.h:81
#define FP_is_PLACED
In autoplace: footprint automatically placed.
Definition footprint.h:449
#define FP_PADS_are_LOCKED
Definition footprint.h:451
FOOTPRINT_STACKUP
Definition footprint.h:91
@ EXPAND_INNER_LAYERS
The 'normal' stackup handling, where there is a single inner layer (In1) and rule areas using it expa...
Definition footprint.h:96
@ CUSTOM_LAYERS
Stackup handling where the footprint can have any number of copper layers, and objects on those layer...
Definition footprint.h:101
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:45
@ FRAME_FOOTPRINT_CHOOSER
Definition frame_type.h:44
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
a few functions useful in geometry calculations.
const wxChar *const traceApi
Flag to enable debug output related to the IPC API and its plugin system.
Definition api_utils.cpp:27
Some functions to handle hotkeys in KiCad.
KIID niluuid(0)
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:172
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:184
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:803
@ LAYER_CONFLICTS_SHADOW
Shadow layer for items flagged conflicting.
Definition layer_ids.h:310
@ LAYER_FOOTPRINTS_FR
Show footprints on front.
Definition layer_ids.h:259
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
Definition layer_ids.h:266
@ LAYER_FP_TEXT
Definition layer_ids.h:240
@ LAYER_FOOTPRINTS_BK
Show footprints on back.
Definition layer_ids.h:260
@ LAYER_ANCHOR
Anchor of items having an anchor point (texts, footprints).
Definition layer_ids.h:248
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
Definition layer_ids.h:263
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
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:28
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:29
bool BoxHitTest(const VECTOR2I &aHitPoint, const BOX2I &aHittee, int aAccuracy)
Perform a point-to-box hit test.
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
KICOMMON_API KIID_PATH UnpackSheetPath(const types::SheetPath &aInput)
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
Definition api_utils.cpp:33
KICOMMON_API VECTOR3D UnpackVector3D(const types::Vector3D &aInput)
KICOMMON_API void PackSheetPath(types::SheetPath &aOutput, const KIID_PATH &aInput)
KICOMMON_API LIB_ID LibIdFromProto(const types::LibraryIdentifier &aId)
Definition api_utils.cpp:64
KICOMMON_API types::LibraryIdentifier LibIdToProto(const LIB_ID &aId)
Definition api_utils.cpp:70
KICOMMON_API void PackVector3D(types::Vector3D &aOutput, const VECTOR3D &aInput)
Definition api_utils.cpp:92
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ PTH
Plated through hole pad.
Definition padstack.h:98
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
Definition padstack.h:118
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
Definition padstack.h:117
@ MECHANICAL
a pad used for mechanical support
Definition padstack.h:122
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:123
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
Definition padstack.h:120
@ NONE
no special fabrication property
Definition padstack.h:115
@ TESTPOINT
a test point pad
Definition padstack.h:119
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:121
@ BGA
Smd pad, used in BGA footprints.
Definition padstack.h:116
#define _HKI(x)
Definition page_info.cpp:44
BARCODE class definition.
Class to handle a set of BOARD_ITEMs.
#define TYPE_HASH(x)
Definition property.h:74
#define NO_SETTER(owner, type)
Definition property.h:828
@ PT_DEGREE
Angle expressed in degrees.
Definition property.h:66
@ PT_RATIO
Definition property.h:68
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
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)
bool operator()(const BOARD_ITEM *itemA, const BOARD_ITEM *itemB) const
bool operator()(const PAD *aFirst, const PAD *aSecond) const
bool operator()(const ZONE *aFirst, const ZONE *aSecond) const
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
KIBIS_MODEL * model
int clearance
int actual
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:254
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:106
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:103
@ 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:104
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:111
@ 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:108
@ 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_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:101
@ 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:102
@ 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_POINT_T
class PCB_POINT, a 0-dimensional point
Definition typeinfo.h:113
@ 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:105
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition zones.h:47
@ THERMAL
Use thermal relief for pads.
Definition zones.h:50
@ THT_THERMAL
Thermal relief only for THT pads.
Definition zones.h:52
@ NONE
Pads are not covered.
Definition zones.h:49
@ FULL
pads are covered by copper
Definition zones.h:51