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