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