KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_screen.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) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <stack>
24#include <vector>
25#include <wx/filefn.h>
26#include <wx/log.h>
27
28#include <eda_item.h>
29#include <id.h>
30#include <string_utils.h>
31#include <kiway.h>
32#include <plotters/plotter.h>
33#include <sch_plotter.h>
34#include <project.h>
35#include <project_sch.h>
36#include <reporter.h>
37#include <trace_helpers.h>
38#include <sch_edit_frame.h>
39#include <sch_item.h>
40
42#include <connection_graph.h>
43#include <junction_helpers.h>
44#include <sch_commit.h>
45#include <sch_pin.h>
46#include <sch_symbol.h>
47#include <sch_group.h>
48#include <sch_junction.h>
49#include <sch_line.h>
50#include <sch_marker.h>
51#include <sch_sheet.h>
52#include <sch_sheet_pin.h>
53#include <sch_text.h>
54#include <schematic.h>
56#include <tool/common_tools.h>
57#include <sim/sim_model.h> // For V6 to V7 simulation model migration.
58#include <locale_io.h>
59
60#include <algorithm>
61#include <math/vector3.h>
62#include <memory>
63
64// TODO(JE) Debugging only
65#include <core/profile.h>
67
68#include "sch_bus_entry.h"
69#include "sch_shape.h"
70
76static const wxChar DanglingProfileMask[] = wxT( "DANGLING_PROFILE" );
77
78
80 BASE_SCREEN( aParent, SCH_SCREEN_T ),
83 m_isReadOnly( false ),
84 m_fileExists( false )
85{
87 m_refCount = 0;
88 m_zoomInitialized = false;
89 m_LastZoomLevel = 1.0;
90
91 // Suitable for schematic only. For symbol_editor and viewlib, must be set to true
92 m_Center = false;
93
94 InitDataPoints( m_paper.GetSizeIU( schIUScale.IU_PER_MILS ) );
95}
96
97
103
104
106{
107 wxCHECK_MSG( GetParent() && GetParent()->Type() == SCHEMATIC_T, nullptr,
108 wxT( "SCH_SCREEN must have a SCHEMATIC parent!" ) );
109
110 return static_cast<SCHEMATIC*>( GetParent() );
111}
112
113
115{
116 for( const std::pair<const wxString, LIB_SYMBOL*>& libSymbol : m_libSymbols )
117 delete libSymbol.second;
118
119 m_libSymbols.clear();
120}
121
122
123void SCH_SCREEN::SetFileName( const wxString& aFileName )
124{
125 // Don't assert here. We still call this after failing to load a file in order to show the
126 // user what we *tried* to load.
127 // wxASSERT( aFileName.IsEmpty() || wxIsAbsolutePath( aFileName ) );
128
129 m_fileName = aFileName;
130}
131
132
134{
135 m_refCount++;
136}
137
138
140{
141 wxCHECK_RET( m_refCount != 0, wxT( "Screen reference count already zero. Bad programmer!" ) );
142 m_refCount--;
143}
144
145
146bool SCH_SCREEN::HasItems( KICAD_T aItemType ) const
147{
148 EE_RTREE::EE_TYPE sheets = m_rtree.OfType( aItemType );
149
150 return sheets.begin() != sheets.end();
151}
152
153
154bool SCH_SCREEN::ClassOf( const EDA_ITEM* aItem )
155{
156 return aItem && SCH_SCREEN_T == aItem->Type();
157}
158
159
160void SCH_SCREEN::Append( SCH_ITEM* aItem, bool aUpdateLibSymbol )
161{
162 if( aItem->Type() != SCH_SHEET_PIN_T && aItem->Type() != SCH_FIELD_T )
163 {
164 // Ensure the item can reach the SCHEMATIC through this screen
165 aItem->SetParent( this );
166
167 if( aItem->Type() == SCH_SYMBOL_T && aUpdateLibSymbol )
168 {
169 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
170
171 if( symbol->GetLibSymbolRef() )
172 {
173 symbol->GetLibSymbolRef()->GetDrawItems().sort();
174
175 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
176
177 if( it == m_libSymbols.end() || !it->second )
178 {
180 new LIB_SYMBOL( *symbol->GetLibSymbolRef() );
181 }
182 else
183 {
184 // The original library symbol may have changed since the last time
185 // it was added to the schematic. If it has changed, then a new name
186 // must be created for the library symbol list to prevent all of the
187 // other schematic symbols referencing that library symbol from changing.
188 LIB_SYMBOL* foundSymbol = it->second;
189
190 foundSymbol->GetDrawItems().sort();
191
192 if( *foundSymbol != *symbol->GetLibSymbolRef() )
193 {
194 wxString newName;
195 std::vector<wxString> matches;
196
197 getLibSymbolNameMatches( *symbol, matches );
198 foundSymbol = nullptr;
199
200 for( const wxString& libSymbolName : matches )
201 {
202 it = m_libSymbols.find( libSymbolName );
203
204 if( it == m_libSymbols.end() )
205 continue;
206
207 foundSymbol = it->second;
208
209 wxCHECK2( foundSymbol, continue );
210
211 wxString tmp = symbol->GetLibSymbolRef()->GetName();
212
213 // Temporarily update the new symbol library symbol name so it
214 // doesn't fail on the name comparison below.
215 symbol->GetLibSymbolRef()->SetName( foundSymbol->GetName() );
216
217 if( *foundSymbol == *symbol->GetLibSymbolRef() )
218 {
219 newName = libSymbolName;
220 symbol->GetLibSymbolRef()->SetName( tmp );
221 break;
222 }
223
224 symbol->GetLibSymbolRef()->SetName( tmp );
225 foundSymbol = nullptr;
226 }
227
228 if( !foundSymbol )
229 {
230 int cnt = 1;
231
232 newName.Printf( wxT( "%s_%d" ),
234 cnt );
235
236 while( m_libSymbols.find( newName ) != m_libSymbols.end() )
237 {
238 cnt += 1;
239 newName.Printf( wxT( "%s_%d" ),
241 cnt );
242 }
243 }
244
245 // Update the schematic symbol library link as this symbol only exists
246 // in the schematic.
247 symbol->SetSchSymbolLibraryName( newName );
248
249 if( !foundSymbol )
250 {
251 // Update the schematic symbol library link as this symbol does not
252 // exist in any symbol library.
253 LIB_ID newLibId( wxEmptyString, newName );
254 LIB_SYMBOL* newLibSymbol = new LIB_SYMBOL( *symbol->GetLibSymbolRef() );
255
256 newLibSymbol->SetLibId( newLibId );
257 newLibSymbol->SetName( newName );
258 symbol->SetLibSymbol( newLibSymbol->Flatten().release() );
259 m_libSymbols[newName] = newLibSymbol;
260 }
261 }
262 else
263 {
264 // LIB_SYMBOL::Compare ignores embedded files, so an embedded-file-only
265 // edit leaves the cached symbol equal but stale. Refresh the cache from
266 // the instance so the change survives serialization.
267 *foundSymbol->GetEmbeddedFiles() = *symbol->GetLibSymbolRef()->GetEmbeddedFiles();
268 }
269 }
270 }
271 }
272
273 m_rtree.insert( aItem );
275 }
276}
277
278
280{
281 wxCHECK_RET( aScreen, "Invalid screen object." );
282
283 // No need to descend the hierarchy. Once the top level screen is copied, all of its
284 // children are copied as well.
285 for( SCH_ITEM* aItem : aScreen->m_rtree )
286 Append( aItem );
287
288 aScreen->Clear( false );
289}
290
291
292void SCH_SCREEN::Clear( bool aFree )
293{
294 if( aFree )
295 {
296 FreeDrawList();
298 }
299 else
300 {
301 m_rtree.clear();
302 }
303
304 // Clear the project settings
306
307 m_titles.Clear();
308}
309
310
312{
313 // We don't know which order we will encounter dependent items (e.g. pins or fields), so
314 // we store the items to be deleted until we've fully cleared the tree before deleting
315 std::vector<SCH_ITEM*> delete_list;
316
317 std::copy_if( m_rtree.begin(), m_rtree.end(), std::back_inserter( delete_list ),
318 []( SCH_ITEM* aItem )
319 {
320 return ( aItem->Type() != SCH_SHEET_PIN_T && aItem->Type() != SCH_FIELD_T );
321 } );
322
323 m_rtree.clear();
324
325 for( SCH_ITEM* item : delete_list )
326 delete item;
327}
328
329
330void SCH_SCREEN::Update( SCH_ITEM* aItem, bool aUpdateLibSymbol )
331{
332 if( Remove( aItem, aUpdateLibSymbol ) )
333 Append( aItem, aUpdateLibSymbol );
334}
335
336
337bool SCH_SCREEN::Remove( SCH_ITEM* aItem, bool aUpdateLibSymbol )
338{
339 bool retv = m_rtree.remove( aItem );
340
341 // Check if the library symbol for the removed schematic symbol is still required.
342 if( retv && aItem->Type() == SCH_SYMBOL_T && aUpdateLibSymbol )
343 {
344 SCH_SYMBOL* removedSymbol = static_cast<SCH_SYMBOL*>( aItem );
345
346 bool removeUnusedLibSymbol = true;
347
348 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
349 {
350 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
351
352 if( removedSymbol->GetSchSymbolLibraryName() == symbol->GetSchSymbolLibraryName() )
353 {
354 removeUnusedLibSymbol = false;
355 break;
356 }
357 }
358
359 if( removeUnusedLibSymbol )
360 {
361 auto it = m_libSymbols.find( removedSymbol->GetSchSymbolLibraryName() );
362
363 if( it != m_libSymbols.end() )
364 {
365 delete it->second;
366 m_libSymbols.erase( it );
367 }
368 }
369 }
370
371 return retv;
372}
373
374
376{
377 wxCHECK_RET( aItem, wxT( "Cannot delete invalid item from screen." ) );
378
379 // Markers are not saved in the file, no need to flag as modified.
380 // TODO: Maybe we should have a listing somewhere of items that aren't saved?
381 if( aItem->Type() != SCH_MARKER_T )
383
384 Remove( aItem );
385
386 if( aItem->Type() == SCH_SHEET_PIN_T )
387 {
388 // This structure is attached to a sheet, get the parent sheet object.
389 SCH_SHEET_PIN* sheetPin = (SCH_SHEET_PIN*) aItem;
390 SCH_SHEET* sheet = sheetPin->GetParent();
391 wxCHECK_RET( sheet, wxT( "Sheet pin parent not properly set, bad programmer!" ) );
392 sheet->RemovePin( sheetPin );
393 return;
394 }
395
396 delete aItem;
397}
398
399
400bool SCH_SCREEN::CheckIfOnDrawList( const SCH_ITEM* aItem ) const
401{
402 return m_rtree.contains( aItem, true );
403}
404
405
406SCH_ITEM* SCH_SCREEN::GetItem( const VECTOR2I& aPosition, int aAccuracy, KICAD_T aType ) const
407{
408 BOX2I bbox;
409 bbox.SetOrigin( aPosition );
410 bbox.Inflate( aAccuracy );
411
412 for( SCH_ITEM* item : Items().Overlapping( aType, bbox ) )
413 {
414 if( item->HitTest( aPosition, aAccuracy ) )
415 return item;
416 }
417
418 return nullptr;
419}
420
421
422std::set<SCH_ITEM*> SCH_SCREEN::MarkConnections( SCH_ITEM* aItem, bool aSecondPass )
423{
424#define PROCESSED CANDIDATE // Don't use SKIP_STRUCT; IsConnected() returns false if it's set.
425
426 std::set<SCH_ITEM*> retval;
427 std::stack<SCH_ITEM*> toSearch;
428
429 auto getItemEndpoints = []( SCH_ITEM* aCandidate ) -> std::vector<VECTOR2I>
430 {
431 if( !aCandidate )
432 return {};
433
434 if( aCandidate->Type() == SCH_LINE_T )
435 {
436 SCH_LINE* line = static_cast<SCH_LINE*>( aCandidate );
437 return { line->GetStartPoint(), line->GetEndPoint() };
438 }
439
440 if( aCandidate->Type() == SCH_SHAPE_T )
441 {
442 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aCandidate );
443
444 if( shape->GetShape() == SHAPE_T::ARC || shape->GetShape() == SHAPE_T::BEZIER )
445 return { shape->GetStart(), shape->GetEnd() };
446 else if( shape->GetShape() == SHAPE_T::RECTANGLE )
447 return shape->GetRectCorners();
448 else if( shape->GetShape() == SHAPE_T::SEGMENT )
449 return { shape->GetStart(), shape->GetEnd() };
450 else if( shape->GetShape() == SHAPE_T::POLY )
451 return shape->GetPolyPoints();
452 }
453
454 return {};
455 };
456
457 if( !aItem || getItemEndpoints( aItem ).empty() )
458 return retval;
459
460 toSearch.push( aItem );
461
462 while( !toSearch.empty() )
463 {
464 SCH_ITEM* item = toSearch.top();
465 toSearch.pop();
466
467 if( item->HasFlag( PROCESSED ) )
468 continue;
469
470 item->SetFlags( PROCESSED );
471
472 const BOX2I bbox = item->GetBoundingBox();
473
474 for( KICAD_T type : { SCH_LINE_T, SCH_SHAPE_T } )
475 {
476 for( SCH_ITEM* candidate : Items().Overlapping( type, bbox ) )
477 {
478 if( candidate->HasFlag( PROCESSED ) )
479 continue;
480
481 std::vector<VECTOR2I> endpoints = getItemEndpoints( candidate );
482
483 if( endpoints.empty() )
484 continue;
485
486 // Skip connecting items on different layers (e.g. buses)
487 if( item->GetLayer() != candidate->GetLayer() )
488 continue;
489
490 bool sharesEndpoint = false;
491
492 for( const VECTOR2I& pt : endpoints )
493 {
494 if( item->IsEndPoint( pt ) )
495 {
496 sharesEndpoint = true;
497
498 if( aSecondPass && item->IsConnected( pt ) )
499 {
500 SCH_ITEM* junction = GetItem( pt, 0, SCH_JUNCTION_T );
501
502 if( junction )
503 retval.insert( junction );
504 }
505 }
506 }
507
508 if( !sharesEndpoint )
509 continue;
510
511 toSearch.push( candidate );
512 retval.insert( candidate );
513 }
514 }
515 }
516
517 for( SCH_ITEM* item : Items() )
518 item->ClearTempFlags();
519
520 return retval;
521}
522
523
524bool SCH_SCREEN::IsJunction( const VECTOR2I& aPosition ) const
525{
527 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, false );
528 return info.isJunction;
529}
530
531
532bool SCH_SCREEN::IsExplicitJunction( const VECTOR2I& aPosition ) const
533{
535 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, false );
536
537 return info.AllowsExplicitJunction();
538}
539
540
541bool SCH_SCREEN::IsExplicitJunctionNeeded( const VECTOR2I& aPosition ) const
542{
544 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, false );
545
546 return info.AllowsExplicitJunction() && !info.hasExplicitJunctionDot;
547}
548
549
551{
553 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, true );
554
555 return info.AllowsExplicitJunction();
556}
557
558
560 SPIN_STYLE aDefaultOrientation,
561 const SCH_SHEET_PATH* aSheet ) const
562{
563 auto ret = aDefaultOrientation;
564
565 for( SCH_ITEM* item : Items().Overlapping( aPosition ) )
566 {
567 if( item->GetEditFlags() & STRUCT_DELETED )
568 continue;
569
570 switch( item->Type() )
571 {
573 {
574 auto busEntry = static_cast<const SCH_BUS_WIRE_ENTRY*>( item );
575 if( busEntry->m_connected_bus_item )
576 {
577 // bus connected, take the bus direction into consideration only if it is
578 // vertical or horizontal
579 auto bus = static_cast<const SCH_LINE*>( busEntry->m_connected_bus_item );
580 if( bus->Angle().AsDegrees() == 90.0 )
581 {
582 // bus is vertical -> label shall be horizontal and
583 // shall be placed to the side where the bus entry is
584 if( aPosition.x < bus->GetPosition().x )
585 ret = SPIN_STYLE::LEFT;
586 else if( aPosition.x > bus->GetPosition().x )
587 ret = SPIN_STYLE::RIGHT;
588 }
589 else if( bus->Angle().AsDegrees() == 0.0 )
590 {
591 // bus is horizontal -> label shall be vertical and
592 // shall be placed to the side where the bus entry is
593 if( aPosition.y < bus->GetPosition().y )
594 ret = SPIN_STYLE::UP;
595 else if( aPosition.y > bus->GetPosition().y )
596 ret = SPIN_STYLE::BOTTOM;
597 }
598 }
599 }
600 break;
601
602 case SCH_LINE_T:
603 {
604 auto line = static_cast<const SCH_LINE*>( item );
605 // line angles goes between -90 and 90 degrees, but normalize
606 auto angle = line->Angle().Normalize90().AsDegrees();
607
608 if( -45 < angle && angle <= 45 )
609 {
610 if( line->GetStartPoint().x <= line->GetEndPoint().x )
611 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::RIGHT : SPIN_STYLE::LEFT;
612 else
613 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::LEFT : SPIN_STYLE::RIGHT;
614 }
615 else
616 {
617 if( line->GetStartPoint().y <= line->GetEndPoint().y )
618 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::BOTTOM : SPIN_STYLE::UP;
619 else
620 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::UP : SPIN_STYLE::BOTTOM;
621 }
622 }
623 break;
624
625 case SCH_SYMBOL_T:
626 {
627 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
628
629 for( SCH_PIN* pin : symbol->GetPins( aSheet ) )
630 {
631 if( pin->GetPosition() == aPosition )
632 {
633 ret = GetPinSpinStyle( *pin, *symbol );
634 break;
635 }
636 }
637 }
638 break;
639
640 default: break;
641 }
642 }
643
644 return ret;
645}
646
647
648bool SCH_SCREEN::IsTerminalPoint( const VECTOR2I& aPosition, int aLayer ) const
649{
650 wxCHECK_MSG( aLayer == LAYER_NOTES || aLayer == LAYER_BUS || aLayer == LAYER_WIRE, false,
651 wxT( "Invalid layer type passed to SCH_SCREEN::IsTerminalPoint()." ) );
652
653 SCH_SHEET_PIN* sheetPin;
654 SCH_LABEL_BASE* label;
655
656 switch( aLayer )
657 {
658 case LAYER_BUS:
659 if( GetBus( aPosition ) )
660 return true;
661
662 sheetPin = GetSheetPin( aPosition );
663
664 if( sheetPin && sheetPin->IsConnected( aPosition ) )
665 return true;
666
667 label = GetLabel( aPosition );
668
669 if( label && !label->IsNew() && label->IsConnected( aPosition ) )
670 return true;
671
672 break;
673
674 case LAYER_NOTES:
675 if( GetLine( aPosition ) )
676 return true;
677
678 break;
679
680 case LAYER_WIRE:
681 if( GetItem( aPosition, 1, SCH_BUS_WIRE_ENTRY_T ) )
682 return true;
683
684 if( GetItem( aPosition, 1, SCH_JUNCTION_T ) )
685 return true;
686
687 if( GetPin( aPosition, nullptr, true ) )
688 return true;
689
690 if( GetWire( aPosition ) )
691 return true;
692
693 label = GetLabel( aPosition, 1 );
694
695 if( label && !label->IsNew() && label->IsConnected( aPosition ) )
696 return true;
697
698 sheetPin = GetSheetPin( aPosition );
699
700 if( sheetPin && sheetPin->IsConnected( aPosition ) )
701 return true;
702
703 break;
704
705 default:
706 break;
707 }
708
709 return false;
710}
711
712
714 SYMBOL_LIBRARY_ADAPTER* aLibraries )
715{
716 wxCHECK_RET( Schematic(), "Cannot call SCH_SCREEN::UpdateSymbolLinks with no SCHEMATIC" );
717
718 wxString msg;
719 std::vector<SCH_SYMBOL*> symbols;
720 SYMBOL_LIBRARY_ADAPTER* libs = aLibraries ? aLibraries
721 : PROJECT_SCH::SymbolLibAdapter( &Schematic()->Project() );
722
723 // Headless GUI callers can share an adapter with the editor's preload worker.
724 if( aLegacyLibs )
725 libs->AbortAsyncLoad();
726
727 LEGACY_SYMBOL_LIBS* legacyLibs = aLegacyLibs ? aLegacyLibs : PROJECT_SCH::LegacySchLibs( &Schematic()->Project() );
728
729 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
730 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
731
732 // Remove them from the R tree. Their bounding box size may change.
733 for( SCH_SYMBOL* symbol : symbols )
734 Remove( symbol );
735
736 // Clear all existing symbol links.
738
739 for( SCH_SYMBOL* symbol : symbols )
740 {
741 LIB_SYMBOL* tmp = nullptr;
742
743 // If the symbol is already in the internal library, map the symbol to it.
744 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
745
746 if( ( it != m_libSymbols.end() ) )
747 {
748 if( aReporter )
749 {
750 msg.Printf( _( "Setting schematic symbol '%s %s' library identifier to '%s'." ),
751 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
752 symbol->GetField( FIELD_T::VALUE )->GetText(),
753 UnescapeString( symbol->GetLibId().Format() ) );
754 aReporter->ReportTail( msg, RPT_SEVERITY_INFO );
755 }
756
757 // Internal library symbols are already flattened so just make a copy.
758 symbol->SetLibSymbol( new LIB_SYMBOL( *it->second ) );
759 continue;
760 }
761
762 if( !symbol->GetLibId().IsValid() && !( aLegacyLibs && symbol->GetLibId().IsLegacy() ) )
763 {
764 if( aReporter )
765 {
766 msg.Printf( _( "Schematic symbol reference '%s' library identifier is not valid. "
767 "Unable to link library symbol." ),
768 UnescapeString( symbol->GetLibId().Format() ) );
769 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
770 }
771
772 continue;
773 }
774
775 // LIB_TABLE_BASE::LoadSymbol() throws an IO_ERROR if the library nickname
776 // is not found in the table so check if the library still exists in the table
777 // before attempting to load the symbol.
778 std::optional<LIBRARY_TABLE_ROW*> libRow = libs->GetRow( symbol->GetLibId().GetLibNickname() );
779 bool hasLibraryRow = libRow.has_value();
780 bool hasLoadedLibrary = libs->HasLibrary( symbol->GetLibId().GetLibNickname() );
781
782 if( !hasLibraryRow && !legacyLibs )
783 {
784 if( aReporter )
785 {
786 msg.Printf( _( "Symbol library '%s' not found and no fallback cache library "
787 "available. Unable to link library symbol." ),
788 symbol->GetLibId().GetLibNickname().wx_str() );
789 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
790 }
791
792 continue;
793 }
794
795 if( hasLibraryRow && !hasLoadedLibrary )
796 {
797 libs->LoadOne( symbol->GetLibId().GetLibNickname() );
798 hasLoadedLibrary = libs->HasLibrary( symbol->GetLibId().GetLibNickname() );
799 }
800
801 if( hasLoadedLibrary )
802 {
803 try
804 {
805 tmp = libs->LoadSymbol( symbol->GetLibId() );
806 }
807 catch( const IO_ERROR& ioe )
808 {
809 if( aReporter )
810 {
811 msg.Printf( _( "I/O error %s resolving library symbol %s" ), ioe.What(),
812 UnescapeString( symbol->GetLibId().Format() ) );
813 aReporter->ReportTail( msg, RPT_SEVERITY_ERROR );
814 }
815 }
816 }
817
818 if( !tmp && legacyLibs && legacyLibs->GetLibraryCount() )
819 {
820 LEGACY_SYMBOL_LIB& legacyCacheLib = legacyLibs->back();
821
822 // It better be the cache library.
823 wxCHECK2( legacyCacheLib.IsCache(), continue );
824
825 wxString id = symbol->GetLibId().Format();
826
827 id.Replace( ':', '_' );
828
829 if( aReporter )
830 {
831 msg.Printf( _( "Falling back to cache to set symbol '%s:%s' link '%s'." ),
832 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
833 symbol->GetField( FIELD_T::VALUE )->GetText(),
834 UnescapeString( id ) );
835 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
836 }
837
838 tmp = legacyCacheLib.FindSymbol( id );
839 }
840
841 if( tmp )
842 {
843 // We want a full symbol not just the top level child symbol.
844 std::unique_ptr<LIB_SYMBOL> libSymbol = tmp->Flatten();
845 libSymbol->SetParent();
846
847 m_libSymbols.insert( { symbol->GetSchSymbolLibraryName(),
848 new LIB_SYMBOL( *libSymbol ) } );
849
850 if( aReporter )
851 {
852 msg.Printf( _( "Setting schematic symbol '%s %s' library identifier to '%s'." ),
853 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
854 symbol->GetField( FIELD_T::VALUE )->GetText(),
855 UnescapeString( symbol->GetLibId().Format() ) );
856 aReporter->ReportTail( msg, RPT_SEVERITY_INFO );
857 }
858
859 symbol->SetLibSymbol( libSymbol.release() );
860 }
861 else
862 {
863 if( aReporter )
864 {
865 msg.Printf( _( "No library symbol found for schematic symbol '%s %s'." ),
866 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
867 symbol->GetField( FIELD_T::VALUE )->GetText() );
868 aReporter->ReportTail( msg, RPT_SEVERITY_ERROR );
869 }
870 }
871 }
872
873 // Changing the symbol may adjust the bbox of the symbol. This re-inserts the
874 // item with the new bbox
875 for( SCH_SYMBOL* symbol : symbols )
876 Append( symbol );
877}
878
879
881{
882 std::vector<SCH_SYMBOL*> symbols;
883
884 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
885 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
886
887 for( SCH_SYMBOL* symbol : symbols )
888 {
889 // Changing the symbol may adjust the bbox of the symbol; remove and reinsert it afterwards.
890 m_rtree.remove( symbol );
891
892 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
893
894 if( it != m_libSymbols.end() )
895 symbol->SetLibSymbol( new LIB_SYMBOL( *it->second ) );
896 else
897 symbol->SetLibSymbol( nullptr );
898
899 m_rtree.insert( symbol );
900 }
901}
902
903
905{
906 SCH_ITEM* result = nullptr;
907 bool ambiguous = false;
908 const auto consider = [&]( SCH_ITEM* item )
909 {
910 if( item->m_Uuid == aId )
911 {
912 ambiguous |= result && result != item;
913 result = item;
914 }
915 };
916
917 for( SCH_ITEM* item : Items() )
918 {
919 consider( item );
920
921 if( item->Type() == SCH_SYMBOL_T || item->Type() == SCH_SHEET_T )
922 {
923 item->RunOnChildren(
924 [&]( SCH_ITEM* child )
925 {
926 if( child->IsConnectable() )
927 consider( child );
928 },
930 }
931 }
932
933 return ambiguous ? nullptr : result;
934}
935
936
938{
939 for( SCH_ITEM* item : Items() )
940 item->SetConnectivityDirty( true );
941}
942
943
944void SCH_SCREEN::Plot( PLOTTER* aPlotter, const SCH_PLOT_OPTS& aPlotOpts ) const
945{
946 std::vector<SCH_ITEM*> items;
947 items.reserve( Items().size() );
948
949 for( SCH_ITEM* item : Items() )
950 items.push_back( item );
951
952 Plot( aPlotter, aPlotOpts, items );
953}
954
955
956void SCH_SCREEN::Plot( PLOTTER* aPlotter, const SCH_PLOT_OPTS& aPlotOpts, const std::vector<SCH_ITEM*>& aItems ) const
957{
958 // Ensure links are up to date, even if a library was reloaded for some reason:
959 std::vector<SCH_ITEM*> junctions;
960 std::vector<SCH_ITEM*> bitmaps;
961 std::vector<SCH_SYMBOL*> symbols;
962 std::vector<SCH_ITEM*> other;
963 double hopOverScale = 0.0;
964 int defaultLineWidth = schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
965
966 if( !aItems.empty() && aItems[0]->Schematic() )
967 {
968 hopOverScale = aItems[0]->Schematic()->Settings().GetHopOverScale();
969 defaultLineWidth = aItems[0]->Schematic()->Settings().m_DefaultLineWidth;
970 }
971
972 for( SCH_ITEM* item : aItems )
973 {
974 if( item->IsMoving() )
975 continue;
976
977 if( item->Type() == SCH_JUNCTION_T )
978 junctions.push_back( item );
979 else if( item->Type() == SCH_BITMAP_T )
980 bitmaps.push_back( item );
981 else
982 other.push_back( item );
983
984 // Where the symbols overlap each other, we need to plot the text items a second
985 // time to get them on top of the overlapping element. This collection is in addition
986 // to the symbols already collected in `other`
987 if( item->Type() == SCH_SYMBOL_T )
988 {
989 for( SCH_ITEM* sym : m_rtree.Overlapping( SCH_SYMBOL_T, item->GetBoundingBox() ) )
990 {
991 if( sym != item )
992 {
993 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
994 break;
995 }
996 }
997 }
998 }
999
1001 std::sort( other.begin(), other.end(),
1002 []( const SCH_ITEM* a, const SCH_ITEM* b )
1003 {
1004 if( a->Type() == b->Type() )
1005 return a->GetLayer() > b->GetLayer();
1006
1007 return a->Type() > b->Type();
1008 } );
1009
1010 auto* renderSettings = static_cast<SCH_RENDER_SETTINGS*>( aPlotter->RenderSettings() );
1011 constexpr bool background = true;
1012
1013 // Bitmaps are drawn first to ensure they are in the background
1014 // This is particularly important for the wxPostscriptDC (used in *nix printers) as
1015 // the bitmap PS command clears the screen
1016 for( SCH_ITEM* item : bitmaps )
1017 {
1018 aPlotter->SetCurrentLineWidth( item->GetEffectivePenWidth( renderSettings ) );
1019 item->Plot( aPlotter, background, aPlotOpts, 0, 0, { 0, 0 }, false );
1020 }
1021
1022 // Plot the background items
1023 for( SCH_ITEM* item : other )
1024 {
1025 aPlotter->SetCurrentLineWidth( item->GetEffectivePenWidth( renderSettings ) );
1026 item->Plot( aPlotter, background, aPlotOpts, 0, 0, { 0, 0 }, false );
1027 }
1028
1029 // Plot the foreground items
1030 for( SCH_ITEM* item : other )
1031 {
1032 double lineWidth = item->GetEffectivePenWidth( renderSettings );
1033 aPlotter->SetCurrentLineWidth( lineWidth );
1034
1035 if( item->Type() != SCH_LINE_T )
1036 {
1037 item->Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1038 }
1039 else
1040 {
1041 SCH_LINE* aLine = static_cast<SCH_LINE*>( item );
1042
1043 if( ( !aLine->IsWire() && !aLine->IsBus() ) || !aPlotOpts.m_plotHopOver )
1044 {
1045 item->Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1046 }
1047 else
1048 {
1049 double arcRadius = defaultLineWidth * hopOverScale;
1050 std::vector<VECTOR3I> curr_wire_shape = aLine->BuildWireWithHopShape( this, arcRadius );
1051
1052 // The hop pieces are standalone copies/shapes without the connection map, so
1053 // resolve the net-class color and style from the original wire and reuse them.
1054 COLOR4D lineColor = aLine->GetLineColor();
1055 LINE_STYLE lineStyle = aLine->GetEffectiveLineStyle();
1056
1057 for( size_t ii = 1; ii < curr_wire_shape.size(); ii++ )
1058 {
1059 VECTOR2I start( curr_wire_shape[ii-1].x, curr_wire_shape[ii-1].y );
1060
1061 if( curr_wire_shape[ii-1].z == 0 ) // This is the start point of a segment
1062 // there are always 2 points in list for a segment
1063 {
1064 VECTOR2I end( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1065
1066 SCH_LINE curr_line( *aLine );
1067 curr_line.SetStartPoint( start );
1068 curr_line.SetEndPoint( end );
1069 curr_line.SetLineColor( lineColor );
1070 curr_line.SetLineStyle( lineStyle );
1071 curr_line.Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1072 }
1073 else // This is the start point of a arc. there are always 3 points in list for an arc
1074 {
1075 VECTOR2I arc_middle( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1076 ii++;
1077 VECTOR2I arc_end( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1078 ii++;
1079
1080 SCH_SHAPE arc( SHAPE_T::ARC, aLine->GetLayer(), lineWidth );
1081
1082 arc.SetArcGeometry( start, arc_middle, arc_end );
1083 // Hop are a small arc, so use a solid line style gives best results
1085 arc.SetLineColor( lineColor );
1086 arc.Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1087 }
1088 }
1089 }
1090 }
1091 }
1092
1093 // After plotting the symbols as a group above (in `other`), we need to overplot the pins
1094 // and symbols to ensure that they are always visible
1095 TRANSFORM savedTransform = renderSettings->m_Transform;
1096
1097 wxString variant = Schematic()->GetCurrentVariant();
1098 SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
1099
1100 for( const SCH_SYMBOL* sym :symbols )
1101 {
1102 renderSettings->m_Transform = sym->GetTransform();
1103 aPlotter->SetCurrentLineWidth( sym->GetEffectivePenWidth( renderSettings ) );
1104
1105 bool dnp = sym->GetDNP( sheet, variant );
1106
1107 for( SCH_FIELD field : sym->GetFields() )
1108 {
1109 field.ClearRenderCache();
1110 field.Plot( aPlotter, false, aPlotOpts, sym->GetUnit(), sym->GetBodyStyle(), { 0, 0 }, dnp );
1111
1112 if( sym->IsSymbolLikePowerLocalLabel() && field.GetId() == FIELD_T::VALUE
1113 && ( field.IsVisible() || field.IsForceVisible() ) )
1114 {
1115 sym->PlotLocalPowerIconShape( aPlotter );
1116 }
1117 }
1118
1119 sym->PlotPins( aPlotter, dnp );
1120
1121 if( dnp && Schematic()->Settings().m_ShowDNPMarkers )
1122 sym->PlotDNP( aPlotter );
1123 }
1124
1125 renderSettings->m_Transform = savedTransform;
1126
1127 for( SCH_ITEM* item : junctions )
1128 {
1129 aPlotter->SetCurrentLineWidth( item->GetEffectivePenWidth( renderSettings ) );
1130 item->Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1131 }
1132}
1133
1134
1136{
1137 for( SCH_ITEM* item : Items() )
1138 item->ClearTempFlags();
1139}
1140
1141
1142SCH_PIN* SCH_SCREEN::GetPin( const VECTOR2I& aPosition, SCH_SYMBOL** aSymbol,
1143 bool aEndPointOnly ) const
1144{
1145 SCH_SYMBOL* candidate = nullptr;
1146 SCH_PIN* pin = nullptr;
1147
1148 for( SCH_ITEM* item : Items().Overlapping( SCH_SYMBOL_T, aPosition ) )
1149 {
1150 candidate = static_cast<SCH_SYMBOL*>( item );
1151
1152 if( aEndPointOnly )
1153 {
1154 pin = nullptr;
1155
1156 if( !candidate->GetLibSymbolRef() )
1157 continue;
1158
1159 for( SCH_PIN* test_pin : candidate->GetLibPins() )
1160 {
1161 if( candidate->GetPinPhysicalPosition( test_pin ) == aPosition )
1162 {
1163 pin = test_pin;
1164 break;
1165 }
1166 }
1167
1168 if( pin )
1169 break;
1170 }
1171 else
1172 {
1173 pin = static_cast<SCH_PIN*>( candidate->GetDrawItem( aPosition, SCH_PIN_T ) );
1174
1175 if( pin )
1176 break;
1177 }
1178 }
1179
1180 if( pin && aSymbol )
1181 *aSymbol = candidate;
1182
1183 return pin;
1184}
1185
1186
1188{
1189 SCH_SHEET_PIN* sheetPin = nullptr;
1190
1191 for( SCH_ITEM* item : Items().Overlapping( SCH_SHEET_T, aPosition ) )
1192 {
1193 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1194
1195 sheetPin = sheet->GetPin( aPosition );
1196
1197 if( sheetPin )
1198 break;
1199 }
1200
1201 return sheetPin;
1202}
1203
1204
1205size_t SCH_SCREEN::CountConnectedItems( const VECTOR2I& aPos, bool aTestJunctions ) const
1206{
1207 size_t count = 0;
1208
1209 for( const SCH_ITEM* item : Items().Overlapping( aPos ) )
1210 {
1211 if( ( item->Type() != SCH_JUNCTION_T || aTestJunctions ) && item->IsConnected( aPos ) )
1212 count++;
1213 }
1214
1215 return count;
1216}
1217
1218
1219void SCH_SCREEN::ClearAnnotation( SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
1220{
1221
1222 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1223 {
1224 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1225
1226 symbol->ClearAnnotation( aSheetPath, aResetPrefix );
1227 }
1228}
1229
1230
1232{
1233 if( GetClientSheetPaths().size() <= 1 ) // No need for alternate reference
1234 return;
1235
1236 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1237 {
1238 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1239
1240 // Add (when not existing) all sheet path entries
1241 for( const SCH_SHEET_PATH& sheet : GetClientSheetPaths() )
1242 symbol->AddSheetPathReferenceEntryIfMissing( sheet.Path() );
1243 }
1244}
1245
1246
1247void SCH_SCREEN::GetHierarchicalItems( std::vector<SCH_ITEM*>* aItems ) const
1248{
1249 static const std::vector<KICAD_T> hierarchicalTypes = { SCH_SYMBOL_T,
1252
1253 for( SCH_ITEM* item : Items() )
1254 {
1255 if( item->IsType( hierarchicalTypes ) )
1256 aItems->push_back( item );
1257 }
1258}
1259
1260
1261void SCH_SCREEN::GetSheets( std::vector<SCH_ITEM*>* aItems ) const
1262{
1263 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1264 aItems->push_back( item );
1265
1266 std::sort( aItems->begin(), aItems->end(),
1267 []( EDA_ITEM* a, EDA_ITEM* b ) -> bool
1268 {
1269 if( a->GetPosition().x == b->GetPosition().x )
1270 {
1271 // Ensure deterministic sort
1272 if( a->GetPosition().y == b->GetPosition().y )
1273 return a->m_Uuid < b->m_Uuid;
1274
1275 return a->GetPosition().y < b->GetPosition().y;
1276 }
1277 else
1278 {
1279 return a->GetPosition().x < b->GetPosition().x;
1280 }
1281 } );
1282}
1283
1284
1286 std::function<void( SCH_ITEM* )>* aChangedHandler ) const
1287{
1288 PROF_TIMER timer( __FUNCTION__ );
1289
1290 std::vector<DANGLING_END_ITEM> endPointsByPos;
1291 std::vector<DANGLING_END_ITEM> endPointsByType;
1292
1293 auto get_ends =
1294 [&]( SCH_ITEM* item )
1295 {
1296 if( item->IsConnectable() )
1297 item->GetEndPoints( endPointsByType );
1298 };
1299
1300 auto update_state =
1301 [&]( SCH_ITEM* item )
1302 {
1303 if( item->UpdateDanglingState( endPointsByType, endPointsByPos, aPath ) )
1304 {
1305 if( aChangedHandler )
1306 ( *aChangedHandler )( item );
1307 }
1308 };
1309
1310 for( SCH_ITEM* item : Items() )
1311 {
1312 get_ends( item );
1313 item->RunOnChildren( get_ends, RECURSE_MODE::NO_RECURSE );
1314 }
1315
1316 PROF_TIMER sortTimer( "SCH_SCREEN::TestDanglingEnds pre-sort" );
1317 endPointsByPos = endPointsByType;
1318 DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
1319 sortTimer.Stop();
1320
1321 if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
1322 sortTimer.Show();
1323
1324 for( SCH_ITEM* item : Items() )
1325 {
1326 update_state( item );
1327 item->RunOnChildren( update_state, RECURSE_MODE::NO_RECURSE );
1328 }
1329
1330 if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
1331 timer.Show();
1332}
1333
1334
1335SCH_LINE* SCH_SCREEN::GetLine( const VECTOR2I& aPosition, int aAccuracy, int aLayer,
1336 SCH_LINE_TEST_T aSearchType ) const
1337{
1338 // an accuracy of 0 had problems with rounding errors; use at least 1
1339 aAccuracy = std::max( aAccuracy, 1 );
1340
1341 for( SCH_ITEM* item : Items().Overlapping( aPosition, aAccuracy ) )
1342 {
1343 if( item->Type() != SCH_LINE_T )
1344 continue;
1345
1346 if( item->GetLayer() != aLayer )
1347 continue;
1348
1349 if( !item->HitTest( aPosition, aAccuracy ) )
1350 continue;
1351
1352 switch( aSearchType )
1353 {
1354 case ENTIRE_LENGTH_T:
1355 return (SCH_LINE*) item;
1356
1358 if( !( (SCH_LINE*) item )->IsEndPoint( aPosition ) )
1359 return (SCH_LINE*) item;
1360 break;
1361
1362 case END_POINTS_ONLY_T:
1363 if( ( (SCH_LINE*) item )->IsEndPoint( aPosition ) )
1364 return (SCH_LINE*) item;
1365 }
1366 }
1367
1368 return nullptr;
1369}
1370
1371
1372std::vector<SCH_LINE*> SCH_SCREEN::GetBusesAndWires( const VECTOR2I& aPosition,
1373 bool aIgnoreEndpoints ) const
1374{
1375 std::vector<SCH_LINE*> retVal;
1376
1377 for( SCH_ITEM* item : Items().Overlapping( SCH_LINE_T, aPosition ) )
1378 {
1379 if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } ) )
1380 {
1381 SCH_LINE* wire = static_cast<SCH_LINE*>( item );
1382
1383 if( aIgnoreEndpoints && wire->IsEndPoint( aPosition ) )
1384 continue;
1385
1386 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), aPosition ) )
1387 retVal.push_back( wire );
1388 }
1389 }
1390
1391 return retVal;
1392}
1393
1394
1395std::vector<VECTOR2I> SCH_SCREEN::GetConnections() const
1396{
1397 std::vector<VECTOR2I> retval;
1398
1399 for( SCH_ITEM* item : Items() )
1400 {
1401 // Avoid items that are changing
1402 if( !( item->GetEditFlags() & ( IS_MOVING | IS_DELETED ) ) )
1403 {
1404 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1405 retval.insert( retval.end(), pts.begin(), pts.end() );
1406 }
1407 }
1408
1409 // We always have some overlapping connection points. Drop duplicates here
1410 std::sort( retval.begin(), retval.end(),
1411 []( const VECTOR2I& a, const VECTOR2I& b ) -> bool
1412 {
1413 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1414 } );
1415
1416 retval.erase( std::unique( retval.begin(), retval.end() ), retval.end() );
1417
1418 return retval;
1419}
1420
1421
1422std::vector<VECTOR2I> SCH_SCREEN::GetNeededJunctions( const std::deque<EDA_ITEM*>& aItems ) const
1423{
1424 std::vector<VECTOR2I> pts;
1425 std::vector<VECTOR2I> connections = GetConnections();
1426
1427 for( const EDA_ITEM* edaItem : aItems )
1428 {
1429 const SCH_ITEM* item = dynamic_cast<const SCH_ITEM*>( edaItem );
1430
1431 if( !item || !item->IsConnectable() )
1432 continue;
1433
1434 std::vector<VECTOR2I> new_pts = item->GetConnectionPoints();
1435 pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
1436
1437 // If the item is a line, we also add any connection points from the rest of the schematic
1438 // that terminate on the line after it is moved.
1439 if( item->Type() == SCH_LINE_T )
1440 {
1441 SCH_LINE* line = (SCH_LINE*) item;
1442
1443 for( const VECTOR2I& pt : connections )
1444 {
1445 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1446 pts.push_back( pt );
1447 }
1448 }
1449 }
1450
1451 // We always have some overlapping connection points. Drop duplicates here
1452 std::sort( pts.begin(), pts.end(),
1453 []( const VECTOR2I& a, const VECTOR2I& b ) -> bool
1454 {
1455 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1456 } );
1457
1458 pts.erase( unique( pts.begin(), pts.end() ), pts.end() );
1459
1460 // We only want the needed junction points, remove all the others
1461 pts.erase( std::remove_if( pts.begin(), pts.end(),
1462 [this]( const VECTOR2I& a ) -> bool
1463 {
1464 return !IsExplicitJunctionNeeded( a );
1465 } ),
1466 pts.end() );
1467
1468 return pts;
1469}
1470
1471
1472SCH_LABEL_BASE* SCH_SCREEN::GetLabel( const VECTOR2I& aPosition, int aAccuracy ) const
1473{
1474 for( SCH_ITEM* item : Items().Overlapping( aPosition, aAccuracy ) )
1475 {
1476 switch( item->Type() )
1477 {
1478 case SCH_LABEL_T:
1479 case SCH_GLOBAL_LABEL_T:
1480 case SCH_HIER_LABEL_T:
1482 if( item->HitTest( aPosition, aAccuracy ) )
1483 return static_cast<SCH_LABEL_BASE*>( item );
1484
1485 break;
1486
1487 default:
1488 ;
1489 }
1490 }
1491
1492 return nullptr;
1493}
1494
1495
1497{
1498 std::unique_ptr<LIB_SYMBOL> symbol( aLibSymbol );
1499 wxCHECK( symbol, /* void */ );
1500
1501 wxString key = symbol->GetLibId().Format().wx_str();
1502 AddLibSymbol( key, std::move( symbol ) );
1503}
1504
1505
1506void SCH_SCREEN::AddLibSymbol( const wxString& aKey, std::unique_ptr<LIB_SYMBOL> aLibSymbol )
1507{
1508 wxCHECK( aLibSymbol, /* void */ );
1509
1510 auto insertion = m_libSymbols.try_emplace( aKey, nullptr );
1511 auto it = insertion.first;
1512 LIB_SYMBOL* previous = std::exchange( it->second, aLibSymbol.release() );
1513
1514 delete previous;
1515}
1516
1517
1519{
1520 SCHEMATIC* schematic = Schematic();
1521
1522 const std::vector<wxString>* embeddedFonts = schematic->GetEmbeddedFiles()->UpdateFontFiles();
1523
1524 for( auto& [name, libSym] : m_libSymbols )
1525 {
1526 for( auto& [filename, embeddedFile] : libSym->EmbeddedFileMap() )
1527 {
1528 EMBEDDED_FILES::EMBEDDED_FILE* file = schematic->GetEmbeddedFile( filename );
1529
1530 if( file )
1531 {
1532 embeddedFile->compressedEncodedData = file->compressedEncodedData;
1533 embeddedFile->decompressedData = file->decompressedData;
1534 embeddedFile->data_hash = file->data_hash;
1535 embeddedFile->is_valid = file->is_valid;
1536 }
1537 }
1538
1539 libSym->RunOnChildren(
1540 [&]( SCH_ITEM* aChild )
1541 {
1542 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aChild ) )
1543 textItem->ResolveFont( embeddedFonts );
1544 },
1546 }
1547
1548 std::vector<SCH_ITEM*> items_to_update;
1549
1550 for( SCH_ITEM* item : Items() )
1551 {
1552 bool update = false;
1553
1554 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( item ) )
1555 update |= textItem->ResolveFont( embeddedFonts );
1556
1557 item->RunOnChildren(
1558 [&]( SCH_ITEM* aChild )
1559 {
1560 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aChild ) )
1561 update |= textItem->ResolveFont( embeddedFonts );
1562 },
1564
1565 if( update )
1566 items_to_update.push_back( item );
1567 }
1568
1569 for( SCH_ITEM* item : items_to_update )
1570 Update( item );
1571}
1572
1573
1574void SCH_SCREEN::AddBusAlias( std::shared_ptr<BUS_ALIAS> aAlias )
1575{
1576 if( SCHEMATIC* schematic = Schematic() )
1577 schematic->AddBusAlias( aAlias );
1578}
1579
1580
1582{
1583 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1584 {
1585 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1586
1587 // Add missing value and footprint instance data for legacy schematics.
1588 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
1589 {
1590 symbol->AddHierarchicalReference( instance.m_Path, instance.m_Reference,
1591 instance.m_Unit );
1592 }
1593 }
1594}
1595
1596
1598{
1599 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1600 {
1601 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1602
1603 // Fix pre-8.0 legacy power symbols with invisible pins
1604 // that have mismatched pin names and value fields
1605 if( symbol->GetLibSymbolRef()
1606 && symbol->GetLibSymbolRef()->IsGlobalPower()
1607 && symbol->GetAllLibPins().size() > 0
1608 && symbol->GetAllLibPins()[0]->IsGlobalPower()
1609 && !symbol->GetAllLibPins()[0]->IsVisible() )
1610 {
1611 symbol->SetValueFieldText( symbol->GetAllLibPins()[0]->GetName() );
1612 }
1613 }
1614}
1615
1616
1618 std::vector<wxString>& aMatches )
1619{
1620 wxString searchName = aSymbol.GetLibId().GetUniStringLibId();
1621
1622 if( m_libSymbols.find( searchName ) != m_libSymbols.end() )
1623 aMatches.emplace_back( searchName );
1624
1625 searchName = aSymbol.GetLibId().GetUniStringLibItemName() + wxS( "_" );
1626
1627 long tmp;
1628 wxString suffix;
1629
1630 for( auto& pair : m_libSymbols )
1631 {
1632 if( pair.first.StartsWith( searchName, &suffix ) && suffix.ToLong( &tmp ) )
1633 aMatches.emplace_back( pair.first );
1634 }
1635
1636 return aMatches.size();
1637}
1638
1639
1640void SCH_SCREEN::PruneOrphanedSymbolInstances( const wxString& aProjectName,
1641 const SCH_SHEET_LIST& aValidSheetPaths )
1642{
1643 // The project name cannot be empty. Projects older than 7.0 did not save project names
1644 // when saving instance data. Running this algorithm with an empty project name would
1645 // clobber all instance data for projects other than the current one when a schematic
1646 // file is shared across multiple projects. Because running the schematic editor in
1647 // stand alone mode can result in an empty project name, do not assert here.
1648 if( aProjectName.IsEmpty() )
1649 return;
1650
1651 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1652 {
1653 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1654
1655 wxCHECK2( symbol, continue );
1656
1657 std::set<KIID_PATH> pathsToPrune;
1658 const std::vector<SCH_SYMBOL_INSTANCE> instances = symbol->GetInstances();
1659
1660 for( const SCH_SYMBOL_INSTANCE& instance : instances )
1661 {
1662 // Ignore instance paths from other projects.
1663 if( aProjectName != instance.m_ProjectName )
1664 continue;
1665
1666 std::optional<SCH_SHEET_PATH> pathFound =
1667 aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
1668
1669 // Check for paths that do not exist in the current project and paths that do
1670 // not contain the current symbol.
1671 if( !pathFound )
1672 pathsToPrune.emplace( instance.m_Path );
1673 else if( pathFound.value().LastScreen() != this )
1674 pathsToPrune.emplace( pathFound.value().Path() );
1675 }
1676
1677 for( const KIID_PATH& sheetPath : pathsToPrune )
1678 {
1679 wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' symbol instance %s." ),
1680 aProjectName, sheetPath.AsString() );
1681 symbol->RemoveInstance( sheetPath );
1682 }
1683 }
1684}
1685
1686
1687void SCH_SCREEN::PruneOrphanedSheetInstances( const wxString& aProjectName,
1688 const SCH_SHEET_LIST& aValidSheetPaths )
1689{
1690 // The project name cannot be empty. Projects older than 7.0 did not save project names
1691 // when saving instance data. Running this algorithm with an empty project name would
1692 // clobber all instance data for projects other than the current one when a schematic
1693 // file is shared across multiple projects. Because running the schematic editor in
1694 // stand alone mode can result in an empty project name, do not assert here.
1695 if( aProjectName.IsEmpty() )
1696 return;
1697
1698 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1699 {
1700 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1701
1702 wxCHECK2( sheet, continue );
1703
1704 std::set<KIID_PATH> pathsToPrune;
1705 const std::vector<SCH_SHEET_INSTANCE> instances = sheet->GetInstances();
1706
1707 for( const SCH_SHEET_INSTANCE& instance : instances )
1708 {
1709 // Ignore instance paths from other projects.
1710 if( aProjectName != instance.m_ProjectName )
1711 continue;
1712
1713 std::optional<SCH_SHEET_PATH> pathFound =
1714 aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
1715
1716 // Check for paths that do not exist in the current project and paths that do
1717 // not contain the current symbol.
1718 if( !pathFound )
1719 pathsToPrune.emplace( instance.m_Path );
1720 else if( pathFound.value().LastScreen() != this )
1721 pathsToPrune.emplace( pathFound.value().Path() );
1722 }
1723
1724 for( const KIID_PATH& sheetPath : pathsToPrune )
1725 {
1726 wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' sheet instance %s." ),
1727 aProjectName, sheetPath.AsString() );
1728 sheet->RemoveInstance( sheetPath );
1729 }
1730 }
1731}
1732
1733
1735{
1736 wxString trimmedFieldName;
1737
1738 for( const SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1739 {
1740 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
1741
1742 wxCHECK2( symbol, continue );
1743
1744 for( const SCH_FIELD& field : symbol->GetFields() )
1745 {
1746 trimmedFieldName = field.GetName();
1747 trimmedFieldName.Trim();
1748 trimmedFieldName.Trim( false );
1749
1750 if( field.GetName() != trimmedFieldName )
1751 return true;
1752 }
1753 }
1754
1755 return false;
1756}
1757
1758
1759std::set<wxString> SCH_SCREEN::GetSheetNames() const
1760{
1761 std::set<wxString> retv;
1762
1763 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1764 {
1765 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1766
1767 wxCHECK2( sheet, continue );
1768
1769 retv.emplace( sheet->GetName() );
1770 }
1771
1772 return retv;
1773}
1774
1775
1777{
1778 wxCHECK( Schematic(), false );
1779
1780 SCH_SHEET_LIST hierarchy = Schematic()->Hierarchy();
1781
1782 for( const SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1783 {
1784 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
1785
1786 const std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
1787
1788 for( const SCH_SYMBOL_INSTANCE& instance : symbolInstances )
1789 {
1790 if( !hierarchy.HasPath( instance.m_Path ) )
1791 return true;
1792 }
1793 }
1794
1795 return false;
1796}
1797
1798
1799wxString SCH_SCREEN::GroupsSanityCheck( bool repair )
1800{
1801 if( repair )
1802 {
1803 while( GroupsSanityCheckInternal( repair ) != wxEmptyString )
1804 {
1805 };
1806
1807 return wxEmptyString;
1808 }
1809 return GroupsSanityCheckInternal( repair );
1810}
1811
1812
1814{
1815 // Cycle detection
1816 //
1817 // Each group has at most one parent group.
1818 // So we start at group 0 and traverse the parent chain, marking groups seen along the way.
1819 // If we ever see a group that we've already marked, that's a cycle.
1820 // If we reach the end of the chain, we know all groups in that chain are not part of any cycle.
1821 //
1822 // Algorithm below is linear in the # of groups because each group is visited only once.
1823 // There may be extra time taken due to the container access calls and iterators.
1824 //
1825 // Groups we know are cycle free
1826 std::unordered_set<EDA_GROUP*> knownCycleFreeGroups;
1827 // Groups in the current chain we're exploring.
1828 std::unordered_set<EDA_GROUP*> currentChainGroups;
1829 // Groups we haven't checked yet.
1830 std::unordered_set<EDA_GROUP*> toCheckGroups;
1831
1832 // Initialize set of groups and generators to check that could participate in a cycle.
1833 for( SCH_ITEM* item : Items().OfType( SCH_GROUP_T ) )
1834 toCheckGroups.insert( static_cast<SCH_GROUP*>( item ) );
1835
1836 while( !toCheckGroups.empty() )
1837 {
1838 currentChainGroups.clear();
1839 EDA_GROUP* group = *toCheckGroups.begin();
1840
1841 while( true )
1842 {
1843 if( currentChainGroups.find( group ) != currentChainGroups.end() )
1844 {
1845 if( repair )
1846 Remove( static_cast<SCH_ITEM*>( group->AsEdaItem() ) );
1847
1848 return "Cycle detected in group membership";
1849 }
1850 else if( knownCycleFreeGroups.find( group ) != knownCycleFreeGroups.end() )
1851 {
1852 // Parent is a group we know does not lead to a cycle
1853 break;
1854 }
1855
1856 currentChainGroups.insert( group );
1857 // We haven't visited currIdx yet, so it must be in toCheckGroups
1858 toCheckGroups.erase( group );
1859
1860 group = group->AsEdaItem()->GetParentGroup();
1861
1862 if( !group )
1863 {
1864 // end of chain and no cycles found in this chain
1865 break;
1866 }
1867 }
1868
1869 // No cycles found in chain, so add it to set of groups we know don't participate
1870 // in a cycle.
1871 knownCycleFreeGroups.insert( currentChainGroups.begin(), currentChainGroups.end() );
1872 }
1873
1874 // Success
1875 return "";
1876}
1877
1878
1880{
1881 wxCHECK( Schematic() && !m_fileName.IsEmpty(), false );
1882
1883 wxFileName thisScreenFn( m_fileName );
1884 wxFileName thisProjectFn( Schematic()->Project().GetProjectFullName() );
1885
1886 wxCHECK( thisProjectFn.IsAbsolute(), false );
1887
1888 if( thisScreenFn.GetDirCount() < thisProjectFn.GetDirCount() )
1889 return false;
1890
1891 while( thisProjectFn.GetDirCount() != thisScreenFn.GetDirCount() )
1892 thisScreenFn.RemoveLastDir();
1893
1894 return thisScreenFn.GetPath() == thisProjectFn.GetPath();
1895}
1896
1897
1898std::set<wxString> SCH_SCREEN::GetVariantNames() const
1899{
1900 std::set<wxString> variantNames;
1901
1902 for( const SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1903 {
1904 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
1905
1906 wxCHECK2( symbol, continue );
1907
1908 const std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
1909
1910 for( const SCH_SYMBOL_INSTANCE& instance : symbolInstances )
1911 {
1912 for( const auto& [name, variant] : instance.m_Variants )
1913 variantNames.emplace( name );
1914 }
1915 }
1916
1917 for( const SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1918 {
1919 const SCH_SHEET* sheet = static_cast<const SCH_SHEET*>( item );
1920
1921 wxCHECK2( sheet, continue );
1922
1923 const std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
1924
1925 for( const SCH_SHEET_INSTANCE& instance : sheetInstances )
1926 {
1927 for( const auto& [name, variant] : instance.m_Variants )
1928 variantNames.emplace( name );
1929 }
1930 }
1931
1932 return variantNames;
1933}
1934
1935
1936void SCH_SCREEN::DeleteVariant( const wxString& aVariantName, SCH_COMMIT* aCommit )
1937{
1938 wxCHECK( !aVariantName.IsEmpty(), /* void */ );
1939
1940 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1941 {
1942 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1943
1944 wxCHECK2( symbol, continue );
1945
1946 std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
1947
1948 for( SCH_SYMBOL_INSTANCE& instance : symbolInstances )
1949 {
1950 if( instance.m_Variants.contains( aVariantName ) )
1951 {
1952 if( aCommit )
1953 aCommit->Modify( item, this );
1954
1955 symbol->DeleteVariant( instance.m_Path, aVariantName );
1956 }
1957 }
1958 }
1959
1960 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1961 {
1962 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1963
1964 wxCHECK2( sheet, continue );
1965
1966 std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
1967
1968 for( SCH_SHEET_INSTANCE& instance : sheetInstances )
1969 {
1970 if( instance.m_Variants.contains( aVariantName ) )
1971 {
1972 if( aCommit )
1973 aCommit->Modify( item, this );
1974
1975 sheet->DeleteVariant( instance.m_Path, aVariantName );
1976 }
1977 }
1978 }
1979}
1980
1981
1982void SCH_SCREEN::RenameVariant( const wxString& aOldName, const wxString& aNewName,
1983 SCH_COMMIT* aCommit )
1984{
1985 wxCHECK( !aOldName.IsEmpty() && !aNewName.IsEmpty(), /* void */ );
1986
1987 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1988 {
1989 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1990
1991 wxCHECK2( symbol, continue );
1992
1993 std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
1994
1995 for( SCH_SYMBOL_INSTANCE& instance : symbolInstances )
1996 {
1997 if( instance.m_Variants.contains( aOldName ) )
1998 {
1999 if( aCommit )
2000 aCommit->Modify( item, this );
2001
2002 symbol->RenameVariant( instance.m_Path, aOldName, aNewName );
2003 }
2004 }
2005 }
2006
2007 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
2008 {
2009 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2010
2011 wxCHECK2( sheet, continue );
2012
2013 std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
2014
2015 for( SCH_SHEET_INSTANCE& instance : sheetInstances )
2016 {
2017 if( instance.m_Variants.contains( aOldName ) )
2018 {
2019 if( aCommit )
2020 aCommit->Modify( item, this );
2021
2022 sheet->RenameVariant( instance.m_Path, aOldName, aNewName );
2023 }
2024 }
2025 }
2026}
2027
2028
2029void SCH_SCREEN::CopyVariant( const wxString& aSourceVariant, const wxString& aNewVariant,
2030 SCH_COMMIT* aCommit )
2031{
2032 wxCHECK( !aSourceVariant.IsEmpty() && !aNewVariant.IsEmpty(), /* void */ );
2033
2034 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
2035 {
2036 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2037
2038 wxCHECK2( symbol, continue );
2039
2040 std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
2041
2042 for( SCH_SYMBOL_INSTANCE& instance : symbolInstances )
2043 {
2044 if( instance.m_Variants.contains( aSourceVariant ) )
2045 {
2046 if( aCommit )
2047 aCommit->Modify( item, this );
2048
2049 symbol->CopyVariant( instance.m_Path, aSourceVariant, aNewVariant );
2050 }
2051 }
2052 }
2053
2054 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
2055 {
2056 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2057
2058 wxCHECK2( sheet, continue );
2059
2060 std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
2061
2062 for( SCH_SHEET_INSTANCE& instance : sheetInstances )
2063 {
2064 if( instance.m_Variants.contains( aSourceVariant ) )
2065 {
2066 if( aCommit )
2067 aCommit->Modify( item, this );
2068
2069 sheet->CopyVariant( instance.m_Path, aSourceVariant, aNewVariant );
2070 }
2071 }
2072 }
2073}
2074
2075
2076#if defined(DEBUG)
2077void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
2078{
2079 // for now, make it look like XML, expand on this later.
2080 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n";
2081
2082 for( const SCH_ITEM* item : Items() )
2083 item->Show( nestLevel + 1, os );
2084
2085 NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
2086}
2087#endif
2088
2089
2091{
2092 m_index = 0;
2093 buildScreenList( aSheet );
2094}
2095
2096
2100
2101
2103{
2104 m_index = 0;
2105
2106 if( m_screens.size() > 0 )
2107 return m_screens[0];
2108
2109 return nullptr;
2110}
2111
2112
2114{
2115 if( m_index < m_screens.size() )
2116 m_index++;
2117
2118 return GetScreen( m_index );
2119}
2120
2121
2122SCH_SCREEN* SCH_SCREENS::GetScreen( unsigned int aIndex ) const
2123{
2124 if( aIndex < m_screens.size() )
2125 return m_screens[ aIndex ];
2126
2127 return nullptr;
2128}
2129
2130
2131SCH_SHEET* SCH_SCREENS::GetSheet( unsigned int aIndex ) const
2132{
2133 if( aIndex < m_sheets.size() )
2134 return m_sheets[ aIndex ];
2135
2136 return nullptr;
2137}
2138
2139
2141{
2142 if( aScreen == nullptr )
2143 return;
2144
2145 for( const SCH_SCREEN* screen : m_screens )
2146 {
2147 if( screen == aScreen )
2148 return;
2149 }
2150
2151 m_screens.push_back( aScreen );
2152 m_sheets.push_back( aSheet );
2153}
2154
2155
2157{
2158 if( aSheet && aSheet->Type() == SCH_SHEET_T )
2159 {
2160 SCH_SCREEN* screen = aSheet->GetScreen();
2161
2162 if( !screen )
2163 return;
2164
2165 addScreenToList( screen, aSheet );
2166
2167 for( SCH_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
2168 buildScreenList( static_cast<SCH_SHEET*>( item ) );
2169 }
2170}
2171
2172
2174{
2175 SCH_SCREEN* first = GetFirst();
2176
2177 if( !first )
2178 return;
2179
2180 SCHEMATIC* sch = first->Schematic();
2181
2182 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::ClearAnnotationOfNewSheetPaths" );
2183
2184 // Clear the annotation for symbols inside new sheetpaths not already in aInitialSheetList
2185 SCH_SCREENS screensList( sch->Root() ); // The list of screens, shared by sheet paths
2186 screensList.BuildClientSheetPathList(); // build the shared by sheet paths, by screen
2187
2188 // Search for new sheet paths, not existing in aInitialSheetPathList
2189 // and existing in sheetpathList
2190 for( SCH_SHEET_PATH& sheetpath : sch->Hierarchy() )
2191 {
2192 bool path_exists = false;
2193
2194 for( const SCH_SHEET_PATH& existing_sheetpath: aInitialSheetPathList )
2195 {
2196 if( existing_sheetpath.Path() == sheetpath.Path() )
2197 {
2198 path_exists = true;
2199 break;
2200 }
2201 }
2202
2203 if( !path_exists )
2204 {
2205 // A new sheet path is found: clear the annotation corresponding to this new path:
2206 SCH_SCREEN* curr_screen = sheetpath.LastScreen();
2207
2208 // Clear annotation and create the AR for this path, if not exists,
2209 // when the screen is shared by sheet paths.
2210 // Otherwise ClearAnnotation do nothing, because the F1 field is used as
2211 // reference default value and takes the latest displayed value
2212 curr_screen->EnsureAlternateReferencesExist();
2213 curr_screen->ClearAnnotation( &sheetpath, false );
2214 }
2215 }
2216}
2217
2218
2220{
2221 std::vector<SCH_ITEM*> items;
2222 int count = 0;
2223
2224 auto timestamp_cmp = []( const EDA_ITEM* a, const EDA_ITEM* b ) -> bool
2225 {
2226 return a->m_Uuid < b->m_Uuid;
2227 };
2228
2229 std::set<EDA_ITEM*, decltype( timestamp_cmp )> unique_stamps( timestamp_cmp );
2230
2231 // Collect ALL items from all screens to detect duplicate UUIDs.
2232 // This is essential for design blocks where multiple instances of the same content
2233 // are placed on the same sheet - each instance needs unique UUIDs for items like
2234 // wires, junctions, and groups, not just symbols and sheets.
2235 for( SCH_SCREEN* screen : m_screens )
2236 {
2237 for( SCH_ITEM* item : screen->Items() )
2238 items.push_back( item );
2239 }
2240
2241 if( items.size() < 2 )
2242 return 0;
2243
2244 for( EDA_ITEM* item : items )
2245 {
2246 if( !unique_stamps.insert( item ).second )
2247 {
2248 // Reset to fully random UUID. This may lose reference, but better to be
2249 // deterministic about it rather than to have duplicate UUIDs with random
2250 // side-effects.
2251 const_cast<KIID&>( item->m_Uuid ) = KIID();
2252 count++;
2253
2254 // @todo If the item is a sheet, we need to descend the hierarchy from the sheet
2255 // and replace all instances of the changed UUID in sheet paths. Otherwise,
2256 // all instance paths with the sheet's UUID will get clobbered.
2257 }
2258 }
2259
2260 return count;
2261}
2262
2263
2265{
2266 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2267 {
2268 for( SCH_ITEM* item : screen->Items() )
2269 item->ClearEditFlags();
2270 }
2271}
2272
2273
2275{
2276 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2277 {
2278 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
2279 {
2280 if( item == aMarker )
2281 {
2282 screen->DeleteItem( item );
2283 return;
2284 }
2285 }
2286 }
2287}
2288
2289
2290void SCH_SCREENS::DeleteMarkers( enum MARKER_BASE::MARKER_T aMarkerType, int aErrorCode,
2291 bool aIncludeExclusions )
2292{
2293 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2294 {
2295 std::vector<SCH_ITEM*> markers;
2296
2297 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
2298 {
2299 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
2300 std::shared_ptr<RC_ITEM>rcItem = marker->GetRCItem();
2301
2302 if( marker->GetMarkerType() == aMarkerType
2303 && ( aErrorCode == ERCE_UNSPECIFIED || rcItem->GetErrorCode() == aErrorCode )
2304 && ( !marker->IsExcluded() || aIncludeExclusions ) )
2305 {
2306 markers.push_back( item );
2307 }
2308 }
2309
2310 for( SCH_ITEM* marker : markers )
2311 screen->DeleteItem( marker );
2312 }
2313}
2314
2315
2317 bool aIncludeExclusions )
2318{
2319 DeleteMarkers( aMarkerType, ERCE_UNSPECIFIED, aIncludeExclusions );
2320}
2321
2322
2324{
2325 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2326 screen->UpdateSymbolLinks( aReporter );
2327
2328 SCH_SCREEN* first = GetFirst();
2329
2330 if( !first )
2331 return;
2332
2333 SCHEMATIC* sch = first->Schematic();
2334
2335 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::UpdateSymbolLinks" );
2336
2337 // Replacing library symbols invalidates pointers retained by connectivity.
2338 sch->RebuildConnectivity();
2339}
2340
2341
2343{
2344 bool has_symbols = false;
2345
2346 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2347 {
2348 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
2349 {
2350 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2351 has_symbols = true;
2352
2353 if( !symbol->GetLibId().GetLibNickname().empty() )
2354 return false;
2355 }
2356 }
2357
2358 // return true (i.e. has no fully defined symbol) only if at least one symbol is found
2359 return has_symbols ? true : false;
2360}
2361
2362
2363size_t SCH_SCREENS::GetLibNicknames( wxArrayString& aLibNicknames )
2364{
2365 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2366 {
2367 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
2368 {
2369 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2370 const UTF8& nickname = symbol->GetLibId().GetLibNickname();
2371
2372 if( !nickname.empty() && ( aLibNicknames.Index( nickname ) == wxNOT_FOUND ) )
2373 aLibNicknames.Add( nickname );
2374 }
2375 }
2376
2377 return aLibNicknames.GetCount();
2378}
2379
2380
2381int SCH_SCREENS::ChangeSymbolLibNickname( const wxString& aFrom, const wxString& aTo )
2382{
2383 SCH_SCREEN* screen;
2384 int cnt = 0;
2385
2386 for( screen = GetFirst(); screen; screen = GetNext() )
2387 {
2388 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
2389 {
2390 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2391
2392 if( symbol->GetLibId().GetLibNickname().wx_str() != aFrom )
2393 continue;
2394
2395 LIB_ID id = symbol->GetLibId();
2396 id.SetLibNickname( aTo );
2397 symbol->SetLibId( id );
2398 cnt++;
2399 }
2400 }
2401
2402 return cnt;
2403}
2404
2405
2406bool SCH_SCREENS::HasSchematic( const wxString& aSchematicFileName )
2407{
2408 for( const SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2409 {
2410 if( screen->GetFileName() == aSchematicFileName )
2411 return true;
2412 }
2413
2414 return false;
2415}
2416
2417
2419{
2420 SCH_SCREEN* first = GetFirst();
2421
2422 if( !first )
2423 return;
2424
2425 SCHEMATIC* sch = first->Schematic();
2426
2427 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::BuildClientSheetPathList" );
2428
2429 // Don't build until we have a hierarchy to work with. This can be called before the hierarchy is built.
2430 if( !sch->HasHierarchy() )
2431 return;
2432
2433 for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
2434 curr_screen->GetClientSheetPaths().clear();
2435
2436 for( SCH_SHEET_PATH& sheetpath : sch->Hierarchy() )
2437 {
2438 SCH_SCREEN* used_screen = sheetpath.LastScreen();
2439
2440 // Search for the used_screen in list and add this unique sheet path:
2441 for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
2442 {
2443 if( used_screen == curr_screen )
2444 {
2445 curr_screen->GetClientSheetPaths().push_back( sheetpath );
2446 break;
2447 }
2448 }
2449 }
2450}
2451
2452
2454{
2455 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2456 screen->SetLegacySymbolInstanceData();
2457}
2458
2459
2461{
2462 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2463 screen->FixLegacyPowerSymbolMismatches();
2464}
2465
2466
2468{
2469 LOCALE_IO toggle;
2470
2471 // V6 schematics may specify model names in Value fields, which we don't do in V7.
2472 // Migrate by adding an equivalent model for these symbols.
2473
2474 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
2475 {
2476 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2477 SIM_MODEL::MigrateSimModel<SCH_SYMBOL>( *symbol, &Schematic()->Project() );
2478 }
2479}
2480
2481
2482void SCH_SCREENS::PruneOrphanedSymbolInstances( const wxString& aProjectName,
2483 const SCH_SHEET_LIST& aValidSheetPaths )
2484{
2485 if( aProjectName.IsEmpty() )
2486 return;
2487
2488 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2489 screen->PruneOrphanedSymbolInstances( aProjectName, aValidSheetPaths );
2490}
2491
2492
2493void SCH_SCREENS::PruneOrphanedSheetInstances( const wxString& aProjectName,
2494 const SCH_SHEET_LIST& aValidSheetPaths )
2495{
2496 if( aProjectName.IsEmpty() )
2497 return;
2498
2499 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2500 screen->PruneOrphanedSheetInstances( aProjectName, aValidSheetPaths );
2501}
2502
2503
2505{
2506 for( const SCH_SCREEN* screen : m_screens )
2507 {
2508 if( screen->HasSymbolFieldNamesWithWhiteSpace() )
2509 return true;
2510 }
2511
2512 return false;
2513}
2514
2515
2516std::set<wxString> SCH_SCREENS::GetVariantNames() const
2517{
2518 std::set<wxString> variantNames;
2519
2520 for( const SCH_SCREEN* screen : m_screens )
2521 {
2522 for( const wxString& variantName : screen->GetVariantNames() )
2523 variantNames.emplace( variantName );
2524 }
2525
2526 return variantNames;
2527}
2528
2529
2530void SCH_SCREENS::DeleteVariant( const wxString& aVariantName, SCH_COMMIT* aCommit )
2531{
2532 wxCHECK( !aVariantName.IsEmpty(), /* void */ );
2533
2534 for( SCH_SCREEN* screen : m_screens )
2535 screen->DeleteVariant( aVariantName, aCommit );
2536}
2537
2538
2539void SCH_SCREENS::RenameVariant( const wxString& aOldName, const wxString& aNewName,
2540 SCH_COMMIT* aCommit )
2541{
2542 wxCHECK( !aOldName.IsEmpty() && !aNewName.IsEmpty(), /* void */ );
2543
2544 for( SCH_SCREEN* screen : m_screens )
2545 screen->RenameVariant( aOldName, aNewName, aCommit );
2546}
2547
2548
2549void SCH_SCREENS::CopyVariant( const wxString& aSourceVariant, const wxString& aNewVariant,
2550 SCH_COMMIT* aCommit )
2551{
2552 wxCHECK( !aSourceVariant.IsEmpty() && !aNewVariant.IsEmpty(), /* void */ );
2553
2554 for( SCH_SCREEN* screen : m_screens )
2555 screen->CopyVariant( aSourceVariant, aNewVariant, aCommit );
2556}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
int m_virtualPageNumber
An integer based page number used for printing a range of pages.
bool m_Center
Center on screen.
Definition base_screen.h:92
int m_pageCount
The number of BASE_SCREEN objects in this design.
BASE_SCREEN(EDA_ITEM *aParent, KICAD_T aType=SCREEN_T)
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
void InitDataPoints(const VECTOR2I &aPageSizeInternalUnits)
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
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:102
static void sort_dangling_end_items(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos)
Both contain the same information.
EDA_ANGLE Normalize90()
Definition eda_angle.h:257
double AsDegrees() const
Definition eda_angle.h:116
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
const KIID m_Uuid
Definition eda_item.h:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM * GetParent() const
Definition eda_item.h:112
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
bool IsNew() const
Definition eda_item.h:131
std::vector< VECTOR2I > GetPolyPoints() const
Duplicate the polygon outlines into a flat list of VECTOR2I points.
void SetLineStyle(const LINE_STYLE aStyle)
SHAPE_T GetShape() const
Definition eda_shape.h:175
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
void SetLineColor(const COLOR4D &aColor)
Definition eda_shape.h:171
std::vector< VECTOR2I > GetRectCorners() const
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
EMBEDDED_FILE * GetEmbeddedFile(const wxString &aName) const
Returns the embedded file with the given name or nullptr if it does not exist.
const std::vector< wxString > * UpdateFontFiles()
Helper function to get a list of fonts for fontconfig to add to the library.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
Definition kiid.h:46
A collection of #SYMBOL_LIB objects.
Object used to load, save, search, and otherwise manipulate symbol library files.
LIB_SYMBOL * FindSymbol(const wxString &aName) const
Find LIB_SYMBOL by aName.
void AbortAsyncLoad()
Aborts any async load in progress; blocks until fully done aborting.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
wxString GetUniStringLibId() const
Definition lib_id.h:144
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Define a library symbol object.
Definition lib_symbol.h:119
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:832
wxString GetName() const override
Definition lib_symbol.h:181
EMBEDDED_FILES * GetEmbeddedFiles() override
bool IsGlobalPower() const override
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
void SetLibId(const LIB_ID &aLibId)
virtual void SetName(const wxString &aName)
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
bool IsExcluded() const
Definition marker_base.h:89
std::shared_ptr< RC_ITEM > GetRCItem() const
enum MARKER_T GetMarkerType() const
Definition marker_base.h:87
Base plotter engine class.
Definition plotter.h:136
RENDER_SETTINGS * RenderSettings()
Definition plotter.h:167
virtual void SetCurrentLineWidth(int width, void *aData=nullptr)=0
Set the line width for the next drawing.
A small class to help profiling.
Definition profile.h:46
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition profile.h:103
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:86
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
static LEGACY_SYMBOL_LIBS * LegacySchLibs(PROJECT *aProject)
Returns the list of symbol libraries from a legacy (pre-5.x) design This is only used from the remapp...
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & ReportTail(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the end of the list, for objects that support report ordering.
Definition reporter.h:121
Holds all the data relating to one schematic.
Definition schematic.h:148
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
bool HasHierarchy() const
Check if the hierarchy has been built.
Definition schematic.h:189
wxString GetCurrentVariant() const
Return the current variant being edited.
EMBEDDED_FILES * GetEmbeddedFiles() override
void RebuildConnectivity(std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr, KIGFX::SCH_VIEW *aSchView=nullptr)
Fully rebuild connectivity without changing source geometry.
SCH_SHEET & Root() const
Definition schematic.h:199
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:303
Class for a wire to bus entry.
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:48
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
virtual bool IsEndPoint(const VECTOR2I &aPt) const
Test if aPt is an end point of this schematic object.
Definition sch_item.h:522
virtual bool IsConnectable() const
Definition sch_item.h:531
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition sch_item.h:345
bool IsConnected(const VECTOR2I &aPoint) const
Test the item to see if it is connected to aPoint.
Definition sch_item.cpp:494
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition sch_item.h:546
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
void SetStartPoint(const VECTOR2I &aPosition)
Definition sch_line.h:137
std::vector< VECTOR3I > BuildWireWithHopShape(const SCH_SCREEN *aScreen, double aArcRadius) const
For wires only: build the list of points to draw the shape using segments and 180 deg arcs Points are...
bool IsWire() const
Return true if the line is a wire.
void SetLineColor(const COLOR4D &aColor)
Definition sch_line.cpp:371
LINE_STYLE GetEffectiveLineStyle() const
Definition sch_line.cpp:424
EDA_ANGLE Angle() const
Get the angle between the start and end lines.
Definition sch_line.h:101
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
Definition sch_line.cpp:998
VECTOR2I GetEndPoint() const
Definition sch_line.h:145
VECTOR2I GetStartPoint() const
Definition sch_line.h:136
bool IsBus() const
Return true if the line is a bus.
void SetLineStyle(const LINE_STYLE aStyle)
Definition sch_line.cpp:408
bool IsEndPoint(const VECTOR2I &aPoint) const override
Test if aPt is an end point of this schematic object.
Definition sch_line.h:88
COLOR4D GetLineColor() const
Return COLOR4D::UNSPECIFIED if a custom color hasn't been set for this line.
Definition sch_line.cpp:395
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:146
SCH_SCREEN * GetNext()
unsigned int m_index
Definition sch_screen.h:904
std::vector< SCH_SHEET * > m_sheets
Definition sch_screen.h:903
SCH_SCREEN * GetScreen(unsigned int aIndex) const
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in the full schematic.
void DeleteMarker(SCH_MARKER *aMarker)
Delete a specific marker.
void DeleteMarkers(enum MARKER_BASE::MARKER_T aMarkerTyp, int aErrorCode, bool aIncludeExclusions=true)
Delete all markers of a particular type and error code.
void buildScreenList(SCH_SHEET *aSheet)
void FixLegacyPowerSymbolMismatches()
Fix legacy power symbols that have mismatched value text fields and invisible power pin names.
void CopyVariant(const wxString &aSourceVariant, const wxString &aNewVariant, SCH_COMMIT *aCommit=nullptr)
SCH_SCREEN * GetFirst()
void DeleteAllMarkers(enum MARKER_BASE::MARKER_T aMarkerType, bool aIncludeExclusions)
Delete all electronic rules check markers of aMarkerType from all the screens in the list.
void PruneOrphanedSheetInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
int ChangeSymbolLibNickname(const wxString &aFrom, const wxString &aTo)
Change all of the symbol library nicknames.
void RenameVariant(const wxString &aOldName, const wxString &aNewName, SCH_COMMIT *aCommit=nullptr)
SCH_SCREENS(SCH_SHEET *aSheet)
void BuildClientSheetPathList()
Build the list of sheet paths sharing a screen for each screen in use.
bool HasSymbolFieldNamesWithWhiteSpace() const
void ClearAnnotationOfNewSheetPaths(SCH_SHEET_LIST &aInitialSheetPathList)
Clear the annotation for the symbols inside new sheetpaths when a complex hierarchy is modified and n...
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
void ClearEditFlags()
SCH_SHEET * GetSheet(unsigned int aIndex) const
int ReplaceDuplicateTimeStamps()
Test all sheet and symbol objects in the schematic for duplicate time stamps and replaces them as nec...
std::set< wxString > GetVariantNames() const
std::vector< SCH_SCREEN * > m_screens
Definition sch_screen.h:902
void DeleteVariant(const wxString &aVariantName, SCH_COMMIT *aCommit=nullptr)
bool HasSchematic(const wxString &aSchematicFileName)
Check if one of the schematics in the list of screens is aSchematicFileName.
size_t GetLibNicknames(wxArrayString &aLibNicknames)
Fetch all of the symbol library nicknames into aLibNicknames.
void SetLegacySymbolInstanceData()
Update the symbol value and footprint instance data for legacy designs.
void addScreenToList(SCH_SCREEN *aScreen, SCH_SHEET *aSheet)
std::set< wxString > GetVariantNames() const
void DeleteVariant(const wxString &aVariantName, SCH_COMMIT *aCommit=nullptr)
std::map< wxString, LIB_SYMBOL * > m_libSymbols
Library symbols required for this schematic.
Definition sch_screen.h:719
SCH_PIN * GetPin(const VECTOR2I &aPosition, SCH_SYMBOL **aSymbol=nullptr, bool aEndPointOnly=false) const
Test the screen for a symbol pin item at aPosition.
bool m_fileExists
Flag to indicate the file associated with this screen has been created.
Definition sch_screen.h:716
void ClearDrawingState()
Clear the state flags of all the items in the screen.
SCH_LINE * GetLine(const VECTOR2I &aPosition, int aAccuracy=0, int aLayer=LAYER_NOTES, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Return a line item located at aPosition.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void AddLibSymbol(LIB_SYMBOL *aLibSymbol)
Add aLibSymbol to the library symbol map.
bool HasSymbolFieldNamesWithWhiteSpace() const
void AddBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
Add a bus alias definition.
void FixLegacyPowerSymbolMismatches()
Fix legacy power symbols that have mismatched value text fields and invisible power pin names.
bool HasItems(KICAD_T aItemType) const
void Clear(bool aFree=true)
Delete all draw items and clears the project settings.
bool HasInstanceDataFromOtherProjects() const
Check symbols for instance data from other projects.
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
Remove all invalid symbol instance data in this screen object for the project defined by aProjectName...
std::vector< SCH_SHEET_PATH > & GetClientSheetPaths()
Return the number of times this screen is used.
Definition sch_screen.h:191
SCH_LINE * GetWire(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition sch_screen.h:451
std::set< SCH_ITEM * > MarkConnections(SCH_ITEM *aItem, bool aSecondPass)
Return all wires and junctions connected to aItem which are not connected any symbol pin or all graph...
std::set< wxString > GetSheetNames() const
TITLE_BLOCK m_titles
Definition sch_screen.h:703
void TestDanglingEnds(const SCH_SHEET_PATH *aPath=nullptr, std::function< void(SCH_ITEM *)> *aChangedHandler=nullptr) const
Test all of the connectable objects in the schematic for unused connection points.
void EnsureAlternateReferencesExist()
For screens shared by many sheetpaths (complex hierarchies): to be able to clear or modify any refere...
void PruneOrphanedSheetInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
Remove all invalid sheet instance data in this screen object for the project defined by aProjectName ...
std::vector< SCH_LINE * > GetBusesAndWires(const VECTOR2I &aPosition, bool aIgnoreEndpoints=false) const
Return buses and wires passing through aPosition.
wxString GroupsSanityCheckInternal(bool repair)
int m_modification_sync
Definition sch_screen.h:707
double m_LastZoomLevel
last value for the zoom level, useful in Eeschema when changing the current displayed sheet to reuse ...
Definition sch_screen.h:685
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:118
int m_fileFormatVersionAtLoad
Definition sch_screen.h:689
void DecRefCount()
SCH_ITEM * GetItem(const VECTOR2I &aPosition, int aAccuracy=0, KICAD_T aType=SCH_LOCATE_ANY_T) const
Check aPosition within a distance of aAccuracy for items of type aFilter.
bool IsExplicitJunctionAllowed(const VECTOR2I &aPosition) const
Indicate that a junction dot may be placed at the given location.
void clearLibSymbols()
wxString m_fileName
Definition sch_screen.h:688
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
void UpdateLocalLibSymbolLinks()
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in this schematic with the local projec...
void IncRefCount()
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
static bool ClassOf(const EDA_ITEM *aItem)
void SetLegacySymbolInstanceData()
Update the symbol value and footprint instance data for legacy designs.
void UpdateSymbolLinks(REPORTER *aReporter=nullptr, LEGACY_SYMBOL_LIBS *aLegacyLibs=nullptr, SYMBOL_LIBRARY_ADAPTER *aLibraries=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in this schematic from the project #SYM...
SCH_LINE * GetBus(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition sch_screen.h:457
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
SCH_SCREEN(EDA_ITEM *aParent=nullptr)
SCHEMATIC * Schematic() const
EE_RTREE m_rtree
Definition sch_screen.h:705
void FixupEmbeddedData()
After loading a file from disk, the library symbols do not yet contain the full data for their embedd...
SCH_ITEM * GetConnectivityItem(const KIID &aId) const
Resolve a drawing item or a connectable child on this screen; ambiguous IDs return null.
void CopyVariant(const wxString &aSourceVariant, const wxString &aNewVariant, SCH_COMMIT *aCommit=nullptr)
void GetHierarchicalItems(std::vector< SCH_ITEM * > *aItems) const
Add all schematic sheet and symbol objects in the screen to aItems.
bool IsExplicitJunctionNeeded(const VECTOR2I &aPosition) const
Indicate that a junction dot is necessary at the given location, and does not yet exist.
friend SCHEMATIC
Definition sch_screen.h:655
SCH_SHEET_PIN * GetSheetPin(const VECTOR2I &aPosition) const
Test the screen if aPosition is a sheet label object.
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
bool InProjectPath() const
Check if the schematic file is in the current project path.
void RenameVariant(const wxString &aOldName, const wxString &aNewName, SCH_COMMIT *aCommit=nullptr)
void FreeDrawList()
Free all the items from the schematic associated with the screen.
void Plot(PLOTTER *aPlotter, const SCH_PLOT_OPTS &aPlotOpts) const
Plot all the schematic objects to aPlotter.
virtual wxString GetClass() const override
Return the class name.
Definition sch_screen.h:132
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
void SetConnectivityDirty()
bool m_zoomInitialized
Definition sch_screen.h:710
std::vector< VECTOR2I > GetNeededJunctions(const std::deque< EDA_ITEM * > &aItems) const
Return the unique set of points belonging to aItems where a junction is needed.
PAGE_INFO m_paper
Definition sch_screen.h:702
bool IsJunction(const VECTOR2I &aPosition) const
Test if a junction is required for the items at aPosition on the screen.
bool m_isReadOnly
Read only status of the screen file.
Definition sch_screen.h:713
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,...
bool CheckIfOnDrawList(const SCH_ITEM *aItem) const
std::vector< VECTOR2I > GetConnections() const
Collect a unique list of all possible connection points in the schematic.
SPIN_STYLE GetLabelOrientationForPoint(const VECTOR2I &aPosition, SPIN_STYLE aDefaultOrientation, const SCH_SHEET_PATH *aSheet) const
void ClearAnnotation(SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear the annotation for the symbols in aSheetPath on the screen.
size_t CountConnectedItems(const VECTOR2I &aPos, bool aTestJunctions) const
void MigrateSimModels()
Migrate any symbols having V6 simulation models to their V7 equivalents.
void DeleteItem(SCH_ITEM *aItem)
Remove aItem from the linked list and deletes the object.
size_t getLibSymbolNameMatches(const SCH_SYMBOL &aSymbol, std::vector< wxString > &aMatches)
Return a list of potential library symbol matches for aSymbol.
SCH_LABEL_BASE * GetLabel(const VECTOR2I &aPosition, int aAccuracy=0) const
Return a label item located at aPosition.
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
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.
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...
Define a sheet pin (label) used in sheets to create hierarchical schematics.
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void CopyVariant(const KIID_PATH &aPath, const wxString &aSourceVariant, const wxString &aNewVariant)
void RemoveInstance(const KIID_PATH &aInstancePath)
wxString GetName() const
Definition sch_sheet.h:142
SCH_SHEET_PIN * GetPin(const VECTOR2I &aPosition)
Return the sheet pin item found at aPosition in the sheet.
void RemovePin(const SCH_SHEET_PIN *aSheetPin)
Remove aSheetPin from the sheet.
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
void DeleteVariant(const KIID_PATH &aPath, const wxString &aVariantName)
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition sch_sheet.h:519
Schematic symbol object.
Definition sch_symbol.h:75
void SetLibId(const LIB_ID &aName)
SCH_ITEM * GetDrawItem(const VECTOR2I &aPosition, KICAD_T aType=TYPE_NOT_INIT)
Return the symbol library item at aPosition that is part of this symbol.
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:134
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
wxString GetSchSymbolLibraryName() const
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool AddSheetPathReferenceEntryIfMissing(const KIID_PATH &aSheetPath)
Add an instance to the alternate references list (m_instances), if this entry does not already exist.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
std::vector< SCH_PIN * > GetAllLibPins() const
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:164
void SetSchSymbolLibraryName(const wxString &aName)
The name of the symbol in the schematic library symbol list.
Definition sch_symbol.h:179
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
std::vector< SCH_PIN * > GetLibPins() const
Populate a vector with all the pins from the library object that match the current unit and bodyStyle...
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:183
void DeleteVariant(const KIID_PATH &aPath, const wxString &aVariantName)
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
VECTOR2I GetPinPhysicalPosition(const SCH_PIN *Pin) const
void CopyVariant(const KIID_PATH &aPath, const wxString &aSourceVariant, const wxString &aNewVariant)
static void MigrateSimModel(T &aSymbol, const PROJECT *aProject)
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:42
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition utf8.h:67
bool empty() const
Definition utf8.h:105
wxString wx_str() const
Definition utf8.cpp:41
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
@ NO_RECURSE
Definition eda_item.h:52
#define IS_DELETED
#define STRUCT_DELETED
flag indication structures to be erased
#define IS_MOVING
Item being moved.
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
@ ERCE_UNSPECIFIED
static const wxChar DanglingProfileMask[]
Flag to enable connectivity profiling.
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
@ LAYER_WIRE
Definition layer_ids.h:474
@ LAYER_NOTES
Definition layer_ids.h:489
@ LAYER_BUS
Definition layer_ids.h:475
POINT_INFO AnalyzePoint(const EE_RTREE &aItem, const VECTOR2I &aPosition, bool aBreakCrossings)
Check a tree of items for a confluence at a given point and work out what kind of junction it is,...
PAGE_SIZE_TYPE
Definition page_info.h:46
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
Class to handle a set of SCH_ITEMs.
#define PROCESSED
SCH_LINE_TEST_T
Definition sch_screen.h:72
@ ENTIRE_LENGTH_T
Definition sch_screen.h:73
@ EXCLUDE_END_POINTS_T
Definition sch_screen.h:75
@ END_POINTS_ONLY_T
Definition sch_screen.h:74
wxString UnescapeString(const wxString &aSource)
LINE_STYLE
Dashed line types.
The EE_TYPE struct provides a type-specific auto-range iterator to the RTree.
Definition sch_rtree.h:198
SearchIter begin()
Definition sch_rtree.h:237
SearchIter end()
Definition sch_rtree.h:238
std::vector< char > decompressedData
A selection of information about a point in the schematic that might be eligible for turning into a j...
A simple container for sheet instance information.
A simple container for schematic symbol instance information.
SPIN_STYLE GetPinSpinStyle(const SCH_PIN &aPin, const SCH_SYMBOL &aSymbol)
Get the spin style for a pin's label, taking into account the pin's orientation, as well as the given...
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
KIBIS_PIN * pin
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
Definition trigo.cpp:85
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ SCH_GROUP_T
Definition typeinfo.h:169
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_FIELD_T
Definition typeinfo.h:146
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:167
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_SHEET_T
Definition typeinfo.h:171
@ SCH_MARKER_T
Definition typeinfo.h:154
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_HIER_LABEL_T
Definition typeinfo.h:165
@ SCH_SCREEN_T
Definition typeinfo.h:198
@ SCH_LABEL_LOCATE_ANY_T
Definition typeinfo.h:187
@ SCHEMATIC_T
Definition typeinfo.h:200
@ SCH_SHEET_PIN_T
Definition typeinfo.h:170
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:157
@ SCH_BITMAP_T
Definition typeinfo.h:160
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:164
@ SCH_JUNCTION_T
Definition typeinfo.h:155
@ SCH_PIN_T
Definition typeinfo.h:149
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683