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