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