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