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