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
1295wxString BOARD::GetUniqueZoneName( const wxString& aBaseName, const ZONE* aExclude ) const
1296{
1297 if( aBaseName.IsEmpty() )
1298 return aBaseName;
1299
1300 auto inUse = [&]( const wxString& aName )
1301 {
1302 for( const ZONE* zone : m_zones )
1303 {
1304 if( zone != aExclude && zone->GetZoneName() == aName )
1305 return true;
1306 }
1307
1308 return false;
1309 };
1310
1311 if( !inUse( aBaseName ) )
1312 return aBaseName;
1313
1314 // Strip a trailing _<number> so repeated copies increment the root (foo_1 -> foo_2),
1315 // instead of stacking suffixes (foo_1_1_1).
1316 wxString root = aBaseName;
1317
1318 if( aBaseName.Find( '_' ) != wxNOT_FOUND )
1319 {
1320 wxString suffix = aBaseName.AfterLast( '_' );
1321 bool allDigits = !suffix.IsEmpty();
1322
1323 for( wxUniChar ch : suffix )
1324 {
1325 if( !wxIsdigit( ch ) )
1326 {
1327 allDigits = false;
1328 break;
1329 }
1330 }
1331
1332 if( allDigits )
1333 root = aBaseName.BeforeLast( '_' );
1334 }
1335
1336 for( int i = 1;; ++i )
1337 {
1338 wxString candidate = wxString::Format( wxT( "%s_%d" ), root, i );
1339
1340 if( !inUse( candidate ) )
1341 return candidate;
1342 }
1343}
1344
1345
1346void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode, bool aSkipConnectivity )
1347{
1348 if( aBoardItem == nullptr )
1349 {
1350 wxFAIL_MSG( wxT( "BOARD::Add() param error: aBoardItem nullptr" ) );
1351 return;
1352 }
1353
1354 CacheItemById( aBoardItem );
1355
1356 switch( aBoardItem->Type() )
1357 {
1358 case PCB_NETINFO_T: m_NetInfo.AppendNet( (NETINFO_ITEM*) aBoardItem ); break;
1359
1360 // this one uses a vector
1361 case PCB_MARKER_T: m_markers.push_back( (PCB_MARKER*) aBoardItem ); break;
1362
1363 // this one uses a vector
1364 case PCB_GROUP_T: m_groups.push_back( (PCB_GROUP*) aBoardItem ); break;
1365
1366 // this one uses a vector
1367 case PCB_GENERATOR_T: m_generators.push_back( (PCB_GENERATOR*) aBoardItem ); break;
1368
1369 // this one uses a vector
1370 case PCB_ZONE_T: m_zones.push_back( (ZONE*) aBoardItem ); break;
1371
1372 case PCB_VIA_T:
1373 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1374 m_tracks.push_back( static_cast<PCB_VIA*>( aBoardItem ) );
1375 else
1376 m_tracks.push_front( static_cast<PCB_VIA*>( aBoardItem ) );
1377
1378 break;
1379
1380 case PCB_TRACE_T:
1381 case PCB_ARC_T:
1382 if( !IsCopperLayer( aBoardItem->GetLayer() ) )
1383 {
1384 // The only current known source of these is SWIG (KICAD-BY7, et al).
1385 // N.B. This inserts a small memory leak as we lose the track/via/arc.
1386 wxFAIL_MSG( wxString::Format( "BOARD::Add() Cannot place Track on non-copper layer: %d = %s",
1387 static_cast<int>( aBoardItem->GetLayer() ),
1388 GetLayerName( aBoardItem->GetLayer() ) ) );
1389 return;
1390 }
1391
1392 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1393 m_tracks.push_back( static_cast<PCB_TRACK*>( aBoardItem ) );
1394 else
1395 m_tracks.push_front( static_cast<PCB_TRACK*>( aBoardItem ) );
1396
1397 break;
1398
1399 case PCB_FOOTPRINT_T:
1400 {
1401 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aBoardItem );
1402
1403 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1404 m_footprints.push_back( footprint );
1405 else
1406 m_footprints.push_front( footprint );
1407
1408 CacheChildrenById( footprint );
1409 break;
1410 }
1411
1412 case PCB_BARCODE_T:
1413 case PCB_DIM_ALIGNED_T:
1414 case PCB_DIM_CENTER_T:
1415 case PCB_DIM_RADIAL_T:
1417 case PCB_DIM_LEADER_T:
1418 case PCB_SHAPE_T:
1420 case PCB_FIELD_T:
1421 case PCB_TEXT_T:
1422 case PCB_TEXTBOX_T:
1423 case PCB_TABLE_T:
1424 case PCB_TARGET_T:
1425 {
1426 if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND )
1427 m_drawings.push_back( aBoardItem );
1428 else
1429 m_drawings.push_front( aBoardItem );
1430
1431 if( aBoardItem->Type() == PCB_TABLE_T )
1432 {
1433 CacheChildrenById( aBoardItem );
1434 }
1435
1436 break;
1437 }
1438
1439 case PCB_POINT_T:
1440 // These aren't graphics as they have no physical presence
1441 m_points.push_back( static_cast<PCB_POINT*>( aBoardItem ) );
1442 break;
1443
1444 case PCB_TABLECELL_T:
1445 // Handled by parent table
1446 break;
1447
1448 default:
1449 wxFAIL_MSG( wxString::Format( wxT( "BOARD::Add() item type %s not handled" ), aBoardItem->GetClass() ) );
1450 return;
1451 }
1452
1453 aBoardItem->SetParent( this );
1454 aBoardItem->ClearEditFlags();
1455
1456 if( !aSkipConnectivity )
1457 m_connectivity->Add( aBoardItem );
1458
1459 if( aMode != ADD_MODE::BULK_INSERT && aMode != ADD_MODE::BULK_APPEND )
1461}
1462
1463
1464void BOARD::FinalizeBulkAdd( std::vector<BOARD_ITEM*>& aNewItems )
1465{
1467}
1468
1469
1470void BOARD::FinalizeBulkRemove( std::vector<BOARD_ITEM*>& aRemovedItems )
1471{
1472 InvokeListeners( &BOARD_LISTENER::OnBoardItemsRemoved, *this, aRemovedItems );
1473}
1474
1475
1477{
1478 for( int ii = (int) m_zones.size() - 1; ii >= 0; --ii )
1479 {
1480 ZONE* zone = m_zones[ii];
1481
1482 if( zone->IsTeardropArea() && zone->HasFlag( STRUCT_DELETED ) )
1483 {
1484 UncacheItemById( zone->m_Uuid );
1485 m_zones.erase( m_zones.begin() + ii );
1486 m_connectivity->Remove( zone );
1487 aCommit.Removed( zone );
1488 }
1489 }
1490}
1491
1492
1493void BOARD::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aRemoveMode )
1494{
1495 // find these calls and fix them! Don't send me no stinking' nullptr.
1496 wxASSERT( aBoardItem );
1497
1498 // This is redundant with BOARD_COMMIT::Push but necessary to support SWIG interaction
1499 // until the SWIG API is completely removed (since it doesn't use the commit system)
1500 if( EDA_GROUP* parentGroup = aBoardItem->GetParentGroup();
1501 parentGroup && !( parentGroup->AsEdaItem()->GetFlags() & STRUCT_DELETED ) )
1502 {
1503 parentGroup->RemoveItem( aBoardItem );
1504 }
1505
1506 UncacheItemById( aBoardItem->m_Uuid );
1507
1508 switch( aBoardItem->Type() )
1509 {
1510 case PCB_NETINFO_T:
1511 {
1512 NETINFO_ITEM* netItem = static_cast<NETINFO_ITEM*>( aBoardItem );
1513 NETINFO_ITEM* unconnected = m_NetInfo.GetNetItem( NETINFO_LIST::UNCONNECTED );
1514
1515 for( BOARD_CONNECTED_ITEM* boardItem : AllConnectedItems() )
1516 {
1517 if( boardItem->GetNet() == netItem )
1518 boardItem->SetNet( unconnected );
1519 }
1520
1521 m_NetInfo.RemoveNet( netItem );
1522 break;
1523 }
1524
1525 case PCB_MARKER_T: std::erase( m_markers, aBoardItem ); break;
1526
1527 case PCB_GROUP_T: std::erase( m_groups, aBoardItem ); break;
1528
1529 case PCB_ZONE_T: std::erase( m_zones, aBoardItem ); break;
1530
1531 case PCB_POINT_T: std::erase( m_points, aBoardItem ); break;
1532
1533 case PCB_GENERATOR_T: std::erase( m_generators, aBoardItem ); break;
1534
1535 case PCB_FOOTPRINT_T:
1536 {
1537 std::erase( m_footprints, aBoardItem );
1538 UncacheChildrenById( aBoardItem );
1539
1540 break;
1541 }
1542
1543 case PCB_TRACE_T:
1544 case PCB_ARC_T:
1545 case PCB_VIA_T: std::erase( m_tracks, aBoardItem ); break;
1546
1547 case PCB_BARCODE_T:
1548 case PCB_DIM_ALIGNED_T:
1549 case PCB_DIM_CENTER_T:
1550 case PCB_DIM_RADIAL_T:
1552 case PCB_DIM_LEADER_T:
1553 case PCB_SHAPE_T:
1555 case PCB_FIELD_T:
1556 case PCB_TEXT_T:
1557 case PCB_TEXTBOX_T:
1558 case PCB_TABLE_T:
1559 case PCB_TARGET_T:
1560 {
1561 std::erase( m_drawings, aBoardItem );
1562
1563 if( aBoardItem->Type() == PCB_TABLE_T )
1564 {
1565 UncacheChildrenById( aBoardItem );
1566 }
1567
1568 break;
1569 }
1570
1571 case PCB_TABLECELL_T:
1572 // Handled by parent table
1573 break;
1574
1575 // other types may use linked list
1576 default:
1577 wxFAIL_MSG( wxString::Format( wxT( "BOARD::Remove() item type %s not handled" ), aBoardItem->GetClass() ) );
1578 }
1579
1580 aBoardItem->SetFlags( STRUCT_DELETED );
1581
1582 m_connectivity->Remove( aBoardItem );
1583
1584 if( aRemoveMode != REMOVE_MODE::BULK )
1586}
1587
1588
1589void BOARD::RemoveAll( std::initializer_list<KICAD_T> aTypes )
1590{
1591 std::vector<BOARD_ITEM*> removed;
1592 std::vector<NETINFO_ITEM*> removedNets;
1593
1594 for( const KICAD_T& type : aTypes )
1595 {
1596 switch( type )
1597 {
1598 case PCB_NETINFO_T:
1599 for( NETINFO_ITEM* item : m_NetInfo )
1600 {
1601 removed.emplace_back( item );
1602 removedNets.emplace_back( item );
1603 }
1604
1605 // Listeners must observe live pointers during FinalizeBulkRemove;
1606 // free after notification (issue 24100).
1607 m_NetInfo.detachAll();
1608 break;
1609
1610 case PCB_MARKER_T:
1611 std::copy( m_markers.begin(), m_markers.end(), std::back_inserter( removed ) );
1612 m_markers.clear();
1613 break;
1614
1615 case PCB_GROUP_T:
1616 std::copy( m_groups.begin(), m_groups.end(), std::back_inserter( removed ) );
1617 m_groups.clear();
1618 break;
1619
1620 case PCB_POINT_T:
1621 std::copy( m_points.begin(), m_points.end(), std::back_inserter( removed ) );
1622 m_points.clear();
1623 break;
1624
1625 case PCB_ZONE_T:
1626 std::copy( m_zones.begin(), m_zones.end(), std::back_inserter( removed ) );
1627 m_zones.clear();
1628 break;
1629
1630 case PCB_GENERATOR_T:
1631 std::copy( m_generators.begin(), m_generators.end(), std::back_inserter( removed ) );
1632 m_generators.clear();
1633 break;
1634
1635 case PCB_FOOTPRINT_T:
1636 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( removed ) );
1637 m_footprints.clear();
1638 break;
1639
1640 case PCB_TRACE_T:
1641 std::copy( m_tracks.begin(), m_tracks.end(), std::back_inserter( removed ) );
1642 m_tracks.clear();
1643 break;
1644
1645 case PCB_ARC_T:
1646 case PCB_VIA_T: wxFAIL_MSG( wxT( "Use PCB_TRACE_T to remove all tracks, arcs, and vias" ) ); break;
1647
1648 case PCB_SHAPE_T:
1649 std::copy( m_drawings.begin(), m_drawings.end(), std::back_inserter( removed ) );
1650 m_drawings.clear();
1651 break;
1652
1653 case PCB_DIM_ALIGNED_T:
1654 case PCB_DIM_CENTER_T:
1655 case PCB_DIM_RADIAL_T:
1657 case PCB_DIM_LEADER_T:
1659 case PCB_FIELD_T:
1660 case PCB_TEXT_T:
1661 case PCB_TEXTBOX_T:
1662 case PCB_TABLE_T:
1663 case PCB_TARGET_T:
1664 case PCB_BARCODE_T: wxFAIL_MSG( wxT( "Use PCB_SHAPE_T to remove all graphics and text" ) ); break;
1665
1666 default: wxFAIL_MSG( wxT( "BOARD::RemoveAll() needs more ::Type() support" ) );
1667 }
1668 }
1669
1670 m_itemByIdCache.clear();
1671 m_cachedIdByItem.clear();
1672
1674
1675 FinalizeBulkRemove( removed );
1676
1677 for( NETINFO_ITEM* item : removedNets )
1678 delete item;
1679}
1680
1681
1683{
1684 PCB_LAYER_COLLECTOR collector;
1685
1686 collector.SetLayerId( aLayer );
1688
1689 if( collector.GetCount() != 0 )
1690 {
1691 // Skip items owned by footprints and footprints when building
1692 // the actual list of removed layers: these items are not removed
1693 for( int i = 0; i < collector.GetCount(); i++ )
1694 {
1695 BOARD_ITEM* item = collector[i];
1696
1697 if( item->Type() == PCB_FOOTPRINT_T || item->GetParentFootprint() )
1698 continue;
1699
1700 // Vias are on multiple adjacent layers, but only the top and
1701 // the bottom layers are stored. So there are issues only if one
1702 // is on a removed layer
1703 if( item->Type() == PCB_VIA_T )
1704 {
1705 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1706
1707 if( via->GetViaType() == VIATYPE::THROUGH )
1708 continue;
1709 else
1710 {
1711 PCB_LAYER_ID top_layer;
1712 PCB_LAYER_ID bottom_layer;
1713 via->LayerPair( &top_layer, &bottom_layer );
1714
1715 if( top_layer != aLayer && bottom_layer != aLayer )
1716 continue;
1717 }
1718 }
1719
1720 return true;
1721 }
1722 }
1723
1724 return false;
1725}
1726
1727
1729{
1730 bool modified = false;
1731 bool removedItemLayers = false;
1732 PCB_LAYER_COLLECTOR collector;
1733
1734 collector.SetLayerId( aLayer );
1736
1737 for( int i = 0; i < collector.GetCount(); i++ )
1738 {
1739 BOARD_ITEM* item = collector[i];
1740
1741 // Do not remove/change an item owned by a footprint
1742 if( item->GetParentFootprint() )
1743 continue;
1744
1745 // Do not remove footprints
1746 if( item->Type() == PCB_FOOTPRINT_T )
1747 continue;
1748
1749 // Note: vias are specific. They are only on copper layers, and
1750 // do not use a layer set, only store the copper top and the copper bottom.
1751 // So reinit the layer set does not work with vias
1752 if( item->Type() == PCB_VIA_T )
1753 {
1754 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1755
1756 if( via->GetViaType() == VIATYPE::THROUGH )
1757 {
1758 removedItemLayers = true;
1759 continue;
1760 }
1761 else if( via->IsOnLayer( aLayer ) )
1762 {
1763 PCB_LAYER_ID top_layer;
1764 PCB_LAYER_ID bottom_layer;
1765 via->LayerPair( &top_layer, &bottom_layer );
1766
1767 if( top_layer == aLayer || bottom_layer == aLayer )
1768 {
1769 // blind/buried vias with a top or bottom layer on a removed layer
1770 // are removed. Perhaps one could just modify the top/bottom layer,
1771 // but I am not sure this is better.
1772 Remove( item );
1773 delete item;
1774 modified = true;
1775 }
1776
1777 removedItemLayers = true;
1778 }
1779 }
1780 else if( item->IsOnLayer( aLayer ) )
1781 {
1782 LSET layers = item->GetLayerSet();
1783
1784 layers.reset( aLayer );
1785
1786 if( layers.any() )
1787 {
1788 item->SetLayerSet( layers );
1789 }
1790 else
1791 {
1792 Remove( item );
1793 delete item;
1794 modified = true;
1795 }
1796
1797 removedItemLayers = true;
1798 }
1799 }
1800
1801 if( removedItemLayers )
1803
1804 return modified;
1805}
1806
1807
1808wxString BOARD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1809{
1810 return wxString::Format( _( "PCB" ) );
1811}
1812
1813
1815{
1816 INSPECTOR_FUNC inspector = [&]( EDA_ITEM* descendant, void* aTestData )
1817 {
1818 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( descendant );
1819
1820 if( dimension->GetUnitsMode() == DIM_UNITS_MODE::AUTOMATIC )
1821 {
1822 dimension->UpdateUnits();
1823
1824 if( aView )
1825 aView->Update( dimension );
1826 }
1827
1829 };
1830
1831 aItem->Visit( inspector, nullptr,
1833}
1834
1835
1837{
1838 for( PCB_MARKER* marker : m_markers )
1839 UncacheItemById( marker->m_Uuid );
1840
1841 for( PCB_MARKER* marker : m_markers )
1842 delete marker;
1843
1844 m_markers.clear();
1846}
1847
1848
1849void BOARD::DeleteMARKERs( bool aWarningsAndErrors, bool aExclusions )
1850{
1851 // Deleting lots of items from a vector can be very slow. Copy remaining items instead.
1852 std::vector<PCB_MARKER*> remaining;
1853
1854 for( PCB_MARKER* marker : m_markers )
1855 {
1856 if( ( marker->GetSeverity() == RPT_SEVERITY_EXCLUSION && aExclusions )
1857 || ( marker->GetSeverity() != RPT_SEVERITY_EXCLUSION && aWarningsAndErrors ) )
1858 {
1859 UncacheItemById( marker->m_Uuid );
1860 delete marker;
1861 }
1862 else
1863 {
1864 remaining.push_back( marker );
1865 }
1866 }
1867
1868 m_markers = std::move( remaining );
1870}
1871
1872
1874{
1875 std::vector<FOOTPRINT*> footprints;
1876 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( footprints ) );
1877
1879
1880 for( FOOTPRINT* footprint : footprints )
1881 delete footprint;
1882}
1883
1884
1886{
1887 std::vector<FOOTPRINT*> footprints;
1888 std::copy( m_footprints.begin(), m_footprints.end(), std::back_inserter( footprints ) );
1889
1891
1892 for( FOOTPRINT* footprint : footprints )
1893 footprint->SetParent( nullptr );
1894}
1895
1896
1897BOARD_ITEM* BOARD::ResolveItem( const KIID& aID, bool aAllowNullptrReturn ) const
1898{
1899 if( aID == niluuid )
1900 return nullptr;
1901
1902 if( BOARD_ITEM* cached = GetCachedItemById( aID ) )
1903 return cached;
1904
1905 // Linear scan fallback for items not in the cache. Any hit is cached so
1906 // subsequent lookups for the same item are O(1).
1907
1908 for( PCB_GROUP* group : m_groups )
1909 {
1910 if( group->m_Uuid == aID )
1911 return CacheAndReturnItemById( aID, group );
1912 }
1913
1914 for( PCB_GENERATOR* generator : m_generators )
1915 {
1916 if( generator->m_Uuid == aID )
1917 return CacheAndReturnItemById( aID, generator );
1918 }
1919
1920 for( PCB_TRACK* track : Tracks() )
1921 {
1922 if( track->m_Uuid == aID )
1923 return CacheAndReturnItemById( aID, track );
1924 }
1925
1926 for( FOOTPRINT* footprint : Footprints() )
1927 {
1928 if( footprint->m_Uuid == aID )
1929 return CacheAndReturnItemById( aID, footprint );
1930
1931 for( PAD* pad : footprint->Pads() )
1932 {
1933 if( pad->m_Uuid == aID )
1934 return CacheAndReturnItemById( aID, pad );
1935 }
1936
1937 for( PCB_FIELD* field : footprint->GetFields() )
1938 {
1939 wxCHECK2( field, continue );
1940
1941 if( field && field->m_Uuid == aID )
1942 return CacheAndReturnItemById( aID, field );
1943 }
1944
1945 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
1946 {
1947 if( drawing->m_Uuid == aID )
1948 return CacheAndReturnItemById( aID, drawing );
1949 }
1950
1951 for( BOARD_ITEM* zone : footprint->Zones() )
1952 {
1953 if( zone->m_Uuid == aID )
1954 return CacheAndReturnItemById( aID, zone );
1955 }
1956
1957 for( PCB_GROUP* group : footprint->Groups() )
1958 {
1959 if( group->m_Uuid == aID )
1960 return CacheAndReturnItemById( aID, group );
1961 }
1962
1963 for( PCB_POINT* point : footprint->Points() )
1964 {
1965 if( point->m_Uuid == aID )
1966 return CacheAndReturnItemById( aID, point );
1967 }
1968 }
1969
1970 for( ZONE* zone : Zones() )
1971 {
1972 if( zone->m_Uuid == aID )
1973 return CacheAndReturnItemById( aID, zone );
1974 }
1975
1976 for( BOARD_ITEM* drawing : Drawings() )
1977 {
1978 if( drawing->Type() == PCB_TABLE_T )
1979 {
1980 for( PCB_TABLECELL* cell : static_cast<PCB_TABLE*>( drawing )->GetCells() )
1981 {
1982 if( cell->m_Uuid == aID )
1983 return CacheAndReturnItemById( aID, drawing );
1984 }
1985 }
1986
1987 if( drawing->m_Uuid == aID )
1988 return CacheAndReturnItemById( aID, drawing );
1989 }
1990
1991 for( PCB_MARKER* marker : m_markers )
1992 {
1993 if( marker->m_Uuid == aID )
1994 return CacheAndReturnItemById( aID, marker );
1995 }
1996
1997 for( PCB_POINT* point : m_points )
1998 {
1999 if( point->m_Uuid == aID )
2000 return CacheAndReturnItemById( aID, point );
2001 }
2002
2003 for( NETINFO_ITEM* netInfo : m_NetInfo )
2004 {
2005 if( netInfo->m_Uuid == aID )
2006 return CacheAndReturnItemById( aID, netInfo );
2007 }
2008
2009 if( m_Uuid == aID )
2010 return const_cast<BOARD*>( this );
2011
2012 // Not found; weak reference has been deleted.
2013 if( aAllowNullptrReturn )
2014 return nullptr;
2015
2017}
2018
2019
2021{
2022 auto it = m_itemByIdCache.find( aId );
2023
2024 if( it == m_itemByIdCache.end() )
2025 return nullptr;
2026
2027 BOARD_ITEM* item = it->second;
2028
2029 if( item && item->m_Uuid == aId )
2030 return item;
2031
2032 UncacheItemById( aId );
2033 return nullptr;
2034}
2035
2036
2038{
2039 if( IsFootprintHolder() )
2040 return;
2041
2042 if( auto prev = m_cachedIdByItem.find( aItem );
2043 prev != m_cachedIdByItem.end() && prev->second != aItem->m_Uuid )
2044 {
2045 auto prevIt = m_itemByIdCache.find( prev->second );
2046
2047 if( prevIt != m_itemByIdCache.end() && prevIt->second == aItem )
2048 m_itemByIdCache.erase( prevIt );
2049 }
2050
2051 if( auto existing = m_itemByIdCache.find( aItem->m_Uuid );
2052 existing != m_itemByIdCache.end() && existing->second != aItem )
2053 {
2054 if( auto prev = m_cachedIdByItem.find( existing->second );
2055 prev != m_cachedIdByItem.end() && prev->second == aItem->m_Uuid )
2056 {
2057 m_cachedIdByItem.erase( prev );
2058 }
2059 }
2060
2061 m_itemByIdCache.insert_or_assign( aItem->m_Uuid, aItem );
2062 m_cachedIdByItem.insert_or_assign( aItem, aItem->m_Uuid );
2063}
2064
2065
2066void BOARD::UncacheItemById( const KIID& aId ) const
2067{
2068 auto it = m_itemByIdCache.find( aId );
2069
2070 if( it == m_itemByIdCache.end() )
2071 return;
2072
2073 const BOARD_ITEM* item = it->second;
2074
2075 m_itemByIdCache.erase( it );
2076
2077 if( auto cached = m_cachedIdByItem.find( item );
2078 cached != m_cachedIdByItem.end() && cached->second == aId )
2079 {
2080 m_cachedIdByItem.erase( cached );
2081 }
2082}
2083
2084
2086{
2087 if( IsFootprintHolder() )
2088 return aItem;
2089
2090 if( auto prev = m_cachedIdByItem.find( aItem );
2091 prev != m_cachedIdByItem.end() && prev->second != aId )
2092 {
2093 auto prevIt = m_itemByIdCache.find( prev->second );
2094
2095 if( prevIt != m_itemByIdCache.end() && prevIt->second == aItem )
2096 m_itemByIdCache.erase( prevIt );
2097 }
2098
2099 if( auto existing = m_itemByIdCache.find( aId );
2100 existing != m_itemByIdCache.end() && existing->second != aItem )
2101 {
2102 if( auto prev = m_cachedIdByItem.find( existing->second );
2103 prev != m_cachedIdByItem.end() && prev->second == aId )
2104 {
2105 m_cachedIdByItem.erase( prev );
2106 }
2107 }
2108
2109 m_itemByIdCache.insert_or_assign( aId, aItem );
2110 m_cachedIdByItem.insert_or_assign( aItem, aId );
2111
2112 return aItem;
2113}
2114
2115
2117{
2118 if( auto cached = m_cachedIdByItem.find( aItem ); cached != m_cachedIdByItem.end() )
2119 {
2120 auto it = m_itemByIdCache.find( cached->second );
2121
2122 if( it != m_itemByIdCache.end() && it->second == aItem )
2123 m_itemByIdCache.erase( it );
2124
2125 m_cachedIdByItem.erase( cached );
2126 return;
2127 }
2128
2129 for( auto it = m_itemByIdCache.begin(); it != m_itemByIdCache.end(); )
2130 {
2131 if( it->second == aItem )
2132 it = m_itemByIdCache.erase( it );
2133 else
2134 ++it;
2135 }
2136}
2137
2138
2139void BOARD::RebindItemUuid( BOARD_ITEM* aItem, const KIID& aNewId )
2140{
2141 wxCHECK_RET( aItem, "BOARD::RebindItemUuid() requires a valid item" );
2142
2143 if( IsFootprintHolder() )
2144 return;
2145
2146 if( aItem->m_Uuid == aNewId )
2147 {
2148 CacheAndReturnItemById( aNewId, aItem );
2149 return;
2150 }
2151
2152 if( BOARD_ITEM* existing = GetCachedItemById( aNewId ); existing && existing != aItem )
2153 {
2154 wxFAIL_MSG( wxString::Format( "BOARD::RebindItemUuid() duplicate target UUID: %s",
2155 aNewId.AsString() ) );
2156 return;
2157 }
2158
2159 UncacheItemByPtr( aItem );
2160 aItem->SetUuidDirect( aNewId );
2161 CacheAndReturnItemById( aNewId, aItem );
2162}
2163
2164
2166{
2167 std::set<KIID> ids;
2168 int duplicates = 0;
2169
2170 auto processItem =
2171 [&]( BOARD_ITEM* aItem )
2172 {
2173 wxCHECK2( aItem, return );
2174
2175 if( ids.count( aItem->m_Uuid ) )
2176 {
2177 duplicates++;
2178 RebindItemUuid( aItem, KIID() );
2179 }
2180
2181 ids.insert( aItem->m_Uuid );
2182 };
2183
2184 // Footprint IDs are the most important, so give them the first crack at "claiming" a
2185 // particular KIID.
2186 for( FOOTPRINT* footprint : Footprints() )
2187 processItem( footprint );
2188
2189 // After that the principal use is for DRC marker pointers, which are most likely to pads
2190 // or tracks.
2191 for( FOOTPRINT* footprint : Footprints() )
2192 {
2193 for( PAD* pad : footprint->Pads() )
2194 processItem( pad );
2195 }
2196
2197 for( PCB_TRACK* track : Tracks() )
2198 processItem( track );
2199
2200 // From here out I don't think order matters much.
2201 for( FOOTPRINT* footprint : Footprints() )
2202 {
2203 processItem( &footprint->Reference() );
2204 processItem( &footprint->Value() );
2205
2206 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2207 processItem( item );
2208
2209 for( ZONE* zone : footprint->Zones() )
2210 processItem( zone );
2211
2212 for( PCB_GROUP* group : footprint->Groups() )
2213 processItem( group );
2214 }
2215
2216 // Everything owned by the board not handled above.
2217 for( BOARD_ITEM* item : GetItemSet() )
2218 {
2219 // Top-level footprints and tracks were handled above.
2220 switch( item->Type() )
2221 {
2222 case PCB_FOOTPRINT_T:
2223 case PCB_TRACE_T:
2224 case PCB_ARC_T:
2225 case PCB_VIA_T:
2226 break;
2227
2228 default:
2229 processItem( item );
2230 break;
2231 }
2232 }
2233
2234 return duplicates;
2235}
2236
2237
2238void BOARD::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
2239{
2240 // the board itself
2241 aMap[m_Uuid] = this;
2242
2243 for( PCB_TRACK* track : Tracks() )
2244 aMap[track->m_Uuid] = track;
2245
2246 for( FOOTPRINT* footprint : Footprints() )
2247 {
2248 aMap[footprint->m_Uuid] = footprint;
2249
2250 for( PAD* pad : footprint->Pads() )
2251 aMap[pad->m_Uuid] = pad;
2252
2253 aMap[footprint->Reference().m_Uuid] = &footprint->Reference();
2254 aMap[footprint->Value().m_Uuid] = &footprint->Value();
2255
2256 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2257 aMap[drawing->m_Uuid] = drawing;
2258 }
2259
2260 for( ZONE* zone : Zones() )
2261 aMap[zone->m_Uuid] = zone;
2262
2263 for( BOARD_ITEM* drawing : Drawings() )
2264 aMap[drawing->m_Uuid] = drawing;
2265
2266 for( PCB_MARKER* marker : m_markers )
2267 aMap[marker->m_Uuid] = marker;
2268
2269 for( PCB_GROUP* group : m_groups )
2270 aMap[group->m_Uuid] = group;
2271
2272 for( PCB_POINT* point : m_points )
2273 aMap[point->m_Uuid] = point;
2274
2275 for( PCB_GENERATOR* generator : m_generators )
2276 aMap[generator->m_Uuid] = generator;
2277}
2278
2279
2280wxString BOARD::ConvertCrossReferencesToKIIDs( const wxString& aSource ) const
2281{
2282 wxString newbuf;
2283 size_t sourceLen = aSource.length();
2284
2285 for( size_t i = 0; i < sourceLen; ++i )
2286 {
2287 // Check for escaped expressions: \${ or \@{
2288 // These should be copied verbatim without any ref→KIID conversion
2289 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2290 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2291 {
2292 // Copy the escape sequence and the entire escaped expression
2293 newbuf.append( aSource[i] ); // backslash
2294 newbuf.append( aSource[i + 1] ); // $ or @
2295 newbuf.append( aSource[i + 2] ); // {
2296 i += 2;
2297
2298 // Find and copy everything until the matching closing brace
2299 int braceDepth = 1;
2300 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2301 {
2302 if( aSource[i] == '{' )
2303 braceDepth++;
2304 else if( aSource[i] == '}' )
2305 braceDepth--;
2306
2307 newbuf.append( aSource[i] );
2308 }
2309 i--; // Back up one since the for loop will increment
2310 continue;
2311 }
2312
2313 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2314 {
2315 wxString token;
2316 bool isCrossRef = false;
2317
2318 for( i = i + 2; i < sourceLen; ++i )
2319 {
2320 if( aSource[i] == '}' )
2321 break;
2322
2323 if( aSource[i] == ':' )
2324 isCrossRef = true;
2325
2326 token.append( aSource[i] );
2327 }
2328
2329 if( isCrossRef )
2330 {
2331 wxString remainder;
2332 wxString ref = token.BeforeFirst( ':', &remainder );
2333
2334 for( const FOOTPRINT* footprint : Footprints() )
2335 {
2336 if( footprint->GetReference().CmpNoCase( ref ) == 0 )
2337 {
2338 wxString test( remainder );
2339
2340 if( footprint->ResolveTextVar( &test ) )
2341 token = footprint->m_Uuid.AsString() + wxT( ":" ) + remainder;
2342
2343 break;
2344 }
2345 }
2346 }
2347
2348 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2349 }
2350 else
2351 {
2352 newbuf.append( aSource[i] );
2353 }
2354 }
2355
2356 return newbuf;
2357}
2358
2359
2360wxString BOARD::ConvertKIIDsToCrossReferences( const wxString& aSource ) const
2361{
2362 wxString newbuf;
2363 size_t sourceLen = aSource.length();
2364
2365 for( size_t i = 0; i < sourceLen; ++i )
2366 {
2367 // Check for escaped expressions: \${ or \@{
2368 // These should be copied verbatim without any KIID→ref conversion
2369 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2370 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2371 {
2372 // Copy the escape sequence and the entire escaped expression
2373 newbuf.append( aSource[i] ); // backslash
2374 newbuf.append( aSource[i + 1] ); // $ or @
2375 newbuf.append( aSource[i + 2] ); // {
2376 i += 2;
2377
2378 // Find and copy everything until the matching closing brace
2379 int braceDepth = 1;
2380 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2381 {
2382 if( aSource[i] == '{' )
2383 braceDepth++;
2384 else if( aSource[i] == '}' )
2385 braceDepth--;
2386
2387 newbuf.append( aSource[i] );
2388 }
2389 i--; // Back up one since the for loop will increment
2390 continue;
2391 }
2392
2393 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2394 {
2395 wxString token;
2396 bool isCrossRef = false;
2397
2398 for( i = i + 2; i < sourceLen; ++i )
2399 {
2400 if( aSource[i] == '}' )
2401 break;
2402
2403 if( aSource[i] == ':' )
2404 isCrossRef = true;
2405
2406 token.append( aSource[i] );
2407 }
2408
2409 if( isCrossRef )
2410 {
2411 wxString remainder;
2412 wxString ref = token.BeforeFirst( ':', &remainder );
2413 BOARD_ITEM* refItem = ResolveItem( KIID( ref ), true );
2414
2415 if( refItem && refItem->Type() == PCB_FOOTPRINT_T )
2416 {
2417 token = static_cast<FOOTPRINT*>( refItem )->GetReference() + wxT( ":" ) + remainder;
2418 }
2419 }
2420
2421 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2422 }
2423 else
2424 {
2425 newbuf.append( aSource[i] );
2426 }
2427 }
2428
2429 return newbuf;
2430}
2431
2432
2433unsigned BOARD::GetNodesCount( int aNet ) const
2434{
2435 unsigned retval = 0;
2436
2437 for( FOOTPRINT* footprint : Footprints() )
2438 {
2439 for( PAD* pad : footprint->Pads() )
2440 {
2441 if( ( aNet == -1 && pad->GetNetCode() > 0 ) || aNet == pad->GetNetCode() )
2442 retval++;
2443 }
2444 }
2445
2446 return retval;
2447}
2448
2449
2450BOX2I BOARD::ComputeBoundingBox( bool aBoardEdgesOnly, bool aPhysicalLayersOnly ) const
2451{
2452 BOX2I bbox;
2453 LSET visible = GetVisibleLayers();
2454
2455 if( aPhysicalLayersOnly )
2456 visible &= LSET::PhysicalLayersMask();
2457
2458 // If the board is just showing a footprint, we want all footprint layers included in the
2459 // bounding box
2460 if( IsFootprintHolder() )
2461 visible.set();
2462
2463 if( aBoardEdgesOnly )
2464 visible.set( Edge_Cuts );
2465
2466 // Check shapes, dimensions, texts, and fiducials
2467 for( BOARD_ITEM* item : m_drawings )
2468 {
2469 if( aBoardEdgesOnly && ( item->GetLayer() != Edge_Cuts || item->Type() != PCB_SHAPE_T ) )
2470 continue;
2471
2472 if( ( item->GetLayerSet() & visible ).any() )
2473 bbox.Merge( item->GetBoundingBox() );
2474 }
2475
2476 // Check footprints
2477 for( FOOTPRINT* footprint : m_footprints )
2478 {
2479 if( aBoardEdgesOnly )
2480 {
2481 for( const BOARD_ITEM* edge : footprint->GraphicalItems() )
2482 {
2483 if( edge->GetLayer() == Edge_Cuts && edge->Type() == PCB_SHAPE_T )
2484 bbox.Merge( edge->GetBoundingBox() );
2485 }
2486 }
2487 else if( ( footprint->GetLayerSet() & visible ).any() )
2488 {
2489 bbox.Merge( footprint->GetBoundingBox( true ) );
2490 }
2491 }
2492
2493 if( !aBoardEdgesOnly )
2494 {
2495 // Check tracks
2496 for( PCB_TRACK* track : m_tracks )
2497 {
2498 if( ( track->GetLayerSet() & visible ).any() )
2499 bbox.Merge( track->GetBoundingBox() );
2500 }
2501
2502 // Check zones
2503 for( ZONE* aZone : m_zones )
2504 {
2505 if( ( aZone->GetLayerSet() & visible ).any() )
2506 bbox.Merge( aZone->GetBoundingBox() );
2507 }
2508
2509 for( PCB_POINT* point : m_points )
2510 {
2511 bbox.Merge( point->GetBoundingBox() );
2512 }
2513 }
2514
2515 return bbox;
2516}
2517
2518
2519void BOARD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2520{
2521 int padCount = 0;
2522 int viaCount = 0;
2523 int trackSegmentCount = 0;
2524 std::set<int> netCodes;
2525 int unconnected = GetConnectivity()->GetUnconnectedCount( true );
2526
2527 for( PCB_TRACK* item : m_tracks )
2528 {
2529 if( item->Type() == PCB_VIA_T )
2530 viaCount++;
2531 else
2532 trackSegmentCount++;
2533
2534 if( item->GetNetCode() > 0 )
2535 netCodes.insert( item->GetNetCode() );
2536 }
2537
2538 for( FOOTPRINT* footprint : Footprints() )
2539 {
2540 for( PAD* pad : footprint->Pads() )
2541 {
2542 padCount++;
2543
2544 if( pad->GetNetCode() > 0 )
2545 netCodes.insert( pad->GetNetCode() );
2546 }
2547 }
2548
2549 aList.emplace_back( _( "Pads" ), wxString::Format( wxT( "%d" ), padCount ) );
2550 aList.emplace_back( _( "Vias" ), wxString::Format( wxT( "%d" ), viaCount ) );
2551 aList.emplace_back( _( "Track Segments" ), wxString::Format( wxT( "%d" ), trackSegmentCount ) );
2552 aList.emplace_back( _( "Nets" ), wxString::Format( wxT( "%d" ), (int) netCodes.size() ) );
2553 aList.emplace_back( _( "Unrouted" ), wxString::Format( wxT( "%d" ), unconnected ) );
2554}
2555
2556
2557INSPECT_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const std::vector<KICAD_T>& scanTypes )
2558{
2559#if 0 && defined( DEBUG )
2560 std::cout << GetClass().mb_str() << ' ';
2561#endif
2562
2563 bool footprintsScanned = false;
2564 bool drawingsScanned = false;
2565 bool tracksScanned = false;
2566
2567 for( KICAD_T scanType : scanTypes )
2568 {
2569 switch( scanType )
2570 {
2571 case PCB_T:
2572 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
2573 return INSPECT_RESULT::QUIT;
2574
2575 break;
2576
2577 /*
2578 * Instances of the requested KICAD_T live in a list, either one that I manage, or one
2579 * that my footprints manage. If it's a type managed by class FOOTPRINT, then simply
2580 * pass it on to each footprint's Visit() function via IterateForward( m_footprints, ... ).
2581 */
2582
2583 case PCB_FOOTPRINT_T:
2584 case PCB_PAD_T:
2585 case PCB_SHAPE_T:
2587 case PCB_FIELD_T:
2588 case PCB_TEXT_T:
2589 case PCB_TEXTBOX_T:
2590 case PCB_TABLE_T:
2591 case PCB_TABLECELL_T:
2592 case PCB_DIM_ALIGNED_T:
2593 case PCB_DIM_CENTER_T:
2594 case PCB_DIM_RADIAL_T:
2596 case PCB_DIM_LEADER_T:
2597 case PCB_TARGET_T:
2598 case PCB_BARCODE_T:
2599 if( !footprintsScanned )
2600 {
2601 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2602 {
2603 return INSPECT_RESULT::QUIT;
2604 }
2605
2606 footprintsScanned = true;
2607 }
2608
2609 if( !drawingsScanned )
2610 {
2611 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2612 {
2613 return INSPECT_RESULT::QUIT;
2614 }
2615
2616 drawingsScanned = true;
2617 }
2618
2619 break;
2620
2621 case PCB_VIA_T:
2622 case PCB_TRACE_T:
2623 case PCB_ARC_T:
2624 if( !tracksScanned )
2625 {
2626 if( IterateForward<PCB_TRACK*>( m_tracks, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2627 {
2628 return INSPECT_RESULT::QUIT;
2629 }
2630
2631 tracksScanned = true;
2632 }
2633
2634 break;
2635
2636 case PCB_MARKER_T:
2637 for( PCB_MARKER* marker : m_markers )
2638 {
2639 if( marker->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2640 return INSPECT_RESULT::QUIT;
2641 }
2642
2643 break;
2644
2645 case PCB_POINT_T:
2646 for( PCB_POINT* point : m_points )
2647 {
2648 if( point->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2649 return INSPECT_RESULT::QUIT;
2650 }
2651
2652 break;
2653
2654 case PCB_ZONE_T:
2655 if( !footprintsScanned )
2656 {
2657 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2658 {
2659 return INSPECT_RESULT::QUIT;
2660 }
2661
2662 footprintsScanned = true;
2663 }
2664
2665 for( ZONE* zone : m_zones )
2666 {
2667 if( zone->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2668 return INSPECT_RESULT::QUIT;
2669 }
2670
2671 break;
2672
2673 case PCB_GENERATOR_T:
2674 if( !footprintsScanned )
2675 {
2676 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2677 {
2678 return INSPECT_RESULT::QUIT;
2679 }
2680
2681 footprintsScanned = true;
2682 }
2683
2684 if( IterateForward<PCB_GENERATOR*>( m_generators, inspector, testData, { scanType } )
2686 {
2687 return INSPECT_RESULT::QUIT;
2688 }
2689
2690 break;
2691
2692 case PCB_GROUP_T:
2693 if( IterateForward<PCB_GROUP*>( m_groups, inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2694 {
2695 return INSPECT_RESULT::QUIT;
2696 }
2697
2698 break;
2699
2700 default: break;
2701 }
2702 }
2703
2705}
2706
2707
2708NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const
2709{
2710 // the first valid netcode is 1 and the last is m_NetInfo.GetCount()-1.
2711 // zero is reserved for "no connection" and is not actually a net.
2712 // nullptr is returned for non valid netcodes
2713
2714 if( aNetcode == NETINFO_LIST::UNCONNECTED && m_NetInfo.GetNetCount() == 0 )
2716 else
2717 return m_NetInfo.GetNetItem( aNetcode );
2718}
2719
2720
2721NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
2722{
2723 return m_NetInfo.GetNetItem( aNetname );
2724}
2725
2726
2727int BOARD::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet )
2728{
2729 int rv = 0;
2730 int count = 0;
2731
2732 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
2733 {
2734 int ch = *it;
2735
2736 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
2737 {
2738 continue;
2739 }
2740 else if( ch == '+' )
2741 {
2742 aComplementNet = wxT( "-" );
2743 rv = 1;
2744 }
2745 else if( ch == '-' )
2746 {
2747 aComplementNet = wxT( "+" );
2748 rv = -1;
2749 }
2750 else if( ch == 'N' )
2751 {
2752 aComplementNet = wxT( "P" );
2753 rv = -1;
2754 }
2755 else if( ch == 'P' )
2756 {
2757 aComplementNet = wxT( "N" );
2758 rv = 1;
2759 }
2760 else
2761 {
2762 break;
2763 }
2764 }
2765
2766 if( rv != 0 && count >= 1 )
2767 {
2768 aComplementNet = aNetName.Left( aNetName.length() - count ) + aComplementNet + aNetName.Right( count - 1 );
2769 }
2770
2771 return rv;
2772}
2773
2774
2776{
2777 if( aNet )
2778 {
2779 wxString refName = aNet->GetNetname();
2780 wxString coupledNetName;
2781
2782 if( MatchDpSuffix( refName, coupledNetName ) )
2783 return FindNet( coupledNetName );
2784 }
2785
2786 return nullptr;
2787}
2788
2789
2790FOOTPRINT* BOARD::FindFootprintByReference( const wxString& aReference ) const
2791{
2792 for( FOOTPRINT* footprint : m_footprints )
2793 {
2794 if( aReference == footprint->GetReference() )
2795 return footprint;
2796 }
2797
2798 return nullptr;
2799}
2800
2801
2803{
2804 for( FOOTPRINT* footprint : m_footprints )
2805 {
2806 if( footprint->GetPath() == aPath )
2807 return footprint;
2808 }
2809
2810 return nullptr;
2811}
2812
2813
2814PAD* BOARD::FindPadByUuid( const KIID& aUuid ) const
2815{
2816 for( FOOTPRINT* footprint : m_footprints )
2817 {
2818 if( PAD* pad = footprint->FindPadByUuid( aUuid ) )
2819 return pad;
2820 }
2821
2822 return nullptr;
2823}
2824
2825
2826void BOARD::ReplaceNetChainTerminalPad( const wxString& aNetChain, const KIID& aPrev, const KIID& aNew )
2827{
2828 PAD* newPad = FindPadByUuid( aNew );
2829
2830 for( NETINFO_ITEM* net : m_NetInfo )
2831 {
2832 if( net->GetNetChain() == aNetChain )
2833 {
2834 for( int i = 0; i < 2; ++i )
2835 {
2836 PAD* pad = net->GetTerminalPad( i );
2837
2838 if( pad && pad->m_Uuid == aPrev )
2839 net->SetTerminalPad( i, newPad );
2840 }
2841 }
2842 }
2843}
2844
2845
2847{
2848 std::set<wxString> names;
2849
2850 for( const NETINFO_ITEM* net : m_NetInfo )
2851 {
2852 if( !net->GetNetname().IsEmpty() )
2853 names.insert( net->GetNetname() );
2854 }
2855
2856 return names;
2857}
2858
2859
2861{
2862 if( m_project && !m_project->IsNullProject() )
2863 SetProperties( m_project->GetTextVars() );
2864}
2865
2866
2867static wxString FindVariantNameCaseInsensitive( const std::vector<wxString>& aNames,
2868 const wxString& aVariantName )
2869{
2870 for( const wxString& name : aNames )
2871 {
2872 if( name.CmpNoCase( aVariantName ) == 0 )
2873 return name;
2874 }
2875
2876 return wxEmptyString;
2877}
2878
2879
2880void BOARD::SetCurrentVariant( const wxString& aVariant )
2881{
2882 const wxString previous = m_currentVariant;
2883
2884 if( aVariant.IsEmpty() || aVariant.CmpNoCase( GetDefaultVariantName() ) == 0 )
2885 {
2886 m_currentVariant.Clear();
2887 }
2888 else
2889 {
2890 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariant );
2891
2892 if( actualName.IsEmpty() )
2893 m_currentVariant.Clear();
2894 else
2895 m_currentVariant = actualName;
2896 }
2897
2898 // Variant overrides on footprint fields change `${REFDES:FIELD}` resolution,
2899 // so every cross-ref dependent must repaint on switch. Skip the fan-out if
2900 // the active variant did not actually change (e.g. redundant UI callback).
2901 if( previous != m_currentVariant && m_textVarAdapter )
2902 m_textVarAdapter->Tracker().InvalidateVariantScoped();
2903}
2904
2905
2906bool BOARD::HasVariant( const wxString& aVariantName ) const
2907{
2908 return !FindVariantNameCaseInsensitive( m_variantNames, aVariantName ).IsEmpty();
2909}
2910
2911
2912void BOARD::AddVariant( const wxString& aVariantName )
2913{
2914 if( aVariantName.IsEmpty()
2915 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0
2916 || HasVariant( aVariantName ) )
2917 return;
2918
2919 m_variantNames.push_back( aVariantName );
2920}
2921
2922
2923void BOARD::DeleteVariant( const wxString& aVariantName )
2924{
2925 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2926 return;
2927
2928 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
2929 [&]( const wxString& name )
2930 {
2931 return name.CmpNoCase( aVariantName ) == 0;
2932 } );
2933
2934 if( it != m_variantNames.end() )
2935 {
2936 wxString actualName = *it;
2937 m_variantNames.erase( it );
2938 m_variantDescriptions.erase( actualName );
2939
2940 // Clear current variant if it was the deleted one
2941 if( m_currentVariant.CmpNoCase( aVariantName ) == 0 )
2942 m_currentVariant.Clear();
2943
2944 // Remove variant from all footprints
2945 for( FOOTPRINT* fp : m_footprints )
2946 fp->DeleteVariant( actualName );
2947 }
2948}
2949
2950
2951void BOARD::RenameVariant( const wxString& aOldName, const wxString& aNewName )
2952{
2953 if( aNewName.IsEmpty() || aNewName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2954 return;
2955
2956 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
2957 [&]( const wxString& name )
2958 {
2959 return name.CmpNoCase( aOldName ) == 0;
2960 } );
2961
2962 if( it != m_variantNames.end() )
2963 {
2964 wxString actualOldName = *it;
2965
2966 // Check if new name already exists (case-insensitive) and isn't the same variant
2967 wxString existingName = FindVariantNameCaseInsensitive( m_variantNames, aNewName );
2968
2969 if( !existingName.IsEmpty() && existingName.CmpNoCase( actualOldName ) != 0 )
2970 return;
2971
2972 if( actualOldName == aNewName )
2973 return;
2974
2975 *it = aNewName;
2976
2977 // Transfer description
2978 auto descIt = m_variantDescriptions.find( actualOldName );
2979
2980 if( descIt != m_variantDescriptions.end() )
2981 {
2982 if( !descIt->second.IsEmpty() )
2983 m_variantDescriptions[aNewName] = descIt->second;
2984
2985 m_variantDescriptions.erase( descIt );
2986 }
2987
2988 // Update current variant if it was the renamed one
2989 if( m_currentVariant.CmpNoCase( aOldName ) == 0 )
2990 m_currentVariant = aNewName;
2991
2992 // Rename variant in all footprints
2993 for( FOOTPRINT* fp : m_footprints )
2994 fp->RenameVariant( actualOldName, aNewName );
2995 }
2996}
2997
2998
2999wxString BOARD::GetVariantDescription( const wxString& aVariantName ) const
3000{
3001 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
3002 return wxEmptyString;
3003
3004 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
3005
3006 if( actualName.IsEmpty() )
3007 return wxEmptyString;
3008
3009 auto it = m_variantDescriptions.find( actualName );
3010
3011 if( it != m_variantDescriptions.end() )
3012 return it->second;
3013
3014 return wxEmptyString;
3015}
3016
3017
3018void BOARD::SetVariantDescription( const wxString& aVariantName, const wxString& aDescription )
3019{
3020 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
3021 return;
3022
3023 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
3024
3025 if( actualName.IsEmpty() )
3026 return;
3027
3028 if( aDescription.IsEmpty() )
3029 m_variantDescriptions.erase( actualName );
3030 else
3031 m_variantDescriptions[actualName] = aDescription;
3032}
3033
3034
3035wxArrayString BOARD::GetVariantNamesForUI() const
3036{
3037 wxArrayString names;
3038 names.Add( GetDefaultVariantName() );
3039
3040 for( const wxString& name : m_variantNames )
3041 names.Add( name );
3042
3043 names.Sort( SortVariantNames );
3044
3045 return names;
3046}
3047
3048
3050{
3051 m_lengthDelayCalc->SynchronizeTuningProfileProperties();
3052}
3053
3054
3055void BOARD::SynchronizeNetsAndNetClasses( bool aResetTrackAndViaSizes )
3056{
3057 if( !m_project )
3058 return;
3059
3061 const std::shared_ptr<NETCLASS>& defaultNetClass = bds.m_NetSettings->GetDefaultNetclass();
3062
3064
3065 for( NETINFO_ITEM* net : m_NetInfo )
3066 net->SetNetClass( bds.m_NetSettings->GetEffectiveNetClass( net->GetNetname() ) );
3067
3068 if( aResetTrackAndViaSizes )
3069 {
3070 // Set initial values for custom track width & via size to match the default
3071 // netclass settings
3072 bds.UseCustomTrackViaSize( false );
3073 bds.SetCustomTrackWidth( defaultNetClass->GetTrackWidth() );
3074 bds.SetCustomViaSize( defaultNetClass->GetViaDiameter() );
3075 bds.SetCustomViaDrill( defaultNetClass->GetViaDrill() );
3076 bds.SetCustomDiffPairWidth( defaultNetClass->GetDiffPairWidth() );
3077 bds.SetCustomDiffPairGap( defaultNetClass->GetDiffPairGap() );
3078 bds.SetCustomDiffPairViaGap( defaultNetClass->GetDiffPairViaGap() );
3079 }
3080
3082}
3083
3084
3085bool BOARD::SynchronizeComponentClasses( const std::unordered_set<wxString>& aNewSheetPaths ) const
3086{
3087 std::shared_ptr<COMPONENT_CLASS_SETTINGS> settings = GetProject()->GetProjectFile().ComponentClassSettings();
3088
3089 return m_componentClassManager->SyncDynamicComponentClassAssignments(
3090 settings->GetComponentClassAssignments(), settings->GetEnableSheetComponentClasses(), aNewSheetPaths );
3091}
3092
3093
3095{
3096 int error_count = 0;
3097
3098 for( ZONE* zone : Zones() )
3099 {
3100 if( !zone->IsOnCopperLayer() )
3101 {
3102 zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3103 continue;
3104 }
3105
3106 if( zone->GetNetCode() != 0 ) // i.e. if this zone is connected to a net
3107 {
3108 const NETINFO_ITEM* net = zone->GetNet();
3109
3110 if( net )
3111 {
3112 zone->SetNetCode( net->GetNetCode() );
3113 }
3114 else
3115 {
3116 error_count++;
3117
3118 // keep Net Name and set m_NetCode to -1 : error flag.
3119 zone->SetNetCode( -1 );
3120 }
3121 }
3122 }
3123
3124 return error_count;
3125}
3126
3127
3128PAD* BOARD::GetPad( const VECTOR2I& aPosition, const LSET& aLayerSet ) const
3129{
3130 for( FOOTPRINT* footprint : m_footprints )
3131 {
3132 PAD* pad = nullptr;
3133
3134 if( footprint->HitTest( aPosition ) )
3135 pad = footprint->GetPad( aPosition, aLayerSet.any() ? aLayerSet : LSET::AllCuMask() );
3136
3137 if( pad )
3138 return pad;
3139 }
3140
3141 return nullptr;
3142}
3143
3144
3145PAD* BOARD::GetPad( const PCB_TRACK* aTrace, ENDPOINT_T aEndPoint ) const
3146{
3147 const VECTOR2I& aPosition = aTrace->GetEndPoint( aEndPoint );
3148
3149 LSET lset( { aTrace->GetLayer() } );
3150
3151 return GetPad( aPosition, lset );
3152}
3153
3154
3155PAD* BOARD::GetPad( std::vector<PAD*>& aPadList, const VECTOR2I& aPosition, const LSET& aLayerSet ) const
3156{
3157 // Search aPadList for aPosition
3158 // aPadList is sorted by X then Y values, and a fast binary search is used
3159 int idxmax = aPadList.size() - 1;
3160
3161 int delta = aPadList.size();
3162
3163 int idx = 0; // Starting index is the beginning of list
3164
3165 while( delta )
3166 {
3167 // Calculate half size of remaining interval to test.
3168 // Ensure the computed value is not truncated (too small)
3169 if( ( delta & 1 ) && ( delta > 1 ) )
3170 delta++;
3171
3172 delta /= 2;
3173
3174 PAD* pad = aPadList[idx];
3175
3176 if( pad->GetPosition() == aPosition ) // candidate found
3177 {
3178 // The pad must match the layer mask:
3179 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3180 return pad;
3181
3182 // More than one pad can be at aPosition
3183 // search for a pad at aPosition that matched this mask
3184
3185 // search next
3186 for( int ii = idx + 1; ii <= idxmax; ii++ )
3187 {
3188 pad = aPadList[ii];
3189
3190 if( pad->GetPosition() != aPosition )
3191 break;
3192
3193 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3194 return pad;
3195 }
3196 // search previous
3197 for( int ii = idx - 1; ii >= 0; ii-- )
3198 {
3199 pad = aPadList[ii];
3200
3201 if( pad->GetPosition() != aPosition )
3202 break;
3203
3204 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3205 return pad;
3206 }
3207
3208 // Not found:
3209 return nullptr;
3210 }
3211
3212 if( pad->GetPosition().x == aPosition.x ) // Must search considering Y coordinate
3213 {
3214 if( pad->GetPosition().y < aPosition.y ) // Must search after this item
3215 {
3216 idx += delta;
3217
3218 if( idx > idxmax )
3219 idx = idxmax;
3220 }
3221 else // Must search before this item
3222 {
3223 idx -= delta;
3224
3225 if( idx < 0 )
3226 idx = 0;
3227 }
3228 }
3229 else if( pad->GetPosition().x < aPosition.x ) // Must search after this item
3230 {
3231 idx += delta;
3232
3233 if( idx > idxmax )
3234 idx = idxmax;
3235 }
3236 else // Must search before this item
3237 {
3238 idx -= delta;
3239
3240 if( idx < 0 )
3241 idx = 0;
3242 }
3243 }
3244
3245 return nullptr;
3246}
3247
3248
3254bool sortPadsByXthenYCoord( PAD* const& aLH, PAD* const& aRH )
3255{
3256 if( aLH->GetPosition().x == aRH->GetPosition().x )
3257 return aLH->GetPosition().y < aRH->GetPosition().y;
3258
3259 return aLH->GetPosition().x < aRH->GetPosition().x;
3260}
3261
3262
3263void BOARD::GetSortedPadListByXthenYCoord( std::vector<PAD*>& aVector, int aNetCode ) const
3264{
3265 for( FOOTPRINT* footprint : Footprints() )
3266 {
3267 for( PAD* pad : footprint->Pads() )
3268 {
3269 if( aNetCode < 0 || pad->GetNetCode() == aNetCode )
3270 aVector.push_back( pad );
3271 }
3272 }
3273
3274 std::sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
3275}
3276
3277
3279{
3280 if( GetDesignSettings().m_HasStackup )
3282
3283 BOARD_STACKUP stackup;
3285 return stackup;
3286}
3287
3288
3289std::tuple<int, double, double, double, double> BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const
3290{
3291 std::shared_ptr<CONNECTIVITY_DATA> connectivity = GetBoard()->GetConnectivity();
3292 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items;
3293
3294 for( BOARD_CONNECTED_ITEM* boardItem : connectivity->GetConnectedItems( &aTrack, EXCLUDE_ZONES ) )
3295 {
3297
3298 if( item.Type() != LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
3299 items.push_back( std::move( item ) );
3300 }
3301
3302 constexpr PATH_OPTIMISATIONS opts = {
3303 .OptimiseVias = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false
3304 };
3306 items, opts, nullptr, nullptr, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL,
3308
3309 return std::make_tuple( items.size(), details.TrackLength + details.ViaLength, details.PadToDieLength,
3310 details.TrackDelay + details.ViaDelay, details.PadToDieDelay );
3311}
3312
3313
3314FOOTPRINT* BOARD::GetFootprint( const VECTOR2I& aPosition, PCB_LAYER_ID aActiveLayer, bool aVisibleOnly,
3315 bool aIgnoreLocked ) const
3316{
3317 FOOTPRINT* footprint = nullptr;
3318 FOOTPRINT* alt_footprint = nullptr;
3319 int min_dim = 0x7FFFFFFF;
3320 int alt_min_dim = 0x7FFFFFFF;
3321 bool current_layer_back = IsBackLayer( aActiveLayer );
3322
3323 for( FOOTPRINT* candidate : m_footprints )
3324 {
3325 // is the ref point within the footprint's bounds?
3326 if( !candidate->HitTest( aPosition ) )
3327 continue;
3328
3329 // if caller wants to ignore locked footprints, and this one is locked, skip it.
3330 if( aIgnoreLocked && candidate->IsLocked() )
3331 continue;
3332
3333 PCB_LAYER_ID layer = candidate->GetLayer();
3334
3335 // Filter non visible footprints if requested
3336 if( !aVisibleOnly || IsFootprintLayerVisible( layer ) )
3337 {
3338 BOX2I bb = candidate->GetBoundingBox( false );
3339
3340 int offx = bb.GetX() + bb.GetWidth() / 2;
3341 int offy = bb.GetY() + bb.GetHeight() / 2;
3342
3343 // off x & offy point to the middle of the box.
3344 int dist =
3345 ( aPosition.x - offx ) * ( aPosition.x - offx ) + ( aPosition.y - offy ) * ( aPosition.y - offy );
3346
3347 if( current_layer_back == IsBackLayer( layer ) )
3348 {
3349 if( dist <= min_dim )
3350 {
3351 // better footprint shown on the active side
3352 footprint = candidate;
3353 min_dim = dist;
3354 }
3355 }
3356 else if( aVisibleOnly && IsFootprintLayerVisible( layer ) )
3357 {
3358 if( dist <= alt_min_dim )
3359 {
3360 // better footprint shown on the other side
3361 alt_footprint = candidate;
3362 alt_min_dim = dist;
3363 }
3364 }
3365 }
3366 }
3367
3368 if( footprint )
3369 return footprint;
3370
3371 if( alt_footprint )
3372 return alt_footprint;
3373
3374 return nullptr;
3375}
3376
3377
3378std::list<ZONE*> BOARD::GetZoneList( bool aIncludeZonesInFootprints ) const
3379{
3380 std::list<ZONE*> zones;
3381
3382 for( ZONE* zone : Zones() )
3383 zones.push_back( zone );
3384
3385 if( aIncludeZonesInFootprints )
3386 {
3387 for( FOOTPRINT* footprint : m_footprints )
3388 {
3389 for( ZONE* zone : footprint->Zones() )
3390 zones.push_back( zone );
3391 }
3392 }
3393
3394 return zones;
3395}
3396
3397
3398ZONE* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, PCB_LAYER_ID aLayer, VECTOR2I aStartPointPosition,
3400{
3401 ZONE* new_area = new ZONE( this );
3402
3403 new_area->SetNetCode( aNetcode );
3404 new_area->SetLayer( aLayer );
3405
3406 m_zones.push_back( new_area );
3407
3408 new_area->SetHatchStyle( (ZONE_BORDER_DISPLAY_STYLE) aHatch );
3409
3410 // Add the first corner to the new zone
3411 new_area->AppendCorner( aStartPointPosition, -1 );
3412
3413 if( aNewZonesList )
3414 {
3415 ITEM_PICKER picker( nullptr, new_area, UNDO_REDO::NEWITEM );
3416 aNewZonesList->PushItem( picker );
3417 }
3418
3419 return new_area;
3420}
3421
3422
3423bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, bool aInferOutlineIfNecessary,
3424 OUTLINE_ERROR_HANDLER* aErrorHandler, bool aAllowUseArcsInPolygons,
3425 bool aIncludeNPTHAsOutlines )
3426{
3427 // max dist from one endPt to next startPt: use the current value
3428 int chainingEpsilon = GetOutlinesChainingEpsilon();
3429
3430 bool success = BuildBoardPolygonOutlines( this, aOutlines, GetDesignSettings().m_MaxError, chainingEpsilon,
3431 aInferOutlineIfNecessary, aErrorHandler, aAllowUseArcsInPolygons );
3432
3433 // Now subtract NPTH oval holes from outlines if required
3434 if( aIncludeNPTHAsOutlines )
3435 {
3436 for( FOOTPRINT* fp : Footprints() )
3437 {
3438 for( PAD* pad : fp->Pads() )
3439 {
3440 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
3441 continue;
3442
3443 SHAPE_POLY_SET hole;
3444 pad->TransformHoleToPolygon( hole, 0, pad->GetMaxError(), ERROR_INSIDE );
3445
3446 if( hole.OutlineCount() > 0 ) // can be not the case for malformed NPTH holes
3447 {
3448 // Issue #20159: BooleanSubtract correctly clips holes extending past board
3449 // edges (common with oval holes near irregular boards). O(n log n) per hole
3450 // vs O(1) for AddHole, but only used for 3D viewer generation, not a hot path.
3451 aOutlines.BooleanSubtract( hole );
3452 }
3453 }
3454 }
3455 }
3456
3457 // Make polygon strictly simple to avoid issues (especially in 3D viewer)
3458 aOutlines.Simplify();
3459
3460 return success;
3461}
3462
3463
3465{
3467 return static_cast<EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3468
3469 return static_cast<EMBEDDED_FILES*>( this );
3470}
3471
3472
3474{
3476 return static_cast<const EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3477
3478 return static_cast<const EMBEDDED_FILES*>( this );
3479}
3480
3481
3482std::set<KIFONT::OUTLINE_FONT*> BOARD::GetFonts() const
3483{
3485
3486 std::set<KIFONT::OUTLINE_FONT*> fonts;
3487
3488 for( BOARD_ITEM* item : Drawings() )
3489 {
3490 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
3491 {
3492 KIFONT::FONT* font = text->GetFont();
3493
3494 if( font && font->IsOutline() )
3495 {
3496 KIFONT::OUTLINE_FONT* outlineFont = static_cast<KIFONT::OUTLINE_FONT*>( font );
3497 PERMISSION permission = outlineFont->GetEmbeddingPermission();
3498
3499 if( permission == PERMISSION::EDITABLE || permission == PERMISSION::INSTALLABLE )
3500 fonts.insert( outlineFont );
3501 }
3502 }
3503 }
3504
3505 return fonts;
3506}
3507
3508
3510{
3511 for( KIFONT::OUTLINE_FONT* font : GetFonts() )
3512 {
3513 EMBEDDED_FILES::EMBEDDED_FILE* file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
3515 }
3516}
3517
3518
3519const std::vector<PAD*> BOARD::GetPads() const
3520{
3521 std::vector<PAD*> allPads;
3522
3523 for( FOOTPRINT* footprint : Footprints() )
3524 {
3525 for( PAD* pad : footprint->Pads() )
3526 allPads.push_back( pad );
3527 }
3528
3529 return allPads;
3530}
3531
3532
3533const std::vector<BOARD_CONNECTED_ITEM*> BOARD::AllConnectedItems()
3534{
3535 std::vector<BOARD_CONNECTED_ITEM*> items;
3536
3537 for( PCB_TRACK* track : Tracks() )
3538 items.push_back( track );
3539
3540 for( FOOTPRINT* footprint : Footprints() )
3541 {
3542 for( PAD* pad : footprint->Pads() )
3543 items.push_back( pad );
3544
3545 for( ZONE* zone : footprint->Zones() )
3546 items.push_back( zone );
3547
3548 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
3549 {
3550 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( dwg ) )
3551 items.push_back( bci );
3552 }
3553 }
3554
3555 for( ZONE* zone : Zones() )
3556 items.push_back( zone );
3557
3558 for( BOARD_ITEM* item : Drawings() )
3559 {
3560 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
3561 items.push_back( bci );
3562 }
3563
3564 return items;
3565}
3566
3567
3568void BOARD::MapNets( BOARD* aDestBoard )
3569{
3571 {
3572 NETINFO_ITEM* netInfo = aDestBoard->FindNet( item->GetNetname() );
3573
3574 if( netInfo )
3575 item->SetNet( netInfo );
3576 else
3577 {
3578 NETINFO_ITEM* newNet = new NETINFO_ITEM( aDestBoard, item->GetNetname() );
3579 aDestBoard->Add( newNet );
3580 item->SetNet( newNet );
3581 }
3582 }
3583}
3584
3585
3587{
3589 {
3590 if( FindNet( item->GetNetCode() ) == nullptr )
3591 item->SetNetCode( NETINFO_LIST::ORPHANED );
3592 }
3593}
3594
3595
3597{
3598 if( !alg::contains( m_listeners, aListener ) )
3599 m_listeners.push_back( aListener );
3600}
3601
3602
3604{
3605 auto i = std::find( m_listeners.begin(), m_listeners.end(), aListener );
3606
3607 if( i != m_listeners.end() )
3608 {
3609 std::iter_swap( i, m_listeners.end() - 1 );
3610 m_listeners.pop_back();
3611 }
3612}
3613
3614
3616{
3617 m_listeners.clear();
3618}
3619
3620
3625
3626
3627void BOARD::OnItemsChanged( std::vector<BOARD_ITEM*>& aItems )
3628{
3630}
3631
3632
3633void BOARD::OnItemsCompositeUpdate( std::vector<BOARD_ITEM*>& aAddedItems, std::vector<BOARD_ITEM*>& aRemovedItems,
3634 std::vector<BOARD_ITEM*>& aChangedItems )
3635{
3636 InvokeListeners( &BOARD_LISTENER::OnBoardCompositeUpdate, *this, aAddedItems, aRemovedItems, aChangedItems );
3637}
3638
3639
3644
3645
3652
3653
3661
3662
3663void BOARD::SetHighLightNet( int aNetCode, bool aMulti )
3664{
3665 bool already = m_highLight.m_netCodes.count( aNetCode );
3666
3667 if( !already )
3668 {
3669 if( !aMulti )
3670 m_highLight.m_netCodes.clear();
3671
3672 m_highLight.m_netCodes.insert( aNetCode );
3674 }
3675}
3676
3677
3678void BOARD::HighLightON( bool aValue )
3679{
3680 if( m_highLight.m_highLightOn != aValue )
3681 {
3682 m_highLight.m_highLightOn = aValue;
3684 }
3685}
3686
3687
3688wxString BOARD::GroupsSanityCheck( bool repair )
3689{
3690 if( repair )
3691 {
3692 while( GroupsSanityCheckInternal( repair ) != wxEmptyString )
3693 {
3694 };
3695
3696 return wxEmptyString;
3697 }
3698 return GroupsSanityCheckInternal( repair );
3699}
3700
3701
3703{
3704 // Cycle detection
3705 //
3706 // Each group has at most one parent group.
3707 // So we start at group 0 and traverse the parent chain, marking groups seen along the way.
3708 // If we ever see a group that we've already marked, that's a cycle.
3709 // If we reach the end of the chain, we know all groups in that chain are not part of any cycle.
3710 //
3711 // Algorithm below is linear in the # of groups because each group is visited only once.
3712 // There may be extra time taken due to the container access calls and iterators.
3713 //
3714 // Groups we know are cycle free
3715 std::unordered_set<EDA_GROUP*> knownCycleFreeGroups;
3716 // Groups in the current chain we're exploring.
3717 std::unordered_set<EDA_GROUP*> currentChainGroups;
3718 // Groups we haven't checked yet.
3719 std::unordered_set<EDA_GROUP*> toCheckGroups;
3720
3721 // Initialize set of groups and generators to check that could participate in a cycle.
3722 for( PCB_GROUP* group : Groups() )
3723 toCheckGroups.insert( group );
3724
3725 for( PCB_GENERATOR* gen : Generators() )
3726 toCheckGroups.insert( gen );
3727
3728 while( !toCheckGroups.empty() )
3729 {
3730 currentChainGroups.clear();
3731 EDA_GROUP* group = *toCheckGroups.begin();
3732
3733 while( true )
3734 {
3735 if( currentChainGroups.find( group ) != currentChainGroups.end() )
3736 {
3737 if( repair )
3738 Remove( static_cast<BOARD_ITEM*>( group->AsEdaItem() ) );
3739
3740 return "Cycle detected in group membership";
3741 }
3742 else if( knownCycleFreeGroups.find( group ) != knownCycleFreeGroups.end() )
3743 {
3744 // Parent is a group we know does not lead to a cycle
3745 break;
3746 }
3747
3748 currentChainGroups.insert( group );
3749 // We haven't visited currIdx yet, so it must be in toCheckGroups
3750 toCheckGroups.erase( group );
3751
3752 group = group->AsEdaItem()->GetParentGroup();
3753
3754 if( !group )
3755 {
3756 // end of chain and no cycles found in this chain
3757 break;
3758 }
3759 }
3760
3761 // No cycles found in chain, so add it to set of groups we know don't participate
3762 // in a cycle.
3763 knownCycleFreeGroups.insert( currentChainGroups.begin(), currentChainGroups.end() );
3764 }
3765
3766 // Success
3767 return "";
3768}
3769
3770
3772{
3773 if( a->Type() != b->Type() )
3774 return a->Type() < b->Type();
3775
3776 if( a->GetLayer() != b->GetLayer() )
3777 return a->GetLayer() < b->GetLayer();
3778
3779 if( a->GetPosition().x != b->GetPosition().x )
3780 return a->GetPosition().x < b->GetPosition().x;
3781
3782 if( a->GetPosition().y != b->GetPosition().y )
3783 return a->GetPosition().y < b->GetPosition().y;
3784
3785 if( a->m_Uuid != b->m_Uuid ) // shopuld be always the case foer valid boards
3786 return a->m_Uuid < b->m_Uuid;
3787
3788 return a < b;
3789}
3790
3791
3792bool BOARD::cmp_drawings::operator()( const BOARD_ITEM* aFirst, const BOARD_ITEM* aSecond ) const
3793{
3794 if( aFirst->Type() != aSecond->Type() )
3795 return aFirst->Type() < aSecond->Type();
3796
3797 if( aFirst->GetLayer() != aSecond->GetLayer() )
3798 return aFirst->GetLayer() < aSecond->GetLayer();
3799
3800 if( aFirst->Type() == PCB_SHAPE_T )
3801 {
3802 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aFirst );
3803 const PCB_SHAPE* other = static_cast<const PCB_SHAPE*>( aSecond );
3804 return shape->Compare( other ) < 0;
3805 }
3806 else if( aFirst->Type() == PCB_TEXT_T || aFirst->Type() == PCB_FIELD_T )
3807 {
3808 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aFirst );
3809 const PCB_TEXT* other = static_cast<const PCB_TEXT*>( aSecond );
3810 return text->Compare( other ) < 0;
3811 }
3812 else if( aFirst->Type() == PCB_TEXTBOX_T )
3813 {
3814 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( aFirst );
3815 const PCB_TEXTBOX* other = static_cast<const PCB_TEXTBOX*>( aSecond );
3816
3817 int shapeCmp = textbox->PCB_SHAPE::Compare( other );
3818
3819 if( shapeCmp != 0 )
3820 return shapeCmp < 0;
3821
3822 return textbox->EDA_TEXT::Compare( other ) < 0;
3823 }
3824 else if( aFirst->Type() == PCB_TABLE_T )
3825 {
3826 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( aFirst );
3827 const PCB_TABLE* other = static_cast<const PCB_TABLE*>( aSecond );
3828
3829 return PCB_TABLE::Compare( table, other ) < 0;
3830 }
3831 else if( aFirst->Type() == PCB_BARCODE_T )
3832 {
3833 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( aFirst );
3834 const PCB_BARCODE* other = static_cast<const PCB_BARCODE*>( aSecond );
3835
3836 return PCB_BARCODE::Compare( barcode, other ) < 0;
3837 }
3838
3839 return aFirst->m_Uuid < aSecond->m_Uuid;
3840}
3841
3842
3844 KIGFX::RENDER_SETTINGS* aRenderSettings ) const
3845{
3846 int maxError = GetDesignSettings().m_MaxError;
3847
3848 // convert tracks and vias:
3849 for( const PCB_TRACK* track : m_tracks )
3850 {
3851 if( !track->IsOnLayer( aLayer ) )
3852 continue;
3853
3854 track->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3855 }
3856
3857 // convert pads and other copper items in footprints
3858 for( const FOOTPRINT* footprint : m_footprints )
3859 {
3860 footprint->TransformPadsToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3861
3862 footprint->TransformFPShapesToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE, true, /* include text */
3863 true, /* include shapes */
3864 false /* include private items */ );
3865
3866 for( const ZONE* zone : footprint->Zones() )
3867 {
3868 if( zone->GetLayerSet().test( aLayer ) )
3869 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
3870 }
3871 }
3872
3873 // convert copper zones
3874 for( const ZONE* zone : Zones() )
3875 {
3876 if( zone->GetLayerSet().test( aLayer ) )
3877 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
3878 }
3879
3880 // convert graphic items on copper layers (texts)
3881 for( const BOARD_ITEM* item : m_drawings )
3882 {
3883 if( !item->IsOnLayer( aLayer ) )
3884 continue;
3885
3886 switch( item->Type() )
3887 {
3888 case PCB_SHAPE_T:
3889 {
3890 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( item );
3891 shape->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3892 break;
3893 }
3894
3895 case PCB_BARCODE_T:
3896 {
3897 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( item );
3898 barcode->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3899 break;
3900 }
3901
3902 case PCB_FIELD_T:
3903 case PCB_TEXT_T:
3904 {
3905 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
3906 text->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3907 break;
3908 }
3909
3910 case PCB_TEXTBOX_T:
3911 {
3912 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
3913 // border
3914 textbox->PCB_SHAPE::TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3915 // text
3916 textbox->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3917 break;
3918 }
3919
3920 case PCB_TABLE_T:
3921 {
3922 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
3923 table->TransformGraphicItemsToPolySet( aOutlines, maxError, ERROR_INSIDE, aRenderSettings );
3924 break;
3925 }
3926
3927 case PCB_DIM_ALIGNED_T:
3928 case PCB_DIM_CENTER_T:
3929 case PCB_DIM_RADIAL_T:
3931 case PCB_DIM_LEADER_T:
3932 {
3933 const PCB_DIMENSION_BASE* dim = static_cast<const PCB_DIMENSION_BASE*>( item );
3934 dim->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3935 dim->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3936 break;
3937 }
3938
3939 default: break;
3940 }
3941 }
3942}
3943
3944
3946{
3947 BOARD_ITEM_SET items;
3948
3949 std::copy( m_tracks.begin(), m_tracks.end(), std::inserter( items, items.end() ) );
3950 std::copy( m_zones.begin(), m_zones.end(), std::inserter( items, items.end() ) );
3951 std::copy( m_generators.begin(), m_generators.end(), std::inserter( items, items.end() ) );
3952 std::copy( m_footprints.begin(), m_footprints.end(), std::inserter( items, items.end() ) );
3953 std::copy( m_drawings.begin(), m_drawings.end(), std::inserter( items, items.end() ) );
3954 std::copy( m_markers.begin(), m_markers.end(), std::inserter( items, items.end() ) );
3955 std::copy( m_groups.begin(), m_groups.end(), std::inserter( items, items.end() ) );
3956 std::copy( m_points.begin(), m_points.end(), std::inserter( items, items.end() ) );
3957
3958 return items;
3959}
3960
3961
3963{
3964 // Delegate to the non-const overload via a single safe const_cast on the
3965 // *this pointer. GetItemSet doesn't mutate the BOARD; the non-const
3966 // signature is historical.
3967 return const_cast<BOARD*>( this )->GetItemSet();
3968}
3969
3970
3971bool BOARD::operator==( const BOARD_ITEM& aItem ) const
3972{
3973 if( aItem.Type() != Type() )
3974 return false;
3975
3976 const BOARD& other = static_cast<const BOARD&>( aItem );
3977
3978 if( *m_designSettings != *other.m_designSettings )
3979 return false;
3980
3981 if( m_NetInfo.GetNetCount() != other.m_NetInfo.GetNetCount() )
3982 return false;
3983
3984 const NETNAMES_MAP& thisNetNames = m_NetInfo.NetsByName();
3985 const NETNAMES_MAP& otherNetNames = other.m_NetInfo.NetsByName();
3986
3987 for( auto it1 = thisNetNames.begin(), it2 = otherNetNames.begin();
3988 it1 != thisNetNames.end() && it2 != otherNetNames.end(); ++it1, ++it2 )
3989 {
3990 // We only compare the names in order here, not the index values
3991 // as the index values are auto-generated and the names are not.
3992 if( it1->first != it2->first )
3993 return false;
3994 }
3995
3996 if( m_properties.size() != other.m_properties.size() )
3997 return false;
3998
3999 for( auto it1 = m_properties.begin(), it2 = other.m_properties.begin();
4000 it1 != m_properties.end() && it2 != other.m_properties.end(); ++it1, ++it2 )
4001 {
4002 if( *it1 != *it2 )
4003 return false;
4004 }
4005
4006 if( m_paper.GetCustomHeightMils() != other.m_paper.GetCustomHeightMils() )
4007 return false;
4008
4009 if( m_paper.GetCustomWidthMils() != other.m_paper.GetCustomWidthMils() )
4010 return false;
4011
4012 if( m_paper.GetSizeMils() != other.m_paper.GetSizeMils() )
4013 return false;
4014
4015 if( m_paper.GetPaperId() != other.m_paper.GetPaperId() )
4016 return false;
4017
4018 if( m_paper.GetWxOrientation() != other.m_paper.GetWxOrientation() )
4019 return false;
4020
4021 for( int ii = 0; !m_titles.GetComment( ii ).empty(); ++ii )
4022 {
4023 if( m_titles.GetComment( ii ) != other.m_titles.GetComment( ii ) )
4024 return false;
4025 }
4026
4027 wxArrayString ourVars;
4028 m_titles.GetContextualTextVars( &ourVars );
4029
4030 wxArrayString otherVars;
4031 other.m_titles.GetContextualTextVars( &otherVars );
4032
4033 if( ourVars != otherVars )
4034 return false;
4035
4036 return true;
4037}
4038
4040{
4041 m_boardOutline->GetOutline().RemoveAllContours();
4042
4043 bool has_outline = GetBoardPolygonOutlines( m_boardOutline->GetOutline(), false );
4044
4045 if( has_outline )
4046 m_boardOutline->GetOutline().Fracture();
4047}
4048
4049
4051{
4052 // return the number of PTH with Press-Fit fabr attribute
4053 int count = 0;
4054
4055 for( FOOTPRINT* footprint : Footprints() )
4056 {
4057 for( PAD* pad : footprint->Pads() )
4058 {
4059 if( pad->GetProperty() == PAD_PROP::PRESSFIT )
4060 count++;
4061 }
4062 }
4063
4064 return count;
4065}
4066
4067
4069{
4070 // @return the number of PTH with Castellated fabr attribute
4071 int count = 0;
4072
4073 for( FOOTPRINT* footprint : Footprints() )
4074 {
4075 for( PAD* pad : footprint->Pads() )
4076 {
4077 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
4078 count++;
4079 }
4080 }
4081
4082 return count;
4083}
4084
4085
4086void BOARD::SaveToHistory( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
4087{
4088 // The board can transiently have no project (e.g. during a non-KiCad import while the old
4089 // project is being unloaded and the new one has not yet been linked). The autosave timer can
4090 // fire in that window, so guard against a null project here rather than dereferencing it.
4092
4093 if( !project )
4094 return;
4095
4096 wxString projPath = project->GetProjectPath();
4097
4098 if( projPath.IsEmpty() )
4099 return;
4100
4101 // Verify we're saving for the correct project
4102 if( !projPath.IsSameAs( aProjectPath ) )
4103 {
4104 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - project path mismatch: %s vs %s" ), projPath,
4105 aProjectPath );
4106 return;
4107 }
4108
4109 wxString boardPath = GetFileName();
4110
4111 if( boardPath.IsEmpty() )
4112 return; // unsaved board
4113
4114 // Derive relative path from project root.
4115 if( !boardPath.StartsWith( projPath ) )
4116 {
4117 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - board not under project: %s" ), boardPath );
4118 return; // not under project
4119 }
4120
4121 wxString rel = boardPath.Mid( projPath.length() );
4122
4123 try
4124 {
4126 STRING_FORMATTER formatter;
4127
4128 pi.FormatBoardToFormatter( &formatter, this, nullptr );
4129
4130 HISTORY_FILE_DATA entry;
4131 entry.relativePath = rel;
4132 entry.content = std::move( formatter.MutableString() );
4133 entry.prettify = true;
4134
4135 if( ADVANCED_CFG::GetCfg().m_CompactSave )
4136 entry.formatMode = KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
4137
4138 aFileData.push_back( std::move( entry ) );
4139
4140 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialized %zu bytes for '%s'" ),
4141 aFileData.back().content.size(), rel );
4142 }
4143 catch( const IO_ERROR& ioe )
4144 {
4145 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialize failed: %s" ), wxString::FromUTF8( ioe.What() ) );
4146 }
4147}
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:3254
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:2867
#define DEFAULT_CHAINING_EPSILON_MM
Definition board.h:88
BOARD_USE
Flags to specify how the board is being used.
Definition board.h:363
@ NORMAL
Definition board.h:364
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition board.h:236
@ LT_POWER
Definition board.h:239
@ LT_FRONT
Definition board.h:243
@ LT_MIXED
Definition board.h:240
@ LT_BACK
Definition board.h:244
@ LT_UNDEFINED
Definition board.h:237
@ LT_JUMPER
Definition board.h:241
@ LT_AUX
Definition board.h:242
@ LT_SIGNAL
Definition board.h:238
std::set< BOARD_ITEM *, CompareByUuid > BOARD_ITEM_SET
Set of BOARD_ITEMs ordered by UUID.
Definition board.h:357
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & reset(size_t pos)
Definition base_set.h:143
BASE_SET & set(size_t pos)
Definition base_set.h:116
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Container for design settings for a BOARD object.
void UseCustomTrackViaSize(bool aEnabled)
Enables/disables custom track/via size settings.
void SetCustomDiffPairWidth(int aWidth)
Sets custom track width for differential pairs (i.e.
void SetEnabledLayers(const LSET &aMask)
Change the bit-mask of enabled layers to aMask.
std::shared_ptr< NET_SETTINGS > m_NetSettings
void SetCustomTrackWidth(int aWidth)
Sets custom width for track (i.e.
void SetCustomViaSize(int aSize)
Set custom size for via diameter (i.e.
const LSET & GetEnabledLayers() const
Return a bit-mask of all the layers that are enabled.
void SetCustomDiffPairGap(int aGap)
Sets custom gap for differential pairs (i.e.
bool IsLayerEnabled(PCB_LAYER_ID aLayerId) const
Test whether a given layer aLayerId is enabled.
void SetUserDefinedLayerCount(int aNewLayerCount)
Set the number of user defined layers to aNewLayerCount.
BOARD_STACKUP & GetStackupDescriptor()
void SetCustomViaDrill(int aDrill)
Sets custom size for via drill (i.e.
void SetCopperLayerCount(int aNewLayerCount)
Set the copper layer count to aNewLayerCount.
void SetCustomDiffPairViaGap(int aGap)
Sets custom via gap for differential pairs (i.e.
BOARD_ITEM_CONTAINER(BOARD_ITEM *aParent, KICAD_T aType)
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:342
virtual void OnBoardRatsnestChanged(BOARD &aBoard)
Definition board.h:346
virtual void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:339
virtual void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:343
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:340
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem)
Definition board.h:338
virtual void OnBoardHighlightNetChanged(BOARD &aBoard)
Definition board.h:345
virtual void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:341
virtual void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems)
Definition board.h:347
virtual void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems)
Definition board.h:344
Manage layers needed to make a physical board.
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &scanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition board.cpp:2557
ZONE * m_SolderMaskBridges
Definition board.h:1707
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:3278
std::map< ZONE *, std::map< PCB_LAYER_ID, ISOLATED_ISLANDS > > m_ZoneIsolatedIslandsMap
Definition board.h:1708
PCB_LAYER_ID GetCopperLayerStackMaxId() const
Definition board.cpp:1009
GENERATORS m_generators
Definition board.h:1748
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:3621
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition board.h:501
bool IsFootprintHolder() const
Find out if the board is being used to hold a single footprint for editing/viewing.
Definition board.h:403
PAD * GetPad(const VECTOR2I &aPosition, const LSET &aLayerMask) const
Find a pad aPosition on aLayer.
Definition board.cpp:3128
SHARDED_CACHE< PTR_PTR_LAYER_CACHE_KEY, bool > m_IntersectsAreaCache
Definition board.h:1674
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:1766
void CacheItemById(BOARD_ITEM *aItem) const
Add an item to the item-by-id cache.
Definition board.cpp:2037
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsCourtyardResultCache
Definition board.h:1676
std::unordered_map< const BOARD_ITEM *, wxString > m_ItemNetclassCache
Definition board.h:1688
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3464
SHARDED_CACHE< PTR_PTR_LAYER_CACHE_KEY, bool > m_EnclosedByAreaCache
Definition board.h:1675
int m_fileFormatVersionAtLoad
Definition board.h:1763
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition board.cpp:2775
void UncacheItemById(const KIID &aId) const
Remove an item from the item-by-id cache.
Definition board.cpp:2066
void SetCurrentVariant(const wxString &aVariant)
Definition board.cpp:2880
std::vector< ZONE * > m_DRCCopperZones
Definition board.h:1703
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:1346
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_EnclosedByAreaResultCache
Definition board.h:1680
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:3568
TITLE_BLOCK m_titles
Definition board.h:1770
GAL_SET m_LegacyVisibleItems
Definition board.h:498
std::vector< wxString > m_variantNames
Definition board.h:1777
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1524
wxArrayString GetVariantNamesForUI() const
Return the variant names for UI display.
Definition board.cpp:3035
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:434
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition board.h:999
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:3533
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:1731
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:3289
std::set< wxString > GetNetClassAssignmentCandidates() const
Return the set of netname candidates for netclass assignment.
Definition board.cpp:2846
BOARD_USE m_boardUse
What is this board being used for.
Definition board.h:1734
PAGE_INFO m_paper
Definition board.h:1769
void RemoveAllListeners()
Remove all listeners.
Definition board.cpp:3615
SHARDED_CACHE< PTR_PTR_CACHE_KEY, bool > m_IntersectsBCourtyardCache
Definition board.h:1673
FOOTPRINTS m_footprints
Definition board.h:1744
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:1790
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:3843
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:3596
void UpdateUserUnits(BOARD_ITEM *aItem, KIGFX::VIEW *aView)
Update any references within aItem (or its descendants) to the user units.
Definition board.cpp:1814
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:466
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:3663
void CompileRatsnest()
Rebuild the entire board ratsnest.
Definition board.cpp:3646
HIGH_LIGHT_INFO m_highLight
Definition board.h:1760
std::map< wxString, wxString > m_variantDescriptions
Definition board.h:1778
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:2708
EDA_UNITS m_userUnits
Definition board.h:1773
void UpdateBoardOutline()
Definition board.cpp:4039
const ZONES & Zones() const
Definition board.h:425
void BulkRemoveStaleTeardrops(BOARD_COMMIT &aCommit)
Remove all teardrop zones with the STRUCT_DELETED flag set.
Definition board.cpp:1476
void DeleteVariant(const wxString &aVariantName)
Definition board.cpp:2923
void InvokeListeners(Func &&aFunc, Args &&... args)
Definition board.h:1718
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:3586
void InitializeClearanceCache()
Initialize the clearance cache for all board items.
Definition board.cpp:1168
EMBEDDED_FILES * m_embeddedFilesDelegate
Definition board.h:1806
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:3398
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:461
~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:4086
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:1743
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:3633
int SetAreasNetCodesFromNetNames()
Set the .m_NetCode member of all copper areas, according to the area Net Name The SetNetCodesFromNetN...
Definition board.cpp:3094
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:3055
void ResetNetHighLight()
Reset all high light data to the init state.
Definition board.cpp:3654
SHARDED_CACHE< PTR_PTR_CACHE_KEY, bool > m_IntersectsCourtyardCache
Definition board.h:1671
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:3378
bool ResolveTextVar(wxString *token, int aDepth) const
Definition board.cpp:563
const MARKERS & Markers() const
Definition board.h:440
void UncacheChildrenById(const BOARD_ITEM *aParent)
Definition board.h:1621
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:3519
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:1814
TITLE_BLOCK & GetTitleBlock()
Definition board.h:903
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:1747
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:2814
std::unordered_map< const BOARD_ITEM *, KIID > m_cachedIdByItem
Definition board.h:1756
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:1761
NETINFO_LIST m_NetInfo
Definition board.h:1798
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition board.h:497
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:2906
void AddVariant(const wxString &aVariantName)
Definition board.cpp:2912
int GetCopperLayerCount() const
Definition board.cpp:985
std::vector< BOARD_LISTENER * > m_listeners
Definition board.h:1800
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:1728
void IncrementTimeStamp()
Definition board.cpp:283
int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet)
Fetch the coupled netname for a given net.
Definition board.cpp:2727
wxString GetUniqueZoneName(const wxString &aBaseName, const ZONE *aExclude=nullptr) const
Return a name based on aBaseName that is not used by any other zone or rule area on the board.
Definition board.cpp:1295
PCB_POINTS m_points
Definition board.h:1750
std::unique_ptr< LENGTH_DELAY_CALCULATION > m_lengthDelayCalc
Definition board.h:1809
const FOOTPRINTS & Footprints() const
Definition board.h:421
std::shared_ptr< CONNECTIVITY_DATA > m_connectivity
Definition board.h:1767
std::set< KIFONT::OUTLINE_FONT * > GetFonts() const override
Get the list of all outline fonts used in the board.
Definition board.cpp:3482
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:1589
const BOARD_ITEM_SET GetItemSet()
Collect every owned item (tracks, zones, generators, footprints, drawings, markers,...
Definition board.cpp:3945
const TRACKS & Tracks() const
Definition board.h:419
int m_DRCMaxPhysicalClearance
Definition board.h:1706
FOOTPRINT * FindFootprintByPath(const KIID_PATH &aPath) const
Search for a FOOTPRINT within this board with the given path.
Definition board.cpp:2802
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:1470
std::unordered_map< wxString, LSET > m_LayerExpressionCache
Definition board.h:1682
BOARD_ITEM * GetCachedItemById(const KIID &aId) const
Return a cached item for aId if the entry is still self-consistent.
Definition board.cpp:2020
bool m_embedFonts
Definition board.h:1802
wxString GroupsSanityCheckInternal(bool repair)
Definition board.cpp:3702
std::shared_ptr< const FOOTPRINT_COURTYARD_INDEX > m_footprintCourtyardIndex
Definition board.h:1699
void OnRatsnestChanged()
Notify the board and its listeners that the ratsnest has been recomputed.
Definition board.cpp:3640
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource) const
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition board.cpp:2280
wxString GetClass() const override
Return the class name.
Definition board.h:1264
std::unique_ptr< COMPONENT_CLASS_MANAGER > m_componentClassManager
Definition board.h:1808
SHARDED_CACHE< PTR_PTR_CACHE_KEY, bool > m_IntersectsFCourtyardCache
Definition board.h:1672
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:3423
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition board.h:505
void SetCopperLayerCount(int aCount)
Definition board.cpp:991
std::unordered_map< const ZONE *, BOX2I > m_ZoneBBoxCache
Definition board.h:1685
std::unordered_map< const ZONE *, SHAPE_POLY_SET > m_DeflatedZoneOutlineCache
Definition board.h:1696
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsFCourtyardResultCache
Definition board.h:1677
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:1772
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:3314
bool HasItemsOnLayer(PCB_LAYER_ID aLayer)
Definition board.cpp:1682
const wxString & GetFileName() const
Definition board.h:410
bool operator==(const BOARD_ITEM &aOther) const override
Definition board.cpp:3971
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:4068
wxString GetVariantDescription(const wxString &aVariantName) const
Definition board.cpp:2999
FOOTPRINT * FindFootprintByReference(const wxString &aReference) const
Search for a FOOTPRINT within this board with the given reference designator.
Definition board.cpp:2790
unsigned GetNodesCount(int aNet=-1) const
Definition board.cpp:2433
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Definition board.cpp:2238
SHARDED_CACHE< ITEM_FIELD_CACHE_KEY, wxString > m_ItemFieldCache
Definition board.h:1681
std::map< PCB_LAYER_ID, std::vector< ZONE * > > m_DRCCopperZonesByLayer
Definition board.h:1704
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:1684
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:1737
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:1885
std::map< int, LAYER > m_layers
Definition board.h:1758
wxString GetCurrentVariant() const
Definition board.h:469
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:949
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:3263
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:1679
int m_DRCMaxClearance
Definition board.h:1705
void ClearProject()
Definition board.cpp:252
void ReplaceNetChainTerminalPad(const wxString &aNetChain, const KIID &aPrev, const KIID &aNew)
Definition board.cpp:2826
void UncacheItemByPtr(const BOARD_ITEM *aItem)
Remove every cache entry that still points to aItem.
Definition board.cpp:2116
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition board.h:1683
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:1464
wxString m_currentVariant
Definition board.h:1776
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:1873
PROJECT * GetProject() const
Definition board.h:658
bool IsEmpty() const
Definition board.cpp:662
int GetPadWithPressFitAttrCount()
Definition board.cpp:4050
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:2519
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:3688
void RenameVariant(const wxString &aOldName, const wxString &aNewName)
Definition board.cpp:2951
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
std::vector< ZONE * > m_DRCZones
Definition board.h:1702
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:2360
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:2139
int RepairDuplicateItemUuids()
Rebind duplicate attached-item UUIDs so each live board item has a unique ID.
Definition board.cpp:2165
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition board.cpp:2860
std::unordered_map< KIID, BOARD_ITEM * > m_itemByIdCache
Definition board.h:1755
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
Definition board.cpp:3603
std::shared_mutex m_CachesMutex
Definition board.h:1668
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aPhysicalLayersOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition board.cpp:2450
std::shared_ptr< const FOOTPRINT_COURTYARD_INDEX > GetFootprintCourtyardIndex()
Return a spatial index of footprint courtyards, building it on first use.
Definition board.cpp:336
std::atomic< int > m_timeStamp
Definition board.h:1735
bool SynchronizeComponentClasses(const std::unordered_set< wxString > &aNewSheetPaths) const
Copy component class / component class generator information from the project settings.
Definition board.cpp:3085
BOARD_ITEM * CacheAndReturnItemById(const KIID &aId, BOARD_ITEM *aItem) const
Definition board.cpp:2085
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition board.cpp:1836
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition board.cpp:1493
std::unordered_map< wxString, std::vector< ZONE * > > m_ZonesByNameCache
Definition board.h:1692
GROUPS m_groups
Definition board.h:1746
MARKERS m_markers
Definition board.h:1742
std::optional< int > m_maxClearanceValue
Definition board.h:1686
void HighLightON(bool aValue=true)
Enable or disable net highlighting.
Definition board.cpp:3678
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:1593
void SynchronizeTuningProfileProperties()
Ensure that all time domain properties providers are in sync with current settings.
Definition board.cpp:3049
TRACKS m_tracks
Definition board.h:1745
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:1897
bool m_LegacyCopperEdgeClearanceLoaded
Definition board.h:502
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:3627
SHARDED_CACHE< ITEM_SELECTOR_LAYER_CACHE_KEY, bool > m_IntersectsBCourtyardResultCache
Definition board.h:1678
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:642
VECTOR2I GetPosition() const override
Definition board.cpp:668
void SetVariantDescription(const wxString &aVariantName, const wxString &aDescription)
Definition board.cpp:3018
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:3509
PCB_BOARD_OUTLINE * m_boardOutline
Definition board.h:1749
void SetUserDefinedLayerCount(int aCount)
Definition board.cpp:1004
const DRAWINGS & Drawings() const
Definition board.h:423
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition board.cpp:1808
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.
const std::map< wxString, std::shared_ptr< EMBEDDED_FILE > > & EmbeddedFileMap() const
Provide an iterable view of the file collection.
EMBEDDED_FILES()=default
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
Helper for storing and iterating over GAL_LAYER_IDs.
Definition layer_ids.h: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:619
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:686
bool SetNetCode(int aNetCode, bool aNoAssert) override
Override that clamps the netcode to 0 when this zone is in copper-thieving fill mode.
Definition zone.cpp:601
const wxString & GetZoneName() const
Definition zone.h:160
bool IsTeardropArea() const
Definition zone.h:788
bool AppendCorner(VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition zone.cpp:1410
#define EXCLUDE_ZONES
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, bool aInferOutlineIfNecessary, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const VECTOR2I &pt)> OUTLINE_ERROR_HANDLER
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
RECURSE_MODE
Definition eda_item.h:48
@ RECURSE
Definition eda_item.h:49
INSPECT_RESULT
Definition eda_item.h:42
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:89
std::function< INSPECT_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Used to inspect and possibly collect the (search) results of iterating over a list or tree of KICAD_T...
Definition eda_item.h:86
#define STRUCT_DELETED
flag indication structures to be erased
EDA_UNITS
Definition eda_units.h:44
static const std::string DesignRulesFileExtension
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
KIID niluuid(0)
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h: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:3792
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition board.cpp:3771
std::vector< char > decompressedData
Data produced by a registered saver on the UI thread, consumed by either the background local-history...
std::string content
Serialized content (mutually exclusive with sourcePath)
KICAD_FORMAT::FORMAT_MODE formatMode
wxString relativePath
Destination path relative to the project root.
Container to hold information pertinent to a layer of a BOARD.
Definition board.h:252
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition board.cpp: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.