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