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