KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_sheet_path.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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <refdes_utils.h>
27#include <hash.h>
28#include <sch_screen.h>
29#include <sch_marker.h>
30#include <sch_label.h>
31#include <sch_shape.h>
32#include <sch_sheet_path.h>
33#include <sch_symbol.h>
34#include <sch_sheet.h>
35#include <schematic.h>
36#include <string_utils.h>
37#include <template_fieldnames.h>
38#include <trace_helpers.h>
39
40#include <wx/filename.h>
41#include <wx/log.h>
42
43
50{
51public:
53 SCH_ITEM( nullptr, NOT_USED )
54 {}
55
56 wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override
57 {
58 return _( "(Deleted Item)" );
59 }
60
61 wxString GetClass() const override
62 {
63 return wxT( "DELETED_SHEET_ITEM" );
64 }
65
67 {
68 static DELETED_SHEET_ITEM* item = nullptr;
69
70 if( !item )
71 item = new DELETED_SHEET_ITEM();
72
73 return item;
74 }
75
76 // pure virtuals:
77 void SetPosition( const VECTOR2I& ) override {}
78 void Move( const VECTOR2I& aMoveVector ) override {}
79 void MirrorHorizontally( int aCenter ) override {}
80 void MirrorVertically( int aCenter ) override {}
81 void Rotate( const VECTOR2I& aCenter, bool aRotateCCW ) override {}
82
83 double Similarity( const SCH_ITEM& aOther ) const override
84 {
85 return 0.0;
86 }
87
88 bool operator==( const SCH_ITEM& aOther ) const override
89 {
90 return false;
91 }
92
93#if defined(DEBUG)
94 void Show( int , std::ostream& ) const override {}
95#endif
96};
97
98
107
108
110{
111 m_DNP = aSheet.GetDNP();
115 m_ExcludedFromPosFiles = false; // Sheets don't have position files exclusion
116}
117
118
119namespace std
120{
122 {
123 return path.GetCurrentHash();
124 }
125}
126
127
133
134
136{
137 initFromOther( aOther );
138}
139
140
142{
143 initFromOther( aOther );
144 return *this;
145}
146
147
148// Move assignment operator
150{
151 m_sheets = std::move( aOther.m_sheets );
152
153 m_virtualPageNumber = aOther.m_virtualPageNumber;
154 m_current_hash = aOther.m_current_hash;
155 m_cached_page_number = aOther.m_cached_page_number;
156
157 m_recursion_test_cache = std::move( aOther.m_recursion_test_cache );
158
159 return *this;
160}
161
162
164{
165 SCH_SHEET_PATH retv = *this;
166
167 size_t size = aOther.size();
168
169 for( size_t i = 0; i < size; i++ )
170 retv.push_back( aOther.at( i ) );
171
172 return retv;
173}
174
175
177{
178 m_sheets = aOther.m_sheets;
182
183 // Note: don't copy m_recursion_test_cache as it is slow and we want std::vector<SCH_SHEET_PATH>
184 // to be very fast to construct for use in the connectivity algorithm.
186}
187
189{
190 m_current_hash = 0;
191
192 for( SCH_SHEET* sheet : m_sheets )
193 hash_combine( m_current_hash, sheet->m_Uuid.Hash() );
194}
195
196
197int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
198{
199 if( size() > aSheetPathToTest.size() )
200 return 1;
201
202 if( size() < aSheetPathToTest.size() )
203 return -1;
204
205 // otherwise, same number of sheets.
206 for( unsigned i = 0; i < size(); i++ )
207 {
208 if( at( i )->m_Uuid < aSheetPathToTest.at( i )->m_Uuid )
209 return -1;
210
211 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
212 return 1;
213 }
214
215 return 0;
216}
217
218
219int SCH_SHEET_PATH::ComparePageNum( const SCH_SHEET_PATH& aSheetPathToTest ) const
220{
221 wxString pageA = this->GetPageNumber();
222 wxString pageB = aSheetPathToTest.GetPageNumber();
223
224 int pageNumComp = SCH_SHEET::ComparePageNum( pageA, pageB );
225
226 if( pageNumComp == 0 )
227 {
228 int virtualPageA = GetVirtualPageNumber();
229 int virtualPageB = aSheetPathToTest.GetVirtualPageNumber();
230
231 if( virtualPageA > virtualPageB )
232 pageNumComp = 1;
233 else if( virtualPageA < virtualPageB )
234 pageNumComp = -1;
235 }
236
237 return pageNumComp;
238}
239
240
241bool SCH_SHEET_PATH::IsContainedWithin( const SCH_SHEET_PATH& aSheetPathToTest ) const
242{
243 if( aSheetPathToTest.size() > size() )
244 return false;
245
246 for( size_t i = 0; i < aSheetPathToTest.size(); ++i )
247 {
248 if( at( i )->m_Uuid != aSheetPathToTest.at( i )->m_Uuid )
249 {
250 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is not within path '%s'.",
251 aSheetPathToTest.Path().AsString(), Path().AsString() );
252
253 return false;
254 }
255 }
256
257 wxLogTrace( traceSchSheetPaths, "Sheet path '%s' is within path '%s'.",
258 aSheetPathToTest.Path().AsString(), Path().AsString() );
259
260 return true;
261}
262
263
265{
266 if( !empty() )
267 return m_sheets.back();
268
269 return nullptr;
270}
271
272
274{
275 SCH_SHEET* lastSheet = Last();
276
277 if( lastSheet )
278 return lastSheet->GetScreen();
279
280 return nullptr;
281}
282
283
285{
286 SCH_SHEET* lastSheet = Last();
287
288 if( lastSheet )
289 return lastSheet->GetScreen();
290
291 return nullptr;
292}
293
294
296{
297 for( SCH_SHEET* sheet : m_sheets )
298 {
299 if( sheet->GetExcludedFromSim() )
300 return true;
301 }
302
303 return false;
304}
305
306
307bool SCH_SHEET_PATH::GetExcludedFromSim( const wxString& aVariantName ) const
308{
309 if( aVariantName.IsEmpty() )
310 return GetExcludedFromSim();
311
312 for( SCH_SHEET* sheet : m_sheets )
313 {
314 if( sheet->GetExcludedFromSim( this, aVariantName ) )
315 return true;
316 }
317
318 return false;
319}
320
321
323{
324 for( SCH_SHEET* sheet : m_sheets )
325 {
326 if( sheet->GetExcludedFromBOM() )
327 return true;
328 }
329
330 return false;
331}
332
333
334bool SCH_SHEET_PATH::GetExcludedFromBOM( const wxString& aVariantName ) const
335{
336 if( aVariantName.IsEmpty() )
337 return GetExcludedFromBOM();
338
339 for( SCH_SHEET* sheet : m_sheets )
340 {
341 if( sheet->GetExcludedFromBOM( this, aVariantName ) )
342 return true;
343 }
344
345 return false;
346}
347
348
350{
351 for( SCH_SHEET* sheet : m_sheets )
352 {
353 if( sheet->GetExcludedFromBoard() )
354 return true;
355 }
356
357 return false;
358}
359
360
361bool SCH_SHEET_PATH::GetExcludedFromBoard( const wxString& aVariantName ) const
362{
363 if( aVariantName.IsEmpty() )
364 return GetExcludedFromBoard();
365
366 for( SCH_SHEET* sheet : m_sheets )
367 {
368 if( sheet->GetExcludedFromBoard( this, aVariantName ) )
369 return true;
370 }
371
372 return false;
373}
374
375
377{
378 for( SCH_SHEET* sheet : m_sheets )
379 {
380 if( sheet->GetDNP() )
381 return true;
382 }
383
384 return false;
385}
386
387
388bool SCH_SHEET_PATH::GetDNP( const wxString& aVariantName ) const
389{
390 if( aVariantName.IsEmpty() )
391 return GetDNP();
392
393 for( SCH_SHEET* sheet : m_sheets )
394 {
395 if( sheet->GetDNP( this, aVariantName ) )
396 return true;
397 }
398
399 return false;
400}
401
402
404{
405 wxString s;
406
407 s = wxT( "/" ); // This is the root path
408
409 // Start at 1 to avoid the root sheet, which does not need to be added to the path.
410 // Its timestamp changes anyway.
411 for( unsigned i = 1; i < size(); i++ )
412 s += at( i )->m_Uuid.AsString() + "/";
413
414 return s;
415}
416
417
419{
421 size_t size = m_sheets.size();
422
423 if( m_sheets.empty() )
424 return path;
425
426 if( m_sheets[0]->m_Uuid != niluuid )
427 {
428 path.reserve( size );
429 path.push_back( m_sheets[0]->m_Uuid );
430 }
431 else
432 {
433 // Skip the virtual root
434 path.reserve( size - 1 );
435 }
436
437 for( size_t i = 1; i < size; i++ )
438 path.push_back( m_sheets[i]->m_Uuid );
439
440 return path;
441}
442
443
444wxString SCH_SHEET_PATH::PathHumanReadable( bool aUseShortRootName,
445 bool aStripTrailingSeparator,
446 bool aEscapeSheetNames ) const
447{
448 wxString s;
449
450 // Determine the starting index - skip virtual root if present
451 size_t startIdx = 0;
452
453 if( !empty() && at( 0 )->IsVirtualRootSheet() )
454 startIdx = 1;
455
456 if( aUseShortRootName )
457 {
458 s = wxS( "/" ); // Use only the short name in netlists
459 }
460 else
461 {
462 wxString fileName;
463
464 if( size() > startIdx && at( startIdx )->GetScreen() )
465 fileName = at( startIdx )->GetScreen()->GetFileName();
466
467 wxFileName fn = fileName;
468
469 s = fn.GetName() + wxS( "/" );
470 }
471
472 // Start at startIdx + 1 since we've already processed the root sheet.
473 for( unsigned i = startIdx + 1; i < size(); i++ )
474 {
475 wxString sheetName = at( i )->GetField( FIELD_T::SHEET_NAME )->GetShownText( false );
476
477 if( aEscapeSheetNames )
478 sheetName = EscapeString( sheetName, CTX_NETNAME );
479
480 s << sheetName << wxS( "/" );
481 }
482
483 if( aStripTrailingSeparator && s.EndsWith( "/" ) )
484 s = s.Left( s.length() - 1 );
485
486 return s;
487}
488
489
491{
492 std::vector<SCH_ITEM*> items;
493
494 std::copy_if( LastScreen()->Items().begin(), LastScreen()->Items().end(),
495 std::back_inserter( items ),
496 []( SCH_ITEM* aItem )
497 {
498 return ( aItem->Type() == SCH_SYMBOL_T
499 || aItem->Type() == SCH_GLOBAL_LABEL_T
500 || aItem->Type() == SCH_SHAPE_T );
501 } );
502
503 std::optional<wxString> variantName;
504 const SCHEMATIC* schematic = LastScreen()->Schematic();
505
506 if( schematic )
507 variantName = schematic->GetCurrentVariant();
508
509 for( SCH_ITEM* item : items )
510 {
511 if( item->Type() == SCH_SYMBOL_T )
512 {
513 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
514
515 symbol->GetField( FIELD_T::REFERENCE )->SetText( symbol->GetRef( this ) );
516 symbol->SetUnit( symbol->GetUnitSelection( this ) );
517 LastScreen()->Update( item, false );
518 }
519 else if( item->Type() == SCH_GLOBAL_LABEL_T )
520 {
521 SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( item );
522
523 if( label->GetFields().size() > 0 ) // Possible when reading a legacy .sch schematic
524 {
525 SCH_FIELD* intersheetRefs = label->GetField( FIELD_T::INTERSHEET_REFS );
526
527 // Fixup for legacy files which didn't store a position for the intersheet refs
528 // unless they were shown.
529 if( intersheetRefs->GetPosition() == VECTOR2I() && !intersheetRefs->IsVisible() )
531
532 intersheetRefs->SetVisible( label->Schematic()->Settings().m_IntersheetRefsShow );
533 LastScreen()->Update( intersheetRefs );
534 }
535 }
536 else if( item->Type() == SCH_SHAPE_T )
537 {
538 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
539 shape->UpdateHatching();
540 }
541 }
542}
543
544
545void SCH_SHEET_PATH::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
546 bool aForceIncludeOrphanSymbols ) const
547{
548 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
549 {
550 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
551 AppendSymbol( aReferences, symbol, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
552 }
553}
554
555
557 bool aIncludePowerSymbols,
558 bool aForceIncludeOrphanSymbols ) const
559{
560 // Skip pseudo-symbols, which have a reference starting with #. This mainly
561 // affects power symbols.
562 if( aIncludePowerSymbols || aSymbol->GetRef( this )[0] != wxT( '#' ) )
563 {
564 if( aSymbol->GetLibSymbolRef() || aForceIncludeOrphanSymbols )
565 {
566 SCH_REFERENCE schReference( aSymbol, *this );
567
568 schReference.SetSheetNumber( GetPageNumberAsInt() );
569 aReferences.AddItem( schReference );
570 }
571 }
572}
573
574
576 bool aIncludePowerSymbols ) const
577{
578 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
579 {
580 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
581 AppendMultiUnitSymbol( aRefList, symbol, aIncludePowerSymbols );
582 }
583}
584
585
587 SCH_SYMBOL* aSymbol,
588 bool aIncludePowerSymbols ) const
589{
590 // Skip pseudo-symbols, which have a reference starting with #. This mainly
591 // affects power symbols.
592 if( !aIncludePowerSymbols && aSymbol->GetRef( this )[0] == wxT( '#' ) )
593 return;
594
595 LIB_SYMBOL* symbol = aSymbol->GetLibSymbolRef().get();
596
597 if( symbol && symbol->GetUnitCount() > 1 )
598 {
599 SCH_REFERENCE schReference = SCH_REFERENCE( aSymbol, *this );
600 schReference.SetSheetNumber( GetPageNumberAsInt() );
601 wxString reference_str = schReference.GetRef();
602
603 // Never lock unassigned references
604 if( reference_str[reference_str.Len() - 1] == '?' )
605 return;
606
607 aRefList[reference_str].AddItem( schReference );
608 }
609}
610
611
613{
614 return m_current_hash == d1.GetCurrentHash();
615}
616
617
618bool SCH_SHEET_PATH::TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName )
619{
620 auto pair = std::make_pair( aSrcFileName, aDestFileName );
621
622 if( m_recursion_test_cache.count( pair ) )
623 return m_recursion_test_cache.at( pair );
624
625 SCHEMATIC* sch = LastScreen()->Schematic();
626
627 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_PATH::TestForRecursion!" );
628
629 wxFileName rootFn = sch->GetFileName();
630 wxFileName srcFn = aSrcFileName;
631 wxFileName destFn = aDestFileName;
632
633 if( srcFn.IsRelative() )
634 srcFn.MakeAbsolute( rootFn.GetPath() );
635
636 if( destFn.IsRelative() )
637 destFn.MakeAbsolute( rootFn.GetPath() );
638
639 // The source and destination sheet file names cannot be the same.
640 if( srcFn == destFn )
641 {
642 m_recursion_test_cache[pair] = true;
643 return true;
644 }
645
649 unsigned i = 0;
650
651 while( i < size() )
652 {
653 wxFileName cmpFn = at( i )->GetFileName();
654
655 if( cmpFn.IsRelative() )
656 cmpFn.MakeAbsolute( rootFn.GetPath() );
657
658 // Test if the file name of the destination sheet is in anywhere in this sheet path.
659 if( cmpFn == destFn )
660 break;
661
662 i++;
663 }
664
665 // The destination sheet file name was not found in the sheet path or the destination
666 // sheet file name is the root sheet so no recursion is possible.
667 if( i >= size() || i == 0 )
668 {
669 m_recursion_test_cache[pair] = false;
670 return false;
671 }
672
673 // Walk back up to the root sheet to see if the source file name is already a parent in
674 // the sheet path. If so, recursion will occur.
675 do
676 {
677 i -= 1;
678
679 wxFileName cmpFn = at( i )->GetFileName();
680
681 if( cmpFn.IsRelative() )
682 cmpFn.MakeAbsolute( rootFn.GetPath() );
683
684 if( cmpFn == srcFn )
685 {
686 m_recursion_test_cache[pair] = true;
687 return true;
688 }
689
690 } while( i != 0 );
691
692 // The source sheet file name is not a parent of the destination sheet file name.
693 m_recursion_test_cache[pair] = false;
694 return false;
695}
696
697
699{
700 SCH_SHEET* sheet = Last();
701
702 wxCHECK( sheet, wxEmptyString );
703
704 KIID_PATH tmpPath = Path();
705
706 if( !tmpPath.empty() )
707 tmpPath.pop_back();
708 else
709 return wxEmptyString;
710
711 return sheet->getPageNumber( tmpPath );
712}
713
715{
716 long page;
717 wxString pageStr = GetPageNumber();
718
719 if( pageStr.ToLong( &page ) )
720 return (int) page;
721
722 return GetVirtualPageNumber();
723}
724
725
726void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
727{
728 SCH_SHEET* sheet = Last();
729
730 wxCHECK( sheet, /* void */ );
731
732 KIID_PATH tmpPath = Path();
733
734 if( !tmpPath.empty() )
735 {
736 tmpPath.pop_back();
737 }
738 else
739 {
740 wxCHECK_MSG( false, /* void */, wxS( "Sheet paths must have a least one valid sheet." ) );
741 }
742
743 sheet->addInstance( tmpPath );
744 sheet->setPageNumber( tmpPath, aPageNumber );
745}
746
747
749 const wxString& aProjectName )
750{
751 wxCHECK( !aProjectName.IsEmpty(), /* void */ );
752
753 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
754 SCH_SHEET_PATH currentSheetPath( *this );
755
756 // Prefix the new hierarchical path.
757 newSheetPath = newSheetPath + currentSheetPath;
758
759 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
760 {
761 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
762
763 wxCHECK2( symbol, continue );
764
765 SCH_SYMBOL_INSTANCE newSymbolInstance;
766
767 if( symbol->GetInstance( newSymbolInstance, Path(), true ) )
768 {
769 newSymbolInstance.m_ProjectName = aProjectName;
770
771 // Use an existing symbol instance for this path if it exists.
772 newSymbolInstance.m_Path = newSheetPath.Path();
773 symbol->AddHierarchicalReference( newSymbolInstance );
774 }
775 else if( !symbol->GetInstances().empty() )
776 {
777 newSymbolInstance.m_ProjectName = aProjectName;
778
779 // Use the first symbol instance if any symbol instance data exists.
780 newSymbolInstance = symbol->GetInstances()[0];
781 newSymbolInstance.m_Path = newSheetPath.Path();
782 symbol->AddHierarchicalReference( newSymbolInstance );
783 }
784 else
785 {
786 newSymbolInstance.m_ProjectName = aProjectName;
787
788 // Fall back to the last saved symbol field and unit settings if there is no
789 // instance data.
790 newSymbolInstance.m_Path = newSheetPath.Path();
791 newSymbolInstance.m_Reference = symbol->GetField( FIELD_T::REFERENCE )->GetText();
792 newSymbolInstance.m_Unit = symbol->GetUnit();
793 symbol->AddHierarchicalReference( newSymbolInstance );
794 }
795 }
796}
797
798
800{
801 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
802 {
803 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
804
805 wxCHECK2( symbol, continue );
806
807 SCH_SHEET_PATH fullSheetPath( aPrefixSheetPath );
808 SCH_SHEET_PATH currentSheetPath( *this );
809
810 // Prefix the hierarchical path of the symbol instance to be removed.
811 fullSheetPath = fullSheetPath + currentSheetPath;
812 symbol->RemoveInstance( fullSheetPath );
813 }
814}
815
816
817void SCH_SHEET_PATH::CheckForMissingSymbolInstances( const wxString& aProjectName )
818{
819 // Skip sheet paths without screens (e.g., sheets that haven't been loaded yet or virtual root)
820 if( aProjectName.IsEmpty() || !LastScreen() )
821 return;
822
823 wxLogTrace( traceSchSheetPaths, "CheckForMissingSymbolInstances for path: %s (project: %s)",
824 PathHumanReadable( false ), aProjectName );
825 wxLogTrace( traceSchSheetPaths, " Sheet path size=%zu, Path().AsString()='%s'",
826 size(), Path().AsString() );
827
828 for( SCH_ITEM* item : LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
829 {
830 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
831
832 wxCHECK2( symbol, continue );
833
834 SCH_SYMBOL_INSTANCE symbolInstance;
835
836 if( !symbol->GetInstance( symbolInstance, Path() ) )
837 {
838 wxLogTrace( traceSchSheetPaths, "Adding missing symbol \"%s\" instance data for "
839 "sheet path '%s'.",
840 symbol->m_Uuid.AsString(), PathHumanReadable( false ) );
841
842 // Legacy schematics that are not shared do not contain separate instance data.
843 // The symbol reference and unit are saved in the reference field and unit entries.
844 if( ( LastScreen()->GetRefCount() <= 1 ) &&
845 ( LastScreen()->GetFileFormatVersionAtLoad() <= 20200310 ) )
846 {
847 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
848 symbolInstance.m_Reference = refField->GetShownText( this, true );
849 symbolInstance.m_Unit = symbol->GetUnit();
850
851 wxLogTrace( traceSchSheetPaths,
852 " Legacy format: Using reference '%s' from field, unit %d",
853 symbolInstance.m_Reference, symbolInstance.m_Unit );
854 }
855 else if( !symbol->GetInstances().empty() )
856 {
857 // When a schematic is opened as a different project (e.g., a subsheet opened
858 // directly from File Browser), use the first available instance data.
859 // This provides better UX than showing unannotated references.
860 const SCH_SYMBOL_INSTANCE& firstInstance = symbol->GetInstances()[0];
861 symbolInstance.m_Reference = firstInstance.m_Reference;
862 symbolInstance.m_Unit = firstInstance.m_Unit;
863
864 wxLogTrace( traceSchSheetPaths,
865 " Using first available instance: ref=%s, unit=%d",
866 symbolInstance.m_Reference, symbolInstance.m_Unit );
867 }
868 else
869 {
870 // Fall back to the symbol's reference field and unit if no instance data exists.
871 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
872 symbolInstance.m_Reference = refField->GetText();
873 symbolInstance.m_Unit = symbol->GetUnit();
874
875 wxLogTrace( traceSchSheetPaths,
876 " No instance data: Using reference '%s' from field, unit %d",
877 symbolInstance.m_Reference, symbolInstance.m_Unit );
878 }
879
880 symbolInstance.m_ProjectName = aProjectName;
881 symbolInstance.m_Path = Path();
882 symbol->AddHierarchicalReference( symbolInstance );
883
884 wxLogTrace( traceSchSheetPaths,
885 " Created instance: ref=%s, path=%s",
886 symbolInstance.m_Reference, symbolInstance.m_Path.AsString() );
887 }
888 else
889 {
890 wxLogTrace( traceSchSheetPaths,
891 " Symbol %s already has instance: ref=%s, path=%s",
892 symbol->m_Uuid.AsString(),
893 symbolInstance.m_Reference,
894 symbolInstance.m_Path.AsString() );
895 }
896 }
897}
898
899
901{
902 wxCHECK( m_sheets.size() > 1, /* void */ );
903
904 wxFileName sheetFileName = Last()->GetFileName();
905
906 // If the sheet file name is absolute, then the user requested is so don't make it relative.
907 if( sheetFileName.IsAbsolute() )
908 return;
909
910 SCH_SCREEN* screen = LastScreen();
911 SCH_SCREEN* parentScreen = m_sheets[ m_sheets.size() - 2 ]->GetScreen();
912
913 wxCHECK( screen && parentScreen, /* void */ );
914
915 wxFileName fileName = screen->GetFileName();
916 wxFileName parentFileName = parentScreen->GetFileName();
917
918 // SCH_SCREEN file names must be absolute. If they are not, someone set them incorrectly
919 // on load or on creation.
920 wxCHECK( fileName.IsAbsolute() && parentFileName.IsAbsolute(), /* void */ );
921
922 if( fileName.GetPath() == parentFileName.GetPath() )
923 {
924 Last()->SetFileName( fileName.GetFullName() );
925 }
926 else if( fileName.MakeRelativeTo( parentFileName.GetPath() ) )
927 {
928 Last()->SetFileName( fileName.GetFullPath() );
929 }
930 else
931 {
932 Last()->SetFileName( screen->GetFileName() );
933 }
934
935 wxLogTrace( tracePathsAndFiles,
936 wxT( "\n File name: '%s'"
937 "\n parent file name '%s',"
938 "\n sheet '%s' file name '%s'." ),
939 screen->GetFileName(), parentScreen->GetFileName(), PathHumanReadable(),
940 Last()->GetFileName() );
941}
942
943
945{
946 if( aSheet != nullptr )
947 BuildSheetList( aSheet, false );
948}
949
950
951void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
952{
953 if( !aSheet )
954 return;
955
956 wxLogTrace( traceSchSheetPaths,
957 "BuildSheetList called with sheet '%s' (UUID=%s, isVirtualRoot=%d)",
958 aSheet->GetName(),
959 aSheet->m_Uuid.AsString(),
960 aSheet->m_Uuid == niluuid ? 1 : 0 );
961
962 // Special handling for virtual root: process its children without adding the root itself
963 if( aSheet->IsVirtualRootSheet() )
964 {
965 wxLogTrace( traceSchSheetPaths, " Skipping virtual root, processing children only" );
966
967 if( aSheet->GetScreen() )
968 {
969 std::vector<SCH_ITEM*> childSheets;
970 aSheet->GetScreen()->GetSheets( &childSheets );
971
972 for( SCH_ITEM* item : childSheets )
973 {
974 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
975 BuildSheetList( sheet, aCheckIntegrity );
976 }
977 }
978
979 return;
980 }
981
982 std::vector<SCH_SHEET*> badSheets;
983
984 m_currentSheetPath.push_back( aSheet );
985 m_currentSheetPath.SetVirtualPageNumber( static_cast<int>( size() ) + 1 );
986 push_back( m_currentSheetPath );
987
988 if( m_currentSheetPath.LastScreen() )
989 {
990 wxString parentFileName = aSheet->GetFileName();
991 std::vector<SCH_ITEM*> childSheets;
992 m_currentSheetPath.LastScreen()->GetSheets( &childSheets );
993
994 for( SCH_ITEM* item : childSheets )
995 {
996 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
997
998 if( aCheckIntegrity )
999 {
1000 if( !m_currentSheetPath.TestForRecursion( sheet->GetFileName(), parentFileName ) )
1001 BuildSheetList( sheet, true );
1002 else
1003 badSheets.push_back( sheet );
1004 }
1005 else
1006 {
1007 // If we are not performing a full recursion test, at least check if we are in
1008 // a simple recursion scenario to prevent stack overflow crashes
1009 wxCHECK2_MSG( sheet->GetFileName() != aSheet->GetFileName(), continue,
1010 wxT( "Recursion prevented in SCH_SHEET_LIST::BuildSheetList" ) );
1011
1012 BuildSheetList( sheet, false );
1013 }
1014 }
1015 }
1016
1017 if( aCheckIntegrity )
1018 {
1019 for( SCH_SHEET* sheet : badSheets )
1020 {
1021 m_currentSheetPath.LastScreen()->Remove( sheet );
1022 m_currentSheetPath.LastScreen()->SetContentModified();
1023 }
1024 }
1025
1026 m_currentSheetPath.pop_back();
1027}
1028
1029
1030void SCH_SHEET_LIST::SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums )
1031{
1032 for( const SCH_SHEET_PATH& path : *this )
1033 path.CachePageNumber();
1034
1035 std::sort( begin(), end(),
1036 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
1037 {
1038 // Find the divergence point in the paths
1039 size_t common_len = 0;
1040 size_t min_len = std::min( a.size(), b.size() );
1041
1042 while( common_len < min_len && a.at( common_len )->m_Uuid == b.at( common_len )->m_Uuid )
1043 common_len++;
1044
1045 // If one path is a prefix of the other, the shorter one comes first
1046 // This ensures parents come before children
1047 if( common_len == a.size() )
1048 return true; // a is a prefix of b - a is the parent
1049 if( common_len == b.size() )
1050 return false; // b is a prefix of a - b is the parent
1051
1052 // Paths diverge at common_len
1053 // If they share the same parent, sort by page number
1054 // This ensures siblings are sorted by page number
1055 SCH_SHEET* sheet_a = a.at( common_len );
1056 SCH_SHEET* sheet_b = b.at( common_len );
1057
1058 // Create partial paths to get to these sheets for page number comparison
1059 KIID_PATH ancestor;
1060 for( size_t i = 0; i < common_len; i++ )
1061 ancestor.push_back( a.at( i )->m_Uuid );
1062
1063 // Compare page numbers - use the last sheet's page number
1064 wxString page_a = sheet_a->getPageNumber( ancestor );
1065 wxString page_b = sheet_b->getPageNumber( ancestor );
1066
1067 int retval = SCH_SHEET::ComparePageNum( page_a, page_b );
1068
1069 if( retval != 0 )
1070 return retval < 0;
1071
1072 // If page numbers are the same, use virtual page numbers as a tie-breaker
1074 return true;
1075 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
1076 return false;
1077
1078 // Finally, use UUIDs for stable ordering when everything else is equal
1079 return a.GetCurrentHash() < b.GetCurrentHash();
1080 } );
1081
1082 if( aUpdateVirtualPageNums )
1083 {
1084 int virtualPageNum = 1;
1085
1086 for( SCH_SHEET_PATH& sheet : *this )
1087 sheet.SetVirtualPageNumber( virtualPageNum++ );
1088 }
1089}
1090
1091
1092void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
1093{
1094 for( const SCH_SHEET_PATH& path : *this )
1095 path.CachePageNumber();
1096
1097 std::sort( begin(), end(),
1098 []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
1099 {
1101 b.GetCachedPageNumber() );
1102
1103 if( retval < 0 )
1104 return true;
1105 else if( retval > 0 )
1106 return false;
1107
1109 return true;
1110 else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
1111 return false;
1112
1113 // Enforce strict ordering. If the page numbers are the same, use UUIDs
1114 return a.GetCurrentHash() < b.GetCurrentHash();
1115 } );
1116
1117 if( aUpdateVirtualPageNums )
1118 {
1119 int virtualPageNum = 1;
1120
1121 for( SCH_SHEET_PATH& sheet : *this )
1122 sheet.SetVirtualPageNumber( virtualPageNum++ );
1123 }
1124}
1125
1126
1127bool SCH_SHEET_LIST::NameExists( const wxString& aSheetName ) const
1128{
1129 for( const SCH_SHEET_PATH& sheet : *this )
1130 {
1131 if( sheet.Last()->GetName() == aSheetName )
1132 return true;
1133 }
1134
1135 return false;
1136}
1137
1138
1139bool SCH_SHEET_LIST::PageNumberExists( const wxString& aPageNumber ) const
1140{
1141 for( const SCH_SHEET_PATH& sheet : *this )
1142 {
1143 if( sheet.GetPageNumber() == aPageNumber )
1144 return true;
1145 }
1146
1147 return false;
1148}
1149
1150
1151void SCH_SHEET_LIST::TrimToPageNumbers( const std::vector<wxString>& aPageInclusions )
1152{
1153 auto it = std::remove_if( begin(), end(),
1154 [&]( const SCH_SHEET_PATH& sheet )
1155 {
1156 return std::find( aPageInclusions.begin(),
1157 aPageInclusions.end(),
1158 sheet.GetPageNumber() ) == aPageInclusions.end();
1159 } );
1160
1161 erase( it, end() );
1162}
1163
1164
1166{
1167 for( const SCH_SHEET_PATH& sheet : *this )
1168 {
1169 if( sheet.LastScreen() && sheet.LastScreen()->IsContentModified() )
1170 return true;
1171 }
1172
1173 return false;
1174}
1175
1176
1178{
1179 for( const SCH_SHEET_PATH& sheet : *this )
1180 {
1181 if( sheet.LastScreen() )
1182 sheet.LastScreen()->SetContentModified( false );
1183 }
1184}
1185
1186
1187SCH_ITEM* SCH_SHEET_LIST::ResolveItem( const KIID& aID, SCH_SHEET_PATH* aPathOut, bool aAllowNullptrReturn ) const
1188{
1189 for( const SCH_SHEET_PATH& sheet : *this )
1190 {
1191 SCH_ITEM* item = sheet.ResolveItem( aID );
1192
1193 if( item )
1194 {
1195 if( aPathOut )
1196 *aPathOut = sheet;
1197
1198 return item;
1199 }
1200 }
1201
1202 // Not found; weak reference has been deleted.
1203 if( aAllowNullptrReturn )
1204 return nullptr;
1205 else
1207}
1208
1209
1211{
1212 for( SCH_ITEM* aItem : LastScreen()->Items() )
1213 {
1214 if( aItem->m_Uuid == aID )
1215 return aItem;
1216
1217 SCH_ITEM* childMatch = nullptr;
1218
1219 aItem->RunOnChildren(
1220 [&]( SCH_ITEM* aChild )
1221 {
1222 if( aChild->m_Uuid == aID )
1223 childMatch = aChild;
1224 },
1226
1227 if( childMatch )
1228 return childMatch;
1229 }
1230
1231 return nullptr;
1232}
1233
1234
1235void SCH_SHEET_LIST::FillItemMap( std::map<KIID, EDA_ITEM*>& aMap )
1236{
1237 for( const SCH_SHEET_PATH& sheet : *this )
1238 {
1239 SCH_SCREEN* screen = sheet.LastScreen();
1240
1241 for( SCH_ITEM* aItem : screen->Items() )
1242 {
1243 aMap[ aItem->m_Uuid ] = aItem;
1244
1245 aItem->RunOnChildren(
1246 [&]( SCH_ITEM* aChild )
1247 {
1248 aMap[ aChild->m_Uuid ] = aChild;
1249 },
1251 }
1252 }
1253}
1254
1255
1257{
1258 // List of reference for power symbols
1259 SCH_REFERENCE_LIST references;
1260
1261 // Map of locked symbols (not used, but needed by Annotate()
1262 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
1263
1264 // Build the list of power symbols:
1265 for( SCH_SHEET_PATH& sheet : *this )
1266 {
1267 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1268 {
1269 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1270 LIB_SYMBOL* libSymbol = symbol->GetLibSymbolRef().get();
1271
1272 if( libSymbol && libSymbol->IsPower() )
1273 {
1274 SCH_REFERENCE schReference( symbol, sheet );
1275 references.AddItem( schReference );
1276 }
1277 }
1278 }
1279
1280 // Find duplicate, and silently clear annotation of duplicate
1281 std::map<wxString, int> ref_list; // stores the existing references
1282
1283 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1284 {
1285 wxString curr_ref = references[ii].GetRef();
1286
1287 if( curr_ref.IsEmpty() )
1288 continue;
1289
1290 if( ref_list.find( curr_ref ) == ref_list.end() )
1291 {
1292 ref_list[curr_ref] = ii;
1293 continue;
1294 }
1295
1296 // Possible duplicate, if the ref ends by a number:
1297 if( curr_ref.Last() < '0' && curr_ref.Last() > '9' )
1298 continue; // not annotated
1299
1300 // Duplicate: clear annotation by removing the number ending the ref
1301 while( !curr_ref.IsEmpty() && curr_ref.Last() >= '0' && curr_ref.Last() <= '9' )
1302 curr_ref.RemoveLast();
1303
1304 references[ii].SetRef( curr_ref );
1305 }
1306
1307 // Break full symbol reference into name (prefix) and number:
1308 // example: IC1 become IC, and 1
1309 references.SplitReferences();
1310
1311 // Ensure all power symbols have the reference starting by '#'
1312 // (Not sure this is really useful)
1313 for( unsigned ii = 0; ii< references.GetCount(); ++ii )
1314 {
1315 SCH_REFERENCE& ref_unit = references[ii];
1316
1317 if( ref_unit.GetRef()[0] != '#' )
1318 {
1319 wxString new_ref = "#" + ref_unit.GetRef();
1320 ref_unit.SetRef( new_ref );
1321 ref_unit.SetRefNum( ii );
1322 }
1323 }
1324}
1325
1326
1327void SCH_SHEET_LIST::GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols,
1328 bool aForceIncludeOrphanSymbols ) const
1329{
1330 for( const SCH_SHEET_PATH& sheet : *this )
1331 sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
1332}
1333
1334
1336 const SCH_SHEET_PATH& aSheetPath,
1337 bool aIncludePowerSymbols,
1338 bool aForceIncludeOrphanSymbols ) const
1339{
1340 for( const SCH_SHEET_PATH& sheet : *this )
1341 {
1342 if( sheet.IsContainedWithin( aSheetPath ) )
1343 sheet.GetSymbols( aReferences, aIncludePowerSymbols, aForceIncludeOrphanSymbols );
1344 }
1345}
1346
1347
1348void SCH_SHEET_LIST::GetSheetsWithinPath( std::vector<SCH_SHEET_PATH>& aSheets,
1349 const SCH_SHEET_PATH& aSheetPath ) const
1350{
1351 for( const SCH_SHEET_PATH& sheet : *this )
1352 {
1353 if( sheet.IsContainedWithin( aSheetPath ) )
1354 aSheets.push_back( sheet );
1355 }
1356}
1357
1358
1359std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetSheetPathByKIIDPath( const KIID_PATH& aPath,
1360 bool aIncludeLastSheet ) const
1361{
1362 for( const SCH_SHEET_PATH& sheet : *this )
1363 {
1364 KIID_PATH testPath = sheet.Path();
1365
1366 if( !aIncludeLastSheet )
1367 testPath.pop_back();
1368
1369 if( testPath == aPath )
1370 return SCH_SHEET_PATH( sheet );
1371 }
1372
1373 return std::nullopt;
1374}
1375
1376
1378 bool aIncludePowerSymbols ) const
1379{
1380 for( auto it = begin(); it != end(); ++it )
1381 {
1383 ( *it ).GetMultiUnitSymbols( tempMap, aIncludePowerSymbols );
1384
1385 for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : tempMap )
1386 {
1387 // Merge this list into the main one
1388 unsigned n_refs = pair.second.GetCount();
1389
1390 for( unsigned thisRef = 0; thisRef < n_refs; ++thisRef )
1391 aRefList[pair.first].AddItem( pair.second[thisRef] );
1392 }
1393 }
1394}
1395
1396
1397bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
1398 const wxString& aDestFileName )
1399{
1400 if( empty() )
1401 return false;
1402
1403 SCHEMATIC* sch = at( 0 ).LastScreen()->Schematic();
1404
1405 wxCHECK_MSG( sch, false, "No SCHEMATIC found in SCH_SHEET_LIST::TestForRecursion!" );
1406
1407 wxFileName rootFn = sch->GetFileName();
1408 wxFileName destFn = aDestFileName;
1409
1410 if( destFn.IsRelative() )
1411 destFn.MakeAbsolute( rootFn.GetPath() );
1412
1413 // Test each SCH_SHEET_PATH in this SCH_SHEET_LIST for potential recursion.
1414 for( unsigned i = 0; i < size(); i++ )
1415 {
1416 // Test each SCH_SHEET_PATH in the source sheet.
1417 for( unsigned j = 0; j < aSrcSheetHierarchy.size(); j++ )
1418 {
1419 const SCH_SHEET_PATH* sheetPath = &aSrcSheetHierarchy[j];
1420
1421 for( unsigned k = 0; k < sheetPath->size(); k++ )
1422 {
1423 if( at( i ).TestForRecursion( sheetPath->GetSheet( k )->GetFileName(),
1424 aDestFileName ) )
1425 {
1426 return true;
1427 }
1428 }
1429 }
1430 }
1431
1432 // The source sheet file can safely be added to the destination sheet file.
1433 return false;
1434}
1435
1436
1438{
1439 for( SCH_SHEET_PATH& path : *this )
1440 {
1441 if( path.Path() == aPath->Path() )
1442 return &path;
1443 }
1444
1445 return nullptr;
1446}
1447
1448
1450{
1451 for( SCH_SHEET_PATH& sheetpath : *this )
1452 {
1453 if( sheetpath.LastScreen() == aScreen )
1454 return sheetpath;
1455 }
1456
1457 return SCH_SHEET_PATH();
1458}
1459
1460
1462{
1463 SCH_SHEET_LIST retval;
1464
1465 for( const SCH_SHEET_PATH& sheetpath : *this )
1466 {
1467 if( sheetpath.LastScreen() == aScreen )
1468 retval.push_back( sheetpath );
1469 }
1470
1471 return retval;
1472}
1473
1474
1476 const std::vector<SCH_SYMBOL_INSTANCE>& aSymbolInstances )
1477{
1478 for( SCH_SHEET_PATH& sheetPath : *this )
1479 {
1480 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1481 {
1482 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1483
1484 wxCHECK2( symbol, continue );
1485
1486 KIID_PATH sheetPathWithSymbolUuid = sheetPath.Path();
1487 sheetPathWithSymbolUuid.push_back( symbol->m_Uuid );
1488
1489 auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
1490 [ sheetPathWithSymbolUuid ]( const SCH_SYMBOL_INSTANCE& r ) -> bool
1491 {
1492 return sheetPathWithSymbolUuid == r.m_Path;
1493 } );
1494
1495 if( it == aSymbolInstances.end() )
1496 {
1497 wxLogTrace( traceSchSheetPaths, "No symbol instance found for symbol '%s'",
1498 sheetPathWithSymbolUuid.AsString() );
1499 continue;
1500 }
1501
1502 // Symbol instance paths are stored and looked up in memory with the root path so use
1503 // the full path here.
1504 symbol->AddHierarchicalReference( sheetPath.Path(), it->m_Reference, it->m_Unit );
1505 symbol->GetField( FIELD_T::REFERENCE )->SetText( it->m_Reference );
1506
1507 if( !it->m_Value.IsEmpty() )
1508 symbol->SetValueFieldText( it->m_Value );
1509
1510 if( !it->m_Footprint.IsEmpty() )
1511 symbol->SetFootprintFieldText( it->m_Footprint );
1512
1513 symbol->UpdatePrefix();
1514 }
1515 }
1516}
1517
1518
1519void SCH_SHEET_LIST::UpdateSheetInstanceData( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
1520{
1521
1522 for( SCH_SHEET_PATH& path : *this )
1523 {
1524 SCH_SHEET* sheet = path.Last();
1525
1526 wxCHECK2( sheet && path.Last(), continue );
1527
1528 auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(),
1529 [&path]( const SCH_SHEET_INSTANCE& r ) -> bool
1530 {
1531 return path.Path() == r.m_Path;
1532 } );
1533
1534 if( it == aSheetInstances.end() )
1535 {
1536 wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'",
1537 path.Path().AsString() );
1538 continue;
1539 }
1540
1541 wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
1542 ( sheet->GetName().IsEmpty() ) ? wxString( wxT( "root" ) ) : sheet->GetName(),
1543 path.Path().AsString(), it->m_PageNumber );
1544 path.SetPageNumber( it->m_PageNumber );
1545 }
1546}
1547
1548
1549std::vector<KIID_PATH> SCH_SHEET_LIST::GetPaths() const
1550{
1551 std::vector<KIID_PATH> paths;
1552
1553 for( const SCH_SHEET_PATH& sheetPath : *this )
1554 paths.emplace_back( sheetPath.Path() );
1555
1556 return paths;
1557}
1558
1559
1560std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
1561{
1562 std::vector<SCH_SHEET_INSTANCE> retval;
1563
1564 for( const SCH_SHEET_PATH& path : *this )
1565 {
1566 const SCH_SHEET* sheet = path.Last();
1567
1568 wxCHECK2( sheet, continue );
1569
1570 SCH_SHEET_INSTANCE instance;
1571 SCH_SHEET_PATH tmpPath = path;
1572
1573 tmpPath.pop_back();
1574 instance.m_Path = tmpPath.Path();
1575 instance.m_PageNumber = path.GetPageNumber();
1576
1577 retval.push_back( std::move( instance ) );
1578 }
1579
1580 return retval;
1581}
1582
1583
1585{
1586 for( const SCH_SHEET_PATH& instance : *this )
1587 {
1588 if( !instance.GetPageNumber().IsEmpty() )
1589 return false;
1590 }
1591
1592 return true;
1593}
1594
1595
1597{
1598 // Don't accidentally renumber existing sheets.
1599 wxCHECK( AllSheetPageNumbersEmpty(), /* void */ );
1600
1601 wxString tmp;
1602 int pageNumber = 1;
1603
1604 for( SCH_SHEET_PATH& instance : *this )
1605 {
1606 if( instance.Last()->IsVirtualRootSheet() )
1607 continue;
1608
1609 tmp.Printf( "%d", pageNumber );
1610 instance.SetPageNumber( tmp );
1611 pageNumber += 1;
1612 }
1613}
1614
1615
1617 const wxString& aProjectName )
1618{
1619 for( SCH_SHEET_PATH& sheetPath : *this )
1620 sheetPath.AddNewSymbolInstances( aPrefixSheetPath, aProjectName );
1621}
1622
1623
1625{
1626 for( SCH_SHEET_PATH& sheetPath : *this )
1627 sheetPath.RemoveSymbolInstances( aPrefixSheetPath );
1628}
1629
1630
1632 int aLastVirtualPageNumber )
1633{
1634 wxString pageNumber;
1635 int lastUsedPageNumber = 1;
1636 int nextVirtualPageNumber = aLastVirtualPageNumber;
1637
1638 // Fetch the list of page numbers already in use.
1639 std::vector< wxString > usedPageNumbers;
1640
1641 if( aPrefixSheetPath.size() )
1642 {
1643 SCH_SHEET_LIST prefixHierarchy( aPrefixSheetPath.at( 0 ) );
1644
1645 for( const SCH_SHEET_PATH& path : prefixHierarchy )
1646 {
1647 pageNumber = path.GetPageNumber();
1648
1649 if( !pageNumber.IsEmpty() )
1650 usedPageNumbers.emplace_back( pageNumber );
1651 }
1652 }
1653
1654 for( SCH_SHEET_PATH& sheetPath : *this )
1655 {
1656 KIID_PATH tmp = sheetPath.Path();
1657 SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
1658
1659 // Prefix the new hierarchical path.
1660 newSheetPath = newSheetPath + sheetPath;
1661
1662 // Sheets cannot have themselves in the path.
1663 tmp.pop_back();
1664
1665 SCH_SHEET* sheet = sheetPath.Last();
1666
1667 wxCHECK2( sheet, continue );
1668
1669 nextVirtualPageNumber += 1;
1670
1671 SCH_SHEET_INSTANCE instance;
1672
1673 // Add the instance if it doesn't already exist
1674 if( !sheet->getInstance( instance, tmp, true ) )
1675 {
1676 sheet->addInstance( tmp );
1677 sheet->getInstance( instance, tmp, true );
1678 }
1679
1680 // Get a new page number if we don't have one
1681 if( instance.m_PageNumber.IsEmpty() )
1682 {
1683 // Generate the next available page number.
1684 do
1685 {
1686 pageNumber.Printf( wxT( "%d" ), lastUsedPageNumber );
1687 lastUsedPageNumber += 1;
1688 } while( std::find( usedPageNumbers.begin(), usedPageNumbers.end(), pageNumber ) !=
1689 usedPageNumbers.end() );
1690
1691 instance.m_PageNumber = pageNumber;
1692 newSheetPath.SetVirtualPageNumber( nextVirtualPageNumber );
1693 }
1694
1695 newSheetPath.SetPageNumber( instance.m_PageNumber );
1696 usedPageNumbers.push_back( instance.m_PageNumber );
1697 }
1698}
1699
1700
1701void SCH_SHEET_LIST::CheckForMissingSymbolInstances( const wxString& aProjectName )
1702{
1703 wxLogTrace( traceSchSheetPaths,
1704 "SCH_SHEET_LIST::CheckForMissingSymbolInstances: Processing %zu sheet paths",
1705 size() );
1706
1707 for( SCH_SHEET_PATH& sheetPath : *this )
1708 {
1709 wxLogTrace( traceSchSheetPaths,
1710 " Processing sheet path: '%s' (size=%zu, KIID_PATH='%s')",
1711 sheetPath.PathHumanReadable( false ),
1712 sheetPath.size(),
1713 sheetPath.Path().AsString() );
1714 sheetPath.CheckForMissingSymbolInstances( aProjectName );
1715 }
1716}
1717
1718
1720{
1721 int lastVirtualPageNumber = 1;
1722
1723 for( const SCH_SHEET_PATH& sheetPath : *this )
1724 {
1725 if( sheetPath.GetVirtualPageNumber() > lastVirtualPageNumber )
1726 lastVirtualPageNumber = sheetPath.GetVirtualPageNumber();
1727 }
1728
1729 return lastVirtualPageNumber;
1730}
1731
1732
1733bool SCH_SHEET_LIST::HasPath( const KIID_PATH& aPath ) const
1734{
1735 for( const SCH_SHEET_PATH& path : *this )
1736 {
1737 if( path.Path() == aPath )
1738 return true;
1739 }
1740
1741 return false;
1742}
1743
1744
1745bool SCH_SHEET_LIST::ContainsSheet( const SCH_SHEET* aSheet ) const
1746{
1747 for( const SCH_SHEET_PATH& path : *this )
1748 {
1749 for( size_t i = 0; i < path.size(); i++ )
1750 {
1751 if( path.at( i ) == aSheet )
1752 return true;
1753 }
1754 }
1755
1756 return false;
1757}
1758
1759
1760std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetOrdinalPath( const SCH_SCREEN* aScreen ) const
1761{
1762 // Sheet paths with sheets that do not have a screen object are not valid.
1763 if( !aScreen )
1764 return std::nullopt;
1765
1766 for( const SCH_SHEET_PATH& path: *this )
1767 {
1768 if( path.LastScreen() == aScreen )
1769 return std::optional<SCH_SHEET_PATH>( path );
1770 }
1771
1772 return std::nullopt;
1773}
bool IsContentModified() const
Definition base_screen.h:60
void SetContentModified(bool aModified=true)
Definition base_screen.h:59
wxString GetClass() const override
Return the class name.
void SetPosition(const VECTOR2I &) override
static DELETED_SHEET_ITEM * GetInstance()
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
bool operator==(const SCH_ITEM &aOther) const override
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
const KIID m_Uuid
Definition eda_item.h:522
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
virtual void UpdateHatching() const
virtual bool IsVisible() const
Definition eda_text.h:187
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:400
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
wxString AsString() const
Definition kiid.cpp:365
Definition kiid.h:49
wxString AsString() const
Definition kiid.cpp:244
Define a library symbol object.
Definition lib_symbol.h:83
bool IsPower() const override
int GetUnitCount() const override
Holds all the data relating to one schematic.
Definition schematic.h:88
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCHEMATIC_SETTINGS & Settings() const
wxString GetCurrentVariant() const
Return the current variant being edited.
VECTOR2I GetPosition() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:116
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) const
void SetText(const wxString &aText) override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this label.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
Definition sch_item.h:631
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:254
int GetUnit() const
Definition sch_item.h:239
virtual void SetUnit(int aUnit)
Definition sch_item.h:238
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:56
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
std::vector< SCH_FIELD > & GetFields()
Definition sch_label.h:212
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
void AddItem(const SCH_REFERENCE &aItem)
A helper to define a symbol's reference designator in a schematic.
void SetRef(const wxString &aReference)
void SetRefNum(int aNum)
wxString GetRef() const
void SetSheetNumber(int aSheetNumber)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
const wxString & GetFileName() const
Definition sch_screen.h:154
SCHEMATIC * Schematic() const
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
void GetSheets(std::vector< SCH_ITEM * > *aItems) const
Similar to Items().OfType( SCH_SHEET_T ), but return the sheets in a deterministic order (L-R,...
std::optional< SCH_SHEET_PATH > GetSheetPathByKIIDPath(const KIID_PATH &aPath, bool aIncludeLastSheet=true) const
Finds a SCH_SHEET_PATH that matches the provided KIID_PATH.
SCH_ITEM * ResolveItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr, bool aAllowNullptrReturn=false) const
Fetch a SCH_ITEM by ID.
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols=true) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the li...
std::optional< SCH_SHEET_PATH > GetOrdinalPath(const SCH_SCREEN *aScreen) const
Return the ordinal sheet path of aScreen.
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Fill an item cache for temporary use when many items need to be fetched.
SCH_SHEET_PATH m_currentSheetPath
void TrimToPageNumbers(const std::vector< wxString > &aPageInclusions)
Truncates the list by removing sheet's with page numbers not in the given list.
void SortByPageNumbers(bool aUpdateVirtualPageNums=true)
Sort the list of sheets by page number.
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this list of sheet paths prefixed with aPrefix...
bool NameExists(const wxString &aSheetName) const
std::vector< SCH_SHEET_INSTANCE > GetSheetInstances() const
Fetch the instance information for all of the sheets in the hierarchy.
void UpdateSheetInstanceData(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
void SetInitialPageNumbers()
Set initial sheet page numbers.
void RemoveSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath)
SCH_SHEET_LIST FindAllSheetsForScreen(const SCH_SCREEN *aScreen) const
Return a SCH_SHEET_LIST with a copy of all the SCH_SHEET_PATH using a particular screen.
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
bool IsModified() const
Check the entire hierarchy for any modifications.
SCH_SHEET_LIST(SCH_SHEET *aSheet=nullptr)
Construct a flattened list of SCH_SHEET_PATH objects from aSheet.
void AnnotatePowerSymbols()
Silently annotate the not yet annotated power symbols of the entire hierarchy of the sheet path list.
int GetLastVirtualPageNumber() const
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
void GetSheetsWithinPath(std::vector< SCH_SHEET_PATH > &aSheets, const SCH_SHEET_PATH &aSheetPath) const
Add a SCH_SHEET_PATH object to aSheets for each sheet in the list that are contained within aSheetPat...
bool PageNumberExists(const wxString &aPageNumber) const
void SortByHierarchicalPageNumbers(bool aUpdateVirtualPageNums=true)
This works like SortByPageNumbers, but it sorts the sheets first by their hierarchical depth and then...
void AddNewSheetInstances(const SCH_SHEET_PATH &aPrefixSheetPath, int aLastVirtualPageNumber)
bool ContainsSheet(const SCH_SHEET *aSheet) const
std::vector< KIID_PATH > GetPaths() const
void GetSymbolsWithinPath(SCH_REFERENCE_LIST &aReferences, const SCH_SHEET_PATH &aSheetPath, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets that are contained wi...
void BuildSheetList(SCH_SHEET *aSheet, bool aCheckIntegrity)
Build the list of sheets and their sheet path from aSheet.
SCH_SHEET_PATH FindSheetForScreen(const SCH_SCREEN *aScreen)
Return the first SCH_SHEET_PATH object (not necessarily the only one) using a particular screen.
void CheckForMissingSymbolInstances(const wxString &aProjectName)
bool HasPath(const KIID_PATH &aPath) const
SCH_SHEET_PATH * FindSheetForPath(const SCH_SHEET_PATH *aPath)
Return a pointer to the first SCH_SHEET_PATH object (not necessarily the only one) matching the provi...
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName)
Test every SCH_SHEET_PATH in this SCH_SHEET_LIST to verify if adding the sheets stored in aSrcSheetHi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool GetExcludedFromBOM() const
void AppendMultiUnitSymbol(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, SCH_SYMBOL *aSymbol, bool aIncludePowerSymbols=true) const
Append a SCH_REFERENCE_LIST object to aRefList based on aSymbol, storing same-reference set of multi-...
const SCH_SHEET * GetSheet(unsigned aIndex) const
bool empty() const
Forwarded method from std::vector.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Adds SCH_REFERENCE object to aReferences for each symbol in the sheet.
int ComparePageNum(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare sheets by their page number.
size_t GetCurrentHash() const
bool operator==(const SCH_SHEET_PATH &d1) const
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this sheet path prefixed with aPrefixSheetPath...
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
bool TestForRecursion(const wxString &aSrcFileName, const wxString &aDestFileName)
Test the SCH_SHEET_PATH file names to check adding the sheet stored in the file aSrcFileName to the s...
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
void MakeFilePathRelativeToParentSheet()
Make the sheet file name relative to its parent sheet.
SCH_ITEM * ResolveItem(const KIID &aID) const
Fetch a SCH_ITEM by ID.
wxString GetCachedPageNumber() const
std::vector< SCH_SHEET * > m_sheets
SCH_SCREEN * LastScreen()
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols=true) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the sh...
void initFromOther(const SCH_SHEET_PATH &aOther)
wxString m_cached_page_number
wxString GetPageNumber() const
void RemoveSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath)
void CheckForMissingSymbolInstances(const wxString &aProjectName)
bool IsContainedWithin(const SCH_SHEET_PATH &aSheetPathToTest) const
Check if this path is contained inside aSheetPathToTest.
SCH_SHEET * at(size_t aIndex) const
Forwarded method from std::vector.
void SetVirtualPageNumber(int aPageNumber)
Set the sheet instance virtual page number.
void AppendSymbol(SCH_REFERENCE_LIST &aReferences, SCH_SYMBOL *aSymbol, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Append a SCH_REFERENCE object to aReferences based on aSymbol.
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
std::map< std::pair< wxString, wxString >, bool > m_recursion_test_cache
bool GetExcludedFromSim() const
wxString PathAsString() const
Return the path of time stamps which do not changes even when editing sheet parameters.
bool GetExcludedFromBoard() const
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET_PATH & operator=(const SCH_SHEET_PATH &aOther)
int GetPageNumberAsInt() const
bool GetDNP() const
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
SCH_SHEET_PATH operator+(const SCH_SHEET_PATH &aOther)
int m_virtualPageNumber
Page numbers are maintained by the sheet load order.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
int GetVirtualPageNumber() const
void pop_back()
Forwarded method from std::vector.
void InitializeAttributes(const SCH_SHEET &aSheet)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:382
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:376
bool getInstance(SCH_SHEET_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
bool addInstance(const KIID_PATH &aInstance)
Add a new instance aSheetPath to the instance list.
wxString getPageNumber(const KIID_PATH &aParentPath) const
Return the sheet page number for aParentPath.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
wxString GetName() const
Definition sch_sheet.h:142
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
static int ComparePageNum(const wxString &aPageNumberA, const wxString &aPageNumberB)
Compare page numbers of schematic sheets.
void setPageNumber(const KIID_PATH &aInstance, const wxString &aPageNumber)
Set the page number for the sheet instance aInstance.
bool IsVirtualRootSheet() const
bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flags.
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition sch_sheet.h:467
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:76
void UpdatePrefix()
Set the prefix based on the current reference designator.
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:135
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
void SetFootprintFieldText(const wxString &aFootprint)
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
bool GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
bool m_ExcludedFromBOM
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
@ NO_RECURSE
Definition eda_item.h:53
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:32
KIID niluuid(0)
STL namespace.
Collection of utility functions for component reference designators (refdes)
@ AUTOPLACE_AUTO
Definition sch_item.h:71
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
A simple container for sheet instance information.
A simple container for schematic symbol instance information.
size_t operator()(const SCH_SHEET_PATH &path) const
@ INTERSHEET_REFS
Global label cross-reference page numbers.
@ REFERENCE
Field Reference of part, i.e. "IC21".
std::string path
VECTOR2I end
wxLogTrace helper definitions.
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_SHAPE_T
Definition typeinfo.h:153
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:79
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:172
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695