KiCad PCB EDA Suite
Loading...
Searching...
No Matches
board.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
7 *
8 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, you may find one here:
22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * or you may search the http://www.gnu.org website for the version 2 license,
24 * or you may write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
28#include <iterator>
29#include <algorithm>
30
31#include <wx/log.h>
32
33#include <drc/drc_engine.h>
34#include <drc/drc_rtree.h>
36#include <board_commit.h>
37#include <board.h>
38#include <collectors.h>
40#include <core/arraydim.h>
41#include <core/kicad_algo.h>
44#include <footprint.h>
46#include <font/outline_font.h>
48#include <lset.h>
49#include <pad.h>
50#include <pcb_base_frame.h>
51#include <pcb_track.h>
52#include <pcb_marker.h>
53#include <pcb_group.h>
54#include <pcb_generator.h>
55#include <pcb_point.h>
56#include <pcb_target.h>
57#include <pcb_shape.h>
58#include <pcb_barcode.h>
59#include <pcb_text.h>
60#include <pcb_textbox.h>
61#include <pcb_table.h>
62#include <pcb_dimension.h>
63#include <pgm_base.h>
64#include <pcbnew_settings.h>
65#include <progress_reporter.h>
66#include <project.h>
72#include <reporter.h>
73#include <tool/tool_manager.h>
75#include <string_utils.h>
76#include <thread_pool.h>
77#include <zone.h>
78#include <mutex>
79#include <pcb_board_outline.h>
80#include <local_history.h>
81#include <pcb_io/pcb_io_mgr.h>
83#include <advanced_config.h>
84#include <richio.h>
85#include <trace_helpers.h>
86
87// This is an odd place for this, but CvPcb won't link if it's in board_item.cpp like I first
88// tried it.
90
91
93 BOARD_ITEM_CONTAINER( nullptr, PCB_T ),
98 m_timeStamp( 1 ),
100 m_project( nullptr ),
102 m_designSettings( new BOARD_DESIGN_SETTINGS( nullptr, "board.design_settings" ) ),
103 m_NetInfo( this ),
104 m_embedFonts( false ),
105 m_embeddedFilesDelegate( nullptr ),
106 m_componentClassManager( std::make_unique<COMPONENT_CLASS_MANAGER>( this ) ),
107 m_lengthDelayCalc( std::make_unique<LENGTH_DELAY_CALCULATION>( this ) )
108{
109 // A too small value do not allow connecting 2 shapes (i.e. segments) not exactly connected
110 // A too large value do not allow safely connecting 2 shapes like very short segments.
112
115 m_boardOutline = new PCB_BOARD_OUTLINE( this );
116
117 // we have not loaded a board yet, assume latest until then.
118 m_fileFormatVersionAtLoad = LEGACY_BOARD_FILE_VERSION;
119
120 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
121 {
122 m_layers[layer].m_name = GetStandardLayerName( ToLAYER_ID( layer ) );
123
124 if( IsCopperLayer( layer ) )
125 m_layers[layer].m_type = LT_SIGNAL;
126 else if( layer >= User_1 && layer & 1 )
127 m_layers[layer].m_type = LT_AUX;
128 else
129 m_layers[layer].m_type = LT_UNDEFINED;
130 }
131
133
134 // Creates a zone to show sloder mask bridges created by a min web value
135 // it it just to show them
136 m_SolderMaskBridges = new ZONE( this );
138 m_SolderMaskBridges->SetLayerSet( LSET().set( F_Mask ).set( B_Mask ) );
139 int infinity = ( std::numeric_limits<int>::max() / 2 ) - pcbIUScale.mmToIU( 1 );
140 m_SolderMaskBridges->Outline()->NewOutline();
141 m_SolderMaskBridges->Outline()->Append( VECTOR2I( -infinity, -infinity ) );
142 m_SolderMaskBridges->Outline()->Append( VECTOR2I( -infinity, +infinity ) );
143 m_SolderMaskBridges->Outline()->Append( VECTOR2I( +infinity, +infinity ) );
144 m_SolderMaskBridges->Outline()->Append( VECTOR2I( +infinity, -infinity ) );
145 m_SolderMaskBridges->SetMinThickness( 0 );
146
148
149 // Initialize default netclass.
150 bds.m_NetSettings->SetDefaultNetclass( std::make_shared<NETCLASS>( NETCLASS::Default ) );
151 bds.m_NetSettings->GetDefaultNetclass()->SetDescription( _( "This is the default net class." ) );
152
153 bds.UseCustomTrackViaSize( false );
154
155 // Initialize ratsnest
156 m_connectivity.reset( new CONNECTIVITY_DATA() );
157
158 // Set flag bits on these that will only be cleared if these are loaded from a legacy file
159 m_LegacyVisibleLayers.reset().set( Rescue );
161
162 // Install the text-variable dependency adapter as a listener so subsequent
163 // BOARD_COMMIT pushes and undo/redo events reach the tracker. No items
164 // exist yet — RebuildIndex is invoked after load by callers that bypass
165 // per-item notifications.
166 m_textVarAdapter = std::make_unique<BOARD_TEXT_VAR_ADAPTER>( *this );
168}
169
170
172{
173 m_itemByIdCache.clear();
174 m_cachedIdByItem.clear();
175
176 // Clean up the owned elements
178
179 delete m_SolderMaskBridges;
180
181 BOARD_ITEM_SET ownedItems = GetItemSet();
182
183 m_zones.clear();
184 m_footprints.clear();
185 m_tracks.clear();
186 m_drawings.clear();
187 m_groups.clear();
188 m_points.clear();
189
190 delete m_boardOutline;
191 m_generators.clear();
192
193 // Delete the owned items after clearing the containers, because some item dtors
194 // cause call chains that query the containers
195 for( BOARD_ITEM* item : ownedItems )
196 delete item;
197
198 // Remove any listeners
200}
201
202
204{
205 if( !GetConnectivity()->Build( this, aReporter ) )
206 return false;
207
209 return true;
210}
211
212
213void BOARD::SetProject( PROJECT* aProject, bool aReferenceOnly )
214{
215 if( m_project == aProject )
216 return;
217
218 if( m_project )
219 ClearProject();
220
221 m_project = aProject;
222
223 if( aProject && !aReferenceOnly )
224 {
225 PROJECT_FILE& project = aProject->GetProjectFile();
226
227 // Link the design settings object to the project file
228 project.m_BoardSettings = &GetDesignSettings();
229
230 // Set parent, which also will load the values from JSON stored in the project if we don't
231 // have legacy design settings loaded already
232 project.m_BoardSettings->SetParent( &project, !m_LegacyDesignSettingsLoaded );
233
234 // The DesignSettings' netclasses pointer will be pointing to its internal netclasses
235 // list at this point. If we loaded anything into it from a legacy board file then we
236 // want to transfer it over to the project netclasses list.
238 {
239 std::shared_ptr<NET_SETTINGS> legacySettings = GetDesignSettings().m_NetSettings;
240 std::shared_ptr<NET_SETTINGS>& projectSettings = project.NetSettings();
241
242 projectSettings->SetDefaultNetclass( legacySettings->GetDefaultNetclass() );
243 projectSettings->SetNetclasses( legacySettings->GetNetclasses() );
244 projectSettings->SetNetclassPatternAssignments(
245 std::move( legacySettings->GetNetclassPatternAssignments() ) );
246 }
247
248 // Now update the DesignSettings' netclass pointer to point into the project.
249 GetDesignSettings().m_NetSettings = project.NetSettings();
250 }
251}
252
253
255{
256 if( !m_project )
257 return;
258
259 PROJECT_FILE& project = m_project->GetProjectFile();
260
261 // Owned by the BOARD
262 if( project.m_BoardSettings )
263 {
264 project.ReleaseNestedSettings( project.m_BoardSettings );
265 project.m_BoardSettings = nullptr;
266 }
267
269 GetDesignSettings().SetParent( nullptr );
270 m_project = nullptr;
271}
272
273
275{
276 std::unique_lock<std::shared_mutex> writeLock( m_CachesMutex );
277
278 m_timeStamp++;
279
283 || m_maxClearanceValue.has_value() || !m_ItemNetclassCache.empty()
284 || !m_ZonesByNameCache.empty() || !m_DeflatedZoneOutlineCache.empty() )
285 {
286 m_IntersectsAreaCache.clear();
287 m_EnclosedByAreaCache.clear();
292 m_ItemNetclassCache.clear();
293 m_ZonesByNameCache.clear();
295
296 m_ZoneBBoxCache.clear();
297
298 m_CopperItemRTreeCache = nullptr;
299
300 // These are always regenerated before use, but still probably safer to clear them
301 // while we're here.
304 m_DRCZones.clear();
305 m_DRCCopperZones.clear();
309
310 m_maxClearanceValue.reset();
311 }
312}
313
314
316{
317 std::set<std::pair<KIID, KIID>> m_ratsnestExclusions;
318
319 for( PCB_MARKER* marker : GetBoard()->Markers() )
320 {
321 if( marker->GetMarkerType() == MARKER_BASE::MARKER_RATSNEST && marker->IsExcluded() )
322 {
323 const std::shared_ptr<RC_ITEM>& rcItem = marker->GetRCItem();
324 m_ratsnestExclusions.emplace( rcItem->GetMainItemID(), rcItem->GetAuxItemID() );
325 m_ratsnestExclusions.emplace( rcItem->GetAuxItemID(), rcItem->GetMainItemID() );
326 }
327 }
328
330 [&]( CN_EDGE& aEdge )
331 {
332 if( aEdge.GetSourceNode() && aEdge.GetTargetNode() && !aEdge.GetSourceNode()->Dirty()
333 && !aEdge.GetTargetNode()->Dirty() )
334 {
335 std::pair<KIID, KIID> ids = { aEdge.GetSourceNode()->Parent()->m_Uuid,
336 aEdge.GetTargetNode()->Parent()->m_Uuid };
337
338 aEdge.SetVisible( m_ratsnestExclusions.count( ids ) == 0 );
339 }
340
341 return true;
342 } );
343}
344
345
347{
348 m_designSettings->m_DrcExclusions.clear();
349 m_designSettings->m_DrcExclusionComments.clear();
350
351 for( PCB_MARKER* marker : m_markers )
352 {
353 if( marker->IsExcluded() )
354 {
355 wxString serialized = marker->SerializeToString();
356 m_designSettings->m_DrcExclusions.insert( serialized );
357 m_designSettings->m_DrcExclusionComments[serialized] = marker->GetComment();
358 }
359 }
360
361 if( m_project )
362 {
363 if( PROJECT_FILE* projectFile = &m_project->GetProjectFile() )
364 {
365 if( BOARD_DESIGN_SETTINGS* prjSettings = projectFile->m_BoardSettings )
366 {
367 prjSettings->m_DrcExclusions = m_designSettings->m_DrcExclusions;
368 prjSettings->m_DrcExclusionComments = m_designSettings->m_DrcExclusionComments;
369 }
370 }
371 }
372}
373
374std::set<wxString>::iterator FindByFirstNFields( std::set<wxString>& strSet, const wxString& searchStr, char delimiter,
375 int n )
376{
377 wxString searchPrefix = searchStr;
378
379 // Extract first n fields from the search string
380 int delimiterCount = 0;
381 size_t pos = 0;
382
383 while( pos < searchPrefix.length() && delimiterCount < n )
384 {
385 if( searchPrefix[pos] == delimiter )
386 delimiterCount++;
387
388 pos++;
389 }
390
391 if( delimiterCount == n )
392 searchPrefix = searchPrefix.Left( pos - 1 ); // Exclude the nth delimiter
393
394 for( auto it = strSet.begin(); it != strSet.end(); ++it )
395 {
396 if( it->StartsWith( searchPrefix + delimiter ) || *it == searchPrefix )
397 return it;
398 }
399
400 return strSet.end();
401}
402
403std::vector<PCB_MARKER*> BOARD::ResolveDRCExclusions( bool aCreateMarkers )
404{
405 std::set<wxString> exclusions = m_designSettings->m_DrcExclusions;
406 std::map<wxString, wxString> comments = m_designSettings->m_DrcExclusionComments;
407
408 m_designSettings->m_DrcExclusions.clear();
409 m_designSettings->m_DrcExclusionComments.clear();
410
411 for( PCB_MARKER* marker : GetBoard()->Markers() )
412 {
413 std::set<wxString>::iterator it;
414 wxString serialized = marker->SerializeToString();
415 wxString matchedExclusion;
416
417 if( !serialized.Contains( "unconnected_items" ) )
418 {
419 it = exclusions.find( serialized );
420
421 if( it != exclusions.end() )
422 matchedExclusion = *it;
423 }
424 else
425 {
426 const int numberOfFieldsExcludingIds = 3;
427 const char delimiter = '|';
428 it = FindByFirstNFields( exclusions, serialized, delimiter, numberOfFieldsExcludingIds );
429
430 if( it != exclusions.end() )
431 matchedExclusion = *it;
432 }
433
434 if( it != exclusions.end() )
435 {
436 marker->SetExcluded( true, comments[matchedExclusion] );
437
438 // Exclusion still valid; store back to BOARD_DESIGN_SETTINGS
439 m_designSettings->m_DrcExclusions.insert( matchedExclusion );
440 m_designSettings->m_DrcExclusionComments[matchedExclusion] = comments[matchedExclusion];
441
442 exclusions.erase( it );
443 }
444 }
445
446 std::vector<PCB_MARKER*> newMarkers;
447
448 if( aCreateMarkers )
449 {
450 for( const wxString& serialized : exclusions )
451 {
452 PCB_MARKER* marker = PCB_MARKER::DeserializeFromString( serialized );
453
454 if( !marker )
455 continue;
456
457 std::vector<KIID> ids = marker->GetRCItem()->GetIDs();
458
459 int uuidCount = 0;
460
461 for( const KIID& uuid : ids )
462 {
463 if( uuidCount < 1 || uuid != niluuid )
464 {
465 if( !ResolveItem( uuid, true ) )
466 {
467 delete marker;
468 marker = nullptr;
469 break;
470 }
471 }
472 uuidCount++;
473 }
474
475 if( marker )
476 {
477 marker->SetExcluded( true, comments[serialized] );
478 newMarkers.push_back( marker );
479
480 // Exclusion still valid; store back to BOARD_DESIGN_SETTINGS
481 m_designSettings->m_DrcExclusions.insert( serialized );
482 m_designSettings->m_DrcExclusionComments[serialized] = comments[serialized];
483 }
484 }
485 }
486
487 return newMarkers;
488}
489
490
491void BOARD::GetContextualTextVars( wxArrayString* aVars ) const
492{
493 auto add = [&]( const wxString& aVar )
494 {
495 if( !alg::contains( *aVars, aVar ) )
496 aVars->push_back( aVar );
497 };
498
499 add( wxT( "LAYER" ) );
500 add( wxT( "FILENAME" ) );
501 add( wxT( "FILEPATH" ) );
502 add( wxT( "PROJECTNAME" ) );
503 add( wxT( "DRC_ERROR <message_text>" ) );
504 add( wxT( "DRC_WARNING <message_text>" ) );
505 add( wxT( "VARIANT" ) );
506 add( wxT( "VARIANT_DESC" ) );
507
509
510 if( GetProject() )
511 {
512 for( std::pair<wxString, wxString> entry : GetProject()->GetTextVars() )
513 add( entry.first );
514 }
515}
516
517
518bool BOARD::ResolveTextVar( wxString* token, int aDepth ) const
519{
520 if( token->Contains( ':' ) )
521 {
522 wxString remainder;
523 wxString ref = token->BeforeFirst( ':', &remainder );
524 BOARD_ITEM* refItem = ResolveItem( KIID( ref ), true );
525
526 if( refItem && refItem->Type() == PCB_FOOTPRINT_T )
527 {
528 FOOTPRINT* refFP = static_cast<FOOTPRINT*>( refItem );
529
530 if( refFP->ResolveTextVar( &remainder, aDepth + 1 ) )
531 {
532 *token = std::move( remainder );
533 return true;
534 }
535 }
536
537 // If UUID resolution failed, try to resolve by reference designator
538 // This handles typing ${U1:VALUE} directly without save/reload
539 if( !refItem )
540 {
541 for( const FOOTPRINT* footprint : Footprints() )
542 {
543 if( footprint->GetReference().CmpNoCase( ref ) == 0 )
544 {
545 wxString remainderCopy = remainder;
546
547 if( footprint->ResolveTextVar( &remainderCopy, aDepth + 1 ) )
548 {
549 *token = std::move( remainderCopy );
550 }
551 else
552 {
553 // Field/function not found on footprint
554 *token = wxString::Format( wxT( "<Unresolved: %s:%s>" ), footprint->GetReference(), remainder );
555 }
556
557 return true;
558 }
559 }
560
561 // Reference not found - show error message
562 *token = wxString::Format( wxT( "<Unknown reference: %s>" ), ref );
563 return true;
564 }
565 }
566
567 if( token->IsSameAs( wxT( "FILENAME" ) ) )
568 {
569 wxFileName fn( GetFileName() );
570 *token = fn.GetFullName();
571 return true;
572 }
573 else if( token->IsSameAs( wxT( "FILEPATH" ) ) )
574 {
575 wxFileName fn( GetFileName() );
576 *token = fn.GetFullPath();
577 return true;
578 }
579 else if( token->IsSameAs( wxT( "VARIANT" ) ) )
580 {
581 *token = GetCurrentVariant();
582 return true;
583 }
584 else if( token->IsSameAs( wxT( "VARIANT_DESC" ) ) )
585 {
587 return true;
588 }
589 else if( token->IsSameAs( wxT( "PROJECTNAME" ) ) && GetProject() )
590 {
591 *token = GetProject()->GetProjectName();
592 return true;
593 }
594
595 wxString var = *token;
596
597 if( m_properties.count( var ) )
598 {
599 *token = m_properties.at( var );
600 return true;
601 }
602 else if( GetTitleBlock().TextVarResolver( token, m_project ) )
603 {
604 return true;
605 }
606
607 if( GetProject() && GetProject()->TextVarResolver( token ) )
608 return true;
609
610 return false;
611}
612
613
614bool BOARD::IsEmpty() const
615{
616 return m_drawings.empty() && m_footprints.empty() && m_tracks.empty() && m_zones.empty() && m_points.empty();
617}
618
619
621{
622 return ZeroOffset;
623}
624
625
626void BOARD::SetPosition( const VECTOR2I& aPos )
627{
628 wxLogWarning( wxT( "This should not be called on the BOARD object" ) );
629}
630
631
632void BOARD::Move( const VECTOR2I& aMoveVector ) // overload
633{
634 INSPECTOR_FUNC inspector = [&]( EDA_ITEM* item, void* testData )
635 {
636 if( item->IsBOARD_ITEM() )
637 {
638 BOARD_ITEM* board_item = static_cast<BOARD_ITEM*>( item );
639
640 // aMoveVector was snapshotted, don't need "data".
641 // Only move the top level group
642 if( !board_item->GetParentGroup() && !board_item->GetParentFootprint() )
643 board_item->Move( aMoveVector );
644 }
645
647 };
648
649 Visit( inspector, nullptr, GENERAL_COLLECTOR::BoardLevelItems );
650}
651
652
653void BOARD::RunOnChildren( const std::function<void( BOARD_ITEM* )>& aFunction, RECURSE_MODE aMode ) const
654{
655 try
656 {
657 for( PCB_TRACK* track : m_tracks )
658 aFunction( track );
659
660 for( ZONE* zone : m_zones )
661 aFunction( zone );
662
663 for( PCB_MARKER* marker : m_markers )
664 aFunction( marker );
665
666 for( PCB_GROUP* group : m_groups )
667 aFunction( group );
668
669 for( PCB_POINT* point : m_points )
670 aFunction( point );
671
672 for( FOOTPRINT* footprint : m_footprints )
673 {
674 aFunction( footprint );
675
676 if( aMode == RECURSE_MODE::RECURSE )
677 footprint->RunOnChildren( aFunction, RECURSE_MODE::RECURSE );
678 }
679
680 for( BOARD_ITEM* drawing : m_drawings )
681 {
682 aFunction( drawing );
683
684 if( aMode == RECURSE_MODE::RECURSE )
685 drawing->RunOnChildren( aFunction, RECURSE_MODE::RECURSE );
686 }
687 }
688 catch( std::bad_function_call& )
689 {
690 wxFAIL_MSG( wxT( "Error running BOARD::RunOnChildren" ) );
691 }
692}
693
694
696{
697 TRACKS ret;
698
699 INSPECTOR_FUNC inspector = [aNetCode, &ret]( EDA_ITEM* item, void* testData )
700 {
701 PCB_TRACK* t = static_cast<PCB_TRACK*>( item );
702
703 if( t->GetNetCode() == aNetCode )
704 ret.push_back( t );
705
707 };
708
709 // visit this BOARD's PCB_TRACKs and PCB_VIAs with above TRACK INSPECTOR which
710 // appends all in aNetCode to ret.
711 Visit( inspector, nullptr, GENERAL_COLLECTOR::Tracks );
712
713 return ret;
714}
715
716
717bool BOARD::SetLayerDescr( PCB_LAYER_ID aIndex, const LAYER& aLayer )
718{
719 m_layers[aIndex] = aLayer;
721 return true;
722}
723
724
725PCB_LAYER_ID BOARD::GetLayerID( const wxString& aLayerName ) const
726{
727 // Check the BOARD physical layer names.
728 for( auto& [layer_id, layer] : m_layers )
729 {
730 if( layer.m_name == aLayerName || layer.m_userName == aLayerName )
731 return ToLAYER_ID( layer_id );
732 }
733
734 // Otherwise fall back to the system standard layer names for virtual layers.
735 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
736 {
737 if( GetStandardLayerName( ToLAYER_ID( layer ) ) == aLayerName )
738 return ToLAYER_ID( layer );
739 }
740
741 return UNDEFINED_LAYER;
742}
743
744
745const wxString BOARD::GetLayerName( PCB_LAYER_ID aLayer ) const
746{
747 // All layer names are stored in the BOARD.
748 if( IsLayerEnabled( aLayer ) )
749 {
750 auto it = m_layers.find( aLayer );
751
752 // Standard names were set in BOARD::BOARD() but they may be over-ridden by
753 // BOARD::SetLayerName(). For copper layers, return the user defined layer name,
754 // if it was set. Otherwise return the Standard English layer name.
755 if( it != m_layers.end() && !it->second.m_userName.IsEmpty() )
756 return it->second.m_userName;
757 }
758
759 return GetStandardLayerName( aLayer );
760}
761
762
763bool BOARD::SetLayerName( PCB_LAYER_ID aLayer, const wxString& aLayerName )
764{
765 if( aLayerName.IsEmpty() )
766 {
767 // If the name is empty, we clear the user name.
768 m_layers[aLayer].m_userName.clear();
770 }
771 else
772 {
773 // no quote chars in the name allowed
774 if( aLayerName.Find( wxChar( '"' ) ) != wxNOT_FOUND )
775 return false;
776
777 if( IsLayerEnabled( aLayer ) )
778 {
779 m_layers[aLayer].m_userName = aLayerName;
781 return true;
782 }
783 }
784
785 return false;
786}
787
788
790{
791 return ::IsFrontLayer( aLayer ) || GetLayerType( aLayer ) == LT_FRONT;
792}
793
794
796{
797 return ::IsBackLayer( aLayer ) || GetLayerType( aLayer ) == LT_BACK;
798}
799
800
802{
803 if( IsLayerEnabled( aLayer ) )
804 {
805 auto it = m_layers.find( aLayer );
806
807 if( it != m_layers.end() )
808 return it->second.m_type;
809 }
810
811 if( aLayer >= User_1 && !IsCopperLayer( aLayer ) )
812 return LT_AUX;
813 else if( IsCopperLayer( aLayer ) )
814 return LT_SIGNAL;
815 else
816 return LT_UNDEFINED;
817}
818
819
820bool BOARD::SetLayerType( PCB_LAYER_ID aLayer, LAYER_T aLayerType )
821{
822 if( IsLayerEnabled( aLayer ) )
823 {
824 m_layers[aLayer].m_type = aLayerType;
826 return true;
827 }
828
829 return false;
830}
831
832
833const char* LAYER::ShowType( LAYER_T aType )
834{
835 switch( aType )
836 {
837 default:
838 case LT_SIGNAL: return "signal";
839 case LT_POWER: return "power";
840 case LT_MIXED: return "mixed";
841 case LT_JUMPER: return "jumper";
842 case LT_AUX: return "auxiliary";
843 case LT_FRONT: return "front";
844 case LT_BACK: return "back";
845 }
846}
847
848
849LAYER_T LAYER::ParseType( const char* aType )
850{
851 if( strcmp( aType, "signal" ) == 0 )
852 return LT_SIGNAL;
853 else if( strcmp( aType, "power" ) == 0 )
854 return LT_POWER;
855 else if( strcmp( aType, "mixed" ) == 0 )
856 return LT_MIXED;
857 else if( strcmp( aType, "jumper" ) == 0 )
858 return LT_JUMPER;
859 else if( strcmp( aType, "auxiliary" ) == 0 )
860 return LT_AUX;
861 else if( strcmp( aType, "front" ) == 0 )
862 return LT_FRONT;
863 else if( strcmp( aType, "back" ) == 0 )
864 return LT_BACK;
865 else
866 return LT_UNDEFINED;
867}
868
869
871{
872 for( int layer = F_Cu; layer < PCB_LAYER_ID_COUNT; ++layer )
873 m_layers[layer].m_opposite = ::FlipLayer( ToLAYER_ID( layer ), GetCopperLayerCount() );
874
875 // Match up similary-named front/back user layers
876 for( int layer = User_1; layer <= PCB_LAYER_ID_COUNT; layer += 2 )
877 {
878 if( m_layers[layer].m_opposite != layer ) // already paired
879 continue;
880
881 if( m_layers[layer].m_type != LT_FRONT && m_layers[layer].m_type != LT_BACK )
882 continue;
883
884 wxString principalName = m_layers[layer].m_userName.AfterFirst( '.' );
885
886 for( int ii = layer + 2; ii <= PCB_LAYER_ID_COUNT; ii += 2 )
887 {
888 if( m_layers[ii].m_opposite != ii ) // already paired
889 continue;
890
891 if( m_layers[ii].m_type != LT_FRONT && m_layers[ii].m_type != LT_BACK )
892 continue;
893
894 if( m_layers[layer].m_type == m_layers[ii].m_type )
895 continue;
896
897 wxString candidate = m_layers[ii].m_userName.AfterFirst( '.' );
898
899 if( !candidate.IsEmpty() && candidate == principalName )
900 {
901 m_layers[layer].m_opposite = ii;
902 m_layers[ii].m_opposite = layer;
903 break;
904 }
905 }
906 }
907
908 // Match up non-custom-named consecutive front/back user layer pairs
909 for( int layer = User_1; layer < PCB_LAYER_ID_COUNT - 2; layer += 2 )
910 {
911 int next = layer + 2;
912
913 // ignore already-matched layers
914 if( m_layers[layer].m_opposite != layer || m_layers[next].m_opposite != next )
915 continue;
916
917 // ignore layer pairs that aren't consecutive front/back
918 if( m_layers[layer].m_type != LT_FRONT || m_layers[next].m_type != LT_BACK )
919 continue;
920
921 if( m_layers[layer].m_userName != m_layers[layer].m_name && m_layers[next].m_userName != m_layers[next].m_name )
922 {
923 m_layers[layer].m_opposite = next;
924 m_layers[next].m_opposite = layer;
925 }
926 }
927}
928
929
931{
932 auto it = m_layers.find( aLayer );
933 return it == m_layers.end() ? aLayer : ToLAYER_ID( it->second.m_opposite );
934}
935
936
941
942
944{
947}
948
949
954
955
957{
959}
960
962{
963 int imax = GetCopperLayerCount();
964
965 // layers IDs are F_Cu, B_Cu, and even IDs values (imax values)
966 if( imax <= 2 ) // at least 2 layers are expected
967 return B_Cu;
968
969 // For a 4 layer, last ID is In2_Cu = 6 (IDs are 0, 2, 4, 6)
970 return static_cast<PCB_LAYER_ID>( ( imax - 1 ) * 2 );
971}
972
973
974int BOARD::LayerDepth( PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer ) const
975{
976 if( aStartLayer > aEndLayer )
977 std::swap( aStartLayer, aEndLayer );
978
979 if( aEndLayer == B_Cu )
980 aEndLayer = ToLAYER_ID( F_Cu + GetCopperLayerCount() - 1 );
981
982 return aEndLayer - aStartLayer;
983}
984
985
987{
989}
990
991
993{
994 // If there is no project, assume layer is visible always
995 return GetDesignSettings().IsLayerEnabled( aLayer )
996 && ( !m_project || m_project->GetLocalSettings().m_VisibleLayers[aLayer] );
997}
998
999
1001{
1002 return m_project ? m_project->GetLocalSettings().m_VisibleLayers : LSET::AllLayersMask();
1003}
1004
1005
1006void BOARD::SetEnabledLayers( const LSET& aLayerSet )
1007{
1008 GetDesignSettings().SetEnabledLayers( aLayerSet );
1009}
1010
1011
1013{
1014 return GetDesignSettings().IsLayerEnabled( aLayer );
1015}
1016
1017
1018void BOARD::SetVisibleLayers( const LSET& aLayerSet )
1019{
1020 if( m_project )
1021 m_project->GetLocalSettings().m_VisibleLayers = aLayerSet;
1022}
1023
1024
1026{
1027 // Call SetElementVisibility for each item
1028 // to ensure specific calculations that can be needed by some items,
1029 // just changing the visibility flags could be not sufficient.
1030 for( size_t i = 0; i < aSet.size(); i++ )
1031 SetElementVisibility( GAL_LAYER_ID_START + static_cast<int>( i ), aSet[i] );
1032}
1033
1034
1036{
1037 SetVisibleLayers( LSET().set() );
1038
1039 // Call SetElementVisibility for each item,
1040 // to ensure specific calculations that can be needed by some items
1042 SetElementVisibility( ii, true );
1043}
1044
1045
1047{
1048 return m_project ? m_project->GetLocalSettings().m_VisibleItems : GAL_SET::DefaultVisible();
1049}
1050
1051
1053{
1054 return !m_project || m_project->GetLocalSettings().m_VisibleItems[aLayer - GAL_LAYER_ID_START];
1055}
1056
1057
1058void BOARD::SetElementVisibility( GAL_LAYER_ID aLayer, bool isEnabled )
1059{
1060 if( m_project )
1061 m_project->GetLocalSettings().m_VisibleItems.set( aLayer - GAL_LAYER_ID_START, isEnabled );
1062
1063 switch( aLayer )
1064 {
1065 case LAYER_RATSNEST:
1066 {
1067 // because we have a tool to show/hide ratsnest relative to a pad or a footprint
1068 // so the hide/show option is a per item selection
1069
1070 for( PCB_TRACK* track : Tracks() )
1071 track->SetLocalRatsnestVisible( isEnabled );
1072
1073 for( FOOTPRINT* footprint : Footprints() )
1074 {
1075 for( PAD* pad : footprint->Pads() )
1076 pad->SetLocalRatsnestVisible( isEnabled );
1077 }
1078
1079 for( ZONE* zone : Zones() )
1080 zone->SetLocalRatsnestVisible( isEnabled );
1081
1082 break;
1083 }
1084
1085 default:;
1086 }
1087}
1088
1089
1091{
1092 switch( aLayer )
1093 {
1096 default: wxFAIL_MSG( wxT( "BOARD::IsModuleLayerVisible(): bad layer" ) ); return true;
1097 }
1098}
1099
1100
1105
1106
1108{
1109 *m_designSettings = aSettings;
1110}
1111
1112
1114{
1115 if( m_designSettings && m_designSettings->m_DRCEngine )
1116 m_designSettings->m_DRCEngine->InvalidateClearanceCache( aUuid );
1117}
1118
1119
1121{
1122 if( m_designSettings && m_designSettings->m_DRCEngine )
1123 m_designSettings->m_DRCEngine->InitializeClearanceCache();
1124}
1125
1126
1128{
1129 if( !m_maxClearanceValue.has_value() )
1130 {
1131 std::unique_lock<std::shared_mutex> writeLock( m_CachesMutex );
1132
1133 int worstClearance = m_designSettings->GetBiggestClearanceValue();
1134
1135 for( ZONE* zone : m_zones )
1136 worstClearance = std::max( worstClearance, zone->GetLocalClearance().value() );
1137
1138 for( FOOTPRINT* footprint : m_footprints )
1139 {
1140 for( PAD* pad : footprint->Pads() )
1141 {
1142 std::optional<int> override = pad->GetClearanceOverrides( nullptr );
1143
1144 if( override.has_value() )
1145 worstClearance = std::max( worstClearance, override.value() );
1146 }
1147
1148 for( ZONE* zone : footprint->Zones() )
1149 worstClearance = std::max( worstClearance, zone->GetLocalClearance().value() );
1150 }
1151
1152 m_maxClearanceValue = worstClearance;
1153 }
1154
1155 return m_maxClearanceValue.value_or( 0 );
1156};
1157
1158
1159void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter, const std::vector<ZONE*>& aZones )
1160{
1161 std::vector<ZONE*> zones = aZones;
1162
1163 if( zones.empty() )
1164 zones = m_zones;
1165
1166 if( zones.empty() )
1167 return;
1168
1169 if( aReporter )
1170 aReporter->Report( _( "Tessellating copper zones..." ) );
1171
1173 std::vector<std::future<size_t>> returns;
1174
1175 returns.reserve( zones.size() );
1176
1178 [&tp]( std::function<void()> aTask )
1179 {
1180 tp.detach_task( std::move( aTask ) );
1181 };
1182
1183 auto cache_zones = [aReporter, &submitter]( ZONE* aZone ) -> size_t
1184 {
1185 if( aReporter && aReporter->IsCancelled() )
1186 return 0;
1187
1188 aZone->CacheTriangulation( UNDEFINED_LAYER, submitter );
1189
1190 if( aReporter )
1191 aReporter->AdvanceProgress();
1192
1193 return 1;
1194 };
1195
1196 for( ZONE* zone : zones )
1197 returns.emplace_back( tp.submit_task(
1198 [cache_zones, zone]
1199 {
1200 return cache_zones( zone );
1201 } ) );
1202
1203 // Finalize the triangulation threads
1204 for( const std::future<size_t>& ret : returns )
1205 {
1206 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1207
1208 while( status != std::future_status::ready )
1209 {
1210 if( aReporter )
1211 aReporter->KeepRefreshing();
1212
1213 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1214 }
1215 }
1216}
1217
1218
1219void BOARD::RunOnNestedEmbeddedFiles( const std::function<void( EMBEDDED_FILES* )>& aFunction )
1220{
1221 for( FOOTPRINT* footprint : m_footprints )
1222 aFunction( footprint->GetEmbeddedFiles() );
1223}
1224
1225
1227{
1229 [&]( EMBEDDED_FILES* nested )
1230 {
1231 for( auto& [filename, embeddedFile] : nested->EmbeddedFileMap() )
1232 {
1234
1235 if( file )
1236 {
1237 embeddedFile->compressedEncodedData = file->compressedEncodedData;
1238 embeddedFile->decompressedData = file->decompressedData;
1239 embeddedFile->data_hash = file->data_hash;
1240 embeddedFile->is_valid = file->is_valid;
1241 }
1242 }
1243 } );
1244}
1245
1246
1247void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode, bool aSkipConnectivity )
1248{
1249 if( aBoardItem == nullptr )
1250 {
1251 wxFAIL_MSG( wxT( "BOARD::Add() param error: aBoardItem nullptr" ) );
1252 return;
1253 }
1254
1255 CacheItemById( aBoardItem );
1256
1257 switch( aBoardItem->Type() )
1258 {
1259 case PCB_NETINFO_T: m_NetInfo.AppendNet( (NETINFO_ITEM*) aBoardItem ); break;
1260
1261 // this one uses a vector
1262 case PCB_MARKER_T: m_markers.push_back( (PCB_MARKER*) aBoardItem ); break;
1263
1264 // this one uses a vector
1265 case PCB_GROUP_T: m_groups.push_back( (PCB_GROUP*) aBoardItem ); break;
1266
1267 // this one uses a vector
1268 case PCB_GENERATOR_T: m_generators.push_back( (PCB_GENERATOR*) aBoardItem ); break;
1269
1270 // this one uses a vector
1271 case PCB_ZONE_T: m_zones.push_back( (ZONE*) aBoardItem ); break;
1272
1273 case PCB_VIA_T:
1274 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1275 m_tracks.push_back( static_cast<PCB_VIA*>( aBoardItem ) );
1276 else
1277 m_tracks.push_front( static_cast<PCB_VIA*>( aBoardItem ) );
1278
1279 break;
1280
1281 case PCB_TRACE_T:
1282 case PCB_ARC_T:
1283 if( !IsCopperLayer( aBoardItem->GetLayer() ) )
1284 {
1285 // The only current known source of these is SWIG (KICAD-BY7, et al).
1286 // N.B. This inserts a small memory leak as we lose the track/via/arc.
1287 wxFAIL_MSG( wxString::Format( "BOARD::Add() Cannot place Track on non-copper layer: %d = %s",
1288 static_cast<int>( aBoardItem->GetLayer() ),
1289 GetLayerName( aBoardItem->GetLayer() ) ) );
1290 return;
1291 }
1292
1293 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1294 m_tracks.push_back( static_cast<PCB_TRACK*>( aBoardItem ) );
1295 else
1296 m_tracks.push_front( static_cast<PCB_TRACK*>( aBoardItem ) );
1297
1298 break;
1299
1300 case PCB_FOOTPRINT_T:
1301 {
1302 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aBoardItem );
1303
1304 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1305 m_footprints.push_back( footprint );
1306 else
1307 m_footprints.push_front( footprint );
1308
1309 CacheChildrenById( footprint );
1310 break;
1311 }
1312
1313 case PCB_BARCODE_T:
1314 case PCB_DIM_ALIGNED_T:
1315 case PCB_DIM_CENTER_T:
1316 case PCB_DIM_RADIAL_T:
1318 case PCB_DIM_LEADER_T:
1319 case PCB_SHAPE_T:
1321 case PCB_FIELD_T:
1322 case PCB_TEXT_T:
1323 case PCB_TEXTBOX_T:
1324 case PCB_TABLE_T:
1325 case PCB_TARGET_T:
1326 {
1327 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1328 m_drawings.push_back( aBoardItem );
1329 else
1330 m_drawings.push_front( aBoardItem );
1331
1332 if( aBoardItem->Type() == PCB_TABLE_T )
1333 {
1334 CacheChildrenById( aBoardItem );
1335 }
1336
1337 break;
1338 }
1339
1340 case PCB_POINT_T:
1341 // These aren't graphics as they have no physical presence
1342 m_points.push_back( static_cast<PCB_POINT*>( aBoardItem ) );
1343 break;
1344
1345 case PCB_TABLECELL_T:
1346 // Handled by parent table
1347 break;
1348
1349 default:
1350 wxFAIL_MSG( wxString::Format( wxT( "BOARD::Add() item type %s not handled" ), aBoardItem->GetClass() ) );
1351 return;
1352 }
1353
1354 aBoardItem->SetParent( this );
1355 aBoardItem->ClearEditFlags();
1356
1357 if( !aSkipConnectivity )
1358 m_connectivity->Add( aBoardItem );
1359
1360 if( aMode != ADD_MODE::BULK_INSERT && aMode != ADD_MODE::BULK_APPEND )
1362}
1363
1364
1365void BOARD::FinalizeBulkAdd( std::vector<BOARD_ITEM*>& aNewItems )
1366{
1368}
1369
1370
1371void BOARD::FinalizeBulkRemove( std::vector<BOARD_ITEM*>& aRemovedItems )
1372{
1373 InvokeListeners( &BOARD_LISTENER::OnBoardItemsRemoved, *this, aRemovedItems );
1374}
1375
1376
1378{
1379 for( int ii = (int) m_zones.size() - 1; ii >= 0; --ii )
1380 {
1381 ZONE* zone = m_zones[ii];
1382
1383 if( zone->IsTeardropArea() && zone->HasFlag( STRUCT_DELETED ) )
1384 {
1385 UncacheItemById( zone->m_Uuid );
1386 m_zones.erase( m_zones.begin() + ii );
1387 m_connectivity->Remove( zone );
1388 aCommit.Removed( zone );
1389 }
1390 }
1391}
1392
1393
1394void BOARD::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aRemoveMode )
1395{
1396 // find these calls and fix them! Don't send me no stinking' nullptr.
1397 wxASSERT( aBoardItem );
1398
1399 // This is redundant with BOARD_COMMIT::Push but necessary to support SWIG interaction
1400 // until the SWIG API is completely removed (since it doesn't use the commit system)
1401 if( EDA_GROUP* parentGroup = aBoardItem->GetParentGroup();
1402 parentGroup && !( parentGroup->AsEdaItem()->GetFlags() & STRUCT_DELETED ) )
1403 {
1404 parentGroup->RemoveItem( aBoardItem );
1405 }
1406
1407 UncacheItemById( aBoardItem->m_Uuid );
1408
1409 switch( aBoardItem->Type() )
1410 {
1411 case PCB_NETINFO_T:
1412 {
1413 NETINFO_ITEM* netItem = static_cast<NETINFO_ITEM*>( aBoardItem );
1414 NETINFO_ITEM* unconnected = m_NetInfo.GetNetItem( NETINFO_LIST::UNCONNECTED );
1415
1416 for( BOARD_CONNECTED_ITEM* boardItem : AllConnectedItems() )
1417 {
1418 if( boardItem->GetNet() == netItem )
1419 boardItem->SetNet( unconnected );
1420 }
1421
1422 m_NetInfo.RemoveNet( netItem );
1423 break;
1424 }
1425
1426 case PCB_MARKER_T: std::erase( m_markers, aBoardItem ); break;
1427
1428 case PCB_GROUP_T: std::erase( m_groups, aBoardItem ); break;
1429
1430 case PCB_ZONE_T: std::erase( m_zones, aBoardItem ); break;
1431
1432 case PCB_POINT_T: std::erase( m_points, aBoardItem ); break;
1433
1434 case PCB_GENERATOR_T: std::erase( m_generators, aBoardItem ); break;
1435
1436 case PCB_FOOTPRINT_T:
1437 {
1438 std::erase( m_footprints, aBoardItem );
1439 UncacheChildrenById( aBoardItem );
1440
1441 break;
1442 }
1443
1444 case PCB_TRACE_T:
1445 case PCB_ARC_T:
1446 case PCB_VIA_T: std::erase( m_tracks, aBoardItem ); break;
1447
1448 case PCB_BARCODE_T:
1449 case PCB_DIM_ALIGNED_T:
1450 case PCB_DIM_CENTER_T:
1451 case PCB_DIM_RADIAL_T:
1453 case PCB_DIM_LEADER_T:
1454 case PCB_SHAPE_T:
1456 case PCB_FIELD_T:
1457 case PCB_TEXT_T:
1458 case PCB_TEXTBOX_T:
1459 case PCB_TABLE_T:
1460 case PCB_TARGET_T:
1461 {
1462 std::erase( m_drawings, aBoardItem );
1463
1464 if( aBoardItem->Type() == PCB_TABLE_T )
1465 {
1466 UncacheChildrenById( aBoardItem );
1467 }
1468
1469 break;
1470 }
1471
1472 case PCB_TABLECELL_T:
1473 // Handled by parent table
1474 break;
1475
1476 // other types may use linked list
1477 default:
1478 wxFAIL_MSG( wxString::Format( wxT( "BOARD::Remove() item type %s not handled" ), aBoardItem->GetClass() ) );
1479 }
1480
1481 aBoardItem->SetFlags( STRUCT_DELETED );
1482
1483 m_connectivity->Remove( aBoardItem );
1484
1485 if( aRemoveMode != REMOVE_MODE::BULK )
1487}
1488
1489
1490void BOARD::RemoveAll( std::initializer_list<KICAD_T> aTypes )
1491{
1492 std::vector<BOARD_ITEM*> removed;
1493
1494 for( const KICAD_T& type : aTypes )
1495 {
1496 switch( type )
1497 {
1498 case PCB_NETINFO_T:
1499 for( NETINFO_ITEM* item : m_NetInfo )
1500 removed.emplace_back( item );
1501
1502 m_NetInfo.clear();
1503 break;
1504
1505 case PCB_MARKER_T:
1506 std::copy( m_markers.begin(), m_markers.end(), std::back_inserter( removed ) );
1507 m_markers.clear();
1508 break;
1509
1510 case PCB_GROUP_T:
1511 std::copy( m_groups.begin(), m_groups.end(), std::back_inserter( removed ) );
1512 m_groups.clear();
1513 break;
1514
1515 case PCB_POINT_T:
1516 std::copy( m_points.begin(), m_points.end(), std::back_inserter( removed ) );
1517 m_points.clear();
1518 break;
1519
1520 case PCB_ZONE_T:
1521 std::copy( m_zones.begin(), m_zones.end(), std::back_inserter( removed ) );
1522 m_zones.clear();
1523 break;
1524
1525 case PCB_GENERATOR_T:
1526 std::copy( m_generators.begin(), m_generators.end(), std::back_inserter( removed ) );
1527 m_generators.clear();
1528 break;
1529
1530 case PCB_FOOTPRINT_T:
1531 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( removed ) );
1532 m_footprints.clear();
1533 break;
1534
1535 case PCB_TRACE_T:
1536 std::copy( m_tracks.begin(), m_tracks.end(), std::back_inserter( removed ) );
1537 m_tracks.clear();
1538 break;
1539
1540 case PCB_ARC_T:
1541 case PCB_VIA_T: wxFAIL_MSG( wxT( "Use PCB_TRACE_T to remove all tracks, arcs, and vias" ) ); break;
1542
1543 case PCB_SHAPE_T:
1544 std::copy( m_drawings.begin(), m_drawings.end(), std::back_inserter( removed ) );
1545 m_drawings.clear();
1546 break;
1547
1548 case PCB_DIM_ALIGNED_T:
1549 case PCB_DIM_CENTER_T:
1550 case PCB_DIM_RADIAL_T:
1552 case PCB_DIM_LEADER_T:
1554 case PCB_FIELD_T:
1555 case PCB_TEXT_T:
1556 case PCB_TEXTBOX_T:
1557 case PCB_TABLE_T:
1558 case PCB_TARGET_T:
1559 case PCB_BARCODE_T: wxFAIL_MSG( wxT( "Use PCB_SHAPE_T to remove all graphics and text" ) ); break;
1560
1561 default: wxFAIL_MSG( wxT( "BOARD::RemoveAll() needs more ::Type() support" ) );
1562 }
1563 }
1564
1565 m_itemByIdCache.clear();
1566 m_cachedIdByItem.clear();
1567
1569
1570 FinalizeBulkRemove( removed );
1571}
1572
1573
1575{
1576 PCB_LAYER_COLLECTOR collector;
1577
1578 collector.SetLayerId( aLayer );
1580
1581 if( collector.GetCount() != 0 )
1582 {
1583 // Skip items owned by footprints and footprints when building
1584 // the actual list of removed layers: these items are not removed
1585 for( int i = 0; i < collector.GetCount(); i++ )
1586 {
1587 BOARD_ITEM* item = collector[i];
1588
1589 if( item->Type() == PCB_FOOTPRINT_T || item->GetParentFootprint() )
1590 continue;
1591
1592 // Vias are on multiple adjacent layers, but only the top and
1593 // the bottom layers are stored. So there are issues only if one
1594 // is on a removed layer
1595 if( item->Type() == PCB_VIA_T )
1596 {
1597 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1598
1599 if( via->GetViaType() == VIATYPE::THROUGH )
1600 continue;
1601 else
1602 {
1603 PCB_LAYER_ID top_layer;
1604 PCB_LAYER_ID bottom_layer;
1605 via->LayerPair( &top_layer, &bottom_layer );
1606
1607 if( top_layer != aLayer && bottom_layer != aLayer )
1608 continue;
1609 }
1610 }
1611
1612 return true;
1613 }
1614 }
1615
1616 return false;
1617}
1618
1619
1621{
1622 bool modified = false;
1623 bool removedItemLayers = false;
1624 PCB_LAYER_COLLECTOR collector;
1625
1626 collector.SetLayerId( aLayer );
1628
1629 for( int i = 0; i < collector.GetCount(); i++ )
1630 {
1631 BOARD_ITEM* item = collector[i];
1632
1633 // Do not remove/change an item owned by a footprint
1634 if( item->GetParentFootprint() )
1635 continue;
1636
1637 // Do not remove footprints
1638 if( item->Type() == PCB_FOOTPRINT_T )
1639 continue;
1640
1641 // Note: vias are specific. They are only on copper layers, and
1642 // do not use a layer set, only store the copper top and the copper bottom.
1643 // So reinit the layer set does not work with vias
1644 if( item->Type() == PCB_VIA_T )
1645 {
1646 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1647
1648 if( via->GetViaType() == VIATYPE::THROUGH )
1649 {
1650 removedItemLayers = true;
1651 continue;
1652 }
1653 else if( via->IsOnLayer( aLayer ) )
1654 {
1655 PCB_LAYER_ID top_layer;
1656 PCB_LAYER_ID bottom_layer;
1657 via->LayerPair( &top_layer, &bottom_layer );
1658
1659 if( top_layer == aLayer || bottom_layer == aLayer )
1660 {
1661 // blind/buried vias with a top or bottom layer on a removed layer
1662 // are removed. Perhaps one could just modify the top/bottom layer,
1663 // but I am not sure this is better.
1664 Remove( item );
1665 delete item;
1666 modified = true;
1667 }
1668
1669 removedItemLayers = true;
1670 }
1671 }
1672 else if( item->IsOnLayer( aLayer ) )
1673 {
1674 LSET layers = item->GetLayerSet();
1675
1676 layers.reset( aLayer );
1677
1678 if( layers.any() )
1679 {
1680 item->SetLayerSet( layers );
1681 }
1682 else
1683 {
1684 Remove( item );
1685 delete item;
1686 modified = true;
1687 }
1688
1689 removedItemLayers = true;
1690 }
1691 }
1692
1693 if( removedItemLayers )
1695
1696 return modified;
1697}
1698
1699
1700wxString BOARD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1701{
1702 return wxString::Format( _( "PCB" ) );
1703}
1704
1705
1707{
1708 INSPECTOR_FUNC inspector = [&]( EDA_ITEM* descendant, void* aTestData )
1709 {
1710 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( descendant );
1711
1712 if( dimension->GetUnitsMode() == DIM_UNITS_MODE::AUTOMATIC )
1713 {
1714 dimension->UpdateUnits();
1715
1716 if( aView )
1717 aView->Update( dimension );
1718 }
1719
1721 };
1722
1723 aItem->Visit( inspector, nullptr,
1725}
1726
1727
1729{
1730 for( PCB_MARKER* marker : m_markers )
1731 UncacheItemById( marker->m_Uuid );
1732
1733 for( PCB_MARKER* marker : m_markers )
1734 delete marker;
1735
1736 m_markers.clear();
1738}
1739
1740
1741void BOARD::DeleteMARKERs( bool aWarningsAndErrors, bool aExclusions )
1742{
1743 // Deleting lots of items from a vector can be very slow. Copy remaining items instead.
1744 std::vector<PCB_MARKER*> remaining;
1745
1746 for( PCB_MARKER* marker : m_markers )
1747 {
1748 if( ( marker->GetSeverity() == RPT_SEVERITY_EXCLUSION && aExclusions )
1749 || ( marker->GetSeverity() != RPT_SEVERITY_EXCLUSION && aWarningsAndErrors ) )
1750 {
1751 UncacheItemById( marker->m_Uuid );
1752 delete marker;
1753 }
1754 else
1755 {
1756 remaining.push_back( marker );
1757 }
1758 }
1759
1760 m_markers = std::move( remaining );
1762}
1763
1764
1766{
1767 std::vector<FOOTPRINT*> footprints;
1768 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( footprints ) );
1769
1771
1772 for( FOOTPRINT* footprint : footprints )
1773 delete footprint;
1774}
1775
1776
1778{
1779 std::vector<FOOTPRINT*> footprints;
1780 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( footprints ) );
1781
1783
1784 for( FOOTPRINT* footprint : footprints )
1785 footprint->SetParent( nullptr );
1786}
1787
1788
1789BOARD_ITEM* BOARD::ResolveItem( const KIID& aID, bool aAllowNullptrReturn ) const
1790{
1791 if( aID == niluuid )
1792 return nullptr;
1793
1794 if( BOARD_ITEM* cached = GetCachedItemById( aID ) )
1795 return cached;
1796
1797 // Linear scan fallback for items not in the cache. Any hit is cached so
1798 // subsequent lookups for the same item are O(1).
1799
1800 for( PCB_GROUP* group : m_groups )
1801 {
1802 if( group->m_Uuid == aID )
1803 return CacheAndReturnItemById( aID, group );
1804 }
1805
1806 for( PCB_GENERATOR* generator : m_generators )
1807 {
1808 if( generator->m_Uuid == aID )
1809 return CacheAndReturnItemById( aID, generator );
1810 }
1811
1812 for( PCB_TRACK* track : Tracks() )
1813 {
1814 if( track->m_Uuid == aID )
1815 return CacheAndReturnItemById( aID, track );
1816 }
1817
1818 for( FOOTPRINT* footprint : Footprints() )
1819 {
1820 if( footprint->m_Uuid == aID )
1821 return CacheAndReturnItemById( aID, footprint );
1822
1823 for( PAD* pad : footprint->Pads() )
1824 {
1825 if( pad->m_Uuid == aID )
1826 return CacheAndReturnItemById( aID, pad );
1827 }
1828
1829 for( PCB_FIELD* field : footprint->GetFields() )
1830 {
1831 wxCHECK2( field, continue );
1832
1833 if( field && field->m_Uuid == aID )
1834 return CacheAndReturnItemById( aID, field );
1835 }
1836
1837 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
1838 {
1839 if( drawing->m_Uuid == aID )
1840 return CacheAndReturnItemById( aID, drawing );
1841 }
1842
1843 for( BOARD_ITEM* zone : footprint->Zones() )
1844 {
1845 if( zone->m_Uuid == aID )
1846 return CacheAndReturnItemById( aID, zone );
1847 }
1848
1849 for( PCB_GROUP* group : footprint->Groups() )
1850 {
1851 if( group->m_Uuid == aID )
1852 return CacheAndReturnItemById( aID, group );
1853 }
1854
1855 for( PCB_POINT* point : footprint->Points() )
1856 {
1857 if( point->m_Uuid == aID )
1858 return CacheAndReturnItemById( aID, point );
1859 }
1860 }
1861
1862 for( ZONE* zone : Zones() )
1863 {
1864 if( zone->m_Uuid == aID )
1865 return CacheAndReturnItemById( aID, zone );
1866 }
1867
1868 for( BOARD_ITEM* drawing : Drawings() )
1869 {
1870 if( drawing->Type() == PCB_TABLE_T )
1871 {
1872 for( PCB_TABLECELL* cell : static_cast<PCB_TABLE*>( drawing )->GetCells() )
1873 {
1874 if( cell->m_Uuid == aID )
1875 return CacheAndReturnItemById( aID, drawing );
1876 }
1877 }
1878
1879 if( drawing->m_Uuid == aID )
1880 return CacheAndReturnItemById( aID, drawing );
1881 }
1882
1883 for( PCB_MARKER* marker : m_markers )
1884 {
1885 if( marker->m_Uuid == aID )
1886 return CacheAndReturnItemById( aID, marker );
1887 }
1888
1889 for( PCB_POINT* point : m_points )
1890 {
1891 if( point->m_Uuid == aID )
1892 return CacheAndReturnItemById( aID, point );
1893 }
1894
1895 for( NETINFO_ITEM* netInfo : m_NetInfo )
1896 {
1897 if( netInfo->m_Uuid == aID )
1898 return CacheAndReturnItemById( aID, netInfo );
1899 }
1900
1901 if( m_Uuid == aID )
1902 return const_cast<BOARD*>( this );
1903
1904 // Not found; weak reference has been deleted.
1905 if( aAllowNullptrReturn )
1906 return nullptr;
1907
1909}
1910
1911
1913{
1914 auto it = m_itemByIdCache.find( aId );
1915
1916 if( it == m_itemByIdCache.end() )
1917 return nullptr;
1918
1919 BOARD_ITEM* item = it->second;
1920
1921 if( item && item->m_Uuid == aId )
1922 return item;
1923
1924 UncacheItemById( aId );
1925 return nullptr;
1926}
1927
1928
1930{
1931 if( IsFootprintHolder() )
1932 return;
1933
1934 if( auto prev = m_cachedIdByItem.find( aItem );
1935 prev != m_cachedIdByItem.end() && prev->second != aItem->m_Uuid )
1936 {
1937 auto prevIt = m_itemByIdCache.find( prev->second );
1938
1939 if( prevIt != m_itemByIdCache.end() && prevIt->second == aItem )
1940 m_itemByIdCache.erase( prevIt );
1941 }
1942
1943 if( auto existing = m_itemByIdCache.find( aItem->m_Uuid );
1944 existing != m_itemByIdCache.end() && existing->second != aItem )
1945 {
1946 if( auto prev = m_cachedIdByItem.find( existing->second );
1947 prev != m_cachedIdByItem.end() && prev->second == aItem->m_Uuid )
1948 {
1949 m_cachedIdByItem.erase( prev );
1950 }
1951 }
1952
1953 m_itemByIdCache.insert_or_assign( aItem->m_Uuid, aItem );
1954 m_cachedIdByItem.insert_or_assign( aItem, aItem->m_Uuid );
1955}
1956
1957
1958void BOARD::UncacheItemById( const KIID& aId ) const
1959{
1960 auto it = m_itemByIdCache.find( aId );
1961
1962 if( it == m_itemByIdCache.end() )
1963 return;
1964
1965 const BOARD_ITEM* item = it->second;
1966
1967 m_itemByIdCache.erase( it );
1968
1969 if( auto cached = m_cachedIdByItem.find( item );
1970 cached != m_cachedIdByItem.end() && cached->second == aId )
1971 {
1972 m_cachedIdByItem.erase( cached );
1973 }
1974}
1975
1976
1978{
1979 if( auto prev = m_cachedIdByItem.find( aItem );
1980 prev != m_cachedIdByItem.end() && prev->second != aId )
1981 {
1982 auto prevIt = m_itemByIdCache.find( prev->second );
1983
1984 if( prevIt != m_itemByIdCache.end() && prevIt->second == aItem )
1985 m_itemByIdCache.erase( prevIt );
1986 }
1987
1988 if( auto existing = m_itemByIdCache.find( aId );
1989 existing != m_itemByIdCache.end() && existing->second != aItem )
1990 {
1991 if( auto prev = m_cachedIdByItem.find( existing->second );
1992 prev != m_cachedIdByItem.end() && prev->second == aId )
1993 {
1994 m_cachedIdByItem.erase( prev );
1995 }
1996 }
1997
1998 m_itemByIdCache.insert_or_assign( aId, aItem );
1999 m_cachedIdByItem.insert_or_assign( aItem, aId );
2000
2001 return aItem;
2002}
2003
2004
2006{
2007 if( auto cached = m_cachedIdByItem.find( aItem ); cached != m_cachedIdByItem.end() )
2008 {
2009 auto it = m_itemByIdCache.find( cached->second );
2010
2011 if( it != m_itemByIdCache.end() && it->second == aItem )
2012 m_itemByIdCache.erase( it );
2013
2014 m_cachedIdByItem.erase( cached );
2015 return;
2016 }
2017
2018 for( auto it = m_itemByIdCache.begin(); it != m_itemByIdCache.end(); )
2019 {
2020 if( it->second == aItem )
2021 it = m_itemByIdCache.erase( it );
2022 else
2023 ++it;
2024 }
2025}
2026
2027
2028void BOARD::RebindItemUuid( BOARD_ITEM* aItem, const KIID& aNewId )
2029{
2030 wxCHECK_RET( aItem, "BOARD::RebindItemUuid() requires a valid item" );
2031
2032 if( IsFootprintHolder() )
2033 return;
2034
2035 if( aItem->m_Uuid == aNewId )
2036 {
2037 CacheAndReturnItemById( aNewId, aItem );
2038 return;
2039 }
2040
2041 if( BOARD_ITEM* existing = GetCachedItemById( aNewId ); existing && existing != aItem )
2042 {
2043 wxFAIL_MSG( wxString::Format( "BOARD::RebindItemUuid() duplicate target UUID: %s",
2044 aNewId.AsString() ) );
2045 return;
2046 }
2047
2048 UncacheItemByPtr( aItem );
2049 aItem->SetUuidDirect( aNewId );
2050 CacheAndReturnItemById( aNewId, aItem );
2051}
2052
2053
2055{
2056 std::set<KIID> ids;
2057 int duplicates = 0;
2058
2059 auto processItem =
2060 [&]( BOARD_ITEM* aItem )
2061 {
2062 wxCHECK2( aItem, return );
2063
2064 if( ids.count( aItem->m_Uuid ) )
2065 {
2066 duplicates++;
2067 RebindItemUuid( aItem, KIID() );
2068 }
2069
2070 ids.insert( aItem->m_Uuid );
2071 };
2072
2073 // Footprint IDs are the most important, so give them the first crack at "claiming" a
2074 // particular KIID.
2075 for( FOOTPRINT* footprint : Footprints() )
2076 processItem( footprint );
2077
2078 // After that the principal use is for DRC marker pointers, which are most likely to pads
2079 // or tracks.
2080 for( FOOTPRINT* footprint : Footprints() )
2081 {
2082 for( PAD* pad : footprint->Pads() )
2083 processItem( pad );
2084 }
2085
2086 for( PCB_TRACK* track : Tracks() )
2087 processItem( track );
2088
2089 // From here out I don't think order matters much.
2090 for( FOOTPRINT* footprint : Footprints() )
2091 {
2092 processItem( &footprint->Reference() );
2093 processItem( &footprint->Value() );
2094
2095 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2096 processItem( item );
2097
2098 for( ZONE* zone : footprint->Zones() )
2099 processItem( zone );
2100
2101 for( PCB_GROUP* group : footprint->Groups() )
2102 processItem( group );
2103 }
2104
2105 // Everything owned by the board not handled above.
2106 for( BOARD_ITEM* item : GetItemSet() )
2107 {
2108 // Top-level footprints and tracks were handled above.
2109 switch( item->Type() )
2110 {
2111 case PCB_FOOTPRINT_T:
2112 case PCB_TRACE_T:
2113 case PCB_ARC_T:
2114 case PCB_VIA_T:
2115 break;
2116
2117 default:
2118 processItem( item );
2119 break;
2120 }
2121 }
2122
2123 return duplicates;
2124}
2125
2126
2127void BOARD::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
2128{
2129 // the board itself
2130 aMap[m_Uuid] = this;
2131
2132 for( PCB_TRACK* track : Tracks() )
2133 aMap[track->m_Uuid] = track;
2134
2135 for( FOOTPRINT* footprint : Footprints() )
2136 {
2137 aMap[footprint->m_Uuid] = footprint;
2138
2139 for( PAD* pad : footprint->Pads() )
2140 aMap[pad->m_Uuid] = pad;
2141
2142 aMap[footprint->Reference().m_Uuid] = &footprint->Reference();
2143 aMap[footprint->Value().m_Uuid] = &footprint->Value();
2144
2145 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2146 aMap[drawing->m_Uuid] = drawing;
2147 }
2148
2149 for( ZONE* zone : Zones() )
2150 aMap[zone->m_Uuid] = zone;
2151
2152 for( BOARD_ITEM* drawing : Drawings() )
2153 aMap[drawing->m_Uuid] = drawing;
2154
2155 for( PCB_MARKER* marker : m_markers )
2156 aMap[marker->m_Uuid] = marker;
2157
2158 for( PCB_GROUP* group : m_groups )
2159 aMap[group->m_Uuid] = group;
2160
2161 for( PCB_POINT* point : m_points )
2162 aMap[point->m_Uuid] = point;
2163
2164 for( PCB_GENERATOR* generator : m_generators )
2165 aMap[generator->m_Uuid] = generator;
2166}
2167
2168
2169wxString BOARD::ConvertCrossReferencesToKIIDs( const wxString& aSource ) const
2170{
2171 wxString newbuf;
2172 size_t sourceLen = aSource.length();
2173
2174 for( size_t i = 0; i < sourceLen; ++i )
2175 {
2176 // Check for escaped expressions: \${ or \@{
2177 // These should be copied verbatim without any ref→KIID conversion
2178 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2179 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2180 {
2181 // Copy the escape sequence and the entire escaped expression
2182 newbuf.append( aSource[i] ); // backslash
2183 newbuf.append( aSource[i + 1] ); // $ or @
2184 newbuf.append( aSource[i + 2] ); // {
2185 i += 2;
2186
2187 // Find and copy everything until the matching closing brace
2188 int braceDepth = 1;
2189 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2190 {
2191 if( aSource[i] == '{' )
2192 braceDepth++;
2193 else if( aSource[i] == '}' )
2194 braceDepth--;
2195
2196 newbuf.append( aSource[i] );
2197 }
2198 i--; // Back up one since the for loop will increment
2199 continue;
2200 }
2201
2202 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2203 {
2204 wxString token;
2205 bool isCrossRef = false;
2206
2207 for( i = i + 2; i < sourceLen; ++i )
2208 {
2209 if( aSource[i] == '}' )
2210 break;
2211
2212 if( aSource[i] == ':' )
2213 isCrossRef = true;
2214
2215 token.append( aSource[i] );
2216 }
2217
2218 if( isCrossRef )
2219 {
2220 wxString remainder;
2221 wxString ref = token.BeforeFirst( ':', &remainder );
2222
2223 for( const FOOTPRINT* footprint : Footprints() )
2224 {
2225 if( footprint->GetReference().CmpNoCase( ref ) == 0 )
2226 {
2227 wxString test( remainder );
2228
2229 if( footprint->ResolveTextVar( &test ) )
2230 token = footprint->m_Uuid.AsString() + wxT( ":" ) + remainder;
2231
2232 break;
2233 }
2234 }
2235 }
2236
2237 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2238 }
2239 else
2240 {
2241 newbuf.append( aSource[i] );
2242 }
2243 }
2244
2245 return newbuf;
2246}
2247
2248
2249wxString BOARD::ConvertKIIDsToCrossReferences( const wxString& aSource ) const
2250{
2251 wxString newbuf;
2252 size_t sourceLen = aSource.length();
2253
2254 for( size_t i = 0; i < sourceLen; ++i )
2255 {
2256 // Check for escaped expressions: \${ or \@{
2257 // These should be copied verbatim without any KIID→ref conversion
2258 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2259 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2260 {
2261 // Copy the escape sequence and the entire escaped expression
2262 newbuf.append( aSource[i] ); // backslash
2263 newbuf.append( aSource[i + 1] ); // $ or @
2264 newbuf.append( aSource[i + 2] ); // {
2265 i += 2;
2266
2267 // Find and copy everything until the matching closing brace
2268 int braceDepth = 1;
2269 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2270 {
2271 if( aSource[i] == '{' )
2272 braceDepth++;
2273 else if( aSource[i] == '}' )
2274 braceDepth--;
2275
2276 newbuf.append( aSource[i] );
2277 }
2278 i--; // Back up one since the for loop will increment
2279 continue;
2280 }
2281
2282 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2283 {
2284 wxString token;
2285 bool isCrossRef = false;
2286
2287 for( i = i + 2; i < sourceLen; ++i )
2288 {
2289 if( aSource[i] == '}' )
2290 break;
2291
2292 if( aSource[i] == ':' )
2293 isCrossRef = true;
2294
2295 token.append( aSource[i] );
2296 }
2297
2298 if( isCrossRef )
2299 {
2300 wxString remainder;
2301 wxString ref = token.BeforeFirst( ':', &remainder );
2302 BOARD_ITEM* refItem = ResolveItem( KIID( ref ), true );
2303
2304 if( refItem && refItem->Type() == PCB_FOOTPRINT_T )
2305 {
2306 token = static_cast<FOOTPRINT*>( refItem )->GetReference() + wxT( ":" ) + remainder;
2307 }
2308 }
2309
2310 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2311 }
2312 else
2313 {
2314 newbuf.append( aSource[i] );
2315 }
2316 }
2317
2318 return newbuf;
2319}
2320
2321
2322unsigned BOARD::GetNodesCount( int aNet ) const
2323{
2324 unsigned retval = 0;
2325
2326 for( FOOTPRINT* footprint : Footprints() )
2327 {
2328 for( PAD* pad : footprint->Pads() )
2329 {
2330 if( ( aNet == -1 && pad->GetNetCode() > 0 ) || aNet == pad->GetNetCode() )
2331 retval++;
2332 }
2333 }
2334
2335 return retval;
2336}
2337
2338
2339BOX2I BOARD::ComputeBoundingBox( bool aBoardEdgesOnly, bool aPhysicalLayersOnly ) const
2340{
2341 BOX2I bbox;
2342 LSET visible = GetVisibleLayers();
2343
2344 if( aPhysicalLayersOnly )
2345 visible &= LSET::PhysicalLayersMask();
2346
2347 // If the board is just showing a footprint, we want all footprint layers included in the
2348 // bounding box
2349 if( IsFootprintHolder() )
2350 visible.set();
2351
2352 if( aBoardEdgesOnly )
2353 visible.set( Edge_Cuts );
2354
2355 // Check shapes, dimensions, texts, and fiducials
2356 for( BOARD_ITEM* item : m_drawings )
2357 {
2358 if( aBoardEdgesOnly && ( item->GetLayer() != Edge_Cuts || item->Type() != PCB_SHAPE_T ) )
2359 continue;
2360
2361 if( ( item->GetLayerSet() & visible ).any() )
2362 bbox.Merge( item->GetBoundingBox() );
2363 }
2364
2365 // Check footprints
2366 for( FOOTPRINT* footprint : m_footprints )
2367 {
2368 if( aBoardEdgesOnly )
2369 {
2370 for( const BOARD_ITEM* edge : footprint->GraphicalItems() )
2371 {
2372 if( edge->GetLayer() == Edge_Cuts && edge->Type() == PCB_SHAPE_T )
2373 bbox.Merge( edge->GetBoundingBox() );
2374 }
2375 }
2376 else if( ( footprint->GetLayerSet() & visible ).any() )
2377 {
2378 bbox.Merge( footprint->GetBoundingBox( true ) );
2379 }
2380 }
2381
2382 if( !aBoardEdgesOnly )
2383 {
2384 // Check tracks
2385 for( PCB_TRACK* track : m_tracks )
2386 {
2387 if( ( track->GetLayerSet() & visible ).any() )
2388 bbox.Merge( track->GetBoundingBox() );
2389 }
2390
2391 // Check zones
2392 for( ZONE* aZone : m_zones )
2393 {
2394 if( ( aZone->GetLayerSet() & visible ).any() )
2395 bbox.Merge( aZone->GetBoundingBox() );
2396 }
2397
2398 for( PCB_POINT* point : m_points )
2399 {
2400 bbox.Merge( point->GetBoundingBox() );
2401 }
2402 }
2403
2404 return bbox;
2405}
2406
2407
2408void BOARD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2409{
2410 int padCount = 0;
2411 int viaCount = 0;
2412 int trackSegmentCount = 0;
2413 std::set<int> netCodes;
2414 int unconnected = GetConnectivity()->GetUnconnectedCount( true );
2415
2416 for( PCB_TRACK* item : m_tracks )
2417 {
2418 if( item->Type() == PCB_VIA_T )
2419 viaCount++;
2420 else
2421 trackSegmentCount++;
2422
2423 if( item->GetNetCode() > 0 )
2424 netCodes.insert( item->GetNetCode() );
2425 }
2426
2427 for( FOOTPRINT* footprint : Footprints() )
2428 {
2429 for( PAD* pad : footprint->Pads() )
2430 {
2431 padCount++;
2432
2433 if( pad->GetNetCode() > 0 )
2434 netCodes.insert( pad->GetNetCode() );
2435 }
2436 }
2437
2438 aList.emplace_back( _( "Pads" ), wxString::Format( wxT( "%d" ), padCount ) );
2439 aList.emplace_back( _( "Vias" ), wxString::Format( wxT( "%d" ), viaCount ) );
2440 aList.emplace_back( _( "Track Segments" ), wxString::Format( wxT( "%d" ), trackSegmentCount ) );
2441 aList.emplace_back( _( "Nets" ), wxString::Format( wxT( "%d" ), (int) netCodes.size() ) );
2442 aList.emplace_back( _( "Unrouted" ), wxString::Format( wxT( "%d" ), unconnected ) );
2443}
2444
2445
2446INSPECT_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const std::vector<KICAD_T>& scanTypes )
2447{
2448#if 0 && defined( DEBUG )
2449 std::cout << GetClass().mb_str() << ' ';
2450#endif
2451
2452 bool footprintsScanned = false;
2453 bool drawingsScanned = false;
2454 bool tracksScanned = false;
2455
2456 for( KICAD_T scanType : scanTypes )
2457 {
2458 switch( scanType )
2459 {
2460 case PCB_T:
2461 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
2462 return INSPECT_RESULT::QUIT;
2463
2464 break;
2465
2466 /*
2467 * Instances of the requested KICAD_T live in a list, either one that I manage, or one
2468 * that my footprints manage. If it's a type managed by class FOOTPRINT, then simply
2469 * pass it on to each footprint's Visit() function via IterateForward( m_footprints, ... ).
2470 */
2471
2472 case PCB_FOOTPRINT_T:
2473 case PCB_PAD_T:
2474 case PCB_SHAPE_T:
2476 case PCB_FIELD_T:
2477 case PCB_TEXT_T:
2478 case PCB_TEXTBOX_T:
2479 case PCB_TABLE_T:
2480 case PCB_TABLECELL_T:
2481 case PCB_DIM_ALIGNED_T:
2482 case PCB_DIM_CENTER_T:
2483 case PCB_DIM_RADIAL_T:
2485 case PCB_DIM_LEADER_T:
2486 case PCB_TARGET_T:
2487 case PCB_BARCODE_T:
2488 if( !footprintsScanned )
2489 {
2490 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2491 {
2492 return INSPECT_RESULT::QUIT;
2493 }
2494
2495 footprintsScanned = true;
2496 }
2497
2498 if( !drawingsScanned )
2499 {
2500 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2501 {
2502 return INSPECT_RESULT::QUIT;
2503 }
2504
2505 drawingsScanned = true;
2506 }
2507
2508 break;
2509
2510 case PCB_VIA_T:
2511 case PCB_TRACE_T:
2512 case PCB_ARC_T:
2513 if( !tracksScanned )
2514 {
2515 if( IterateForward<PCB_TRACK*>( m_tracks, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2516 {
2517 return INSPECT_RESULT::QUIT;
2518 }
2519
2520 tracksScanned = true;
2521 }
2522
2523 break;
2524
2525 case PCB_MARKER_T:
2526 for( PCB_MARKER* marker : m_markers )
2527 {
2528 if( marker->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2529 return INSPECT_RESULT::QUIT;
2530 }
2531
2532 break;
2533
2534 case PCB_POINT_T:
2535 for( PCB_POINT* point : m_points )
2536 {
2537 if( point->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2538 return INSPECT_RESULT::QUIT;
2539 }
2540
2541 break;
2542
2543 case PCB_ZONE_T:
2544 if( !footprintsScanned )
2545 {
2546 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2547 {
2548 return INSPECT_RESULT::QUIT;
2549 }
2550
2551 footprintsScanned = true;
2552 }
2553
2554 for( ZONE* zone : m_zones )
2555 {
2556 if( zone->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2557 return INSPECT_RESULT::QUIT;
2558 }
2559
2560 break;
2561
2562 case PCB_GENERATOR_T:
2563 if( !footprintsScanned )
2564 {
2565 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2566 {
2567 return INSPECT_RESULT::QUIT;
2568 }
2569
2570 footprintsScanned = true;
2571 }
2572
2573 if( IterateForward<PCB_GENERATOR*>( m_generators, inspector, testData, { scanType } )
2575 {
2576 return INSPECT_RESULT::QUIT;
2577 }
2578
2579 break;
2580
2581 case PCB_GROUP_T:
2582 if( IterateForward<PCB_GROUP*>( m_groups, inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2583 {
2584 return INSPECT_RESULT::QUIT;
2585 }
2586
2587 break;
2588
2589 default: break;
2590 }
2591 }
2592
2594}
2595
2596
2597NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const
2598{
2599 // the first valid netcode is 1 and the last is m_NetInfo.GetCount()-1.
2600 // zero is reserved for "no connection" and is not actually a net.
2601 // nullptr is returned for non valid netcodes
2602
2603 if( aNetcode == NETINFO_LIST::UNCONNECTED && m_NetInfo.GetNetCount() == 0 )
2605 else
2606 return m_NetInfo.GetNetItem( aNetcode );
2607}
2608
2609
2610NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
2611{
2612 return m_NetInfo.GetNetItem( aNetname );
2613}
2614
2615
2616int BOARD::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet )
2617{
2618 int rv = 0;
2619 int count = 0;
2620
2621 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
2622 {
2623 int ch = *it;
2624
2625 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
2626 {
2627 continue;
2628 }
2629 else if( ch == '+' )
2630 {
2631 aComplementNet = wxT( "-" );
2632 rv = 1;
2633 }
2634 else if( ch == '-' )
2635 {
2636 aComplementNet = wxT( "+" );
2637 rv = -1;
2638 }
2639 else if( ch == 'N' )
2640 {
2641 aComplementNet = wxT( "P" );
2642 rv = -1;
2643 }
2644 else if( ch == 'P' )
2645 {
2646 aComplementNet = wxT( "N" );
2647 rv = 1;
2648 }
2649 else
2650 {
2651 break;
2652 }
2653 }
2654
2655 if( rv != 0 && count >= 1 )
2656 {
2657 aComplementNet = aNetName.Left( aNetName.length() - count ) + aComplementNet + aNetName.Right( count - 1 );
2658 }
2659
2660 return rv;
2661}
2662
2663
2665{
2666 if( aNet )
2667 {
2668 wxString refName = aNet->GetNetname();
2669 wxString coupledNetName;
2670
2671 if( MatchDpSuffix( refName, coupledNetName ) )
2672 return FindNet( coupledNetName );
2673 }
2674
2675 return nullptr;
2676}
2677
2678
2679FOOTPRINT* BOARD::FindFootprintByReference( const wxString& aReference ) const
2680{
2681 for( FOOTPRINT* footprint : m_footprints )
2682 {
2683 if( aReference == footprint->GetReference() )
2684 return footprint;
2685 }
2686
2687 return nullptr;
2688}
2689
2690
2692{
2693 for( FOOTPRINT* footprint : m_footprints )
2694 {
2695 if( footprint->GetPath() == aPath )
2696 return footprint;
2697 }
2698
2699 return nullptr;
2700}
2701
2702
2704{
2705 std::set<wxString> names;
2706
2707 for( const NETINFO_ITEM* net : m_NetInfo )
2708 {
2709 if( !net->GetNetname().IsEmpty() )
2710 names.insert( net->GetNetname() );
2711 }
2712
2713 return names;
2714}
2715
2716
2718{
2719 if( m_project && !m_project->IsNullProject() )
2720 SetProperties( m_project->GetTextVars() );
2721}
2722
2723
2724static wxString FindVariantNameCaseInsensitive( const std::vector<wxString>& aNames,
2725 const wxString& aVariantName )
2726{
2727 for( const wxString& name : aNames )
2728 {
2729 if( name.CmpNoCase( aVariantName ) == 0 )
2730 return name;
2731 }
2732
2733 return wxEmptyString;
2734}
2735
2736
2737void BOARD::SetCurrentVariant( const wxString& aVariant )
2738{
2739 const wxString previous = m_currentVariant;
2740
2741 if( aVariant.IsEmpty() || aVariant.CmpNoCase( GetDefaultVariantName() ) == 0 )
2742 {
2743 m_currentVariant.Clear();
2744 }
2745 else
2746 {
2747 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariant );
2748
2749 if( actualName.IsEmpty() )
2750 m_currentVariant.Clear();
2751 else
2752 m_currentVariant = actualName;
2753 }
2754
2755 // Variant overrides on footprint fields change `${REFDES:FIELD}` resolution,
2756 // so every cross-ref dependent must repaint on switch. Skip the fan-out if
2757 // the active variant did not actually change (e.g. redundant UI callback).
2758 if( previous != m_currentVariant && m_textVarAdapter )
2759 m_textVarAdapter->Tracker().InvalidateVariantScoped();
2760}
2761
2762
2763bool BOARD::HasVariant( const wxString& aVariantName ) const
2764{
2765 return !FindVariantNameCaseInsensitive( m_variantNames, aVariantName ).IsEmpty();
2766}
2767
2768
2769void BOARD::AddVariant( const wxString& aVariantName )
2770{
2771 if( aVariantName.IsEmpty()
2772 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0
2773 || HasVariant( aVariantName ) )
2774 return;
2775
2776 m_variantNames.push_back( aVariantName );
2777}
2778
2779
2780void BOARD::DeleteVariant( const wxString& aVariantName )
2781{
2782 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2783 return;
2784
2785 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
2786 [&]( const wxString& name )
2787 {
2788 return name.CmpNoCase( aVariantName ) == 0;
2789 } );
2790
2791 if( it != m_variantNames.end() )
2792 {
2793 wxString actualName = *it;
2794 m_variantNames.erase( it );
2795 m_variantDescriptions.erase( actualName );
2796
2797 // Clear current variant if it was the deleted one
2798 if( m_currentVariant.CmpNoCase( aVariantName ) == 0 )
2799 m_currentVariant.Clear();
2800
2801 // Remove variant from all footprints
2802 for( FOOTPRINT* fp : m_footprints )
2803 fp->DeleteVariant( actualName );
2804 }
2805}
2806
2807
2808void BOARD::RenameVariant( const wxString& aOldName, const wxString& aNewName )
2809{
2810 if( aNewName.IsEmpty() || aNewName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2811 return;
2812
2813 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
2814 [&]( const wxString& name )
2815 {
2816 return name.CmpNoCase( aOldName ) == 0;
2817 } );
2818
2819 if( it != m_variantNames.end() )
2820 {
2821 wxString actualOldName = *it;
2822
2823 // Check if new name already exists (case-insensitive) and isn't the same variant
2824 wxString existingName = FindVariantNameCaseInsensitive( m_variantNames, aNewName );
2825
2826 if( !existingName.IsEmpty() && existingName.CmpNoCase( actualOldName ) != 0 )
2827 return;
2828
2829 if( actualOldName == aNewName )
2830 return;
2831
2832 *it = aNewName;
2833
2834 // Transfer description
2835 auto descIt = m_variantDescriptions.find( actualOldName );
2836
2837 if( descIt != m_variantDescriptions.end() )
2838 {
2839 if( !descIt->second.IsEmpty() )
2840 m_variantDescriptions[aNewName] = descIt->second;
2841
2842 m_variantDescriptions.erase( descIt );
2843 }
2844
2845 // Update current variant if it was the renamed one
2846 if( m_currentVariant.CmpNoCase( aOldName ) == 0 )
2847 m_currentVariant = aNewName;
2848
2849 // Rename variant in all footprints
2850 for( FOOTPRINT* fp : m_footprints )
2851 fp->RenameVariant( actualOldName, aNewName );
2852 }
2853}
2854
2855
2856wxString BOARD::GetVariantDescription( const wxString& aVariantName ) const
2857{
2858 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2859 return wxEmptyString;
2860
2861 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
2862
2863 if( actualName.IsEmpty() )
2864 return wxEmptyString;
2865
2866 auto it = m_variantDescriptions.find( actualName );
2867
2868 if( it != m_variantDescriptions.end() )
2869 return it->second;
2870
2871 return wxEmptyString;
2872}
2873
2874
2875void BOARD::SetVariantDescription( const wxString& aVariantName, const wxString& aDescription )
2876{
2877 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2878 return;
2879
2880 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
2881
2882 if( actualName.IsEmpty() )
2883 return;
2884
2885 if( aDescription.IsEmpty() )
2886 m_variantDescriptions.erase( actualName );
2887 else
2888 m_variantDescriptions[actualName] = aDescription;
2889}
2890
2891
2892wxArrayString BOARD::GetVariantNamesForUI() const
2893{
2894 wxArrayString names;
2895 names.Add( GetDefaultVariantName() );
2896
2897 for( const wxString& name : m_variantNames )
2898 names.Add( name );
2899
2900 names.Sort( SortVariantNames );
2901
2902 return names;
2903}
2904
2905
2907{
2908 m_lengthDelayCalc->SynchronizeTuningProfileProperties();
2909}
2910
2911
2912void BOARD::SynchronizeNetsAndNetClasses( bool aResetTrackAndViaSizes )
2913{
2914 if( !m_project )
2915 return;
2916
2918 const std::shared_ptr<NETCLASS>& defaultNetClass = bds.m_NetSettings->GetDefaultNetclass();
2919
2921
2922 for( NETINFO_ITEM* net : m_NetInfo )
2923 net->SetNetClass( bds.m_NetSettings->GetEffectiveNetClass( net->GetNetname() ) );
2924
2925 if( aResetTrackAndViaSizes )
2926 {
2927 // Set initial values for custom track width & via size to match the default
2928 // netclass settings
2929 bds.UseCustomTrackViaSize( false );
2930 bds.SetCustomTrackWidth( defaultNetClass->GetTrackWidth() );
2931 bds.SetCustomViaSize( defaultNetClass->GetViaDiameter() );
2932 bds.SetCustomViaDrill( defaultNetClass->GetViaDrill() );
2933 bds.SetCustomDiffPairWidth( defaultNetClass->GetDiffPairWidth() );
2934 bds.SetCustomDiffPairGap( defaultNetClass->GetDiffPairGap() );
2935 bds.SetCustomDiffPairViaGap( defaultNetClass->GetDiffPairViaGap() );
2936 }
2937
2939}
2940
2941
2942bool BOARD::SynchronizeComponentClasses( const std::unordered_set<wxString>& aNewSheetPaths ) const
2943{
2944 std::shared_ptr<COMPONENT_CLASS_SETTINGS> settings = GetProject()->GetProjectFile().ComponentClassSettings();
2945
2946 return m_componentClassManager->SyncDynamicComponentClassAssignments(
2947 settings->GetComponentClassAssignments(), settings->GetEnableSheetComponentClasses(), aNewSheetPaths );
2948}
2949
2950
2952{
2953 int error_count = 0;
2954
2955 for( ZONE* zone : Zones() )
2956 {
2957 if( !zone->IsOnCopperLayer() )
2958 {
2959 zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
2960 continue;
2961 }
2962
2963 if( zone->GetNetCode() != 0 ) // i.e. if this zone is connected to a net
2964 {
2965 const NETINFO_ITEM* net = zone->GetNet();
2966
2967 if( net )
2968 {
2969 zone->SetNetCode( net->GetNetCode() );
2970 }
2971 else
2972 {
2973 error_count++;
2974
2975 // keep Net Name and set m_NetCode to -1 : error flag.
2976 zone->SetNetCode( -1 );
2977 }
2978 }
2979 }
2980
2981 return error_count;
2982}
2983
2984
2985PAD* BOARD::GetPad( const VECTOR2I& aPosition, const LSET& aLayerSet ) const
2986{
2987 for( FOOTPRINT* footprint : m_footprints )
2988 {
2989 PAD* pad = nullptr;
2990
2991 if( footprint->HitTest( aPosition ) )
2992 pad = footprint->GetPad( aPosition, aLayerSet.any() ? aLayerSet : LSET::AllCuMask() );
2993
2994 if( pad )
2995 return pad;
2996 }
2997
2998 return nullptr;
2999}
3000
3001
3002PAD* BOARD::GetPad( const PCB_TRACK* aTrace, ENDPOINT_T aEndPoint ) const
3003{
3004 const VECTOR2I& aPosition = aTrace->GetEndPoint( aEndPoint );
3005
3006 LSET lset( { aTrace->GetLayer() } );
3007
3008 return GetPad( aPosition, lset );
3009}
3010
3011
3012PAD* BOARD::GetPad( std::vector<PAD*>& aPadList, const VECTOR2I& aPosition, const LSET& aLayerSet ) const
3013{
3014 // Search aPadList for aPosition
3015 // aPadList is sorted by X then Y values, and a fast binary search is used
3016 int idxmax = aPadList.size() - 1;
3017
3018 int delta = aPadList.size();
3019
3020 int idx = 0; // Starting index is the beginning of list
3021
3022 while( delta )
3023 {
3024 // Calculate half size of remaining interval to test.
3025 // Ensure the computed value is not truncated (too small)
3026 if( ( delta & 1 ) && ( delta > 1 ) )
3027 delta++;
3028
3029 delta /= 2;
3030
3031 PAD* pad = aPadList[idx];
3032
3033 if( pad->GetPosition() == aPosition ) // candidate found
3034 {
3035 // The pad must match the layer mask:
3036 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3037 return pad;
3038
3039 // More than one pad can be at aPosition
3040 // search for a pad at aPosition that matched this mask
3041
3042 // search next
3043 for( int ii = idx + 1; ii <= idxmax; ii++ )
3044 {
3045 pad = aPadList[ii];
3046
3047 if( pad->GetPosition() != aPosition )
3048 break;
3049
3050 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3051 return pad;
3052 }
3053 // search previous
3054 for( int ii = idx - 1; ii >= 0; ii-- )
3055 {
3056 pad = aPadList[ii];
3057
3058 if( pad->GetPosition() != aPosition )
3059 break;
3060
3061 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3062 return pad;
3063 }
3064
3065 // Not found:
3066 return nullptr;
3067 }
3068
3069 if( pad->GetPosition().x == aPosition.x ) // Must search considering Y coordinate
3070 {
3071 if( pad->GetPosition().y < aPosition.y ) // Must search after this item
3072 {
3073 idx += delta;
3074
3075 if( idx > idxmax )
3076 idx = idxmax;
3077 }
3078 else // Must search before this item
3079 {
3080 idx -= delta;
3081
3082 if( idx < 0 )
3083 idx = 0;
3084 }
3085 }
3086 else if( pad->GetPosition().x < aPosition.x ) // Must search after this item
3087 {
3088 idx += delta;
3089
3090 if( idx > idxmax )
3091 idx = idxmax;
3092 }
3093 else // Must search before this item
3094 {
3095 idx -= delta;
3096
3097 if( idx < 0 )
3098 idx = 0;
3099 }
3100 }
3101
3102 return nullptr;
3103}
3104
3105
3111bool sortPadsByXthenYCoord( PAD* const& aLH, PAD* const& aRH )
3112{
3113 if( aLH->GetPosition().x == aRH->GetPosition().x )
3114 return aLH->GetPosition().y < aRH->GetPosition().y;
3115
3116 return aLH->GetPosition().x < aRH->GetPosition().x;
3117}
3118
3119
3120void BOARD::GetSortedPadListByXthenYCoord( std::vector<PAD*>& aVector, int aNetCode ) const
3121{
3122 for( FOOTPRINT* footprint : Footprints() )
3123 {
3124 for( PAD* pad : footprint->Pads() )
3125 {
3126 if( aNetCode < 0 || pad->GetNetCode() == aNetCode )
3127 aVector.push_back( pad );
3128 }
3129 }
3130
3131 std::sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
3132}
3133
3134
3136{
3137 if( GetDesignSettings().m_HasStackup )
3139
3140 BOARD_STACKUP stackup;
3142 return stackup;
3143}
3144
3145
3146std::tuple<int, double, double, double, double> BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const
3147{
3148 std::shared_ptr<CONNECTIVITY_DATA> connectivity = GetBoard()->GetConnectivity();
3149 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items;
3150
3151 for( BOARD_CONNECTED_ITEM* boardItem : connectivity->GetConnectedItems( &aTrack, EXCLUDE_ZONES ) )
3152 {
3154
3155 if( item.Type() != LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
3156 items.push_back( std::move( item ) );
3157 }
3158
3159 constexpr PATH_OPTIMISATIONS opts = {
3160 .OptimiseVias = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false
3161 };
3163 items, opts, nullptr, nullptr, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL,
3165
3166 return std::make_tuple( items.size(), details.TrackLength + details.ViaLength, details.PadToDieLength,
3167 details.TrackDelay + details.ViaDelay, details.PadToDieDelay );
3168}
3169
3170
3171FOOTPRINT* BOARD::GetFootprint( const VECTOR2I& aPosition, PCB_LAYER_ID aActiveLayer, bool aVisibleOnly,
3172 bool aIgnoreLocked ) const
3173{
3174 FOOTPRINT* footprint = nullptr;
3175 FOOTPRINT* alt_footprint = nullptr;
3176 int min_dim = 0x7FFFFFFF;
3177 int alt_min_dim = 0x7FFFFFFF;
3178 bool current_layer_back = IsBackLayer( aActiveLayer );
3179
3180 for( FOOTPRINT* candidate : m_footprints )
3181 {
3182 // is the ref point within the footprint's bounds?
3183 if( !candidate->HitTest( aPosition ) )
3184 continue;
3185
3186 // if caller wants to ignore locked footprints, and this one is locked, skip it.
3187 if( aIgnoreLocked && candidate->IsLocked() )
3188 continue;
3189
3190 PCB_LAYER_ID layer = candidate->GetLayer();
3191
3192 // Filter non visible footprints if requested
3193 if( !aVisibleOnly || IsFootprintLayerVisible( layer ) )
3194 {
3195 BOX2I bb = candidate->GetBoundingBox( false );
3196
3197 int offx = bb.GetX() + bb.GetWidth() / 2;
3198 int offy = bb.GetY() + bb.GetHeight() / 2;
3199
3200 // off x & offy point to the middle of the box.
3201 int dist =
3202 ( aPosition.x - offx ) * ( aPosition.x - offx ) + ( aPosition.y - offy ) * ( aPosition.y - offy );
3203
3204 if( current_layer_back == IsBackLayer( layer ) )
3205 {
3206 if( dist <= min_dim )
3207 {
3208 // better footprint shown on the active side
3209 footprint = candidate;
3210 min_dim = dist;
3211 }
3212 }
3213 else if( aVisibleOnly && IsFootprintLayerVisible( layer ) )
3214 {
3215 if( dist <= alt_min_dim )
3216 {
3217 // better footprint shown on the other side
3218 alt_footprint = candidate;
3219 alt_min_dim = dist;
3220 }
3221 }
3222 }
3223 }
3224
3225 if( footprint )
3226 return footprint;
3227
3228 if( alt_footprint )
3229 return alt_footprint;
3230
3231 return nullptr;
3232}
3233
3234
3235std::list<ZONE*> BOARD::GetZoneList( bool aIncludeZonesInFootprints ) const
3236{
3237 std::list<ZONE*> zones;
3238
3239 for( ZONE* zone : Zones() )
3240 zones.push_back( zone );
3241
3242 if( aIncludeZonesInFootprints )
3243 {
3244 for( FOOTPRINT* footprint : m_footprints )
3245 {
3246 for( ZONE* zone : footprint->Zones() )
3247 zones.push_back( zone );
3248 }
3249 }
3250
3251 return zones;
3252}
3253
3254
3255ZONE* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, PCB_LAYER_ID aLayer, VECTOR2I aStartPointPosition,
3257{
3258 ZONE* new_area = new ZONE( this );
3259
3260 new_area->SetNetCode( aNetcode );
3261 new_area->SetLayer( aLayer );
3262
3263 m_zones.push_back( new_area );
3264
3265 new_area->SetHatchStyle( (ZONE_BORDER_DISPLAY_STYLE) aHatch );
3266
3267 // Add the first corner to the new zone
3268 new_area->AppendCorner( aStartPointPosition, -1 );
3269
3270 if( aNewZonesList )
3271 {
3272 ITEM_PICKER picker( nullptr, new_area, UNDO_REDO::NEWITEM );
3273 aNewZonesList->PushItem( picker );
3274 }
3275
3276 return new_area;
3277}
3278
3279
3280bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, bool aInferOutlineIfNecessary,
3281 OUTLINE_ERROR_HANDLER* aErrorHandler, bool aAllowUseArcsInPolygons,
3282 bool aIncludeNPTHAsOutlines )
3283{
3284 // max dist from one endPt to next startPt: use the current value
3285 int chainingEpsilon = GetOutlinesChainingEpsilon();
3286
3287 bool success = BuildBoardPolygonOutlines( this, aOutlines, GetDesignSettings().m_MaxError, chainingEpsilon,
3288 aInferOutlineIfNecessary, aErrorHandler, aAllowUseArcsInPolygons );
3289
3290 // Now subtract NPTH oval holes from outlines if required
3291 if( aIncludeNPTHAsOutlines )
3292 {
3293 for( FOOTPRINT* fp : Footprints() )
3294 {
3295 for( PAD* pad : fp->Pads() )
3296 {
3297 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
3298 continue;
3299
3300 SHAPE_POLY_SET hole;
3301 pad->TransformHoleToPolygon( hole, 0, pad->GetMaxError(), ERROR_INSIDE );
3302
3303 if( hole.OutlineCount() > 0 ) // can be not the case for malformed NPTH holes
3304 {
3305 // Issue #20159: BooleanSubtract correctly clips holes extending past board
3306 // edges (common with oval holes near irregular boards). O(n log n) per hole
3307 // vs O(1) for AddHole, but only used for 3D viewer generation, not a hot path.
3308 aOutlines.BooleanSubtract( hole );
3309 }
3310 }
3311 }
3312 }
3313
3314 // Make polygon strictly simple to avoid issues (especially in 3D viewer)
3315 aOutlines.Simplify();
3316
3317 return success;
3318}
3319
3320
3322{
3324 return static_cast<EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3325
3326 return static_cast<EMBEDDED_FILES*>( this );
3327}
3328
3329
3331{
3333 return static_cast<const EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3334
3335 return static_cast<const EMBEDDED_FILES*>( this );
3336}
3337
3338
3339std::set<KIFONT::OUTLINE_FONT*> BOARD::GetFonts() const
3340{
3342
3343 std::set<KIFONT::OUTLINE_FONT*> fonts;
3344
3345 for( BOARD_ITEM* item : Drawings() )
3346 {
3347 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
3348 {
3349 KIFONT::FONT* font = text->GetFont();
3350
3351 if( font && font->IsOutline() )
3352 {
3353 KIFONT::OUTLINE_FONT* outlineFont = static_cast<KIFONT::OUTLINE_FONT*>( font );
3354 PERMISSION permission = outlineFont->GetEmbeddingPermission();
3355
3356 if( permission == PERMISSION::EDITABLE || permission == PERMISSION::INSTALLABLE )
3357 fonts.insert( outlineFont );
3358 }
3359 }
3360 }
3361
3362 return fonts;
3363}
3364
3365
3367{
3368 for( KIFONT::OUTLINE_FONT* font : GetFonts() )
3369 {
3370 EMBEDDED_FILES::EMBEDDED_FILE* file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
3372 }
3373}
3374
3375
3376const std::vector<PAD*> BOARD::GetPads() const
3377{
3378 std::vector<PAD*> allPads;
3379
3380 for( FOOTPRINT* footprint : Footprints() )
3381 {
3382 for( PAD* pad : footprint->Pads() )
3383 allPads.push_back( pad );
3384 }
3385
3386 return allPads;
3387}
3388
3389
3390const std::vector<BOARD_CONNECTED_ITEM*> BOARD::AllConnectedItems()
3391{
3392 std::vector<BOARD_CONNECTED_ITEM*> items;
3393
3394 for( PCB_TRACK* track : Tracks() )
3395 items.push_back( track );
3396
3397 for( FOOTPRINT* footprint : Footprints() )
3398 {
3399 for( PAD* pad : footprint->Pads() )
3400 items.push_back( pad );
3401
3402 for( ZONE* zone : footprint->Zones() )
3403 items.push_back( zone );
3404
3405 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
3406 {
3407 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( dwg ) )
3408 items.push_back( bci );
3409 }
3410 }
3411
3412 for( ZONE* zone : Zones() )
3413 items.push_back( zone );
3414
3415 for( BOARD_ITEM* item : Drawings() )
3416 {
3417 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
3418 items.push_back( bci );
3419 }
3420
3421 return items;
3422}
3423
3424
3425void BOARD::MapNets( BOARD* aDestBoard )
3426{
3428 {
3429 NETINFO_ITEM* netInfo = aDestBoard->FindNet( item->GetNetname() );
3430
3431 if( netInfo )
3432 item->SetNet( netInfo );
3433 else
3434 {
3435 NETINFO_ITEM* newNet = new NETINFO_ITEM( aDestBoard, item->GetNetname() );
3436 aDestBoard->Add( newNet );
3437 item->SetNet( newNet );
3438 }
3439 }
3440}
3441
3442
3444{
3446 {
3447 if( FindNet( item->GetNetCode() ) == nullptr )
3448 item->SetNetCode( NETINFO_LIST::ORPHANED );
3449 }
3450}
3451
3452
3454{
3455 if( !alg::contains( m_listeners, aListener ) )
3456 m_listeners.push_back( aListener );
3457}
3458
3459
3461{
3462 auto i = std::find( m_listeners.begin(), m_listeners.end(), aListener );
3463
3464 if( i != m_listeners.end() )
3465 {
3466 std::iter_swap( i, m_listeners.end() - 1 );
3467 m_listeners.pop_back();
3468 }
3469}
3470
3471
3473{
3474 m_listeners.clear();
3475}
3476
3477
3482
3483
3484void BOARD::OnItemsChanged( std::vector<BOARD_ITEM*>& aItems )
3485{
3487}
3488
3489
3490void BOARD::OnItemsCompositeUpdate( std::vector<BOARD_ITEM*>& aAddedItems, std::vector<BOARD_ITEM*>& aRemovedItems,
3491 std::vector<BOARD_ITEM*>& aChangedItems )
3492{
3493 InvokeListeners( &BOARD_LISTENER::OnBoardCompositeUpdate, *this, aAddedItems, aRemovedItems, aChangedItems );
3494}
3495
3496
3501
3502
3510
3511
3512void BOARD::SetHighLightNet( int aNetCode, bool aMulti )
3513{
3514 if( !m_highLight.m_netCodes.count( aNetCode ) )
3515 {
3516 if( !aMulti )
3517 m_highLight.m_netCodes.clear();
3518
3519 m_highLight.m_netCodes.insert( aNetCode );
3521 }
3522}
3523
3524
3525void BOARD::HighLightON( bool aValue )
3526{
3527 if( m_highLight.m_highLightOn != aValue )
3528 {
3529 m_highLight.m_highLightOn = aValue;
3531 }
3532}
3533
3534
3535wxString BOARD::GroupsSanityCheck( bool repair )
3536{
3537 if( repair )
3538 {
3539 while( GroupsSanityCheckInternal( repair ) != wxEmptyString )
3540 {
3541 };
3542
3543 return wxEmptyString;
3544 }
3545 return GroupsSanityCheckInternal( repair );
3546}
3547
3548
3550{
3551 // Cycle detection
3552 //
3553 // Each group has at most one parent group.
3554 // So we start at group 0 and traverse the parent chain, marking groups seen along the way.
3555 // If we ever see a group that we've already marked, that's a cycle.
3556 // If we reach the end of the chain, we know all groups in that chain are not part of any cycle.
3557 //
3558 // Algorithm below is linear in the # of groups because each group is visited only once.
3559 // There may be extra time taken due to the container access calls and iterators.
3560 //
3561 // Groups we know are cycle free
3562 std::unordered_set<EDA_GROUP*> knownCycleFreeGroups;
3563 // Groups in the current chain we're exploring.
3564 std::unordered_set<EDA_GROUP*> currentChainGroups;
3565 // Groups we haven't checked yet.
3566 std::unordered_set<EDA_GROUP*> toCheckGroups;
3567
3568 // Initialize set of groups and generators to check that could participate in a cycle.
3569 for( PCB_GROUP* group : Groups() )
3570 toCheckGroups.insert( group );
3571
3572 for( PCB_GENERATOR* gen : Generators() )
3573 toCheckGroups.insert( gen );
3574
3575 while( !toCheckGroups.empty() )
3576 {
3577 currentChainGroups.clear();
3578 EDA_GROUP* group = *toCheckGroups.begin();
3579
3580 while( true )
3581 {
3582 if( currentChainGroups.find( group ) != currentChainGroups.end() )
3583 {
3584 if( repair )
3585 Remove( static_cast<BOARD_ITEM*>( group->AsEdaItem() ) );
3586
3587 return "Cycle detected in group membership";
3588 }
3589 else if( knownCycleFreeGroups.find( group ) != knownCycleFreeGroups.end() )
3590 {
3591 // Parent is a group we know does not lead to a cycle
3592 break;
3593 }
3594
3595 currentChainGroups.insert( group );
3596 // We haven't visited currIdx yet, so it must be in toCheckGroups
3597 toCheckGroups.erase( group );
3598
3599 group = group->AsEdaItem()->GetParentGroup();
3600
3601 if( !group )
3602 {
3603 // end of chain and no cycles found in this chain
3604 break;
3605 }
3606 }
3607
3608 // No cycles found in chain, so add it to set of groups we know don't participate
3609 // in a cycle.
3610 knownCycleFreeGroups.insert( currentChainGroups.begin(), currentChainGroups.end() );
3611 }
3612
3613 // Success
3614 return "";
3615}
3616
3617
3619{
3620 if( a->Type() != b->Type() )
3621 return a->Type() < b->Type();
3622
3623 if( a->GetLayer() != b->GetLayer() )
3624 return a->GetLayer() < b->GetLayer();
3625
3626 if( a->GetPosition().x != b->GetPosition().x )
3627 return a->GetPosition().x < b->GetPosition().x;
3628
3629 if( a->GetPosition().y != b->GetPosition().y )
3630 return a->GetPosition().y < b->GetPosition().y;
3631
3632 if( a->m_Uuid != b->m_Uuid ) // shopuld be always the case foer valid boards
3633 return a->m_Uuid < b->m_Uuid;
3634
3635 return a < b;
3636}
3637
3638
3639bool BOARD::cmp_drawings::operator()( const BOARD_ITEM* aFirst, const BOARD_ITEM* aSecond ) const
3640{
3641 if( aFirst->Type() != aSecond->Type() )
3642 return aFirst->Type() < aSecond->Type();
3643
3644 if( aFirst->GetLayer() != aSecond->GetLayer() )
3645 return aFirst->GetLayer() < aSecond->GetLayer();
3646
3647 if( aFirst->Type() == PCB_SHAPE_T )
3648 {
3649 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aFirst );
3650 const PCB_SHAPE* other = static_cast<const PCB_SHAPE*>( aSecond );
3651 return shape->Compare( other ) < 0;
3652 }
3653 else if( aFirst->Type() == PCB_TEXT_T || aFirst->Type() == PCB_FIELD_T )
3654 {
3655 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aFirst );
3656 const PCB_TEXT* other = static_cast<const PCB_TEXT*>( aSecond );
3657 return text->Compare( other ) < 0;
3658 }
3659 else if( aFirst->Type() == PCB_TEXTBOX_T )
3660 {
3661 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( aFirst );
3662 const PCB_TEXTBOX* other = static_cast<const PCB_TEXTBOX*>( aSecond );
3663
3664 int shapeCmp = textbox->PCB_SHAPE::Compare( other );
3665
3666 if( shapeCmp != 0 )
3667 return shapeCmp < 0;
3668
3669 return textbox->EDA_TEXT::Compare( other ) < 0;
3670 }
3671 else if( aFirst->Type() == PCB_TABLE_T )
3672 {
3673 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( aFirst );
3674 const PCB_TABLE* other = static_cast<const PCB_TABLE*>( aSecond );
3675
3676 return PCB_TABLE::Compare( table, other ) < 0;
3677 }
3678 else if( aFirst->Type() == PCB_BARCODE_T )
3679 {
3680 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( aFirst );
3681 const PCB_BARCODE* other = static_cast<const PCB_BARCODE*>( aSecond );
3682
3683 return PCB_BARCODE::Compare( barcode, other ) < 0;
3684 }
3685
3686 return aFirst->m_Uuid < aSecond->m_Uuid;
3687}
3688
3689
3691 KIGFX::RENDER_SETTINGS* aRenderSettings ) const
3692{
3693 int maxError = GetDesignSettings().m_MaxError;
3694
3695 // convert tracks and vias:
3696 for( const PCB_TRACK* track : m_tracks )
3697 {
3698 if( !track->IsOnLayer( aLayer ) )
3699 continue;
3700
3701 track->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3702 }
3703
3704 // convert pads and other copper items in footprints
3705 for( const FOOTPRINT* footprint : m_footprints )
3706 {
3707 footprint->TransformPadsToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3708
3709 footprint->TransformFPShapesToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE, true, /* include text */
3710 true, /* include shapes */
3711 false /* include private items */ );
3712
3713 for( const ZONE* zone : footprint->Zones() )
3714 {
3715 if( zone->GetLayerSet().test( aLayer ) )
3716 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
3717 }
3718 }
3719
3720 // convert copper zones
3721 for( const ZONE* zone : Zones() )
3722 {
3723 if( zone->GetLayerSet().test( aLayer ) )
3724 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
3725 }
3726
3727 // convert graphic items on copper layers (texts)
3728 for( const BOARD_ITEM* item : m_drawings )
3729 {
3730 if( !item->IsOnLayer( aLayer ) )
3731 continue;
3732
3733 switch( item->Type() )
3734 {
3735 case PCB_SHAPE_T:
3736 {
3737 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( item );
3738 shape->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3739 break;
3740 }
3741
3742 case PCB_BARCODE_T:
3743 {
3744 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( item );
3745 barcode->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3746 break;
3747 }
3748
3749 case PCB_FIELD_T:
3750 case PCB_TEXT_T:
3751 {
3752 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
3753 text->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3754 break;
3755 }
3756
3757 case PCB_TEXTBOX_T:
3758 {
3759 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
3760 // border
3761 textbox->PCB_SHAPE::TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3762 // text
3763 textbox->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3764 break;
3765 }
3766
3767 case PCB_TABLE_T:
3768 {
3769 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
3770 table->TransformGraphicItemsToPolySet( aOutlines, maxError, ERROR_INSIDE, aRenderSettings );
3771 break;
3772 }
3773
3774 case PCB_DIM_ALIGNED_T:
3775 case PCB_DIM_CENTER_T:
3776 case PCB_DIM_RADIAL_T:
3778 case PCB_DIM_LEADER_T:
3779 {
3780 const PCB_DIMENSION_BASE* dim = static_cast<const PCB_DIMENSION_BASE*>( item );
3781 dim->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3782 dim->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3783 break;
3784 }
3785
3786 default: break;
3787 }
3788 }
3789}
3790
3791
3793{
3794 BOARD_ITEM_SET items;
3795
3796 std::copy( m_tracks.begin(), m_tracks.end(), std::inserter( items, items.end() ) );
3797 std::copy( m_zones.begin(), m_zones.end(), std::inserter( items, items.end() ) );
3798 std::copy( m_generators.begin(), m_generators.end(), std::inserter( items, items.end() ) );
3799 std::copy( m_footprints.begin(), m_footprints.end(), std::inserter( items, items.end() ) );
3800 std::copy( m_drawings.begin(), m_drawings.end(), std::inserter( items, items.end() ) );
3801 std::copy( m_markers.begin(), m_markers.end(), std::inserter( items, items.end() ) );
3802 std::copy( m_groups.begin(), m_groups.end(), std::inserter( items, items.end() ) );
3803 std::copy( m_points.begin(), m_points.end(), std::inserter( items, items.end() ) );
3804
3805 return items;
3806}
3807
3808
3809bool BOARD::operator==( const BOARD_ITEM& aItem ) const
3810{
3811 if( aItem.Type() != Type() )
3812 return false;
3813
3814 const BOARD& other = static_cast<const BOARD&>( aItem );
3815
3816 if( *m_designSettings != *other.m_designSettings )
3817 return false;
3818
3819 if( m_NetInfo.GetNetCount() != other.m_NetInfo.GetNetCount() )
3820 return false;
3821
3822 const NETNAMES_MAP& thisNetNames = m_NetInfo.NetsByName();
3823 const NETNAMES_MAP& otherNetNames = other.m_NetInfo.NetsByName();
3824
3825 for( auto it1 = thisNetNames.begin(), it2 = otherNetNames.begin();
3826 it1 != thisNetNames.end() && it2 != otherNetNames.end(); ++it1, ++it2 )
3827 {
3828 // We only compare the names in order here, not the index values
3829 // as the index values are auto-generated and the names are not.
3830 if( it1->first != it2->first )
3831 return false;
3832 }
3833
3834 if( m_properties.size() != other.m_properties.size() )
3835 return false;
3836
3837 for( auto it1 = m_properties.begin(), it2 = other.m_properties.begin();
3838 it1 != m_properties.end() && it2 != other.m_properties.end(); ++it1, ++it2 )
3839 {
3840 if( *it1 != *it2 )
3841 return false;
3842 }
3843
3844 if( m_paper.GetCustomHeightMils() != other.m_paper.GetCustomHeightMils() )
3845 return false;
3846
3847 if( m_paper.GetCustomWidthMils() != other.m_paper.GetCustomWidthMils() )
3848 return false;
3849
3850 if( m_paper.GetSizeMils() != other.m_paper.GetSizeMils() )
3851 return false;
3852
3853 if( m_paper.GetPaperId() != other.m_paper.GetPaperId() )
3854 return false;
3855
3856 if( m_paper.GetWxOrientation() != other.m_paper.GetWxOrientation() )
3857 return false;
3858
3859 for( int ii = 0; !m_titles.GetComment( ii ).empty(); ++ii )
3860 {
3861 if( m_titles.GetComment( ii ) != other.m_titles.GetComment( ii ) )
3862 return false;
3863 }
3864
3865 wxArrayString ourVars;
3866 m_titles.GetContextualTextVars( &ourVars );
3867
3868 wxArrayString otherVars;
3869 other.m_titles.GetContextualTextVars( &otherVars );
3870
3871 if( ourVars != otherVars )
3872 return false;
3873
3874 return true;
3875}
3876
3878{
3879 m_boardOutline->GetOutline().RemoveAllContours();
3880
3881 bool has_outline = GetBoardPolygonOutlines( m_boardOutline->GetOutline(), false );
3882
3883 if( has_outline )
3884 m_boardOutline->GetOutline().Fracture();
3885}
3886
3887
3889{
3890 // return the number of PTH with Press-Fit fabr attribute
3891 int count = 0;
3892
3893 for( FOOTPRINT* footprint : Footprints() )
3894 {
3895 for( PAD* pad : footprint->Pads() )
3896 {
3897 if( pad->GetProperty() == PAD_PROP::PRESSFIT )
3898 count++;
3899 }
3900 }
3901
3902 return count;
3903}
3904
3905
3907{
3908 // @return the number of PTH with Castellated fabr attribute
3909 int count = 0;
3910
3911 for( FOOTPRINT* footprint : Footprints() )
3912 {
3913 for( PAD* pad : footprint->Pads() )
3914 {
3915 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
3916 count++;
3917 }
3918 }
3919
3920 return count;
3921}
3922
3923
3924void BOARD::SaveToHistory( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
3925{
3926 // The board can transiently have no project (e.g. during a non-KiCad import while the old
3927 // project is being unloaded and the new one has not yet been linked). The autosave timer can
3928 // fire in that window, so guard against a null project here rather than dereferencing it.
3930
3931 if( !project )
3932 return;
3933
3934 wxString projPath = project->GetProjectPath();
3935
3936 if( projPath.IsEmpty() )
3937 return;
3938
3939 // Verify we're saving for the correct project
3940 if( !projPath.IsSameAs( aProjectPath ) )
3941 {
3942 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - project path mismatch: %s vs %s" ), projPath,
3943 aProjectPath );
3944 return;
3945 }
3946
3947 wxString boardPath = GetFileName();
3948
3949 if( boardPath.IsEmpty() )
3950 return; // unsaved board
3951
3952 // Derive relative path from project root.
3953 if( !boardPath.StartsWith( projPath ) )
3954 {
3955 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - board not under project: %s" ), boardPath );
3956 return; // not under project
3957 }
3958
3959 wxString rel = boardPath.Mid( projPath.length() );
3960
3961 // Build destination path inside .history mirror.
3962 wxFileName historyRoot( projPath, wxEmptyString );
3963 historyRoot.AppendDir( wxS( ".history" ) );
3964 wxFileName dst( historyRoot.GetPath(), rel );
3965
3966 // Ensure destination directories exist on the UI thread so the background task can write.
3967 wxFileName dstDir( dst );
3968 dstDir.SetFullName( wxEmptyString );
3969
3970 if( !dstDir.DirExists() )
3971 wxFileName::Mkdir( dstDir.GetPath(), 0777, wxPATH_MKDIR_FULL );
3972
3973 try
3974 {
3976 STRING_FORMATTER formatter;
3977
3978 pi.FormatBoardToFormatter( &formatter, this, nullptr );
3979
3980 HISTORY_FILE_DATA entry;
3981 entry.path = dst.GetFullPath();
3982 entry.content = std::move( formatter.MutableString() );
3983 entry.prettify = true;
3984
3985 if( ADVANCED_CFG::GetCfg().m_CompactSave )
3986 entry.formatMode = KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
3987
3988 aFileData.push_back( std::move( entry ) );
3989
3990 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialized %zu bytes for '%s'" ),
3991 aFileData.back().content.size(), dst.GetFullPath() );
3992 }
3993 catch( const IO_ERROR& ioe )
3994 {
3995 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialize failed: %s" ), wxString::FromUTF8( ioe.What() ) );
3996 }
3997}
const char * name
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
bool sortPadsByXthenYCoord(PAD *const &aLH, PAD *const &aRH)
Used by #GetSortedPadListByXCoord to sort a pad list by X coordinate value.
Definition board.cpp:3111
std::set< wxString >::iterator FindByFirstNFields(std::set< wxString > &strSet, const wxString &searchStr, char delimiter, int n)
Definition board.cpp:374
static wxString FindVariantNameCaseInsensitive(const std::vector< wxString > &aNames, const wxString &aVariantName)
Definition board.cpp:2724
#define DEFAULT_CHAINING_EPSILON_MM
Definition board.h:88
BOARD_USE
Flags to specify how the board is being used.
Definition board.h:313
@ NORMAL
Definition board.h:314
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition board.h:186
@ LT_POWER
Definition board.h:189
@ LT_FRONT
Definition board.h:193
@ LT_MIXED
Definition board.h:190
@ LT_BACK
Definition board.h:194
@ LT_UNDEFINED
Definition board.h:187
@ LT_JUMPER
Definition board.h:191
@ LT_AUX
Definition board.h:192
@ LT_SIGNAL
Definition board.h:188
std::set< BOARD_ITEM *, CompareByUuid > BOARD_ITEM_SET
Set of BOARD_ITEMs ordered by UUID.
Definition board.h:307
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & reset(size_t pos)
Definition base_set.h:143
BASE_SET & set(size_t pos)
Definition base_set.h:116
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Container for design settings for a BOARD object.
void UseCustomTrackViaSize(bool aEnabled)
Enables/disables custom track/via size settings.
void SetCustomDiffPairWidth(int aWidth)
Sets custom track width for differential pairs (i.e.
void SetEnabledLayers(const LSET &aMask)
Change the bit-mask of enabled layers to aMask.
std::shared_ptr< NET_SETTINGS > m_NetSettings
void SetCustomTrackWidth(int aWidth)
Sets custom width for track (i.e.
void SetCustomViaSize(int aSize)
Set custom size for via diameter (i.e.
const LSET & GetEnabledLayers() const
Return a bit-mask of all the layers that are enabled.
void SetCustomDiffPairGap(int aGap)
Sets custom gap for differential pairs (i.e.
bool IsLayerEnabled(PCB_LAYER_ID aLayerId) const
Test whether a given layer aLayerId is enabled.
void SetUserDefinedLayerCount(int aNewLayerCount)
Set the number of user defined layers to aNewLayerCount.
BOARD_STACKUP & GetStackupDescriptor()
void SetCustomViaDrill(int aDrill)
Sets custom size for via drill (i.e.
void SetCopperLayerCount(int aNewLayerCount)
Set the copper layer count to aNewLayerCount.
void SetCustomDiffPairViaGap(int aGap)
Sets custom via gap for differential pairs (i.e.
BOARD_ITEM_CONTAINER(BOARD_ITEM *aParent, KICAD_T aType)
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:268
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
virtual void SetLayerSet(const LSET &aLayers)
Definition board_item.h:296
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition board_item.h:375
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:350
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:288
static VECTOR2I ZeroOffset
A value of wxPoint(0,0) which can be passed to the Draw() functions.
Definition board_item.h:205
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
virtual void OnBoardNetSettingsChanged(BOARD &aBoard)
Definition board.h:292
virtual void OnBoardRatsnestChanged(BOARD &aBoard)
Definition board.h:296
virtual void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:289
virtual void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:293
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:290
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:288
virtual void OnBoardHighlightNetChanged(BOARD &aBoard)
Definition board.h:295
virtual void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:291
virtual void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems)
Definition board.h:297
virtual void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:294
Manage layers needed to make a physical board.
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &scanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition board.cpp:2446
ZONE * m_SolderMaskBridges
Definition board.h:1567
void GetContextualTextVars(wxArrayString *aVars) const
Definition board.cpp:491
bool IsFootprintLayerVisible(PCB_LAYER_ID aLayer) const
Expect either of the two layers on which a footprint can reside, and returns whether that layer is vi...
Definition board.cpp:1090
BOARD_STACKUP GetStackupOrDefault() const
Definition board.cpp:3135
std::unordered_map< PTR_PTR_LAYER_CACHE_KEY, bool > m_EnclosedByAreaCache
Definition board.h:1544
std::map< ZONE *, std::map< PCB_LAYER_ID, ISOLATED_ISLANDS > > m_ZoneIsolatedIslandsMap
Definition board.h:1568
PCB_LAYER_ID GetCopperLayerStackMaxId() const
Definition board.cpp:961
GENERATORS m_generators
Definition board.h:1606
void OnItemChanged(BOARD_ITEM *aItem)
Notify the board and its listeners that an item on the board has been modified in some way.
Definition board.cpp:3478
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition board.h:430
bool IsFootprintHolder() const
Find out if the board is being used to hold a single footprint for editing/viewing.
Definition board.h:353
PAD * GetPad(const VECTOR2I &aPosition, const LSET &aLayerMask) const
Find a pad aPosition on aLayer.
Definition board.cpp:2985
int GetUserDefinedLayerCount() const
Definition board.cpp:950
void recalcOpposites()
Definition board.cpp:870
void SetPosition(const VECTOR2I &aPos) override
Definition board.cpp:626
std::map< wxString, wxString > m_properties
Definition board.h:1624
void CacheItemById(BOARD_ITEM *aItem) const
Add an item to the item-by-id cache.
Definition board.cpp:1929
std::unordered_map< const BOARD_ITEM *, wxString > m_ItemNetclassCache
Definition board.h:1551
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3321
int m_fileFormatVersionAtLoad
Definition board.h:1621
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition board.cpp:2664
void UncacheItemById(const KIID &aId) const
Remove an item from the item-by-id cache.
Definition board.cpp:1958
void SetCurrentVariant(const wxString &aVariant)
Definition board.cpp:2737
std::vector< ZONE * > m_DRCCopperZones
Definition board.h:1563
void SetVisibleLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition board.cpp:1018
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1247
void MapNets(BOARD *aDestBoard)
Map all nets in the given board to nets with the same name (if any) in the destination board.
Definition board.cpp:3425
TITLE_BLOCK m_titles
Definition board.h:1628
GAL_SET m_LegacyVisibleItems
Definition board.h:427
std::vector< wxString > m_variantNames
Definition board.h:1635
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1408
wxArrayString GetVariantNamesForUI() const
Return the variant names for UI display.
Definition board.cpp:2892
void RunOnNestedEmbeddedFiles(const std::function< void(EMBEDDED_FILES *)> &aFunction) override
Provide access to nested embedded files, such as symbols in schematics and footprints in boards.
Definition board.cpp:1219
const GENERATORS & Generators() const
Definition board.h:370
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition board.h:909
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:3390
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition board.cpp:1052
int m_outlinesChainingEpsilon
the max distance between 2 end point to see them connected when building the board outlines
Definition board.h:1591
std::tuple< int, double, double, double, double > GetTrackLength(const PCB_TRACK &aTrack) const
Return data on the length and number of track segments connected to a given track.
Definition board.cpp:3146
std::set< wxString > GetNetClassAssignmentCandidates() const
Return the set of netname candidates for netclass assignment.
Definition board.cpp:2703
BOARD_USE m_boardUse
What is this board being used for.
Definition board.h:1594
PAGE_INFO m_paper
Definition board.h:1627
void RemoveAllListeners()
Remove all listeners.
Definition board.cpp:3472
FOOTPRINTS m_footprints
Definition board.h:1602
std::unique_ptr< BOARD_DESIGN_SETTINGS > m_designSettings
All of the board design settings are stored as a JSON object inside the project file.
Definition board.h:1648
void ConvertBrdLayerToPolygonalContours(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aOutlines, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const
Build a set of polygons which are the outlines of copper items (pads, tracks, vias,...
Definition board.cpp:3690
void AddListener(BOARD_LISTENER *aListener)
Add a listener to the board to receive calls whenever something on the board has been modified.
Definition board.cpp:3453
void UpdateUserUnits(BOARD_ITEM *aItem, KIGFX::VIEW *aView)
Update any references within aItem (or its descendants) to the user units.
Definition board.cpp:1706
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:395
bool IsBackLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:795
GAL_SET GetVisibleElements() const
Return a set of all the element categories that are visible.
Definition board.cpp:1046
void SetHighLightNet(int aNetCode, bool aMulti=false)
Select the netcode to be highlighted.
Definition board.cpp:3512
HIGH_LIGHT_INFO m_highLight
Definition board.h:1618
std::map< wxString, wxString > m_variantDescriptions
Definition board.h:1636
bool SetLayerDescr(PCB_LAYER_ID aIndex, const LAYER &aLayer)
Return the type of the copper layer given by aLayer.
Definition board.cpp:717
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2597
EDA_UNITS m_userUnits
Definition board.h:1631
void UpdateBoardOutline()
Definition board.cpp:3877
const ZONES & Zones() const
Definition board.h:368
void BulkRemoveStaleTeardrops(BOARD_COMMIT &aCommit)
Remove all teardrop zones with the STRUCT_DELETED flag set.
Definition board.cpp:1377
void DeleteVariant(const wxString &aVariantName)
Definition board.cpp:2780
void InvokeListeners(Func &&aFunc, Args &&... args)
Definition board.h:1578
void SetDesignSettings(const BOARD_DESIGN_SETTINGS &aSettings)
Definition board.cpp:1107
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1000
void SanitizeNetcodes()
Definition board.cpp:3443
void InitializeClearanceCache()
Initialize the clearance cache for all board items.
Definition board.cpp:1120
EMBEDDED_FILES * m_embeddedFilesDelegate
Definition board.h:1664
ZONE * AddArea(PICKED_ITEMS_LIST *aNewZonesList, int aNetcode, PCB_LAYER_ID aLayer, VECTOR2I aStartPointPosition, ZONE_BORDER_DISPLAY_STYLE aHatch)
Add an empty copper area to board areas list.
Definition board.cpp:3255
bool IsFrontLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:789
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:390
~BOARD()
Definition board.cpp:171
void SaveToHistory(const wxString &aProjectPath, std::vector< HISTORY_FILE_DATA > &aFileData)
Serialize board into HISTORY_FILE_DATA for non-blocking history commit.
Definition board.cpp:3924
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition board.cpp:203
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition board.cpp:1012
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition board.cpp:801
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition board.cpp:346
DRAWINGS m_drawings
Definition board.h:1601
void OnItemsCompositeUpdate(std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems)
Notify the board and its listeners that items on the board have been modified in a composite operatio...
Definition board.cpp:3490
int SetAreasNetCodesFromNetNames()
Set the .m_NetCode member of all copper areas, according to the area Net Name The SetNetCodesFromNetN...
Definition board.cpp:2951
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:2912
void ResetNetHighLight()
Reset all high light data to the init state.
Definition board.cpp:3503
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition board.cpp:763
std::list< ZONE * > GetZoneList(bool aIncludeZonesInFootprints=false) const
Definition board.cpp:3235
bool ResolveTextVar(wxString *token, int aDepth) const
Definition board.cpp:518
const MARKERS & Markers() const
Definition board.h:376
void UncacheChildrenById(const BOARD_ITEM *aParent)
Definition board.h:1503
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:930
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
Definition board.cpp:3376
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition board.cpp:632
std::unique_ptr< class BOARD_TEXT_VAR_ADAPTER > m_textVarAdapter
Definition board.h:1672
TITLE_BLOCK & GetTitleBlock()
Definition board.h:813
void FixupEmbeddedData()
After loading a file from disk, the footprints do not yet contain the full data for their embedded fi...
Definition board.cpp:1226
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition board.cpp:1127
ZONES m_zones
Definition board.h:1605
void InvalidateClearanceCache(const KIID &aUuid)
Invalidate the clearance cache for a specific item.
Definition board.cpp:1113
std::unordered_map< const BOARD_ITEM *, KIID > m_cachedIdByItem
Definition board.h:1614
PCB_LAYER_ID GetLayerID(const wxString &aLayerName) const
Return the ID of a layer.
Definition board.cpp:725
HIGH_LIGHT_INFO m_highLightPrevious
Definition board.h:1619
NETINFO_LIST m_NetInfo
Definition board.h:1656
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition board.h:426
void SetVisibleAlls()
Change the bit-mask of visible element categories and layers.
Definition board.cpp:1035
bool HasVariant(const wxString &aVariantName) const
Definition board.cpp:2763
void AddVariant(const wxString &aVariantName)
Definition board.cpp:2769
int GetCopperLayerCount() const
Definition board.cpp:937
int m_timeStamp
Definition board.h:1595
std::vector< BOARD_LISTENER * > m_listeners
Definition board.h:1658
bool RemoveAllItemsOnLayer(PCB_LAYER_ID aLayer)
Removes all owned items other than footprints existing on the given board layer, and modifies the sta...
Definition board.cpp:1620
std::unordered_map< PTR_PTR_CACHE_KEY, bool > m_IntersectsCourtyardCache
Definition board.h:1540
void IncrementTimeStamp()
Definition board.cpp:274
int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet)
Fetch the coupled netname for a given net.
Definition board.cpp:2616
std::unordered_map< PTR_PTR_CACHE_KEY, bool > m_IntersectsFCourtyardCache
Definition board.h:1541
PCB_POINTS m_points
Definition board.h:1608
std::unique_ptr< LENGTH_DELAY_CALCULATION > m_lengthDelayCalc
Definition board.h:1667
const FOOTPRINTS & Footprints() const
Definition board.h:364
std::shared_ptr< CONNECTIVITY_DATA > m_connectivity
Definition board.h:1625
std::set< KIFONT::OUTLINE_FONT * > GetFonts() const override
Get the list of all outline fonts used in the board.
Definition board.cpp:3339
void RemoveAll(std::initializer_list< KICAD_T > aTypes={ PCB_NETINFO_T, PCB_MARKER_T, PCB_GROUP_T, PCB_ZONE_T, PCB_GENERATOR_T, PCB_FOOTPRINT_T, PCB_TRACE_T, PCB_SHAPE_T })
An efficient way to remove all items of a certain type from the board.
Definition board.cpp:1490
const BOARD_ITEM_SET GetItemSet()
Definition board.cpp:3792
const TRACKS & Tracks() const
Definition board.h:362
int m_DRCMaxPhysicalClearance
Definition board.h:1566
FOOTPRINT * FindFootprintByPath(const KIID_PATH &aPath) const
Search for a FOOTPRINT within this board with the given path.
Definition board.cpp:2691
void FinalizeBulkRemove(std::vector< BOARD_ITEM * > &aRemovedItems)
Must be used if Remove() is used using a BULK_x REMOVE_MODE to generate a change event for listeners.
Definition board.cpp:1371
std::unordered_map< wxString, LSET > m_LayerExpressionCache
Definition board.h:1545
BOARD_ITEM * GetCachedItemById(const KIID &aId) const
Return a cached item for aId if the entry is still self-consistent.
Definition board.cpp:1912
bool m_embedFonts
Definition board.h:1660
wxString GroupsSanityCheckInternal(bool repair)
Definition board.cpp:3549
void OnRatsnestChanged()
Notify the board and its listeners that the ratsnest has been recomputed.
Definition board.cpp:3497
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource) const
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition board.cpp:2169
wxString GetClass() const override
Return the class name.
Definition board.h:1148
std::unique_ptr< COMPONENT_CLASS_MANAGER > m_componentClassManager
Definition board.h:1666
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, bool aInferOutlineIfNecessary, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition board.cpp:3280
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition board.h:434
void SetCopperLayerCount(int aCount)
Definition board.cpp:943
std::unordered_map< const ZONE *, BOX2I > m_ZoneBBoxCache
Definition board.h:1548
std::unordered_map< const ZONE *, SHAPE_POLY_SET > m_DeflatedZoneOutlineCache
Definition board.h:1559
std::unordered_map< PTR_PTR_CACHE_KEY, bool > m_IntersectsBCourtyardCache
Definition board.h:1542
TRACKS TracksInNet(int aNetCode)
Collect all the TRACKs and VIAs that are members of a net given by aNetCode.
Definition board.cpp:695
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
Definition board.cpp:213
PROJECT * m_project
Definition board.h:1630
FOOTPRINT * GetFootprint(const VECTOR2I &aPosition, PCB_LAYER_ID aActiveLayer, bool aVisibleOnly, bool aIgnoreLocked=false) const
Get a footprint by its bounding rectangle at aPosition on aLayer.
Definition board.cpp:3171
bool HasItemsOnLayer(PCB_LAYER_ID aLayer)
Definition board.cpp:1574
const wxString & GetFileName() const
Definition board.h:360
bool operator==(const BOARD_ITEM &aOther) const override
Definition board.cpp:3809
std::vector< PCB_MARKER * > ResolveDRCExclusions(bool aCreateMarkers)
Rebuild DRC markers from the serialized data in BOARD_DESIGN_SETTINGS.
Definition board.cpp:403
int GetPadWithCastellatedAttrCount()
Definition board.cpp:3906
wxString GetVariantDescription(const wxString &aVariantName) const
Definition board.cpp:2856
FOOTPRINT * FindFootprintByReference(const wxString &aReference) const
Search for a FOOTPRINT within this board with the given reference designator.
Definition board.cpp:2679
unsigned GetNodesCount(int aNet=-1) const
Definition board.cpp:2322
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Definition board.cpp:2127
std::map< PCB_LAYER_ID, std::vector< ZONE * > > m_DRCCopperZonesByLayer
Definition board.h:1564
void SetElementVisibility(GAL_LAYER_ID aLayer, bool aNewState)
Change the visibility of an element category.
Definition board.cpp:1058
std::shared_ptr< DRC_RTREE > m_CopperItemRTreeCache
Definition board.h:1547
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition board.cpp:820
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:745
void DetachAllFootprints()
Remove all footprints without deleting.
Definition board.cpp:1777
std::map< int, LAYER > m_layers
Definition board.h:1616
wxString GetCurrentVariant() const
Definition board.h:398
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const override
Invoke a function on all children.
Definition board.cpp:653
int GetOutlinesChainingEpsilon()
Definition board.h:859
void GetSortedPadListByXthenYCoord(std::vector< PAD * > &aVector, int aNetCode=-1) const
First empties then fills the vector with all pads and sorts them by increasing x coordinate,...
Definition board.cpp:3120
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:992
int m_DRCMaxClearance
Definition board.h:1565
void ClearProject()
Definition board.cpp:254
void UncacheItemByPtr(const BOARD_ITEM *aItem)
Remove every cache entry that still points to aItem.
Definition board.cpp:2005
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition board.h:1546
void FinalizeBulkAdd(std::vector< BOARD_ITEM * > &aNewItems)
Must be used if Add() is used using a BULK_x ADD_MODE to generate a change event for listeners.
Definition board.cpp:1365
wxString m_currentVariant
Definition board.h:1634
int LayerDepth(PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer) const
Definition board.cpp:974
void DeleteAllFootprints()
Remove all footprints from the deque and free the memory associated with them.
Definition board.cpp:1765
PROJECT * GetProject() const
Definition board.h:587
bool IsEmpty() const
Definition board.cpp:614
int GetPadWithPressFitAttrCount()
Definition board.cpp:3888
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 board.cpp:2408
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
Definition board.cpp:3535
void RenameVariant(const wxString &aOldName, const wxString &aNewName)
Definition board.cpp:2808
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1101
std::vector< ZONE * > m_DRCZones
Definition board.h:1562
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:986
BOARD()
Definition board.cpp:92
void UpdateRatsnestExclusions()
Update the visibility flags on the current unconnected ratsnest lines.
Definition board.cpp:315
wxString ConvertKIIDsToCrossReferences(const wxString &aSource) const
Definition board.cpp:2249
void RebindItemUuid(BOARD_ITEM *aItem, const KIID &aNewId)
Rebind the UUID of an attached item and keep the item-by-id cache coherent.
Definition board.cpp:2028
int RepairDuplicateItemUuids()
Rebind duplicate attached-item UUIDs so each live board item has a unique ID.
Definition board.cpp:2054
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition board.cpp:2717
std::unordered_map< KIID, BOARD_ITEM * > m_itemByIdCache
Definition board.h:1613
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
Definition board.cpp:3460
std::shared_mutex m_CachesMutex
Definition board.h:1539
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aPhysicalLayersOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition board.cpp:2339
bool SynchronizeComponentClasses(const std::unordered_set< wxString > &aNewSheetPaths) const
Copy component class / component class generator information from the project settings.
Definition board.cpp:2942
BOARD_ITEM * CacheAndReturnItemById(const KIID &aId, BOARD_ITEM *aItem) const
Definition board.cpp:1977
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition board.cpp:1728
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition board.cpp:1394
std::unordered_map< wxString, std::vector< ZONE * > > m_ZonesByNameCache
Definition board.h:1555
GROUPS m_groups
Definition board.h:1604
MARKERS m_markers
Definition board.h:1600
std::unordered_map< PTR_PTR_LAYER_CACHE_KEY, bool > m_IntersectsAreaCache
Definition board.h:1543
std::optional< int > m_maxClearanceValue
Definition board.h:1549
void HighLightON(bool aValue=true)
Enable or disable net highlighting.
Definition board.cpp:3525
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1006
void CacheChildrenById(const BOARD_ITEM *aParent)
Definition board.h:1477
void SynchronizeTuningProfileProperties()
Ensure that all time domain properties providers are in sync with current settings.
Definition board.cpp:2906
TRACKS m_tracks
Definition board.h:1603
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:1789
bool m_LegacyCopperEdgeClearanceLoaded
Definition board.h:431
void OnItemsChanged(std::vector< BOARD_ITEM * > &aItems)
Notify the board and its listeners that an item on the board has been modified in some way.
Definition board.cpp:3484
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:571
VECTOR2I GetPosition() const override
Definition board.cpp:620
void SetVariantDescription(const wxString &aVariantName, const wxString &aDescription)
Definition board.cpp:2875
void CacheTriangulation(PROGRESS_REPORTER *aReporter=nullptr, const std::vector< ZONE * > &aZones={})
Definition board.cpp:1159
void SetVisibleElements(const GAL_SET &aMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1025
void EmbedFonts() override
Finds all fonts used in the board and embeds them in the file if permissions allow.
Definition board.cpp:3366
PCB_BOARD_OUTLINE * m_boardOutline
Definition board.h:1607
void SetUserDefinedLayerCount(int aCount)
Definition board.cpp:956
const DRAWINGS & Drawings() const
Definition board.h:366
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition board.cpp:1700
constexpr coord_type GetY() const
Definition box2.h:208
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr coord_type GetX() const
Definition box2.h:207
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 size_type GetHeight() const
Definition box2.h:215
bool Dirty() const
BOARD_CONNECTED_ITEM * Parent() const
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
std::shared_ptr< const CN_ANCHOR > GetSourceNode() const
void SetVisible(bool aVisible)
std::shared_ptr< const CN_ANCHOR > GetTargetNode() const
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Definition commit.h:96
A class to manage Component Classes in a board context.
void RunOnUnconnectedEdges(std::function< bool(CN_EDGE &)> aFunc)
unsigned int GetUnconnectedCount(bool aVisibileOnly) const
static DELETED_BOARD_ITEM * GetInstance()
Definition board_item.h:525
The base class for create windows for drawing purpose.
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
virtual VECTOR2I GetPosition() const
Definition eda_item.h:279
virtual void ClearEditFlags()
Definition eda_item.h:163
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:149
const KIID m_Uuid
Definition eda_item.h:528
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:118
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
static INSPECT_RESULT IterateForward(std::deque< T > &aList, INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &scanTypes)
This changes first parameter to avoid the DList and use the main queue instead.
Definition eda_item.h:332
virtual INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes)
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition eda_item.cpp:137
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:153
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:41
int Compare(const EDA_SHAPE *aOther) const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:93
EMBEDDED_FILE * GetEmbeddedFile(const wxString &aName) const
Returns the embedded file with the given name or nullptr if it does not exist.
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
EMBEDDED_FILES()=default
const std::map< wxString, EMBEDDED_FILE * > & EmbeddedFileMap() const
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
Helper for storing and iterating over GAL_LAYER_IDs.
Definition layer_ids.h:405
static GAL_SET DefaultVisible()
Definition lset.cpp:786
static const std::vector< KICAD_T > BoardLevelItems
A scan list for all primary board items, omitting items which are subordinate to a FOOTPRINT,...
Definition collectors.h:69
static const std::vector< KICAD_T > Tracks
A scan list for only TRACKs and ARCs.
Definition collectors.h:129
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:98
virtual bool IsOutline() const
Definition font.h:106
Class OUTLINE_FONT implements outline font drawing.
EMBEDDING_PERMISSION GetEmbeddingPermission() const
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
bool IsBOARD_ITEM() const
Definition view_item.h:102
virtual wxString GetClass() const =0
Return the class name.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition view.cpp:1809
Definition kiid.h:48
wxString AsString() const
Definition kiid.cpp:244
Lightweight class which holds a pad, via, or a routed trace outline.
TYPE Type() const
Gets the routing item type.
Class which calculates lengths (and associated routing statistics) in a BOARD context.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
LENGTH_DELAY_STATS CalculateLengthDetails(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr, LENGTH_DELAY_LAYER_OPT aLayerOpt=LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, LENGTH_DELAY_DOMAIN_OPT aDomain=LENGTH_DELAY_DOMAIN_OPT::NO_DELAY_DETAIL) const
Calculates the electrical length of the given items.
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:599
static const LSET & AllLayersMask()
Definition lset.cpp:641
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:697
std::shared_ptr< RC_ITEM > GetRCItem() const
void SetExcluded(bool aExcluded, const wxString &aComment=wxEmptyString)
Definition marker_base.h:94
void SetParent(JSON_SETTINGS *aParent, bool aLoadFromFile=true)
static const char Default[]
the name of the default NETCLASS
Definition netclass.h:44
void SetDescription(const wxString &aDesc)
Definition netclass.h:111
Handle the data for a net.
Definition netinfo.h:50
wxString GetClass() const override
Return the class name.
Definition netinfo.h:61
const wxString & GetNetname() const
Definition netinfo.h:103
int GetNetCode() const
Definition netinfo.h:97
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:228
static const int ORPHANED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition netinfo.h:232
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition netinfo.h:236
unsigned GetNetCount() const
Definition netinfo.h:216
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
Definition netinfo.h:219
void ClearAllCaches()
Clears the effective netclass cache for all nets.
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const wxString &aNetName)
Fetches the effective (may be aggregate) netclass for the given net name.
std::shared_ptr< NETCLASS > GetDefaultNetclass()
Gets the default netclass for the project.
void SetDefaultNetclass(std::shared_ptr< NETCLASS > netclass)
Sets the default netclass for the project Calling user is responsible for resetting the effective net...
Definition pad.h:55
VECTOR2I GetPosition() const override
Definition pad.h:209
const VECTOR2D & GetSizeMils() const
Definition page_info.h:150
wxPrintOrientation GetWxOrientation() const
Definition page_info.h:133
static double GetCustomHeightMils()
Definition page_info.h:202
wxPaperSize GetPaperId() const
Definition page_info.h:138
static double GetCustomWidthMils()
Definition page_info.h:197
static int Compare(const PCB_BARCODE *aBarcode, const PCB_BARCODE *aOther)
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the barcode (text + symbol shapes) to polygonal geometry suitable for filling/collision tests...
Abstract dimension API.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
DIM_UNITS_MODE GetUnitsMode() const
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
void FormatBoardToFormatter(OUTPUTFORMATTER *aOut, BOARD *aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr)
Serialize a BOARD to an OUTPUTFORMATTER without file I/O or Prettify.
Collect all BOARD_ITEM objects on a given layer.
Definition collectors.h:549
void Collect(BOARD_ITEM *aBoard, const std::vector< KICAD_T > &aTypes)
Test a BOARD_ITEM using this class's Inspector method, which does the collection.
void SetLayerId(PCB_LAYER_ID aLayerId)
Definition collectors.h:555
static PCB_MARKER * DeserializeFromString(const wxString &data)
A PCB_POINT is a 0-dimensional point that is used to mark a position on a PCB, or more usually a foot...
Definition pcb_point.h:43
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.
static int Compare(const PCB_TABLE *aTable, const PCB_TABLE *aOther)
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...
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...
Definition pcb_text.cpp:610
const VECTOR2I & GetEndPoint(ENDPOINT_T aEndPoint) const
Return the selected endpoint (start or end)
Definition pcb_track.h:112
A holder to handle information on schematic or board items.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
A progress reporter interface for use in multi-threaded environments.
virtual bool IsCancelled() const =0
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
The backing store for a PROJECT, in JSON format.
std::shared_ptr< COMPONENT_CLASS_SETTINGS > & ComponentClassSettings()
Container for project specific data.
Definition project.h:66
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:199
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:204
std::vector< KIID > GetIDs() const
Definition rc_item.h:133
Represent a set of closed polygons.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int OutlineCount() const
Return the number of outlines in the set.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
std::function< void(std::function< void()>)> TASK_SUBMITTER
Callback that submits a unit of work for asynchronous execution.
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:422
std::string & MutableString()
Definition richio.h:450
const wxString & GetComment(int aIdx) const
static void GetContextualTextVars(wxArrayString *aVars)
Handle a list of polygons defining a copper zone.
Definition zone.h:74
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:550
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:591
bool IsTeardropArea() const
Definition zone.h:691
bool AppendCorner(VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition zone.cpp:1189
#define EXCLUDE_ZONES
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, bool aInferOutlineIfNecessary, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const VECTOR2I &pt)> OUTLINE_ERROR_HANDLER
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
RECURSE_MODE
Definition eda_item.h:52
@ RECURSE
Definition eda_item.h:53
INSPECT_RESULT
Definition eda_item.h:46
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:93
std::function< INSPECT_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Used to inspect and possibly collect the (search) results of iterating over a list or tree of KICAD_T...
Definition eda_item.h:90
#define STRUCT_DELETED
flag indication structures to be erased
EDA_UNITS
Definition eda_units.h:48
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
KIID niluuid(0)
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:679
GAL_LAYER_ID
GAL layers are "virtual" layers, i.e.
Definition layer_ids.h:228
@ GAL_LAYER_ID_START
Definition layer_ids.h:229
@ LAYER_FOOTPRINTS_FR
Show footprints on front.
Definition layer_ids.h:259
@ GAL_LAYER_ID_BITMASK_END
This is the end of the layers used for visibility bit masks in legacy board files.
Definition layer_ids.h:287
@ LAYER_RATSNEST
Definition layer_ids.h:253
@ LAYER_FOOTPRINTS_BK
Show footprints on back.
Definition layer_ids.h:260
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ Rescue
Definition layer_ids.h:121
@ User_1
Definition layer_ids.h:124
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:171
@ F_Cu
Definition layer_ids.h:64
#define GAL_LAYER_INDEX(x)
Use this macro to convert a GAL layer to a 0-indexed offset from LAYER_VIAS.
Definition layer_ids.h:366
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:754
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
STL namespace.
std::map< wxString, NETINFO_ITEM * > NETNAMES_MAP
Definition netinfo.h:186
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:123
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:121
PAGE_SIZE_TYPE
Definition page_info.h:50
BARCODE class definition.
Class to handle a set of BOARD_ITEMs.
std::deque< PCB_TRACK * > TRACKS
ENDPOINT_T
see class PGM_BASE
CITER next(CITER it)
Definition ptree.cpp:124
Class that computes missing connections on a PCB.
@ RPT_SEVERITY_EXCLUSION
wxString GetDefaultVariantName()
int SortVariantNames(const wxString &aLhs, const wxString &aRhs)
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition board.cpp:3639
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition board.cpp:3618
std::vector< char > decompressedData
Data produced by a registered saver on the UI thread, consumed by the background commit thread.
std::string content
Serialized content (mutually exclusive with sourcePath)
wxString path
Destination inside .history/.
KICAD_FORMAT::FORMAT_MODE formatMode
Container to hold information pertinent to a layer of a BOARD.
Definition board.h:202
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition board.cpp:849
static const char * ShowType(LAYER_T aType)
Convert a LAYER_T enum to a string representation of the layer type.
Definition board.cpp:833
Holds length measurement result details and statistics.
Struct to control which optimisations the length calculation code runs on the given path objects.
std::vector< std::vector< std::string > > table
int delta
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
static thread_pool * tp
BS::priority_thread_pool thread_pool
Definition thread_pool.h:31
wxLogTrace helper definitions.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:75
@ PCB_T
Definition typeinfo.h:79
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:85
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:103
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:100
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:94
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:101
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:108
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:90
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:105
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:89
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:86
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:87
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:96
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:98
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:104
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:92
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:83
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:99
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:84
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:95
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:91
@ PCB_NETINFO_T
class NETINFO_ITEM, a description of a net
Definition typeinfo.h:107
@ PCB_POINT_T
class PCB_POINT, a 0-dimensional point
Definition typeinfo.h:110
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:93
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:102
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.