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