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, see <https://www.gnu.org/licenses/>.
22 */
23
24#include <iterator>
25#include <algorithm>
26
27#include <wx/log.h>
28#include <wx/filename.h>
29
30#include <drc/drc_engine.h>
31#include <drc/drc_rtree.h>
35#include <pcb_drill_map.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>
47#include <font/outline_font.h>
49#include <lset.h>
50#include <pad.h>
51#include <pcb_base_frame.h>
52#include <pcb_track.h>
53#include <pcb_marker.h>
54#include <api/board/board_rules.pb.h>
55#include <pcb_group.h>
56#include <pcb_generator.h>
57#include <pcb_point.h>
59#include <pcb_target.h>
60#include <pcb_shape.h>
61#include <pcb_barcode.h>
62#include <pcb_text.h>
63#include <pcb_textbox.h>
64#include <pcb_table.h>
65#include <pcb_dimension.h>
66#include <pgm_base.h>
67#include <pcbnew_settings.h>
68#include <progress_reporter.h>
69#include <project.h>
75#include <reporter.h>
76#include <tool/tool_manager.h>
78#include <string_utils.h>
79#include <thread_pool.h>
80#include <zone.h>
81#include <mutex>
82#include <pcb_board_outline.h>
83#include <local_history.h>
84#include <pcb_io/pcb_io_mgr.h>
86#include <advanced_config.h>
87#include <richio.h>
88#include <trace_helpers.h>
89
90// This is an odd place for this, but CvPcb won't link if it's in board_item.cpp like I first
91// tried it.
93
94
96 BOARD_ITEM_CONTAINER( nullptr, PCB_T ),
101 m_timeStamp( 1 ),
103 m_project( nullptr ),
105 m_designSettings( new BOARD_DESIGN_SETTINGS( nullptr, "board.design_settings" ) ),
106 m_NetInfo( this ),
107 m_embedFonts( false ),
108 m_embeddedFilesDelegate( nullptr ),
109 m_componentClassManager( std::make_unique<COMPONENT_CLASS_MANAGER>( this ) ),
110 m_lengthDelayCalc( std::make_unique<LENGTH_DELAY_CALCULATION>( this ) )
111{
112 // A too small value do not allow connecting 2 shapes (i.e. segments) not exactly connected
113 // A too large value do not allow safely connecting 2 shapes like very short segments.
115
118 m_boardOutline = new PCB_BOARD_OUTLINE( this );
119
120 // we have not loaded a board yet, assume latest until then.
121 m_fileFormatVersionAtLoad = LEGACY_BOARD_FILE_VERSION;
124
125 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
126 {
127 m_layers[layer].m_name = GetStandardLayerName( ToLAYER_ID( layer ) );
128
129 if( IsCopperLayer( layer ) )
130 m_layers[layer].m_type = LT_SIGNAL;
131 else if( layer >= User_1 && layer & 1 )
132 m_layers[layer].m_type = LT_AUX;
133 else
134 m_layers[layer].m_type = LT_UNDEFINED;
135 }
136
138
139 // Creates a zone to show sloder mask bridges created by a min web value
140 // it it just to show them
141 m_SolderMaskBridges = new ZONE( this );
143 m_SolderMaskBridges->SetLayerSet( LSET().set( F_Mask ).set( B_Mask ) );
144 int infinity = ( std::numeric_limits<int>::max() / 2 ) - pcbIUScale.mmToIU( 1 );
145 m_SolderMaskBridges->Outline()->NewOutline();
146 m_SolderMaskBridges->Outline()->Append( VECTOR2I( -infinity, -infinity ) );
147 m_SolderMaskBridges->Outline()->Append( VECTOR2I( -infinity, +infinity ) );
148 m_SolderMaskBridges->Outline()->Append( VECTOR2I( +infinity, +infinity ) );
149 m_SolderMaskBridges->Outline()->Append( VECTOR2I( +infinity, -infinity ) );
150 m_SolderMaskBridges->SetMinThickness( 0 );
151
153
154 // Initialize default netclass.
155 bds.m_NetSettings->SetDefaultNetclass( std::make_shared<NETCLASS>( NETCLASS::Default ) );
156 bds.m_NetSettings->GetDefaultNetclass()->SetDescription( _( "This is the default net class." ) );
157
158 bds.UseCustomTrackViaSize( false );
159
160 // Initialize ratsnest
161 m_connectivity.reset( new CONNECTIVITY_DATA() );
162
163 // Set flag bits on these that will only be cleared if these are loaded from a legacy file
164 m_LegacyVisibleLayers.reset().set( Rescue );
166
167 // Install the text-variable dependency adapter as a listener so subsequent
168 // BOARD_COMMIT pushes and undo/redo events reach the tracker. No items
169 // exist yet — RebuildIndex is invoked after load by callers that bypass
170 // per-item notifications.
171 m_textVarAdapter = std::make_unique<BOARD_TEXT_VAR_ADAPTER>( *this );
173}
174
175
180
181
182// Footprints count because the board editor promotes a pad edit to its parent, so watching
183// PAD_T alone would miss every drill change made through the normal editing path
184static bool affectsDrillModel( const BOARD_ITEM* aItem )
185{
186 if( !aItem )
187 return false;
188
189 switch( aItem->Type() )
190 {
191 case PCB_PAD_T:
192 case PCB_VIA_T:
193 case PCB_FOOTPRINT_T:
194 return true;
195
196 default:
197 return false;
198 }
199}
200
201
202std::vector<const PCB_DRILL_MAP*> BOARD::DrillMapsOnLayer( PCB_LAYER_ID aLayer ) const
203{
204 std::vector<const PCB_DRILL_MAP*> maps;
205
206 for( BOARD_ITEM* item : m_drawings )
207 {
208 if( item->Type() == PCB_DRILL_MAP_T && item->GetLayer() == aLayer )
209 maps.push_back( static_cast<const PCB_DRILL_MAP*>( item ) );
210 }
211
212 return maps;
213}
214
215
217{
218 if( !aItem )
219 return;
220
221 // A deleted map keeps drawing until the holes themselves are told
222 if( aItem->Type() == PCB_DRILL_MAP_T )
223 {
226 }
227 else if( affectsDrillModel( aItem ) )
228 {
230 }
231}
232
233
235{
236 LSET layers;
237 std::vector<std::pair<VECTOR2I, int>> placements;
238
239 for( BOARD_ITEM* item : m_drawings )
240 {
241 if( item->Type() != PCB_DRILL_MAP_T )
242 continue;
243
244 const PCB_DRILL_MAP* map = static_cast<const PCB_DRILL_MAP*>( item );
245
246 layers.set( map->GetLayer() );
247 placements.emplace_back( map->GetOffset(), map->GetSymbolExtent() );
248 }
249
250 // Both, because a map can change layer without moving and can move without changing layer
251 if( m_drillSymbolLayers == layers && m_drillSymbolPlacements == placements )
252 return;
253
254 m_drillSymbolLayers = layers;
255 m_drillSymbolPlacements = std::move( placements );
256
257}
258
259
260std::shared_ptr<const DRILL_SYMBOL_CACHE> BOARD::DrillSymbolCache() const
261{
262 std::lock_guard<std::mutex> lock( m_drillSymbolCacheMutex );
263
264 const uint64_t profileKey = GetDesignSettings().GetDrillSymbolProfile().Fingerprint();
265
267 && m_drillSymbolCache->m_Profile == profileKey )
268 {
269 return m_drillSymbolCache;
270 }
271
272 std::shared_ptr<DRILL_SYMBOL_CACHE> rebuilt = std::make_shared<DRILL_SYMBOL_CACHE>();
273 rebuilt->m_ByGroup = ResolveDrillSymbols( *this );
274 rebuilt->m_ByItem = ResolveDrillSymbolsByItem( *this, rebuilt->m_ByGroup );
275
276 DRILL_CHART_MODEL totalsModel( GetDesignSettings().GetDrillSymbolProfile() );
277 totalsModel.Build( *this, EnumerateDrillSpans( *this ) );
278 rebuilt->m_Totals = totalsModel.Totals();
279
280 for( const auto& [itemId, entries] : rebuilt->m_ByItem )
281 {
282 for( const DRILL_SYMBOL_ENTRY& entry : entries )
283 rebuilt->m_HoleExtent.Merge( entry.m_Position );
284 }
285
286 rebuilt->m_Generation = m_drillModelGeneration;
287 rebuilt->m_Profile = profileKey;
288
289 m_drillSymbolCache = rebuilt;
290
291 return m_drillSymbolCache;
292}
293
294
296{
297 if( m_drillSymbolPlacements.empty() )
298 return aBoundingBox;
299
300 BOX2I result = aBoundingBox;
301
302 for( const auto& [offset, extent] : m_drillSymbolPlacements )
303 {
304 BOX2I symbolBox = aBoundingBox;
305 symbolBox.Move( offset );
306 symbolBox.Inflate( extent );
307 result.Merge( symbolBox );
308 }
309
310 return result;
311}
312
313
314void BOARD::bumpDrillModelFor( const std::vector<BOARD_ITEM*>& aItems )
315{
316 for( const BOARD_ITEM* item : aItems )
317 {
318 if( affectsDrillModel( item ) )
319 {
321 return;
322 }
323 }
324}
325
326
328{
329 // Clears m_boardCacheOwner as it goes. Items that outlive the board rely on that to know
330 // ~BOARD_ITEM must not walk their parent chain back into freed memory
332
333 // Clean up the owned elements
335
336 delete m_SolderMaskBridges;
337
338 std::vector<BOARD_ITEM*> ownedItems = collectOwnedItems();
339
340 std::sort( ownedItems.begin(), ownedItems.end() );
341 ownedItems.erase( std::unique( ownedItems.begin(), ownedItems.end() ), ownedItems.end() );
342
343 m_zones.clear();
344 m_footprints.clear();
345 m_tracks.clear();
346 m_drawings.clear();
347 m_groups.clear();
348 m_constraints.clear();
349 m_points.clear();
350
351 delete m_boardOutline;
352 m_generators.clear();
353
354 // Delete the owned items after clearing the containers, because some item dtors
355 // cause call chains that query the containers
356 for( BOARD_ITEM* item : ownedItems )
357 delete item;
358
359 // Remove any listeners
361}
362
363
365{
366 if( !GetConnectivity()->Build( this, aReporter ) )
367 return false;
368
370 return true;
371}
372
373
374void BOARD::SetProject( PROJECT* aProject, bool aReferenceOnly )
375{
376 if( m_project == aProject )
377 return;
378
379 if( m_project )
380 ClearProject();
381
382 m_project = aProject;
383
384 if( aProject && !aReferenceOnly )
385 {
386 PROJECT_FILE& project = aProject->GetProjectFile();
387
388 // Link the design settings object to the project file
389 project.m_BoardSettings = &GetDesignSettings();
390
391 // Set parent, which also will load the values from JSON stored in the project if we don't
392 // have legacy design settings loaded already
393 project.m_BoardSettings->SetParent( &project, !m_LegacyDesignSettingsLoaded );
394
395 // The DesignSettings' netclasses pointer will be pointing to its internal netclasses
396 // list at this point. If we loaded anything into it from a legacy board file then we
397 // want to transfer it over to the project netclasses list.
399 {
400 std::shared_ptr<NET_SETTINGS> legacySettings = GetDesignSettings().m_NetSettings;
401 std::shared_ptr<NET_SETTINGS>& projectSettings = project.NetSettings();
402
403 projectSettings->SetDefaultNetclass( legacySettings->GetDefaultNetclass() );
404 projectSettings->SetNetclasses( legacySettings->GetNetclasses() );
405 projectSettings->SetNetclassPatternAssignments(
406 std::move( legacySettings->GetNetclassPatternAssignments() ) );
407 }
408
409 // Now update the DesignSettings' netclass pointer to point into the project.
410 GetDesignSettings().m_NetSettings = project.NetSettings();
411 }
412}
413
414
416{
417 if( !m_project )
418 return;
419
420 PROJECT_FILE& project = m_project->GetProjectFile();
421
422 // Release this board's own design settings, not project.m_BoardSettings; a second board
423 // sharing the project (e.g. diffing a file against itself) overwrites m_BoardSettings, so
424 // trusting it would orphan our settings as a dangling entry in the project's nested list
425 project.ReleaseNestedSettings( &GetDesignSettings() );
426
427 if( project.m_BoardSettings == &GetDesignSettings() )
428 project.m_BoardSettings = nullptr;
429
431 m_project = nullptr;
432}
433
434
436{
437 if( m_fileName.IsEmpty() || !m_project )
438 return wxEmptyString;
439
440 wxFileName fn( m_fileName );
442 return m_project->AbsolutePath( fn.GetFullName() );
443}
444
445
447{
448 std::unique_lock<std::shared_mutex> writeLock( m_CachesMutex );
449
450 m_timeStamp++;
451
453
454 if( !m_IntersectsAreaCache.Empty()
455 || !m_IntersectsKeepoutCache.Empty()
456 || !m_EnclosedByAreaCache.Empty()
466 || !m_LayerExpressionCache.empty()
467 || !m_ZoneBBoxCache.empty()
469 || m_maxClearanceValue.has_value()
470 || !m_ItemNetclassCache.empty()
471 || !m_ZonesByNameCache.empty()
473 || !m_ItemFieldCache.Empty()
474 || m_StackedMicroviaCache.has_value() )
475 {
476 m_IntersectsAreaCache.Clear();
478 m_EnclosedByAreaCache.Clear();
488 m_ItemFieldCache.Clear();
491 m_ItemNetclassCache.clear();
492 m_ZonesByNameCache.clear();
494
495 m_ZoneBBoxCache.clear();
496
497 m_CopperItemRTreeCache = nullptr;
498
499 // These are always regenerated before use, but still probably safer to clear them
500 // while we're here.
503 m_DRCZones.clear();
504 m_DRCCopperZones.clear();
508
509 m_maxClearanceValue.reset();
510 }
511}
512
513
514std::shared_ptr<const FOOTPRINT_COURTYARD_INDEX> BOARD::GetFootprintCourtyardIndex()
515{
516 {
517 std::shared_lock<std::shared_mutex> readLock( m_CachesMutex );
518
521 }
522
523 // Build outside the lock; FOOTPRINT::GetCourtyard guards its own cache with a per-footprint
524 // mutex, so building here is safe even when it has to lazily populate that cache. Publish under
525 // the write lock, letting the first builder win if several worker threads race here on the
526 // first courtyard predicate.
527 auto index = std::make_shared<FOOTPRINT_COURTYARD_INDEX>( this );
528
529 std::unique_lock<std::shared_mutex> writeLock( m_CachesMutex );
530
532 m_footprintCourtyardIndex = std::move( index );
533
535}
536
537
539{
540 std::set<std::pair<KIID, KIID>> m_ratsnestExclusions;
541
542 for( PCB_MARKER* marker : GetBoard()->Markers() )
543 {
544 if( marker->GetMarkerType() == MARKER_BASE::MARKER_RATSNEST && marker->IsExcluded() )
545 {
546 const std::shared_ptr<RC_ITEM>& rcItem = marker->GetRCItem();
547 m_ratsnestExclusions.emplace( rcItem->GetMainItemID(), rcItem->GetAuxItemID() );
548 m_ratsnestExclusions.emplace( rcItem->GetAuxItemID(), rcItem->GetMainItemID() );
549 }
550 }
551
553 [&]( CN_EDGE& aEdge )
554 {
555 if( aEdge.GetSourceNode() && aEdge.GetTargetNode() && !aEdge.GetSourceNode()->Dirty()
556 && !aEdge.GetTargetNode()->Dirty() )
557 {
558 std::pair<KIID, KIID> ids = { aEdge.GetSourceNode()->Parent()->m_Uuid,
559 aEdge.GetTargetNode()->Parent()->m_Uuid };
560
561 aEdge.SetVisible( m_ratsnestExclusions.count( ids ) == 0 );
562 }
563
564 return true;
565 } );
566}
567
568
570{
571 m_designSettings->m_DrcExclusions.clear();
572
573 for( PCB_MARKER* marker : m_markers )
574 {
575 // DRC_EXCLUSION::FromMarker() dereferences the RC_ITEM, so a marker carrying none would
576 // fault while persisting exclusions during a save or window close.
577 if( !marker->GetRCItem() )
578 continue;
579
580 if( marker->IsExcluded() )
581 m_designSettings->m_DrcExclusions.insert( DRC_EXCLUSION::FromMarker( *marker ) );
582 }
583
584 if( m_project )
585 {
586 if( PROJECT_FILE* projectFile = &m_project->GetProjectFile() )
587 {
588 if( BOARD_DESIGN_SETTINGS* prjSettings = projectFile->m_BoardSettings )
589 prjSettings->m_DrcExclusions = m_designSettings->m_DrcExclusions;
590 }
591 }
592}
593
594
595std::vector<PCB_MARKER*> BOARD::ResolveDRCExclusions( bool aCreateMarkers )
596{
597 std::set<DRC_EXCLUSION, DRC_EXCLUSION_COMPARE> exclusions = m_designSettings->m_DrcExclusions;
598 m_designSettings->m_DrcExclusions.clear();
599
600 for( PCB_MARKER* marker : GetBoard()->Markers() )
601 {
602 DRC_EXCLUSION lookup = DRC_EXCLUSION::FromMarker( *marker );
603
604 if( auto it = exclusions.find( lookup ); it != exclusions.end() )
605 {
606 marker->SetExcluded( true, it->GetComment() );
607 m_designSettings->m_DrcExclusions.insert( *it );
608 }
609 }
610
611 std::vector<PCB_MARKER*> newMarkers;
612
613 if( aCreateMarkers )
614 {
615 for( const DRC_EXCLUSION& exclusion : exclusions )
616 {
617 if( m_designSettings->m_DrcExclusions.contains( exclusion ) )
618 continue;
619
620 PCB_MARKER* marker = PCB_MARKER::FromProto( exclusion.ToProto().marker() );
621
622 if( !marker )
623 continue;
624
625 std::vector<KIID> ids = marker->GetRCItem()->GetIDs();
626
627 int uuidCount = 0;
628
629 for( const KIID& uuid : ids )
630 {
631 if( uuidCount < 1 || uuid != niluuid )
632 {
633 if( !ResolveItem( uuid, true ) )
634 {
635 delete marker;
636 marker = nullptr;
637 break;
638 }
639 }
640 uuidCount++;
641 }
642
643 if( marker )
644 {
645 marker->SetExcluded( true, exclusion.GetComment() );
646 newMarkers.push_back( marker );
647 m_designSettings->m_DrcExclusions.insert( exclusion );
648 }
649 }
650 }
651
652 return newMarkers;
653}
654
655
656void BOARD::GetContextualTextVars( wxArrayString* aVars ) const
657{
658 auto add = [&]( const wxString& aVar )
659 {
660 if( !alg::contains( *aVars, aVar ) )
661 aVars->push_back( aVar );
662 };
663
664 add( wxT( "LAYER" ) );
665 add( wxT( "FILENAME" ) );
666 add( wxT( "FILEPATH" ) );
667 add( wxT( "PROJECTNAME" ) );
668 add( wxT( "DRC_ERROR <message_text>" ) );
669 add( wxT( "DRC_WARNING <message_text>" ) );
670 add( wxT( "VARIANT" ) );
671 add( wxT( "VARIANT_DESC" ) );
672 add( wxT( "DRILL_OPERATIONS" ) );
673 add( wxT( "DRILL_SITES" ) );
674 add( wxT( "DRILL_GROUPS" ) );
675
677
678 if( GetProject() )
679 {
680 for( std::pair<wxString, wxString> entry : GetProject()->GetTextVars() )
681 add( entry.first );
682 }
683}
684
685
686bool BOARD::ResolveTextVar( wxString* token, int aDepth ) const
687{
688 if( token->Contains( ':' ) )
689 {
690 wxString remainder;
691 wxString ref = token->BeforeFirst( ':', &remainder );
692 BOARD_ITEM* refItem = ResolveItem( KIID( ref ), true );
693
694 if( refItem && refItem->Type() == PCB_FOOTPRINT_T )
695 {
696 FOOTPRINT* refFP = static_cast<FOOTPRINT*>( refItem );
697
698 if( refFP->ResolveTextVar( &remainder, aDepth + 1 ) )
699 {
700 *token = std::move( remainder );
701 return true;
702 }
703 }
704
705 // If UUID resolution failed, try to resolve by reference designator
706 // This handles typing ${U1:VALUE} directly without save/reload
707 if( !refItem )
708 {
709 for( const FOOTPRINT* footprint : Footprints() )
710 {
711 if( footprint->GetReference().CmpNoCase( ref ) == 0 )
712 {
713 wxString remainderCopy = remainder;
714
715 if( footprint->ResolveTextVar( &remainderCopy, aDepth + 1 ) )
716 {
717 *token = std::move( remainderCopy );
718 }
719 else
720 {
721 // Field/function not found on footprint
722 *token = wxString::Format( wxT( "<Unresolved: %s:%s>" ), footprint->GetReference(), remainder );
723 }
724
725 return true;
726 }
727 }
728
729 // Reference not found - show error message
730 *token = wxString::Format( wxT( "<Unknown reference: %s>" ), ref );
731 return true;
732 }
733 }
734
735 if( token->IsSameAs( wxT( "FILENAME" ) ) )
736 {
737 wxFileName fn( GetFileName() );
738 *token = fn.GetFullName();
739 return true;
740 }
741 else if( token->IsSameAs( wxT( "FILEPATH" ) ) )
742 {
743 wxFileName fn( GetFileName() );
744 *token = fn.GetFullPath();
745 return true;
746 }
747 else if( token->IsSameAs( wxT( "VARIANT" ) ) )
748 {
749 *token = GetCurrentVariant();
750 return true;
751 }
752 else if( token->IsSameAs( wxT( "VARIANT_DESC" ) ) )
753 {
755 return true;
756 }
757 else if( token->IsSameAs( wxT( "PROJECTNAME" ) ) && GetProject() )
758 {
759 *token = GetProject()->GetProjectName();
760 return true;
761 }
762 else if( token->IsSameAs( wxT( "DRILL_OPERATIONS" ) )
763 || token->IsSameAs( wxT( "DRILL_SITES" ) )
764 || token->IsSameAs( wxT( "DRILL_GROUPS" ) ) )
765 {
766 // Cached, because this resolves on every redraw of every text item and the model
767 // walks every hole on every span
769
770 if( token->IsSameAs( wxT( "DRILL_OPERATIONS" ) ) )
771 *token = wxString::Format( wxT( "%d" ), totals.m_Operations );
772 else if( token->IsSameAs( wxT( "DRILL_SITES" ) ) )
773 *token = wxString::Format( wxT( "%d" ), totals.m_Sites );
774 else
775 *token = wxString::Format( wxT( "%d" ), totals.m_Groups );
776
777 return true;
778 }
779
780 wxString var = *token;
781
782 if( GetTitleBlock().TextVarResolver( token, m_project, INTERNAL ) )
783 return true;
784
785 // Resolve from the project's live text variables before the board's cached properties so
786 // changes made outside the board (schematic, project settings) are always reflected.
787 if( GetProject() && GetProject()->TextVarResolver( token ) )
788 return true;
789
790 // Fall back to the board's cached properties for backward compatibility with boards that
791 // may carry properties not present in the project.
792 if( m_properties.count( var ) )
793 {
794 *token = m_properties.at( var );
795 return true;
796 }
797
798 return false;
799}
800
801
802bool BOARD::IsEmpty() const
803{
804 return m_drawings.empty() && m_footprints.empty() && m_tracks.empty() && m_zones.empty() && m_points.empty();
805}
806
807
809{
810 return ZeroOffset;
811}
812
813
814void BOARD::SetPosition( const VECTOR2I& aPos )
815{
816 wxLogWarning( wxT( "This should not be called on the BOARD object" ) );
817}
818
819
820void BOARD::Move( const VECTOR2I& aMoveVector ) // overload
821{
822 INSPECTOR_FUNC inspector = [&]( EDA_ITEM* item, void* testData )
823 {
824 if( item->IsBOARD_ITEM() )
825 {
826 BOARD_ITEM* board_item = static_cast<BOARD_ITEM*>( item );
827
828 // aMoveVector was snapshotted, don't need "data".
829 // Only move the top level group
830 if( !board_item->GetParentGroup() && !board_item->GetParentFootprint() )
831 board_item->Move( aMoveVector );
832 }
833
835 };
836
837 Visit( inspector, nullptr, GENERAL_COLLECTOR::BoardLevelItems );
838}
839
840
841void BOARD::RunOnChildren( const std::function<void( BOARD_ITEM* )>& aFunction, RECURSE_MODE aMode ) const
842{
843 try
844 {
845 for( PCB_TRACK* track : m_tracks )
846 aFunction( track );
847
848 for( ZONE* zone : m_zones )
849 aFunction( zone );
850
851 for( PCB_MARKER* marker : m_markers )
852 aFunction( marker );
853
854 for( PCB_GROUP* group : m_groups )
855 aFunction( group );
856
857 for( PCB_CONSTRAINT* constraint : m_constraints )
858 aFunction( constraint );
859
860 for( PCB_POINT* point : m_points )
861 aFunction( point );
862
863 for( FOOTPRINT* footprint : m_footprints )
864 {
865 aFunction( footprint );
866
867 if( aMode == RECURSE_MODE::RECURSE )
868 footprint->RunOnChildren( aFunction, RECURSE_MODE::RECURSE );
869 }
870
871 for( BOARD_ITEM* drawing : m_drawings )
872 {
873 aFunction( drawing );
874
875 if( aMode == RECURSE_MODE::RECURSE )
876 drawing->RunOnChildren( aFunction, RECURSE_MODE::RECURSE );
877 }
878 }
879 catch( std::bad_function_call& )
880 {
881 wxFAIL_MSG( wxT( "Error running BOARD::RunOnChildren" ) );
882 }
883}
884
885
887{
888 TRACKS ret;
889
890 INSPECTOR_FUNC inspector = [aNetCode, &ret]( EDA_ITEM* item, void* testData )
891 {
892 PCB_TRACK* t = static_cast<PCB_TRACK*>( item );
893
894 if( t->GetNetCode() == aNetCode )
895 ret.push_back( t );
896
898 };
899
900 // visit this BOARD's PCB_TRACKs and PCB_VIAs with above TRACK INSPECTOR which
901 // appends all in aNetCode to ret.
902 Visit( inspector, nullptr, GENERAL_COLLECTOR::Tracks );
903
904 return ret;
905}
906
907
908bool BOARD::SetLayerDescr( PCB_LAYER_ID aIndex, const LAYER& aLayer )
909{
910 m_layers[aIndex] = aLayer;
912 return true;
913}
914
915
916PCB_LAYER_ID BOARD::GetLayerID( const wxString& aLayerName ) const
917{
918 // Check the BOARD physical layer names.
919 for( auto& [layer_id, layer] : m_layers )
920 {
921 if( layer.m_name == aLayerName || layer.m_userName == aLayerName )
922 return ToLAYER_ID( layer_id );
923 }
924
925 // Otherwise fall back to the system standard layer names for virtual layers.
926 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
927 {
928 if( GetStandardLayerName( ToLAYER_ID( layer ) ) == aLayerName )
929 return ToLAYER_ID( layer );
930 }
931
932 return UNDEFINED_LAYER;
933}
934
935
936const wxString BOARD::GetLayerName( PCB_LAYER_ID aLayer ) const
937{
938 // All layer names are stored in the BOARD.
939 if( IsLayerEnabled( aLayer ) )
940 {
941 auto it = m_layers.find( aLayer );
942
943 // Standard names were set in BOARD::BOARD() but they may be over-ridden by
944 // BOARD::SetLayerName(). For copper layers, return the user defined layer name,
945 // if it was set. Otherwise return the Standard English layer name.
946 if( it != m_layers.end() && !it->second.m_userName.IsEmpty() )
947 return it->second.m_userName;
948 }
949
950 return GetStandardLayerName( aLayer );
951}
952
953
954bool BOARD::SetLayerName( PCB_LAYER_ID aLayer, const wxString& aLayerName )
955{
956 if( aLayerName.IsEmpty() )
957 {
958 // If the name is empty, we clear the user name.
959 m_layers[aLayer].m_userName.clear();
961 }
962 else
963 {
964 // no quote chars in the name allowed
965 if( aLayerName.Find( wxChar( '"' ) ) != wxNOT_FOUND )
966 return false;
967
968 if( IsLayerEnabled( aLayer ) )
969 {
970 m_layers[aLayer].m_userName = aLayerName;
972
973 // A chart prints the span using layer names, so a rename changes what it says
975 return true;
976 }
977 }
978
979 return false;
980}
981
982
984{
985 return ::IsFrontLayer( aLayer ) || GetLayerType( aLayer ) == LT_FRONT;
986}
987
988
990{
991 return ::IsBackLayer( aLayer ) || GetLayerType( aLayer ) == LT_BACK;
992}
993
994
996{
997 if( IsLayerEnabled( aLayer ) )
998 {
999 auto it = m_layers.find( aLayer );
1000
1001 if( it != m_layers.end() )
1002 return it->second.m_type;
1003 }
1004
1005 if( aLayer >= User_1 && !IsCopperLayer( aLayer ) )
1006 return LT_AUX;
1007 else if( IsCopperLayer( aLayer ) )
1008 return LT_SIGNAL;
1009 else
1010 return LT_UNDEFINED;
1011}
1012
1013
1014bool BOARD::SetLayerType( PCB_LAYER_ID aLayer, LAYER_T aLayerType )
1015{
1016 if( IsLayerEnabled( aLayer ) )
1017 {
1018 m_layers[aLayer].m_type = aLayerType;
1020 return true;
1021 }
1022
1023 return false;
1024}
1025
1026
1027const char* LAYER::ShowType( LAYER_T aType )
1028{
1029 switch( aType )
1030 {
1031 default:
1032 case LT_SIGNAL: return "signal";
1033 case LT_POWER: return "power";
1034 case LT_MIXED: return "mixed";
1035 case LT_JUMPER: return "jumper";
1036 case LT_AUX: return "auxiliary";
1037 case LT_FRONT: return "front";
1038 case LT_BACK: return "back";
1039 }
1040}
1041
1042
1043LAYER_T LAYER::ParseType( const char* aType )
1044{
1045 if( strcmp( aType, "signal" ) == 0 )
1046 return LT_SIGNAL;
1047 else if( strcmp( aType, "power" ) == 0 )
1048 return LT_POWER;
1049 else if( strcmp( aType, "mixed" ) == 0 )
1050 return LT_MIXED;
1051 else if( strcmp( aType, "jumper" ) == 0 )
1052 return LT_JUMPER;
1053 else if( strcmp( aType, "auxiliary" ) == 0 )
1054 return LT_AUX;
1055 else if( strcmp( aType, "front" ) == 0 )
1056 return LT_FRONT;
1057 else if( strcmp( aType, "back" ) == 0 )
1058 return LT_BACK;
1059 else
1060 return LT_UNDEFINED;
1061}
1062
1063
1065{
1066 for( int layer = F_Cu; layer < PCB_LAYER_ID_COUNT; ++layer )
1067 m_layers[layer].m_opposite = ::FlipLayer( ToLAYER_ID( layer ), GetCopperLayerCount() );
1068
1069 // Match up similary-named front/back user layers
1070 for( int layer = User_1; layer <= PCB_LAYER_ID_COUNT; layer += 2 )
1071 {
1072 if( m_layers[layer].m_opposite != layer ) // already paired
1073 continue;
1074
1075 if( m_layers[layer].m_type != LT_FRONT && m_layers[layer].m_type != LT_BACK )
1076 continue;
1077
1078 wxString principalName = m_layers[layer].m_userName.AfterFirst( '.' );
1079
1080 for( int ii = layer + 2; ii <= PCB_LAYER_ID_COUNT; ii += 2 )
1081 {
1082 if( m_layers[ii].m_opposite != ii ) // already paired
1083 continue;
1084
1085 if( m_layers[ii].m_type != LT_FRONT && m_layers[ii].m_type != LT_BACK )
1086 continue;
1087
1088 if( m_layers[layer].m_type == m_layers[ii].m_type )
1089 continue;
1090
1091 wxString candidate = m_layers[ii].m_userName.AfterFirst( '.' );
1092
1093 if( !candidate.IsEmpty() && candidate == principalName )
1094 {
1095 m_layers[layer].m_opposite = ii;
1096 m_layers[ii].m_opposite = layer;
1097 break;
1098 }
1099 }
1100 }
1101
1102 // Match up non-custom-named consecutive front/back user layer pairs
1103 for( int layer = User_1; layer < PCB_LAYER_ID_COUNT - 2; layer += 2 )
1104 {
1105 int next = layer + 2;
1106
1107 // ignore already-matched layers
1108 if( m_layers[layer].m_opposite != layer || m_layers[next].m_opposite != next )
1109 continue;
1110
1111 // ignore layer pairs that aren't consecutive front/back
1112 if( m_layers[layer].m_type != LT_FRONT || m_layers[next].m_type != LT_BACK )
1113 continue;
1114
1115 if( m_layers[layer].m_userName != m_layers[layer].m_name && m_layers[next].m_userName != m_layers[next].m_name )
1116 {
1117 m_layers[layer].m_opposite = next;
1118 m_layers[next].m_opposite = layer;
1119 }
1120 }
1121}
1122
1123
1125{
1126 auto it = m_layers.find( aLayer );
1127 return it == m_layers.end() ? aLayer : ToLAYER_ID( it->second.m_opposite );
1128}
1129
1130
1135
1136
1138{
1141
1142 // A chart prints layer spans, so the count and order change what it says
1144}
1145
1146
1151
1152
1154{
1156}
1157
1159{
1160 int imax = GetCopperLayerCount();
1161
1162 // layers IDs are F_Cu, B_Cu, and even IDs values (imax values)
1163 if( imax <= 2 ) // at least 2 layers are expected
1164 return B_Cu;
1165
1166 // For a 4 layer, last ID is In2_Cu = 6 (IDs are 0, 2, 4, 6)
1167 return static_cast<PCB_LAYER_ID>( ( imax - 1 ) * 2 );
1168}
1169
1170
1171int BOARD::LayerDepth( PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer ) const
1172{
1173 if( aStartLayer > aEndLayer )
1174 std::swap( aStartLayer, aEndLayer );
1175
1176 if( aEndLayer == B_Cu )
1177 aEndLayer = ToLAYER_ID( F_Cu + GetCopperLayerCount() - 1 );
1178
1179 return aEndLayer - aStartLayer;
1180}
1181
1182
1184{
1186}
1187
1188
1190{
1191 // If there is no project, assume layer is visible always
1192 return GetDesignSettings().IsLayerEnabled( aLayer )
1193 && ( !m_project || m_project->GetLocalSettings().m_VisibleLayers[aLayer] );
1194}
1195
1196
1198{
1199 return m_project ? m_project->GetLocalSettings().m_VisibleLayers : LSET::AllLayersMask();
1200}
1201
1202
1203void BOARD::SetEnabledLayers( const LSET& aLayerSet )
1204{
1205 GetDesignSettings().SetEnabledLayers( aLayerSet );
1207}
1208
1209
1211{
1212 return GetDesignSettings().IsLayerEnabled( aLayer );
1213}
1214
1215
1216void BOARD::SetVisibleLayers( const LSET& aLayerSet )
1217{
1218 if( m_project )
1219 m_project->GetLocalSettings().m_VisibleLayers = aLayerSet;
1220}
1221
1222
1224{
1225 // Call SetElementVisibility for each item
1226 // to ensure specific calculations that can be needed by some items,
1227 // just changing the visibility flags could be not sufficient.
1228 for( size_t i = 0; i < aSet.size(); i++ )
1229 SetElementVisibility( GAL_LAYER_ID_START + static_cast<int>( i ), aSet[i] );
1230}
1231
1232
1234{
1235 SetVisibleLayers( LSET().set() );
1236
1237 // Call SetElementVisibility for each item,
1238 // to ensure specific calculations that can be needed by some items
1240 SetElementVisibility( ii, true );
1241}
1242
1243
1245{
1246 return m_project ? m_project->GetLocalSettings().m_VisibleItems : GAL_SET::DefaultVisible();
1247}
1248
1249
1251{
1252 return !m_project || m_project->GetLocalSettings().m_VisibleItems[aLayer - GAL_LAYER_ID_START];
1253}
1254
1255
1256void BOARD::SetElementVisibility( GAL_LAYER_ID aLayer, bool isEnabled )
1257{
1258 if( m_project )
1259 m_project->GetLocalSettings().m_VisibleItems.set( aLayer - GAL_LAYER_ID_START, isEnabled );
1260
1261 switch( aLayer )
1262 {
1263 case LAYER_RATSNEST:
1264 {
1265 // because we have a tool to show/hide ratsnest relative to a pad or a footprint
1266 // so the hide/show option is a per item selection
1267
1268 for( PCB_TRACK* track : Tracks() )
1269 track->SetLocalRatsnestVisible( isEnabled );
1270
1271 for( FOOTPRINT* footprint : Footprints() )
1272 {
1273 for( PAD* pad : footprint->Pads() )
1274 pad->SetLocalRatsnestVisible( isEnabled );
1275 }
1276
1277 for( ZONE* zone : Zones() )
1278 zone->SetLocalRatsnestVisible( isEnabled );
1279
1280 break;
1281 }
1282
1283 default:;
1284 }
1285}
1286
1287
1289{
1290 switch( aLayer )
1291 {
1294 default: wxFAIL_MSG( wxT( "BOARD::IsModuleLayerVisible(): bad layer" ) ); return true;
1295 }
1296}
1297
1298
1303
1304
1306{
1307 *m_designSettings = aSettings;
1308}
1309
1310
1312{
1313 if( m_designSettings && m_designSettings->m_DRCEngine )
1314 m_designSettings->m_DRCEngine->InvalidateClearanceCache( aUuid );
1315}
1316
1317
1319{
1320 if( m_designSettings && m_designSettings->m_DRCEngine )
1321 m_designSettings->m_DRCEngine->InitializeClearanceCache();
1322}
1323
1324
1326{
1327 if( !m_maxClearanceValue.has_value() )
1328 {
1329 std::unique_lock<std::shared_mutex> writeLock( m_CachesMutex );
1330
1331 int worstClearance = m_designSettings->GetBiggestClearanceValue();
1332
1333 for( ZONE* zone : m_zones )
1334 worstClearance = std::max( worstClearance, zone->GetLocalClearance().value() );
1335
1336 for( FOOTPRINT* footprint : m_footprints )
1337 {
1338 for( PAD* pad : footprint->Pads() )
1339 {
1340 std::optional<int> override = pad->GetClearanceOverrides( nullptr );
1341
1342 if( override.has_value() )
1343 worstClearance = std::max( worstClearance, override.value() );
1344 }
1345
1346 for( ZONE* zone : footprint->Zones() )
1347 worstClearance = std::max( worstClearance, zone->GetLocalClearance().value() );
1348 }
1349
1350 m_maxClearanceValue = worstClearance;
1351 }
1352
1353 return m_maxClearanceValue.value_or( 0 );
1354};
1355
1356
1357void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter, const std::vector<ZONE*>& aZones )
1358{
1359 std::vector<ZONE*> zones = aZones;
1360
1361 if( zones.empty() )
1362 zones = m_zones;
1363
1364 if( zones.empty() )
1365 return;
1366
1367 if( aReporter )
1368 aReporter->Report( _( "Tessellating copper zones..." ) );
1369
1371 std::vector<std::future<size_t>> returns;
1372
1373 returns.reserve( zones.size() );
1374
1376 [&tp]( std::function<void()> aTask )
1377 {
1378 tp.detach_task( std::move( aTask ) );
1379 };
1380
1381 auto cache_zones =
1382 [aReporter, &submitter]( ZONE* aZone ) -> size_t
1383 {
1384 if( aReporter && aReporter->IsCancelled() )
1385 return 0;
1386
1387 aZone->CacheTriangulation( UNDEFINED_LAYER, submitter );
1388
1389 if( aReporter )
1390 aReporter->AdvanceProgress();
1391
1392 return 1;
1393 };
1394
1395 for( ZONE* zone : zones )
1396 returns.emplace_back( tp.submit_task(
1397 [cache_zones, zone]
1398 {
1399 return cache_zones( zone );
1400 } ) );
1401
1402 // Finalize the triangulation threads
1403 for( const std::future<size_t>& ret : returns )
1404 {
1405 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1406
1407 while( status != std::future_status::ready )
1408 {
1409 if( aReporter )
1410 aReporter->KeepRefreshing();
1411
1412 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1413 }
1414 }
1415}
1416
1417
1418void BOARD::RunOnNestedEmbeddedFiles( const std::function<void( EMBEDDED_FILES* )>& aFunction )
1419{
1420 for( FOOTPRINT* footprint : m_footprints )
1421 aFunction( footprint->GetEmbeddedFiles() );
1422}
1423
1424
1426{
1428 [&]( EMBEDDED_FILES* nested )
1429 {
1430 for( auto& [filename, embeddedFile] : nested->EmbeddedFileMap() )
1431 {
1433
1434 if( file )
1435 {
1436 embeddedFile->compressedEncodedData = file->compressedEncodedData;
1437 embeddedFile->decompressedData = file->decompressedData;
1438 embeddedFile->data_hash = file->data_hash;
1439 embeddedFile->is_valid = file->is_valid;
1440 }
1441 }
1442 } );
1443}
1444
1445
1446wxString BOARD::GetUniqueZoneName( const wxString& aBaseName, const ZONE* aExclude ) const
1447{
1448 if( aBaseName.IsEmpty() )
1449 return aBaseName;
1450
1451 auto inUse = [&]( const wxString& aName )
1452 {
1453 for( const ZONE* zone : m_zones )
1454 {
1455 if( zone != aExclude && zone->GetZoneName() == aName )
1456 return true;
1457 }
1458
1459 return false;
1460 };
1461
1462 if( !inUse( aBaseName ) )
1463 return aBaseName;
1464
1465 // Strip a trailing _<number> so repeated copies increment the root (foo_1 -> foo_2),
1466 // instead of stacking suffixes (foo_1_1_1).
1467 wxString root = aBaseName;
1468
1469 if( aBaseName.Find( '_' ) != wxNOT_FOUND )
1470 {
1471 wxString suffix = aBaseName.AfterLast( '_' );
1472 bool allDigits = !suffix.IsEmpty();
1473
1474 for( wxUniChar ch : suffix )
1475 {
1476 if( !wxIsdigit( ch ) )
1477 {
1478 allDigits = false;
1479 break;
1480 }
1481 }
1482
1483 if( allDigits )
1484 root = aBaseName.BeforeLast( '_' );
1485 }
1486
1487 for( int i = 1;; ++i )
1488 {
1489 wxString candidate = wxString::Format( wxT( "%s_%d" ), root, i );
1490
1491 if( !inUse( candidate ) )
1492 return candidate;
1493 }
1494}
1495
1496
1497void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode, bool aSkipConnectivity )
1498{
1499 if( aBoardItem == nullptr )
1500 {
1501 wxFAIL_MSG( wxT( "BOARD::Add() param error: aBoardItem nullptr" ) );
1502 return;
1503 }
1504
1505 switch( aBoardItem->Type() )
1506 {
1507 case PCB_NETINFO_T:
1508 m_NetInfo.AppendNet( (NETINFO_ITEM*) aBoardItem );
1509 break;
1510
1511 // this one uses a vector
1512 case PCB_MARKER_T:
1513 m_markers.push_back( (PCB_MARKER*) aBoardItem );
1514 break;
1515
1516 // this one uses a vector
1517 case PCB_GROUP_T:
1518 m_groups.push_back( (PCB_GROUP*) aBoardItem );
1519 break;
1520
1521 case PCB_CONSTRAINT_T:
1522 m_constraints.push_back( (PCB_CONSTRAINT*) aBoardItem );
1523 break;
1524
1525 // this one uses a vector
1526 case PCB_GENERATOR_T:
1527 m_generators.push_back( (PCB_GENERATOR*) aBoardItem );
1528 break;
1529
1530 // this one uses a vector
1531 case PCB_ZONE_T:
1532 m_zones.push_back( (ZONE*) aBoardItem );
1533 break;
1534
1535 case PCB_VIA_T:
1536 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1537 m_tracks.push_back( static_cast<PCB_VIA*>( aBoardItem ) );
1538 else
1539 m_tracks.push_front( static_cast<PCB_VIA*>( aBoardItem ) );
1540
1541 break;
1542
1543 case PCB_TRACE_T:
1544 case PCB_ARC_T:
1545 if( !IsCopperLayer( aBoardItem->GetLayer() ) )
1546 {
1547 // The only current known source of these is SWIG (KICAD-BY7, et al).
1548 // N.B. This inserts a small memory leak as we lose the track/via/arc.
1549 wxFAIL_MSG( wxString::Format( "BOARD::Add() Cannot place Track on non-copper layer: %d = %s",
1550 static_cast<int>( aBoardItem->GetLayer() ),
1551 GetLayerName( aBoardItem->GetLayer() ) ) );
1552 return;
1553 }
1554
1555 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1556 m_tracks.push_back( static_cast<PCB_TRACK*>( aBoardItem ) );
1557 else
1558 m_tracks.push_front( static_cast<PCB_TRACK*>( aBoardItem ) );
1559
1560 break;
1561
1562 case PCB_FOOTPRINT_T:
1563 {
1564 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aBoardItem );
1565
1566 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1567 m_footprints.push_back( footprint );
1568 else
1569 m_footprints.push_front( footprint );
1570
1571 break;
1572 }
1573
1574 case PCB_BARCODE_T:
1575 case PCB_DIM_ALIGNED_T:
1576 case PCB_DIM_CENTER_T:
1577 case PCB_DIM_RADIAL_T:
1579 case PCB_DIM_LEADER_T:
1580 case PCB_SHAPE_T:
1582 case PCB_FIELD_T:
1583 case PCB_TEXT_T:
1584 case PCB_TEXTBOX_T:
1585 case PCB_TABLE_T:
1586 case PCB_DRILL_CHART_T:
1587 case PCB_DRILL_MAP_T:
1588 case PCB_TARGET_T:
1589 case PCB_GRID_ITEM_T:
1590 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1591 m_drawings.push_back( aBoardItem );
1592 else
1593 m_drawings.push_front( aBoardItem );
1594
1595 break;
1596
1597 case PCB_POINT_T:
1598 // These aren't graphics as they have no physical presence
1599 m_points.push_back( static_cast<PCB_POINT*>( aBoardItem ) );
1600 break;
1601
1602 case PCB_TABLECELL_T:
1603 // Handled by parent table
1604 break;
1605
1606 default:
1607 wxFAIL_MSG( wxString::Format( wxT( "BOARD::Add() item type %s not handled" ), aBoardItem->GetClass() ) );
1608 return;
1609 }
1610
1611 aBoardItem->SetParent( this );
1612 aBoardItem->ClearEditFlags();
1613
1614 // Index only after the item is accepted and parented, so a rejected item never lingers as a
1615 // dangling cache entry and an indexed item can always reach its board through its parent.
1616 CacheItemById( aBoardItem );
1617
1618 if( aBoardItem->Type() == PCB_FOOTPRINT_T || BaseType( aBoardItem->Type() ) == PCB_TABLE_T )
1619 CacheChildrenById( aBoardItem );
1620
1621 if( !aSkipConnectivity )
1622 m_connectivity->Add( aBoardItem );
1623
1624 if( aMode != ADD_MODE::BULK_INSERT && aMode != ADD_MODE::BULK_APPEND )
1626
1627 noteDrillModelChange( aBoardItem );
1628}
1629
1630
1631void BOARD::FinalizeBulkAdd( std::vector<BOARD_ITEM*>& aNewItems )
1632{
1634
1635 for( BOARD_ITEM* item : aNewItems )
1636 noteDrillModelChange( item );
1637}
1638
1639
1640void BOARD::FinalizeBulkRemove( std::vector<BOARD_ITEM*>& aRemovedItems )
1641{
1642 InvokeListeners( &BOARD_LISTENER::OnBoardItemsRemoved, *this, aRemovedItems );
1643
1644 for( BOARD_ITEM* item : aRemovedItems )
1645 noteDrillModelChange( item );
1646}
1647
1648
1650{
1651 for( int ii = (int) m_zones.size() - 1; ii >= 0; --ii )
1652 {
1653 ZONE* zone = m_zones[ii];
1654
1655 if( zone->IsTeardropArea() && zone->HasFlag( STRUCT_DELETED ) )
1656 {
1657 UncacheItemById( zone->m_Uuid );
1658 m_zones.erase( m_zones.begin() + ii );
1660 m_connectivity->Remove( zone );
1661
1662 aCommit.Removed( zone );
1663 }
1664 }
1665}
1666
1667
1668void BOARD::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aRemoveMode )
1669{
1670 // find these calls and fix them! Don't send me no stinking' nullptr.
1671 wxASSERT( aBoardItem );
1672
1673 // This is redundant with BOARD_COMMIT::Push but necessary to support SWIG interaction
1674 // until the SWIG API is completely removed (since it doesn't use the commit system)
1675 if( EDA_GROUP* parentGroup = aBoardItem->GetParentGroup();
1676 parentGroup && !( parentGroup->AsEdaItem()->GetFlags() & STRUCT_DELETED ) )
1677 {
1678 parentGroup->RemoveItem( aBoardItem );
1679 }
1680
1681 UncacheItemById( aBoardItem->m_Uuid );
1682
1683 switch( aBoardItem->Type() )
1684 {
1685 case PCB_NETINFO_T:
1686 {
1687 NETINFO_ITEM* netItem = static_cast<NETINFO_ITEM*>( aBoardItem );
1688 NETINFO_ITEM* unconnected = m_NetInfo.GetNetItem( NETINFO_LIST::UNCONNECTED );
1689
1690 for( BOARD_CONNECTED_ITEM* boardItem : AllConnectedItems() )
1691 {
1692 if( boardItem->GetNet() == netItem )
1693 boardItem->SetNet( unconnected );
1694 }
1695
1696 m_NetInfo.RemoveNet( netItem );
1697 break;
1698 }
1699
1700 case PCB_MARKER_T:
1701 std::erase( m_markers, aBoardItem );
1702 break;
1703
1704 case PCB_GROUP_T:
1705 std::erase( m_groups, aBoardItem );
1706 break;
1707
1708 case PCB_CONSTRAINT_T:
1709 std::erase( m_constraints, aBoardItem );
1710 break;
1711
1712 case PCB_ZONE_T:
1713 std::erase( m_zones, aBoardItem );
1714 break;
1715
1716 case PCB_POINT_T:
1717 std::erase( m_points, aBoardItem );
1718 break;
1719
1720 case PCB_GENERATOR_T:
1721 std::erase( m_generators, aBoardItem );
1722 break;
1723
1724 case PCB_FOOTPRINT_T:
1725 std::erase( m_footprints, aBoardItem );
1726 UncacheChildrenById( aBoardItem );
1727
1728 break;
1729
1730 case PCB_TRACE_T:
1731 case PCB_ARC_T:
1732 case PCB_VIA_T:
1733 std::erase( m_tracks, aBoardItem );
1734 break;
1735
1736 case PCB_BARCODE_T:
1737 case PCB_DIM_ALIGNED_T:
1738 case PCB_DIM_CENTER_T:
1739 case PCB_DIM_RADIAL_T:
1741 case PCB_DIM_LEADER_T:
1742 case PCB_SHAPE_T:
1744 case PCB_FIELD_T:
1745 case PCB_TEXT_T:
1746 case PCB_TEXTBOX_T:
1747 case PCB_TABLE_T:
1748 case PCB_DRILL_CHART_T:
1749 case PCB_DRILL_MAP_T:
1750 case PCB_TARGET_T:
1751 case PCB_GRID_ITEM_T:
1752 std::erase( m_drawings, aBoardItem );
1753
1754 if( BaseType( aBoardItem->Type() ) == PCB_TABLE_T )
1755 UncacheChildrenById( aBoardItem );
1756
1757 break;
1758
1759 case PCB_TABLECELL_T:
1760 // Handled by parent table
1761 break;
1762
1763 // other types may use linked list
1764 default:
1765 wxFAIL_MSG( wxString::Format( wxT( "BOARD::Remove() item type %s not handled" ), aBoardItem->GetClass() ) );
1766 }
1767
1768 aBoardItem->SetFlags( STRUCT_DELETED );
1769
1770 m_connectivity->Remove( aBoardItem );
1771
1772 // Bump here, not in ~FOOTPRINT/~ZONE, so an item kept alive after removal (undo) still invalidates
1774
1775 if( aRemoveMode != REMOVE_MODE::BULK )
1777
1778 noteDrillModelChange( aBoardItem );
1779}
1780
1781
1782void BOARD::RemoveAll( std::initializer_list<KICAD_T> aTypes )
1783{
1784 std::vector<BOARD_ITEM*> removed;
1785 std::vector<NETINFO_ITEM*> removedNets;
1786
1787 for( const KICAD_T& type : aTypes )
1788 {
1789 switch( type )
1790 {
1791 case PCB_NETINFO_T:
1792 for( NETINFO_ITEM* item : m_NetInfo )
1793 {
1794 removed.emplace_back( item );
1795 removedNets.emplace_back( item );
1796 }
1797
1798 // Listeners must observe live pointers during FinalizeBulkRemove;
1799 // free after notification (issue 24100).
1800 m_NetInfo.detachAll();
1801 break;
1802
1803 case PCB_MARKER_T:
1804 std::copy( m_markers.begin(), m_markers.end(), std::back_inserter( removed ) );
1805 m_markers.clear();
1806 break;
1807
1808 case PCB_GROUP_T:
1809 std::copy( m_groups.begin(), m_groups.end(), std::back_inserter( removed ) );
1810 m_groups.clear();
1811 break;
1812
1813 case PCB_CONSTRAINT_T:
1814 std::copy( m_constraints.begin(), m_constraints.end(), std::back_inserter( removed ) );
1815 m_constraints.clear();
1816 break;
1817
1818 case PCB_POINT_T:
1819 std::copy( m_points.begin(), m_points.end(), std::back_inserter( removed ) );
1820 m_points.clear();
1821 break;
1822
1823 case PCB_ZONE_T:
1824 std::copy( m_zones.begin(), m_zones.end(), std::back_inserter( removed ) );
1825 m_zones.clear();
1826 break;
1827
1828 case PCB_GENERATOR_T:
1829 std::copy( m_generators.begin(), m_generators.end(), std::back_inserter( removed ) );
1830 m_generators.clear();
1831 break;
1832
1833 case PCB_FOOTPRINT_T:
1834 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( removed ) );
1835 m_footprints.clear();
1836 break;
1837
1838 case PCB_TRACE_T:
1839 std::copy( m_tracks.begin(), m_tracks.end(), std::back_inserter( removed ) );
1840 m_tracks.clear();
1841 break;
1842
1843 case PCB_ARC_T:
1844 case PCB_VIA_T:
1845 wxFAIL_MSG( wxT( "Use PCB_TRACE_T to remove all tracks, arcs, and vias" ) );
1846 break;
1847
1848 case PCB_SHAPE_T:
1849 std::copy( m_drawings.begin(), m_drawings.end(), std::back_inserter( removed ) );
1850 m_drawings.clear();
1851 break;
1852
1853 case PCB_DIM_ALIGNED_T:
1854 case PCB_DIM_CENTER_T:
1855 case PCB_DIM_RADIAL_T:
1857 case PCB_DIM_LEADER_T:
1859 case PCB_FIELD_T:
1860 case PCB_TEXT_T:
1861 case PCB_TEXTBOX_T:
1862 case PCB_TABLE_T:
1863 case PCB_DRILL_CHART_T:
1864 case PCB_DRILL_MAP_T:
1865 case PCB_TARGET_T:
1866 case PCB_BARCODE_T:
1867 wxFAIL_MSG( wxT( "Use PCB_SHAPE_T to remove all graphics and text" ) );
1868 break;
1869
1870 default:
1871 wxFAIL_MSG( wxT( "BOARD::RemoveAll() needs more ::Type() support" ) );
1872 }
1873 }
1874
1876
1878
1879 FinalizeBulkRemove( removed );
1880
1881 for( NETINFO_ITEM* item : removedNets )
1882 delete item;
1883}
1884
1885
1887{
1888 PCB_LAYER_COLLECTOR collector;
1889
1890 collector.SetLayerId( aLayer );
1892
1893 if( collector.GetCount() != 0 )
1894 {
1895 // Skip items owned by footprints and footprints when building
1896 // the actual list of removed layers: these items are not removed
1897 for( int i = 0; i < collector.GetCount(); i++ )
1898 {
1899 BOARD_ITEM* item = collector[i];
1900
1901 if( item->Type() == PCB_FOOTPRINT_T || item->GetParentFootprint() )
1902 continue;
1903
1904 // Vias are on multiple adjacent layers, but only the top and
1905 // the bottom layers are stored. So there are issues only if one
1906 // is on a removed layer
1907 if( item->Type() == PCB_VIA_T )
1908 {
1909 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1910
1911 if( via->GetViaType() == VIATYPE::THROUGH )
1912 continue;
1913 else
1914 {
1915 PCB_LAYER_ID top_layer;
1916 PCB_LAYER_ID bottom_layer;
1917 via->LayerPair( &top_layer, &bottom_layer );
1918
1919 if( top_layer != aLayer && bottom_layer != aLayer )
1920 continue;
1921 }
1922 }
1923
1924 return true;
1925 }
1926 }
1927
1928 return false;
1929}
1930
1931
1933{
1934 bool modified = false;
1935 bool removedItemLayers = false;
1936 PCB_LAYER_COLLECTOR collector;
1937
1938 collector.SetLayerId( aLayer );
1940
1941 for( int i = 0; i < collector.GetCount(); i++ )
1942 {
1943 BOARD_ITEM* item = collector[i];
1944
1945 // Do not remove/change an item owned by a footprint
1946 if( item->GetParentFootprint() )
1947 continue;
1948
1949 // Do not remove footprints
1950 if( item->Type() == PCB_FOOTPRINT_T )
1951 continue;
1952
1953 // Note: vias are specific. They are only on copper layers, and
1954 // do not use a layer set, only store the copper top and the copper bottom.
1955 // So reinit the layer set does not work with vias
1956 if( item->Type() == PCB_VIA_T )
1957 {
1958 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1959
1960 if( via->GetViaType() == VIATYPE::THROUGH )
1961 {
1962 removedItemLayers = true;
1963 continue;
1964 }
1965 else if( via->IsOnLayer( aLayer ) )
1966 {
1967 PCB_LAYER_ID top_layer;
1968 PCB_LAYER_ID bottom_layer;
1969 via->LayerPair( &top_layer, &bottom_layer );
1970
1971 if( top_layer == aLayer || bottom_layer == aLayer )
1972 {
1973 // blind/buried vias with a top or bottom layer on a removed layer
1974 // are removed. Perhaps one could just modify the top/bottom layer,
1975 // but I am not sure this is better.
1976 Remove( item );
1977 delete item;
1978 modified = true;
1979 }
1980
1981 removedItemLayers = true;
1982 }
1983 }
1984 else if( item->IsOnLayer( aLayer ) )
1985 {
1986 LSET layers = item->GetLayerSet();
1987
1988 layers.reset( aLayer );
1989
1990 if( layers.any() )
1991 {
1992 item->SetLayerSet( layers );
1993 }
1994 else
1995 {
1996 Remove( item );
1997 delete item;
1998 modified = true;
1999 }
2000
2001 removedItemLayers = true;
2002 }
2003 }
2004
2005 if( removedItemLayers )
2007
2008 return modified;
2009}
2010
2011
2012wxString BOARD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
2013{
2014 return wxString::Format( _( "PCB" ) );
2015}
2016
2017
2019{
2020 INSPECTOR_FUNC inspector = [&]( EDA_ITEM* descendant, void* aTestData )
2021 {
2022 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( descendant );
2023
2024 if( dimension->GetUnitsMode() == DIM_UNITS_MODE::AUTOMATIC )
2025 {
2026 dimension->UpdateUnits();
2027
2028 if( aView )
2029 aView->Update( dimension );
2030 }
2031
2033 };
2034
2035 aItem->Visit( inspector, nullptr,
2037}
2038
2039
2041{
2042 for( PCB_MARKER* marker : m_markers )
2043 UncacheItemById( marker->m_Uuid );
2044
2045 for( PCB_MARKER* marker : m_markers )
2046 delete marker;
2047
2048 m_markers.clear();
2050}
2051
2052
2053void BOARD::DeleteMARKERs( bool aWarningsAndErrors, bool aExclusions )
2054{
2055 // Deleting lots of items from a vector can be very slow. Copy remaining items instead.
2056 std::vector<PCB_MARKER*> remaining;
2057
2058 for( PCB_MARKER* marker : m_markers )
2059 {
2060 if( ( marker->GetSeverity() == RPT_SEVERITY_EXCLUSION && aExclusions )
2061 || ( marker->GetSeverity() != RPT_SEVERITY_EXCLUSION && aWarningsAndErrors ) )
2062 {
2063 UncacheItemById( marker->m_Uuid );
2064 delete marker;
2065 }
2066 else
2067 {
2068 remaining.push_back( marker );
2069 }
2070 }
2071
2072 m_markers = std::move( remaining );
2074}
2075
2076
2078{
2079 std::vector<FOOTPRINT*> footprints;
2080 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( footprints ) );
2081
2083
2084 for( FOOTPRINT* footprint : footprints )
2085 delete footprint;
2086}
2087
2088
2090{
2091 std::vector<FOOTPRINT*> footprints;
2092 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( footprints ) );
2093
2095
2096 for( FOOTPRINT* footprint : footprints )
2097 footprint->SetParent( nullptr );
2098}
2099
2100
2101static PCB_TABLECELL* findTableCell( const BOARD_ITEM* aDrawing, const KIID& aID )
2102{
2103 if( BaseType( aDrawing->Type() ) != PCB_TABLE_T )
2104 return nullptr;
2105
2106 for( PCB_TABLECELL* cell : static_cast<const PCB_TABLE*>( aDrawing )->GetCells() )
2107 {
2108 if( cell->m_Uuid == aID )
2109 return cell;
2110 }
2111
2112 return nullptr;
2113}
2114
2115
2116BOARD_ITEM* BOARD::ResolveItem( const KIID& aID, bool aAllowNullptrReturn ) const
2117{
2118 if( aID == niluuid )
2119 return nullptr;
2120
2121 if( BOARD_ITEM* cached = GetCachedItemById( aID ) )
2122 return cached;
2123
2124 // Linear scan fallback for items not in the cache. Any hit is cached so
2125 // subsequent lookups for the same item are O(1).
2126
2127 for( PCB_GROUP* group : m_groups )
2128 {
2129 if( group->m_Uuid == aID )
2130 return CacheAndReturnItemById( aID, group );
2131 }
2132
2133 for( PCB_CONSTRAINT* constraint : m_constraints )
2134 {
2135 if( constraint->m_Uuid == aID )
2136 return CacheAndReturnItemById( aID, constraint );
2137 }
2138
2139 for( PCB_GENERATOR* generator : m_generators )
2140 {
2141 if( generator->m_Uuid == aID )
2142 return CacheAndReturnItemById( aID, generator );
2143 }
2144
2145 for( PCB_TRACK* track : Tracks() )
2146 {
2147 if( track->m_Uuid == aID )
2148 return CacheAndReturnItemById( aID, track );
2149 }
2150
2151 for( FOOTPRINT* footprint : Footprints() )
2152 {
2153 if( footprint->m_Uuid == aID )
2154 return CacheAndReturnItemById( aID, footprint );
2155
2156 for( PAD* pad : footprint->Pads() )
2157 {
2158 if( pad->m_Uuid == aID )
2159 return CacheAndReturnItemById( aID, pad );
2160 }
2161
2162 for( PCB_FIELD* field : footprint->GetFields() )
2163 {
2164 wxCHECK2( field, continue );
2165
2166 if( field && field->m_Uuid == aID )
2167 return CacheAndReturnItemById( aID, field );
2168 }
2169
2170 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2171 {
2172 if( PCB_TABLECELL* cell = findTableCell( drawing, aID ) )
2173 return CacheAndReturnItemById( aID, cell );
2174
2175 if( drawing->m_Uuid == aID )
2176 return CacheAndReturnItemById( aID, drawing );
2177 }
2178
2179 for( BOARD_ITEM* zone : footprint->Zones() )
2180 {
2181 if( zone->m_Uuid == aID )
2182 return CacheAndReturnItemById( aID, zone );
2183 }
2184
2185 for( PCB_GROUP* group : footprint->Groups() )
2186 {
2187 if( group->m_Uuid == aID )
2188 return CacheAndReturnItemById( aID, group );
2189 }
2190
2191 for( PCB_CONSTRAINT* constraint : footprint->Constraints() )
2192 {
2193 if( constraint->m_Uuid == aID )
2194 return CacheAndReturnItemById( aID, constraint );
2195 }
2196
2197 for( PCB_POINT* point : footprint->Points() )
2198 {
2199 if( point->m_Uuid == aID )
2200 return CacheAndReturnItemById( aID, point );
2201 }
2202 }
2203
2204 for( ZONE* zone : Zones() )
2205 {
2206 if( zone->m_Uuid == aID )
2207 return CacheAndReturnItemById( aID, zone );
2208 }
2209
2210 for( BOARD_ITEM* drawing : Drawings() )
2211 {
2212 if( PCB_TABLECELL* cell = findTableCell( drawing, aID ) )
2213 return CacheAndReturnItemById( aID, cell );
2214
2215 if( drawing->m_Uuid == aID )
2216 return CacheAndReturnItemById( aID, drawing );
2217 }
2218
2219 for( PCB_MARKER* marker : m_markers )
2220 {
2221 if( marker->m_Uuid == aID )
2222 return CacheAndReturnItemById( aID, marker );
2223 }
2224
2225 for( PCB_POINT* point : m_points )
2226 {
2227 if( point->m_Uuid == aID )
2228 return CacheAndReturnItemById( aID, point );
2229 }
2230
2231 for( NETINFO_ITEM* netInfo : m_NetInfo )
2232 {
2233 if( netInfo->m_Uuid == aID )
2234 return CacheAndReturnItemById( aID, netInfo );
2235 }
2236
2237 if( m_Uuid == aID )
2238 return const_cast<BOARD*>( this );
2239
2240 // Not found; weak reference has been deleted.
2241 if( aAllowNullptrReturn )
2242 return nullptr;
2243
2245}
2246
2247
2249{
2250 auto it = m_itemByIdCache.find( aId );
2251
2252 if( it == m_itemByIdCache.end() )
2253 return nullptr;
2254
2255 BOARD_ITEM* item = it->second;
2256
2257 if( item && item->m_Uuid == aId )
2258 return item;
2259
2260 UncacheItemById( aId );
2261 return nullptr;
2262}
2263
2264
2266{
2267 if( IsFootprintHolder() )
2268 return;
2269
2270 // Hand the item to this board. A stale owner cannot evict it.
2271 if( aItem->m_boardCacheOwner && aItem->m_boardCacheOwner != this )
2272 aItem->m_boardCacheOwner->UncacheItemByPtr( aItem );
2273
2274 // Called once per item on load, so probe and insert in one lookup per map and pay for the
2275 // aliasing fixups only when a key was already taken
2276 auto [idIt, idInserted] = m_itemByIdCache.try_emplace( aItem->m_Uuid, aItem );
2277 auto [itemIt, itemInserted] = m_cachedIdByItem.try_emplace( aItem, aItem->m_Uuid );
2278
2279 if( !itemInserted && itemIt->second != aItem->m_Uuid )
2280 {
2281 // The item was indexed under an older UUID; drop that forward alias
2282 auto prevIt = m_itemByIdCache.find( itemIt->second );
2283
2284 if( prevIt != m_itemByIdCache.end() && prevIt->second == aItem )
2285 m_itemByIdCache.erase( prevIt );
2286
2287 itemIt->second = aItem->m_Uuid;
2288 }
2289
2290 if( !idInserted && idIt->second != aItem )
2291 {
2292 // Another item already claims this UUID; evict it
2293 if( auto prev = m_cachedIdByItem.find( idIt->second );
2294 prev != m_cachedIdByItem.end() && prev->second == aItem->m_Uuid )
2295 {
2296 idIt->second->m_boardCacheOwner = nullptr;
2297 m_cachedIdByItem.erase( prev );
2298 }
2299
2300 idIt->second = aItem;
2301 }
2302
2303 // Set owner last, see CacheAndReturnItemById()
2304 aItem->m_boardCacheOwner = const_cast<BOARD*>( this );
2305}
2306
2307
2308void BOARD::UncacheItemById( const KIID& aId ) const
2309{
2310 auto it = m_itemByIdCache.find( aId );
2311
2312 if( it == m_itemByIdCache.end() )
2313 return;
2314
2315 const BOARD_ITEM* item = it->second;
2316
2317 m_itemByIdCache.erase( it );
2318
2319 if( auto cached = m_cachedIdByItem.find( item );
2320 cached != m_cachedIdByItem.end() && cached->second == aId )
2321 {
2322 item->m_boardCacheOwner = nullptr;
2323 m_cachedIdByItem.erase( cached );
2324 }
2325}
2326
2327
2329{
2330 if( IsFootprintHolder() )
2331 return aItem;
2332
2333 // Hand the item to this board. A stale owner cannot evict it.
2334 if( aItem->m_boardCacheOwner && aItem->m_boardCacheOwner != this )
2335 aItem->m_boardCacheOwner->UncacheItemByPtr( aItem );
2336
2337 // catches a future alias between the cache key and the cached item's own UUID
2338 wxASSERT_MSG( aItem && aItem->m_Uuid == aId,
2339 wxT( "BOARD identity cache key must be the item's own UUID" ) );
2340
2341 if( auto prev = m_cachedIdByItem.find( aItem );
2342 prev != m_cachedIdByItem.end() && prev->second != aId )
2343 {
2344 auto prevIt = m_itemByIdCache.find( prev->second );
2345
2346 if( prevIt != m_itemByIdCache.end() && prevIt->second == aItem )
2347 m_itemByIdCache.erase( prevIt );
2348 }
2349
2350 if( auto existing = m_itemByIdCache.find( aId );
2351 existing != m_itemByIdCache.end() && existing->second != aItem )
2352 {
2353 if( auto prev = m_cachedIdByItem.find( existing->second );
2354 prev != m_cachedIdByItem.end() && prev->second == aId )
2355 {
2356 existing->second->m_boardCacheOwner = nullptr;
2357 m_cachedIdByItem.erase( prev );
2358 }
2359 }
2360
2361 m_itemByIdCache.insert_or_assign( aId, aItem );
2362 m_cachedIdByItem.insert_or_assign( aItem, aId );
2363
2364 // Set owner last, a half-done update then reads as not indexed
2365 aItem->m_boardCacheOwner = const_cast<BOARD*>( this );
2366
2367 return aItem;
2368}
2369
2370
2372{
2373 // Clear owner first, the item no longer points to this board
2374 aItem->m_boardCacheOwner = nullptr;
2375
2376 if( auto cached = m_cachedIdByItem.find( aItem ); cached != m_cachedIdByItem.end() )
2377 {
2378 auto it = m_itemByIdCache.find( cached->second );
2379
2380 if( it != m_itemByIdCache.end() && it->second == aItem )
2381 m_itemByIdCache.erase( it );
2382
2383 m_cachedIdByItem.erase( cached );
2384 return;
2385 }
2386
2387 for( auto it = m_itemByIdCache.begin(); it != m_itemByIdCache.end(); )
2388 {
2389 if( it->second == aItem )
2390 it = m_itemByIdCache.erase( it );
2391 else
2392 ++it;
2393 }
2394}
2395
2396
2398{
2399 for( const auto& [item, id] : m_cachedIdByItem )
2400 item->m_boardCacheOwner = nullptr;
2401
2402 m_itemByIdCache.clear();
2403 m_cachedIdByItem.clear();
2404}
2405
2406
2407void BOARD::RebindItemUuid( BOARD_ITEM* aItem, const KIID& aNewId )
2408{
2409 wxCHECK_RET( aItem, "BOARD::RebindItemUuid() requires a valid item" );
2410
2411 if( IsFootprintHolder() )
2412 return;
2413
2414 if( aItem->m_Uuid == aNewId )
2415 {
2416 CacheAndReturnItemById( aNewId, aItem );
2417 return;
2418 }
2419
2420 if( BOARD_ITEM* existing = GetCachedItemById( aNewId ); existing && existing != aItem )
2421 {
2422 wxFAIL_MSG( wxString::Format( "BOARD::RebindItemUuid() duplicate target UUID: %s",
2423 aNewId.AsString() ) );
2424 return;
2425 }
2426
2427 UncacheItemByPtr( aItem );
2428 aItem->SetUuidDirect( aNewId );
2429 CacheAndReturnItemById( aNewId, aItem );
2430}
2431
2432
2434{
2435 std::set<KIID> ids;
2436 int duplicates = 0;
2437
2438 auto processItem =
2439 [&]( BOARD_ITEM* aItem )
2440 {
2441 wxCHECK2( aItem, return );
2442
2443 if( ids.count( aItem->m_Uuid ) )
2444 {
2445 duplicates++;
2446 RebindItemUuid( aItem, KIID() );
2447 }
2448
2449 ids.insert( aItem->m_Uuid );
2450 };
2451
2452 // Footprint IDs are the most important, so give them the first crack at "claiming" a
2453 // particular KIID.
2454 for( FOOTPRINT* footprint : Footprints() )
2455 processItem( footprint );
2456
2457 // After that the principal use is for DRC marker pointers, which are most likely to pads
2458 // or tracks.
2459 for( FOOTPRINT* footprint : Footprints() )
2460 {
2461 for( PAD* pad : footprint->Pads() )
2462 processItem( pad );
2463 }
2464
2465 for( PCB_TRACK* track : Tracks() )
2466 processItem( track );
2467
2468 // From here out I don't think order matters much.
2469 for( FOOTPRINT* footprint : Footprints() )
2470 {
2471 processItem( &footprint->Reference() );
2472 processItem( &footprint->Value() );
2473
2474 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2475 processItem( item );
2476
2477 for( ZONE* zone : footprint->Zones() )
2478 processItem( zone );
2479
2480 for( PCB_GROUP* group : footprint->Groups() )
2481 processItem( group );
2482 }
2483
2484 // Everything owned by the board not handled above.
2485 for( BOARD_ITEM* item : GetItemSet() )
2486 {
2487 // Top-level footprints and tracks were handled above.
2488 switch( item->Type() )
2489 {
2490 case PCB_FOOTPRINT_T:
2491 case PCB_TRACE_T:
2492 case PCB_ARC_T:
2493 case PCB_VIA_T:
2494 break;
2495
2496 default:
2497 processItem( item );
2498 break;
2499 }
2500 }
2501
2502 return duplicates;
2503}
2504
2505
2506void BOARD::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
2507{
2508 // the board itself
2509 aMap[m_Uuid] = this;
2510
2511 for( PCB_TRACK* track : Tracks() )
2512 aMap[track->m_Uuid] = track;
2513
2514 for( FOOTPRINT* footprint : Footprints() )
2515 {
2516 aMap[footprint->m_Uuid] = footprint;
2517
2518 for( PAD* pad : footprint->Pads() )
2519 aMap[pad->m_Uuid] = pad;
2520
2521 aMap[footprint->Reference().m_Uuid] = &footprint->Reference();
2522 aMap[footprint->Value().m_Uuid] = &footprint->Value();
2523
2524 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2525 aMap[drawing->m_Uuid] = drawing;
2526 }
2527
2528 for( ZONE* zone : Zones() )
2529 aMap[zone->m_Uuid] = zone;
2530
2531 for( BOARD_ITEM* drawing : Drawings() )
2532 aMap[drawing->m_Uuid] = drawing;
2533
2534 for( PCB_MARKER* marker : m_markers )
2535 aMap[marker->m_Uuid] = marker;
2536
2537 for( PCB_GROUP* group : m_groups )
2538 aMap[group->m_Uuid] = group;
2539
2540 for( PCB_CONSTRAINT* constraint : m_constraints )
2541 aMap[constraint->m_Uuid] = constraint;
2542
2543 for( PCB_POINT* point : m_points )
2544 aMap[point->m_Uuid] = point;
2545
2546 for( PCB_GENERATOR* generator : m_generators )
2547 aMap[generator->m_Uuid] = generator;
2548}
2549
2550
2551wxString BOARD::ConvertCrossReferencesToKIIDs( const wxString& aSource ) const
2552{
2553 wxString newbuf;
2554 size_t sourceLen = aSource.length();
2555
2556 for( size_t i = 0; i < sourceLen; ++i )
2557 {
2558 // Check for escaped expressions: \${ or \@{
2559 // These should be copied verbatim without any ref→KIID conversion
2560 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2561 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2562 {
2563 // Copy the escape sequence and the entire escaped expression
2564 newbuf.append( aSource[i] ); // backslash
2565 newbuf.append( aSource[i + 1] ); // $ or @
2566 newbuf.append( aSource[i + 2] ); // {
2567 i += 2;
2568
2569 // Find and copy everything until the matching closing brace
2570 int braceDepth = 1;
2571 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2572 {
2573 if( aSource[i] == '{' )
2574 braceDepth++;
2575 else if( aSource[i] == '}' )
2576 braceDepth--;
2577
2578 newbuf.append( aSource[i] );
2579 }
2580 i--; // Back up one since the for loop will increment
2581 continue;
2582 }
2583
2584 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2585 {
2586 wxString token;
2587 bool isCrossRef = false;
2588
2589 for( i = i + 2; i < sourceLen; ++i )
2590 {
2591 if( aSource[i] == '}' )
2592 break;
2593
2594 if( aSource[i] == ':' )
2595 isCrossRef = true;
2596
2597 token.append( aSource[i] );
2598 }
2599
2600 if( isCrossRef )
2601 {
2602 wxString remainder;
2603 wxString ref = token.BeforeFirst( ':', &remainder );
2604
2605 for( const FOOTPRINT* footprint : Footprints() )
2606 {
2607 if( footprint->GetReference().CmpNoCase( ref ) == 0 )
2608 {
2609 wxString test( remainder );
2610
2611 if( footprint->ResolveTextVar( &test ) )
2612 token = footprint->m_Uuid.AsString() + wxT( ":" ) + remainder;
2613
2614 break;
2615 }
2616 }
2617 }
2618
2619 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2620 }
2621 else
2622 {
2623 newbuf.append( aSource[i] );
2624 }
2625 }
2626
2627 return newbuf;
2628}
2629
2630
2631wxString BOARD::ConvertKIIDsToCrossReferences( const wxString& aSource ) const
2632{
2633 wxString newbuf;
2634 size_t sourceLen = aSource.length();
2635
2636 for( size_t i = 0; i < sourceLen; ++i )
2637 {
2638 // Check for escaped expressions: \${ or \@{
2639 // These should be copied verbatim without any KIID→ref conversion
2640 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2641 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2642 {
2643 // Copy the escape sequence and the entire escaped expression
2644 newbuf.append( aSource[i] ); // backslash
2645 newbuf.append( aSource[i + 1] ); // $ or @
2646 newbuf.append( aSource[i + 2] ); // {
2647 i += 2;
2648
2649 // Find and copy everything until the matching closing brace
2650 int braceDepth = 1;
2651 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2652 {
2653 if( aSource[i] == '{' )
2654 braceDepth++;
2655 else if( aSource[i] == '}' )
2656 braceDepth--;
2657
2658 newbuf.append( aSource[i] );
2659 }
2660 i--; // Back up one since the for loop will increment
2661 continue;
2662 }
2663
2664 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2665 {
2666 wxString token;
2667 bool isCrossRef = false;
2668
2669 for( i = i + 2; i < sourceLen; ++i )
2670 {
2671 if( aSource[i] == '}' )
2672 break;
2673
2674 if( aSource[i] == ':' )
2675 isCrossRef = true;
2676
2677 token.append( aSource[i] );
2678 }
2679
2680 if( isCrossRef )
2681 {
2682 wxString remainder;
2683 wxString ref = token.BeforeFirst( ':', &remainder );
2684 BOARD_ITEM* refItem = ResolveItem( KIID( ref ), true );
2685
2686 if( refItem && refItem->Type() == PCB_FOOTPRINT_T )
2687 {
2688 token = static_cast<FOOTPRINT*>( refItem )->GetReference() + wxT( ":" ) + remainder;
2689 }
2690 }
2691
2692 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2693 }
2694 else
2695 {
2696 newbuf.append( aSource[i] );
2697 }
2698 }
2699
2700 return newbuf;
2701}
2702
2703
2704unsigned BOARD::GetNodesCount( int aNet ) const
2705{
2706 unsigned retval = 0;
2707
2708 for( FOOTPRINT* footprint : Footprints() )
2709 {
2710 for( PAD* pad : footprint->Pads() )
2711 {
2712 if( ( aNet == -1 && pad->GetNetCode() > 0 ) || aNet == pad->GetNetCode() )
2713 retval++;
2714 }
2715 }
2716
2717 return retval;
2718}
2719
2720
2721BOX2I BOARD::ComputeBoundingBox( bool aBoardEdgesOnly, bool aPhysicalLayersOnly ) const
2722{
2723 BOX2I bbox;
2724 LSET visible = GetVisibleLayers();
2725
2726 if( aPhysicalLayersOnly )
2727 visible &= LSET::PhysicalLayersMask();
2728
2729 // If the board is just showing a footprint, we want all footprint layers included in the
2730 // bounding box
2731 if( IsFootprintHolder() )
2732 visible.set();
2733
2734 if( aBoardEdgesOnly )
2735 visible.set( Edge_Cuts );
2736
2737 // Check shapes, dimensions, texts, and fiducials
2738 for( BOARD_ITEM* item : m_drawings )
2739 {
2740 if( aBoardEdgesOnly && ( item->Type() != PCB_SHAPE_T || item->GetLayer() != Edge_Cuts ) )
2741 continue;
2742
2743 if( ( item->GetLayerSet() & visible ).any() )
2744 bbox.Merge( item->GetBoundingBox() );
2745 }
2746
2747 // Check footprints
2748 for( FOOTPRINT* footprint : m_footprints )
2749 {
2750 if( aBoardEdgesOnly )
2751 {
2752 for( const BOARD_ITEM* edge : footprint->GraphicalItems() )
2753 {
2754 if( edge->GetLayer() == Edge_Cuts && edge->Type() == PCB_SHAPE_T )
2755 bbox.Merge( edge->GetBoundingBox() );
2756 }
2757 }
2758 else if( ( footprint->GetLayerSet() & visible ).any() )
2759 {
2760 bbox.Merge( footprint->GetBoundingBox( true ) );
2761 }
2762 }
2763
2764 if( !aBoardEdgesOnly )
2765 {
2766 // Check tracks
2767 for( PCB_TRACK* track : m_tracks )
2768 {
2769 if( ( track->GetLayerSet() & visible ).any() )
2770 bbox.Merge( track->GetBoundingBox() );
2771 }
2772
2773 // Check zones
2774 for( ZONE* aZone : m_zones )
2775 {
2776 if( ( aZone->GetLayerSet() & visible ).any() )
2777 bbox.Merge( aZone->GetBoundingBox() );
2778 }
2779
2780 for( PCB_POINT* point : m_points )
2781 {
2782 bbox.Merge( point->GetBoundingBox() );
2783 }
2784 }
2785
2786 return bbox;
2787}
2788
2789
2790void BOARD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2791{
2792 int padCount = 0;
2793 int viaCount = 0;
2794 int trackSegmentCount = 0;
2795 std::set<int> netCodes;
2796 int unconnected = GetConnectivity()->GetUnconnectedCount( true );
2797
2798 for( PCB_TRACK* item : m_tracks )
2799 {
2800 if( item->Type() == PCB_VIA_T )
2801 viaCount++;
2802 else
2803 trackSegmentCount++;
2804
2805 if( item->GetNetCode() > 0 )
2806 netCodes.insert( item->GetNetCode() );
2807 }
2808
2809 for( FOOTPRINT* footprint : Footprints() )
2810 {
2811 for( PAD* pad : footprint->Pads() )
2812 {
2813 padCount++;
2814
2815 if( pad->GetNetCode() > 0 )
2816 netCodes.insert( pad->GetNetCode() );
2817 }
2818 }
2819
2820 aList.emplace_back( _( "Pads" ), wxString::Format( wxT( "%d" ), padCount ) );
2821 aList.emplace_back( _( "Vias" ), wxString::Format( wxT( "%d" ), viaCount ) );
2822 aList.emplace_back( _( "Track Segments" ), wxString::Format( wxT( "%d" ), trackSegmentCount ) );
2823 aList.emplace_back( _( "Nets" ), wxString::Format( wxT( "%d" ), (int) netCodes.size() ) );
2824 aList.emplace_back( _( "Unrouted" ), wxString::Format( wxT( "%d" ), unconnected ) );
2825}
2826
2827
2828INSPECT_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const std::vector<KICAD_T>& scanTypes )
2829{
2830#if 0 && defined( DEBUG )
2831 std::cout << GetClass().mb_str() << ' ';
2832#endif
2833
2834 bool footprintsScanned = false;
2835 bool drawingsScanned = false;
2836 bool tracksScanned = false;
2837
2838 for( KICAD_T scanType : scanTypes )
2839 {
2840 switch( scanType )
2841 {
2842 case PCB_T:
2843 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
2844 return INSPECT_RESULT::QUIT;
2845
2846 break;
2847
2848 /*
2849 * Instances of the requested KICAD_T live in a list, either one that I manage, or one
2850 * that my footprints manage. If it's a type managed by class FOOTPRINT, then simply
2851 * pass it on to each footprint's Visit() function via IterateForward( m_footprints, ... ).
2852 */
2853
2854 case PCB_FOOTPRINT_T:
2855 case PCB_PAD_T:
2856 case PCB_SHAPE_T:
2858 case PCB_FIELD_T:
2859 case PCB_TEXT_T:
2860 case PCB_TEXTBOX_T:
2861 case PCB_TABLE_T:
2862 case PCB_DRILL_CHART_T:
2863 case PCB_DRILL_MAP_T:
2864 case PCB_TABLECELL_T:
2865 case PCB_DIM_ALIGNED_T:
2866 case PCB_DIM_CENTER_T:
2867 case PCB_DIM_RADIAL_T:
2869 case PCB_DIM_LEADER_T:
2870 case PCB_TARGET_T:
2871 case PCB_BARCODE_T:
2872 case PCB_GRID_ITEM_T:
2873 if( !footprintsScanned )
2874 {
2875 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2876 return INSPECT_RESULT::QUIT;
2877
2878 footprintsScanned = true;
2879 }
2880
2881 if( !drawingsScanned )
2882 {
2883 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2884 return INSPECT_RESULT::QUIT;
2885
2886 drawingsScanned = true;
2887 }
2888
2889 break;
2890
2891 case PCB_VIA_T:
2892 case PCB_TRACE_T:
2893 case PCB_ARC_T:
2894 if( !tracksScanned )
2895 {
2896 if( IterateForward<PCB_TRACK*>( m_tracks, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2897 return INSPECT_RESULT::QUIT;
2898
2899 tracksScanned = true;
2900 }
2901
2902 break;
2903
2904 case PCB_MARKER_T:
2905 for( PCB_MARKER* marker : m_markers )
2906 {
2907 if( marker->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2908 return INSPECT_RESULT::QUIT;
2909 }
2910
2911 break;
2912
2913 case PCB_POINT_T:
2914 for( PCB_POINT* point : m_points )
2915 {
2916 if( point->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2917 return INSPECT_RESULT::QUIT;
2918 }
2919
2920 break;
2921
2922 case PCB_ZONE_T:
2923 if( !footprintsScanned )
2924 {
2925 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2926 return INSPECT_RESULT::QUIT;
2927
2928 footprintsScanned = true;
2929 }
2930
2931 for( ZONE* zone : m_zones )
2932 {
2933 if( zone->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2934 return INSPECT_RESULT::QUIT;
2935 }
2936
2937 break;
2938
2939 case PCB_GENERATOR_T:
2940 if( !footprintsScanned )
2941 {
2942 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2943 return INSPECT_RESULT::QUIT;
2944
2945 footprintsScanned = true;
2946 }
2947
2948 if( IterateForward<PCB_GENERATOR*>( m_generators, inspector, testData, { scanType } )
2950 {
2951 return INSPECT_RESULT::QUIT;
2952 }
2953
2954 break;
2955
2956 case PCB_GROUP_T:
2957 if( IterateForward<PCB_GROUP*>( m_groups, inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2958 return INSPECT_RESULT::QUIT;
2959
2960 break;
2961
2962 case PCB_CONSTRAINT_T:
2963 if( IterateForward<PCB_CONSTRAINT*>( m_constraints, inspector, testData, { scanType } )
2965 {
2966 return INSPECT_RESULT::QUIT;
2967 }
2968
2969 break;
2970
2971 default:
2972 break;
2973 }
2974 }
2975
2977}
2978
2979
2980NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const
2981{
2982 // the first valid netcode is 1 and the last is m_NetInfo.GetCount()-1.
2983 // zero is reserved for "no connection" and is not actually a net.
2984 // nullptr is returned for non valid netcodes
2985
2986 if( aNetcode == NETINFO_LIST::UNCONNECTED && m_NetInfo.GetNetCount() == 0 )
2988 else
2989 return m_NetInfo.GetNetItem( aNetcode );
2990}
2991
2992
2993NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
2994{
2995 return m_NetInfo.GetNetItem( aNetname );
2996}
2997
2998
2999int BOARD::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet )
3000{
3001 int rv = 0;
3002 int count = 0;
3003
3004 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
3005 {
3006 int ch = *it;
3007
3008 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
3009 {
3010 continue;
3011 }
3012 else if( ch == '+' )
3013 {
3014 aComplementNet = wxT( "-" );
3015 rv = 1;
3016 }
3017 else if( ch == '-' )
3018 {
3019 aComplementNet = wxT( "+" );
3020 rv = -1;
3021 }
3022 else if( ch == 'N' )
3023 {
3024 aComplementNet = wxT( "P" );
3025 rv = -1;
3026 }
3027 else if( ch == 'P' )
3028 {
3029 aComplementNet = wxT( "N" );
3030 rv = 1;
3031 }
3032 else
3033 {
3034 break;
3035 }
3036 }
3037
3038 if( rv != 0 && count >= 1 )
3039 {
3040 aComplementNet = aNetName.Left( aNetName.length() - count ) + aComplementNet + aNetName.Right( count - 1 );
3041 }
3042
3043 return rv;
3044}
3045
3046
3048{
3049 if( aNet )
3050 {
3051 wxString refName = aNet->GetNetname();
3052 wxString coupledNetName;
3053
3054 if( MatchDpSuffix( refName, coupledNetName ) )
3055 return FindNet( coupledNetName );
3056 }
3057
3058 return nullptr;
3059}
3060
3061
3062FOOTPRINT* BOARD::FindFootprintByReference( const wxString& aReference ) const
3063{
3064 for( FOOTPRINT* footprint : m_footprints )
3065 {
3066 if( aReference == footprint->GetReference() )
3067 return footprint;
3068 }
3069
3070 return nullptr;
3071}
3072
3073
3075{
3076 for( FOOTPRINT* footprint : m_footprints )
3077 {
3078 if( footprint->GetPath() == aPath )
3079 return footprint;
3080 }
3081
3082 return nullptr;
3083}
3084
3085
3086PAD* BOARD::FindPadByUuid( const KIID& aUuid ) const
3087{
3088 for( FOOTPRINT* footprint : m_footprints )
3089 {
3090 if( PAD* pad = footprint->FindPadByUuid( aUuid ) )
3091 return pad;
3092 }
3093
3094 return nullptr;
3095}
3096
3097
3098void BOARD::ReplaceNetChainTerminalPad( const wxString& aNetChain, const KIID& aPrev, const KIID& aNew )
3099{
3100 PAD* newPad = FindPadByUuid( aNew );
3101
3102 for( NETINFO_ITEM* net : m_NetInfo )
3103 {
3104 if( net->GetNetChain() == aNetChain )
3105 {
3106 for( int i = 0; i < 2; ++i )
3107 {
3108 PAD* pad = net->GetTerminalPad( i );
3109
3110 if( pad && pad->m_Uuid == aPrev )
3111 net->SetTerminalPad( i, newPad );
3112 }
3113 }
3114 }
3115}
3116
3117
3119{
3120 std::set<wxString> names;
3121
3122 for( const NETINFO_ITEM* net : m_NetInfo )
3123 {
3124 if( !net->GetNetname().IsEmpty() )
3125 names.insert( net->GetNetname() );
3126 }
3127
3128 return names;
3129}
3130
3131
3133{
3134 if( m_project && !m_project->IsNullProject() )
3135 SetProperties( m_project->GetTextVars() );
3136}
3137
3138
3139static wxString FindVariantNameCaseInsensitive( const std::vector<wxString>& aNames,
3140 const wxString& aVariantName )
3141{
3142 for( const wxString& name : aNames )
3143 {
3144 if( name.CmpNoCase( aVariantName ) == 0 )
3145 return name;
3146 }
3147
3148 return wxEmptyString;
3149}
3150
3151
3152void BOARD::SetCurrentVariant( const wxString& aVariant )
3153{
3154 const wxString previous = m_currentVariant;
3155
3156 if( aVariant.IsEmpty() || aVariant.CmpNoCase( GetDefaultVariantName() ) == 0 )
3157 {
3158 m_currentVariant.Clear();
3159 }
3160 else
3161 {
3162 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariant );
3163
3164 if( actualName.IsEmpty() )
3165 m_currentVariant.Clear();
3166 else
3167 m_currentVariant = actualName;
3168 }
3169
3170 // Variant overrides on footprint fields change `${REFDES:FIELD}` resolution,
3171 // so every cross-ref dependent must repaint on switch. Skip the fan-out if
3172 // the active variant did not actually change (e.g. redundant UI callback).
3173 if( previous != m_currentVariant && m_textVarAdapter )
3174 m_textVarAdapter->Tracker().InvalidateVariantScoped();
3175}
3176
3177
3178bool BOARD::HasVariant( const wxString& aVariantName ) const
3179{
3180 return !FindVariantNameCaseInsensitive( m_variantNames, aVariantName ).IsEmpty();
3181}
3182
3183
3184void BOARD::AddVariant( const wxString& aVariantName )
3185{
3186 if( aVariantName.IsEmpty()
3187 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0
3188 || HasVariant( aVariantName ) )
3189 return;
3190
3191 m_variantNames.push_back( aVariantName );
3192}
3193
3194
3195void BOARD::DeleteVariant( const wxString& aVariantName )
3196{
3197 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
3198 return;
3199
3200 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
3201 [&]( const wxString& name )
3202 {
3203 return name.CmpNoCase( aVariantName ) == 0;
3204 } );
3205
3206 if( it != m_variantNames.end() )
3207 {
3208 wxString actualName = *it;
3209 m_variantNames.erase( it );
3210 m_variantDescriptions.erase( actualName );
3211
3212 // Clear current variant if it was the deleted one
3213 if( m_currentVariant.CmpNoCase( aVariantName ) == 0 )
3214 m_currentVariant.Clear();
3215
3216 // Remove variant from all footprints
3217 for( FOOTPRINT* fp : m_footprints )
3218 fp->DeleteVariant( actualName );
3219 }
3220}
3221
3222
3223void BOARD::RenameVariant( const wxString& aOldName, const wxString& aNewName )
3224{
3225 if( aNewName.IsEmpty() || aNewName.CmpNoCase( GetDefaultVariantName() ) == 0 )
3226 return;
3227
3228 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
3229 [&]( const wxString& name )
3230 {
3231 return name.CmpNoCase( aOldName ) == 0;
3232 } );
3233
3234 if( it != m_variantNames.end() )
3235 {
3236 wxString actualOldName = *it;
3237
3238 // Check if new name already exists (case-insensitive) and isn't the same variant
3239 wxString existingName = FindVariantNameCaseInsensitive( m_variantNames, aNewName );
3240
3241 if( !existingName.IsEmpty() && existingName.CmpNoCase( actualOldName ) != 0 )
3242 return;
3243
3244 if( actualOldName == aNewName )
3245 return;
3246
3247 *it = aNewName;
3248
3249 // Transfer description
3250 auto descIt = m_variantDescriptions.find( actualOldName );
3251
3252 if( descIt != m_variantDescriptions.end() )
3253 {
3254 if( !descIt->second.IsEmpty() )
3255 m_variantDescriptions[aNewName] = descIt->second;
3256
3257 m_variantDescriptions.erase( descIt );
3258 }
3259
3260 // Update current variant if it was the renamed one
3261 if( m_currentVariant.CmpNoCase( aOldName ) == 0 )
3262 m_currentVariant = aNewName;
3263
3264 // Rename variant in all footprints
3265 for( FOOTPRINT* fp : m_footprints )
3266 fp->RenameVariant( actualOldName, aNewName );
3267 }
3268}
3269
3270
3271void BOARD::CopyVariant( const wxString& aOldName, const wxString& aNewName, const wxString& aNewDescription )
3272{
3273 if( aOldName.IsEmpty() || aNewName.IsEmpty()
3274 || aNewName.CmpNoCase( GetDefaultVariantName() ) == 0 )
3275 {
3276 return;
3277 }
3278
3279 wxString actualOldName = FindVariantNameCaseInsensitive( m_variantNames, aOldName );
3280
3281 if( actualOldName.IsEmpty() )
3282 return;
3283
3284 if( wxString existingName = FindVariantNameCaseInsensitive( m_variantNames, aNewName ); !existingName.IsEmpty() )
3285 return;
3286
3287 AddVariant( aNewName );
3288
3289 if( !aNewDescription.IsEmpty() )
3290 SetVariantDescription( aNewName, aNewDescription );
3291 else
3292 SetVariantDescription( aNewName, GetVariantDescription( actualOldName ) );
3293
3294 for( FOOTPRINT* fp : m_footprints )
3295 {
3296 if( const FOOTPRINT_VARIANT* variant = fp->GetVariant( actualOldName ) )
3297 {
3298 FOOTPRINT_VARIANT copied = *variant;
3299 copied.SetName( aNewName );
3300 fp->SetVariant( copied );
3301 }
3302 }
3303}
3304
3305
3306wxString BOARD::GetVariantDescription( const wxString& aVariantName ) const
3307{
3308 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
3309 return wxEmptyString;
3310
3311 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
3312
3313 if( actualName.IsEmpty() )
3314 return wxEmptyString;
3315
3316 auto it = m_variantDescriptions.find( actualName );
3317
3318 if( it != m_variantDescriptions.end() )
3319 return it->second;
3320
3321 return wxEmptyString;
3322}
3323
3324
3325void BOARD::SetVariantDescription( const wxString& aVariantName, const wxString& aDescription )
3326{
3327 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
3328 return;
3329
3330 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
3331
3332 if( actualName.IsEmpty() )
3333 return;
3334
3335 if( aDescription.IsEmpty() )
3336 m_variantDescriptions.erase( actualName );
3337 else
3338 m_variantDescriptions[actualName] = aDescription;
3339}
3340
3341
3342wxArrayString BOARD::GetVariantNamesForUI() const
3343{
3344 wxArrayString names;
3345 names.Add( GetDefaultVariantName() );
3346
3347 for( const wxString& name : m_variantNames )
3348 names.Add( name );
3349
3350 names.Sort( SortVariantNames );
3351
3352 return names;
3353}
3354
3355
3357{
3358 m_lengthDelayCalc->SynchronizeTuningProfileProperties();
3359}
3360
3361
3363{
3364 if( !m_project )
3365 return;
3366
3367 const std::shared_ptr<NET_SETTINGS>& netSettings = GetDesignSettings().m_NetSettings;
3368
3369 if( !netSettings )
3370 return;
3371
3372 const std::map<wxString, wxString>& chainNetclasses = netSettings->GetNetChainNetClasses();
3373
3374 // Nothing to derive and nothing left from a prior pass, so skip the cache wipe a rebuild
3375 // would cost on every resync of a board without chain overrides.
3376 if( chainNetclasses.empty()
3377 && !netSettings->HasChainPatternAssignments( NET_CHAIN_SOURCE::BOARD ) )
3378 {
3379 return;
3380 }
3381
3382 netSettings->ClearChainPatternAssignments( NET_CHAIN_SOURCE::BOARD );
3383
3384 for( NETINFO_ITEM* net : m_NetInfo )
3385 {
3386 const wxString& chainName = net->GetNetChain();
3387
3388 if( chainName.IsEmpty() )
3389 continue;
3390
3391 auto it = chainNetclasses.find( chainName );
3392
3393 if( it == chainNetclasses.end() || !netSettings->HasNetclass( it->second ) )
3394 continue;
3395
3396 netSettings->SetChainPatternAssignment( NET_CHAIN_SOURCE::BOARD, net->GetNetname(),
3397 it->second );
3398 }
3399}
3400
3401
3402void BOARD::SynchronizeNetsAndNetClasses( bool aResetTrackAndViaSizes )
3403{
3404 if( !m_project )
3405 return;
3406
3408 const std::shared_ptr<NETCLASS>& defaultNetClass = bds.m_NetSettings->GetDefaultNetclass();
3409
3411
3413
3414 for( NETINFO_ITEM* net : m_NetInfo )
3415 net->SetNetClass( bds.m_NetSettings->GetEffectiveNetClass( net->GetNetname() ) );
3416
3417 if( aResetTrackAndViaSizes )
3418 {
3419 // Set initial values for custom track width & via size to match the default
3420 // netclass settings
3421 bds.UseCustomTrackViaSize( false );
3422 bds.SetCustomTrackWidth( defaultNetClass->GetTrackWidth() );
3423 bds.SetCustomViaSize( defaultNetClass->GetViaDiameter() );
3424 bds.SetCustomViaDrill( defaultNetClass->GetViaDrill() );
3425
3426 if( defaultNetClass->HasDiffPairWidth() )
3427 bds.SetCustomDiffPairWidth( defaultNetClass->GetDiffPairWidth() );
3428 else
3429 bds.SetCustomDiffPairWidth( defaultNetClass->GetTrackWidth() );
3430
3431 if( defaultNetClass->HasDiffPairGap() )
3432 bds.SetCustomDiffPairGap( defaultNetClass->GetDiffPairGap() );
3433 else
3434 bds.SetCustomDiffPairGap( defaultNetClass->GetClearance() );
3435
3436 if( defaultNetClass->HasDiffPairViaGap() )
3437 bds.SetCustomDiffPairViaGap( defaultNetClass->GetDiffPairViaGap() );
3438 else
3440 }
3441
3443}
3444
3445
3446bool BOARD::SynchronizeComponentClasses( const std::unordered_set<wxString>& aNewSheetPaths ) const
3447{
3448 std::shared_ptr<COMPONENT_CLASS_SETTINGS> settings = GetProject()->GetProjectFile().ComponentClassSettings();
3449
3450 return m_componentClassManager->SyncDynamicComponentClassAssignments(
3451 settings->GetComponentClassAssignments(), settings->GetEnableSheetComponentClasses(), aNewSheetPaths );
3452}
3453
3454
3456{
3457 int error_count = 0;
3458
3459 for( ZONE* zone : Zones() )
3460 {
3461 if( !zone->IsOnCopperLayer() )
3462 {
3463 zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3464 continue;
3465 }
3466
3467 if( zone->GetNetCode() != 0 ) // i.e. if this zone is connected to a net
3468 {
3469 const NETINFO_ITEM* net = zone->GetNet();
3470
3471 if( net )
3472 {
3473 zone->SetNetCode( net->GetNetCode() );
3474 }
3475 else
3476 {
3477 error_count++;
3478
3479 // keep Net Name and set m_NetCode to -1 : error flag.
3480 zone->SetNetCode( -1 );
3481 }
3482 }
3483 }
3484
3485 return error_count;
3486}
3487
3488
3489PAD* BOARD::GetPad( const VECTOR2I& aPosition, const LSET& aLayerSet ) const
3490{
3491 for( FOOTPRINT* footprint : m_footprints )
3492 {
3493 PAD* pad = nullptr;
3494
3495 if( footprint->HitTest( aPosition ) )
3496 pad = footprint->GetPad( aPosition, aLayerSet.any() ? aLayerSet : LSET::AllCuMask() );
3497
3498 if( pad )
3499 return pad;
3500 }
3501
3502 return nullptr;
3503}
3504
3505
3506PAD* BOARD::GetPad( const PCB_TRACK* aTrace, ENDPOINT_T aEndPoint ) const
3507{
3508 const VECTOR2I& aPosition = aTrace->GetEndPoint( aEndPoint );
3509
3510 LSET lset( { aTrace->GetLayer() } );
3511
3512 return GetPad( aPosition, lset );
3513}
3514
3515
3516PAD* BOARD::GetPad( std::vector<PAD*>& aPadList, const VECTOR2I& aPosition, const LSET& aLayerSet ) const
3517{
3518 // Search aPadList for aPosition
3519 // aPadList is sorted by X then Y values, and a fast binary search is used
3520 int idxmax = aPadList.size() - 1;
3521
3522 int delta = aPadList.size();
3523
3524 int idx = 0; // Starting index is the beginning of list
3525
3526 while( delta )
3527 {
3528 // Calculate half size of remaining interval to test.
3529 // Ensure the computed value is not truncated (too small)
3530 if( ( delta & 1 ) && ( delta > 1 ) )
3531 delta++;
3532
3533 delta /= 2;
3534
3535 PAD* pad = aPadList[idx];
3536
3537 if( pad->GetPosition() == aPosition ) // candidate found
3538 {
3539 // The pad must match the layer mask:
3540 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3541 return pad;
3542
3543 // More than one pad can be at aPosition
3544 // search for a pad at aPosition that matched this mask
3545
3546 // search next
3547 for( int ii = idx + 1; ii <= idxmax; ii++ )
3548 {
3549 pad = aPadList[ii];
3550
3551 if( pad->GetPosition() != aPosition )
3552 break;
3553
3554 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3555 return pad;
3556 }
3557 // search previous
3558 for( int ii = idx - 1; ii >= 0; ii-- )
3559 {
3560 pad = aPadList[ii];
3561
3562 if( pad->GetPosition() != aPosition )
3563 break;
3564
3565 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3566 return pad;
3567 }
3568
3569 // Not found:
3570 return nullptr;
3571 }
3572
3573 if( pad->GetPosition().x == aPosition.x ) // Must search considering Y coordinate
3574 {
3575 if( pad->GetPosition().y < aPosition.y ) // Must search after this item
3576 {
3577 idx += delta;
3578
3579 if( idx > idxmax )
3580 idx = idxmax;
3581 }
3582 else // Must search before this item
3583 {
3584 idx -= delta;
3585
3586 if( idx < 0 )
3587 idx = 0;
3588 }
3589 }
3590 else if( pad->GetPosition().x < aPosition.x ) // Must search after this item
3591 {
3592 idx += delta;
3593
3594 if( idx > idxmax )
3595 idx = idxmax;
3596 }
3597 else // Must search before this item
3598 {
3599 idx -= delta;
3600
3601 if( idx < 0 )
3602 idx = 0;
3603 }
3604 }
3605
3606 return nullptr;
3607}
3608
3609
3615bool sortPadsByXthenYCoord( PAD* const& aLH, PAD* const& aRH )
3616{
3617 if( aLH->GetPosition().x == aRH->GetPosition().x )
3618 return aLH->GetPosition().y < aRH->GetPosition().y;
3619
3620 return aLH->GetPosition().x < aRH->GetPosition().x;
3621}
3622
3623
3624void BOARD::GetSortedPadListByXthenYCoord( std::vector<PAD*>& aVector, int aNetCode ) const
3625{
3626 for( FOOTPRINT* footprint : Footprints() )
3627 {
3628 for( PAD* pad : footprint->Pads() )
3629 {
3630 if( aNetCode < 0 || pad->GetNetCode() == aNetCode )
3631 aVector.push_back( pad );
3632 }
3633 }
3634
3635 std::sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
3636}
3637
3638
3640{
3641 if( GetDesignSettings().m_HasStackup )
3643
3644 BOARD_STACKUP stackup;
3646 return stackup;
3647}
3648
3649
3650std::tuple<int, double, double, double, double> BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const
3651{
3652 std::shared_ptr<CONNECTIVITY_DATA> connectivity = GetBoard()->GetConnectivity();
3653 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items;
3654
3655 for( BOARD_CONNECTED_ITEM* boardItem : connectivity->GetConnectedItems( &aTrack, EXCLUDE_ZONES ) )
3656 {
3658
3659 if( item.Type() != LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
3660 items.push_back( std::move( item ) );
3661 }
3662
3663 constexpr PATH_OPTIMISATIONS opts = {
3664 .OptimiseVias = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false
3665 };
3667 items, opts, nullptr, nullptr, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL,
3669
3670 return std::make_tuple( items.size(), details.TrackLength + details.ViaLength, details.PadToDieLength,
3671 details.TrackDelay + details.ViaDelay, details.PadToDieDelay );
3672}
3673
3674
3675FOOTPRINT* BOARD::GetFootprint( const VECTOR2I& aPosition, PCB_LAYER_ID aActiveLayer, bool aVisibleOnly,
3676 bool aIgnoreLocked ) const
3677{
3678 FOOTPRINT* footprint = nullptr;
3679 FOOTPRINT* alt_footprint = nullptr;
3680 int min_dim = 0x7FFFFFFF;
3681 int alt_min_dim = 0x7FFFFFFF;
3682 bool current_layer_back = IsBackLayer( aActiveLayer );
3683
3684 for( FOOTPRINT* candidate : m_footprints )
3685 {
3686 // is the ref point within the footprint's bounds?
3687 if( !candidate->HitTest( aPosition ) )
3688 continue;
3689
3690 // if caller wants to ignore locked footprints, and this one is locked, skip it.
3691 if( aIgnoreLocked && candidate->IsLocked() )
3692 continue;
3693
3694 PCB_LAYER_ID layer = candidate->GetLayer();
3695
3696 // Filter non visible footprints if requested
3697 if( !aVisibleOnly || IsFootprintLayerVisible( layer ) )
3698 {
3699 BOX2I bb = candidate->GetBoundingBox( false );
3700
3701 int offx = bb.GetX() + bb.GetWidth() / 2;
3702 int offy = bb.GetY() + bb.GetHeight() / 2;
3703
3704 // off x & offy point to the middle of the box.
3705 int dist =
3706 ( aPosition.x - offx ) * ( aPosition.x - offx ) + ( aPosition.y - offy ) * ( aPosition.y - offy );
3707
3708 if( current_layer_back == IsBackLayer( layer ) )
3709 {
3710 if( dist <= min_dim )
3711 {
3712 // better footprint shown on the active side
3713 footprint = candidate;
3714 min_dim = dist;
3715 }
3716 }
3717 else if( aVisibleOnly && IsFootprintLayerVisible( layer ) )
3718 {
3719 if( dist <= alt_min_dim )
3720 {
3721 // better footprint shown on the other side
3722 alt_footprint = candidate;
3723 alt_min_dim = dist;
3724 }
3725 }
3726 }
3727 }
3728
3729 if( footprint )
3730 return footprint;
3731
3732 if( alt_footprint )
3733 return alt_footprint;
3734
3735 return nullptr;
3736}
3737
3738
3739std::list<ZONE*> BOARD::GetZoneList( bool aIncludeZonesInFootprints ) const
3740{
3741 std::list<ZONE*> zones;
3742
3743 for( ZONE* zone : Zones() )
3744 zones.push_back( zone );
3745
3746 if( aIncludeZonesInFootprints )
3747 {
3748 for( FOOTPRINT* footprint : m_footprints )
3749 {
3750 for( ZONE* zone : footprint->Zones() )
3751 zones.push_back( zone );
3752 }
3753 }
3754
3755 return zones;
3756}
3757
3758
3759ZONE* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, PCB_LAYER_ID aLayer, VECTOR2I aStartPointPosition,
3761{
3762 ZONE* new_area = new ZONE( this );
3763
3764 new_area->SetNetCode( aNetcode );
3765 new_area->SetLayer( aLayer );
3766
3767 m_zones.push_back( new_area );
3768
3769 new_area->SetHatchStyle( (ZONE_BORDER_DISPLAY_STYLE) aHatch );
3770
3771 // Add the first corner to the new zone
3772 new_area->AppendCorner( aStartPointPosition, -1 );
3773
3774 if( aNewZonesList )
3775 {
3776 ITEM_PICKER picker( nullptr, new_area, UNDO_REDO::NEWITEM );
3777 aNewZonesList->PushItem( picker );
3778 }
3779
3780 return new_area;
3781}
3782
3783
3784bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, bool aInferOutlineIfNecessary,
3785 OUTLINE_ERROR_HANDLER* aErrorHandler, bool aAllowUseArcsInPolygons,
3786 bool aIncludeNPTHAsOutlines )
3787{
3788 // max dist from one endPt to next startPt: use the current value
3789 int chainingEpsilon = GetOutlinesChainingEpsilon();
3790
3791 bool success = BuildBoardPolygonOutlines( this, aOutlines, GetDesignSettings().m_MaxError, chainingEpsilon,
3792 aInferOutlineIfNecessary, aErrorHandler, aAllowUseArcsInPolygons );
3793
3794 // Now subtract NPTH oval holes from outlines if required
3795 if( aIncludeNPTHAsOutlines )
3796 {
3797 for( FOOTPRINT* fp : Footprints() )
3798 {
3799 for( PAD* pad : fp->Pads() )
3800 {
3801 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
3802 continue;
3803
3804 SHAPE_POLY_SET hole;
3805 pad->TransformHoleToPolygon( hole, 0, pad->GetMaxError(), ERROR_INSIDE );
3806
3807 if( hole.OutlineCount() > 0 ) // can be not the case for malformed NPTH holes
3808 {
3809 // Issue #20159: BooleanSubtract correctly clips holes extending past board
3810 // edges (common with oval holes near irregular boards). O(n log n) per hole
3811 // vs O(1) for AddHole, but only used for 3D viewer generation, not a hot path.
3812 aOutlines.BooleanSubtract( hole );
3813 }
3814 }
3815 }
3816 }
3817
3818 // Make polygon strictly simple to avoid issues (especially in 3D viewer)
3819 aOutlines.Simplify();
3820
3821 return success;
3822}
3823
3824
3826{
3828 return static_cast<EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3829
3830 return static_cast<EMBEDDED_FILES*>( this );
3831}
3832
3833
3835{
3837 return static_cast<const EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3838
3839 return static_cast<const EMBEDDED_FILES*>( this );
3840}
3841
3842
3843std::set<KIFONT::OUTLINE_FONT*> BOARD::GetFonts() const
3844{
3846
3847 std::set<KIFONT::OUTLINE_FONT*> fonts;
3848
3849 for( BOARD_ITEM* item : Drawings() )
3850 {
3851 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
3852 {
3853 KIFONT::FONT* font = text->GetFont();
3854
3855 if( font && font->IsOutline() )
3856 {
3857 KIFONT::OUTLINE_FONT* outlineFont = static_cast<KIFONT::OUTLINE_FONT*>( font );
3858 PERMISSION permission = outlineFont->GetEmbeddingPermission();
3859
3860 if( permission == PERMISSION::EDITABLE || permission == PERMISSION::INSTALLABLE )
3861 fonts.insert( outlineFont );
3862 }
3863 }
3864 }
3865
3866 return fonts;
3867}
3868
3869
3871{
3872 for( KIFONT::OUTLINE_FONT* font : GetFonts() )
3873 {
3874 EMBEDDED_FILES::EMBEDDED_FILE* file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
3875
3876 if( !file )
3877 {
3878 wxLogTrace( "EMBED", "Failed to add font file: %s", font->GetFileName() );
3879 continue;
3880 }
3881
3883 }
3884}
3885
3886
3887const std::vector<PAD*> BOARD::GetPads() const
3888{
3889 std::vector<PAD*> allPads;
3890
3891 for( FOOTPRINT* footprint : Footprints() )
3892 {
3893 for( PAD* pad : footprint->Pads() )
3894 allPads.push_back( pad );
3895 }
3896
3897 return allPads;
3898}
3899
3900
3901const std::vector<BOARD_CONNECTED_ITEM*> BOARD::AllConnectedItems()
3902{
3903 std::vector<BOARD_CONNECTED_ITEM*> items;
3904
3905 for( PCB_TRACK* track : Tracks() )
3906 items.push_back( track );
3907
3908 for( FOOTPRINT* footprint : Footprints() )
3909 {
3910 for( PAD* pad : footprint->Pads() )
3911 items.push_back( pad );
3912
3913 for( ZONE* zone : footprint->Zones() )
3914 items.push_back( zone );
3915
3916 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
3917 {
3918 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( dwg ) )
3919 items.push_back( bci );
3920 }
3921 }
3922
3923 for( ZONE* zone : Zones() )
3924 items.push_back( zone );
3925
3926 for( BOARD_ITEM* item : Drawings() )
3927 {
3928 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
3929 items.push_back( bci );
3930 }
3931
3932 return items;
3933}
3934
3935
3936void BOARD::MapNets( BOARD* aDestBoard )
3937{
3939 {
3940 NETINFO_ITEM* netInfo = aDestBoard->FindNet( item->GetNetname() );
3941
3942 if( netInfo )
3943 item->SetNet( netInfo );
3944 else
3945 {
3946 NETINFO_ITEM* newNet = new NETINFO_ITEM( aDestBoard, item->GetNetname() );
3947 aDestBoard->Add( newNet );
3948 item->SetNet( newNet );
3949 }
3950 }
3951}
3952
3953
3955{
3957 {
3958 if( FindNet( item->GetNetCode() ) == nullptr )
3959 item->SetNetCode( NETINFO_LIST::ORPHANED );
3960 }
3961}
3962
3963
3964void BOARD::OnZonesFilled( const std::vector<ZONE*>& aZones )
3965{
3966 if( aZones.empty() )
3967 return;
3968
3969 for( PCB_GENERATOR* generator : m_generators )
3970 generator->OnZoneFillChanged( aZones );
3971}
3972
3973
3975{
3976 if( !alg::contains( m_listeners, aListener ) )
3977 m_listeners.push_back( aListener );
3978}
3979
3980
3982{
3983 auto i = std::find( m_listeners.begin(), m_listeners.end(), aListener );
3984
3985 if( i != m_listeners.end() )
3986 {
3987 std::iter_swap( i, m_listeners.end() - 1 );
3988 m_listeners.pop_back();
3989 }
3990}
3991
3992
3994{
3995 m_listeners.clear();
3996}
3997
3998
4000{
4001 if( affectsDrillModel( aItem ) )
4003
4005}
4006
4007
4008void BOARD::OnItemsChanged( std::vector<BOARD_ITEM*>& aItems )
4009{
4010 bumpDrillModelFor( aItems );
4011
4013}
4014
4015
4020
4021
4022void BOARD::OnItemsCompositeUpdate( std::vector<BOARD_ITEM*>& aAddedItems, std::vector<BOARD_ITEM*>& aRemovedItems,
4023 std::vector<BOARD_ITEM*>& aChangedItems )
4024{
4025 bumpDrillModelFor( aAddedItems );
4026 bumpDrillModelFor( aRemovedItems );
4027 bumpDrillModelFor( aChangedItems );
4028
4029 InvokeListeners( &BOARD_LISTENER::OnBoardCompositeUpdate, *this, aAddedItems, aRemovedItems, aChangedItems );
4030}
4031
4032
4037
4038
4045
4046
4054
4055
4056void BOARD::SetHighLightNet( int aNetCode, bool aMulti )
4057{
4058 bool already = m_highLight.m_netCodes.count( aNetCode );
4059
4060 if( !already )
4061 {
4062 if( !aMulti )
4063 m_highLight.m_netCodes.clear();
4064
4065 m_highLight.m_netCodes.insert( aNetCode );
4067 }
4068}
4069
4070
4071void BOARD::HighLightON( bool aValue )
4072{
4073 if( m_highLight.m_highLightOn != aValue )
4074 {
4075 m_highLight.m_highLightOn = aValue;
4077 }
4078}
4079
4080
4081wxString BOARD::GroupsSanityCheck( bool repair )
4082{
4083 if( repair )
4084 {
4085 while( GroupsSanityCheckInternal( repair ) != wxEmptyString )
4086 {
4087 };
4088
4089 return wxEmptyString;
4090 }
4091 return GroupsSanityCheckInternal( repair );
4092}
4093
4094
4096{
4097 // Cycle detection
4098 //
4099 // Each group has at most one parent group.
4100 // So we start at group 0 and traverse the parent chain, marking groups seen along the way.
4101 // If we ever see a group that we've already marked, that's a cycle.
4102 // If we reach the end of the chain, we know all groups in that chain are not part of any cycle.
4103 //
4104 // Algorithm below is linear in the # of groups because each group is visited only once.
4105 // There may be extra time taken due to the container access calls and iterators.
4106 //
4107 // Groups we know are cycle free
4108 std::unordered_set<EDA_GROUP*> knownCycleFreeGroups;
4109 // Groups in the current chain we're exploring.
4110 std::unordered_set<EDA_GROUP*> currentChainGroups;
4111 // Groups we haven't checked yet.
4112 std::unordered_set<EDA_GROUP*> toCheckGroups;
4113
4114 // Initialize set of groups and generators to check that could participate in a cycle.
4115 for( PCB_GROUP* group : Groups() )
4116 toCheckGroups.insert( group );
4117
4118 for( PCB_GENERATOR* gen : Generators() )
4119 toCheckGroups.insert( gen );
4120
4121 while( !toCheckGroups.empty() )
4122 {
4123 currentChainGroups.clear();
4124 EDA_GROUP* group = *toCheckGroups.begin();
4125
4126 while( true )
4127 {
4128 if( currentChainGroups.find( group ) != currentChainGroups.end() )
4129 {
4130 if( repair )
4131 Remove( static_cast<BOARD_ITEM*>( group->AsEdaItem() ) );
4132
4133 return "Cycle detected in group membership";
4134 }
4135 else if( knownCycleFreeGroups.find( group ) != knownCycleFreeGroups.end() )
4136 {
4137 // Parent is a group we know does not lead to a cycle
4138 break;
4139 }
4140
4141 currentChainGroups.insert( group );
4142 // We haven't visited currIdx yet, so it must be in toCheckGroups
4143 toCheckGroups.erase( group );
4144
4145 group = group->AsEdaItem()->GetParentGroup();
4146
4147 if( !group )
4148 {
4149 // end of chain and no cycles found in this chain
4150 break;
4151 }
4152 }
4153
4154 // No cycles found in chain, so add it to set of groups we know don't participate
4155 // in a cycle.
4156 knownCycleFreeGroups.insert( currentChainGroups.begin(), currentChainGroups.end() );
4157 }
4158
4159 // Success
4160 return "";
4161}
4162
4163
4165{
4166 if( a->Type() != b->Type() )
4167 return a->Type() < b->Type();
4168
4169 if( a->GetLayer() != b->GetLayer() )
4170 return a->GetLayer() < b->GetLayer();
4171
4172 if( a->GetPosition().x != b->GetPosition().x )
4173 return a->GetPosition().x < b->GetPosition().x;
4174
4175 if( a->GetPosition().y != b->GetPosition().y )
4176 return a->GetPosition().y < b->GetPosition().y;
4177
4178 if( a->m_Uuid != b->m_Uuid ) // shopuld be always the case foer valid boards
4179 return a->m_Uuid < b->m_Uuid;
4180
4181 return a < b;
4182}
4183
4184
4185bool BOARD::cmp_drawings::operator()( const BOARD_ITEM* aFirst, const BOARD_ITEM* aSecond ) const
4186{
4187 if( aFirst->Type() != aSecond->Type() )
4188 return aFirst->Type() < aSecond->Type();
4189
4190 // Layer-free drawings (grid items) assert in GetLayer(); they sort by uuid below.
4191 if( IsSingleLayerType( aFirst->Type() ) && aFirst->GetLayer() != aSecond->GetLayer() )
4192 return aFirst->GetLayer() < aSecond->GetLayer();
4193
4194 // Callers keep these in a std::set, so any branch reporting equality for two distinct items
4195 // loses one of them. Every branch has to fall through to the uuid
4196 int cmp = 0;
4197
4198 if( aFirst->Type() == PCB_SHAPE_T )
4199 {
4200 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aFirst );
4201 const PCB_SHAPE* other = static_cast<const PCB_SHAPE*>( aSecond );
4202
4203 cmp = shape->Compare( other );
4204 }
4205 else if( aFirst->Type() == PCB_TEXT_T || aFirst->Type() == PCB_FIELD_T )
4206 {
4207 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aFirst );
4208 const PCB_TEXT* other = static_cast<const PCB_TEXT*>( aSecond );
4209
4210 cmp = text->Compare( other );
4211 }
4212 else if( aFirst->Type() == PCB_TEXTBOX_T )
4213 {
4214 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( aFirst );
4215 const PCB_TEXTBOX* other = static_cast<const PCB_TEXTBOX*>( aSecond );
4216
4217 cmp = textbox->PCB_SHAPE::Compare( other );
4218
4219 if( cmp == 0 )
4220 cmp = textbox->EDA_TEXT::Compare( other );
4221 }
4222 else if( BaseType( aFirst->Type() ) == PCB_TABLE_T )
4223 {
4224 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( aFirst );
4225 const PCB_TABLE* other = static_cast<const PCB_TABLE*>( aSecond );
4226
4227 cmp = PCB_TABLE::Compare( table, other );
4228 }
4229 else if( aFirst->Type() == PCB_BARCODE_T )
4230 {
4231 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( aFirst );
4232 const PCB_BARCODE* other = static_cast<const PCB_BARCODE*>( aSecond );
4233
4234 cmp = PCB_BARCODE::Compare( barcode, other );
4235 }
4236
4237 if( cmp != 0 )
4238 return cmp < 0;
4239
4240 if( aFirst->m_Uuid != aSecond->m_Uuid )
4241 return aFirst->m_Uuid < aSecond->m_Uuid;
4242
4243 return aFirst < aSecond;
4244}
4245
4246
4248 KIGFX::RENDER_SETTINGS* aRenderSettings ) const
4249{
4250 int maxError = GetDesignSettings().m_MaxError;
4251
4252 // convert tracks and vias:
4253 for( const PCB_TRACK* track : m_tracks )
4254 {
4255 if( !track->IsOnLayer( aLayer ) )
4256 continue;
4257
4258 track->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
4259 }
4260
4261 // convert pads and other copper items in footprints
4262 for( const FOOTPRINT* footprint : m_footprints )
4263 {
4264 footprint->TransformPadsToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
4265
4266 footprint->TransformFPShapesToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE, true, /* include text */
4267 true, /* include shapes */
4268 false /* include private items */ );
4269
4270 for( const ZONE* zone : footprint->Zones() )
4271 {
4272 if( zone->GetLayerSet().test( aLayer ) )
4273 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
4274 }
4275 }
4276
4277 // convert copper zones
4278 for( const ZONE* zone : Zones() )
4279 {
4280 if( zone->GetLayerSet().test( aLayer ) )
4281 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
4282 }
4283
4284 // convert graphic items on copper layers (texts)
4285 for( const BOARD_ITEM* item : m_drawings )
4286 {
4287 if( !item->IsOnLayer( aLayer ) )
4288 continue;
4289
4290 switch( item->Type() )
4291 {
4292 case PCB_SHAPE_T:
4293 {
4294 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( item );
4295 shape->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
4296 break;
4297 }
4298
4299 case PCB_BARCODE_T:
4300 {
4301 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( item );
4302 barcode->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
4303 break;
4304 }
4305
4306 case PCB_FIELD_T:
4307 case PCB_TEXT_T:
4308 {
4309 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
4310 text->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
4311 break;
4312 }
4313
4314 case PCB_TEXTBOX_T:
4315 {
4316 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
4317 // border
4318 textbox->PCB_SHAPE::TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
4319 // text
4320 textbox->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
4321 break;
4322 }
4323
4324 case PCB_TABLE_T:
4325 case PCB_DRILL_CHART_T:
4326 {
4327 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
4328 table->TransformGraphicItemsToPolySet( aOutlines, maxError, ERROR_INSIDE, aRenderSettings );
4329 break;
4330 }
4331
4332 // Configuration only. The symbols it asks for are drawn by the holes themselves
4333 case PCB_DRILL_MAP_T:
4334 break;
4335
4336 case PCB_DIM_ALIGNED_T:
4337 case PCB_DIM_CENTER_T:
4338 case PCB_DIM_RADIAL_T:
4340 case PCB_DIM_LEADER_T:
4341 {
4342 const PCB_DIMENSION_BASE* dim = static_cast<const PCB_DIMENSION_BASE*>( item );
4343 dim->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
4344 dim->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
4345 break;
4346 }
4347
4348 default:
4349 break;
4350 }
4351 }
4352}
4353
4354
4355std::vector<BOARD_ITEM*> BOARD::collectOwnedItems() const
4356{
4357 std::vector<BOARD_ITEM*> items;
4358
4359 items.reserve( m_tracks.size() + m_zones.size() + m_generators.size() + m_footprints.size()
4360 + m_drawings.size() + m_markers.size() + m_groups.size() + m_constraints.size()
4361 + m_points.size() );
4362
4363 items.insert( items.end(), m_tracks.begin(), m_tracks.end() );
4364 items.insert( items.end(), m_zones.begin(), m_zones.end() );
4365 items.insert( items.end(), m_generators.begin(), m_generators.end() );
4366 items.insert( items.end(), m_footprints.begin(), m_footprints.end() );
4367 items.insert( items.end(), m_drawings.begin(), m_drawings.end() );
4368 items.insert( items.end(), m_markers.begin(), m_markers.end() );
4369 items.insert( items.end(), m_groups.begin(), m_groups.end() );
4370 items.insert( items.end(), m_constraints.begin(), m_constraints.end() );
4371 items.insert( items.end(), m_points.begin(), m_points.end() );
4372
4373 return items;
4374}
4375
4376
4378{
4379 std::vector<BOARD_ITEM*> items = collectOwnedItems();
4380
4381 return BOARD_ITEM_SET( items.begin(), items.end() );
4382}
4383
4384
4386{
4387 // Delegate to the non-const overload via a single safe const_cast on the
4388 // *this pointer. GetItemSet doesn't mutate the BOARD; the non-const
4389 // signature is historical.
4390 return const_cast<BOARD*>( this )->GetItemSet();
4391}
4392
4393
4394bool BOARD::operator==( const BOARD_ITEM& aItem ) const
4395{
4396 if( aItem.Type() != Type() )
4397 return false;
4398
4399 const BOARD& other = static_cast<const BOARD&>( aItem );
4400
4401 if( *m_designSettings != *other.m_designSettings )
4402 return false;
4403
4404 if( m_NetInfo.GetNetCount() != other.m_NetInfo.GetNetCount() )
4405 return false;
4406
4407 const NETNAMES_MAP& thisNetNames = m_NetInfo.NetsByName();
4408 const NETNAMES_MAP& otherNetNames = other.m_NetInfo.NetsByName();
4409
4410 for( auto it1 = thisNetNames.begin(), it2 = otherNetNames.begin();
4411 it1 != thisNetNames.end() && it2 != otherNetNames.end(); ++it1, ++it2 )
4412 {
4413 // We only compare the names in order here, not the index values
4414 // as the index values are auto-generated and the names are not.
4415 if( it1->first != it2->first )
4416 return false;
4417 }
4418
4419 if( m_properties.size() != other.m_properties.size() )
4420 return false;
4421
4422 for( auto it1 = m_properties.begin(), it2 = other.m_properties.begin();
4423 it1 != m_properties.end() && it2 != other.m_properties.end(); ++it1, ++it2 )
4424 {
4425 if( *it1 != *it2 )
4426 return false;
4427 }
4428
4429 if( m_paper.GetCustomHeightMils() != other.m_paper.GetCustomHeightMils() )
4430 return false;
4431
4432 if( m_paper.GetCustomWidthMils() != other.m_paper.GetCustomWidthMils() )
4433 return false;
4434
4435 if( m_paper.GetSizeMils() != other.m_paper.GetSizeMils() )
4436 return false;
4437
4438 if( m_paper.GetPaperId() != other.m_paper.GetPaperId() )
4439 return false;
4440
4441 if( m_paper.GetWxOrientation() != other.m_paper.GetWxOrientation() )
4442 return false;
4443
4444 for( int ii = 0; !m_titles.GetComment( ii ).empty(); ++ii )
4445 {
4446 if( m_titles.GetComment( ii ) != other.m_titles.GetComment( ii ) )
4447 return false;
4448 }
4449
4450 wxArrayString ourVars;
4451 m_titles.GetContextualTextVars( &ourVars );
4452
4453 wxArrayString otherVars;
4454 other.m_titles.GetContextualTextVars( &otherVars );
4455
4456 if( ourVars != otherVars )
4457 return false;
4458
4459 return true;
4460}
4461
4463{
4465 m_boardOutline->GetOutline().RemoveAllContours();
4466
4467 bool has_outline = GetBoardPolygonOutlines( m_boardOutline->GetOutline(), false );
4468
4469 if( has_outline )
4470 m_boardOutline->GetOutline().Fracture();
4471}
4472
4473
4475{
4476 // return the number of PTH with Press-Fit fabr attribute
4477 int count = 0;
4478
4479 for( FOOTPRINT* footprint : Footprints() )
4480 {
4481 for( PAD* pad : footprint->Pads() )
4482 {
4483 if( pad->GetProperty() == PAD_PROP::PRESSFIT )
4484 count++;
4485 }
4486 }
4487
4488 return count;
4489}
4490
4491
4493{
4494 // @return the number of PTH with Castellated fabr attribute
4495 int count = 0;
4496
4497 for( FOOTPRINT* footprint : Footprints() )
4498 {
4499 for( PAD* pad : footprint->Pads() )
4500 {
4501 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
4502 count++;
4503 }
4504 }
4505
4506 return count;
4507}
4508
4509
4510void BOARD::SaveToHistory( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
4511{
4512 // The board can transiently have no project (e.g. during a non-KiCad import while the old
4513 // project is being unloaded and the new one has not yet been linked). The autosave timer can
4514 // fire in that window, so guard against a null project here rather than dereferencing it.
4516
4517 if( !project )
4518 return;
4519
4520 wxString projPath = project->GetProjectPath();
4521
4522 if( projPath.IsEmpty() )
4523 return;
4524
4525 // Verify we're saving for the correct project
4526 if( !projPath.IsSameAs( aProjectPath ) )
4527 {
4528 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - project path mismatch: %s vs %s" ), projPath,
4529 aProjectPath );
4530 return;
4531 }
4532
4533 wxString boardPath = GetFileName();
4534
4535 if( boardPath.IsEmpty() )
4536 return; // unsaved board
4537
4538 // Derive relative path from project root.
4539 if( !boardPath.StartsWith( projPath ) )
4540 {
4541 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - board not under project: %s" ), boardPath );
4542 return; // not under project
4543 }
4544
4545 wxString rel = boardPath.Mid( projPath.length() );
4546
4547 try
4548 {
4550 STRING_FORMATTER formatter;
4551
4552 pi.FormatBoardToFormatter( &formatter, this, nullptr );
4553
4554 HISTORY_FILE_DATA entry;
4555 entry.relativePath = rel;
4556 entry.content = std::move( formatter.MutableString() );
4557 entry.prettify = true;
4558
4559 if( ADVANCED_CFG::GetCfg().m_CompactSave )
4560 entry.formatMode = KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
4561
4562 aFileData.push_back( std::move( entry ) );
4563
4564 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialized %zu bytes for '%s'" ),
4565 aFileData.back().content.size(), rel );
4566 }
4567 catch( const IO_ERROR& ioe )
4568 {
4569 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialize failed: %s" ), wxString::FromUTF8( ioe.What() ) );
4570 }
4571}
int index
const char * name
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
static PCB_TABLECELL * findTableCell(const BOARD_ITEM *aDrawing, const KIID &aID)
Definition board.cpp:2101
static bool affectsDrillModel(const BOARD_ITEM *aItem)
Definition board.cpp:184
bool sortPadsByXthenYCoord(PAD *const &aLH, PAD *const &aRH)
Used by #GetSortedPadListByXCoord to sort a pad list by X coordinate value.
Definition board.cpp:3615
static wxString FindVariantNameCaseInsensitive(const std::vector< wxString > &aNames, const wxString &aVariantName)
Definition board.cpp:3139
#define DEFAULT_CHAINING_EPSILON_MM
Definition board.h:93
BOARD_USE
Flags to specify how the board is being used.
Definition board.h:399
@ NORMAL
Definition board.h:400
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition board.h:241
@ LT_POWER
Definition board.h:244
@ LT_FRONT
Definition board.h:248
@ LT_MIXED
Definition board.h:245
@ LT_BACK
Definition board.h:249
@ LT_UNDEFINED
Definition board.h:242
@ LT_JUMPER
Definition board.h:246
@ LT_AUX
Definition board.h:247
@ LT_SIGNAL
Definition board.h:243
std::set< BOARD_ITEM *, CompareByUuid > BOARD_ITEM_SET
Set of BOARD_ITEMs ordered by UUID.
Definition board.h:393
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
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:153
BASE_SET & set(size_t pos)
Definition base_set.h:126
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
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.
DRILL_SYMBOL_PROFILE & GetDrillSymbolProfile()
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)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
BOARD * m_boardCacheOwner
Definition board_item.h:576
virtual void SetLayerSet(const LSET &aLayers)
Definition board_item.h:354
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition board_item.h:435
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:408
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:346
static VECTOR2I ZeroOffset
A value of wxPoint(0,0) which can be passed to the Draw() functions.
Definition board_item.h:232
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
virtual void OnBoardNetSettingsChanged(BOARD &aBoard)
Definition board.h:377
virtual void OnBoardRatsnestChanged(BOARD &aBoard)
Definition board.h:382
virtual void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:374
virtual void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:378
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:375
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:373
virtual void OnBoardHighlightNetChanged(BOARD &aBoard)
Definition board.h:381
virtual void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:376
virtual void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems)
Definition board.h:383
virtual void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:379
virtual void OnBoardSelectionChanged(BOARD &aBoard)
Definition board.h:380
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:2828
ZONE * m_SolderMaskBridges
Definition board.h:1860
void ApplyNetChainNetclasses()
Expand the project's chain-to-netclass assignments into per-net pattern assignments,...
Definition board.cpp:3362
void GetContextualTextVars(wxArrayString *aVars) const
Definition board.cpp:656
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:1288
BOARD_STACKUP GetStackupOrDefault() const
Definition board.cpp:3639
std::map< ZONE *, std::map< PCB_LAYER_ID, ISOLATED_ISLANDS > > m_ZoneIsolatedIslandsMap
Definition board.h:1861
PCB_LAYER_ID GetCopperLayerStackMaxId() const
Definition board.cpp:1158
std::vector< const PCB_DRILL_MAP * > DrillMapsOnLayer(PCB_LAYER_ID aLayer) const
Every map on this layer.
Definition board.cpp:202
GENERATORS m_generators
Definition board.h:1905
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:3999
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition board.h:555
bool IsFootprintHolder() const
Find out if the board is being used to hold a single footprint for editing/viewing.
Definition board.h:439
PAD * GetPad(const VECTOR2I &aPosition, const LSET &aLayerMask) const
Find a pad aPosition on aLayer.
Definition board.cpp:3489
SHARDED_CACHE< PTR_PTR_LAYER_CACHE_KEY, bool > m_IntersectsAreaCache
Definition board.h:1821
int GetUserDefinedLayerCount() const
Definition board.cpp:1147
void recalcOpposites()
Definition board.cpp:1064
void SetPosition(const VECTOR2I &aPos) override
Definition board.cpp:814
std::map< wxString, wxString > m_properties
Definition board.h:1935
void CacheItemById(BOARD_ITEM *aItem) const
Add an item to the item-by-id cache.
Definition board.cpp:2265
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsCourtyardResultCache
Definition board.h:1824
std::unordered_map< const BOARD_ITEM *, wxString > m_ItemNetclassCache
Definition board.h:1837
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3825
SHARDED_CACHE< PTR_PTR_LAYER_CACHE_KEY, bool > m_EnclosedByAreaCache
Definition board.h:1823
int m_fileFormatVersionAtLoad
Definition board.h:1920
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition board.cpp:3047
void UncacheItemById(const KIID &aId) const
Remove an item from the item-by-id cache.
Definition board.cpp:2308
void SetCurrentVariant(const wxString &aVariant)
Definition board.cpp:3152
std::vector< ZONE * > m_DRCCopperZones
Definition board.h:1856
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:1216
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1497
std::shared_ptr< const DRILL_SYMBOL_CACHE > m_drillSymbolCache
Definition board.h:1931
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_EnclosedByAreaResultCache
Definition board.h:1829
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:3936
TITLE_BLOCK m_titles
Definition board.h:1942
GAL_SET m_LegacyVisibleItems
Definition board.h:552
std::vector< wxString > m_variantNames
Definition board.h:1949
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1663
wxArrayString GetVariantNamesForUI() const
Return the variant names for UI display.
Definition board.cpp:3342
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:1418
const GENERATORS & Generators() const
Definition board.h:476
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition board.h:1112
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:3901
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition board.cpp:1250
int m_outlinesChainingEpsilon
the max distance between 2 end point to see them connected when building the board outlines
Definition board.h:1887
uint64_t m_drillModelGeneration
Definition board.h:1921
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:3650
std::set< wxString > GetNetClassAssignmentCandidates() const
Return the set of netname candidates for netclass assignment.
Definition board.cpp:3118
BOARD_USE m_boardUse
What is this board being used for.
Definition board.h:1890
void RefreshDrillSymbolLayers()
Definition board.cpp:234
void CopyVariant(const wxString &aOldName, const wxString &aNewName, const wxString &aNewDescription=wxEmptyString)
Definition board.cpp:3271
PAGE_INFO m_paper
Definition board.h:1941
void RemoveAllListeners()
Remove all listeners.
Definition board.cpp:3993
SHARDED_CACHE< PTR_PTR_CACHE_KEY, bool > m_IntersectsBCourtyardCache
Definition board.h:1820
FOOTPRINTS m_footprints
Definition board.h:1900
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:1962
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:4247
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:3974
void UpdateUserUnits(BOARD_ITEM *aItem, KIGFX::VIEW *aView)
Update any references within aItem (or its descendants) to the user units.
Definition board.cpp:2018
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:518
bool IsBackLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:989
GAL_SET GetVisibleElements() const
Return a set of all the element categories that are visible.
Definition board.cpp:1244
void SetHighLightNet(int aNetCode, bool aMulti=false)
Select the netcode to be highlighted.
Definition board.cpp:4056
void CompileRatsnest()
Rebuild the entire board ratsnest.
Definition board.cpp:4039
HIGH_LIGHT_INFO m_highLight
Definition board.h:1917
std::map< wxString, wxString > m_variantDescriptions
Definition board.h:1950
bool SetLayerDescr(PCB_LAYER_ID aIndex, const LAYER &aLayer)
Return the type of the copper layer given by aLayer.
Definition board.cpp:908
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2980
EDA_UNITS m_userUnits
Definition board.h:1945
CONSTRAINTS m_constraints
Definition board.h:1903
void UpdateBoardOutline()
Definition board.cpp:4462
const ZONES & Zones() const
Definition board.h:467
void BulkRemoveStaleTeardrops(BOARD_COMMIT &aCommit)
Remove all teardrop zones with the STRUCT_DELETED flag set.
Definition board.cpp:1649
void ClearItemByIdCache()
Definition board.cpp:2397
void DeleteVariant(const wxString &aVariantName)
Definition board.cpp:3195
void InvokeListeners(Func &&aFunc, Args &&... args)
Definition board.h:1871
void SetDesignSettings(const BOARD_DESIGN_SETTINGS &aSettings)
Definition board.cpp:1305
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1197
void SanitizeNetcodes()
Definition board.cpp:3954
void InitializeClearanceCache()
Initialize the clearance cache for all board items.
Definition board.cpp:1318
EMBEDDED_FILES * m_embeddedFilesDelegate
Definition board.h:1978
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:3759
bool IsFrontLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:983
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:509
~BOARD()
Definition board.cpp:327
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:4510
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:364
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:1210
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition board.cpp:995
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition board.cpp:569
DRAWINGS m_drawings
Definition board.h:1899
uint64_t m_boardOutlineGeneration
Definition board.h:1922
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:4022
int SetAreasNetCodesFromNetNames()
Set the .m_NetCode member of all copper areas, according to the area Net Name The SetNetCodesFromNetN...
Definition board.cpp:3455
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:3402
void ResetNetHighLight()
Reset all high light data to the init state.
Definition board.cpp:4047
SHARDED_CACHE< PTR_PTR_CACHE_KEY, bool > m_IntersectsCourtyardCache
Definition board.h:1818
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition board.cpp:954
std::list< ZONE * > GetZoneList(bool aIncludeZonesInFootprints=false) const
Definition board.cpp:3739
bool ResolveTextVar(wxString *token, int aDepth) const
Definition board.cpp:686
const MARKERS & Markers() const
Definition board.h:488
void UncacheChildrenById(const BOARD_ITEM *aParent)
Definition board.h:1766
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:1124
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
Definition board.cpp:3887
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition board.cpp:820
std::unique_ptr< class BOARD_TEXT_VAR_ADAPTER > m_textVarAdapter
Definition board.h:1986
TITLE_BLOCK & GetTitleBlock()
Definition board.h:1016
void FixupEmbeddedData()
After loading a file from disk, the footprints do not yet contain the full data for their embedded fi...
Definition board.cpp:1425
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition board.cpp:1325
ZONES m_zones
Definition board.h:1904
void InvalidateClearanceCache(const KIID &aUuid)
Invalidate the clearance cache for a specific item.
Definition board.cpp:1311
PAD * FindPadByUuid(const KIID &aUuid) const
Definition board.cpp:3086
void OnBoardSelectionChanged()
Notify the board and its listeners that the editor selection has changed.
Definition board.cpp:4016
std::unordered_map< const BOARD_ITEM *, KIID > m_cachedIdByItem
Definition board.h:1913
PCB_LAYER_ID GetLayerID(const wxString &aLayerName) const
Return the ID of a layer.
Definition board.cpp:916
HIGH_LIGHT_INFO m_highLightPrevious
Definition board.h:1918
NETINFO_LIST m_NetInfo
Definition board.h:1970
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition board.h:551
void SetVisibleAlls()
Change the bit-mask of visible element categories and layers.
Definition board.cpp:1233
std::shared_ptr< const DRILL_SYMBOL_CACHE > DrillSymbolCache() const
Resolved drill symbols, by group and by owning item.
Definition board.cpp:260
bool HasVariant(const wxString &aVariantName) const
Definition board.cpp:3178
void AddVariant(const wxString &aVariantName)
Definition board.cpp:3184
int GetCopperLayerCount() const
Definition board.cpp:1131
std::vector< BOARD_LISTENER * > m_listeners
Definition board.h:1972
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:1932
SHARDED_CACHE< PTR_PTR_LAYER_CACHE_KEY, bool > m_IntersectsKeepoutCache
Definition board.h:1822
void IncrementTimeStamp()
Definition board.cpp:446
int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet)
Fetch the coupled netname for a given net.
Definition board.cpp:2999
wxString GetUniqueZoneName(const wxString &aBaseName, const ZONE *aExclude=nullptr) const
Return a name based on aBaseName that is not used by any other zone or rule area on the board.
Definition board.cpp:1446
PCB_POINTS m_points
Definition board.h:1907
std::unique_ptr< LENGTH_DELAY_CALCULATION > m_lengthDelayCalc
Definition board.h:1981
const FOOTPRINTS & Footprints() const
Definition board.h:463
std::shared_ptr< CONNECTIVITY_DATA > m_connectivity
Definition board.h:1936
std::set< KIFONT::OUTLINE_FONT * > GetFonts() const override
Get the list of all outline fonts used in the board.
Definition board.cpp:3843
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:1782
const BOARD_ITEM_SET GetItemSet()
Collect every owned item (tracks, zones, generators, footprints, drawings, markers,...
Definition board.cpp:4377
const TRACKS & Tracks() const
Definition board.h:461
int m_DRCMaxPhysicalClearance
Definition board.h:1859
FOOTPRINT * FindFootprintByPath(const KIID_PATH &aPath) const
Search for a FOOTPRINT within this board with the given path.
Definition board.cpp:3074
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:1640
std::unordered_map< wxString, LSET > m_LayerExpressionCache
Definition board.h:1831
BOARD_ITEM * GetCachedItemById(const KIID &aId) const
Return a cached item for aId if the entry is still self-consistent.
Definition board.cpp:2248
bool m_embedFonts
Definition board.h:1974
wxString GroupsSanityCheckInternal(bool repair)
Definition board.cpp:4095
std::shared_ptr< const FOOTPRINT_COURTYARD_INDEX > m_footprintCourtyardIndex
Definition board.h:1852
void OnRatsnestChanged()
Notify the board and its listeners that the ratsnest has been recomputed.
Definition board.cpp:4033
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource) const
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition board.cpp:2551
wxString GetClass() const override
Return the class name.
Definition board.h:1393
std::unique_ptr< COMPONENT_CLASS_MANAGER > m_componentClassManager
Definition board.h:1980
SHARDED_CACHE< PTR_PTR_CACHE_KEY, bool > m_IntersectsFCourtyardCache
Definition board.h:1819
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:3784
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition board.h:559
void SetCopperLayerCount(int aCount)
Definition board.cpp:1137
std::unordered_map< const ZONE *, BOX2I > m_ZoneBBoxCache
Definition board.h:1834
std::unordered_map< const ZONE *, SHAPE_POLY_SET > m_DeflatedZoneOutlineCache
Definition board.h:1849
std::vector< BOARD_ITEM * > collectOwnedItems() const
Get a simple vector of the board's pointers.
Definition board.cpp:4355
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsFCourtyardResultCache
Definition board.h:1825
TRACKS TracksInNet(int aNetCode)
Collect all the TRACKs and VIAs that are members of a net given by aNetCode.
Definition board.cpp:886
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
Definition board.cpp:374
PROJECT * m_project
Definition board.h:1944
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:3675
bool HasItemsOnLayer(PCB_LAYER_ID aLayer)
Definition board.cpp:1886
const wxString & GetFileName() const
Definition board.h:452
bool operator==(const BOARD_ITEM &aOther) const override
Definition board.cpp:4394
std::vector< PCB_MARKER * > ResolveDRCExclusions(bool aCreateMarkers)
Rebuild DRC markers from the serialized data in BOARD_DESIGN_SETTINGS.
Definition board.cpp:595
int GetPadWithCastellatedAttrCount()
Definition board.cpp:4492
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsKeepoutResultCache
Definition board.h:1828
wxString GetVariantDescription(const wxString &aVariantName) const
Definition board.cpp:3306
FOOTPRINT * FindFootprintByReference(const wxString &aReference) const
Search for a FOOTPRINT within this board with the given reference designator.
Definition board.cpp:3062
unsigned GetNodesCount(int aNet=-1) const
Definition board.cpp:2704
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Definition board.cpp:2506
SHARDED_CACHE< ITEM_FIELD_CACHE_KEY, wxString > m_ItemFieldCache
Definition board.h:1830
std::map< PCB_LAYER_ID, std::vector< ZONE * > > m_DRCCopperZonesByLayer
Definition board.h:1857
void SetElementVisibility(GAL_LAYER_ID aLayer, bool aNewState)
Change the visibility of an element category.
Definition board.cpp:1256
std::shared_ptr< DRC_RTREE > m_CopperItemRTreeCache
Definition board.h:1833
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition board.cpp:1014
std::optional< std::set< const PCB_VIA * > > m_StackedMicroviaCache
Definition board.h:1841
wxString m_fileName
Definition board.h:1893
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:936
BOX2I ExpandBoundingBoxForDrillSymbols(const BOX2I &aBoundingBox) const
Include every displaced copy of a hole-owned drill symbol in its view bounds.
Definition board.cpp:295
void DetachAllFootprints()
Remove all footprints without deleting.
Definition board.cpp:2089
std::map< int, LAYER > m_layers
Definition board.h:1915
void noteDrillModelChange(BOARD_ITEM *aItem)
Container-boundary notification, so an item that arrives or leaves without going through a commit sti...
Definition board.cpp:216
wxString GetCurrentVariant() const
Definition board.h:521
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const override
Invoke a function on all children.
Definition board.cpp:841
int GetOutlinesChainingEpsilon()
Definition board.h:1062
void BumpDrillModelGeneration()
Bumped whenever anything a drill chart or map reports on has moved.
Definition board.cpp:176
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:3624
void OnZonesFilled(const std::vector< ZONE * > &aZones)
Notify the board that the listed zones were just refilled.
Definition board.cpp:3964
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:1189
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsAreaResultCache
Definition board.h:1827
int m_DRCMaxClearance
Definition board.h:1858
void ClearProject()
Definition board.cpp:415
void ReplaceNetChainTerminalPad(const wxString &aNetChain, const KIID &aPrev, const KIID &aNew)
Definition board.cpp:3098
void UncacheItemByPtr(const BOARD_ITEM *aItem)
Remove every cache entry that still points to aItem.
Definition board.cpp:2371
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition board.h:1832
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:1631
wxString m_currentVariant
Definition board.h:1948
int LayerDepth(PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer) const
Definition board.cpp:1171
void DeleteAllFootprints()
Remove all footprints from the deque and free the memory associated with them.
Definition board.cpp:2077
PROJECT * GetProject() const
Definition board.h:767
bool IsEmpty() const
Definition board.cpp:802
int GetPadWithPressFitAttrCount()
Definition board.cpp:4474
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:2790
wxString GetDesignRulesPath() const
Return the absolute path to the design rules file for this board.
Definition board.cpp:435
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
Definition board.cpp:4081
void RenameVariant(const wxString &aOldName, const wxString &aNewName)
Definition board.cpp:3223
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
std::vector< ZONE * > m_DRCZones
Definition board.h:1855
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1183
BOARD()
Definition board.cpp:95
void bumpDrillModelFor(const std::vector< BOARD_ITEM * > &aItems)
Definition board.cpp:314
std::vector< std::pair< VECTOR2I, int > > m_drillSymbolPlacements
Offset and symbol reach of every drill map, so a pad or track ViewBBox() does not walk the drawings l...
Definition board.h:1929
void UpdateRatsnestExclusions()
Update the visibility flags on the current unconnected ratsnest lines.
Definition board.cpp:538
wxString ConvertKIIDsToCrossReferences(const wxString &aSource) const
Definition board.cpp:2631
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:2407
int RepairDuplicateItemUuids()
Rebind duplicate attached-item UUIDs so each live board item has a unique ID.
Definition board.cpp:2433
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition board.cpp:3132
std::unordered_map< KIID, BOARD_ITEM * > m_itemByIdCache
Definition board.h:1912
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
Definition board.cpp:3981
std::shared_mutex m_CachesMutex
Definition board.h:1815
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aPhysicalLayersOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition board.cpp:2721
std::shared_ptr< const FOOTPRINT_COURTYARD_INDEX > GetFootprintCourtyardIndex()
Return a spatial index of footprint courtyards, building it on first use.
Definition board.cpp:514
std::atomic< int > m_timeStamp
Definition board.h:1891
std::mutex m_drillSymbolCacheMutex
Definition board.h:1932
bool SynchronizeComponentClasses(const std::unordered_set< wxString > &aNewSheetPaths) const
Copy component class / component class generator information from the project settings.
Definition board.cpp:3446
BOARD_ITEM * CacheAndReturnItemById(const KIID &aId, BOARD_ITEM *aItem) const
Definition board.cpp:2328
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition board.cpp:2040
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition board.cpp:1668
std::unordered_map< wxString, std::vector< ZONE * > > m_ZonesByNameCache
Definition board.h:1845
GROUPS m_groups
Definition board.h:1902
MARKERS m_markers
Definition board.h:1898
LSET m_drillSymbolLayers
Definition board.h:1923
std::optional< int > m_maxClearanceValue
Definition board.h:1835
void HighLightON(bool aValue=true)
Enable or disable net highlighting.
Definition board.cpp:4071
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1203
void CacheChildrenById(const BOARD_ITEM *aParent)
Definition board.h:1738
void SynchronizeTuningProfileProperties()
Ensure that all time domain properties providers are in sync with current settings.
Definition board.cpp:3356
TRACKS m_tracks
Definition board.h:1901
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:2116
bool m_LegacyCopperEdgeClearanceLoaded
Definition board.h:556
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:4008
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsBCourtyardResultCache
Definition board.h:1826
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:751
VECTOR2I GetPosition() const override
Definition board.cpp:808
void SetVariantDescription(const wxString &aVariantName, const wxString &aDescription)
Definition board.cpp:3325
void CacheTriangulation(PROGRESS_REPORTER *aReporter=nullptr, const std::vector< ZONE * > &aZones={})
Definition board.cpp:1357
void SetVisibleElements(const GAL_SET &aMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1223
void EmbedFonts() override
Finds all fonts used in the board and embeds them in the file if permissions allow.
Definition board.cpp:3870
PCB_BOARD_OUTLINE * m_boardOutline
Definition board.h:1906
void SetUserDefinedLayerCount(int aCount)
Definition board.cpp:1153
const DRAWINGS & Drawings() const
Definition board.h:465
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition board.cpp:2012
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr coord_type GetY() const
Definition box2.h:205
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr coord_type GetX() const
Definition box2.h:204
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition box2.h:135
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:79
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Definition commit.h:92
A class to manage Component Classes in a board context.
void RecalculateRatsnest(BOARD_COMMIT *aCommit=nullptr)
Function RecalculateRatsnest() Updates the ratsnest for the board.
void RunOnUnconnectedEdges(std::function< bool(CN_EDGE &)> aFunc)
unsigned int GetUnconnectedCount(bool aVisibileOnly) const
static DELETED_BOARD_ITEM * GetInstance()
Definition board_item.h:609
Container for an DRC exclusion, which is a PCB_MARKER plus an optional comment.
static DRC_EXCLUSION FromMarker(const PCB_MARKER &aMarker)
void Build(const BOARD &aBoard, const std::vector< DRILL_SPAN > &aSpans)
const DRILL_CHART_TOTALS & Totals() const
uint64_t Fingerprint() const
Cheap value used to notice an edit.
The base class for create windows for drawing purpose.
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
virtual VECTOR2I GetPosition() const
Definition eda_item.h:348
virtual void ClearEditFlags()
Definition eda_item.h:178
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
const KIID m_Uuid
Definition eda_item.h:597
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
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:401
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:287
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
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:94
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.
const std::map< wxString, std::shared_ptr< EMBEDDED_FILE > > & EmbeddedFileMap() const
Provide an iterable view of the file collection.
EMBEDDED_FILES()=default
Variant information for a footprint.
Definition footprint.h:227
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:425
static GAL_SET DefaultVisible()
Definition lset.cpp:782
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:132
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:94
virtual bool IsOutline() const
Definition font.h:102
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:98
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:63
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:1852
Definition kiid.h:46
wxString AsString() const
Definition kiid.cpp:264
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_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, LENGTH_DELAY_ITEM_DETAILS *aPerItemLengthDelays=nullptr) const
Calculates the electrical length of the given items.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
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:595
static const LSET & AllLayersMask()
Definition lset.cpp:637
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:693
std::shared_ptr< RC_ITEM > GetRCItem() const
void SetExcluded(bool aExcluded, const wxString &aComment=wxEmptyString)
Definition marker_base.h:90
static const char Default[]
the name of the default NETCLASS
Definition netclass.h:45
void SetDescription(const wxString &aDesc)
Definition netclass.h:128
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:110
int GetNetCode() const
Definition netinfo.h:104
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition netinfo.h:66
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:280
static const int ORPHANED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition netinfo.h:284
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:288
unsigned GetNetCount() const
Definition netinfo.h:254
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
Definition netinfo.h:257
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() const
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:61
VECTOR2I GetPosition() const override
Definition pad.cpp:246
const VECTOR2D & GetSizeMils() const
Definition page_info.h:146
wxPrintOrientation GetWxOrientation() const
Definition page_info.h:129
static double GetCustomHeightMils()
Definition page_info.h:198
wxPaperSize GetPaperId() const
Definition page_info.h:134
static double GetCustomWidthMils()
Definition page_info.h:193
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...
A geometric constraint between board items (issue #2329).
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
Turns on drill symbols at the holes, for one layer.
int GetSymbolExtent() const
const VECTOR2I & GetOffset() const
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
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:545
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:551
static PCB_MARKER * FromProto(const kiapi::board::DrcMarker &aMsg)
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:39
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:786
const VECTOR2I & GetEndPoint(ENDPOINT_T aEndPoint) const
Return the selected endpoint (start or end)
Definition pcb_track.h:108
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:63
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:195
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:201
std::vector< KIID > GetIDs() const
Definition rc_item.h:131
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:430
std::string & MutableString()
Definition richio.h:458
const wxString & GetComment(int aIdx) const
static void GetContextualTextVars(wxArrayString *aVars)
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool AppendCorner(const 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:1441
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:641
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:681
bool SetNetCode(int aNetCode, bool aNoAssert) override
Override that clamps the netcode to 0 when this zone is in copper-thieving fill mode.
Definition zone.cpp:623
const wxString & GetZoneName() const
Definition zone.h:160
bool IsTeardropArea() const
Definition zone.h:782
@ INTERNAL
Definition common.h:92
#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)
std::vector< DRILL_SPAN > EnumerateDrillSpans(const BOARD &aBoard)
Every drill span present on the board, through-holes first.
std::map< KIID, std::vector< DRILL_SYMBOL_ENTRY > > ResolveDrillSymbolsByItem(const BOARD &aBoard, const std::map< std::string, DRILL_SYMBOL_ASSIGNMENT > &aResolved)
The same answer keyed by the item that owns the holes.
std::map< std::string, DRILL_SYMBOL_ASSIGNMENT > ResolveDrillSymbols(const BOARD &aBoard)
The symbol every hole should carry, without touching the board.
#define _(s)
RECURSE_MODE
Definition eda_item.h:50
@ RECURSE
Definition eda_item.h:51
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
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:88
#define STRUCT_DELETED
flag indication structures to be erased
EDA_UNITS
Definition eda_units.h:44
static const std::string DesignRulesFileExtension
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:703
GAL_LAYER_ID
GAL layers are "virtual" layers, i.e.
Definition layer_ids.h:224
@ GAL_LAYER_ID_START
Definition layer_ids.h:225
@ LAYER_FOOTPRINTS_FR
Show footprints on front.
Definition layer_ids.h:255
@ 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:283
@ LAYER_RATSNEST
Definition layer_ids.h:249
@ LAYER_FOOTPRINTS_BK
Show footprints on back.
Definition layer_ids.h:256
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ Rescue
Definition layer_ids.h:117
@ User_1
Definition layer_ids.h:120
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ F_Cu
Definition layer_ids.h:60
#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:383
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
STL namespace.
std::map< wxString, NETINFO_ITEM * > NETNAMES_MAP
Definition netinfo.h:224
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:122
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:120
PAGE_SIZE_TYPE
Definition page_info.h:46
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:120
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:4185
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition board.cpp:4164
DRILL_CHART_TOTALS m_Totals
Counts for the ${DRILL_*} text variables.
Definition board.h:356
One drawable mark, with the geometry the renderer needs to place it.
std::vector< char > decompressedData
Data produced by a registered saver on the UI thread, consumed by either the background local-history...
std::string content
Serialized content (mutually exclusive with sourcePath)
KICAD_FORMAT::FORMAT_MODE formatMode
wxString relativePath
Destination path relative to the project root.
Container to hold information pertinent to a layer of a BOARD.
Definition board.h:257
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition board.cpp:1043
static const char * ShowType(LAYER_T aType)
Convert a LAYER_T enum to a string representation of the layer type.
Definition board.cpp:1027
Holds length measurement result details and statistics.
Struct to control which optimisations the length calculation code runs on the given path objects.
bool copied
static const long long MM
wxString result
Test unit parsing edge cases and error handling.
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:27
wxLogTrace helper definitions.
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:259
constexpr bool IsSingleLayerType(const KICAD_T aType)
Definition typeinfo.h:506
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_T
Definition typeinfo.h:74
@ PCB_CONSTRAINT_T
a geometric constraint between board items
Definition typeinfo.h:237
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:83
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DRILL_MAP_T
class PCB_DRILL_MAP, drill symbols drawn at the holes
Definition typeinfo.h:240
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:81
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:91
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:99
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78
@ PCB_GRID_ITEM_T
a subgrid placed on a board
Definition typeinfo.h:238
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_NETINFO_T
class NETINFO_ITEM, a description of a net
Definition typeinfo.h:102
@ PCB_POINT_T
class PCB_POINT, a 0-dimensional point
Definition typeinfo.h:105
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.