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