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