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