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( IsFootprintHolder() )
1989 return aItem;
1990
1991 if( auto prev = m_cachedIdByItem.find( aItem );
1992 prev != m_cachedIdByItem.end() && prev->second != aId )
1993 {
1994 auto prevIt = m_itemByIdCache.find( prev->second );
1995
1996 if( prevIt != m_itemByIdCache.end() && prevIt->second == aItem )
1997 m_itemByIdCache.erase( prevIt );
1998 }
1999
2000 if( auto existing = m_itemByIdCache.find( aId );
2001 existing != m_itemByIdCache.end() && existing->second != aItem )
2002 {
2003 if( auto prev = m_cachedIdByItem.find( existing->second );
2004 prev != m_cachedIdByItem.end() && prev->second == aId )
2005 {
2006 m_cachedIdByItem.erase( prev );
2007 }
2008 }
2009
2010 m_itemByIdCache.insert_or_assign( aId, aItem );
2011 m_cachedIdByItem.insert_or_assign( aItem, aId );
2012
2013 return aItem;
2014}
2015
2016
2018{
2019 if( auto cached = m_cachedIdByItem.find( aItem ); cached != m_cachedIdByItem.end() )
2020 {
2021 auto it = m_itemByIdCache.find( cached->second );
2022
2023 if( it != m_itemByIdCache.end() && it->second == aItem )
2024 m_itemByIdCache.erase( it );
2025
2026 m_cachedIdByItem.erase( cached );
2027 return;
2028 }
2029
2030 for( auto it = m_itemByIdCache.begin(); it != m_itemByIdCache.end(); )
2031 {
2032 if( it->second == aItem )
2033 it = m_itemByIdCache.erase( it );
2034 else
2035 ++it;
2036 }
2037}
2038
2039
2040void BOARD::RebindItemUuid( BOARD_ITEM* aItem, const KIID& aNewId )
2041{
2042 wxCHECK_RET( aItem, "BOARD::RebindItemUuid() requires a valid item" );
2043
2044 if( IsFootprintHolder() )
2045 return;
2046
2047 if( aItem->m_Uuid == aNewId )
2048 {
2049 CacheAndReturnItemById( aNewId, aItem );
2050 return;
2051 }
2052
2053 if( BOARD_ITEM* existing = GetCachedItemById( aNewId ); existing && existing != aItem )
2054 {
2055 wxFAIL_MSG( wxString::Format( "BOARD::RebindItemUuid() duplicate target UUID: %s",
2056 aNewId.AsString() ) );
2057 return;
2058 }
2059
2060 UncacheItemByPtr( aItem );
2061 aItem->SetUuidDirect( aNewId );
2062 CacheAndReturnItemById( aNewId, aItem );
2063}
2064
2065
2067{
2068 std::set<KIID> ids;
2069 int duplicates = 0;
2070
2071 auto processItem =
2072 [&]( BOARD_ITEM* aItem )
2073 {
2074 wxCHECK2( aItem, return );
2075
2076 if( ids.count( aItem->m_Uuid ) )
2077 {
2078 duplicates++;
2079 RebindItemUuid( aItem, KIID() );
2080 }
2081
2082 ids.insert( aItem->m_Uuid );
2083 };
2084
2085 // Footprint IDs are the most important, so give them the first crack at "claiming" a
2086 // particular KIID.
2087 for( FOOTPRINT* footprint : Footprints() )
2088 processItem( footprint );
2089
2090 // After that the principal use is for DRC marker pointers, which are most likely to pads
2091 // or tracks.
2092 for( FOOTPRINT* footprint : Footprints() )
2093 {
2094 for( PAD* pad : footprint->Pads() )
2095 processItem( pad );
2096 }
2097
2098 for( PCB_TRACK* track : Tracks() )
2099 processItem( track );
2100
2101 // From here out I don't think order matters much.
2102 for( FOOTPRINT* footprint : Footprints() )
2103 {
2104 processItem( &footprint->Reference() );
2105 processItem( &footprint->Value() );
2106
2107 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2108 processItem( item );
2109
2110 for( ZONE* zone : footprint->Zones() )
2111 processItem( zone );
2112
2113 for( PCB_GROUP* group : footprint->Groups() )
2114 processItem( group );
2115 }
2116
2117 // Everything owned by the board not handled above.
2118 for( BOARD_ITEM* item : GetItemSet() )
2119 {
2120 // Top-level footprints and tracks were handled above.
2121 switch( item->Type() )
2122 {
2123 case PCB_FOOTPRINT_T:
2124 case PCB_TRACE_T:
2125 case PCB_ARC_T:
2126 case PCB_VIA_T:
2127 break;
2128
2129 default:
2130 processItem( item );
2131 break;
2132 }
2133 }
2134
2135 return duplicates;
2136}
2137
2138
2139void BOARD::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
2140{
2141 // the board itself
2142 aMap[m_Uuid] = this;
2143
2144 for( PCB_TRACK* track : Tracks() )
2145 aMap[track->m_Uuid] = track;
2146
2147 for( FOOTPRINT* footprint : Footprints() )
2148 {
2149 aMap[footprint->m_Uuid] = footprint;
2150
2151 for( PAD* pad : footprint->Pads() )
2152 aMap[pad->m_Uuid] = pad;
2153
2154 aMap[footprint->Reference().m_Uuid] = &footprint->Reference();
2155 aMap[footprint->Value().m_Uuid] = &footprint->Value();
2156
2157 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2158 aMap[drawing->m_Uuid] = drawing;
2159 }
2160
2161 for( ZONE* zone : Zones() )
2162 aMap[zone->m_Uuid] = zone;
2163
2164 for( BOARD_ITEM* drawing : Drawings() )
2165 aMap[drawing->m_Uuid] = drawing;
2166
2167 for( PCB_MARKER* marker : m_markers )
2168 aMap[marker->m_Uuid] = marker;
2169
2170 for( PCB_GROUP* group : m_groups )
2171 aMap[group->m_Uuid] = group;
2172
2173 for( PCB_POINT* point : m_points )
2174 aMap[point->m_Uuid] = point;
2175
2176 for( PCB_GENERATOR* generator : m_generators )
2177 aMap[generator->m_Uuid] = generator;
2178}
2179
2180
2181wxString BOARD::ConvertCrossReferencesToKIIDs( const wxString& aSource ) const
2182{
2183 wxString newbuf;
2184 size_t sourceLen = aSource.length();
2185
2186 for( size_t i = 0; i < sourceLen; ++i )
2187 {
2188 // Check for escaped expressions: \${ or \@{
2189 // These should be copied verbatim without any ref→KIID conversion
2190 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2191 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2192 {
2193 // Copy the escape sequence and the entire escaped expression
2194 newbuf.append( aSource[i] ); // backslash
2195 newbuf.append( aSource[i + 1] ); // $ or @
2196 newbuf.append( aSource[i + 2] ); // {
2197 i += 2;
2198
2199 // Find and copy everything until the matching closing brace
2200 int braceDepth = 1;
2201 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2202 {
2203 if( aSource[i] == '{' )
2204 braceDepth++;
2205 else if( aSource[i] == '}' )
2206 braceDepth--;
2207
2208 newbuf.append( aSource[i] );
2209 }
2210 i--; // Back up one since the for loop will increment
2211 continue;
2212 }
2213
2214 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2215 {
2216 wxString token;
2217 bool isCrossRef = false;
2218
2219 for( i = i + 2; i < sourceLen; ++i )
2220 {
2221 if( aSource[i] == '}' )
2222 break;
2223
2224 if( aSource[i] == ':' )
2225 isCrossRef = true;
2226
2227 token.append( aSource[i] );
2228 }
2229
2230 if( isCrossRef )
2231 {
2232 wxString remainder;
2233 wxString ref = token.BeforeFirst( ':', &remainder );
2234
2235 for( const FOOTPRINT* footprint : Footprints() )
2236 {
2237 if( footprint->GetReference().CmpNoCase( ref ) == 0 )
2238 {
2239 wxString test( remainder );
2240
2241 if( footprint->ResolveTextVar( &test ) )
2242 token = footprint->m_Uuid.AsString() + wxT( ":" ) + remainder;
2243
2244 break;
2245 }
2246 }
2247 }
2248
2249 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2250 }
2251 else
2252 {
2253 newbuf.append( aSource[i] );
2254 }
2255 }
2256
2257 return newbuf;
2258}
2259
2260
2261wxString BOARD::ConvertKIIDsToCrossReferences( const wxString& aSource ) const
2262{
2263 wxString newbuf;
2264 size_t sourceLen = aSource.length();
2265
2266 for( size_t i = 0; i < sourceLen; ++i )
2267 {
2268 // Check for escaped expressions: \${ or \@{
2269 // These should be copied verbatim without any KIID→ref conversion
2270 if( aSource[i] == '\\' && i + 2 < sourceLen && aSource[i + 2] == '{' &&
2271 ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) )
2272 {
2273 // Copy the escape sequence and the entire escaped expression
2274 newbuf.append( aSource[i] ); // backslash
2275 newbuf.append( aSource[i + 1] ); // $ or @
2276 newbuf.append( aSource[i + 2] ); // {
2277 i += 2;
2278
2279 // Find and copy everything until the matching closing brace
2280 int braceDepth = 1;
2281 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
2282 {
2283 if( aSource[i] == '{' )
2284 braceDepth++;
2285 else if( aSource[i] == '}' )
2286 braceDepth--;
2287
2288 newbuf.append( aSource[i] );
2289 }
2290 i--; // Back up one since the for loop will increment
2291 continue;
2292 }
2293
2294 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i + 1] == '{' )
2295 {
2296 wxString token;
2297 bool isCrossRef = false;
2298
2299 for( i = i + 2; i < sourceLen; ++i )
2300 {
2301 if( aSource[i] == '}' )
2302 break;
2303
2304 if( aSource[i] == ':' )
2305 isCrossRef = true;
2306
2307 token.append( aSource[i] );
2308 }
2309
2310 if( isCrossRef )
2311 {
2312 wxString remainder;
2313 wxString ref = token.BeforeFirst( ':', &remainder );
2314 BOARD_ITEM* refItem = ResolveItem( KIID( ref ), true );
2315
2316 if( refItem && refItem->Type() == PCB_FOOTPRINT_T )
2317 {
2318 token = static_cast<FOOTPRINT*>( refItem )->GetReference() + wxT( ":" ) + remainder;
2319 }
2320 }
2321
2322 newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
2323 }
2324 else
2325 {
2326 newbuf.append( aSource[i] );
2327 }
2328 }
2329
2330 return newbuf;
2331}
2332
2333
2334unsigned BOARD::GetNodesCount( int aNet ) const
2335{
2336 unsigned retval = 0;
2337
2338 for( FOOTPRINT* footprint : Footprints() )
2339 {
2340 for( PAD* pad : footprint->Pads() )
2341 {
2342 if( ( aNet == -1 && pad->GetNetCode() > 0 ) || aNet == pad->GetNetCode() )
2343 retval++;
2344 }
2345 }
2346
2347 return retval;
2348}
2349
2350
2351BOX2I BOARD::ComputeBoundingBox( bool aBoardEdgesOnly, bool aPhysicalLayersOnly ) const
2352{
2353 BOX2I bbox;
2354 LSET visible = GetVisibleLayers();
2355
2356 if( aPhysicalLayersOnly )
2357 visible &= LSET::PhysicalLayersMask();
2358
2359 // If the board is just showing a footprint, we want all footprint layers included in the
2360 // bounding box
2361 if( IsFootprintHolder() )
2362 visible.set();
2363
2364 if( aBoardEdgesOnly )
2365 visible.set( Edge_Cuts );
2366
2367 // Check shapes, dimensions, texts, and fiducials
2368 for( BOARD_ITEM* item : m_drawings )
2369 {
2370 if( aBoardEdgesOnly && ( item->GetLayer() != Edge_Cuts || item->Type() != PCB_SHAPE_T ) )
2371 continue;
2372
2373 if( ( item->GetLayerSet() & visible ).any() )
2374 bbox.Merge( item->GetBoundingBox() );
2375 }
2376
2377 // Check footprints
2378 for( FOOTPRINT* footprint : m_footprints )
2379 {
2380 if( aBoardEdgesOnly )
2381 {
2382 for( const BOARD_ITEM* edge : footprint->GraphicalItems() )
2383 {
2384 if( edge->GetLayer() == Edge_Cuts && edge->Type() == PCB_SHAPE_T )
2385 bbox.Merge( edge->GetBoundingBox() );
2386 }
2387 }
2388 else if( ( footprint->GetLayerSet() & visible ).any() )
2389 {
2390 bbox.Merge( footprint->GetBoundingBox( true ) );
2391 }
2392 }
2393
2394 if( !aBoardEdgesOnly )
2395 {
2396 // Check tracks
2397 for( PCB_TRACK* track : m_tracks )
2398 {
2399 if( ( track->GetLayerSet() & visible ).any() )
2400 bbox.Merge( track->GetBoundingBox() );
2401 }
2402
2403 // Check zones
2404 for( ZONE* aZone : m_zones )
2405 {
2406 if( ( aZone->GetLayerSet() & visible ).any() )
2407 bbox.Merge( aZone->GetBoundingBox() );
2408 }
2409
2410 for( PCB_POINT* point : m_points )
2411 {
2412 bbox.Merge( point->GetBoundingBox() );
2413 }
2414 }
2415
2416 return bbox;
2417}
2418
2419
2420void BOARD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2421{
2422 int padCount = 0;
2423 int viaCount = 0;
2424 int trackSegmentCount = 0;
2425 std::set<int> netCodes;
2426 int unconnected = GetConnectivity()->GetUnconnectedCount( true );
2427
2428 for( PCB_TRACK* item : m_tracks )
2429 {
2430 if( item->Type() == PCB_VIA_T )
2431 viaCount++;
2432 else
2433 trackSegmentCount++;
2434
2435 if( item->GetNetCode() > 0 )
2436 netCodes.insert( item->GetNetCode() );
2437 }
2438
2439 for( FOOTPRINT* footprint : Footprints() )
2440 {
2441 for( PAD* pad : footprint->Pads() )
2442 {
2443 padCount++;
2444
2445 if( pad->GetNetCode() > 0 )
2446 netCodes.insert( pad->GetNetCode() );
2447 }
2448 }
2449
2450 aList.emplace_back( _( "Pads" ), wxString::Format( wxT( "%d" ), padCount ) );
2451 aList.emplace_back( _( "Vias" ), wxString::Format( wxT( "%d" ), viaCount ) );
2452 aList.emplace_back( _( "Track Segments" ), wxString::Format( wxT( "%d" ), trackSegmentCount ) );
2453 aList.emplace_back( _( "Nets" ), wxString::Format( wxT( "%d" ), (int) netCodes.size() ) );
2454 aList.emplace_back( _( "Unrouted" ), wxString::Format( wxT( "%d" ), unconnected ) );
2455}
2456
2457
2458INSPECT_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const std::vector<KICAD_T>& scanTypes )
2459{
2460#if 0 && defined( DEBUG )
2461 std::cout << GetClass().mb_str() << ' ';
2462#endif
2463
2464 bool footprintsScanned = false;
2465 bool drawingsScanned = false;
2466 bool tracksScanned = false;
2467
2468 for( KICAD_T scanType : scanTypes )
2469 {
2470 switch( scanType )
2471 {
2472 case PCB_T:
2473 if( inspector( this, testData ) == INSPECT_RESULT::QUIT )
2474 return INSPECT_RESULT::QUIT;
2475
2476 break;
2477
2478 /*
2479 * Instances of the requested KICAD_T live in a list, either one that I manage, or one
2480 * that my footprints manage. If it's a type managed by class FOOTPRINT, then simply
2481 * pass it on to each footprint's Visit() function via IterateForward( m_footprints, ... ).
2482 */
2483
2484 case PCB_FOOTPRINT_T:
2485 case PCB_PAD_T:
2486 case PCB_SHAPE_T:
2488 case PCB_FIELD_T:
2489 case PCB_TEXT_T:
2490 case PCB_TEXTBOX_T:
2491 case PCB_TABLE_T:
2492 case PCB_TABLECELL_T:
2493 case PCB_DIM_ALIGNED_T:
2494 case PCB_DIM_CENTER_T:
2495 case PCB_DIM_RADIAL_T:
2497 case PCB_DIM_LEADER_T:
2498 case PCB_TARGET_T:
2499 case PCB_BARCODE_T:
2500 if( !footprintsScanned )
2501 {
2502 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2503 {
2504 return INSPECT_RESULT::QUIT;
2505 }
2506
2507 footprintsScanned = true;
2508 }
2509
2510 if( !drawingsScanned )
2511 {
2512 if( IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2513 {
2514 return INSPECT_RESULT::QUIT;
2515 }
2516
2517 drawingsScanned = true;
2518 }
2519
2520 break;
2521
2522 case PCB_VIA_T:
2523 case PCB_TRACE_T:
2524 case PCB_ARC_T:
2525 if( !tracksScanned )
2526 {
2527 if( IterateForward<PCB_TRACK*>( m_tracks, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2528 {
2529 return INSPECT_RESULT::QUIT;
2530 }
2531
2532 tracksScanned = true;
2533 }
2534
2535 break;
2536
2537 case PCB_MARKER_T:
2538 for( PCB_MARKER* marker : m_markers )
2539 {
2540 if( marker->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2541 return INSPECT_RESULT::QUIT;
2542 }
2543
2544 break;
2545
2546 case PCB_POINT_T:
2547 for( PCB_POINT* point : m_points )
2548 {
2549 if( point->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2550 return INSPECT_RESULT::QUIT;
2551 }
2552
2553 break;
2554
2555 case PCB_ZONE_T:
2556 if( !footprintsScanned )
2557 {
2558 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2559 {
2560 return INSPECT_RESULT::QUIT;
2561 }
2562
2563 footprintsScanned = true;
2564 }
2565
2566 for( ZONE* zone : m_zones )
2567 {
2568 if( zone->Visit( inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2569 return INSPECT_RESULT::QUIT;
2570 }
2571
2572 break;
2573
2574 case PCB_GENERATOR_T:
2575 if( !footprintsScanned )
2576 {
2577 if( IterateForward<FOOTPRINT*>( m_footprints, inspector, testData, scanTypes ) == INSPECT_RESULT::QUIT )
2578 {
2579 return INSPECT_RESULT::QUIT;
2580 }
2581
2582 footprintsScanned = true;
2583 }
2584
2585 if( IterateForward<PCB_GENERATOR*>( m_generators, inspector, testData, { scanType } )
2587 {
2588 return INSPECT_RESULT::QUIT;
2589 }
2590
2591 break;
2592
2593 case PCB_GROUP_T:
2594 if( IterateForward<PCB_GROUP*>( m_groups, inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
2595 {
2596 return INSPECT_RESULT::QUIT;
2597 }
2598
2599 break;
2600
2601 default: break;
2602 }
2603 }
2604
2606}
2607
2608
2609NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const
2610{
2611 // the first valid netcode is 1 and the last is m_NetInfo.GetCount()-1.
2612 // zero is reserved for "no connection" and is not actually a net.
2613 // nullptr is returned for non valid netcodes
2614
2615 if( aNetcode == NETINFO_LIST::UNCONNECTED && m_NetInfo.GetNetCount() == 0 )
2617 else
2618 return m_NetInfo.GetNetItem( aNetcode );
2619}
2620
2621
2622NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
2623{
2624 return m_NetInfo.GetNetItem( aNetname );
2625}
2626
2627
2628int BOARD::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet )
2629{
2630 int rv = 0;
2631 int count = 0;
2632
2633 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
2634 {
2635 int ch = *it;
2636
2637 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
2638 {
2639 continue;
2640 }
2641 else if( ch == '+' )
2642 {
2643 aComplementNet = wxT( "-" );
2644 rv = 1;
2645 }
2646 else if( ch == '-' )
2647 {
2648 aComplementNet = wxT( "+" );
2649 rv = -1;
2650 }
2651 else if( ch == 'N' )
2652 {
2653 aComplementNet = wxT( "P" );
2654 rv = -1;
2655 }
2656 else if( ch == 'P' )
2657 {
2658 aComplementNet = wxT( "N" );
2659 rv = 1;
2660 }
2661 else
2662 {
2663 break;
2664 }
2665 }
2666
2667 if( rv != 0 && count >= 1 )
2668 {
2669 aComplementNet = aNetName.Left( aNetName.length() - count ) + aComplementNet + aNetName.Right( count - 1 );
2670 }
2671
2672 return rv;
2673}
2674
2675
2677{
2678 if( aNet )
2679 {
2680 wxString refName = aNet->GetNetname();
2681 wxString coupledNetName;
2682
2683 if( MatchDpSuffix( refName, coupledNetName ) )
2684 return FindNet( coupledNetName );
2685 }
2686
2687 return nullptr;
2688}
2689
2690
2691FOOTPRINT* BOARD::FindFootprintByReference( const wxString& aReference ) const
2692{
2693 for( FOOTPRINT* footprint : m_footprints )
2694 {
2695 if( aReference == footprint->GetReference() )
2696 return footprint;
2697 }
2698
2699 return nullptr;
2700}
2701
2702
2704{
2705 for( FOOTPRINT* footprint : m_footprints )
2706 {
2707 if( footprint->GetPath() == aPath )
2708 return footprint;
2709 }
2710
2711 return nullptr;
2712}
2713
2714
2715PAD* BOARD::FindPadByUuid( const KIID& aUuid ) const
2716{
2717 for( FOOTPRINT* footprint : m_footprints )
2718 {
2719 if( PAD* pad = footprint->FindPadByUuid( aUuid ) )
2720 return pad;
2721 }
2722
2723 return nullptr;
2724}
2725
2726
2727void BOARD::ReplaceNetChainTerminalPad( const wxString& aNetChain, const KIID& aPrev, const KIID& aNew )
2728{
2729 PAD* newPad = FindPadByUuid( aNew );
2730
2731 for( NETINFO_ITEM* net : m_NetInfo )
2732 {
2733 if( net->GetNetChain() == aNetChain )
2734 {
2735 for( int i = 0; i < 2; ++i )
2736 {
2737 PAD* pad = net->GetTerminalPad( i );
2738
2739 if( pad && pad->m_Uuid == aPrev )
2740 net->SetTerminalPad( i, newPad );
2741 }
2742 }
2743 }
2744}
2745
2746
2748{
2749 std::set<wxString> names;
2750
2751 for( const NETINFO_ITEM* net : m_NetInfo )
2752 {
2753 if( !net->GetNetname().IsEmpty() )
2754 names.insert( net->GetNetname() );
2755 }
2756
2757 return names;
2758}
2759
2760
2762{
2763 if( m_project && !m_project->IsNullProject() )
2764 SetProperties( m_project->GetTextVars() );
2765}
2766
2767
2768static wxString FindVariantNameCaseInsensitive( const std::vector<wxString>& aNames,
2769 const wxString& aVariantName )
2770{
2771 for( const wxString& name : aNames )
2772 {
2773 if( name.CmpNoCase( aVariantName ) == 0 )
2774 return name;
2775 }
2776
2777 return wxEmptyString;
2778}
2779
2780
2781void BOARD::SetCurrentVariant( const wxString& aVariant )
2782{
2783 const wxString previous = m_currentVariant;
2784
2785 if( aVariant.IsEmpty() || aVariant.CmpNoCase( GetDefaultVariantName() ) == 0 )
2786 {
2787 m_currentVariant.Clear();
2788 }
2789 else
2790 {
2791 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariant );
2792
2793 if( actualName.IsEmpty() )
2794 m_currentVariant.Clear();
2795 else
2796 m_currentVariant = actualName;
2797 }
2798
2799 // Variant overrides on footprint fields change `${REFDES:FIELD}` resolution,
2800 // so every cross-ref dependent must repaint on switch. Skip the fan-out if
2801 // the active variant did not actually change (e.g. redundant UI callback).
2802 if( previous != m_currentVariant && m_textVarAdapter )
2803 m_textVarAdapter->Tracker().InvalidateVariantScoped();
2804}
2805
2806
2807bool BOARD::HasVariant( const wxString& aVariantName ) const
2808{
2809 return !FindVariantNameCaseInsensitive( m_variantNames, aVariantName ).IsEmpty();
2810}
2811
2812
2813void BOARD::AddVariant( const wxString& aVariantName )
2814{
2815 if( aVariantName.IsEmpty()
2816 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0
2817 || HasVariant( aVariantName ) )
2818 return;
2819
2820 m_variantNames.push_back( aVariantName );
2821}
2822
2823
2824void BOARD::DeleteVariant( const wxString& aVariantName )
2825{
2826 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2827 return;
2828
2829 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
2830 [&]( const wxString& name )
2831 {
2832 return name.CmpNoCase( aVariantName ) == 0;
2833 } );
2834
2835 if( it != m_variantNames.end() )
2836 {
2837 wxString actualName = *it;
2838 m_variantNames.erase( it );
2839 m_variantDescriptions.erase( actualName );
2840
2841 // Clear current variant if it was the deleted one
2842 if( m_currentVariant.CmpNoCase( aVariantName ) == 0 )
2843 m_currentVariant.Clear();
2844
2845 // Remove variant from all footprints
2846 for( FOOTPRINT* fp : m_footprints )
2847 fp->DeleteVariant( actualName );
2848 }
2849}
2850
2851
2852void BOARD::RenameVariant( const wxString& aOldName, const wxString& aNewName )
2853{
2854 if( aNewName.IsEmpty() || aNewName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2855 return;
2856
2857 auto it = std::find_if( m_variantNames.begin(), m_variantNames.end(),
2858 [&]( const wxString& name )
2859 {
2860 return name.CmpNoCase( aOldName ) == 0;
2861 } );
2862
2863 if( it != m_variantNames.end() )
2864 {
2865 wxString actualOldName = *it;
2866
2867 // Check if new name already exists (case-insensitive) and isn't the same variant
2868 wxString existingName = FindVariantNameCaseInsensitive( m_variantNames, aNewName );
2869
2870 if( !existingName.IsEmpty() && existingName.CmpNoCase( actualOldName ) != 0 )
2871 return;
2872
2873 if( actualOldName == aNewName )
2874 return;
2875
2876 *it = aNewName;
2877
2878 // Transfer description
2879 auto descIt = m_variantDescriptions.find( actualOldName );
2880
2881 if( descIt != m_variantDescriptions.end() )
2882 {
2883 if( !descIt->second.IsEmpty() )
2884 m_variantDescriptions[aNewName] = descIt->second;
2885
2886 m_variantDescriptions.erase( descIt );
2887 }
2888
2889 // Update current variant if it was the renamed one
2890 if( m_currentVariant.CmpNoCase( aOldName ) == 0 )
2891 m_currentVariant = aNewName;
2892
2893 // Rename variant in all footprints
2894 for( FOOTPRINT* fp : m_footprints )
2895 fp->RenameVariant( actualOldName, aNewName );
2896 }
2897}
2898
2899
2900wxString BOARD::GetVariantDescription( const wxString& aVariantName ) const
2901{
2902 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2903 return wxEmptyString;
2904
2905 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
2906
2907 if( actualName.IsEmpty() )
2908 return wxEmptyString;
2909
2910 auto it = m_variantDescriptions.find( actualName );
2911
2912 if( it != m_variantDescriptions.end() )
2913 return it->second;
2914
2915 return wxEmptyString;
2916}
2917
2918
2919void BOARD::SetVariantDescription( const wxString& aVariantName, const wxString& aDescription )
2920{
2921 if( aVariantName.IsEmpty() || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0 )
2922 return;
2923
2924 wxString actualName = FindVariantNameCaseInsensitive( m_variantNames, aVariantName );
2925
2926 if( actualName.IsEmpty() )
2927 return;
2928
2929 if( aDescription.IsEmpty() )
2930 m_variantDescriptions.erase( actualName );
2931 else
2932 m_variantDescriptions[actualName] = aDescription;
2933}
2934
2935
2936wxArrayString BOARD::GetVariantNamesForUI() const
2937{
2938 wxArrayString names;
2939 names.Add( GetDefaultVariantName() );
2940
2941 for( const wxString& name : m_variantNames )
2942 names.Add( name );
2943
2944 names.Sort( SortVariantNames );
2945
2946 return names;
2947}
2948
2949
2951{
2952 m_lengthDelayCalc->SynchronizeTuningProfileProperties();
2953}
2954
2955
2956void BOARD::SynchronizeNetsAndNetClasses( bool aResetTrackAndViaSizes )
2957{
2958 if( !m_project )
2959 return;
2960
2962 const std::shared_ptr<NETCLASS>& defaultNetClass = bds.m_NetSettings->GetDefaultNetclass();
2963
2965
2966 for( NETINFO_ITEM* net : m_NetInfo )
2967 net->SetNetClass( bds.m_NetSettings->GetEffectiveNetClass( net->GetNetname() ) );
2968
2969 if( aResetTrackAndViaSizes )
2970 {
2971 // Set initial values for custom track width & via size to match the default
2972 // netclass settings
2973 bds.UseCustomTrackViaSize( false );
2974 bds.SetCustomTrackWidth( defaultNetClass->GetTrackWidth() );
2975 bds.SetCustomViaSize( defaultNetClass->GetViaDiameter() );
2976 bds.SetCustomViaDrill( defaultNetClass->GetViaDrill() );
2977 bds.SetCustomDiffPairWidth( defaultNetClass->GetDiffPairWidth() );
2978 bds.SetCustomDiffPairGap( defaultNetClass->GetDiffPairGap() );
2979 bds.SetCustomDiffPairViaGap( defaultNetClass->GetDiffPairViaGap() );
2980 }
2981
2983}
2984
2985
2986bool BOARD::SynchronizeComponentClasses( const std::unordered_set<wxString>& aNewSheetPaths ) const
2987{
2988 std::shared_ptr<COMPONENT_CLASS_SETTINGS> settings = GetProject()->GetProjectFile().ComponentClassSettings();
2989
2990 return m_componentClassManager->SyncDynamicComponentClassAssignments(
2991 settings->GetComponentClassAssignments(), settings->GetEnableSheetComponentClasses(), aNewSheetPaths );
2992}
2993
2994
2996{
2997 int error_count = 0;
2998
2999 for( ZONE* zone : Zones() )
3000 {
3001 if( !zone->IsOnCopperLayer() )
3002 {
3003 zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3004 continue;
3005 }
3006
3007 if( zone->GetNetCode() != 0 ) // i.e. if this zone is connected to a net
3008 {
3009 const NETINFO_ITEM* net = zone->GetNet();
3010
3011 if( net )
3012 {
3013 zone->SetNetCode( net->GetNetCode() );
3014 }
3015 else
3016 {
3017 error_count++;
3018
3019 // keep Net Name and set m_NetCode to -1 : error flag.
3020 zone->SetNetCode( -1 );
3021 }
3022 }
3023 }
3024
3025 return error_count;
3026}
3027
3028
3029PAD* BOARD::GetPad( const VECTOR2I& aPosition, const LSET& aLayerSet ) const
3030{
3031 for( FOOTPRINT* footprint : m_footprints )
3032 {
3033 PAD* pad = nullptr;
3034
3035 if( footprint->HitTest( aPosition ) )
3036 pad = footprint->GetPad( aPosition, aLayerSet.any() ? aLayerSet : LSET::AllCuMask() );
3037
3038 if( pad )
3039 return pad;
3040 }
3041
3042 return nullptr;
3043}
3044
3045
3046PAD* BOARD::GetPad( const PCB_TRACK* aTrace, ENDPOINT_T aEndPoint ) const
3047{
3048 const VECTOR2I& aPosition = aTrace->GetEndPoint( aEndPoint );
3049
3050 LSET lset( { aTrace->GetLayer() } );
3051
3052 return GetPad( aPosition, lset );
3053}
3054
3055
3056PAD* BOARD::GetPad( std::vector<PAD*>& aPadList, const VECTOR2I& aPosition, const LSET& aLayerSet ) const
3057{
3058 // Search aPadList for aPosition
3059 // aPadList is sorted by X then Y values, and a fast binary search is used
3060 int idxmax = aPadList.size() - 1;
3061
3062 int delta = aPadList.size();
3063
3064 int idx = 0; // Starting index is the beginning of list
3065
3066 while( delta )
3067 {
3068 // Calculate half size of remaining interval to test.
3069 // Ensure the computed value is not truncated (too small)
3070 if( ( delta & 1 ) && ( delta > 1 ) )
3071 delta++;
3072
3073 delta /= 2;
3074
3075 PAD* pad = aPadList[idx];
3076
3077 if( pad->GetPosition() == aPosition ) // candidate found
3078 {
3079 // The pad must match the layer mask:
3080 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3081 return pad;
3082
3083 // More than one pad can be at aPosition
3084 // search for a pad at aPosition that matched this mask
3085
3086 // search next
3087 for( int ii = idx + 1; ii <= idxmax; ii++ )
3088 {
3089 pad = aPadList[ii];
3090
3091 if( pad->GetPosition() != aPosition )
3092 break;
3093
3094 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3095 return pad;
3096 }
3097 // search previous
3098 for( int ii = idx - 1; ii >= 0; ii-- )
3099 {
3100 pad = aPadList[ii];
3101
3102 if( pad->GetPosition() != aPosition )
3103 break;
3104
3105 if( ( aLayerSet & pad->GetLayerSet() ).any() )
3106 return pad;
3107 }
3108
3109 // Not found:
3110 return nullptr;
3111 }
3112
3113 if( pad->GetPosition().x == aPosition.x ) // Must search considering Y coordinate
3114 {
3115 if( pad->GetPosition().y < aPosition.y ) // Must search after this item
3116 {
3117 idx += delta;
3118
3119 if( idx > idxmax )
3120 idx = idxmax;
3121 }
3122 else // Must search before this item
3123 {
3124 idx -= delta;
3125
3126 if( idx < 0 )
3127 idx = 0;
3128 }
3129 }
3130 else if( pad->GetPosition().x < aPosition.x ) // Must search after this item
3131 {
3132 idx += delta;
3133
3134 if( idx > idxmax )
3135 idx = idxmax;
3136 }
3137 else // Must search before this item
3138 {
3139 idx -= delta;
3140
3141 if( idx < 0 )
3142 idx = 0;
3143 }
3144 }
3145
3146 return nullptr;
3147}
3148
3149
3155bool sortPadsByXthenYCoord( PAD* const& aLH, PAD* const& aRH )
3156{
3157 if( aLH->GetPosition().x == aRH->GetPosition().x )
3158 return aLH->GetPosition().y < aRH->GetPosition().y;
3159
3160 return aLH->GetPosition().x < aRH->GetPosition().x;
3161}
3162
3163
3164void BOARD::GetSortedPadListByXthenYCoord( std::vector<PAD*>& aVector, int aNetCode ) const
3165{
3166 for( FOOTPRINT* footprint : Footprints() )
3167 {
3168 for( PAD* pad : footprint->Pads() )
3169 {
3170 if( aNetCode < 0 || pad->GetNetCode() == aNetCode )
3171 aVector.push_back( pad );
3172 }
3173 }
3174
3175 std::sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
3176}
3177
3178
3180{
3181 if( GetDesignSettings().m_HasStackup )
3183
3184 BOARD_STACKUP stackup;
3186 return stackup;
3187}
3188
3189
3190std::tuple<int, double, double, double, double> BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const
3191{
3192 std::shared_ptr<CONNECTIVITY_DATA> connectivity = GetBoard()->GetConnectivity();
3193 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items;
3194
3195 for( BOARD_CONNECTED_ITEM* boardItem : connectivity->GetConnectedItems( &aTrack, EXCLUDE_ZONES ) )
3196 {
3198
3199 if( item.Type() != LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN )
3200 items.push_back( std::move( item ) );
3201 }
3202
3203 constexpr PATH_OPTIMISATIONS opts = {
3204 .OptimiseVias = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false
3205 };
3207 items, opts, nullptr, nullptr, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL,
3209
3210 return std::make_tuple( items.size(), details.TrackLength + details.ViaLength, details.PadToDieLength,
3211 details.TrackDelay + details.ViaDelay, details.PadToDieDelay );
3212}
3213
3214
3215FOOTPRINT* BOARD::GetFootprint( const VECTOR2I& aPosition, PCB_LAYER_ID aActiveLayer, bool aVisibleOnly,
3216 bool aIgnoreLocked ) const
3217{
3218 FOOTPRINT* footprint = nullptr;
3219 FOOTPRINT* alt_footprint = nullptr;
3220 int min_dim = 0x7FFFFFFF;
3221 int alt_min_dim = 0x7FFFFFFF;
3222 bool current_layer_back = IsBackLayer( aActiveLayer );
3223
3224 for( FOOTPRINT* candidate : m_footprints )
3225 {
3226 // is the ref point within the footprint's bounds?
3227 if( !candidate->HitTest( aPosition ) )
3228 continue;
3229
3230 // if caller wants to ignore locked footprints, and this one is locked, skip it.
3231 if( aIgnoreLocked && candidate->IsLocked() )
3232 continue;
3233
3234 PCB_LAYER_ID layer = candidate->GetLayer();
3235
3236 // Filter non visible footprints if requested
3237 if( !aVisibleOnly || IsFootprintLayerVisible( layer ) )
3238 {
3239 BOX2I bb = candidate->GetBoundingBox( false );
3240
3241 int offx = bb.GetX() + bb.GetWidth() / 2;
3242 int offy = bb.GetY() + bb.GetHeight() / 2;
3243
3244 // off x & offy point to the middle of the box.
3245 int dist =
3246 ( aPosition.x - offx ) * ( aPosition.x - offx ) + ( aPosition.y - offy ) * ( aPosition.y - offy );
3247
3248 if( current_layer_back == IsBackLayer( layer ) )
3249 {
3250 if( dist <= min_dim )
3251 {
3252 // better footprint shown on the active side
3253 footprint = candidate;
3254 min_dim = dist;
3255 }
3256 }
3257 else if( aVisibleOnly && IsFootprintLayerVisible( layer ) )
3258 {
3259 if( dist <= alt_min_dim )
3260 {
3261 // better footprint shown on the other side
3262 alt_footprint = candidate;
3263 alt_min_dim = dist;
3264 }
3265 }
3266 }
3267 }
3268
3269 if( footprint )
3270 return footprint;
3271
3272 if( alt_footprint )
3273 return alt_footprint;
3274
3275 return nullptr;
3276}
3277
3278
3279std::list<ZONE*> BOARD::GetZoneList( bool aIncludeZonesInFootprints ) const
3280{
3281 std::list<ZONE*> zones;
3282
3283 for( ZONE* zone : Zones() )
3284 zones.push_back( zone );
3285
3286 if( aIncludeZonesInFootprints )
3287 {
3288 for( FOOTPRINT* footprint : m_footprints )
3289 {
3290 for( ZONE* zone : footprint->Zones() )
3291 zones.push_back( zone );
3292 }
3293 }
3294
3295 return zones;
3296}
3297
3298
3299ZONE* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, PCB_LAYER_ID aLayer, VECTOR2I aStartPointPosition,
3301{
3302 ZONE* new_area = new ZONE( this );
3303
3304 new_area->SetNetCode( aNetcode );
3305 new_area->SetLayer( aLayer );
3306
3307 m_zones.push_back( new_area );
3308
3309 new_area->SetHatchStyle( (ZONE_BORDER_DISPLAY_STYLE) aHatch );
3310
3311 // Add the first corner to the new zone
3312 new_area->AppendCorner( aStartPointPosition, -1 );
3313
3314 if( aNewZonesList )
3315 {
3316 ITEM_PICKER picker( nullptr, new_area, UNDO_REDO::NEWITEM );
3317 aNewZonesList->PushItem( picker );
3318 }
3319
3320 return new_area;
3321}
3322
3323
3324bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, bool aInferOutlineIfNecessary,
3325 OUTLINE_ERROR_HANDLER* aErrorHandler, bool aAllowUseArcsInPolygons,
3326 bool aIncludeNPTHAsOutlines )
3327{
3328 // max dist from one endPt to next startPt: use the current value
3329 int chainingEpsilon = GetOutlinesChainingEpsilon();
3330
3331 bool success = BuildBoardPolygonOutlines( this, aOutlines, GetDesignSettings().m_MaxError, chainingEpsilon,
3332 aInferOutlineIfNecessary, aErrorHandler, aAllowUseArcsInPolygons );
3333
3334 // Now subtract NPTH oval holes from outlines if required
3335 if( aIncludeNPTHAsOutlines )
3336 {
3337 for( FOOTPRINT* fp : Footprints() )
3338 {
3339 for( PAD* pad : fp->Pads() )
3340 {
3341 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
3342 continue;
3343
3344 SHAPE_POLY_SET hole;
3345 pad->TransformHoleToPolygon( hole, 0, pad->GetMaxError(), ERROR_INSIDE );
3346
3347 if( hole.OutlineCount() > 0 ) // can be not the case for malformed NPTH holes
3348 {
3349 // Issue #20159: BooleanSubtract correctly clips holes extending past board
3350 // edges (common with oval holes near irregular boards). O(n log n) per hole
3351 // vs O(1) for AddHole, but only used for 3D viewer generation, not a hot path.
3352 aOutlines.BooleanSubtract( hole );
3353 }
3354 }
3355 }
3356 }
3357
3358 // Make polygon strictly simple to avoid issues (especially in 3D viewer)
3359 aOutlines.Simplify();
3360
3361 return success;
3362}
3363
3364
3366{
3368 return static_cast<EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3369
3370 return static_cast<EMBEDDED_FILES*>( this );
3371}
3372
3373
3375{
3377 return static_cast<const EMBEDDED_FILES*>( m_embeddedFilesDelegate );
3378
3379 return static_cast<const EMBEDDED_FILES*>( this );
3380}
3381
3382
3383std::set<KIFONT::OUTLINE_FONT*> BOARD::GetFonts() const
3384{
3386
3387 std::set<KIFONT::OUTLINE_FONT*> fonts;
3388
3389 for( BOARD_ITEM* item : Drawings() )
3390 {
3391 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
3392 {
3393 KIFONT::FONT* font = text->GetFont();
3394
3395 if( font && font->IsOutline() )
3396 {
3397 KIFONT::OUTLINE_FONT* outlineFont = static_cast<KIFONT::OUTLINE_FONT*>( font );
3398 PERMISSION permission = outlineFont->GetEmbeddingPermission();
3399
3400 if( permission == PERMISSION::EDITABLE || permission == PERMISSION::INSTALLABLE )
3401 fonts.insert( outlineFont );
3402 }
3403 }
3404 }
3405
3406 return fonts;
3407}
3408
3409
3411{
3412 for( KIFONT::OUTLINE_FONT* font : GetFonts() )
3413 {
3414 EMBEDDED_FILES::EMBEDDED_FILE* file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
3416 }
3417}
3418
3419
3420const std::vector<PAD*> BOARD::GetPads() const
3421{
3422 std::vector<PAD*> allPads;
3423
3424 for( FOOTPRINT* footprint : Footprints() )
3425 {
3426 for( PAD* pad : footprint->Pads() )
3427 allPads.push_back( pad );
3428 }
3429
3430 return allPads;
3431}
3432
3433
3434const std::vector<BOARD_CONNECTED_ITEM*> BOARD::AllConnectedItems()
3435{
3436 std::vector<BOARD_CONNECTED_ITEM*> items;
3437
3438 for( PCB_TRACK* track : Tracks() )
3439 items.push_back( track );
3440
3441 for( FOOTPRINT* footprint : Footprints() )
3442 {
3443 for( PAD* pad : footprint->Pads() )
3444 items.push_back( pad );
3445
3446 for( ZONE* zone : footprint->Zones() )
3447 items.push_back( zone );
3448
3449 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
3450 {
3451 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( dwg ) )
3452 items.push_back( bci );
3453 }
3454 }
3455
3456 for( ZONE* zone : Zones() )
3457 items.push_back( zone );
3458
3459 for( BOARD_ITEM* item : Drawings() )
3460 {
3461 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
3462 items.push_back( bci );
3463 }
3464
3465 return items;
3466}
3467
3468
3469void BOARD::MapNets( BOARD* aDestBoard )
3470{
3472 {
3473 NETINFO_ITEM* netInfo = aDestBoard->FindNet( item->GetNetname() );
3474
3475 if( netInfo )
3476 item->SetNet( netInfo );
3477 else
3478 {
3479 NETINFO_ITEM* newNet = new NETINFO_ITEM( aDestBoard, item->GetNetname() );
3480 aDestBoard->Add( newNet );
3481 item->SetNet( newNet );
3482 }
3483 }
3484}
3485
3486
3488{
3490 {
3491 if( FindNet( item->GetNetCode() ) == nullptr )
3492 item->SetNetCode( NETINFO_LIST::ORPHANED );
3493 }
3494}
3495
3496
3498{
3499 if( !alg::contains( m_listeners, aListener ) )
3500 m_listeners.push_back( aListener );
3501}
3502
3503
3505{
3506 auto i = std::find( m_listeners.begin(), m_listeners.end(), aListener );
3507
3508 if( i != m_listeners.end() )
3509 {
3510 std::iter_swap( i, m_listeners.end() - 1 );
3511 m_listeners.pop_back();
3512 }
3513}
3514
3515
3517{
3518 m_listeners.clear();
3519}
3520
3521
3526
3527
3528void BOARD::OnItemsChanged( std::vector<BOARD_ITEM*>& aItems )
3529{
3531}
3532
3533
3534void BOARD::OnItemsCompositeUpdate( std::vector<BOARD_ITEM*>& aAddedItems, std::vector<BOARD_ITEM*>& aRemovedItems,
3535 std::vector<BOARD_ITEM*>& aChangedItems )
3536{
3537 InvokeListeners( &BOARD_LISTENER::OnBoardCompositeUpdate, *this, aAddedItems, aRemovedItems, aChangedItems );
3538}
3539
3540
3545
3546
3554
3555
3556void BOARD::SetHighLightNet( int aNetCode, bool aMulti )
3557{
3558 bool already = m_highLight.m_netCodes.count( aNetCode );
3559
3560 if( !already )
3561 {
3562 if( !aMulti )
3563 m_highLight.m_netCodes.clear();
3564
3565 m_highLight.m_netCodes.insert( aNetCode );
3567 }
3568}
3569
3570
3571void BOARD::HighLightON( bool aValue )
3572{
3573 if( m_highLight.m_highLightOn != aValue )
3574 {
3575 m_highLight.m_highLightOn = aValue;
3577 }
3578}
3579
3580
3581wxString BOARD::GroupsSanityCheck( bool repair )
3582{
3583 if( repair )
3584 {
3585 while( GroupsSanityCheckInternal( repair ) != wxEmptyString )
3586 {
3587 };
3588
3589 return wxEmptyString;
3590 }
3591 return GroupsSanityCheckInternal( repair );
3592}
3593
3594
3596{
3597 // Cycle detection
3598 //
3599 // Each group has at most one parent group.
3600 // So we start at group 0 and traverse the parent chain, marking groups seen along the way.
3601 // If we ever see a group that we've already marked, that's a cycle.
3602 // If we reach the end of the chain, we know all groups in that chain are not part of any cycle.
3603 //
3604 // Algorithm below is linear in the # of groups because each group is visited only once.
3605 // There may be extra time taken due to the container access calls and iterators.
3606 //
3607 // Groups we know are cycle free
3608 std::unordered_set<EDA_GROUP*> knownCycleFreeGroups;
3609 // Groups in the current chain we're exploring.
3610 std::unordered_set<EDA_GROUP*> currentChainGroups;
3611 // Groups we haven't checked yet.
3612 std::unordered_set<EDA_GROUP*> toCheckGroups;
3613
3614 // Initialize set of groups and generators to check that could participate in a cycle.
3615 for( PCB_GROUP* group : Groups() )
3616 toCheckGroups.insert( group );
3617
3618 for( PCB_GENERATOR* gen : Generators() )
3619 toCheckGroups.insert( gen );
3620
3621 while( !toCheckGroups.empty() )
3622 {
3623 currentChainGroups.clear();
3624 EDA_GROUP* group = *toCheckGroups.begin();
3625
3626 while( true )
3627 {
3628 if( currentChainGroups.find( group ) != currentChainGroups.end() )
3629 {
3630 if( repair )
3631 Remove( static_cast<BOARD_ITEM*>( group->AsEdaItem() ) );
3632
3633 return "Cycle detected in group membership";
3634 }
3635 else if( knownCycleFreeGroups.find( group ) != knownCycleFreeGroups.end() )
3636 {
3637 // Parent is a group we know does not lead to a cycle
3638 break;
3639 }
3640
3641 currentChainGroups.insert( group );
3642 // We haven't visited currIdx yet, so it must be in toCheckGroups
3643 toCheckGroups.erase( group );
3644
3645 group = group->AsEdaItem()->GetParentGroup();
3646
3647 if( !group )
3648 {
3649 // end of chain and no cycles found in this chain
3650 break;
3651 }
3652 }
3653
3654 // No cycles found in chain, so add it to set of groups we know don't participate
3655 // in a cycle.
3656 knownCycleFreeGroups.insert( currentChainGroups.begin(), currentChainGroups.end() );
3657 }
3658
3659 // Success
3660 return "";
3661}
3662
3663
3665{
3666 if( a->Type() != b->Type() )
3667 return a->Type() < b->Type();
3668
3669 if( a->GetLayer() != b->GetLayer() )
3670 return a->GetLayer() < b->GetLayer();
3671
3672 if( a->GetPosition().x != b->GetPosition().x )
3673 return a->GetPosition().x < b->GetPosition().x;
3674
3675 if( a->GetPosition().y != b->GetPosition().y )
3676 return a->GetPosition().y < b->GetPosition().y;
3677
3678 if( a->m_Uuid != b->m_Uuid ) // shopuld be always the case foer valid boards
3679 return a->m_Uuid < b->m_Uuid;
3680
3681 return a < b;
3682}
3683
3684
3685bool BOARD::cmp_drawings::operator()( const BOARD_ITEM* aFirst, const BOARD_ITEM* aSecond ) const
3686{
3687 if( aFirst->Type() != aSecond->Type() )
3688 return aFirst->Type() < aSecond->Type();
3689
3690 if( aFirst->GetLayer() != aSecond->GetLayer() )
3691 return aFirst->GetLayer() < aSecond->GetLayer();
3692
3693 if( aFirst->Type() == PCB_SHAPE_T )
3694 {
3695 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aFirst );
3696 const PCB_SHAPE* other = static_cast<const PCB_SHAPE*>( aSecond );
3697 return shape->Compare( other ) < 0;
3698 }
3699 else if( aFirst->Type() == PCB_TEXT_T || aFirst->Type() == PCB_FIELD_T )
3700 {
3701 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aFirst );
3702 const PCB_TEXT* other = static_cast<const PCB_TEXT*>( aSecond );
3703 return text->Compare( other ) < 0;
3704 }
3705 else if( aFirst->Type() == PCB_TEXTBOX_T )
3706 {
3707 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( aFirst );
3708 const PCB_TEXTBOX* other = static_cast<const PCB_TEXTBOX*>( aSecond );
3709
3710 int shapeCmp = textbox->PCB_SHAPE::Compare( other );
3711
3712 if( shapeCmp != 0 )
3713 return shapeCmp < 0;
3714
3715 return textbox->EDA_TEXT::Compare( other ) < 0;
3716 }
3717 else if( aFirst->Type() == PCB_TABLE_T )
3718 {
3719 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( aFirst );
3720 const PCB_TABLE* other = static_cast<const PCB_TABLE*>( aSecond );
3721
3722 return PCB_TABLE::Compare( table, other ) < 0;
3723 }
3724 else if( aFirst->Type() == PCB_BARCODE_T )
3725 {
3726 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( aFirst );
3727 const PCB_BARCODE* other = static_cast<const PCB_BARCODE*>( aSecond );
3728
3729 return PCB_BARCODE::Compare( barcode, other ) < 0;
3730 }
3731
3732 return aFirst->m_Uuid < aSecond->m_Uuid;
3733}
3734
3735
3737 KIGFX::RENDER_SETTINGS* aRenderSettings ) const
3738{
3739 int maxError = GetDesignSettings().m_MaxError;
3740
3741 // convert tracks and vias:
3742 for( const PCB_TRACK* track : m_tracks )
3743 {
3744 if( !track->IsOnLayer( aLayer ) )
3745 continue;
3746
3747 track->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3748 }
3749
3750 // convert pads and other copper items in footprints
3751 for( const FOOTPRINT* footprint : m_footprints )
3752 {
3753 footprint->TransformPadsToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3754
3755 footprint->TransformFPShapesToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE, true, /* include text */
3756 true, /* include shapes */
3757 false /* include private items */ );
3758
3759 for( const ZONE* zone : footprint->Zones() )
3760 {
3761 if( zone->GetLayerSet().test( aLayer ) )
3762 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
3763 }
3764 }
3765
3766 // convert copper zones
3767 for( const ZONE* zone : Zones() )
3768 {
3769 if( zone->GetLayerSet().test( aLayer ) )
3770 zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
3771 }
3772
3773 // convert graphic items on copper layers (texts)
3774 for( const BOARD_ITEM* item : m_drawings )
3775 {
3776 if( !item->IsOnLayer( aLayer ) )
3777 continue;
3778
3779 switch( item->Type() )
3780 {
3781 case PCB_SHAPE_T:
3782 {
3783 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( item );
3784 shape->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3785 break;
3786 }
3787
3788 case PCB_BARCODE_T:
3789 {
3790 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( item );
3791 barcode->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3792 break;
3793 }
3794
3795 case PCB_FIELD_T:
3796 case PCB_TEXT_T:
3797 {
3798 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
3799 text->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3800 break;
3801 }
3802
3803 case PCB_TEXTBOX_T:
3804 {
3805 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
3806 // border
3807 textbox->PCB_SHAPE::TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3808 // text
3809 textbox->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3810 break;
3811 }
3812
3813 case PCB_TABLE_T:
3814 {
3815 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
3816 table->TransformGraphicItemsToPolySet( aOutlines, maxError, ERROR_INSIDE, aRenderSettings );
3817 break;
3818 }
3819
3820 case PCB_DIM_ALIGNED_T:
3821 case PCB_DIM_CENTER_T:
3822 case PCB_DIM_RADIAL_T:
3824 case PCB_DIM_LEADER_T:
3825 {
3826 const PCB_DIMENSION_BASE* dim = static_cast<const PCB_DIMENSION_BASE*>( item );
3827 dim->TransformShapeToPolygon( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
3828 dim->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
3829 break;
3830 }
3831
3832 default: break;
3833 }
3834 }
3835}
3836
3837
3839{
3840 BOARD_ITEM_SET items;
3841
3842 std::copy( m_tracks.begin(), m_tracks.end(), std::inserter( items, items.end() ) );
3843 std::copy( m_zones.begin(), m_zones.end(), std::inserter( items, items.end() ) );
3844 std::copy( m_generators.begin(), m_generators.end(), std::inserter( items, items.end() ) );
3845 std::copy( m_footprints.begin(), m_footprints.end(), std::inserter( items, items.end() ) );
3846 std::copy( m_drawings.begin(), m_drawings.end(), std::inserter( items, items.end() ) );
3847 std::copy( m_markers.begin(), m_markers.end(), std::inserter( items, items.end() ) );
3848 std::copy( m_groups.begin(), m_groups.end(), std::inserter( items, items.end() ) );
3849 std::copy( m_points.begin(), m_points.end(), std::inserter( items, items.end() ) );
3850
3851 return items;
3852}
3853
3854
3855bool BOARD::operator==( const BOARD_ITEM& aItem ) const
3856{
3857 if( aItem.Type() != Type() )
3858 return false;
3859
3860 const BOARD& other = static_cast<const BOARD&>( aItem );
3861
3862 if( *m_designSettings != *other.m_designSettings )
3863 return false;
3864
3865 if( m_NetInfo.GetNetCount() != other.m_NetInfo.GetNetCount() )
3866 return false;
3867
3868 const NETNAMES_MAP& thisNetNames = m_NetInfo.NetsByName();
3869 const NETNAMES_MAP& otherNetNames = other.m_NetInfo.NetsByName();
3870
3871 for( auto it1 = thisNetNames.begin(), it2 = otherNetNames.begin();
3872 it1 != thisNetNames.end() && it2 != otherNetNames.end(); ++it1, ++it2 )
3873 {
3874 // We only compare the names in order here, not the index values
3875 // as the index values are auto-generated and the names are not.
3876 if( it1->first != it2->first )
3877 return false;
3878 }
3879
3880 if( m_properties.size() != other.m_properties.size() )
3881 return false;
3882
3883 for( auto it1 = m_properties.begin(), it2 = other.m_properties.begin();
3884 it1 != m_properties.end() && it2 != other.m_properties.end(); ++it1, ++it2 )
3885 {
3886 if( *it1 != *it2 )
3887 return false;
3888 }
3889
3890 if( m_paper.GetCustomHeightMils() != other.m_paper.GetCustomHeightMils() )
3891 return false;
3892
3893 if( m_paper.GetCustomWidthMils() != other.m_paper.GetCustomWidthMils() )
3894 return false;
3895
3896 if( m_paper.GetSizeMils() != other.m_paper.GetSizeMils() )
3897 return false;
3898
3899 if( m_paper.GetPaperId() != other.m_paper.GetPaperId() )
3900 return false;
3901
3902 if( m_paper.GetWxOrientation() != other.m_paper.GetWxOrientation() )
3903 return false;
3904
3905 for( int ii = 0; !m_titles.GetComment( ii ).empty(); ++ii )
3906 {
3907 if( m_titles.GetComment( ii ) != other.m_titles.GetComment( ii ) )
3908 return false;
3909 }
3910
3911 wxArrayString ourVars;
3912 m_titles.GetContextualTextVars( &ourVars );
3913
3914 wxArrayString otherVars;
3915 other.m_titles.GetContextualTextVars( &otherVars );
3916
3917 if( ourVars != otherVars )
3918 return false;
3919
3920 return true;
3921}
3922
3924{
3925 m_boardOutline->GetOutline().RemoveAllContours();
3926
3927 bool has_outline = GetBoardPolygonOutlines( m_boardOutline->GetOutline(), false );
3928
3929 if( has_outline )
3930 m_boardOutline->GetOutline().Fracture();
3931}
3932
3933
3935{
3936 // return the number of PTH with Press-Fit fabr attribute
3937 int count = 0;
3938
3939 for( FOOTPRINT* footprint : Footprints() )
3940 {
3941 for( PAD* pad : footprint->Pads() )
3942 {
3943 if( pad->GetProperty() == PAD_PROP::PRESSFIT )
3944 count++;
3945 }
3946 }
3947
3948 return count;
3949}
3950
3951
3953{
3954 // @return the number of PTH with Castellated fabr attribute
3955 int count = 0;
3956
3957 for( FOOTPRINT* footprint : Footprints() )
3958 {
3959 for( PAD* pad : footprint->Pads() )
3960 {
3961 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
3962 count++;
3963 }
3964 }
3965
3966 return count;
3967}
3968
3969
3970void BOARD::SaveToHistory( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
3971{
3972 // The board can transiently have no project (e.g. during a non-KiCad import while the old
3973 // project is being unloaded and the new one has not yet been linked). The autosave timer can
3974 // fire in that window, so guard against a null project here rather than dereferencing it.
3976
3977 if( !project )
3978 return;
3979
3980 wxString projPath = project->GetProjectPath();
3981
3982 if( projPath.IsEmpty() )
3983 return;
3984
3985 // Verify we're saving for the correct project
3986 if( !projPath.IsSameAs( aProjectPath ) )
3987 {
3988 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - project path mismatch: %s vs %s" ), projPath,
3989 aProjectPath );
3990 return;
3991 }
3992
3993 wxString boardPath = GetFileName();
3994
3995 if( boardPath.IsEmpty() )
3996 return; // unsaved board
3997
3998 // Derive relative path from project root.
3999 if( !boardPath.StartsWith( projPath ) )
4000 {
4001 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver skipping - board not under project: %s" ), boardPath );
4002 return; // not under project
4003 }
4004
4005 wxString rel = boardPath.Mid( projPath.length() );
4006
4007 try
4008 {
4010 STRING_FORMATTER formatter;
4011
4012 pi.FormatBoardToFormatter( &formatter, this, nullptr );
4013
4014 HISTORY_FILE_DATA entry;
4015 entry.relativePath = rel;
4016 entry.content = std::move( formatter.MutableString() );
4017 entry.prettify = true;
4018
4019 if( ADVANCED_CFG::GetCfg().m_CompactSave )
4020 entry.formatMode = KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
4021
4022 aFileData.push_back( std::move( entry ) );
4023
4024 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialized %zu bytes for '%s'" ),
4025 aFileData.back().content.size(), rel );
4026 }
4027 catch( const IO_ERROR& ioe )
4028 {
4029 wxLogTrace( traceAutoSave, wxS( "[history] pcb saver serialize failed: %s" ), wxString::FromUTF8( ioe.What() ) );
4030 }
4031}
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:3155
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:2768
#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:2458
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:3179
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:3522
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:3029
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:3365
int m_fileFormatVersionAtLoad
Definition board.h:1651
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition board.cpp:2676
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:2781
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:3469
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:2936
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:3434
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:3190
std::set< wxString > GetNetClassAssignmentCandidates() const
Return the set of netname candidates for netclass assignment.
Definition board.cpp:2747
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:3516
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:3736
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:3497
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:3556
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:2609
EDA_UNITS m_userUnits
Definition board.h:1661
void UpdateBoardOutline()
Definition board.cpp:3923
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:2824
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:3487
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:3299
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:3970
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:3534
int SetAreasNetCodesFromNetNames()
Set the .m_NetCode member of all copper areas, according to the area Net Name The SetNetCodesFromNetN...
Definition board.cpp:2995
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:2956
void ResetNetHighLight()
Reset all high light data to the init state.
Definition board.cpp:3547
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:3279
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:3420
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:2715
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:2807
void AddVariant(const wxString &aVariantName)
Definition board.cpp:2813
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:2628
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:3383
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:3838
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:2703
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:3595
void OnRatsnestChanged()
Notify the board and its listeners that the ratsnest has been recomputed.
Definition board.cpp:3541
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource) const
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition board.cpp:2181
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:3324
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:3215
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:3855
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:3952
wxString GetVariantDescription(const wxString &aVariantName) const
Definition board.cpp:2900
FOOTPRINT * FindFootprintByReference(const wxString &aReference) const
Search for a FOOTPRINT within this board with the given reference designator.
Definition board.cpp:2691
unsigned GetNodesCount(int aNet=-1) const
Definition board.cpp:2334
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Definition board.cpp:2139
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:3164
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:2727
void UncacheItemByPtr(const BOARD_ITEM *aItem)
Remove every cache entry that still points to aItem.
Definition board.cpp:2017
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:3934
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:2420
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
Definition board.cpp:3581
void RenameVariant(const wxString &aOldName, const wxString &aNewName)
Definition board.cpp:2852
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:2261
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:2040
int RepairDuplicateItemUuids()
Rebind duplicate attached-item UUIDs so each live board item has a unique ID.
Definition board.cpp:2066
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition board.cpp:2761
std::unordered_map< KIID, BOARD_ITEM * > m_itemByIdCache
Definition board.h:1643
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
Definition board.cpp:3504
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:2351
bool SynchronizeComponentClasses(const std::unordered_set< wxString > &aNewSheetPaths) const
Copy component class / component class generator information from the project settings.
Definition board.cpp:2986
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:3571
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:2950
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:3528
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:2919
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:3410
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:286
virtual void ClearEditFlags()
Definition eda_item.h:170
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:156
const KIID m_Uuid
Definition eda_item.h:535
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:339
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:156
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:160
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_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, LENGTH_DELAY_ITEM_DETAILS *aPerItemLengthDelays=nullptr) const
Calculates the electrical length of the given items.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
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:104
int GetNetCode() const
Definition netinfo.h:98
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:260
static const int ORPHANED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition netinfo.h:264
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:268
unsigned GetNetCount() const
Definition netinfo.h:248
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
Definition netinfo.h:251
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:65
VECTOR2I GetPosition() const override
Definition pad.h:219
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:218
@ 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:3685
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition board.cpp:3664
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.