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