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