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