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