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 for( BOARD_ITEM* item : m_drawings )
1226 {
1227 if( m_privateLayers.test( item->GetLayer() ) )
1228 continue;
1229
1230 if( item->Type() != PCB_FIELD_T && item->Type() != PCB_TEXT_T )
1231 return false;
1232 }
1233
1234 return true;
1235}
1236
1237
1239{
1240 return GetBoundingBox( true, true );
1241}
1242
1243
1244const BOX2I FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const
1245{
1246 std::vector<PCB_TEXT*> texts;
1247 const BOARD* board = GetBoard();
1248 bool isFPEdit = board && board->IsFootprintHolder();
1249 PCB_LAYER_ID footprintSide = GetSide();
1250
1251 if( board )
1252 {
1253 if( aIncludeText && aIncludeInvisibleText )
1254 {
1256 return m_cachedBoundingBox;
1257 }
1258 else if( aIncludeText )
1259 {
1261 return m_cachedVisibleBBox;
1262 }
1263 else
1264 {
1267 }
1268 }
1269
1270 BOX2I bbox( m_pos );
1271 bbox.Inflate( pcbIUScale.mmToIU( 0.25 ) ); // Give a min size to the bbox
1272
1273 for( BOARD_ITEM* item : m_drawings )
1274 {
1275 if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
1276 continue;
1277
1278 // We want the bitmap bounding box just in the footprint editor
1279 // so it will start with the correct initial zoom
1280 if( item->Type() == PCB_REFERENCE_IMAGE_T && !isFPEdit )
1281 continue;
1282
1283 // Handle text separately
1284 if( item->Type() == PCB_TEXT_T )
1285 {
1286 texts.push_back( static_cast<PCB_TEXT*>( item ) );
1287 continue;
1288 }
1289
1290 // If we're not including text then drop annotations as well -- unless, of course, it's
1291 // an unsided footprint -- in which case it's likely to be nothing *but* annotations.
1292 if( !aIncludeText && footprintSide != UNDEFINED_LAYER )
1293 {
1294 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
1295 continue;
1296
1297 if( item->GetLayer() == Cmts_User || item->GetLayer() == Dwgs_User
1298 || item->GetLayer() == Eco1_User || item->GetLayer() == Eco2_User )
1299 {
1300 continue;
1301 }
1302 }
1303
1304 bbox.Merge( item->GetBoundingBox() );
1305 }
1306
1307 for( PCB_FIELD* field : m_fields )
1308 {
1309 // Reference and value get their own processing
1310 if( !field->IsReference() && !field->IsValue() )
1311 texts.push_back( field );
1312 }
1313
1314 for( PAD* pad : m_pads )
1315 bbox.Merge( pad->GetBoundingBox() );
1316
1317 for( ZONE* zone : m_zones )
1318 bbox.Merge( zone->GetBoundingBox() );
1319
1320 bool noDrawItems = ( m_drawings.empty() && m_pads.empty() && m_zones.empty() );
1321
1322 // Groups do not contribute to the rect, only their members
1323 if( aIncludeText || noDrawItems )
1324 {
1325 // Only PCB_TEXT and PCB_FIELD items are independently selectable;
1326 // PCB_TEXTBOX items go in with other graphic items above.
1327 for( PCB_TEXT* text : texts )
1328 {
1329 if( !isFPEdit && m_privateLayers.test( text->GetLayer() ) )
1330 continue;
1331
1332 if( aIncludeInvisibleText || text->IsVisible() )
1333 bbox.Merge( text->GetBoundingBox() );
1334 }
1335
1336 // This can be further optimized when aIncludeInvisibleText is true, but currently
1337 // leaving this as is until it's determined there is a noticeable speed hit.
1338 bool valueLayerIsVisible = true;
1339 bool refLayerIsVisible = true;
1340
1341 if( board )
1342 {
1343 // The first "&&" conditional handles the user turning layers off as well as layers
1344 // not being present in the current PCB stackup. Values, references, and all
1345 // footprint text can also be turned off via the GAL meta-layers, so the 2nd and
1346 // 3rd "&&" conditionals handle that.
1347 valueLayerIsVisible = board->IsLayerVisible( Value().GetLayer() )
1349 && board->IsElementVisible( LAYER_FP_TEXT );
1350
1351 refLayerIsVisible = board->IsLayerVisible( Reference().GetLayer() )
1353 && board->IsElementVisible( LAYER_FP_TEXT );
1354 }
1355
1356
1357 if( ( Value().IsVisible() && valueLayerIsVisible )
1358 || aIncludeInvisibleText
1359 || noDrawItems )
1360 {
1361 bbox.Merge( Value().GetBoundingBox() );
1362 }
1363
1364 if( ( Reference().IsVisible() && refLayerIsVisible )
1365 || aIncludeInvisibleText
1366 || noDrawItems )
1367 {
1368 bbox.Merge( Reference().GetBoundingBox() );
1369 }
1370 }
1371
1372 if( board )
1373 {
1374 if( ( aIncludeText && aIncludeInvisibleText ) || noDrawItems )
1375 {
1377 m_cachedBoundingBox = bbox;
1378 }
1379 else if( aIncludeText )
1380 {
1382 m_cachedVisibleBBox = bbox;
1383 }
1384 else
1385 {
1388 }
1389 }
1390
1391 return bbox;
1392}
1393
1394
1396{
1397 std::vector<PCB_TEXT*> texts;
1398 const BOARD* board = GetBoard();
1399 bool isFPEdit = board && board->IsFootprintHolder();
1400
1401 // Start with an uninitialized bounding box
1402 BOX2I bbox;
1403
1404 for( BOARD_ITEM* item : m_drawings )
1405 {
1406 if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
1407 continue;
1408
1409 if( ( aLayers & item->GetLayerSet() ).none() )
1410 continue;
1411
1412 // We want the bitmap bounding box just in the footprint editor
1413 // so it will start with the correct initial zoom
1414 if( item->Type() == PCB_REFERENCE_IMAGE_T && !isFPEdit )
1415 continue;
1416
1417 bbox.Merge( item->GetBoundingBox() );
1418 }
1419
1420 for( PAD* pad : m_pads )
1421 {
1422 if( ( aLayers & pad->GetLayerSet() ).none() )
1423 continue;
1424
1425 bbox.Merge( pad->GetBoundingBox() );
1426 }
1427
1428 for( ZONE* zone : m_zones )
1429 {
1430 if( ( aLayers & zone->GetLayerSet() ).none() )
1431 continue;
1432
1433 bbox.Merge( zone->GetBoundingBox() );
1434 }
1435
1436 return bbox;
1437}
1438
1439
1441{
1442 const BOARD* board = GetBoard();
1443 bool isFPEdit = board && board->IsFootprintHolder();
1444
1445 if( board )
1446 {
1447 if( m_hullCacheTimeStamp >= board->GetTimeStamp() )
1448 return m_cachedHull;
1449 }
1450
1451 SHAPE_POLY_SET rawPolys;
1452 SHAPE_POLY_SET hull;
1453
1454 for( BOARD_ITEM* item : m_drawings )
1455 {
1456 if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) )
1457 continue;
1458
1459 if( item->Type() != PCB_FIELD_T && item->Type() != PCB_REFERENCE_IMAGE_T )
1460 {
1461 item->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
1462 ERROR_OUTSIDE );
1463 }
1464
1465 // We intentionally exclude footprint fields from the bounding hull.
1466 }
1467
1468 for( PAD* pad : m_pads )
1469 {
1470 pad->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
1471 // In case hole is larger than pad
1472 pad->TransformHoleToPolygon( rawPolys, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
1473 }
1474
1475 for( ZONE* zone : m_zones )
1476 {
1477 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
1478 {
1479 const SHAPE_POLY_SET& layerPoly = *zone->GetFilledPolysList( layer );
1480
1481 for( int ii = 0; ii < layerPoly.OutlineCount(); ii++ )
1482 {
1483 const SHAPE_LINE_CHAIN& poly = layerPoly.COutline( ii );
1484 rawPolys.AddOutline( poly );
1485 }
1486 }
1487 }
1488
1489 // If there are some graphic items, build the actual hull.
1490 // However if no items, create a minimal polygon (can happen if a footprint
1491 // is created with no item: it contains only 2 texts.
1492 if( rawPolys.OutlineCount() == 0 )
1493 {
1494 // generate a small dummy rectangular outline around the anchor
1495 const int halfsize = pcbIUScale.mmToIU( 1.0 );
1496
1497 rawPolys.NewOutline();
1498
1499 // add a square:
1500 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y - halfsize );
1501 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y - halfsize );
1502 rawPolys.Append( GetPosition().x + halfsize, GetPosition().y + halfsize );
1503 rawPolys.Append( GetPosition().x - halfsize, GetPosition().y + halfsize );
1504 }
1505
1506 std::vector<VECTOR2I> convex_hull;
1507 BuildConvexHull( convex_hull, rawPolys );
1508
1511
1512 for( const VECTOR2I& pt : convex_hull )
1513 m_cachedHull.Append( pt );
1514
1515 if( board )
1517
1518 return m_cachedHull;
1519}
1520
1521
1522void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1523{
1524 wxString msg, msg2;
1525
1526 // Don't use GetShownText(); we want to see the variable references here
1527 aList.emplace_back( UnescapeString( Reference().GetText() ),
1528 UnescapeString( Value().GetText() ) );
1529
1530 if( aFrame->IsType( FRAME_FOOTPRINT_VIEWER )
1531 || aFrame->IsType( FRAME_FOOTPRINT_CHOOSER )
1532 || aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
1533 {
1534 size_t padCount = GetPadCount( DO_NOT_INCLUDE_NPTH );
1535
1536 aList.emplace_back( _( "Library" ), GetFPID().GetLibNickname().wx_str() );
1537
1538 aList.emplace_back( _( "Footprint Name" ), GetFPID().GetLibItemName().wx_str() );
1539
1540 aList.emplace_back( _( "Pads" ), wxString::Format( wxT( "%zu" ), padCount ) );
1541
1542 aList.emplace_back( wxString::Format( _( "Doc: %s" ), GetLibDescription() ),
1543 wxString::Format( _( "Keywords: %s" ), GetKeywords() ) );
1544
1545 return;
1546 }
1547
1548 // aFrame is the board editor:
1549
1550 switch( GetSide() )
1551 {
1552 case F_Cu: aList.emplace_back( _( "Board Side" ), _( "Front" ) ); break;
1553 case B_Cu: aList.emplace_back( _( "Board Side" ), _( "Back (Flipped)" ) ); break;
1554 default: /* unsided: user-layers only, etc. */ break;
1555 }
1556
1557 auto addToken = []( wxString* aStr, const wxString& aAttr )
1558 {
1559 if( !aStr->IsEmpty() )
1560 *aStr += wxT( ", " );
1561
1562 *aStr += aAttr;
1563 };
1564
1565 wxString status;
1566 wxString attrs;
1567
1568 if( IsLocked() )
1569 addToken( &status, _( "Locked" ) );
1570
1571 if( m_fpStatus & FP_is_PLACED )
1572 addToken( &status, _( "autoplaced" ) );
1573
1575 addToken( &attrs, _( "not in schematic" ) );
1576
1578 addToken( &attrs, _( "exclude from pos files" ) );
1579
1581 addToken( &attrs, _( "exclude from BOM" ) );
1582
1583 if( m_attributes & FP_DNP )
1584 addToken( &attrs, _( "DNP" ) );
1585
1586 aList.emplace_back( _( "Status: " ) + status, _( "Attributes:" ) + wxS( " " ) + attrs );
1587
1588 aList.emplace_back( _( "Rotation" ), wxString::Format( wxT( "%.4g" ),
1589 GetOrientation().AsDegrees() ) );
1590
1591 msg.Printf( _( "Footprint: %s" ), m_fpid.GetUniStringLibId() );
1592 msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
1593 : m_3D_Drawings.front().m_Filename );
1594 aList.emplace_back( msg, msg2 );
1595
1596 msg.Printf( _( "Doc: %s" ), m_libDescription );
1597 msg2.Printf( _( "Keywords: %s" ), m_keywords );
1598 aList.emplace_back( msg, msg2 );
1599}
1600
1601
1603{
1604 if( const BOARD* board = GetBoard() )
1605 {
1606 if( board->IsFootprintHolder() )
1607 return UNDEFINED_LAYER;
1608 }
1609
1610 // Test pads first; they're the most likely to return a quick answer.
1611 for( PAD* pad : m_pads )
1612 {
1613 if( ( LSET::SideSpecificMask() & pad->GetLayerSet() ).any() )
1614 return GetLayer();
1615 }
1616
1617 for( BOARD_ITEM* item : m_drawings )
1618 {
1619 if( LSET::SideSpecificMask().test( item->GetLayer() ) )
1620 return GetLayer();
1621 }
1622
1623 for( ZONE* zone : m_zones )
1624 {
1625 if( ( LSET::SideSpecificMask() & zone->GetLayerSet() ).any() )
1626 return GetLayer();
1627 }
1628
1629 return UNDEFINED_LAYER;
1630}
1631
1632
1634{
1635 // If we have any pads, fall back on normal checking
1636 for( PAD* pad : m_pads )
1637 {
1638 if( pad->IsOnLayer( aLayer ) )
1639 return true;
1640 }
1641
1642 for( ZONE* zone : m_zones )
1643 {
1644 if( zone->IsOnLayer( aLayer ) )
1645 return true;
1646 }
1647
1648 for( PCB_FIELD* field : m_fields )
1649 {
1650 if( field->IsOnLayer( aLayer ) )
1651 return true;
1652 }
1653
1654 for( BOARD_ITEM* item : m_drawings )
1655 {
1656 if( item->IsOnLayer( aLayer ) )
1657 return true;
1658 }
1659
1660 return false;
1661}
1662
1663
1664bool FOOTPRINT::HitTestOnLayer( const VECTOR2I& aPosition, PCB_LAYER_ID aLayer, int aAccuracy ) const
1665{
1666 for( PAD* pad : m_pads )
1667 {
1668 if( pad->IsOnLayer( aLayer ) && pad->HitTest( aPosition, aAccuracy ) )
1669 return true;
1670 }
1671
1672 for( ZONE* zone : m_zones )
1673 {
1674 if( zone->IsOnLayer( aLayer ) && zone->HitTest( aPosition, aAccuracy ) )
1675 return true;
1676 }
1677
1678 for( BOARD_ITEM* item : m_drawings )
1679 {
1680 if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer )
1681 && item->HitTest( aPosition, aAccuracy ) )
1682 {
1683 return true;
1684 }
1685 }
1686
1687 return false;
1688}
1689
1690
1691bool FOOTPRINT::HitTestOnLayer( const BOX2I& aRect, bool aContained, PCB_LAYER_ID aLayer, int aAccuracy ) const
1692{
1693 std::vector<BOARD_ITEM*> items;
1694
1695 for( PAD* pad : m_pads )
1696 {
1697 if( pad->IsOnLayer( aLayer ) )
1698 items.push_back( pad );
1699 }
1700
1701 for( ZONE* zone : m_zones )
1702 {
1703 if( zone->IsOnLayer( aLayer ) )
1704 items.push_back( zone );
1705 }
1706
1707 for( BOARD_ITEM* item : m_drawings )
1708 {
1709 if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer ) )
1710 items.push_back( item );
1711 }
1712
1713 // If we require the elements to be contained in the rect and any of them are not,
1714 // we can return false;
1715 // Conversely, if we just require any of the elements to have a hit, we can return true
1716 // when the first one is found.
1717 for( BOARD_ITEM* item : items )
1718 {
1719 if( !aContained && item->HitTest( aRect, aContained, aAccuracy ) )
1720 return true;
1721 else if( aContained && !item->HitTest( aRect, aContained, aAccuracy ) )
1722 return false;
1723 }
1724
1725 // If we didn't exit in the loop, that means that we did not return false for aContained or
1726 // we did not return true for !aContained. So we can just return the bool with a test of
1727 // whether there were any elements or not.
1728 return !items.empty() && aContained;
1729}
1730
1731
1732bool FOOTPRINT::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
1733{
1734 BOX2I rect = GetBoundingBox( false, false );
1735 return rect.Inflate( aAccuracy ).Contains( aPosition );
1736}
1737
1738
1739bool FOOTPRINT::HitTestAccurate( const VECTOR2I& aPosition, int aAccuracy ) const
1740{
1741 return GetBoundingHull().Collide( aPosition, aAccuracy );
1742}
1743
1744
1745bool FOOTPRINT::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1746{
1747 BOX2I arect = aRect;
1748 arect.Inflate( aAccuracy );
1749
1750 if( aContained )
1751 {
1752 return arect.Contains( GetBoundingBox( false, false ) );
1753 }
1754 else
1755 {
1756 // If the rect does not intersect the bounding box, skip any tests
1757 if( !aRect.Intersects( GetBoundingBox( false, false ) ) )
1758 return false;
1759
1760 // If there are no pads, zones, or drawings, allow intersection with text
1761 if( m_pads.empty() && m_zones.empty() && m_drawings.empty() )
1762 return GetBoundingBox( true, false ).Intersects( arect );
1763
1764 // Determine if any elements in the FOOTPRINT intersect the rect
1765 for( PAD* pad : m_pads )
1766 {
1767 if( pad->HitTest( arect, false, 0 ) )
1768 return true;
1769 }
1770
1771 for( ZONE* zone : m_zones )
1772 {
1773 if( zone->HitTest( arect, false, 0 ) )
1774 return true;
1775 }
1776
1777 // PCB fields are selectable on their own, so they don't get tested
1778
1779 for( BOARD_ITEM* item : m_drawings )
1780 {
1781 // Text items are selectable on their own, and are therefore excluded from this
1782 // test. TextBox items are NOT selectable on their own, and so MUST be included
1783 // here. Bitmaps aren't selectable since they aren't displayed.
1784 if( item->Type() != PCB_TEXT_T && item->HitTest( arect, false, 0 ) )
1785 return true;
1786 }
1787
1788 // Groups are not hit-tested; only their members
1789
1790 // No items were hit
1791 return false;
1792 }
1793}
1794
1795
1796PAD* FOOTPRINT::FindPadByNumber( const wxString& aPadNumber, PAD* aSearchAfterMe ) const
1797{
1798 bool can_select = aSearchAfterMe ? false : true;
1799
1800 for( PAD* pad : m_pads )
1801 {
1802 if( !can_select && pad == aSearchAfterMe )
1803 {
1804 can_select = true;
1805 continue;
1806 }
1807
1808 if( can_select && pad->GetNumber() == aPadNumber )
1809 return pad;
1810 }
1811
1812 return nullptr;
1813}
1814
1815
1816PAD* FOOTPRINT::GetPad( const VECTOR2I& aPosition, LSET aLayerMask )
1817{
1818 for( PAD* pad : m_pads )
1819 {
1820 // ... and on the correct layer.
1821 if( !( pad->GetLayerSet() & aLayerMask ).any() )
1822 continue;
1823
1824 if( pad->HitTest( aPosition ) )
1825 return pad;
1826 }
1827
1828 return nullptr;
1829}
1830
1831
1832std::vector<const PAD*> FOOTPRINT::GetPads( const wxString& aPadNumber, const PAD* aIgnore ) const
1833{
1834 std::vector<const PAD*> retv;
1835
1836 for( const PAD* pad : m_pads )
1837 {
1838 if( ( aIgnore && aIgnore == pad ) || ( pad->GetNumber() != aPadNumber ) )
1839 continue;
1840
1841 retv.push_back( pad );
1842 }
1843
1844 return retv;
1845}
1846
1847
1848unsigned FOOTPRINT::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1849{
1850 if( aIncludeNPTH )
1851 return m_pads.size();
1852
1853 unsigned cnt = 0;
1854
1855 for( PAD* pad : m_pads )
1856 {
1857 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1858 continue;
1859
1860 cnt++;
1861 }
1862
1863 return cnt;
1864}
1865
1866
1867std::set<wxString> FOOTPRINT::GetUniquePadNumbers( INCLUDE_NPTH_T aIncludeNPTH ) const
1868{
1869 std::set<wxString> usedNumbers;
1870
1871 // Create a set of used pad numbers
1872 for( PAD* pad : m_pads )
1873 {
1874 // Skip pads not on copper layers (used to build complex
1875 // solder paste shapes for instance)
1876 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none() )
1877 continue;
1878
1879 // Skip pads with no name, because they are usually "mechanical"
1880 // pads, not "electrical" pads
1881 if( pad->GetNumber().IsEmpty() )
1882 continue;
1883
1884 if( !aIncludeNPTH )
1885 {
1886 // skip NPTH
1887 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1888 continue;
1889 }
1890
1891 usedNumbers.insert( pad->GetNumber() );
1892 }
1893
1894 return usedNumbers;
1895}
1896
1897
1898unsigned FOOTPRINT::GetUniquePadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1899{
1900 return GetUniquePadNumbers( aIncludeNPTH ).size();
1901}
1902
1903
1905{
1906 if( nullptr == a3DModel )
1907 return;
1908
1909 if( !a3DModel->m_Filename.empty() )
1910 m_3D_Drawings.push_back( *a3DModel );
1911}
1912
1913
1914// see footprint.h
1915INSPECT_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData,
1916 const std::vector<KICAD_T>& aScanTypes )
1917{
1918#if 0 && defined(DEBUG)
1919 std::cout << GetClass().mb_str() << ' ';
1920#endif
1921
1922 bool drawingsScanned = false;
1923
1924 for( KICAD_T scanType : aScanTypes )
1925 {
1926 switch( scanType )
1927 {
1928 case PCB_FOOTPRINT_T:
1929 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
1930 return INSPECT_RESULT::QUIT;
1931
1932 break;
1933
1934 case PCB_PAD_T:
1935 if( IterateForward<PAD*>( m_pads, inspector, testData, { scanType } )
1936 == INSPECT_RESULT::QUIT )
1937 {
1938 return INSPECT_RESULT::QUIT;
1939 }
1940
1941 break;
1942
1943 case PCB_ZONE_T:
1944 if( IterateForward<ZONE*>( m_zones, inspector, testData, { scanType } )
1945 == INSPECT_RESULT::QUIT )
1946 {
1947 return INSPECT_RESULT::QUIT;
1948 }
1949
1950 break;
1951
1952 case PCB_FIELD_T:
1953 if( IterateForward<PCB_FIELD*>( m_fields, inspector, testData, { scanType } )
1954 == INSPECT_RESULT::QUIT )
1955 {
1956 return INSPECT_RESULT::QUIT;
1957 }
1958
1959 break;
1960
1961 case PCB_TEXT_T:
1962 case PCB_DIM_ALIGNED_T:
1963 case PCB_DIM_LEADER_T:
1964 case PCB_DIM_CENTER_T:
1965 case PCB_DIM_RADIAL_T:
1967 case PCB_SHAPE_T:
1968 case PCB_TEXTBOX_T:
1969 case PCB_TABLE_T:
1970 case PCB_TABLECELL_T:
1971 if( !drawingsScanned )
1972 {
1973 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, aScanTypes )
1974 == INSPECT_RESULT::QUIT )
1975 {
1976 return INSPECT_RESULT::QUIT;
1977 }
1978
1979 drawingsScanned = true;
1980 }
1981
1982 break;
1983
1984 case PCB_GROUP_T:
1985 if( IterateForward<PCB_GROUP*>( m_groups, inspector, testData, { scanType } )
1986 == INSPECT_RESULT::QUIT )
1987 {
1988 return INSPECT_RESULT::QUIT;
1989 }
1990
1991 break;
1992
1993 default:
1994 break;
1995 }
1996 }
1997
1998 return INSPECT_RESULT::CONTINUE;
1999}
2000
2001
2002wxString FOOTPRINT::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
2003{
2004 wxString reference = GetReference();
2005
2006 if( reference.IsEmpty() )
2007 reference = _( "<no reference designator>" );
2008
2009 return wxString::Format( _( "Footprint %s" ), reference );
2010}
2011
2012
2014{
2015 return BITMAPS::module;
2016}
2017
2018
2020{
2021 return new FOOTPRINT( *this );
2022}
2023
2024
2025void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM* )>& aFunction ) const
2026{
2027 try
2028 {
2029 for( PCB_FIELD* field : m_fields )
2030 aFunction( field );
2031
2032 for( PAD* pad : m_pads )
2033 aFunction( pad );
2034
2035 for( ZONE* zone : m_zones )
2036 aFunction( zone );
2037
2038 for( PCB_GROUP* group : m_groups )
2039 aFunction( group );
2040
2041 for( BOARD_ITEM* drawing : m_drawings )
2042 aFunction( drawing );
2043 }
2044 catch( std::bad_function_call& )
2045 {
2046 wxFAIL_MSG( wxT( "Error running FOOTPRINT::RunOnChildren" ) );
2047 }
2048}
2049
2050
2051void FOOTPRINT::RunOnDescendants( const std::function<void( BOARD_ITEM* )>& aFunction,
2052 int aDepth ) const
2053{
2054 // Avoid freezes with infinite recursion
2055 if( aDepth > 20 )
2056 return;
2057
2058 try
2059 {
2060 for( PCB_FIELD* field : m_fields )
2061 aFunction( field );
2062
2063 for( PAD* pad : m_pads )
2064 aFunction( pad );
2065
2066 for( ZONE* zone : m_zones )
2067 aFunction( zone );
2068
2069 for( PCB_GROUP* group : m_groups )
2070 {
2071 aFunction( group );
2072 group->RunOnDescendants( aFunction, aDepth + 1 );
2073 }
2074
2075 for( BOARD_ITEM* drawing : m_drawings )
2076 {
2077 aFunction( drawing );
2078 drawing->RunOnDescendants( aFunction, aDepth + 1 );
2079 }
2080 }
2081 catch( std::bad_function_call& )
2082 {
2083 wxFAIL_MSG( wxT( "Error running FOOTPRINT::RunOnDescendants" ) );
2084 }
2085}
2086
2087
2088void FOOTPRINT::ViewGetLayers( int aLayers[], int& aCount ) const
2089{
2090 aCount = 2;
2091 aLayers[0] = LAYER_ANCHOR;
2092
2093 switch( m_layer )
2094 {
2095 default:
2096 wxASSERT_MSG( false, wxT( "Illegal layer" ) ); // do you really have footprints placed
2097 // on other layers?
2099
2100 case F_Cu:
2101 aLayers[1] = LAYER_FOOTPRINTS_FR;
2102 break;
2103
2104 case B_Cu:
2105 aLayers[1] = LAYER_FOOTPRINTS_BK;
2106 break;
2107 }
2108
2109 if( IsLocked() )
2110 aLayers[ aCount++ ] = LAYER_LOCKED_ITEM_SHADOW;
2111
2112 if( IsConflicting() )
2113 aLayers[ aCount++ ] = LAYER_CONFLICTS_SHADOW;
2114
2115 // If there are no pads, and only drawings on a silkscreen layer, then report the silkscreen
2116 // layer as well so that the component can be edited with the silkscreen layer
2117 bool f_silk = false, b_silk = false, non_silk = false;
2118
2119 for( BOARD_ITEM* item : m_drawings )
2120 {
2121 if( item->GetLayer() == F_SilkS )
2122 f_silk = true;
2123 else if( item->GetLayer() == B_SilkS )
2124 b_silk = true;
2125 else
2126 non_silk = true;
2127 }
2128
2129 if( ( f_silk || b_silk ) && !non_silk && m_pads.empty() )
2130 {
2131 if( f_silk )
2132 aLayers[ aCount++ ] = F_SilkS;
2133
2134 if( b_silk )
2135 aLayers[ aCount++ ] = B_SilkS;
2136 }
2137}
2138
2139
2140double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
2141{
2142 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
2143 {
2144 // The locked shadow shape is shown only if the footprint itself is visible
2145 if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
2146 return 0.0;
2147
2148 if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
2149 return 0.0;
2150
2151 return std::numeric_limits<double>::max();
2152 }
2153
2154 if( aLayer == LAYER_CONFLICTS_SHADOW && IsConflicting() )
2155 {
2156 // The locked shadow shape is shown only if the footprint itself is visible
2157 if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
2158 return 0.0;
2159
2160 if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
2161 return 0.0;
2162
2163 return std::numeric_limits<double>::max();
2164 }
2165
2166 int layer = ( m_layer == F_Cu ) ? LAYER_FOOTPRINTS_FR :
2168
2169 // Currently this is only pertinent for the anchor layer; everything else is drawn from the
2170 // children.
2171 // The "good" value is experimentally chosen.
2172 #define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY 1.5
2173
2174 if( aView->IsLayerVisible( layer ) )
2176
2177 return std::numeric_limits<double>::max();
2178}
2179
2180
2182{
2183 BOX2I area = GetBoundingBox( true, true );
2184
2185 // Inflate in case clearance lines are drawn around pads, etc.
2186 if( const BOARD* board = GetBoard() )
2187 {
2188 int biggest_clearance = board->GetMaxClearanceValue();
2189 area.Inflate( biggest_clearance );
2190 }
2191
2192 return area;
2193}
2194
2195
2196bool FOOTPRINT::IsLibNameValid( const wxString & aName )
2197{
2198 const wxChar * invalids = StringLibNameInvalidChars( false );
2199
2200 if( aName.find_first_of( invalids ) != std::string::npos )
2201 return false;
2202
2203 return true;
2204}
2205
2206
2207const wxChar* FOOTPRINT::StringLibNameInvalidChars( bool aUserReadable )
2208{
2209 // This list of characters is also duplicated in validators.cpp and
2210 // lib_id.cpp
2211 // TODO: Unify forbidden character lists - Warning, invalid filename characters are not the same
2212 // as invalid LIB_ID characters. We will need to separate the FP filenames from FP names before this
2213 // can be unified
2214 static const wxChar invalidChars[] = wxT("%$<>\t\n\r\"\\/:");
2215 static const wxChar invalidCharsReadable[] = wxT("% $ < > 'tab' 'return' 'line feed' \\ \" / :");
2216
2217 if( aUserReadable )
2218 return invalidCharsReadable;
2219 else
2220 return invalidChars;
2221}
2222
2223
2224void FOOTPRINT::Move( const VECTOR2I& aMoveVector )
2225{
2226 if( aMoveVector.x == 0 && aMoveVector.y == 0 )
2227 return;
2228
2229 VECTOR2I newpos = m_pos + aMoveVector;
2230 SetPosition( newpos );
2231}
2232
2233
2234void FOOTPRINT::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
2235{
2236 if( aAngle == ANGLE_0 )
2237 return;
2238
2239 EDA_ANGLE orientation = GetOrientation();
2240 EDA_ANGLE newOrientation = orientation + aAngle;
2241 VECTOR2I newpos = m_pos;
2242 RotatePoint( newpos, aRotCentre, aAngle );
2243 SetPosition( newpos );
2244 SetOrientation( newOrientation );
2245
2246 for( PCB_FIELD* field : m_fields )
2247 field->KeepUpright();
2248
2249 for( BOARD_ITEM* item : m_drawings )
2250 {
2251 if( item->Type() == PCB_TEXT_T )
2252 static_cast<PCB_TEXT*>( item )->KeepUpright();
2253 }
2254
2259}
2260
2261
2263{
2264 wxASSERT( aLayer == F_Cu || aLayer == B_Cu );
2265
2266 if( aLayer != GetLayer() )
2267 Flip( GetPosition(), true );
2268}
2269
2270
2271void FOOTPRINT::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
2272{
2273 // Move footprint to its final position:
2274 VECTOR2I finalPos = m_pos;
2275
2276 // Now Flip the footprint.
2277 // Flipping a footprint is a specific transform: it is not mirrored like a text.
2278 // We have to change the side, and ensure the footprint rotation is modified according to the
2279 // transform, because this parameter is used in pick and place files, and when updating the
2280 // footprint from library.
2281 // When flipped around the X axis (Y coordinates changed) orientation is negated
2282 // When flipped around the Y axis (X coordinates changed) orientation is 180 - old orient.
2283 // Because it is specific to a footprint, we flip around the X axis, and after rotate 180 deg
2284
2285 MIRROR( finalPos.y, aCentre.y );
2286
2287 SetPosition( finalPos );
2288
2289 // Flip layer
2291
2292 // Calculate the new orientation, and then clear it for pad flipping.
2293 EDA_ANGLE newOrientation = -m_orient;
2294 newOrientation.Normalize180();
2295 m_orient = ANGLE_0;
2296
2297 // Mirror fields to other side of board.
2298 for( PCB_FIELD* field : m_fields )
2299 field->Flip( m_pos, false );
2300
2301 // Mirror pads to other side of board.
2302 for( PAD* pad : m_pads )
2303 pad->Flip( m_pos, false );
2304
2305 // Now set the new orientation.
2306 m_orient = newOrientation;
2307
2308 // Mirror zones to other side of board.
2309 for( ZONE* zone : m_zones )
2310 zone->Flip( m_pos, false );
2311
2312 // Reverse mirror footprint graphics and texts.
2313 for( BOARD_ITEM* item : m_drawings )
2314 item->Flip( m_pos, false );
2315
2316 // Now rotate 180 deg if required
2317 if( aFlipLeftRight )
2318 Rotate( aCentre, ANGLE_180 );
2319
2323
2324 m_cachedHull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos );
2325
2327}
2328
2329
2331{
2332 VECTOR2I delta = aPos - m_pos;
2333
2334 m_pos += delta;
2335
2336 for( PCB_FIELD* field : m_fields )
2337 field->EDA_TEXT::Offset( delta );
2338
2339 for( PAD* pad : m_pads )
2340 pad->SetPosition( pad->GetPosition() + delta );
2341
2342 for( ZONE* zone : m_zones )
2343 zone->Move( delta );
2344
2345 for( BOARD_ITEM* item : m_drawings )
2346 item->Move( delta );
2347
2354}
2355
2356
2357void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector )
2358{
2359 /*
2360 * Move the reference point of the footprint
2361 * the footprints elements (pads, outlines, edges .. ) are moved
2362 * but:
2363 * - the footprint position is not modified.
2364 * - the relative (local) coordinates of these items are modified
2365 * - Draw coordinates are updated
2366 */
2367
2368 // Update (move) the relative coordinates relative to the new anchor point.
2369 VECTOR2I moveVector = aMoveVector;
2370 RotatePoint( moveVector, -GetOrientation() );
2371
2372 // Update field local coordinates
2373 for( PCB_FIELD* field : m_fields )
2374 field->Move( moveVector );
2375
2376 // Update the pad local coordinates.
2377 for( PAD* pad : m_pads )
2378 pad->Move( moveVector );
2379
2380 // Update the draw element coordinates.
2381 for( BOARD_ITEM* item : GraphicalItems() )
2382 item->Move( moveVector );
2383
2384 // Update the keepout zones
2385 for( ZONE* zone : Zones() )
2386 zone->Move( moveVector );
2387
2388 // Update the 3D models
2389 for( FP_3DMODEL& model : Models() )
2390 {
2391 model.m_Offset.x += pcbIUScale.IUTomm( moveVector.x );
2392 model.m_Offset.y -= pcbIUScale.IUTomm( moveVector.y );
2393 }
2394
2395 m_cachedBoundingBox.Move( moveVector );
2396 m_cachedVisibleBBox.Move( moveVector );
2397 m_cachedTextExcludedBBox.Move( moveVector );
2398 m_cachedHull.Move( moveVector );
2399}
2400
2401
2402void FOOTPRINT::SetOrientation( const EDA_ANGLE& aNewAngle )
2403{
2404 EDA_ANGLE angleChange = aNewAngle - m_orient; // change in rotation
2405
2406 m_orient = aNewAngle;
2408
2409 for( PCB_FIELD* field : m_fields )
2410 field->Rotate( GetPosition(), angleChange );
2411
2412 for( PAD* pad : m_pads )
2413 pad->Rotate( GetPosition(), angleChange );
2414
2415 for( ZONE* zone : m_zones )
2416 zone->Rotate( GetPosition(), angleChange );
2417
2418 for( BOARD_ITEM* item : m_drawings )
2419 item->Rotate( GetPosition(), angleChange );
2420
2424
2425 m_cachedHull.Rotate( angleChange, GetPosition() );
2426}
2427
2428
2430{
2431 FOOTPRINT* dupe = static_cast<FOOTPRINT*>( BOARD_ITEM::Duplicate() );
2432
2433 dupe->RunOnDescendants( [&]( BOARD_ITEM* child )
2434 {
2435 const_cast<KIID&>( child->m_Uuid ) = KIID();
2436 });
2437
2438 return dupe;
2439}
2440
2441
2442BOARD_ITEM* FOOTPRINT::DuplicateItem( const BOARD_ITEM* aItem, bool aAddToFootprint )
2443{
2444 BOARD_ITEM* new_item = nullptr;
2445
2446 switch( aItem->Type() )
2447 {
2448 case PCB_PAD_T:
2449 {
2450 PAD* new_pad = new PAD( *static_cast<const PAD*>( aItem ) );
2451 const_cast<KIID&>( new_pad->m_Uuid ) = KIID();
2452
2453 if( aAddToFootprint )
2454 m_pads.push_back( new_pad );
2455
2456 new_item = new_pad;
2457 break;
2458 }
2459
2460 case PCB_ZONE_T:
2461 {
2462 ZONE* new_zone = new ZONE( *static_cast<const ZONE*>( aItem ) );
2463 const_cast<KIID&>( new_zone->m_Uuid ) = KIID();
2464
2465 if( aAddToFootprint )
2466 m_zones.push_back( new_zone );
2467
2468 new_item = new_zone;
2469 break;
2470 }
2471
2472 case PCB_FIELD_T:
2473 case PCB_TEXT_T:
2474 {
2475 PCB_TEXT* new_text = new PCB_TEXT( *static_cast<const PCB_TEXT*>( aItem ) );
2476 const_cast<KIID&>( new_text->m_Uuid ) = KIID();
2477
2478 if( aItem->Type() == PCB_FIELD_T )
2479 {
2480 switch( static_cast<const PCB_FIELD*>( aItem )->GetId() )
2481 {
2482 case REFERENCE_FIELD: new_text->SetText( wxT( "${REFERENCE}" ) ); break;
2483
2484 case VALUE_FIELD: new_text->SetText( wxT( "${VALUE}" ) ); break;
2485
2486 case DATASHEET_FIELD: new_text->SetText( wxT( "${DATASHEET}" ) ); break;
2487
2488 case FOOTPRINT_FIELD: new_text->SetText( wxT( "${FOOTPRINT}" ) ); break;
2489 }
2490 }
2491
2492 if( aAddToFootprint )
2493 Add( new_text );
2494
2495 new_item = new_text;
2496 break;
2497 }
2498
2499 case PCB_SHAPE_T:
2500 {
2501 PCB_SHAPE* new_shape = new PCB_SHAPE( *static_cast<const PCB_SHAPE*>( aItem ) );
2502 const_cast<KIID&>( new_shape->m_Uuid ) = KIID();
2503
2504 if( aAddToFootprint )
2505 Add( new_shape );
2506
2507 new_item = new_shape;
2508 break;
2509 }
2510
2511 case PCB_TEXTBOX_T:
2512 {
2513 PCB_TEXTBOX* new_textbox = new PCB_TEXTBOX( *static_cast<const PCB_TEXTBOX*>( aItem ) );
2514 const_cast<KIID&>( new_textbox->m_Uuid ) = KIID();
2515
2516 if( aAddToFootprint )
2517 Add( new_textbox );
2518
2519 new_item = new_textbox;
2520 break;
2521 }
2522
2523 case PCB_DIM_ALIGNED_T:
2524 case PCB_DIM_LEADER_T:
2525 case PCB_DIM_CENTER_T:
2526 case PCB_DIM_RADIAL_T:
2528 {
2529 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( aItem->Duplicate() );
2530
2531 if( aAddToFootprint )
2532 Add( dimension );
2533
2534 new_item = dimension;
2535 break;
2536 }
2537
2538 case PCB_GROUP_T:
2539 {
2540 PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem )->DeepDuplicate();
2541
2542 if( aAddToFootprint )
2543 {
2544 group->RunOnDescendants(
2545 [&]( BOARD_ITEM* aCurrItem )
2546 {
2547 Add( aCurrItem );
2548 } );
2549
2550 Add( new_item );
2551 }
2552
2553 new_item = group;
2554 break;
2555 }
2556
2557 case PCB_FOOTPRINT_T:
2558 // Ignore the footprint itself
2559 break;
2560
2561 default:
2562 // Un-handled item for duplication
2563 wxFAIL_MSG( wxT( "Duplication not supported for items of class " ) + aItem->GetClass() );
2564 break;
2565 }
2566
2567 return new_item;
2568}
2569
2570
2571wxString FOOTPRINT::GetNextPadNumber( const wxString& aLastPadNumber ) const
2572{
2573 std::set<wxString> usedNumbers;
2574
2575 // Create a set of used pad numbers
2576 for( PAD* pad : m_pads )
2577 usedNumbers.insert( pad->GetNumber() );
2578
2579 // Pad numbers aren't technically reference designators, but the formatting is close enough
2580 // for these to give us what we need.
2581 wxString prefix = UTIL::GetRefDesPrefix( aLastPadNumber );
2582 int num = GetTrailingInt( aLastPadNumber );
2583
2584 while( usedNumbers.count( wxString::Format( wxT( "%s%d" ), prefix, num ) ) )
2585 num++;
2586
2587 return wxString::Format( wxT( "%s%d" ), prefix, num );
2588}
2589
2590
2592{
2593 // Auto-position reference and value
2594 BOX2I bbox = GetBoundingBox( false, false );
2595 bbox.Inflate( pcbIUScale.mmToIU( 0.2 ) ); // Gap between graphics and text
2596
2597 if( Reference().GetPosition() == VECTOR2I( 0, 0 ) )
2598 {
2602
2603 Reference().SetX( bbox.GetCenter().x );
2604 Reference().SetY( bbox.GetTop() - Reference().GetTextSize().y / 2 );
2605 }
2606
2607 if( Value().GetPosition() == VECTOR2I( 0, 0 ) )
2608 {
2612
2613 Value().SetX( bbox.GetCenter().x );
2614 Value().SetY( bbox.GetBottom() + Value().GetTextSize().y / 2 );
2615 }
2616}
2617
2618
2620{
2621 const wxString& refdes = GetReference();
2622
2623 SetReference( wxString::Format( wxT( "%s%i" ),
2624 UTIL::GetRefDesPrefix( refdes ),
2625 GetTrailingInt( refdes ) + aDelta ) );
2626}
2627
2628
2629// Calculate the area of a PolySet, polygons with hole are allowed.
2630static double polygonArea( SHAPE_POLY_SET& aPolySet )
2631{
2632 // Ensure all outlines are closed, before calculating the SHAPE_POLY_SET area
2633 for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
2634 {
2635 SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
2636 outline.SetClosed( true );
2637
2638 for( int jj = 0; jj < aPolySet.HoleCount( ii ); jj++ )
2639 aPolySet.Hole( ii, jj ).SetClosed( true );
2640 }
2641
2642 return aPolySet.Area();
2643}
2644
2645
2646double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLECTOR& aCollector )
2647{
2648 int textMargin = aCollector.GetGuide()->Accuracy();
2649 SHAPE_POLY_SET poly;
2650
2651 if( aItem->Type() == PCB_MARKER_T )
2652 {
2653 const PCB_MARKER* marker = static_cast<const PCB_MARKER*>( aItem );
2654 SHAPE_LINE_CHAIN markerShape;
2655
2656 marker->ShapeToPolygon( markerShape );
2657 return markerShape.Area();
2658 }
2659 else if( aItem->Type() == PCB_GROUP_T || aItem->Type() == PCB_GENERATOR_T )
2660 {
2661 double combinedArea = 0.0;
2662
2663 for( BOARD_ITEM* member : static_cast<const PCB_GROUP*>( aItem )->GetItems() )
2664 combinedArea += GetCoverageArea( member, aCollector );
2665
2666 return combinedArea;
2667 }
2668 if( aItem->Type() == PCB_FOOTPRINT_T )
2669 {
2670 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
2671
2672 poly = footprint->GetBoundingHull();
2673 }
2674 else if( aItem->Type() == PCB_FIELD_T || aItem->Type() == PCB_TEXT_T )
2675 {
2676 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
2677
2678 text->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
2679 }
2680 else if( aItem->Type() == PCB_TEXTBOX_T )
2681 {
2682 const PCB_TEXTBOX* tb = static_cast<const PCB_TEXTBOX*>( aItem );
2683
2684 tb->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
2685 }
2686 else if( aItem->Type() == PCB_SHAPE_T )
2687 {
2688 // Approximate "linear" shapes with just their width squared, as we don't want to consider
2689 // a linear shape as being much bigger than another for purposes of selection filtering
2690 // just because it happens to be really long.
2691
2692 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
2693
2694 switch( shape->GetShape() )
2695 {
2696 case SHAPE_T::SEGMENT:
2697 case SHAPE_T::ARC:
2698 case SHAPE_T::BEZIER:
2699 return shape->GetWidth() * shape->GetWidth();
2700
2701 case SHAPE_T::RECTANGLE:
2702 case SHAPE_T::CIRCLE:
2703 case SHAPE_T::POLY:
2704 {
2705 if( !shape->IsFilled() )
2706 return shape->GetWidth() * shape->GetWidth();
2707
2709 }
2710
2711 default:
2713 }
2714 }
2715 else if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2716 {
2717 double width = static_cast<const PCB_TRACK*>( aItem )->GetWidth();
2718 return width * width;
2719 }
2720 else
2721 {
2723 }
2724
2725 return polygonArea( poly );
2726}
2727
2728
2729double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
2730{
2731 int textMargin = aCollector.GetGuide()->Accuracy();
2732
2733 SHAPE_POLY_SET footprintRegion( GetBoundingHull() );
2734 SHAPE_POLY_SET coveredRegion;
2735
2737
2738 TransformFPShapesToPolySet( coveredRegion, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF,
2740 true, /* include text */
2741 false, /* include shapes */
2742 false /* include private items */ );
2743
2744 for( int i = 0; i < aCollector.GetCount(); ++i )
2745 {
2746 const BOARD_ITEM* item = aCollector[i];
2747
2748 switch( item->Type() )
2749 {
2750 case PCB_FIELD_T:
2751 case PCB_TEXT_T:
2752 case PCB_TEXTBOX_T:
2753 case PCB_SHAPE_T:
2754 case PCB_TRACE_T:
2755 case PCB_ARC_T:
2756 case PCB_VIA_T:
2757 if( item->GetParent() != this )
2758 {
2759 item->TransformShapeToPolygon( coveredRegion, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
2760 ERROR_OUTSIDE );
2761 }
2762 break;
2763
2764 case PCB_FOOTPRINT_T:
2765 if( item != this )
2766 {
2767 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( item );
2768 coveredRegion.AddOutline( footprint->GetBoundingHull().Outline( 0 ) );
2769 }
2770 break;
2771
2772 default:
2773 break;
2774 }
2775 }
2776
2777 coveredRegion.BooleanIntersection( footprintRegion, SHAPE_POLY_SET::PM_FAST );
2778
2779 double footprintRegionArea = polygonArea( footprintRegion );
2780 double uncoveredRegionArea = footprintRegionArea - polygonArea( coveredRegion );
2781 double coveredArea = footprintRegionArea - uncoveredRegionArea;
2782 double ratio = ( coveredArea / footprintRegionArea );
2783
2784 // Test for negative ratio (should not occur).
2785 // better to be conservative (this will result in the disambiguate dialog)
2786 if( ratio < 0.0 )
2787 return 1.0;
2788
2789 return std::min( ratio, 1.0 );
2790}
2791
2792
2793std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2794{
2795 std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
2796
2797 // There are several possible interpretations here:
2798 // 1) the bounding box (without or without invisible items)
2799 // 2) just the pads and "edges" (ie: non-text graphic items)
2800 // 3) the courtyard
2801
2802 // We'll go with (2) for now, unless the caller is clearly looking for (3)
2803
2804 if( aLayer == F_CrtYd || aLayer == B_CrtYd )
2805 {
2806 const SHAPE_POLY_SET& courtyard = GetCourtyard( aLayer );
2807
2808 if( courtyard.OutlineCount() == 0 ) // malformed/empty polygon
2809 return shape;
2810
2811 shape->AddShape( new SHAPE_SIMPLE( courtyard.COutline( 0 ) ) );
2812 }
2813 else
2814 {
2815 for( PAD* pad : Pads() )
2816 shape->AddShape( pad->GetEffectiveShape( aLayer, aFlash )->Clone() );
2817
2818 for( BOARD_ITEM* item : GraphicalItems() )
2819 {
2820 if( item->Type() == PCB_SHAPE_T )
2821 shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->Clone() );
2822 }
2823 }
2824
2825 return shape;
2826}
2827
2828
2830{
2831 std::lock_guard<std::mutex> lock( m_courtyard_cache_mutex );
2832
2835 {
2836 const_cast<FOOTPRINT*>( this )->BuildCourtyardCaches();
2837 }
2838
2839 if( IsBackLayer( aLayer ) )
2841 else
2843}
2844
2845
2847{
2851
2852 // Build the courtyard area from graphic items on the courtyard.
2853 // Only PCB_SHAPE_T have meaning, graphic texts are ignored.
2854 // Collect items:
2855 std::vector<PCB_SHAPE*> list_front;
2856 std::vector<PCB_SHAPE*> list_back;
2857 std::map<int, int> front_width_histogram;
2858 std::map<int, int> back_width_histogram;
2859
2860 for( BOARD_ITEM* item : GraphicalItems() )
2861 {
2862 if( item->GetLayer() == B_CrtYd && item->Type() == PCB_SHAPE_T )
2863 {
2864 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
2865 list_back.push_back( shape );
2866 back_width_histogram[ shape->GetStroke().GetWidth() ]++;
2867 }
2868
2869 if( item->GetLayer() == F_CrtYd && item->Type() == PCB_SHAPE_T )
2870 {
2871 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
2872 list_front.push_back( shape );
2873 front_width_histogram[ shape->GetStroke().GetWidth() ]++;
2874 }
2875 }
2876
2877 if( !list_front.size() && !list_back.size() )
2878 return;
2879
2880 int maxError = pcbIUScale.mmToIU( 0.005 ); // max error for polygonization
2881 int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt
2882
2883 if( ConvertOutlineToPolygon( list_front, m_courtyard_cache_front, maxError, chainingEpsilon,
2884 true, aErrorHandler ) )
2885 {
2886 int width = 0;
2887
2888 // Touching courtyards, or courtyards -at- the clearance distance are legal.
2889 m_courtyard_cache_front.Inflate( -1, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, maxError );
2890
2892 auto max = std::max_element( front_width_histogram.begin(), front_width_histogram.end(),
2893 []( const std::pair<int, int>& a, const std::pair<int, int>& b )
2894 {
2895 return a.second < b.second;
2896 } );
2897
2898 if( max != front_width_histogram.end() )
2899 width = max->first;
2900
2901 if( width == 0 )
2903
2906 }
2907 else
2908 {
2910 }
2911
2912 if( ConvertOutlineToPolygon( list_back, m_courtyard_cache_back, maxError, chainingEpsilon, true,
2913 aErrorHandler ) )
2914 {
2915 int width = 0;
2916
2917 // Touching courtyards, or courtyards -at- the clearance distance are legal.
2918 m_courtyard_cache_back.Inflate( -1, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, maxError );
2919
2921 auto max = std::max_element( back_width_histogram.begin(), back_width_histogram.end(),
2922 []( const std::pair<int, int>& a, const std::pair<int, int>& b )
2923 {
2924 return a.second < b.second;
2925 } );
2926
2927 if( max != back_width_histogram.end() )
2928 width = max->first;
2929
2930 if( width == 0 )
2932
2935 }
2936 else
2937 {
2939 }
2940
2943}
2944
2945
2946std::map<wxString, int> FOOTPRINT::MapPadNumbersToNetTieGroups() const
2947{
2948 std::map<wxString, int> padNumberToGroupIdxMap;
2949
2950 for( const PAD* pad : m_pads )
2951 padNumberToGroupIdxMap[ pad->GetNumber() ] = -1;
2952
2953 auto processPad =
2954 [&]( wxString aPad, int aGroup )
2955 {
2956 aPad.Trim( true ).Trim( false );
2957
2958 if( !aPad.IsEmpty() )
2959 padNumberToGroupIdxMap[ aPad ] = aGroup;
2960 };
2961
2962 for( int ii = 0; ii < (int) m_netTiePadGroups.size(); ++ii )
2963 {
2964 wxString group( m_netTiePadGroups[ ii ] );
2965 bool esc = false;
2966 wxString pad;
2967
2968 for( wxUniCharRef ch : group )
2969 {
2970 if( esc )
2971 {
2972 esc = false;
2973 pad.Append( ch );
2974 continue;
2975 }
2976
2977 switch( static_cast<unsigned char>( ch ) )
2978 {
2979 case '\\':
2980 esc = true;
2981 break;
2982
2983 case ',':
2984 processPad( pad, ii );
2985 pad.Clear();
2986 break;
2987
2988 default:
2989 pad.Append( ch );
2990 break;
2991 }
2992 }
2993
2994 processPad( pad, ii );
2995 }
2996
2997 return padNumberToGroupIdxMap;
2998}
2999
3000
3001std::vector<PAD*> FOOTPRINT::GetNetTiePads( PAD* aPad ) const
3002{
3003 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
3004 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
3005
3006 std::map<wxString, int> padToNetTieGroupMap = MapPadNumbersToNetTieGroups();
3007 int groupIdx = padToNetTieGroupMap[ aPad->GetNumber() ];
3008 std::vector<PAD*> otherPads;
3009
3010 if( groupIdx >= 0 )
3011 {
3012 for( PAD* pad : m_pads )
3013 {
3014 if( padToNetTieGroupMap[ pad->GetNumber() ] == groupIdx )
3015 otherPads.push_back( pad );
3016 }
3017 }
3018
3019 return otherPads;
3020}
3021
3022
3023void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxString& )>& aErrorHandler )
3024{
3025 int likelyAttr = ( GetLikelyAttribute() & ( FP_SMD | FP_THROUGH_HOLE ) );
3026 int setAttr = ( GetAttributes() & ( FP_SMD | FP_THROUGH_HOLE ) );
3027
3028 if( setAttr && likelyAttr && setAttr != likelyAttr )
3029 {
3030 wxString msg;
3031
3032 switch( likelyAttr )
3033 {
3034 case FP_THROUGH_HOLE:
3035 msg.Printf( _( "(expected 'Through hole'; actual '%s')" ), GetTypeName() );
3036 break;
3037 case FP_SMD:
3038 msg.Printf( _( "(expected 'SMD'; actual '%s')" ), GetTypeName() );
3039 break;
3040 }
3041
3042 if( aErrorHandler )
3043 (aErrorHandler)( msg );
3044 }
3045}
3046
3047
3049 const std::function<void( const PAD*, int,
3050 const wxString& )>& aErrorHandler )
3051{
3052 if( aErrorHandler == nullptr )
3053 return;
3054
3055 for( PAD* pad: Pads() )
3056 {
3057 pad->CheckPad( aUnitsProvider,
3058 [&]( int errorCode, const wxString& msg )
3059 {
3060 aErrorHandler( pad, errorCode, msg );
3061 } );
3062 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
3063 {
3064 // Ensure the drill size can be handled in next calculations.
3065 // Use min size = 4 IU to be able to build a polygon from a hole shape
3066 const int min_drill_size = 4;
3067
3068 if( pad->GetDrillSizeX() <= min_drill_size || pad->GetDrillSizeY() <= min_drill_size )
3069 {
3070 (aErrorHandler)( pad, DRCE_PAD_TH_WITH_NO_HOLE,
3071 _( "(PTH pad's hole size is very small or null)" ) );
3072 }
3073 }
3074
3075 if( pad->GetAttribute() == PAD_ATTRIB::PTH )
3076 {
3077 if( !pad->IsOnCopperLayer() )
3078 {
3079 (aErrorHandler)( pad, DRCE_PADSTACK, _( "(PTH pad has no copper layers)" ) );
3080 }
3081 else
3082 {
3083 // Ensure the pad has a copper area.
3084 // min drill size is already tested and converting shapes to polygon can be made
3085 LSET lset = pad->GetLayerSet() & LSET::AllCuMask();
3086 PCB_LAYER_ID layer = lset.Seq().at( 0 );
3087 SHAPE_POLY_SET padOutline;
3088
3089 pad->TransformShapeToPolygon( padOutline, layer, 0, ARC_HIGH_DEF, ERROR_INSIDE );
3090
3091 std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
3092 SHAPE_POLY_SET holeOutline;
3093
3094 TransformOvalToPolygon( holeOutline, hole->GetSeg().A, hole->GetSeg().B,
3095 hole->GetWidth(), ARC_HIGH_DEF, ERROR_OUTSIDE );
3096
3097 // Test if there is copper area outside hole
3098 SHAPE_POLY_SET padOutlineCopy = padOutline;
3099 padOutline.BooleanSubtract( holeOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
3100
3101 if( padOutline.IsEmpty() )
3102 aErrorHandler( pad, DRCE_PADSTACK, _( "(PTH pad's hole leaves no copper)" ) );
3103 else
3104 {
3105 // Test if the pad hole is fully inside the copper area
3106 holeOutline.BooleanSubtract( padOutlineCopy, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
3107
3108 if( !holeOutline.IsEmpty() )
3109 aErrorHandler( pad, DRCE_PADSTACK,
3110 _( "(PTH pad's hole non fully inside copper)" ) );
3111 }
3112 }
3113 }
3114
3115 if( pad->GetAttribute() == PAD_ATTRIB::SMD )
3116 {
3117 if( pad->IsOnLayer( F_Cu ) && pad->IsOnLayer( B_Cu ) )
3118 {
3119 aErrorHandler( pad, DRCE_PADSTACK,
3120 _( "(SMD pad appears on both front and back copper)" ) );
3121 }
3122 else if( pad->IsOnLayer( F_Cu ) )
3123 {
3124 if( pad->IsOnLayer( B_Mask ) )
3125 {
3126 aErrorHandler( pad, DRCE_PADSTACK,
3127 _( "(SMD pad copper and mask layers don't match)" ) );
3128 }
3129 else if( pad->IsOnLayer( B_Paste ) )
3130 {
3131 aErrorHandler( pad, DRCE_PADSTACK,
3132 _( "(SMD pad copper and paste layers don't match)" ) );
3133 }
3134 }
3135 else if( pad->IsOnLayer( B_Cu ) )
3136 {
3137 if( pad->IsOnLayer( F_Mask ) )
3138 {
3139 aErrorHandler( pad, DRCE_PADSTACK,
3140 _( "(SMD pad copper and mask layers don't match)" ) );
3141 }
3142 else if( pad->IsOnLayer( F_Paste ) )
3143 {
3144 aErrorHandler( pad, DRCE_PADSTACK,
3145 _( "(SMD pad copper and paste layers don't match)" ) );
3146 }
3147 }
3148 }
3149 }
3150}
3151
3152
3153void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const PAD*,
3154 int aErrorCode,
3155 const VECTOR2I& )>& aErrorHandler )
3156{
3157 std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
3158
3159 for( PAD* pad : Pads() )
3160 {
3161 std::vector<PAD*> netTiePads = GetNetTiePads( pad );
3162
3163 for( PAD* other : Pads() )
3164 {
3165 if( other == pad )
3166 continue;
3167
3168 // store canonical order so we don't collide in both directions (a:b and b:a)
3169 PAD* a = pad;
3170 PAD* b = other;
3171
3172 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
3173 std::swap( a, b );
3174
3175 if( checkedPairs.find( { a, b } ) == checkedPairs.end() )
3176 {
3177 checkedPairs[ { a, b } ] = 1;
3178
3179 if( pad->HasDrilledHole() && other->HasDrilledHole() )
3180 {
3181 VECTOR2I pos = pad->GetPosition();
3182
3183 if( pad->GetPosition() == other->GetPosition() )
3184 {
3185 aErrorHandler( pad, other, DRCE_DRILLED_HOLES_COLOCATED, pos );
3186 }
3187 else
3188 {
3189 std::shared_ptr<SHAPE_SEGMENT> holeA = pad->GetEffectiveHoleShape();
3190 std::shared_ptr<SHAPE_SEGMENT> holeB = other->GetEffectiveHoleShape();
3191
3192 if( holeA->Collide( holeB->GetSeg(), 0 ) )
3193 aErrorHandler( pad, other, DRCE_DRILLED_HOLES_TOO_CLOSE, pos );
3194 }
3195 }
3196
3197 if( pad->SameLogicalPadAs( other ) || alg::contains( netTiePads, other ) )
3198 continue;
3199
3200 if( !( ( pad->GetLayerSet() & other->GetLayerSet() ) & LSET::AllCuMask() ).any() )
3201 continue;
3202
3203 if( pad->GetBoundingBox().Intersects( other->GetBoundingBox() ) )
3204 {
3205 VECTOR2I pos;
3206 SHAPE* padShape = pad->GetEffectiveShape().get();
3207 SHAPE* otherShape = other->GetEffectiveShape().get();
3208
3209 if( padShape->Collide( otherShape, 0, nullptr, &pos ) )
3210 aErrorHandler( pad, other, DRCE_SHORTING_ITEMS, pos );
3211 }
3212 }
3213 }
3214 }
3215}
3216
3217
3218void FOOTPRINT::CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
3219 const BOARD_ITEM* bItem,
3220 const BOARD_ITEM* cItem,
3221 const VECTOR2I& )>& aErrorHandler )
3222{
3223 // First build a map from pad numbers to allowed-shorting-group indexes. This ends up being
3224 // something like O(3n), but it still beats O(n^2) for large numbers of pads.
3225
3226 std::map<wxString, int> padNumberToGroupIdxMap = MapPadNumbersToNetTieGroups();
3227
3228 // Now collect all the footprint items which are on copper layers
3229
3230 std::vector<BOARD_ITEM*> copperItems;
3231
3232 for( BOARD_ITEM* item : m_drawings )
3233 {
3234 if( item->IsOnCopperLayer() )
3235 copperItems.push_back( item );
3236
3237 item->RunOnDescendants(
3238 [&]( BOARD_ITEM* descendent )
3239 {
3240 if( descendent->IsOnCopperLayer() )
3241 copperItems.push_back( descendent );
3242 } );
3243 }
3244
3245 for( ZONE* zone : m_zones )
3246 {
3247 if( !zone->GetIsRuleArea() && zone->IsOnCopperLayer() )
3248 copperItems.push_back( zone );
3249 }
3250
3251 for( PCB_FIELD* field : m_fields )
3252 {
3253 if( field->IsOnCopperLayer() )
3254 copperItems.push_back( field );
3255 }
3256
3257 for( PCB_LAYER_ID layer : { F_Cu, In1_Cu, B_Cu } )
3258 {
3259 // Next, build a polygon-set for the copper on this layer. We don't really care about
3260 // nets here, we just want to end up with a set of outlines describing the distinct
3261 // copper polygons of the footprint.
3262
3263 SHAPE_POLY_SET copperOutlines;
3264 std::map<int, std::vector<const PAD*>> outlineIdxToPadsMap;
3265
3266 for( BOARD_ITEM* item : copperItems )
3267 {
3268 if( item->IsOnLayer( layer ) )
3269 {
3270 item->TransformShapeToPolygon( copperOutlines, layer, 0, ARC_HIGH_DEF,
3271 ERROR_OUTSIDE );
3272 }
3273 }
3274
3275 copperOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );
3276
3277 // Index each pad to the outline in the set that it is part of.
3278
3279 for( const PAD* pad : m_pads )
3280 {
3281 for( int ii = 0; ii < copperOutlines.OutlineCount(); ++ii )
3282 {
3283 if( pad->GetEffectiveShape( layer )->Collide( &copperOutlines.Outline( ii ), 0 ) )
3284 outlineIdxToPadsMap[ ii ].emplace_back( pad );
3285 }
3286 }
3287
3288 // Finally, ensure that each outline which contains multiple pads has all its pads
3289 // listed in an allowed-shorting group.
3290
3291 for( const auto& [ outlineIdx, pads ] : outlineIdxToPadsMap )
3292 {
3293 if( pads.size() > 1 )
3294 {
3295 const PAD* firstPad = pads[0];
3296 int firstGroupIdx = padNumberToGroupIdxMap[ firstPad->GetNumber() ];
3297
3298 for( size_t ii = 1; ii < pads.size(); ++ii )
3299 {
3300 const PAD* thisPad = pads[ii];
3301 int thisGroupIdx = padNumberToGroupIdxMap[ thisPad->GetNumber() ];
3302
3303 if( thisGroupIdx < 0 || thisGroupIdx != firstGroupIdx )
3304 {
3305 BOARD_ITEM* shortingItem = nullptr;
3306 VECTOR2I pos = ( firstPad->GetPosition() + thisPad->GetPosition() ) / 2;
3307
3308 pos = copperOutlines.Outline( outlineIdx ).NearestPoint( pos );
3309
3310 for( BOARD_ITEM* item : copperItems )
3311 {
3312 if( item->HitTest( pos, 1 ) )
3313 {
3314 shortingItem = item;
3315 break;
3316 }
3317 }
3318
3319 if( shortingItem )
3320 aErrorHandler( shortingItem, firstPad, thisPad, pos );
3321 else
3322 aErrorHandler( firstPad, thisPad, nullptr, pos );
3323 }
3324 }
3325 }
3326 }
3327 }
3328}
3329
3330
3331void FOOTPRINT::CheckNetTiePadGroups( const std::function<void( const wxString& )>& aErrorHandler )
3332{
3333 std::set<wxString> padNumbers;
3334 wxString msg;
3335
3336 auto ret = MapPadNumbersToNetTieGroups();
3337
3338 for( auto [ padNumber, _ ] : ret )
3339 {
3340 const PAD* pad = FindPadByNumber( padNumber );
3341
3342 if( !pad )
3343 {
3344 msg.Printf( _( "(net-tie pad group contains unknown pad number %s)" ), padNumber );
3345 aErrorHandler( msg );
3346 }
3347 else if( !padNumbers.insert( pad->GetNumber() ).second )
3348 {
3349 msg.Printf( _( "(pad %s appears in more than one net-tie pad group)" ), padNumber );
3350 aErrorHandler( msg );
3351 }
3352 }
3353}
3354
3355
3357{
3358 wxASSERT( aImage->Type() == PCB_FOOTPRINT_T );
3359
3360 FOOTPRINT* image = static_cast<FOOTPRINT*>( aImage );
3361
3362 std::swap( *this, *image );
3363
3365 [&]( BOARD_ITEM* child )
3366 {
3367 child->SetParent( this );
3368 } );
3369
3370 image->RunOnChildren(
3371 [&]( BOARD_ITEM* child )
3372 {
3373 child->SetParent( image );
3374 } );
3375}
3376
3377
3379{
3380 for( PAD* pad : Pads() )
3381 {
3382 if( pad->GetAttribute() != PAD_ATTRIB::SMD )
3383 return true;
3384 }
3385
3386 return false;
3387}
3388
3389
3390bool FOOTPRINT::operator==( const BOARD_ITEM& aOther ) const
3391{
3392 if( aOther.Type() != PCB_FOOTPRINT_T )
3393 return false;
3394
3395 const FOOTPRINT& other = static_cast<const FOOTPRINT&>( aOther );
3396
3397 return *this == other;
3398}
3399
3400
3401bool FOOTPRINT::operator==( const FOOTPRINT& aOther ) const
3402{
3403 if( m_pads.size() != aOther.m_pads.size() )
3404 return false;
3405
3406 for( size_t ii = 0; ii < m_pads.size(); ++ii )
3407 {
3408 if( !( *m_pads[ii] == *aOther.m_pads[ii] ) )
3409 return false;
3410 }
3411
3412 if( m_drawings.size() != aOther.m_drawings.size() )
3413 return false;
3414
3415 for( size_t ii = 0; ii < m_drawings.size(); ++ii )
3416 {
3417 if( !( *m_drawings[ii] == *aOther.m_drawings[ii] ) )
3418 return false;
3419 }
3420
3421 if( m_zones.size() != aOther.m_zones.size() )
3422 return false;
3423
3424 for( size_t ii = 0; ii < m_zones.size(); ++ii )
3425 {
3426 if( !( *m_zones[ii] == *aOther.m_zones[ii] ) )
3427 return false;
3428 }
3429
3430 if( m_fields.size() != aOther.m_fields.size() )
3431 return false;
3432
3433 for( size_t ii = 0; ii < m_fields.size(); ++ii )
3434 {
3435 if( !( *m_fields[ii] == *aOther.m_fields[ii] ) )
3436 return false;
3437 }
3438
3439 return true;
3440}
3441
3442
3443double FOOTPRINT::Similarity( const BOARD_ITEM& aOther ) const
3444{
3445 if( aOther.Type() != PCB_FOOTPRINT_T )
3446 return 0.0;
3447
3448 const FOOTPRINT& other = static_cast<const FOOTPRINT&>( aOther );
3449
3450 double similarity = 1.0;
3451
3452 for( size_t ii = 0; ii < m_pads.size(); ++ii )
3453 {
3454 const PAD* pad = m_pads[ii];
3455 const PAD* otherPad = other.FindPadByNumber( pad->GetNumber() );
3456
3457 if( !otherPad )
3458 continue;
3459
3460 similarity *= pad->Similarity( *otherPad );
3461 }
3462
3463 return similarity;
3464}
3465
3466
3467bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* itemA, const BOARD_ITEM* itemB ) const
3468{
3469 if( itemA->Type() != itemB->Type() )
3470 return itemA->Type() < itemB->Type();
3471
3472 if( itemA->GetLayer() != itemB->GetLayer() )
3473 return itemA->GetLayer() < itemB->GetLayer();
3474
3475 if( itemA->Type() == PCB_SHAPE_T )
3476 {
3477 const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( itemA );
3478 const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( itemB );
3479
3480 if( dwgA->GetShape() != dwgB->GetShape() )
3481 return dwgA->GetShape() < dwgB->GetShape();
3482
3483 // GetStart() and GetEnd() have no meaning with polygons.
3484 // We cannot use them for sorting polygons
3485 if( dwgA->GetShape() != SHAPE_T::POLY )
3486 {
3487 if( dwgA->GetStart().x != dwgB->GetStart().x )
3488 return dwgA->GetStart().x < dwgB->GetStart().x;
3489 if( dwgA->GetStart().y != dwgB->GetStart().y )
3490 return dwgA->GetStart().y < dwgB->GetStart().y;
3491
3492 if( dwgA->GetEnd().x != dwgB->GetEnd().x )
3493 return dwgA->GetEnd().x < dwgB->GetEnd().x;
3494 if( dwgA->GetEnd().y != dwgB->GetEnd().y )
3495 return dwgA->GetEnd().y < dwgB->GetEnd().y;
3496 }
3497
3498 if( dwgA->GetShape() == SHAPE_T::ARC )
3499 {
3500 if( dwgA->GetCenter().x != dwgB->GetCenter().x )
3501 return dwgA->GetCenter().x < dwgB->GetCenter().x;
3502 if( dwgA->GetCenter().y != dwgB->GetCenter().y )
3503 return dwgA->GetCenter().y < dwgB->GetCenter().y;
3504 }
3505 else if( dwgA->GetShape() == SHAPE_T::BEZIER )
3506 {
3507 if( dwgA->GetBezierC1().x != dwgB->GetBezierC1().x )
3508 return dwgA->GetBezierC1().x < dwgB->GetBezierC1().x;
3509 if( dwgA->GetBezierC1().y != dwgB->GetBezierC1().y )
3510 return dwgA->GetBezierC1().y < dwgB->GetBezierC1().y;
3511
3512 if( dwgA->GetBezierC2().x != dwgB->GetBezierC2().x )
3513 return dwgA->GetBezierC2().x < dwgB->GetBezierC2().x;
3514 if( dwgA->GetBezierC2().y != dwgB->GetBezierC2().y )
3515 return dwgA->GetBezierC2().y < dwgB->GetBezierC2().y;
3516 }
3517 else if( dwgA->GetShape() == SHAPE_T::POLY )
3518 {
3519 if( dwgA->GetPolyShape().TotalVertices() != dwgB->GetPolyShape().TotalVertices() )
3520 return dwgA->GetPolyShape().TotalVertices() < dwgB->GetPolyShape().TotalVertices();
3521
3522 for( int ii = 0; ii < dwgA->GetPolyShape().TotalVertices(); ++ii )
3523 {
3524 if( dwgA->GetPolyShape().CVertex( ii ).x != dwgB->GetPolyShape().CVertex( ii ).x )
3525 return dwgA->GetPolyShape().CVertex( ii ).x
3526 < dwgB->GetPolyShape().CVertex( ii ).x;
3527 if( dwgA->GetPolyShape().CVertex( ii ).y != dwgB->GetPolyShape().CVertex( ii ).y )
3528 return dwgA->GetPolyShape().CVertex( ii ).y
3529 < dwgB->GetPolyShape().CVertex( ii ).y;
3530 }
3531 }
3532
3533 if( dwgA->GetWidth() != dwgB->GetWidth() )
3534 return dwgA->GetWidth() < dwgB->GetWidth();
3535 }
3536
3537 if( itemA->m_Uuid != itemB->m_Uuid )
3538 return itemA->m_Uuid < itemB->m_Uuid;
3539
3540 return itemA < itemB;
3541}
3542
3543
3544bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) const
3545{
3546 if( aFirst->GetNumber() != aSecond->GetNumber() )
3547 return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
3548
3549 if( aFirst->GetFPRelativePosition().x != aSecond->GetFPRelativePosition().x )
3550 return aFirst->GetFPRelativePosition().x < aSecond->GetFPRelativePosition().x;
3551 if( aFirst->GetFPRelativePosition().y != aSecond->GetFPRelativePosition().y )
3552 return aFirst->GetFPRelativePosition().y < aSecond->GetFPRelativePosition().y;
3553
3554 if( aFirst->GetSize().x != aSecond->GetSize().x )
3555 return aFirst->GetSize().x < aSecond->GetSize().x;
3556 if( aFirst->GetSize().y != aSecond->GetSize().y )
3557 return aFirst->GetSize().y < aSecond->GetSize().y;
3558
3559 if( aFirst->GetShape() != aSecond->GetShape() )
3560 return aFirst->GetShape() < aSecond->GetShape();
3561
3562 if( aFirst->GetLayerSet().Seq() != aSecond->GetLayerSet().Seq() )
3563 return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
3564
3565 if( aFirst->m_Uuid != aSecond->m_Uuid )
3566 return aFirst->m_Uuid < aSecond->m_Uuid;
3567
3568 return aFirst < aSecond;
3569}
3570
3571
3572bool FOOTPRINT::cmp_padstack::operator()( const PAD* aFirst, const PAD* aSecond ) const
3573{
3574 if( aFirst->GetSize().x != aSecond->GetSize().x )
3575 return aFirst->GetSize().x < aSecond->GetSize().x;
3576 if( aFirst->GetSize().y != aSecond->GetSize().y )
3577 return aFirst->GetSize().y < aSecond->GetSize().y;
3578
3579 if( aFirst->GetShape() != aSecond->GetShape() )
3580 return aFirst->GetShape() < aSecond->GetShape();
3581
3582 if( aFirst->GetLayerSet().Seq() != aSecond->GetLayerSet().Seq() )
3583 return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
3584
3585 if( aFirst->GetDrillSizeX() != aSecond->GetDrillSizeX() )
3586 return aFirst->GetDrillSizeX() < aSecond->GetDrillSizeX();
3587
3588 if( aFirst->GetDrillSizeY() != aSecond->GetDrillSizeY() )
3589 return aFirst->GetDrillSizeY() < aSecond->GetDrillSizeY();
3590
3591 if( aFirst->GetDrillShape() != aSecond->GetDrillShape() )
3592 return aFirst->GetDrillShape() < aSecond->GetDrillShape();
3593
3594 if( aFirst->GetAttribute() != aSecond->GetAttribute() )
3595 return aFirst->GetAttribute() < aSecond->GetAttribute();
3596
3597 if( aFirst->GetOrientation() != aSecond->GetOrientation() )
3598 return aFirst->GetOrientation() < aSecond->GetOrientation();
3599
3600 if( aFirst->GetSolderMaskExpansion() != aSecond->GetSolderMaskExpansion() )
3601 return aFirst->GetSolderMaskExpansion() < aSecond->GetSolderMaskExpansion();
3602
3603 if( aFirst->GetSolderPasteMargin() != aSecond->GetSolderPasteMargin() )
3604 return aFirst->GetSolderPasteMargin() < aSecond->GetSolderPasteMargin();
3605
3606 if( aFirst->GetLocalSolderMaskMargin() != aSecond->GetLocalSolderMaskMargin() )
3607 return aFirst->GetLocalSolderMaskMargin() < aSecond->GetLocalSolderMaskMargin();
3608
3609 std::shared_ptr<SHAPE_POLY_SET> firstShape = aFirst->GetEffectivePolygon( ERROR_INSIDE );
3610 std::shared_ptr<SHAPE_POLY_SET> secondShape = aSecond->GetEffectivePolygon( ERROR_INSIDE );
3611
3612 if( firstShape->VertexCount() != secondShape->VertexCount() )
3613 return firstShape->VertexCount() < secondShape->VertexCount();
3614
3615 for( int ii = 0; ii < firstShape->VertexCount(); ++ii )
3616 {
3617 if( firstShape->CVertex( ii ).x != secondShape->CVertex( ii ).x )
3618 return firstShape->CVertex( ii ).x < secondShape->CVertex( ii ).x;
3619 if( firstShape->CVertex( ii ).y != secondShape->CVertex( ii ).y )
3620 return firstShape->CVertex( ii ).y < secondShape->CVertex( ii ).y;
3621 }
3622
3623 return false;
3624}
3625
3626
3627bool FOOTPRINT::cmp_zones::operator()( const ZONE* aFirst, const ZONE* aSecond ) const
3628{
3629 if( aFirst->GetAssignedPriority() != aSecond->GetAssignedPriority() )
3630 return aFirst->GetAssignedPriority() < aSecond->GetAssignedPriority();
3631
3632 if( aFirst->GetLayerSet().Seq() != aSecond->GetLayerSet().Seq() )
3633 return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
3634
3635 if( aFirst->Outline()->TotalVertices() != aSecond->Outline()->TotalVertices() )
3636 return aFirst->Outline()->TotalVertices() < aSecond->Outline()->TotalVertices();
3637
3638 for( int ii = 0; ii < aFirst->Outline()->TotalVertices(); ++ii )
3639 {
3640 if( aFirst->Outline()->CVertex( ii ).x != aSecond->Outline()->CVertex( ii ).x )
3641 return aFirst->Outline()->CVertex( ii ).x < aSecond->Outline()->CVertex( ii ).x;
3642 if( aFirst->Outline()->CVertex( ii ).y != aSecond->Outline()->CVertex( ii ).y )
3643 return aFirst->Outline()->CVertex( ii ).y < aSecond->Outline()->CVertex( ii ).y;
3644 }
3645
3646 if( aFirst->m_Uuid != aSecond->m_Uuid )
3647 return aFirst->m_Uuid < aSecond->m_Uuid;
3648
3649 return aFirst < aSecond;
3650}
3651
3652
3654 int aClearance, int aMaxError, ERROR_LOC aErrorLoc,
3655 bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads,
3656 bool aSkipNonPlatedPads ) const
3657{
3658 for( const PAD* pad : m_pads )
3659 {
3660 if( !pad->FlashLayer( aLayer ) )
3661 continue;
3662
3663 VECTOR2I clearance( aClearance, aClearance );
3664
3665 switch( aLayer )
3666 {
3667 case F_Cu:
3668 if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
3669 continue;
3670
3671 if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
3672 continue;
3673
3674 break;
3675
3676 case B_Cu:
3677 if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
3678 continue;
3679
3680 if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
3681 continue;
3682
3683 break;
3684
3685 case F_Mask:
3686 case B_Mask:
3687 clearance.x += pad->GetSolderMaskExpansion();
3688 clearance.y += pad->GetSolderMaskExpansion();
3689 break;
3690
3691 case F_Paste:
3692 case B_Paste:
3693 clearance += pad->GetSolderPasteMargin();
3694 break;
3695
3696 default:
3697 break;
3698 }
3699
3700 // Our standard TransformShapeToPolygon() routines can't handle differing x:y clearance
3701 // values (which get generated when a relative paste margin is used with an oblong pad).
3702 // So we apply this huge hack and fake a larger pad to run the transform on.
3703 // Of course being a hack it falls down when dealing with custom shape pads (where the
3704 // size is only the size of the anchor), so for those we punt and just use clearance.x.
3705
3706 if( ( clearance.x < 0 || clearance.x != clearance.y )
3707 && pad->GetShape() != PAD_SHAPE::CUSTOM )
3708 {
3709 VECTOR2I dummySize = pad->GetSize() + clearance + clearance;
3710
3711 if( dummySize.x <= 0 || dummySize.y <= 0 )
3712 continue;
3713
3714 PAD dummy( *pad );
3715 dummy.SetSize( dummySize );
3716 dummy.TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
3717 }
3718 else
3719 {
3720 pad->TransformShapeToPolygon( aBuffer, aLayer, clearance.x, aMaxError, aErrorLoc );
3721 }
3722 }
3723}
3724
3725
3727 int aClearance, int aError, ERROR_LOC aErrorLoc,
3728 bool aIncludeText, bool aIncludeShapes,
3729 bool aIncludePrivateItems ) const
3730{
3731 std::vector<const PCB_TEXT*> texts; // List of PCB_TEXTs to convert
3732
3733 for( BOARD_ITEM* item : GraphicalItems() )
3734 {
3735 if( GetPrivateLayers().test( item->GetLayer() ) && !aIncludePrivateItems )
3736 continue;
3737
3738 if( item->Type() == PCB_TEXT_T && aIncludeText )
3739 {
3740 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
3741
3742 if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer && text->IsVisible() )
3743 texts.push_back( text );
3744 }
3745
3746 if( item->Type() == PCB_TEXTBOX_T && aIncludeText )
3747 {
3748 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
3749
3750 if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer && textbox->IsVisible() )
3751 {
3752 // border
3753 if( textbox->IsBorderEnabled() )
3754 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aError, aErrorLoc );
3755 // text
3756 textbox->TransformTextToPolySet( aBuffer, 0, aError, aErrorLoc );
3757 }
3758 }
3759
3760 if( item->Type() == PCB_SHAPE_T && aIncludeShapes )
3761 {
3762 const PCB_SHAPE* outline = static_cast<PCB_SHAPE*>( item );
3763
3764 if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer )
3765 outline->TransformShapeToPolygon( aBuffer, aLayer, 0, aError, aErrorLoc );
3766 }
3767 }
3768
3769 if( aIncludeText )
3770 {
3771 for( const PCB_FIELD* field : m_fields )
3772 {
3773 if( field->GetLayer() == aLayer && field->IsVisible() )
3774 texts.push_back( field );
3775 }
3776 }
3777
3778 for( const PCB_TEXT* text : texts )
3779 text->TransformTextToPolySet( aBuffer, aClearance, aError, aErrorLoc );
3780}
3781
3782
3783static struct FOOTPRINT_DESC
3784{
3786 {
3788
3789 if( zcMap.Choices().GetCount() == 0 )
3790 {
3791 zcMap.Undefined( ZONE_CONNECTION::INHERITED );
3792 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
3793 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
3794 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
3795 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
3796 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
3797 }
3798
3800
3801 if( layerEnum.Choices().GetCount() == 0 )
3802 {
3803 layerEnum.Undefined( UNDEFINED_LAYER );
3804
3805 for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
3806 layerEnum.Map( *seq, LSET::Name( *seq ) );
3807 }
3808
3809 wxPGChoices fpLayers; // footprints might be placed only on F.Cu & B.Cu
3810 fpLayers.Add( LSET::Name( F_Cu ), F_Cu );
3811 fpLayers.Add( LSET::Name( B_Cu ), B_Cu );
3812
3819
3820 auto layer = new PROPERTY_ENUM<FOOTPRINT, PCB_LAYER_ID>( _HKI( "Layer" ),
3822 layer->SetChoices( fpLayers );
3823 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
3824
3825 propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Orientation" ),
3827 PROPERTY_DISPLAY::PT_DEGREE ) );
3828
3829 const wxString groupFields = _HKI( "Fields" );
3830
3831 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Reference" ),
3833 groupFields );
3834 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Value" ),
3836 groupFields );
3837
3838 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library Link" ),
3840 groupFields );
3841 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library Description" ),
3843 groupFields );
3844 propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Keywords" ),
3846 groupFields );
3847
3848 const wxString groupAttributes = _HKI( "Attributes" );
3849
3850 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Not in Schematic" ),
3851 &FOOTPRINT::SetBoardOnly, &FOOTPRINT::IsBoardOnly ), groupAttributes );
3852 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude From Position Files" ),
3854 groupAttributes );
3855 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Exclude From Bill of Materials" ),
3857 groupAttributes );
3858 propMgr.AddProperty( new PROPERTY<FOOTPRINT, bool>( _HKI( "Do not Populate" ),
3860 groupAttributes );
3861
3862 const wxString groupOverrides = _HKI( "Overrides" );
3863
3865 _HKI( "Exempt From Courtyard Requirement" ),
3867 groupOverrides );
3868 propMgr.AddProperty( new PROPERTY<FOOTPRINT, std::optional<int>>(
3869 _HKI( "Clearance Override" ),
3871 PROPERTY_DISPLAY::PT_SIZE ),
3872 groupOverrides );
3873 propMgr.AddProperty( new PROPERTY<FOOTPRINT, std::optional<int>>(
3874 _HKI( "Solderpaste Margin Override" ),
3876 PROPERTY_DISPLAY::PT_SIZE ),
3877 groupOverrides );
3878 propMgr.AddProperty( new PROPERTY<FOOTPRINT, std::optional<double>>(
3879 _HKI( "Solderpaste Margin Ratio Override" ),
3882 PROPERTY_DISPLAY::PT_RATIO ),
3883 groupOverrides );
3885 _HKI( "Zone Connection Style" ),
3887 groupOverrides );
3888 }
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:231
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:91
PCB_LAYER_ID m_layer
Definition: board_item.h:398
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:265
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:209
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:260
bool IsType(FRAME_T aType) const
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h: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:206
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:279
bool IsFilled() const
Definition: eda_shape.h:91
SHAPE_T GetShape() const
Definition: eda_shape.h:125
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:130
const VECTOR2I & GetBezierC1() const
Definition: eda_shape.h:203
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 SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2330
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:236
LIB_ID m_fpid
Definition: footprint.h:1004
wxString GetLibDescription() const
Definition: footprint.h:244
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: footprint.h:275
KIID_PATH m_path
Definition: footprint.h:1042
bool IsBoardOnly() const
Definition: footprint.h:719
BOX2I m_cachedTextExcludedBBox
Definition: footprint.h:1023
bool IsDNP() const
Definition: footprint.h:755
void SetLocked(bool isLocked) override
Set the #MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition: footprint.h:408
std::vector< PAD * > GetNetTiePads(PAD *aPad) const
Definition: footprint.cpp:3001
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:214
bool HasFieldByName(const wxString &aFieldName) const
Definition: footprint.cpp:527
ZONES & Zones()
Definition: footprint.h:199
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:1057
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:1033
BOX2I m_cachedBoundingBox
Definition: footprint.h:1019
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
Definition: footprint.cpp:2646
bool IsExcludedFromBOM() const
Definition: footprint.h:737
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2402
std::optional< double > m_solderPasteMarginRatio
Definition: footprint.h:1037
PCB_FIELD * GetFieldByName(const wxString &aFieldName)
Return a field in this symbol.
Definition: footprint.cpp:538
void SetDNP(bool aDNP=true)
Definition: footprint.h:756
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:2196
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
Definition: footprint.cpp:1848
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: footprint.h:272
const BOX2I GetLayerBoundingBox(LSET aLayers) const
Return the bounding box of the footprint on a given set of layers.
Definition: footprint.cpp:1395
std::optional< int > m_clearance
Definition: footprint.h:1034
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:3218
void CheckPads(UNITS_PROVIDER *aUnitsProvider, const std::function< void(const PAD *, int, const wxString &)> &aErrorHandler)
Run non-board-specific DRC checks on footprint's pads.
Definition: footprint.cpp:3048
void SetExcludedFromBOM(bool aExclude=true)
Definition: footprint.h:738
int m_fpStatus
Definition: footprint.h:1006
PCB_FIELDS GetFields()
Return a vector of fields from the symbol.
Definition: footprint.h:685
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: footprint.cpp:2140
SHAPE_POLY_SET m_cachedHull
Definition: footprint.h:1025
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:1867
void SetAllowMissingCourtyard(bool aAllow=true)
Definition: footprint.h:747
void SetKeywords(const wxString &aKeywords)
Definition: footprint.h:248
int m_attributes
Definition: footprint.h:1005
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:1602
std::vector< FP_3DMODEL > m_3D_Drawings
Definition: footprint.h:1051
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:2729
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:2442
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:2793
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const override
Invoke a function on all descendants.
Definition: footprint.cpp:2025
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: footprint.cpp:2013
void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction, int aDepth=0) const override
Invoke a function on all descendants.
Definition: footprint.cpp:2051
std::optional< int > GetLocalSolderPasteMargin() const
Definition: footprint.h:268
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:3653
wxArrayString * m_initial_comments
Definition: footprint.h:1052
EDA_ITEM * Clone() const override
Invoke a function on all children.
Definition: footprint.cpp:2019
BOX2I m_cachedVisibleBBox
Definition: footprint.h:1021
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:1022
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:625
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: footprint.cpp:2234
std::optional< int > m_solderPasteMargin
Definition: footprint.h:1036
std::mutex m_courtyard_cache_mutex
Definition: footprint.h:1059
void SetExcludedFromPosFiles(bool aExclude=true)
Definition: footprint.h:729
void SetOrientationDegrees(double aOrientation)
Definition: footprint.h:226
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:2946
std::optional< int > GetLocalClearance() const
Definition: footprint.h:262
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:3443
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:2357
FOOTPRINT & operator=(const FOOTPRINT &aOther)
Definition: footprint.cpp:767
int m_arflag
Definition: footprint.h:1047
double GetOrientationDegrees() const
Definition: footprint.h:230
BOARD_ITEM * Duplicate() const override
Create a copy of this BOARD_ITEM.
Definition: footprint.cpp:2429
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:1915
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:277
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: footprint.h:274
FOOTPRINT(BOARD *parent)
Definition: footprint.cpp:64
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:223
LSET GetPrivateLayers() const
Definition: footprint.h:128
wxString GetFPIDAsString() const
Definition: footprint.h:241
wxString GetValueAsString() const
Definition: footprint.h:619
bool AllowMissingCourtyard() const
Definition: footprint.h:746
PADS & Pads()
Definition: footprint.h:193
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:1440
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:3726
wxString GetTypeName() const
Get the type of footprint.
Definition: footprint.cpp:1186
DRAWINGS m_drawings
Definition: footprint.h:997
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:1056
int m_textExcludedBBoxCacheTimeStamp
Definition: footprint.h:1024
const std::vector< wxString > & GetNetTiePadGroups() const
Definition: footprint.h:326
const LIB_ID & GetFPID() const
Definition: footprint.h:235
void SetReference(const wxString &aReference)
Definition: footprint.h:595
bool IsLocked() const override
Definition: footprint.h:398
bool IsExcludedFromPosFiles() const
Definition: footprint.h:728
void SetLayerAndFlip(PCB_LAYER_ID aLayer)
Used as Layer property setter – performs a flip if necessary to set the footprint layer.
Definition: footprint.cpp:2262
ZONES m_zones
Definition: footprint.h:999
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:1026
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
Definition: footprint.cpp:1898
void AddNetTiePadGroup(const wxString &aGroup)
Definition: footprint.h:333
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: footprint.cpp:2181
LSET m_privateLayers
Definition: footprint.h:1049
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:2224
wxString m_libDescription
Definition: footprint.h:1040
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:1664
VECTOR2I m_pos
Definition: footprint.h:1003
std::vector< wxString > m_netTiePadGroups
Definition: footprint.h:1030
PAD * GetPad(const VECTOR2I &aPosition, LSET aLayerMask=LSET::AllLayersMask())
Get a pad at aPosition on aLayerMask in the footprint.
Definition: footprint.cpp:1816
void Add3DModel(FP_3DMODEL *a3DModel)
Add a3DModel definition to the end of the 3D model list.
Definition: footprint.cpp:1904
void SetValue(const wxString &aValue)
Definition: footprint.h:616
GROUPS m_groups
Definition: footprint.h:1000
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:1522
PCB_FIELD & Reference()
Definition: footprint.h:626
wxString GetReferenceAsString() const
Definition: footprint.h:598
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:1035
SHAPE_POLY_SET m_courtyard_cache_front
Definition: footprint.h:1055
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:1832
void AutoPositionFields()
Position Reference and Value fields at the top and bottom of footprint's bounding box.
Definition: footprint.cpp:2591
wxString m_keywords
Definition: footprint.h:1041
void ClearAllNets()
Clear (i.e.
Definition: footprint.cpp:959
bool HasThroughHolePads() const
Definition: footprint.cpp:3378
void BuildCourtyardCaches(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:2846
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: footprint.cpp:1633
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:1002
bool HitTestAccurate(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if a point is inside the bounding polygon of the footprint.
Definition: footprint.cpp:1739
wxString GetClass() const override
Return the class name.
Definition: footprint.h:861
void IncrementReference(int aDelta)
Bump the current reference by aDelta.
Definition: footprint.cpp:2619
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: footprint.h:271
KIID m_link
Definition: footprint.h:1048
void RemoveField(const wxString &aFieldName)
Remove a user field from the footprint.
Definition: footprint.cpp:589
GROUPS & Groups()
Definition: footprint.h:202
MD5_HASH m_courtyard_cache_back_hash
Definition: footprint.h:1058
bool IsConflicting() const
Definition: footprint.cpp:871
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:207
PCB_FIELDS & Fields()
Definition: footprint.h:190
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:2207
void SetLibDescription(const wxString &aDesc)
Definition: footprint.h:245
bool TextOnly() const
Definition: footprint.cpp:1223
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:2271
void CheckShortingPads(const std::function< void(const PAD *, const PAD *, int aErrorCode, const VECTOR2I &)> &aErrorHandler)
Check for overlapping, different-numbered, non-net-tie pads.
Definition: footprint.cpp:3153
double GetArea(int aPadding=0) const
Definition: footprint.cpp:1123
const wxString & GetReference() const
Definition: footprint.h:589
void CheckNetTiePadGroups(const std::function< void(const wxString &)> &aErrorHandler)
Sanity check net-tie pad groups.
Definition: footprint.cpp:3331
void SetBoardOnly(bool aIsBoardOnly=true)
Definition: footprint.h:720
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: footprint.h:266
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:1046
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2829
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:2088
int m_fileFormatVersionAtLoad
Definition: footprint.h:1007
void SetLocalClearance(std::optional< int > aClearance)
Definition: footprint.h:263
std::optional< int > GetLocalSolderMaskMargin() const
Definition: footprint.h:265
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: footprint.h:269
wxString GetKeywords() const
Definition: footprint.h:247
bool operator==(const BOARD_ITEM &aOther) const override
Definition: footprint.cpp:3390
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:3023
PADS m_pads
Definition: footprint.h:998
virtual void swapData(BOARD_ITEM *aImage) override
Definition: footprint.cpp:3356
wxString GetNextPadNumber(const wxString &aLastPadName) const
Return the next available pad number in the footprint.
Definition: footprint.cpp:2571
int m_boundingBoxCacheTimeStamp
Definition: footprint.h:1020
VECTOR2I GetPosition() const override
Definition: footprint.h:211
DRAWINGS & GraphicalItems()
Definition: footprint.h:196
PCB_FIELDS m_fields
Definition: footprint.h:996
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:1732
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
Definition: footprint.cpp:2002
PAD * FindPadByNumber(const wxString &aPadNumber, PAD *aSearchAfterMe=nullptr) const
Return a PAD with a matching number.
Definition: footprint.cpp:1796
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1238
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:522
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:576
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:385
Definition: pad.h:53
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:391
int GetSolderMaskExpansion() const
Definition: pad.cpp:995
int GetDrillSizeY() const
Definition: pad.h:270
PAD_ATTRIB GetAttribute() const
Definition: pad.h:394
const wxString & GetNumber() const
Definition: pad.h:133
VECTOR2I GetPosition() const override
Definition: pad.h:200
int GetDrillSizeX() const
Definition: pad.h:268
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:452
PAD_SHAPE GetShape() const
Definition: pad.h:192
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:358
PAD_DRILL_SHAPE GetDrillShape() const
Definition: pad.h:376
VECTOR2I GetSolderPasteMargin() const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition: pad.cpp:1032
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pad.h:412
const VECTOR2I & GetSize() const
Definition: pad.h:255
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:185
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_text.cpp:392
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.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
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_DRILLED_HOLES_TOO_CLOSE
Definition: drc_item.h:51
@ DRCE_SHORTING_ITEMS
Definition: drc_item.h:40
@ DRCE_DRILLED_HOLES_COLOCATED
Definition: drc_item.h:52
@ DRCE_PAD_TH_WITH_NO_HOLE
Definition: drc_item.h:80
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:405
INSPECT_RESULT
Definition: eda_item.h:43
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h: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:2630
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:393
#define FP_PADS_are_LOCKED
Definition: footprint.h:395
@ 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:979
@ 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:390
Class to handle a set of BOARD_ITEMs.
#define TYPE_HASH(x)
Definition: property.h:71
#define NO_SETTER(owner, type)
Definition: property.h:774
#define REGISTER_TYPE(x)
Definition: property_mgr.h:371
Collection of utility functions for component reference designators (refdes)
std::vector< FAB_LAYER_COLOR > dummy
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
int GetTrailingInt(const wxString &aStr)
Gets the trailing int, if any, from a string.
wxString UnescapeString(const wxString &aSource)
constexpr double IUTomm(int iu) const
Definition: base_units.h:86
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
bool operator()(const BOARD_ITEM *itemA, const BOARD_ITEM *itemB) const
Definition: footprint.cpp:3467
bool operator()(const PAD *aFirst, const PAD *aSecond) const
Definition: footprint.cpp:3544
bool operator()(const PAD *aFirst, const PAD *aSecond) const
Definition: footprint.cpp:3572
bool operator()(const ZONE *aFirst, const ZONE *aSecond) const
Definition: footprint.cpp:3627
MANDATORY_FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ DATASHEET_FIELD
name of datasheet
@ FOOTPRINT_FIELD
Field Name Module PCB, i.e. "16DIP300".
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ MANDATORY_FIELDS
The first 5 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
@ DESCRIPTION_FIELD
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
constexpr int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_CENTER
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition: typeinfo.h:248
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition: typeinfo.h:91
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:99
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition: typeinfo.h:95
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition: typeinfo.h:94
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:638
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47