KiCad PCB EDA Suite
Loading...
Searching...
No Matches
schematic.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <bus_alias.h>
21#include <commit.h>
22#include <connection_graph.h>
23#include <core/ignore.h>
24#include <core/kicad_algo.h>
25#include <core/profile.h>
26#include <sch_collectors.h>
27#include <erc/erc_settings.h>
28#include <font/outline_font.h>
30#include <progress_reporter.h>
31#include <project.h>
34#include <refdes_tracker.h>
35#include <schematic.h>
36#include <sch_bus_entry.h>
37#include <sch_commit.h>
38#include <sch_junction.h>
39#include <sch_label.h>
40#include <sch_line.h>
41#include <sch_marker.h>
42#include <sch_no_connect.h>
43#include <sch_rule_area.h>
44#include <sch_screen.h>
45#include <sch_sheet_pin.h>
46#include <sch_selection_tool.h>
47#include <sim/spice_settings.h>
48#include <sim/spice_value.h>
49#include <tool/tool_manager.h>
50#include <undo_redo_container.h>
51
52#include <wx/log.h>
53
55
57 EDA_ITEM( nullptr, SCHEMATIC_T ),
58 m_project( nullptr ),
59 m_rootSheet( nullptr ),
60 m_schematicHolder( nullptr )
61{
65
66 SetProject( aPrj );
67
69 [&]( INSPECTABLE* aItem, PROPERTY_BASE* aProperty, COMMIT* aCommit )
70 {
71 // Special case: propagate value, footprint, and datasheet fields to other units
72 // of a given symbol if they aren't in the selection
73
74 SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( aItem );
75
76 if( !field || !IsValid() )
77 return;
78
79 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( field->GetParent() );
80
81 if( !symbol || aProperty->Name() != _HKI( "Text" ) )
82 return;
83
84 // TODO(JE) This will need to get smarter to enable API access
85 SCH_SHEET_PATH sheetPath = CurrentSheet();
86
87 wxString newValue = aItem->Get<wxString>( aProperty );
88
89 if( field->GetId() == FIELD_T::REFERENCE )
90 {
91 symbol->SetRef( &sheetPath, newValue );
92
93 // The user might want to change all the units to the new ref. Or they
94 // might not. Since we have no way of knowing, we default to the most
95 // concrete action (change only the selected reference).
96 return;
97 }
98
99 wxString ref = symbol->GetRef( &sheetPath );
100 int unit = symbol->GetUnit();
101 LIB_ID libId = symbol->GetLibId();
102
103 for( SCH_SHEET_PATH& sheet : Hierarchy() )
104 {
105 std::vector<SCH_SYMBOL*> otherUnits;
106
107 CollectOtherUnits( ref, unit, libId, sheet, &otherUnits );
108
109 for( SCH_SYMBOL* otherUnit : otherUnits )
110 {
111 switch( field->GetId() )
112 {
113 case FIELD_T::VALUE:
116 {
117 if( aCommit )
118 aCommit->Modify( otherUnit, sheet.LastScreen() );
119
120 otherUnit->GetField( field->GetId() )->SetText( newValue );
121 break;
122 }
123
124 default:
125 break;
126 }
127 }
128 }
129 } );
130}
131
132
142
143
145{
146 delete m_rootSheet;
147
148 m_rootSheet = nullptr;
149
150 m_connectionGraph->Reset();
151 m_currentSheet->clear();
152}
153
154
156{
157 if( m_project )
158 {
159 PROJECT_FILE& project = m_project->GetProjectFile();
160
161 // d'tor will save settings to file
162 delete project.m_ErcSettings;
163 project.m_ErcSettings = nullptr;
164
165 // d'tor will save settings to file
166 delete project.m_SchematicSettings;
167 project.m_SchematicSettings = nullptr;
168 }
169
170 m_project = aPrj;
171
172 if( m_project )
173 {
174 PROJECT_FILE& project = m_project->GetProjectFile();
175 project.m_ErcSettings = new ERC_SETTINGS( &project, "erc" );
176 project.m_SchematicSettings = new SCHEMATIC_SETTINGS( &project, "schematic" );
177
178 project.m_SchematicSettings->LoadFromFile();
179 project.m_SchematicSettings->m_NgspiceSettings->LoadFromFile();
180 project.m_ErcSettings->LoadFromFile();
181 }
182}
183
184
186{
187 wxASSERT( m_project );
188
189 // Cache all existing annotations in the REFDES_TRACKER
190 std::shared_ptr<REFDES_TRACKER> refdesTracker = m_project->GetProjectFile().m_SchematicSettings->m_refDesTracker;
191
192 SCH_SHEET_LIST sheets = Hierarchy();
193 SCH_REFERENCE_LIST references;
194
195 sheets.GetSymbols( references );
196
197 for( const SCH_REFERENCE& ref : references )
198 {
199 refdesTracker->Insert( ref.GetFullRef( false ).ToStdString() );
200 }
201}
202
203
204bool SCHEMATIC::Contains( const SCH_REFERENCE& aRef ) const
205{
206 SCH_SHEET_LIST sheets = Hierarchy();
207 SCH_REFERENCE_LIST references;
208
213 sheets.GetSymbols( references );
214
215 return std::any_of( references.begin(), references.end(),
216 [&]( const SCH_REFERENCE& ref )
217 {
218 return ref.GetFullRef( true ) == aRef.GetFullRef( true );
219 } );
220}
221
222
223void SCHEMATIC::SetRoot( SCH_SHEET* aRootSheet )
224{
225 wxCHECK_RET( aRootSheet, wxS( "Call to SetRoot with null SCH_SHEET!" ) );
226
227 m_rootSheet = aRootSheet;
228
229 m_currentSheet->clear();
230 m_currentSheet->push_back( m_rootSheet );
231
233 m_connectionGraph->Reset();
234}
235
236
238{
239 return IsValid() ? m_rootSheet->GetScreen() : nullptr;
240}
241
242
244{
245 wxCHECK( !m_hierarchy.empty(), m_hierarchy );
246
247 return m_hierarchy;
248}
249
250
255
256
257void SCHEMATIC::GetContextualTextVars( wxArrayString* aVars ) const
258{
259 auto add =
260 [&]( const wxString& aVar )
261 {
262 if( !alg::contains( *aVars, aVar ) )
263 aVars->push_back( aVar );
264 };
265
266 add( wxT( "#" ) );
267 add( wxT( "##" ) );
268 add( wxT( "SHEETPATH" ) );
269 add( wxT( "SHEETNAME" ) );
270 add( wxT( "FILENAME" ) );
271 add( wxT( "FILEPATH" ) );
272 add( wxT( "PROJECTNAME" ) );
273
274 if( !CurrentSheet().empty() )
276
277 for( std::pair<wxString, wxString> entry : m_project->GetTextVars() )
278 add( entry.first );
279}
280
281
282bool SCHEMATIC::ResolveTextVar( const SCH_SHEET_PATH* aSheetPath, wxString* token,
283 int aDepth ) const
284{
285 wxCHECK( aSheetPath, false );
286
287 if( token->IsSameAs( wxT( "#" ) ) )
288 {
289 *token = aSheetPath->GetPageNumber();
290 return true;
291 }
292 else if( token->IsSameAs( wxT( "##" ) ) )
293 {
294 *token = wxString::Format( "%i", Root().CountSheets() );
295 return true;
296 }
297 else if( token->IsSameAs( wxT( "SHEETPATH" ) ) )
298 {
299 *token = aSheetPath->PathHumanReadable();
300 return true;
301 }
302 else if( token->IsSameAs( wxT( "SHEETNAME" ) ) )
303 {
304 *token = aSheetPath->Last()->GetName();
305 return true;
306 }
307 else if( token->IsSameAs( wxT( "FILENAME" ) ) )
308 {
309 wxFileName fn( GetFileName() );
310 *token = fn.GetFullName();
311 return true;
312 }
313 else if( token->IsSameAs( wxT( "FILEPATH" ) ) )
314 {
315 wxFileName fn( GetFileName() );
316 *token = fn.GetFullPath();
317 return true;
318 }
319 else if( token->IsSameAs( wxT( "PROJECTNAME" ) ) )
320 {
321 *token = m_project->GetProjectName();
322 return true;
323 }
324
325 if( aSheetPath->LastScreen()->GetTitleBlock().TextVarResolver( token, m_project ) )
326 return true;
327
328 if( m_project->TextVarResolver( token ) )
329 return true;
330
331 return false;
332}
333
334
336{
337 return IsValid() ? m_rootSheet->GetScreen()->GetFileName() : wxString( wxEmptyString );
338}
339
340
342{
343 wxASSERT( m_project );
344 return *m_project->GetProjectFile().m_SchematicSettings;
345}
346
347
349{
350 wxASSERT( m_project );
351 return *m_project->GetProjectFile().m_ErcSettings;
352}
353
354
355std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
356{
357 SCH_SHEET_LIST sheetList = Hierarchy();
358 ERC_SETTINGS& settings = ErcSettings();
359
360 // Migrate legacy marker exclusions to new format to ensure exclusion matching functions across
361 // file versions. Silently drops any legacy exclusions which can not be mapped to the new format
362 // without risking an incorrect exclusion - this is preferable to silently dropping
363 // new ERC errors / warnings due to an incorrect match between a legacy and new
364 // marker serialization format
365 std::set<wxString> migratedExclusions;
366
367 for( auto it = settings.m_ErcExclusions.begin(); it != settings.m_ErcExclusions.end(); )
368 {
369 SCH_MARKER* testMarker = SCH_MARKER::DeserializeFromString( sheetList, *it );
370
371 if( !testMarker )
372 {
373 it = settings.m_ErcExclusions.erase( it );
374 continue;
375 }
376
377 if( testMarker->IsLegacyMarker() )
378 {
379 const wxString settingsKey = testMarker->GetRCItem()->GetSettingsKey();
380
381 if( settingsKey != wxT( "pin_to_pin" )
382 && settingsKey != wxT( "hier_label_mismatch" )
383 && settingsKey != wxT( "different_unit_net" ) )
384 {
385 migratedExclusions.insert( testMarker->SerializeToString() );
386 }
387
388 it = settings.m_ErcExclusions.erase( it );
389 }
390 else
391 {
392 ++it;
393 }
394
395 delete testMarker;
396 }
397
398 settings.m_ErcExclusions.insert( migratedExclusions.begin(), migratedExclusions.end() );
399
400 // End of legacy exclusion removal / migrations
401
402 for( const SCH_SHEET_PATH& sheet : sheetList )
403 {
404 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_MARKER_T ) )
405 {
406 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
407 wxString serialized = marker->SerializeToString();
408 std::set<wxString>::iterator it = settings.m_ErcExclusions.find( serialized );
409
410 if( it != settings.m_ErcExclusions.end() )
411 {
412 marker->SetExcluded( true, settings.m_ErcExclusionComments[serialized] );
413 settings.m_ErcExclusions.erase( it );
414 }
415 }
416 }
417
418 std::vector<SCH_MARKER*> newMarkers;
419
420 for( const wxString& serialized : settings.m_ErcExclusions )
421 {
422 SCH_MARKER* marker = SCH_MARKER::DeserializeFromString( sheetList, serialized );
423
424 if( marker )
425 {
426 marker->SetExcluded( true, settings.m_ErcExclusionComments[serialized] );
427 newMarkers.push_back( marker );
428 }
429 }
430
431 settings.m_ErcExclusions.clear();
432
433 return newMarkers;
434}
435
436
437std::shared_ptr<BUS_ALIAS> SCHEMATIC::GetBusAlias( const wxString& aLabel ) const
438{
439 for( const SCH_SHEET_PATH& sheet : Hierarchy() )
440 {
441 for( const std::shared_ptr<BUS_ALIAS>& alias : sheet.LastScreen()->GetBusAliases() )
442 {
443 if( alias->GetName() == aLabel )
444 return alias;
445 }
446 }
447
448 return nullptr;
449}
450
451
453{
454 std::set<wxString> names;
455
456 for( const auto& [ key, subgraphList ] : m_connectionGraph->GetNetMap() )
457 {
458 CONNECTION_SUBGRAPH* firstSubgraph = subgraphList[0];
459
460 if( !firstSubgraph->GetDriverConnection()->IsBus()
462 {
463 names.insert( key.Name );
464 }
465 }
466
467 return names;
468}
469
470
471bool SCHEMATIC::ResolveCrossReference( wxString* token, int aDepth ) const
472{
473 wxString remainder;
474 wxString ref = token->BeforeFirst( ':', &remainder );
475 KIID_PATH path( ref );
476 KIID uuid = path.back();
477 SCH_SHEET_PATH sheetPath;
478 SCH_ITEM* refItem = ResolveItem( KIID( uuid ), &sheetPath, true );
479
480 if( path.size() > 1 )
481 {
482 path.pop_back();
483 sheetPath = Hierarchy().GetSheetPathByKIIDPath( path ).value_or( sheetPath );
484 }
485
486 if( refItem && refItem->Type() == SCH_SYMBOL_T )
487 {
488 SCH_SYMBOL* refSymbol = static_cast<SCH_SYMBOL*>( refItem );
489
490 if( refSymbol->ResolveTextVar( &sheetPath, &remainder, aDepth + 1 ) )
491 *token = std::move( remainder );
492 else
493 *token = refSymbol->GetRef( &sheetPath, true ) + wxS( ":" ) + remainder;
494
495 return true; // Cross-reference is resolved whether or not the actual textvar was
496 }
497 else if( refItem && refItem->Type() == SCH_SHEET_T )
498 {
499 SCH_SHEET* refSheet = static_cast<SCH_SHEET*>( refItem );
500
501 sheetPath.push_back( refSheet );
502
503 if( refSheet->ResolveTextVar( &sheetPath, &remainder, aDepth + 1 ) )
504 *token = std::move( remainder );
505
506 return true; // Cross-reference is resolved whether or not the actual textvar was
507 }
508
509 return false;
510}
511
512
513std::map<int, wxString> SCHEMATIC::GetVirtualPageToSheetNamesMap() const
514{
515 std::map<int, wxString> namesMap;
516
517 for( const SCH_SHEET_PATH& sheet : Hierarchy() )
518 {
519 if( sheet.size() == 1 )
520 namesMap[sheet.GetVirtualPageNumber()] = _( "<root sheet>" );
521 else
522 namesMap[sheet.GetVirtualPageNumber()] = sheet.Last()->GetName();
523 }
524
525 return namesMap;
526}
527
528
529std::map<int, wxString> SCHEMATIC::GetVirtualPageToSheetPagesMap() const
530{
531 std::map<int, wxString> pagesMap;
532
533 for( const SCH_SHEET_PATH& sheet : Hierarchy() )
534 pagesMap[sheet.GetVirtualPageNumber()] = sheet.GetPageNumber();
535
536 return pagesMap;
537}
538
539
540wxString SCHEMATIC::ConvertRefsToKIIDs( const wxString& aSource ) const
541{
542 wxString newbuf;
543 size_t sourceLen = aSource.length();
544
545 for( size_t i = 0; i < sourceLen; ++i )
546 {
547 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
548 {
549 wxString token;
550 bool isCrossRef = false;
551 int nesting = 0;
552
553 for( i = i + 2; i < sourceLen; ++i )
554 {
555 if( aSource[i] == '{'
556 && ( aSource[i-1] == '_' || aSource[i-1] == '^' || aSource[i-1] == '~' ) )
557 {
558 nesting++;
559 }
560
561 if( aSource[i] == '}' )
562 {
563 nesting--;
564
565 if( nesting < 0 )
566 break;
567 }
568
569 if( aSource[i] == ':' )
570 isCrossRef = true;
571
572 token.append( aSource[i] );
573 }
574
575 if( isCrossRef )
576 {
577 wxString remainder;
578 wxString ref = token.BeforeFirst( ':', &remainder );
579 SCH_REFERENCE_LIST references;
580
581 Hierarchy().GetSymbols( references );
582
583 for( size_t jj = 0; jj < references.GetCount(); jj++ )
584 {
585 SCH_SYMBOL* refSymbol = references[ jj ].GetSymbol();
586
587 if( ref == refSymbol->GetRef( &references[ jj ].GetSheetPath(), true ) )
588 {
589 KIID_PATH path = references[ jj ].GetSheetPath().Path();
590 path.push_back( refSymbol->m_Uuid );
591
592 token = path.AsString() + wxS( ":" ) + remainder;
593 break;
594 }
595 }
596 }
597
598 newbuf.append( wxS( "${" ) + token + wxS( "}" ) );
599 }
600 else
601 {
602 newbuf.append( aSource[i] );
603 }
604 }
605
606 return newbuf;
607}
608
609
610wxString SCHEMATIC::ConvertKIIDsToRefs( const wxString& aSource ) const
611{
612 wxString newbuf;
613 size_t sourceLen = aSource.length();
614
615 for( size_t i = 0; i < sourceLen; ++i )
616 {
617 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
618 {
619 wxString token;
620 bool isCrossRef = false;
621
622 for( i = i + 2; i < sourceLen; ++i )
623 {
624 if( aSource[i] == '}' )
625 break;
626
627 if( aSource[i] == ':' )
628 isCrossRef = true;
629
630 token.append( aSource[i] );
631 }
632
633 if( isCrossRef )
634 {
635 wxString remainder;
636 wxString ref = token.BeforeFirst( ':', &remainder );
637 KIID_PATH path( ref );
638 KIID uuid = path.back();
639 SCH_SHEET_PATH sheetPath;
640 SCH_ITEM* refItem = ResolveItem( uuid, &sheetPath, true );
641
642 if( path.size() > 1 )
643 {
644 path.pop_back();
645 sheetPath = Hierarchy().GetSheetPathByKIIDPath( path ).value_or( sheetPath );
646 }
647
648 if( refItem && refItem->Type() == SCH_SYMBOL_T )
649 {
650 SCH_SYMBOL* refSymbol = static_cast<SCH_SYMBOL*>( refItem );
651 token = refSymbol->GetRef( &sheetPath, true ) + wxS( ":" ) + remainder;
652 }
653 }
654
655 newbuf.append( wxS( "${" ) + token + wxS( "}" ) );
656 }
657 else
658 {
659 newbuf.append( aSource[i] );
660 }
661 }
662
663 return newbuf;
664}
665
666
673
674
676{
677 // Filename is rootSheetName-sheetName-...-sheetName
678 // Note that we need to fetch the rootSheetName out of its filename, as the root SCH_SHEET's
679 // name is just a timestamp.
680
681 wxFileName rootFn( CurrentSheet().at( 0 )->GetFileName() );
682 wxString filename = rootFn.GetName();
683
684 for( unsigned i = 1; i < CurrentSheet().size(); i++ )
685 filename += wxT( "-" ) + CurrentSheet().at( i )->GetName();
686
687 return filename;
688}
689
690
692{
693 SCH_SCREEN* screen;
694 SCH_SCREENS s_list( Root() );
695
696 // Set the sheet count, and the sheet number (1 for root sheet)
697 int sheet_count = Root().CountSheets();
698 int sheet_number = 1;
699 const KIID_PATH& current_sheetpath = CurrentSheet().Path();
700
701 // @todo Remove all pseudo page number system is left over from prior to real page number
702 // implementation.
703 for( const SCH_SHEET_PATH& sheet : Hierarchy() )
704 {
705 if( sheet.Path() == current_sheetpath ) // Current sheet path found
706 break;
707
708 sheet_number++; // Not found, increment before this current path
709 }
710
711 for( screen = s_list.GetFirst(); screen != nullptr; screen = s_list.GetNext() )
712 screen->SetPageCount( sheet_count );
713
714 CurrentSheet().SetVirtualPageNumber( sheet_number );
715 CurrentSheet().LastScreen()->SetVirtualPageNumber( sheet_number );
716 CurrentSheet().LastScreen()->SetPageNumber( CurrentSheet().GetPageNumber() );
717}
718
719
721{
722 std::map<wxString, std::set<int>>& pageRefsMap = GetPageRefsMap();
723
724 pageRefsMap.clear();
725
726 for( const SCH_SHEET_PATH& sheet : Hierarchy() )
727 {
728 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_GLOBAL_LABEL_T ) )
729 {
730 SCH_GLOBALLABEL* global = static_cast<SCH_GLOBALLABEL*>( item );
731 wxString resolvedLabel = global->GetShownText( &sheet, false );
732
733 pageRefsMap[ resolvedLabel ].insert( sheet.GetVirtualPageNumber() );
734 }
735 }
736
737 bool show = Settings().m_IntersheetRefsShow;
738
739 // Refresh all visible global labels. Note that we have to collect them first as the
740 // SCH_SCREEN::Update() call is going to invalidate the RTree iterator.
741
742 std::vector<SCH_GLOBALLABEL*> currentSheetGlobalLabels;
743
744 for( EDA_ITEM* item : CurrentSheet().LastScreen()->Items().OfType( SCH_GLOBAL_LABEL_T ) )
745 currentSheetGlobalLabels.push_back( static_cast<SCH_GLOBALLABEL*>( item ) );
746
747 for( SCH_GLOBALLABEL* globalLabel : currentSheetGlobalLabels )
748 {
749 std::vector<SCH_FIELD>& fields = globalLabel->GetFields();
750
751 fields[0].SetVisible( show );
752
753 if( show )
754 {
755 if( fields.size() == 1 && fields[0].GetTextPos() == globalLabel->GetPosition() )
756 globalLabel->AutoplaceFields( CurrentSheet().LastScreen(), AUTOPLACE_AUTO );
757
758 CurrentSheet().LastScreen()->Update( globalLabel );
759
760 for( SCH_FIELD& field : globalLabel->GetFields() )
761 field.ClearBoundingBoxCache();
762
763 globalLabel->ClearBoundingBoxCache();
764
766 m_schematicHolder->IntersheetRefUpdate( globalLabel );
767 }
768 }
769}
770
771
772wxString SCHEMATIC::GetOperatingPoint( const wxString& aNetName, int aPrecision,
773 const wxString& aRange )
774{
775 wxString spiceNetName( aNetName.Lower() );
777
778 if( spiceNetName == wxS( "gnd" ) || spiceNetName == wxS( "0" ) )
779 return wxEmptyString;
780
781 auto it = m_operatingPoints.find( spiceNetName );
782
783 if( it != m_operatingPoints.end() )
784 return SPICE_VALUE( it->second ).ToString( { aPrecision, aRange } );
785 else if( m_operatingPoints.empty() )
786 return wxS( "--" );
787 else
788 return wxS( "?" );
789}
790
791
793{
794 SCH_SCREENS screens( Root() );
795
796 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
797 {
798 std::deque<EDA_ITEM*> allItems;
799
800 for( SCH_ITEM* item : screen->Items() )
801 allItems.push_back( item );
802
803 // Add missing junctions and breakup wires as needed
804 for( const VECTOR2I& point : screen->GetNeededJunctions( allItems ) )
805 {
806 SCH_JUNCTION* junction = new SCH_JUNCTION( point );
807 screen->Append( junction );
808
809 // Breakup wires
810 for( SCH_LINE* wire : screen->GetBusesAndWires( point, true ) )
811 {
812 SCH_LINE* newSegment = wire->NonGroupAware_BreakAt( point );
813 screen->Append( newSegment );
814 }
815 }
816 }
817}
818
819
820void SCHEMATIC::OnItemsAdded( std::vector<SCH_ITEM*>& aNewItems )
821{
823}
824
825
826void SCHEMATIC::OnItemsRemoved( std::vector<SCH_ITEM*>& aRemovedItems )
827{
829}
830
831
832void SCHEMATIC::OnItemsChanged( std::vector<SCH_ITEM*>& aItems )
833{
835}
836
837
842
843
845{
846 if( !alg::contains( m_listeners, aListener ) )
847 m_listeners.push_back( aListener );
848}
849
850
852{
853 auto i = std::find( m_listeners.begin(), m_listeners.end(), aListener );
854
855 if( i != m_listeners.end() )
856 {
857 std::iter_swap( i, m_listeners.end() - 1 );
858 m_listeners.pop_back();
859 }
860}
861
862
864{
865 m_listeners.clear();
866}
867
868
870{
871 // Use a sorted sheetList to reduce file churn
872 SCH_SHEET_LIST sheetList = Hierarchy();
873 ERC_SETTINGS& ercSettings = ErcSettings();
874
875 ercSettings.m_ErcExclusions.clear();
876 ercSettings.m_ErcExclusionComments.clear();
877
878 for( unsigned i = 0; i < sheetList.size(); i++ )
879 {
880 for( SCH_ITEM* item : sheetList[i].LastScreen()->Items().OfType( SCH_MARKER_T ) )
881 {
882 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
883
884 if( marker->IsExcluded() )
885 {
886 wxString serialized = marker->SerializeToString();
887 ercSettings.m_ErcExclusions.insert( serialized );
888 ercSettings.m_ErcExclusionComments[ serialized ] = marker->GetComment();
889 }
890 }
891 }
892}
893
894
896{
897 SCH_SHEET_LIST sheetList = Hierarchy();
898
899 for( SCH_MARKER* marker : ResolveERCExclusions() )
900 {
901 SCH_SHEET_PATH errorPath;
902 ignore_unused( sheetList.ResolveItem( marker->GetRCItem()->GetMainItemID(), &errorPath ) );
903
904 if( errorPath.LastScreen() )
905 errorPath.LastScreen()->Append( marker );
906 else
907 RootScreen()->Append( marker );
908 }
909
910 // Once we have the ERC Exclusions, record them in the project file so that
911 // they are retained even before the schematic is saved (PCB Editor can also save the project)
913}
914
915
917{
918 return static_cast<EMBEDDED_FILES*>( this );
919}
920
921
923{
924 return static_cast<const EMBEDDED_FILES*>( this );
925}
926
927
928void SCHEMATIC::RunOnNestedEmbeddedFiles( const std::function<void( EMBEDDED_FILES* )>& aFunction )
929{
930 SCH_SCREENS screens( Root() );
931
932 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
933 {
934 for( auto& [name, libSym] : screen->GetLibSymbols() )
935 aFunction( libSym->GetEmbeddedFiles() );
936 }
937}
938
939
940std::set<KIFONT::OUTLINE_FONT*> SCHEMATIC::GetFonts() const
941{
942 std::set<KIFONT::OUTLINE_FONT*> fonts;
943
944 SCH_SHEET_LIST sheetList = Hierarchy();
945
946 for( const SCH_SHEET_PATH& sheet : sheetList )
947 {
948 for( SCH_ITEM* item : sheet.LastScreen()->Items() )
949 {
950 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
951 {
952 KIFONT::FONT* font = text->GetFont();
953
954 if( !font || font->IsStroke() )
955 continue;
956
957 using EMBEDDING_PERMISSION = KIFONT::OUTLINE_FONT::EMBEDDING_PERMISSION;
958 auto* outline = static_cast<KIFONT::OUTLINE_FONT*>( font );
959
960 if( outline->GetEmbeddingPermission() == EMBEDDING_PERMISSION::EDITABLE
961 || outline->GetEmbeddingPermission() == EMBEDDING_PERMISSION::INSTALLABLE )
962 {
963 fonts.insert( outline );
964 }
965 }
966 }
967 }
968
969 return fonts;
970}
971
972
974{
975 std::set<KIFONT::OUTLINE_FONT*> fonts = GetFonts();
976
977 for( KIFONT::OUTLINE_FONT* font : fonts )
978 {
979 auto file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
980
981 if( !file )
982 {
983 wxLogTrace( "EMBED", "Failed to add font file: %s", font->GetFileName() );
984 continue;
985 }
986
988 }
989}
990
991
992std::set<const SCH_SCREEN*> SCHEMATIC::GetSchematicsSharedByMultipleProjects() const
993{
994 std::set<const SCH_SCREEN*> retv;
995
996 wxCHECK( m_rootSheet, retv );
997
998 SCH_SHEET_LIST hierarchy( m_rootSheet );
999 SCH_SCREENS screens( m_rootSheet );
1000
1001 for( const SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
1002 {
1003 for( const SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
1004 {
1005 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
1006
1007 const std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
1008
1009 for( const SCH_SYMBOL_INSTANCE& instance : symbolInstances )
1010 {
1011 if( !hierarchy.HasPath( instance.m_Path ) )
1012 {
1013 retv.insert( screen );
1014 break;
1015 }
1016 }
1017
1018 if( retv.count( screen ) )
1019 break;
1020 }
1021 }
1022
1023 return retv;
1024}
1025
1026
1028{
1029 wxCHECK( m_rootSheet, false );
1030
1031 SCH_SCREENS screens( m_rootSheet );
1032
1033 for( const SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
1034 {
1035 wxCHECK2( screen, continue );
1036
1037 if( screen->GetRefCount() > 1 )
1038 return true;
1039 }
1040
1041 return false;
1042}
1043
1044
1045void SCHEMATIC::CleanUp( SCH_COMMIT* aCommit, SCH_SCREEN* aScreen )
1046{
1047 SCH_SELECTION_TOOL* selectionTool = m_schematicHolder ? m_schematicHolder->GetSelectionTool() : nullptr;
1048 std::vector<SCH_LINE*> lines;
1049 std::vector<SCH_JUNCTION*> junctions;
1050 std::vector<SCH_NO_CONNECT*> ncs;
1051 std::vector<SCH_ITEM*> items_to_remove;
1052 bool changed = true;
1053
1054 if( aScreen == nullptr )
1055 aScreen = GetCurrentScreen();
1056
1057 auto remove_item = [&]( SCH_ITEM* aItem ) -> void
1058 {
1059 changed = true;
1060
1061 if( !( aItem->GetFlags() & STRUCT_DELETED ) )
1062 {
1063 aItem->SetFlags( STRUCT_DELETED );
1064
1065 if( aItem->IsSelected() && selectionTool )
1066 selectionTool->RemoveItemFromSel( aItem, true /*quiet mode*/ );
1067
1068 if( m_schematicHolder )
1069 {
1070 m_schematicHolder->RemoveFromScreen( aItem, aScreen );
1071 }
1072 aCommit->Removed( aItem, aScreen );
1073 }
1074 };
1075
1076
1077 for( SCH_ITEM* item : aScreen->Items().OfType( SCH_JUNCTION_T ) )
1078 {
1079 if( !aScreen->IsExplicitJunction( item->GetPosition() ) )
1080 items_to_remove.push_back( item );
1081 else
1082 junctions.push_back( static_cast<SCH_JUNCTION*>( item ) );
1083 }
1084
1085 for( SCH_ITEM* item : items_to_remove )
1086 remove_item( item );
1087
1088 for( SCH_ITEM* item : aScreen->Items().OfType( SCH_NO_CONNECT_T ) )
1089 ncs.push_back( static_cast<SCH_NO_CONNECT*>( item ) );
1090
1091 alg::for_all_pairs( junctions.begin(), junctions.end(),
1092 [&]( SCH_JUNCTION* aFirst, SCH_JUNCTION* aSecond )
1093 {
1094 if( ( aFirst->GetEditFlags() & STRUCT_DELETED )
1095 || ( aSecond->GetEditFlags() & STRUCT_DELETED ) )
1096 {
1097 return;
1098 }
1099
1100 if( aFirst->GetPosition() == aSecond->GetPosition() )
1101 remove_item( aSecond );
1102 } );
1103
1104 alg::for_all_pairs( ncs.begin(), ncs.end(),
1105 [&]( SCH_NO_CONNECT* aFirst, SCH_NO_CONNECT* aSecond )
1106 {
1107 if( ( aFirst->GetEditFlags() & STRUCT_DELETED )
1108 || ( aSecond->GetEditFlags() & STRUCT_DELETED ) )
1109 {
1110 return;
1111 }
1112
1113 if( aFirst->GetPosition() == aSecond->GetPosition() )
1114 remove_item( aSecond );
1115 } );
1116
1117
1118 auto minX = []( const SCH_LINE* l )
1119 {
1120 return std::min( l->GetStartPoint().x, l->GetEndPoint().x );
1121 };
1122
1123 auto maxX = []( const SCH_LINE* l )
1124 {
1125 return std::max( l->GetStartPoint().x, l->GetEndPoint().x );
1126 };
1127
1128 auto minY = []( const SCH_LINE* l )
1129 {
1130 return std::min( l->GetStartPoint().y, l->GetEndPoint().y );
1131 };
1132
1133 auto maxY = []( const SCH_LINE* l )
1134 {
1135 return std::max( l->GetStartPoint().y, l->GetEndPoint().y );
1136 };
1137
1138 // Would be nice to put lines in a canonical form here by swapping
1139 // start <-> end as needed but I don't know what swapping breaks.
1140 while( changed )
1141 {
1142 changed = false;
1143 lines.clear();
1144
1145 for( SCH_ITEM* item : aScreen->Items().OfType( SCH_LINE_T ) )
1146 {
1147 if( item->GetLayer() == LAYER_WIRE || item->GetLayer() == LAYER_BUS )
1148 lines.push_back( static_cast<SCH_LINE*>( item ) );
1149 }
1150
1151 // Sort by minimum X position
1152 std::sort( lines.begin(), lines.end(),
1153 [&]( const SCH_LINE* a, const SCH_LINE* b )
1154 {
1155 return minX( a ) < minX( b );
1156 } );
1157
1158 for( auto it1 = lines.begin(); it1 != lines.end(); ++it1 )
1159 {
1160 SCH_LINE* firstLine = *it1;
1161
1162 if( firstLine->GetEditFlags() & STRUCT_DELETED )
1163 continue;
1164
1165 if( firstLine->IsNull() )
1166 {
1167 remove_item( firstLine );
1168 continue;
1169 }
1170
1171 int firstRightXEdge = maxX( firstLine );
1172 auto it2 = it1;
1173
1174 for( ++it2; it2 != lines.end(); ++it2 )
1175 {
1176 SCH_LINE* secondLine = *it2;
1177 int secondLeftXEdge = minX( secondLine );
1178
1179 // impossible to overlap remaining lines
1180 if( secondLeftXEdge > firstRightXEdge )
1181 break;
1182
1183 // No Y axis overlap
1184 if( !( std::max( minY( firstLine ), minY( secondLine ) )
1185 <= std::min( maxY( firstLine ), maxY( secondLine ) ) ) )
1186 {
1187 continue;
1188 }
1189
1190 if( secondLine->GetFlags() & STRUCT_DELETED )
1191 continue;
1192
1193 if( !secondLine->IsParallel( firstLine )
1194 || !secondLine->IsStrokeEquivalent( firstLine )
1195 || secondLine->GetLayer() != firstLine->GetLayer() )
1196 {
1197 continue;
1198 }
1199
1200 // Remove identical lines
1201 if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
1202 && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
1203 {
1204 remove_item( secondLine );
1205 continue;
1206 }
1207
1208 // See if we can merge an overlap (or two colinear touching segments with
1209 // no junction where they meet).
1210 SCH_LINE* mergedLine = secondLine->MergeOverlap( aScreen, firstLine, true );
1211
1212 if( mergedLine != nullptr )
1213 {
1214 remove_item( firstLine );
1215 remove_item( secondLine );
1216
1217 if( m_schematicHolder )
1218 {
1219 m_schematicHolder->AddToScreen( mergedLine, aScreen );
1220 }
1221
1222 aCommit->Added( mergedLine, aScreen );
1223
1224 if( selectionTool && ( firstLine->IsSelected() || secondLine->IsSelected() ) )
1225 selectionTool->AddItemToSel( mergedLine, true /*quiet mode*/ );
1226
1227 break;
1228 }
1229 }
1230 }
1231 }
1232}
1233
1234
1236 TOOL_MANAGER* aToolManager,
1237 PROGRESS_REPORTER* aProgressReporter,
1238 KIGFX::SCH_VIEW* aSchView,
1239 std::function<void( SCH_ITEM* )>* aChangedItemHandler,
1240 PICKED_ITEMS_LIST* aLastChangeList )
1241{
1242 SCHEMATIC_SETTINGS& settings = Settings();
1244 SCH_SHEET_LIST list = Hierarchy();
1245 SCH_COMMIT localCommit( aToolManager );
1246
1247 if( !aCommit )
1248 aCommit = &localCommit;
1249
1250 PROF_TIMER timer;
1251
1252 // Ensure schematic graph is accurate
1253 if( aCleanupFlags == LOCAL_CLEANUP )
1254 {
1255 CleanUp( aCommit, GetCurrentScreen() );
1256 }
1257 else if( aCleanupFlags == GLOBAL_CLEANUP )
1258 {
1259 for( const SCH_SHEET_PATH& sheet : list )
1260 CleanUp( aCommit, sheet.LastScreen() );
1261 }
1262
1263 timer.Stop();
1264 wxLogTrace( "CONN_PROFILE", "SchematicCleanUp() %0.4f ms", timer.msecs() );
1265
1266 if( settings.m_IntersheetRefsShow )
1268
1269 if( !ADVANCED_CFG::GetCfg().m_IncrementalConnectivity
1270 || aCleanupFlags == GLOBAL_CLEANUP
1271 || aLastChangeList == nullptr
1272 || ConnectionGraph()->IsMinor() )
1273 {
1274 // Clear all resolved netclass caches in case labels have changed
1275 m_project->GetProjectFile().NetSettings()->ClearAllCaches();
1276
1277 // Update all rule areas so we can cascade implied connectivity changes
1278 std::unordered_set<SCH_SCREEN*> all_screens;
1279
1280 for( const SCH_SHEET_PATH& path : list )
1281 all_screens.insert( path.LastScreen() );
1282
1283 SCH_RULE_AREA::UpdateRuleAreasInScreens( all_screens, aSchView );
1284
1285 // Recalculate all connectivity
1286 ConnectionGraph()->Recalculate( list, true, aChangedItemHandler, aProgressReporter );
1287 }
1288 else
1289 {
1290 struct CHANGED_ITEM
1291 {
1292 SCH_ITEM* item;
1293 SCH_ITEM* linked_item;
1294 SCH_SCREEN* screen;
1295 };
1296
1297 // Final change sets
1298 std::set<SCH_ITEM*> changed_items;
1299 std::set<VECTOR2I> pts;
1300 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> item_paths;
1301
1302 // Working change sets
1303 std::unordered_set<SCH_SCREEN*> changed_screens;
1304 std::set<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>> changed_rule_areas;
1305 std::vector<CHANGED_ITEM> changed_connectable_items;
1306
1307 // Lambda to add an item to the connectivity update sets
1308 auto addItemToChangeSet = [&changed_items, &pts, &item_paths]( CHANGED_ITEM itemData )
1309 {
1310 std::vector<SCH_SHEET_PATH>& paths = itemData.screen->GetClientSheetPaths();
1311
1312 std::vector<VECTOR2I> tmp_pts = itemData.item->GetConnectionPoints();
1313 pts.insert( tmp_pts.begin(), tmp_pts.end() );
1314 changed_items.insert( itemData.item );
1315
1316 for( SCH_SHEET_PATH& path : paths )
1317 item_paths.insert( std::make_pair( path, itemData.item ) );
1318
1319 if( !itemData.linked_item || !itemData.linked_item->IsConnectable() )
1320 return;
1321
1322 tmp_pts = itemData.linked_item->GetConnectionPoints();
1323 pts.insert( tmp_pts.begin(), tmp_pts.end() );
1324 changed_items.insert( itemData.linked_item );
1325
1326 // We have to directly add the pins here because the link may not exist on the schematic
1327 // anymore and so won't be picked up by GetScreen()->Items().Overlapping() below.
1328 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( itemData.linked_item ) )
1329 {
1330 std::vector<SCH_PIN*> pins = symbol->GetPins();
1331 changed_items.insert( pins.begin(), pins.end() );
1332 }
1333
1334 for( SCH_SHEET_PATH& path : paths )
1335 item_paths.insert( std::make_pair( path, itemData.linked_item ) );
1336 };
1337
1338 // Get all changed connectable items and determine all changed screens
1339 for( unsigned ii = 0; ii < aLastChangeList->GetCount(); ++ii )
1340 {
1341 switch( aLastChangeList->GetPickedItemStatus( ii ) )
1342 {
1343 // Only care about changed, new, and deleted items, the other
1344 // cases are not connectivity-related
1345 case UNDO_REDO::CHANGED:
1346 case UNDO_REDO::NEWITEM:
1347 case UNDO_REDO::DELETED:
1348 break;
1349
1350 default:
1351 continue;
1352 }
1353
1354 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aLastChangeList->GetPickedItem( ii ) );
1355
1356 if( item )
1357 {
1358 SCH_SCREEN* screen = static_cast<SCH_SCREEN*>( aLastChangeList->GetScreenForItem( ii ) );
1359 changed_screens.insert( screen );
1360
1361 if( item->Type() == SCH_RULE_AREA_T )
1362 {
1363 SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( item );
1364 changed_rule_areas.insert( { ruleArea, screen } );
1365 }
1366 else if( item->IsConnectable() )
1367 {
1368 SCH_ITEM* linked_item = dynamic_cast<SCH_ITEM*>( aLastChangeList->GetPickedItemLink( ii ) );
1369 changed_connectable_items.push_back( { item, linked_item, screen } );
1370 }
1371 }
1372 }
1373
1374 // Update rule areas in changed screens to propagate any directive connectivity changes
1375 std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>> forceUpdateRuleAreas =
1376 SCH_RULE_AREA::UpdateRuleAreasInScreens( changed_screens, aSchView );
1377
1378 std::for_each( forceUpdateRuleAreas.begin(), forceUpdateRuleAreas.end(),
1379 [&]( std::pair<SCH_RULE_AREA*, SCH_SCREEN*>& updatedRuleArea )
1380 {
1381 changed_rule_areas.insert( updatedRuleArea );
1382 } );
1383
1384 // If a SCH_RULE_AREA was changed, we need to add all past and present contained items to
1385 // update their connectivity
1386 std::map<KIID, EDA_ITEM*> itemMap;
1387 list.FillItemMap( itemMap );
1388
1389 auto addPastAndPresentContainedItems =
1390 [&]( SCH_RULE_AREA* changedRuleArea, SCH_SCREEN* screen )
1391 {
1392 for( const KIID& pastItem : changedRuleArea->GetPastContainedItems() )
1393 {
1394 if( itemMap.contains( pastItem ) )
1395 addItemToChangeSet( { static_cast<SCH_ITEM*>( itemMap[pastItem] ), nullptr, screen } );
1396 }
1397
1398 for( SCH_ITEM* containedItem : changedRuleArea->GetContainedItems() )
1399 addItemToChangeSet( { containedItem, nullptr, screen } );
1400 };
1401
1402 for( const auto& [changedRuleArea, screen] : changed_rule_areas )
1403 addPastAndPresentContainedItems( changedRuleArea, screen );
1404
1405 // Add all changed items, and associated items, to the change set
1406 for( CHANGED_ITEM& changed_item_data : changed_connectable_items )
1407 {
1408 addItemToChangeSet( changed_item_data );
1409
1410 // If a SCH_DIRECTIVE_LABEL was changed which is attached to a SCH_RULE_AREA, we need
1411 // to add the contained items to the change set to force update of their connectivity
1412 if( changed_item_data.item->Type() == SCH_DIRECTIVE_LABEL_T )
1413 {
1414 const std::vector<VECTOR2I> labelConnectionPoints =
1415 changed_item_data.item->GetConnectionPoints();
1416
1417 auto candidateRuleAreas =
1418 changed_item_data.screen->Items().Overlapping( SCH_RULE_AREA_T,
1419 changed_item_data.item->GetBoundingBox() );
1420
1421 for( SCH_ITEM* candidateRuleArea : candidateRuleAreas )
1422 {
1423 SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( candidateRuleArea );
1424 std::vector<SHAPE*> borderShapes = ruleArea->MakeEffectiveShapes( true );
1425
1426 if( ruleArea->GetPolyShape().CollideEdge( labelConnectionPoints[0], nullptr, 5 ) )
1427 addPastAndPresentContainedItems( ruleArea, changed_item_data.screen );
1428 }
1429 }
1430 }
1431
1432 for( const VECTOR2I& pt: pts )
1433 {
1434 for( SCH_ITEM* item : GetCurrentScreen()->Items().Overlapping( pt ) )
1435 {
1436 // Leave this check in place. Overlapping items are not necessarily connectable.
1437 if( !item->IsConnectable() )
1438 continue;
1439
1440 if( item->Type() == SCH_LINE_T )
1441 {
1442 if( item->HitTest( pt ) )
1443 changed_items.insert( item );
1444 }
1445 else if( item->Type() == SCH_SYMBOL_T && item->IsConnected( pt ) )
1446 {
1447 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1448 std::vector<SCH_PIN*> pins = symbol->GetPins();
1449
1450 changed_items.insert( pins.begin(), pins.end() );
1451 }
1452 else if( item->Type() == SCH_SHEET_T )
1453 {
1454 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1455
1456 wxCHECK2( sheet, continue );
1457
1458 std::vector<SCH_SHEET_PIN*> sheetPins = sheet->GetPins();
1459 changed_items.insert( sheetPins.begin(), sheetPins.end() );
1460 }
1461 else
1462 {
1463 if( item->IsConnected( pt ) )
1464 changed_items.insert( item );
1465 }
1466 }
1467 }
1468
1469 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> all_items =
1470 ConnectionGraph()->ExtractAffectedItems( changed_items );
1471
1472 all_items.insert( item_paths.begin(), item_paths.end() );
1473
1474 CONNECTION_GRAPH new_graph( this );
1475
1476 new_graph.SetLastCodes( ConnectionGraph() );
1477
1478 std::shared_ptr<NET_SETTINGS> netSettings = m_project->GetProjectFile().NetSettings();
1479
1480 std::set<wxString> affectedNets;
1481
1482 for( auto&[ path, item ] : all_items )
1483 {
1484 wxCHECK2( item, continue );
1485 item->SetConnectivityDirty();
1486 SCH_CONNECTION* conn = item->Connection();
1487
1488 if( conn )
1489 affectedNets.insert( conn->Name() );
1490 }
1491
1492 // Reset resolved netclass cache for this connection
1493 for( const wxString& netName : affectedNets )
1494 netSettings->ClearCacheForNet( netName );
1495
1496 new_graph.Recalculate( list, false, aChangedItemHandler, aProgressReporter );
1497 ConnectionGraph()->Merge( new_graph );
1498 }
1499
1500 if( !localCommit.Empty() )
1501 localCommit.Push( _( "Schematic Cleanup" ) );
1502}
1503
1504
1506{
1507 Reset();
1508
1509 SCH_SHEET* rootSheet = new SCH_SHEET( this );
1510 SetRoot( rootSheet );
1511
1512 SCH_SCREEN* rootScreen = new SCH_SCREEN( this );
1513 const_cast<KIID&>( rootSheet->m_Uuid ) = rootScreen->GetUuid();
1514 Root().SetScreen( rootScreen );
1515
1516
1517 RootScreen()->SetFileName( wxEmptyString );
1518
1519 // Don't leave root page number empty
1520 SCH_SHEET_PATH rootSheetPath;
1521
1522 rootSheetPath.push_back( rootSheet );
1523 RootScreen()->SetPageNumber( wxT( "1" ) );
1524 rootSheetPath.SetPageNumber( wxT( "1" ) );
1525
1526 // Rehash sheetpaths in hierarchy since we changed the uuid.
1528}
const char * name
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetPageCount(int aPageCount)
void SetPageNumber(const wxString &aPageNumber)
Definition base_screen.h:79
void SetVirtualPageNumber(int aPageNumber)
Definition base_screen.h:76
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:72
bool Empty() const
Definition commit.h:137
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Definition commit.h:96
Calculate the connectivity of a schematic and generates netlists.
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Update the connection graph for the given list of sheets.
std::set< std::pair< SCH_SHEET_PATH, SCH_ITEM * > > ExtractAffectedItems(const std::set< SCH_ITEM * > &aItems)
For a set of items, this will remove the connected items and their associated data including subgraph...
void SetLastCodes(const CONNECTION_GRAPH *aOther)
void Merge(CONNECTION_GRAPH &aGraph)
Combine the input graph contents into the current graph.
A subgraph is a set of items that are electrically connected on a single sheet.
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
const SCH_CONNECTION * GetDriverConnection() const
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:148
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
bool IsSelected() const
Definition eda_item.h:127
EDA_ITEM * GetParent() const
Definition eda_item.h:112
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:145
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
SHAPE_POLY_SET & GetPolyShape()
Definition eda_shape.h:337
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:79
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
EMBEDDED_FILES()=default
Container for ERC settings.
std::map< wxString, wxString > m_ErcExclusionComments
std::set< wxString > m_ErcExclusions
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:37
wxAny Get(PROPERTY_BASE *aProperty) const
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:131
virtual bool IsStroke() const
Definition font.h:138
Class OUTLINE_FONT implements outline font drawing.
Definition kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
bool IsExcluded() const
Definition marker_base.h:93
std::shared_ptr< RC_ITEM > GetRCItem() const
void SetExcluded(bool aExcluded, const wxString &aComment=wxEmptyString)
Definition marker_base.h:94
wxString GetComment() const
static void ConvertToSpiceMarkup(wxString *aNetName)
Remove formatting wrappers and replace illegal spice net name characters with underscores.
A holder to handle information on schematic or board items.
UNDO_REDO GetPickedItemStatus(unsigned int aIdx) const
EDA_ITEM * GetPickedItemLink(unsigned int aIdx) const
unsigned GetCount() const
BASE_SCREEN * GetScreenForItem(unsigned int aIdx) const
EDA_ITEM * GetPickedItem(unsigned int aIdx) const
A small class to help profiling.
Definition profile.h:49
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:88
double msecs(bool aSinceLast=false)
Definition profile.h:149
A progress reporter interface for use in multi-threaded environments.
The backing store for a PROJECT, in JSON format.
Container for project specific data.
Definition project.h:65
const wxString & Name() const
Definition property.h:219
static PROPERTY_MANAGER & Instance()
void UnregisterListeners(TYPE_ID aType)
void RegisterListener(TYPE_ID aType, PROPERTY_LISTENER aListenerFunc)
Registers a listener for the given type.
wxString GetSettingsKey() const
Definition rc_item.h:172
virtual void OnSchItemsRemoved(SCHEMATIC &aSch, std::vector< SCH_ITEM * > &aSchItem)
Definition schematic.h:65
virtual void OnSchItemsChanged(SCHEMATIC &aSch, std::vector< SCH_ITEM * > &aSchItem)
Definition schematic.h:66
virtual void OnSchSheetChanged(SCHEMATIC &aSch)
Definition schematic.h:70
virtual void OnSchItemsAdded(SCHEMATIC &aSch, std::vector< SCH_ITEM * > &aSchItem)
Definition schematic.h:64
These are loaded from Eeschema settings but then overwritten by the project settings.
void Reset()
Initialize this schematic to a blank one, unloading anything existing.
std::set< const SCH_SCREEN * > GetSchematicsSharedByMultipleProjects() const
Return a list of schematic files in the current project that contain instance data for multiple proje...
void CreateDefaultScreens()
void SetLegacySymbolInstanceData()
Update the symbol value and footprint instance data for legacy designs.
void OnItemsAdded(std::vector< SCH_ITEM * > &aNewItems)
Must be used if Add() is used using a BULK_x ADD_MODE to generate a change event for listeners.
CONNECTION_GRAPH * m_connectionGraph
Hold and calculate connectivity information of this schematic.
Definition schematic.h:451
SCH_SHEET_LIST m_hierarchy
Cache of the entire schematic hierarchy sorted by sheet page number.
Definition schematic.h:473
void ResolveERCExclusionsPostUpdate()
Update markers to match recorded exclusions.
void RecomputeIntersheetRefs()
Update the schematic's page reference map for all global labels, and refresh the labels so that they ...
void CacheExistingAnnotation()
Store all existing annotations in the REFDES_TRACKER.
SCH_SHEET_LIST BuildSheetListSortedByPageNumbers() const
Definition schematic.h:108
void RemoveListener(SCHEMATIC_LISTENER *aListener)
Remove the specified listener.
bool IsComplexHierarchy() const
Test if the schematic is a complex hierarchy.
void OnSchSheetChanged()
Notify the schematic and its listeners that the current sheet has been changed.
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCH_SHEET_PATH * m_currentSheet
The sheet path of the sheet currently being edited or displayed.
Definition schematic.h:448
wxString GetOperatingPoint(const wxString &aNetName, int aPrecision, const wxString &aRange)
void CleanUp(SCH_COMMIT *aCommit, SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
void OnItemsRemoved(std::vector< SCH_ITEM * > &aRemovedItems)
Must be used if Remove() is used using a BULK_x REMOVE_MODE to generate a change event for listeners.
virtual ~SCHEMATIC()
std::shared_ptr< BUS_ALIAS > GetBusAlias(const wxString &aLabel) const
Return a pointer to a bus alias object for the given label, or null if one doesn't exist.
std::vector< SCH_MARKER * > ResolveERCExclusions()
void EmbedFonts() override
Embed fonts in the schematic.
SCHEMATIC_SETTINGS & Settings() const
SCH_SCREEN * GetCurrentScreen() const
Definition schematic.h:181
wxString ConvertKIIDsToRefs(const wxString &aSource) const
SCH_ITEM * ResolveItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr, bool aAllowNullptrReturn=false) const
Definition schematic.h:134
void RecordERCExclusions()
Scan existing markers and record data from any that are Excluded.
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
std::map< wxString, std::set< int > > & GetPageRefsMap()
Definition schematic.h:219
void FixupJunctionsAfterImport()
Add junctions to this schematic where required.
std::set< KIFONT::OUTLINE_FONT * > GetFonts() const override
Get a set of fonts used in the schematic.
bool Contains(const SCH_REFERENCE &aRef) const
Check if the schematic contains the specified reference.
wxString ConvertRefsToKIIDs(const wxString &aSource) const
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
void SetProject(PROJECT *aPrj)
void AddListener(SCHEMATIC_LISTENER *aListener)
Add a listener to the schematic to receive calls whenever something on the schematic has been modifie...
std::map< int, wxString > GetVirtualPageToSheetPagesMap() const
EMBEDDED_FILES * GetEmbeddedFiles() override
PROJECT * m_project
Definition schematic.h:436
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:183
SCH_SCREEN * RootScreen() const
Helper to retrieve the screen of the root sheet.
SCHEMATIC(PROJECT *aPrj)
Definition schematic.cpp:56
bool ResolveTextVar(const SCH_SHEET_PATH *aSheetPath, wxString *token, int aDepth) const
std::set< wxString > GetNetClassAssignmentCandidates()
Return the set of netname candidates for netclass assignment.
void InvokeListeners(Func &&aFunc, Args &&... args)
Definition schematic.h:430
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition schematic.h:156
static bool m_IsSchematicExists
True if a SCHEMATIC exists, false if not.
Definition schematic.h:418
void RemoveAllListeners()
Remove all listeners.
void GetContextualTextVars(wxArrayString *aVars) const
SCH_SHEET & Root() const
Definition schematic.h:140
std::map< int, wxString > GetVirtualPageToSheetNamesMap() const
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.
SCHEMATIC_HOLDER * m_schematicHolder
What currently "Holds" the schematic, i.e.
Definition schematic.h:483
wxString GetUniqueFilenameForCurrentSheet()
Get the unique file name for the current sheet.
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
std::vector< SCHEMATIC_LISTENER * > m_listeners
Currently installed listeners.
Definition schematic.h:478
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:171
bool ResolveCrossReference(wxString *token, int aDepth) const
Resolves text vars that refer to other items.
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags, TOOL_MANAGER *aToolManager, PROGRESS_REPORTER *aProgressReporter=nullptr, KIGFX::SCH_VIEW *aSchView=nullptr, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PICKED_ITEMS_LIST *aLastChangeList=nullptr)
Generate the connection data for the entire schematic hierarchy.
std::map< wxString, double > m_operatingPoints
Simulation operating points for text variable substitution.
Definition schematic.h:468
ERC_SETTINGS & ErcSettings() const
void RefreshHierarchy()
void OnItemsChanged(std::vector< SCH_ITEM * > &aItems)
Notify the schematic and its listeners that an item on the schematic has been modified in some way.
SCH_SHEET * m_rootSheet
The top-level sheet in this schematic hierarchy (or potentially the only one)
Definition schematic.h:439
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString Name(bool aIgnoreSheet=false) const
bool IsBus() const
FIELD_T GetId() const
Definition sch_field.h:116
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
virtual bool IsConnectable() const
Definition sch_item.h:493
int GetUnit() const
Definition sch_item.h:238
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition sch_item.h:309
VECTOR2I GetPosition() const override
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
SCH_LINE * NonGroupAware_BreakAt(const VECTOR2I &aPoint)
This version should only be used when importing files.
Definition sch_line.cpp:562
bool IsParallel(const SCH_LINE *aLine) const
Definition sch_line.cpp:416
VECTOR2I GetEndPoint() const
Definition sch_line.h:144
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
SCH_LINE * MergeOverlap(SCH_SCREEN *aScreen, SCH_LINE *aLine, bool aCheckJunctions)
Check line against aLine to see if it overlaps and merge if it does.
Definition sch_line.cpp:429
bool IsNull() const
Definition sch_line.h:137
bool IsStrokeEquivalent(const SCH_LINE *aLine)
Definition sch_line.h:196
bool IsEndPoint(const VECTOR2I &aPoint) const override
Test if aPt is an end point of this schematic object.
Definition sch_line.h:91
static SCH_MARKER * DeserializeFromString(const SCH_SHEET_LIST &aSheetList, const wxString &data)
wxString SerializeToString() const
bool IsLegacyMarker() const
Determine if this marker is legacy (i.e.
Definition sch_marker.h:121
VECTOR2I GetPosition() const override
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
A helper to define a symbol's reference designator in a schematic.
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const override
Make a set of SHAPE objects representing the EDA_SHAPE.
const std::unordered_set< SCH_ITEM * > & GetContainedItems() const
Return a set of all items contained within the rule area.
static std::vector< std::pair< SCH_RULE_AREA *, SCH_SCREEN * > > UpdateRuleAreasInScreens(std::unordered_set< SCH_SCREEN * > &screens, KIGFX::SCH_VIEW *view)
Update all rule area connectvity / caches in the given sheet paths.
const std::unordered_set< KIID > & GetPastContainedItems() const
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:758
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
void SetLegacySymbolInstanceData()
Update the symbol value and footprint instance data for legacy designs.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
bool IsExplicitJunction(const VECTOR2I &aPosition) const
Indicate that a junction dot is necessary at the given location.
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:117
const KIID & GetUuid() const
Definition sch_screen.h:539
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
const TITLE_BLOCK & GetTitleBlock() const
Definition sch_screen.h:163
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
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 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 HasPath(const KIID_PATH &aPath) const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
SCH_SHEET * at(size_t aIndex) const
Forwarded method from std::vector.
void SetVirtualPageNumber(int aPageNumber)
Set the sheet instance virtual page number.
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
wxString GetName() const
Definition sch_sheet.h:113
int CountSheets() const
Count the number of sheets found in "this" sheet including all of the subsheets.
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition sch_sheet.h:187
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the sheet.
Schematic symbol object.
Definition sch_symbol.h:75
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:134
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:164
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
bool CollideEdge(const VECTOR2I &aPoint, VERTEX_INDEX *aClosestVertex=nullptr, int aClearance=0) const
Check whether aPoint collides with any edge of any of the contours of the polygon.
Helper class to recognize Spice formatted values.
Definition spice_value.h:56
wxString ToString() const
Return string value as when converting double to string (e.g.
bool TextVarResolver(wxString *aToken, const PROJECT *aProject, int aFlags=0) const
static void GetContextualTextVars(wxArrayString *aVars)
Master controller class:
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
#define STRUCT_DELETED
flag indication structures to be erased
void ignore_unused(const T &)
Definition ignore.h:24
@ LAYER_WIRE
Definition layer_ids.h:451
@ LAYER_BUS
Definition layer_ids.h:452
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
void for_all_pairs(_InputIterator __first, _InputIterator __last, _Function __f)
Apply a function to every possible pair of elements of a sequence.
Definition kicad_algo.h:84
#define _HKI(x)
Definition page_info.cpp:44
#define TYPE_HASH(x)
Definition property.h:73
void CollectOtherUnits(const wxString &aRef, int aUnit, const LIB_ID &aLibId, SCH_SHEET_PATH &aSheet, std::vector< SCH_SYMBOL * > *otherUnits)
@ AUTOPLACE_AUTO
Definition sch_item.h:70
SCH_CLEANUP_FLAGS
Definition schematic.h:74
@ LOCAL_CLEANUP
Definition schematic.h:76
@ GLOBAL_CLEANUP
Definition schematic.h:77
A simple container for schematic symbol instance information.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
@ SCH_LINE_T
Definition typeinfo.h:165
@ SCH_NO_CONNECT_T
Definition typeinfo.h:162
@ SCH_SYMBOL_T
Definition typeinfo.h:174
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:173
@ SCH_SHEET_T
Definition typeinfo.h:177
@ SCH_MARKER_T
Definition typeinfo.h:160
@ SCH_RULE_AREA_T
Definition typeinfo.h:172
@ SCHEMATIC_T
Definition typeinfo.h:206
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:170
@ SCH_JUNCTION_T
Definition typeinfo.h:161
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695