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