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