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