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