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