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