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