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