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
395 if( auto it = m_libSymbols.find( aName ); it != m_libSymbols.end() )
396 {
397 delete it->second;
398 m_libSymbols.erase( it );
399 return true;
400 }
401
402 return false;
403}
404
405
407{
408 wxCHECK_RET( aItem, wxT( "Cannot delete invalid item from screen." ) );
409
410 // Markers are not saved in the file, no need to flag as modified.
411 // TODO: Maybe we should have a listing somewhere of items that aren't saved?
412 if( aItem->Type() != SCH_MARKER_T )
414
415 Remove( aItem );
416
417 if( aItem->Type() == SCH_SHEET_PIN_T )
418 {
419 // This structure is attached to a sheet, get the parent sheet object.
420 SCH_SHEET_PIN* sheetPin = (SCH_SHEET_PIN*) aItem;
421 SCH_SHEET* sheet = sheetPin->GetParent();
422 wxCHECK_RET( sheet, wxT( "Sheet pin parent not properly set, bad programmer!" ) );
423 sheet->RemovePin( sheetPin );
424 return;
425 }
426
427 delete aItem;
428}
429
430
431bool SCH_SCREEN::CheckIfOnDrawList( const SCH_ITEM* aItem ) const
432{
433 return m_rtree.contains( aItem, true );
434}
435
436
437SCH_ITEM* SCH_SCREEN::GetItem( const VECTOR2I& aPosition, int aAccuracy, KICAD_T aType ) const
438{
439 BOX2I bbox;
440 bbox.SetOrigin( aPosition );
441 bbox.Inflate( aAccuracy );
442
443 for( SCH_ITEM* item : Items().Overlapping( aType, bbox ) )
444 {
445 if( item->HitTest( aPosition, aAccuracy ) )
446 return item;
447 }
448
449 return nullptr;
450}
451
452
453std::set<SCH_ITEM*> SCH_SCREEN::MarkConnections( SCH_ITEM* aItem, bool aSecondPass )
454{
455#define PROCESSED CANDIDATE // Don't use SKIP_STRUCT; IsConnected() returns false if it's set.
456
457 std::set<SCH_ITEM*> retval;
458 std::stack<SCH_ITEM*> toSearch;
459
460 auto getItemEndpoints = []( SCH_ITEM* aCandidate ) -> std::vector<VECTOR2I>
461 {
462 if( !aCandidate )
463 return {};
464
465 if( aCandidate->Type() == SCH_LINE_T )
466 {
467 SCH_LINE* line = static_cast<SCH_LINE*>( aCandidate );
468 return { line->GetStartPoint(), line->GetEndPoint() };
469 }
470
471 if( aCandidate->Type() == SCH_SHAPE_T )
472 {
473 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aCandidate );
474
475 if( shape->GetShape() == SHAPE_T::ARC || shape->GetShape() == SHAPE_T::BEZIER )
476 return { shape->GetStart(), shape->GetEnd() };
477 else if( shape->GetShape() == SHAPE_T::RECTANGLE )
478 return shape->GetRectCorners();
479 else if( shape->GetShape() == SHAPE_T::SEGMENT )
480 return { shape->GetStart(), shape->GetEnd() };
481 else if( shape->GetShape() == SHAPE_T::POLY )
482 return shape->GetPolyPoints();
483 }
484
485 return {};
486 };
487
488 if( !aItem || getItemEndpoints( aItem ).empty() )
489 return retval;
490
491 toSearch.push( aItem );
492
493 while( !toSearch.empty() )
494 {
495 SCH_ITEM* item = toSearch.top();
496 toSearch.pop();
497
498 if( item->HasFlag( PROCESSED ) )
499 continue;
500
501 item->SetFlags( PROCESSED );
502
503 const BOX2I bbox = item->GetBoundingBox();
504
505 for( KICAD_T type : { SCH_LINE_T, SCH_SHAPE_T } )
506 {
507 for( SCH_ITEM* candidate : Items().Overlapping( type, bbox ) )
508 {
509 if( candidate->HasFlag( PROCESSED ) )
510 continue;
511
512 std::vector<VECTOR2I> endpoints = getItemEndpoints( candidate );
513
514 if( endpoints.empty() )
515 continue;
516
517 // Skip connecting items on different layers (e.g. buses)
518 if( item->GetLayer() != candidate->GetLayer() )
519 continue;
520
521 bool sharesEndpoint = false;
522
523 for( const VECTOR2I& pt : endpoints )
524 {
525 if( item->IsEndPoint( pt ) )
526 {
527 sharesEndpoint = true;
528
529 if( aSecondPass && item->IsConnected( pt ) )
530 {
531 SCH_ITEM* junction = GetItem( pt, 0, SCH_JUNCTION_T );
532
533 if( junction )
534 retval.insert( junction );
535 }
536 }
537 }
538
539 if( !sharesEndpoint )
540 continue;
541
542 toSearch.push( candidate );
543 retval.insert( candidate );
544 }
545 }
546 }
547
548 for( SCH_ITEM* item : Items() )
549 item->ClearTempFlags();
550
551 return retval;
552}
553
554
555bool SCH_SCREEN::IsJunction( const VECTOR2I& aPosition ) const
556{
558 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, false );
559 return info.isJunction;
560}
561
562
563bool SCH_SCREEN::IsExplicitJunction( const VECTOR2I& aPosition ) const
564{
566 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, false );
567
568 return info.AllowsExplicitJunction();
569}
570
571
572bool SCH_SCREEN::IsExplicitJunctionNeeded( const VECTOR2I& aPosition ) const
573{
575 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, false );
576
577 return info.AllowsExplicitJunction() && !info.hasExplicitJunctionDot;
578}
579
580
582{
584 JUNCTION_HELPERS::AnalyzePoint( Items(), aPosition, true );
585
586 return info.AllowsExplicitJunction();
587}
588
589
591 SPIN_STYLE aDefaultOrientation,
592 const SCH_SHEET_PATH* aSheet ) const
593{
594 auto ret = aDefaultOrientation;
595
596 for( SCH_ITEM* item : Items().Overlapping( aPosition ) )
597 {
598 if( item->GetEditFlags() & STRUCT_DELETED )
599 continue;
600
601 switch( item->Type() )
602 {
604 {
605 auto busEntry = static_cast<const SCH_BUS_WIRE_ENTRY*>( item );
606 if( busEntry->m_connected_bus_item )
607 {
608 // bus connected, take the bus direction into consideration only if it is
609 // vertical or horizontal
610 auto bus = static_cast<const SCH_LINE*>( busEntry->m_connected_bus_item );
611 if( bus->Angle().AsDegrees() == 90.0 )
612 {
613 // bus is vertical -> label shall be horizontal and
614 // shall be placed to the side where the bus entry is
615 if( aPosition.x < bus->GetPosition().x )
616 ret = SPIN_STYLE::LEFT;
617 else if( aPosition.x > bus->GetPosition().x )
618 ret = SPIN_STYLE::RIGHT;
619 }
620 else if( bus->Angle().AsDegrees() == 0.0 )
621 {
622 // bus is horizontal -> label shall be vertical and
623 // shall be placed to the side where the bus entry is
624 if( aPosition.y < bus->GetPosition().y )
625 ret = SPIN_STYLE::UP;
626 else if( aPosition.y > bus->GetPosition().y )
627 ret = SPIN_STYLE::BOTTOM;
628 }
629 }
630 }
631 break;
632
633 case SCH_LINE_T:
634 {
635 auto line = static_cast<const SCH_LINE*>( item );
636 // line angles goes between -90 and 90 degrees, but normalize
637 auto angle = line->Angle().Normalize90().AsDegrees();
638
639 if( -45 < angle && angle <= 45 )
640 {
641 if( line->GetStartPoint().x <= line->GetEndPoint().x )
642 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::RIGHT : SPIN_STYLE::LEFT;
643 else
644 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::LEFT : SPIN_STYLE::RIGHT;
645 }
646 else
647 {
648 if( line->GetStartPoint().y <= line->GetEndPoint().y )
649 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::BOTTOM : SPIN_STYLE::UP;
650 else
651 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::UP : SPIN_STYLE::BOTTOM;
652 }
653 }
654 break;
655
656 case SCH_SYMBOL_T:
657 {
658 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
659
660 for( SCH_PIN* pin : symbol->GetPins( aSheet ) )
661 {
662 if( pin->GetPosition() == aPosition )
663 {
664 ret = GetPinSpinStyle( *pin, *symbol );
665 break;
666 }
667 }
668 }
669 break;
670
671 default: break;
672 }
673 }
674
675 return ret;
676}
677
678
679bool SCH_SCREEN::IsTerminalPoint( const VECTOR2I& aPosition, int aLayer ) const
680{
681 wxCHECK_MSG( aLayer == LAYER_NOTES || aLayer == LAYER_BUS || aLayer == LAYER_WIRE, false,
682 wxT( "Invalid layer type passed to SCH_SCREEN::IsTerminalPoint()." ) );
683
684 SCH_SHEET_PIN* sheetPin;
685 SCH_LABEL_BASE* label;
686
687 switch( aLayer )
688 {
689 case LAYER_BUS:
690 if( GetBus( aPosition ) )
691 return true;
692
693 sheetPin = GetSheetPin( aPosition );
694
695 if( sheetPin && sheetPin->IsConnected( aPosition ) )
696 return true;
697
698 label = GetLabel( aPosition );
699
700 if( label && !label->IsNew() && label->IsConnected( aPosition ) )
701 return true;
702
703 break;
704
705 case LAYER_NOTES:
706 if( GetLine( aPosition ) )
707 return true;
708
709 break;
710
711 case LAYER_WIRE:
712 if( GetItem( aPosition, 1, SCH_BUS_WIRE_ENTRY_T ) )
713 return true;
714
715 if( GetItem( aPosition, 1, SCH_JUNCTION_T ) )
716 return true;
717
718 if( GetPin( aPosition, nullptr, true ) )
719 return true;
720
721 if( GetWire( aPosition ) )
722 return true;
723
724 label = GetLabel( aPosition, 1 );
725
726 if( label && !label->IsNew() && label->IsConnected( aPosition ) )
727 return true;
728
729 sheetPin = GetSheetPin( aPosition );
730
731 if( sheetPin && sheetPin->IsConnected( aPosition ) )
732 return true;
733
734 break;
735
736 default:
737 break;
738 }
739
740 return false;
741}
742
743
745 SYMBOL_LIBRARY_ADAPTER* aLibraries )
746{
747 wxCHECK_RET( Schematic(), "Cannot call SCH_SCREEN::UpdateSymbolLinks with no SCHEMATIC" );
748
749 wxString msg;
750 std::vector<SCH_SYMBOL*> symbols;
751 SYMBOL_LIBRARY_ADAPTER* libs = aLibraries ? aLibraries
752 : PROJECT_SCH::SymbolLibAdapter( &Schematic()->Project() );
753
754 // Headless GUI callers can share an adapter with the editor's preload worker.
755 if( aLegacyLibs )
756 libs->AbortAsyncLoad();
757
758 LEGACY_SYMBOL_LIBS* legacyLibs = aLegacyLibs ? aLegacyLibs : PROJECT_SCH::LegacySchLibs( &Schematic()->Project() );
759
760 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
761 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
762
763 // Remove them from the R tree. Their bounding box size may change.
764 for( SCH_SYMBOL* symbol : symbols )
765 Remove( symbol );
766
767 // Clear all existing symbol links.
769
770 for( SCH_SYMBOL* symbol : symbols )
771 {
772 LIB_SYMBOL* tmp = nullptr;
773
774 // If the symbol is already in the internal library, map the symbol to it.
775 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
776
777 if( ( it != m_libSymbols.end() ) )
778 {
779 if( aReporter )
780 {
781 msg.Printf( _( "Setting schematic symbol '%s %s' library identifier to '%s'." ),
782 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
783 symbol->GetField( FIELD_T::VALUE )->GetText(),
784 UnescapeString( symbol->GetLibId().Format() ) );
785 aReporter->ReportTail( msg, RPT_SEVERITY_INFO );
786 }
787
788 // Internal library symbols are already flattened so just make a copy.
789 symbol->SetLibSymbol( new LIB_SYMBOL( *it->second ) );
790 continue;
791 }
792
793 if( !symbol->GetLibId().IsValid() && !( aLegacyLibs && symbol->GetLibId().IsLegacy() ) )
794 {
795 if( aReporter )
796 {
797 msg.Printf( _( "Schematic symbol reference '%s' library identifier is not valid. "
798 "Unable to link library symbol." ),
799 UnescapeString( symbol->GetLibId().Format() ) );
800 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
801 }
802
803 continue;
804 }
805
806 // LIB_TABLE_BASE::LoadSymbol() throws an IO_ERROR if the library nickname
807 // is not found in the table so check if the library still exists in the table
808 // before attempting to load the symbol.
809 std::optional<LIBRARY_TABLE_ROW*> libRow = libs->GetRow( symbol->GetLibId().GetLibNickname() );
810 bool hasLibraryRow = libRow.has_value();
811 bool hasLoadedLibrary = libs->HasLibrary( symbol->GetLibId().GetLibNickname() );
812
813 if( !hasLibraryRow && !legacyLibs )
814 {
815 if( aReporter )
816 {
817 msg.Printf( _( "Symbol library '%s' not found and no fallback cache library "
818 "available. Unable to link library symbol." ),
819 symbol->GetLibId().GetLibNickname().wx_str() );
820 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
821 }
822
823 continue;
824 }
825
826 if( hasLibraryRow && !hasLoadedLibrary )
827 {
828 libs->LoadOne( symbol->GetLibId().GetLibNickname() );
829 hasLoadedLibrary = libs->HasLibrary( symbol->GetLibId().GetLibNickname() );
830 }
831
832 if( hasLoadedLibrary )
833 {
834 try
835 {
836 tmp = libs->LoadSymbol( symbol->GetLibId() );
837 }
838 catch( const IO_ERROR& ioe )
839 {
840 if( aReporter )
841 {
842 msg.Printf( _( "I/O error %s resolving library symbol %s" ), ioe.What(),
843 UnescapeString( symbol->GetLibId().Format() ) );
844 aReporter->ReportTail( msg, RPT_SEVERITY_ERROR );
845 }
846 }
847 }
848
849 if( !tmp && legacyLibs && legacyLibs->GetLibraryCount() )
850 {
851 LEGACY_SYMBOL_LIB& legacyCacheLib = legacyLibs->back();
852
853 // It better be the cache library.
854 wxCHECK2( legacyCacheLib.IsCache(), continue );
855
856 wxString id = symbol->GetLibId().Format();
857
858 id.Replace( ':', '_' );
859
860 if( aReporter )
861 {
862 msg.Printf( _( "Falling back to cache to set symbol '%s:%s' link '%s'." ),
863 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
864 symbol->GetField( FIELD_T::VALUE )->GetText(),
865 UnescapeString( id ) );
866 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
867 }
868
869 tmp = legacyCacheLib.FindSymbol( id );
870 }
871
872 if( tmp )
873 {
874 // We want a full symbol not just the top level child symbol.
875 std::unique_ptr<LIB_SYMBOL> libSymbol = tmp->Flatten();
876 libSymbol->SetParent();
877
878 m_libSymbols.insert( { symbol->GetSchSymbolLibraryName(),
879 new LIB_SYMBOL( *libSymbol ) } );
880
881 if( aReporter )
882 {
883 msg.Printf( _( "Setting schematic symbol '%s %s' library identifier to '%s'." ),
884 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
885 symbol->GetField( FIELD_T::VALUE )->GetText(),
886 UnescapeString( symbol->GetLibId().Format() ) );
887 aReporter->ReportTail( msg, RPT_SEVERITY_INFO );
888 }
889
890 symbol->SetLibSymbol( libSymbol.release() );
891 }
892 else
893 {
894 if( aReporter )
895 {
896 msg.Printf( _( "No library symbol found for schematic symbol '%s %s'." ),
897 symbol->GetField( FIELD_T::REFERENCE )->GetText(),
898 symbol->GetField( FIELD_T::VALUE )->GetText() );
899 aReporter->ReportTail( msg, RPT_SEVERITY_ERROR );
900 }
901 }
902 }
903
904 // Changing the symbol may adjust the bbox of the symbol. This re-inserts the
905 // item with the new bbox
906 for( SCH_SYMBOL* symbol : symbols )
907 Append( symbol );
908}
909
910
912{
914
915 std::vector<SCH_SYMBOL*> symbols;
916
917 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
918 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
919
920 for( SCH_SYMBOL* symbol : symbols )
921 {
922 // Changing the symbol may adjust the bbox of the symbol; remove and reinsert it afterwards.
923 m_rtree.remove( symbol );
924
925 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
926
927 if( it != m_libSymbols.end() )
928 symbol->SetLibSymbol( new LIB_SYMBOL( *it->second ) );
929 else
930 symbol->SetLibSymbol( nullptr );
931
932 m_rtree.insert( symbol );
933 }
934}
935
936
938{
940
941 if( aChangedType != SCH_LINE_T )
943
944 m_connectivityItems.reset();
945}
946
947
949{
950 switch( aItem->Type() )
951 {
952 case SCH_MARKER_T:
953 case SCH_BITMAP_T:
954 case SCH_SHAPE_T:
955 case SCH_GROUP_T:
956 return false;
957
958 case SCH_LINE_T:
959 return aItem->IsConnectable();
960
961 default:
962 return true;
963 }
964}
965
966
968{
970 {
971 auto& index = m_connectivityItems.emplace();
972
973 const auto add =
974 [&]( SCH_ITEM* aItem )
975 {
976 auto [it, inserted] = index.emplace( aItem->m_Uuid, aItem );
977
978 if( !inserted && it->second != aItem )
979 it->second = nullptr;
980 };
981
982 for( SCH_ITEM* item : Items() )
983 {
984 add( item );
985
986 if( item->Type() == SCH_SYMBOL_T || item->Type() == SCH_SHEET_T )
987 {
988 item->RunOnChildren(
989 [&]( SCH_ITEM* aChild )
990 {
991 if( aChild->IsConnectable() )
992 add( aChild );
993 },
995 }
996 }
997 }
998
999 const auto it = m_connectivityItems->find( aId );
1000 return it == m_connectivityItems->end() ? nullptr : it->second;
1001}
1002
1003
1004void SCH_SCREEN::Plot( PLOTTER* aPlotter, const SCH_PLOT_OPTS& aPlotOpts ) const
1005{
1006 std::vector<SCH_ITEM*> items;
1007 items.reserve( Items().size() );
1008
1009 for( SCH_ITEM* item : Items() )
1010 items.push_back( item );
1011
1012 Plot( aPlotter, aPlotOpts, items );
1013}
1014
1015
1016void SCH_SCREEN::Plot( PLOTTER* aPlotter, const SCH_PLOT_OPTS& aPlotOpts, const std::vector<SCH_ITEM*>& aItems ) const
1017{
1018 // Ensure links are up to date, even if a library was reloaded for some reason:
1019 std::vector<SCH_ITEM*> junctions;
1020 std::vector<SCH_ITEM*> bitmaps;
1021 std::vector<SCH_SYMBOL*> symbols;
1022 std::vector<SCH_ITEM*> other;
1023 double hopOverScale = 0.0;
1024 int defaultLineWidth = schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
1025
1026 if( !aItems.empty() && aItems[0]->Schematic() )
1027 {
1028 hopOverScale = aItems[0]->Schematic()->Settings().GetHopOverScale();
1029 defaultLineWidth = aItems[0]->Schematic()->Settings().m_DefaultLineWidth;
1030 }
1031
1032 for( SCH_ITEM* item : aItems )
1033 {
1034 if( item->IsMoving() )
1035 continue;
1036
1037 if( item->Type() == SCH_JUNCTION_T )
1038 junctions.push_back( item );
1039 else if( item->Type() == SCH_BITMAP_T )
1040 bitmaps.push_back( item );
1041 else
1042 other.push_back( item );
1043
1044 // Where the symbols overlap each other, we need to plot the text items a second
1045 // time to get them on top of the overlapping element. This collection is in addition
1046 // to the symbols already collected in `other`
1047 if( item->Type() == SCH_SYMBOL_T )
1048 {
1049 for( SCH_ITEM* sym : m_rtree.Overlapping( SCH_SYMBOL_T, item->GetBoundingBox() ) )
1050 {
1051 if( sym != item )
1052 {
1053 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
1054 break;
1055 }
1056 }
1057 }
1058 }
1059
1061 std::sort( other.begin(), other.end(),
1062 []( const SCH_ITEM* a, const SCH_ITEM* b )
1063 {
1064 if( a->Type() == b->Type() )
1065 return a->GetLayer() > b->GetLayer();
1066
1067 return a->Type() > b->Type();
1068 } );
1069
1070 auto* renderSettings = static_cast<SCH_RENDER_SETTINGS*>( aPlotter->RenderSettings() );
1071 constexpr bool background = true;
1072
1073 // Bitmaps are drawn first to ensure they are in the background
1074 // This is particularly important for the wxPostscriptDC (used in *nix printers) as
1075 // the bitmap PS command clears the screen
1076 for( SCH_ITEM* item : bitmaps )
1077 {
1078 aPlotter->SetCurrentLineWidth( item->GetEffectivePenWidth( renderSettings ) );
1079 item->Plot( aPlotter, background, aPlotOpts, 0, 0, { 0, 0 }, false );
1080 }
1081
1082 // Plot the background items
1083 for( SCH_ITEM* item : other )
1084 {
1085 aPlotter->SetCurrentLineWidth( item->GetEffectivePenWidth( renderSettings ) );
1086 item->Plot( aPlotter, background, aPlotOpts, 0, 0, { 0, 0 }, false );
1087 }
1088
1089 // Plot the foreground items
1090 for( SCH_ITEM* item : other )
1091 {
1092 double lineWidth = item->GetEffectivePenWidth( renderSettings );
1093 aPlotter->SetCurrentLineWidth( lineWidth );
1094
1095 if( item->Type() != SCH_LINE_T )
1096 {
1097 item->Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1098 }
1099 else
1100 {
1101 SCH_LINE* aLine = static_cast<SCH_LINE*>( item );
1102
1103 if( ( !aLine->IsWire() && !aLine->IsBus() ) || !aPlotOpts.m_plotHopOver )
1104 {
1105 item->Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1106 }
1107 else
1108 {
1109 double arcRadius = defaultLineWidth * hopOverScale;
1110 std::vector<VECTOR3I> curr_wire_shape = aLine->BuildWireWithHopShape( this, arcRadius );
1111
1112 // The hop pieces are standalone copies/shapes without the connection map, so
1113 // resolve the net-class color and style from the original wire and reuse them.
1114 COLOR4D lineColor = aLine->GetLineColor();
1115 LINE_STYLE lineStyle = aLine->GetEffectiveLineStyle();
1116
1117 for( size_t ii = 1; ii < curr_wire_shape.size(); ii++ )
1118 {
1119 VECTOR2I start( curr_wire_shape[ii-1].x, curr_wire_shape[ii-1].y );
1120
1121 if( curr_wire_shape[ii-1].z == 0 ) // This is the start point of a segment
1122 // there are always 2 points in list for a segment
1123 {
1124 VECTOR2I end( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1125
1126 SCH_LINE curr_line( *aLine );
1127 curr_line.SetStartPoint( start );
1128 curr_line.SetEndPoint( end );
1129 curr_line.SetLineColor( lineColor );
1130 curr_line.SetLineStyle( lineStyle );
1131 curr_line.Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1132 }
1133 else // This is the start point of a arc. there are always 3 points in list for an arc
1134 {
1135 VECTOR2I arc_middle( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1136 ii++;
1137 VECTOR2I arc_end( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1138 ii++;
1139
1140 SCH_SHAPE arc( SHAPE_T::ARC, aLine->GetLayer(), lineWidth );
1141
1142 arc.SetArcGeometry( start, arc_middle, arc_end );
1143 // Hop are a small arc, so use a solid line style gives best results
1145 arc.SetLineColor( lineColor );
1146 arc.Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1147 }
1148 }
1149 }
1150 }
1151 }
1152
1153 // After plotting the symbols as a group above (in `other`), we need to overplot the pins
1154 // and symbols to ensure that they are always visible
1155 TRANSFORM savedTransform = renderSettings->m_Transform;
1156
1157 wxString variant = Schematic()->GetCurrentVariant();
1158 SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
1159
1160 for( const SCH_SYMBOL* sym :symbols )
1161 {
1162 renderSettings->m_Transform = sym->GetTransform();
1163 aPlotter->SetCurrentLineWidth( sym->GetEffectivePenWidth( renderSettings ) );
1164
1165 bool dnp = sym->GetDNP( sheet, variant );
1166
1167 for( SCH_FIELD field : sym->GetFields() )
1168 {
1169 field.ClearRenderCache();
1170 field.Plot( aPlotter, false, aPlotOpts, sym->GetUnit(), sym->GetBodyStyle(), { 0, 0 }, dnp );
1171
1172 if( sym->IsSymbolLikePowerLocalLabel()
1173 && field.GetId() == FIELD_T::VALUE
1174 && ( field.IsVisible() || field.IsForceVisible() ) )
1175 {
1176 sym->PlotLocalPowerIconShape( aPlotter );
1177 }
1178 }
1179
1180 sym->PlotPins( aPlotter, dnp );
1181
1182 if( dnp && Schematic()->Settings().m_ShowDNPMarkers )
1183 sym->PlotDNP( aPlotter );
1184 }
1185
1186 renderSettings->m_Transform = savedTransform;
1187
1188 for( SCH_ITEM* item : junctions )
1189 {
1190 aPlotter->SetCurrentLineWidth( item->GetEffectivePenWidth( renderSettings ) );
1191 item->Plot( aPlotter, !background, aPlotOpts, 0, 0, { 0, 0 }, false );
1192 }
1193}
1194
1195
1197{
1198 for( SCH_ITEM* item : Items() )
1199 item->ClearTempFlags();
1200}
1201
1202
1203SCH_PIN* SCH_SCREEN::GetPin( const VECTOR2I& aPosition, SCH_SYMBOL** aSymbol,
1204 bool aEndPointOnly ) const
1205{
1206 SCH_SYMBOL* candidate = nullptr;
1207 SCH_PIN* pin = nullptr;
1208
1209 for( SCH_ITEM* item : Items().Overlapping( SCH_SYMBOL_T, aPosition ) )
1210 {
1211 candidate = static_cast<SCH_SYMBOL*>( item );
1212
1213 if( aEndPointOnly )
1214 {
1215 pin = nullptr;
1216
1217 if( !candidate->GetLibSymbolRef() )
1218 continue;
1219
1220 for( SCH_PIN* test_pin : candidate->GetLibPins() )
1221 {
1222 if( candidate->GetPinPhysicalPosition( test_pin ) == aPosition )
1223 {
1224 pin = test_pin;
1225 break;
1226 }
1227 }
1228
1229 if( pin )
1230 break;
1231 }
1232 else
1233 {
1234 pin = static_cast<SCH_PIN*>( candidate->GetDrawItem( aPosition, SCH_PIN_T ) );
1235
1236 if( pin )
1237 break;
1238 }
1239 }
1240
1241 if( pin && aSymbol )
1242 *aSymbol = candidate;
1243
1244 return pin;
1245}
1246
1247
1249{
1250 SCH_SHEET_PIN* sheetPin = nullptr;
1251
1252 for( SCH_ITEM* item : Items().Overlapping( SCH_SHEET_T, aPosition ) )
1253 {
1254 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1255
1256 sheetPin = sheet->GetPin( aPosition );
1257
1258 if( sheetPin )
1259 break;
1260 }
1261
1262 return sheetPin;
1263}
1264
1265
1266size_t SCH_SCREEN::CountConnectedItems( const VECTOR2I& aPos, bool aTestJunctions ) const
1267{
1268 size_t count = 0;
1269
1270 for( const SCH_ITEM* item : Items().Overlapping( aPos ) )
1271 {
1272 if( ( item->Type() != SCH_JUNCTION_T || aTestJunctions ) && item->IsConnected( aPos ) )
1273 count++;
1274 }
1275
1276 return count;
1277}
1278
1279
1280void SCH_SCREEN::ClearAnnotation( SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
1281{
1282
1283 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1284 {
1285 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1286
1287 symbol->ClearAnnotation( aSheetPath, aResetPrefix );
1288 }
1289}
1290
1291
1293{
1294 if( GetClientSheetPaths().size() <= 1 ) // No need for alternate reference
1295 return;
1296
1297 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1298 {
1299 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1300
1301 // Add (when not existing) all sheet path entries
1302 for( const SCH_SHEET_PATH& sheet : GetClientSheetPaths() )
1303 symbol->AddSheetPathReferenceEntryIfMissing( sheet.Path() );
1304 }
1305}
1306
1307
1308void SCH_SCREEN::GetHierarchicalItems( std::vector<SCH_ITEM*>* aItems ) const
1309{
1310 static const std::vector<KICAD_T> hierarchicalTypes = { SCH_SYMBOL_T,
1313
1314 for( SCH_ITEM* item : Items() )
1315 {
1316 if( item->IsType( hierarchicalTypes ) )
1317 aItems->push_back( item );
1318 }
1319}
1320
1321
1322void SCH_SCREEN::GetSheets( std::vector<SCH_ITEM*>* aItems ) const
1323{
1324 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1325 aItems->push_back( item );
1326
1327 std::sort( aItems->begin(), aItems->end(),
1328 []( EDA_ITEM* a, EDA_ITEM* b ) -> bool
1329 {
1330 if( a->GetPosition().x == b->GetPosition().x )
1331 {
1332 // Ensure deterministic sort
1333 if( a->GetPosition().y == b->GetPosition().y )
1334 return a->m_Uuid < b->m_Uuid;
1335
1336 return a->GetPosition().y < b->GetPosition().y;
1337 }
1338 else
1339 {
1340 return a->GetPosition().x < b->GetPosition().x;
1341 }
1342 } );
1343}
1344
1345
1347 std::function<void( SCH_ITEM* )>* aChangedHandler ) const
1348{
1349 PROF_TIMER timer( __FUNCTION__ );
1350
1351 std::vector<DANGLING_END_ITEM> endPointsByPos;
1352 std::vector<DANGLING_END_ITEM> endPointsByType;
1353
1354 auto get_ends =
1355 [&]( SCH_ITEM* item )
1356 {
1357 if( item->IsConnectable() )
1358 item->GetEndPoints( endPointsByType );
1359 };
1360
1361 auto update_state =
1362 [&]( SCH_ITEM* item )
1363 {
1364 if( item->UpdateDanglingState( endPointsByType, endPointsByPos, aPath ) )
1365 {
1366 if( aChangedHandler )
1367 ( *aChangedHandler )( item );
1368 }
1369 };
1370
1371 for( SCH_ITEM* item : Items() )
1372 {
1373 get_ends( item );
1374 item->RunOnChildren( get_ends, RECURSE_MODE::NO_RECURSE );
1375 }
1376
1377 PROF_TIMER sortTimer( "SCH_SCREEN::TestDanglingEnds pre-sort" );
1378 endPointsByPos = endPointsByType;
1379 DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
1380 sortTimer.Stop();
1381
1382 if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
1383 sortTimer.Show();
1384
1385 for( SCH_ITEM* item : Items() )
1386 {
1387 update_state( item );
1388 item->RunOnChildren( update_state, RECURSE_MODE::NO_RECURSE );
1389 }
1390
1391 if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
1392 timer.Show();
1393}
1394
1395
1396SCH_LINE* SCH_SCREEN::GetLine( const VECTOR2I& aPosition, int aAccuracy, int aLayer,
1397 SCH_LINE_TEST_T aSearchType ) const
1398{
1399 // an accuracy of 0 had problems with rounding errors; use at least 1
1400 aAccuracy = std::max( aAccuracy, 1 );
1401
1402 for( SCH_ITEM* item : Items().Overlapping( aPosition, aAccuracy ) )
1403 {
1404 if( item->Type() != SCH_LINE_T )
1405 continue;
1406
1407 if( item->GetLayer() != aLayer )
1408 continue;
1409
1410 if( !item->HitTest( aPosition, aAccuracy ) )
1411 continue;
1412
1413 switch( aSearchType )
1414 {
1415 case ENTIRE_LENGTH_T:
1416 return (SCH_LINE*) item;
1417
1419 if( !( (SCH_LINE*) item )->IsEndPoint( aPosition ) )
1420 return (SCH_LINE*) item;
1421 break;
1422
1423 case END_POINTS_ONLY_T:
1424 if( ( (SCH_LINE*) item )->IsEndPoint( aPosition ) )
1425 return (SCH_LINE*) item;
1426 }
1427 }
1428
1429 return nullptr;
1430}
1431
1432
1433std::vector<SCH_LINE*> SCH_SCREEN::GetBusesAndWires( const VECTOR2I& aPosition,
1434 bool aIgnoreEndpoints ) const
1435{
1436 std::vector<SCH_LINE*> retVal;
1437
1438 for( SCH_ITEM* item : Items().Overlapping( SCH_LINE_T, aPosition ) )
1439 {
1440 if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } ) )
1441 {
1442 SCH_LINE* wire = static_cast<SCH_LINE*>( item );
1443
1444 if( aIgnoreEndpoints && wire->IsEndPoint( aPosition ) )
1445 continue;
1446
1447 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), aPosition ) )
1448 retVal.push_back( wire );
1449 }
1450 }
1451
1452 return retVal;
1453}
1454
1455
1456std::vector<VECTOR2I> SCH_SCREEN::GetConnections() const
1457{
1458 std::vector<VECTOR2I> retval;
1459
1460 for( SCH_ITEM* item : Items() )
1461 {
1462 // Avoid items that are changing
1463 if( !( item->GetEditFlags() & ( IS_MOVING | IS_DELETED ) ) )
1464 {
1465 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1466 retval.insert( retval.end(), pts.begin(), pts.end() );
1467 }
1468 }
1469
1470 // We always have some overlapping connection points. Drop duplicates here
1471 std::sort( retval.begin(), retval.end(),
1472 []( const VECTOR2I& a, const VECTOR2I& b ) -> bool
1473 {
1474 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1475 } );
1476
1477 retval.erase( std::unique( retval.begin(), retval.end() ), retval.end() );
1478
1479 return retval;
1480}
1481
1482
1483std::vector<VECTOR2I> SCH_SCREEN::GetNeededJunctions( const std::deque<EDA_ITEM*>& aItems ) const
1484{
1485 std::vector<VECTOR2I> pts;
1486 std::vector<VECTOR2I> connections = GetConnections();
1487
1488 for( const EDA_ITEM* edaItem : aItems )
1489 {
1490 const SCH_ITEM* item = dynamic_cast<const SCH_ITEM*>( edaItem );
1491
1492 if( !item || !item->IsConnectable() )
1493 continue;
1494
1495 std::vector<VECTOR2I> new_pts = item->GetConnectionPoints();
1496 pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
1497
1498 // If the item is a line, we also add any connection points from the rest of the schematic
1499 // that terminate on the line after it is moved.
1500 if( item->Type() == SCH_LINE_T )
1501 {
1502 SCH_LINE* line = (SCH_LINE*) item;
1503
1504 for( const VECTOR2I& pt : connections )
1505 {
1506 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1507 pts.push_back( pt );
1508 }
1509 }
1510 }
1511
1512 // We always have some overlapping connection points. Drop duplicates here
1513 std::sort( pts.begin(), pts.end(),
1514 []( const VECTOR2I& a, const VECTOR2I& b ) -> bool
1515 {
1516 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1517 } );
1518
1519 pts.erase( unique( pts.begin(), pts.end() ), pts.end() );
1520
1521 // We only want the needed junction points, remove all the others
1522 pts.erase( std::remove_if( pts.begin(), pts.end(),
1523 [this]( const VECTOR2I& a ) -> bool
1524 {
1525 return !IsExplicitJunctionNeeded( a );
1526 } ),
1527 pts.end() );
1528
1529 return pts;
1530}
1531
1532
1533SCH_LABEL_BASE* SCH_SCREEN::GetLabel( const VECTOR2I& aPosition, int aAccuracy ) const
1534{
1535 for( SCH_ITEM* item : Items().Overlapping( aPosition, aAccuracy ) )
1536 {
1537 switch( item->Type() )
1538 {
1539 case SCH_LABEL_T:
1540 case SCH_GLOBAL_LABEL_T:
1541 case SCH_HIER_LABEL_T:
1543 if( item->HitTest( aPosition, aAccuracy ) )
1544 return static_cast<SCH_LABEL_BASE*>( item );
1545
1546 break;
1547
1548 default:
1549 ;
1550 }
1551 }
1552
1553 return nullptr;
1554}
1555
1556
1558{
1559 std::unique_ptr<LIB_SYMBOL> symbol( aLibSymbol );
1560 wxCHECK( symbol, /* void */ );
1561
1562 wxString key = symbol->GetLibId().Format().wx_str();
1563 AddLibSymbol( key, std::move( symbol ) );
1564}
1565
1566
1567void SCH_SCREEN::AddLibSymbol( const wxString& aKey, std::unique_ptr<LIB_SYMBOL> aLibSymbol )
1568{
1569 wxCHECK( aLibSymbol, /* void */ );
1570
1571 auto insertion = m_libSymbols.try_emplace( aKey, nullptr );
1572 auto it = insertion.first;
1573 LIB_SYMBOL* previous = std::exchange( it->second, aLibSymbol.release() );
1574
1575 delete previous;
1576}
1577
1578
1580{
1581 SCHEMATIC* schematic = Schematic();
1582
1583 const std::vector<wxString>* embeddedFonts = schematic->GetEmbeddedFiles()->UpdateFontFiles();
1584
1585 for( auto& [name, libSym] : m_libSymbols )
1586 {
1587 for( auto& [filename, embeddedFile] : libSym->EmbeddedFileMap() )
1588 {
1589 EMBEDDED_FILES::EMBEDDED_FILE* file = schematic->GetEmbeddedFile( filename );
1590
1591 if( file )
1592 {
1593 embeddedFile->compressedEncodedData = file->compressedEncodedData;
1594 embeddedFile->decompressedData = file->decompressedData;
1595 embeddedFile->data_hash = file->data_hash;
1596 embeddedFile->is_valid = file->is_valid;
1597 }
1598 }
1599
1600 libSym->RunOnChildren(
1601 [&]( SCH_ITEM* aChild )
1602 {
1603 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aChild ) )
1604 textItem->ResolveFont( embeddedFonts );
1605 },
1607 }
1608
1609 std::vector<SCH_ITEM*> items_to_update;
1610
1611 for( SCH_ITEM* item : Items() )
1612 {
1613 bool update = false;
1614
1615 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( item ) )
1616 update |= textItem->ResolveFont( embeddedFonts );
1617
1618 item->RunOnChildren(
1619 [&]( SCH_ITEM* aChild )
1620 {
1621 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aChild ) )
1622 update |= textItem->ResolveFont( embeddedFonts );
1623 },
1625
1626 if( update )
1627 items_to_update.push_back( item );
1628 }
1629
1630 for( SCH_ITEM* item : items_to_update )
1631 Update( item );
1632}
1633
1634
1635void SCH_SCREEN::AddBusAlias( std::shared_ptr<BUS_ALIAS> aAlias )
1636{
1637 if( SCHEMATIC* schematic = Schematic() )
1638 schematic->AddBusAlias( aAlias );
1639}
1640
1641
1643{
1644 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1645 {
1646 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1647
1648 // Add missing value and footprint instance data for legacy schematics.
1649 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
1650 {
1651 symbol->AddHierarchicalReference( instance.m_Path, instance.m_Reference,
1652 instance.m_Unit );
1653 }
1654 }
1655}
1656
1657
1659{
1660 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1661 {
1662 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1663
1664 // Fix pre-8.0 legacy power symbols with invisible pins
1665 // that have mismatched pin names and value fields
1666 if( symbol->GetLibSymbolRef()
1667 && symbol->GetLibSymbolRef()->IsGlobalPower()
1668 && symbol->GetAllLibPins().size() > 0
1669 && symbol->GetAllLibPins()[0]->IsGlobalPower()
1670 && !symbol->GetAllLibPins()[0]->IsVisible() )
1671 {
1672 symbol->SetValueFieldText( symbol->GetAllLibPins()[0]->GetName() );
1673 }
1674 }
1675}
1676
1677
1679 std::vector<wxString>& aMatches )
1680{
1681 wxString searchName = aSymbol.GetLibId().GetUniStringLibId();
1682
1683 if( m_libSymbols.find( searchName ) != m_libSymbols.end() )
1684 aMatches.emplace_back( searchName );
1685
1686 searchName = aSymbol.GetLibId().GetUniStringLibItemName() + wxS( "_" );
1687
1688 long tmp;
1689 wxString suffix;
1690
1691 for( auto& pair : m_libSymbols )
1692 {
1693 if( pair.first.StartsWith( searchName, &suffix ) && suffix.ToLong( &tmp ) )
1694 aMatches.emplace_back( pair.first );
1695 }
1696
1697 return aMatches.size();
1698}
1699
1700
1701void SCH_SCREEN::PruneOrphanedSymbolInstances( const wxString& aProjectName,
1702 const SCH_SHEET_LIST& aValidSheetPaths )
1703{
1704 // The project name cannot be empty. Projects older than 7.0 did not save project names
1705 // when saving instance data. Running this algorithm with an empty project name would
1706 // clobber all instance data for projects other than the current one when a schematic
1707 // file is shared across multiple projects. Because running the schematic editor in
1708 // stand alone mode can result in an empty project name, do not assert here.
1709 if( aProjectName.IsEmpty() )
1710 return;
1711
1712 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1713 {
1714 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1715
1716 wxCHECK2( symbol, continue );
1717
1718 std::set<KIID_PATH> pathsToPrune;
1719 const std::vector<SCH_SYMBOL_INSTANCE> instances = symbol->GetInstances();
1720
1721 for( const SCH_SYMBOL_INSTANCE& instance : instances )
1722 {
1723 // Ignore instance paths from other projects.
1724 if( aProjectName != instance.m_ProjectName )
1725 continue;
1726
1727 std::optional<SCH_SHEET_PATH> pathFound =
1728 aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
1729
1730 // Check for paths that do not exist in the current project and paths that do
1731 // not contain the current symbol.
1732 if( !pathFound )
1733 pathsToPrune.emplace( instance.m_Path );
1734 else if( pathFound.value().LastScreen() != this )
1735 pathsToPrune.emplace( pathFound.value().Path() );
1736 }
1737
1738 for( const KIID_PATH& sheetPath : pathsToPrune )
1739 {
1740 wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' symbol instance %s." ),
1741 aProjectName, sheetPath.AsString() );
1742 symbol->RemoveInstance( sheetPath );
1743 }
1744 }
1745}
1746
1747
1748void SCH_SCREEN::PruneOrphanedSheetInstances( const wxString& aProjectName,
1749 const SCH_SHEET_LIST& aValidSheetPaths )
1750{
1751 // The project name cannot be empty. Projects older than 7.0 did not save project names
1752 // when saving instance data. Running this algorithm with an empty project name would
1753 // clobber all instance data for projects other than the current one when a schematic
1754 // file is shared across multiple projects. Because running the schematic editor in
1755 // stand alone mode can result in an empty project name, do not assert here.
1756 if( aProjectName.IsEmpty() )
1757 return;
1758
1759 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1760 {
1761 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1762
1763 wxCHECK2( sheet, continue );
1764
1765 std::set<KIID_PATH> pathsToPrune;
1766 const std::vector<SCH_SHEET_INSTANCE> instances = sheet->GetInstances();
1767
1768 for( const SCH_SHEET_INSTANCE& instance : instances )
1769 {
1770 // Ignore instance paths from other projects.
1771 if( aProjectName != instance.m_ProjectName )
1772 continue;
1773
1774 std::optional<SCH_SHEET_PATH> pathFound =
1775 aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
1776
1777 // Check for paths that do not exist in the current project and paths that do
1778 // not contain the current symbol.
1779 if( !pathFound )
1780 pathsToPrune.emplace( instance.m_Path );
1781 else if( pathFound.value().LastScreen() != this )
1782 pathsToPrune.emplace( pathFound.value().Path() );
1783 }
1784
1785 for( const KIID_PATH& sheetPath : pathsToPrune )
1786 {
1787 wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' sheet instance %s." ),
1788 aProjectName, sheetPath.AsString() );
1789 sheet->RemoveInstance( sheetPath );
1790 }
1791 }
1792}
1793
1794
1796{
1797 wxString trimmedFieldName;
1798
1799 for( const SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1800 {
1801 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
1802
1803 wxCHECK2( symbol, continue );
1804
1805 for( const SCH_FIELD& field : symbol->GetFields() )
1806 {
1807 trimmedFieldName = field.GetName();
1808 trimmedFieldName.Trim();
1809 trimmedFieldName.Trim( false );
1810
1811 if( field.GetName() != trimmedFieldName )
1812 return true;
1813 }
1814 }
1815
1816 return false;
1817}
1818
1819
1820std::set<wxString> SCH_SCREEN::GetSheetNames() const
1821{
1822 std::set<wxString> retv;
1823
1824 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1825 {
1826 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1827
1828 wxCHECK2( sheet, continue );
1829
1830 retv.emplace( sheet->GetName() );
1831 }
1832
1833 return retv;
1834}
1835
1836
1838{
1839 wxCHECK( Schematic(), false );
1840
1841 SCH_SHEET_LIST hierarchy = Schematic()->Hierarchy();
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 const std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
1848
1849 for( const SCH_SYMBOL_INSTANCE& instance : symbolInstances )
1850 {
1851 if( !hierarchy.HasPath( instance.m_Path ) )
1852 return true;
1853 }
1854 }
1855
1856 for( const SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1857 {
1858 const SCH_SHEET* sheet = static_cast<const SCH_SHEET*>( item );
1859
1860 const std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
1861
1862 for( const SCH_SHEET_INSTANCE& instance : sheetInstances )
1863 {
1864 if( !hierarchy.HasPath( instance.m_Path ) )
1865 return true;
1866 }
1867 }
1868
1869 return false;
1870}
1871
1872
1873wxString SCH_SCREEN::GroupsSanityCheck( bool repair )
1874{
1875 if( repair )
1876 {
1877 while( GroupsSanityCheckInternal( repair ) != wxEmptyString )
1878 {
1879 };
1880
1881 return wxEmptyString;
1882 }
1883 return GroupsSanityCheckInternal( repair );
1884}
1885
1886
1888{
1889 // Cycle detection
1890 //
1891 // Each group has at most one parent group.
1892 // So we start at group 0 and traverse the parent chain, marking groups seen along the way.
1893 // If we ever see a group that we've already marked, that's a cycle.
1894 // If we reach the end of the chain, we know all groups in that chain are not part of any cycle.
1895 //
1896 // Algorithm below is linear in the # of groups because each group is visited only once.
1897 // There may be extra time taken due to the container access calls and iterators.
1898 //
1899 // Groups we know are cycle free
1900 std::unordered_set<EDA_GROUP*> knownCycleFreeGroups;
1901 // Groups in the current chain we're exploring.
1902 std::unordered_set<EDA_GROUP*> currentChainGroups;
1903 // Groups we haven't checked yet.
1904 std::unordered_set<EDA_GROUP*> toCheckGroups;
1905
1906 // Initialize set of groups and generators to check that could participate in a cycle.
1907 for( SCH_ITEM* item : Items().OfType( SCH_GROUP_T ) )
1908 toCheckGroups.insert( static_cast<SCH_GROUP*>( item ) );
1909
1910 while( !toCheckGroups.empty() )
1911 {
1912 currentChainGroups.clear();
1913 EDA_GROUP* group = *toCheckGroups.begin();
1914
1915 while( true )
1916 {
1917 if( currentChainGroups.find( group ) != currentChainGroups.end() )
1918 {
1919 if( repair )
1920 Remove( static_cast<SCH_ITEM*>( group->AsEdaItem() ) );
1921
1922 return "Cycle detected in group membership";
1923 }
1924 else if( knownCycleFreeGroups.find( group ) != knownCycleFreeGroups.end() )
1925 {
1926 // Parent is a group we know does not lead to a cycle
1927 break;
1928 }
1929
1930 currentChainGroups.insert( group );
1931 // We haven't visited currIdx yet, so it must be in toCheckGroups
1932 toCheckGroups.erase( group );
1933
1934 group = group->AsEdaItem()->GetParentGroup();
1935
1936 if( !group )
1937 {
1938 // end of chain and no cycles found in this chain
1939 break;
1940 }
1941 }
1942
1943 // No cycles found in chain, so add it to set of groups we know don't participate
1944 // in a cycle.
1945 knownCycleFreeGroups.insert( currentChainGroups.begin(), currentChainGroups.end() );
1946 }
1947
1948 // Success
1949 return "";
1950}
1951
1952
1954{
1955 wxCHECK( Schematic() && !m_fileName.IsEmpty(), false );
1956
1957 wxFileName thisScreenFn( m_fileName );
1958 wxFileName thisProjectFn( Schematic()->Project().GetProjectFullName() );
1959
1960 wxCHECK( thisProjectFn.IsAbsolute(), false );
1961
1962 if( thisScreenFn.GetDirCount() < thisProjectFn.GetDirCount() )
1963 return false;
1964
1965 while( thisProjectFn.GetDirCount() != thisScreenFn.GetDirCount() )
1966 thisScreenFn.RemoveLastDir();
1967
1968 return thisScreenFn.GetPath() == thisProjectFn.GetPath();
1969}
1970
1971
1972std::set<wxString> SCH_SCREEN::GetVariantNames() const
1973{
1974 std::set<wxString> variantNames;
1975
1976 for( const SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1977 {
1978 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
1979
1980 wxCHECK2( symbol, continue );
1981
1982 const std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
1983
1984 for( const SCH_SYMBOL_INSTANCE& instance : symbolInstances )
1985 {
1986 for( const auto& [name, variant] : instance.m_Variants )
1987 variantNames.emplace( name );
1988 }
1989 }
1990
1991 for( const SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1992 {
1993 const SCH_SHEET* sheet = static_cast<const SCH_SHEET*>( item );
1994
1995 wxCHECK2( sheet, continue );
1996
1997 const std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
1998
1999 for( const SCH_SHEET_INSTANCE& instance : sheetInstances )
2000 {
2001 for( const auto& [name, variant] : instance.m_Variants )
2002 variantNames.emplace( name );
2003 }
2004 }
2005
2006 return variantNames;
2007}
2008
2009
2010void SCH_SCREEN::DeleteVariant( const wxString& aVariantName, SCH_COMMIT* aCommit )
2011{
2012 wxCHECK( !aVariantName.IsEmpty(), /* void */ );
2013
2014 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
2015 {
2016 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2017
2018 wxCHECK2( symbol, continue );
2019
2020 std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
2021
2022 for( SCH_SYMBOL_INSTANCE& instance : symbolInstances )
2023 {
2024 if( instance.m_Variants.contains( aVariantName ) )
2025 {
2026 if( aCommit )
2027 aCommit->Modify( item, this );
2028
2029 symbol->DeleteVariant( instance.m_Path, aVariantName );
2030 }
2031 }
2032 }
2033
2034 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
2035 {
2036 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2037
2038 wxCHECK2( sheet, continue );
2039
2040 std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
2041
2042 for( SCH_SHEET_INSTANCE& instance : sheetInstances )
2043 {
2044 if( instance.m_Variants.contains( aVariantName ) )
2045 {
2046 if( aCommit )
2047 aCommit->Modify( item, this );
2048
2049 sheet->DeleteVariant( instance.m_Path, aVariantName );
2050 }
2051 }
2052 }
2053}
2054
2055
2056void SCH_SCREEN::RenameVariant( const wxString& aOldName, const wxString& aNewName,
2057 SCH_COMMIT* aCommit )
2058{
2059 wxCHECK( !aOldName.IsEmpty() && !aNewName.IsEmpty(), /* void */ );
2060
2061 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
2062 {
2063 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2064
2065 wxCHECK2( symbol, continue );
2066
2067 std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
2068
2069 for( SCH_SYMBOL_INSTANCE& instance : symbolInstances )
2070 {
2071 if( instance.m_Variants.contains( aOldName ) )
2072 {
2073 if( aCommit )
2074 aCommit->Modify( item, this );
2075
2076 symbol->RenameVariant( instance.m_Path, aOldName, aNewName );
2077 }
2078 }
2079 }
2080
2081 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
2082 {
2083 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2084
2085 wxCHECK2( sheet, continue );
2086
2087 std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
2088
2089 for( SCH_SHEET_INSTANCE& instance : sheetInstances )
2090 {
2091 if( instance.m_Variants.contains( aOldName ) )
2092 {
2093 if( aCommit )
2094 aCommit->Modify( item, this );
2095
2096 sheet->RenameVariant( instance.m_Path, aOldName, aNewName );
2097 }
2098 }
2099 }
2100}
2101
2102
2103void SCH_SCREEN::CopyVariant( const wxString& aSourceVariant, const wxString& aNewVariant,
2104 SCH_COMMIT* aCommit )
2105{
2106 wxCHECK( !aSourceVariant.IsEmpty() && !aNewVariant.IsEmpty(), /* void */ );
2107
2108 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
2109 {
2110 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2111
2112 wxCHECK2( symbol, continue );
2113
2114 std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = symbol->GetInstances();
2115
2116 for( SCH_SYMBOL_INSTANCE& instance : symbolInstances )
2117 {
2118 if( instance.m_Variants.contains( aSourceVariant ) )
2119 {
2120 if( aCommit )
2121 aCommit->Modify( item, this );
2122
2123 symbol->CopyVariant( instance.m_Path, aSourceVariant, aNewVariant );
2124 }
2125 }
2126 }
2127
2128 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
2129 {
2130 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2131
2132 wxCHECK2( sheet, continue );
2133
2134 std::vector<SCH_SHEET_INSTANCE> sheetInstances = sheet->GetInstances();
2135
2136 for( SCH_SHEET_INSTANCE& instance : sheetInstances )
2137 {
2138 if( instance.m_Variants.contains( aSourceVariant ) )
2139 {
2140 if( aCommit )
2141 aCommit->Modify( item, this );
2142
2143 sheet->CopyVariant( instance.m_Path, aSourceVariant, aNewVariant );
2144 }
2145 }
2146 }
2147}
2148
2149
2150#if defined(DEBUG)
2151void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
2152{
2153 // for now, make it look like XML, expand on this later.
2154 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n";
2155
2156 for( const SCH_ITEM* item : Items() )
2157 item->Show( nestLevel + 1, os );
2158
2159 NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
2160}
2161#endif
2162
2163
2165{
2166 m_index = 0;
2167 buildScreenList( aSheet );
2168}
2169
2170
2174
2175
2177{
2178 m_index = 0;
2179
2180 if( m_screens.size() > 0 )
2181 return m_screens[0];
2182
2183 return nullptr;
2184}
2185
2186
2188{
2189 if( m_index < m_screens.size() )
2190 m_index++;
2191
2192 return GetScreen( m_index );
2193}
2194
2195
2196SCH_SCREEN* SCH_SCREENS::GetScreen( unsigned int aIndex ) const
2197{
2198 if( aIndex < m_screens.size() )
2199 return m_screens[ aIndex ];
2200
2201 return nullptr;
2202}
2203
2204
2205SCH_SHEET* SCH_SCREENS::GetSheet( unsigned int aIndex ) const
2206{
2207 if( aIndex < m_sheets.size() )
2208 return m_sheets[ aIndex ];
2209
2210 return nullptr;
2211}
2212
2213
2215{
2216 if( aScreen == nullptr )
2217 return;
2218
2219 for( const SCH_SCREEN* screen : m_screens )
2220 {
2221 if( screen == aScreen )
2222 return;
2223 }
2224
2225 m_screens.push_back( aScreen );
2226 m_sheets.push_back( aSheet );
2227}
2228
2229
2231{
2232 if( aSheet && aSheet->Type() == SCH_SHEET_T )
2233 {
2234 SCH_SCREEN* screen = aSheet->GetScreen();
2235
2236 if( !screen )
2237 return;
2238
2239 addScreenToList( screen, aSheet );
2240
2241 for( SCH_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
2242 buildScreenList( static_cast<SCH_SHEET*>( item ) );
2243 }
2244}
2245
2246
2248{
2249 SCH_SCREEN* first = GetFirst();
2250
2251 if( !first )
2252 return;
2253
2254 SCHEMATIC* sch = first->Schematic();
2255
2256 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::ClearAnnotationOfNewSheetPaths" );
2257
2258 // Clear the annotation for symbols inside new sheetpaths not already in aInitialSheetList
2259 SCH_SCREENS screensList( sch->Root() ); // The list of screens, shared by sheet paths
2260 screensList.BuildClientSheetPathList(); // build the shared by sheet paths, by screen
2261
2262 // Search for new sheet paths, not existing in aInitialSheetPathList
2263 // and existing in sheetpathList
2264 for( SCH_SHEET_PATH& sheetpath : sch->Hierarchy() )
2265 {
2266 bool path_exists = false;
2267
2268 for( const SCH_SHEET_PATH& existing_sheetpath: aInitialSheetPathList )
2269 {
2270 if( existing_sheetpath.Path() == sheetpath.Path() )
2271 {
2272 path_exists = true;
2273 break;
2274 }
2275 }
2276
2277 if( !path_exists )
2278 {
2279 // A new sheet path is found: clear the annotation corresponding to this new path:
2280 SCH_SCREEN* curr_screen = sheetpath.LastScreen();
2281
2282 // Clear annotation and create the AR for this path, if not exists,
2283 // when the screen is shared by sheet paths.
2284 // Otherwise ClearAnnotation do nothing, because the F1 field is used as
2285 // reference default value and takes the latest displayed value
2286 curr_screen->EnsureAlternateReferencesExist();
2287 curr_screen->ClearAnnotation( &sheetpath, false );
2288 }
2289 }
2290}
2291
2292
2294{
2295 std::vector<SCH_ITEM*> items;
2296 int count = 0;
2297
2298 auto timestamp_cmp = []( const EDA_ITEM* a, const EDA_ITEM* b ) -> bool
2299 {
2300 return a->m_Uuid < b->m_Uuid;
2301 };
2302
2303 std::set<EDA_ITEM*, decltype( timestamp_cmp )> unique_stamps( timestamp_cmp );
2304
2305 // Collect ALL items from all screens to detect duplicate UUIDs.
2306 // This is essential for design blocks where multiple instances of the same content
2307 // are placed on the same sheet - each instance needs unique UUIDs for items like
2308 // wires, junctions, and groups, not just symbols and sheets.
2309 for( SCH_SCREEN* screen : m_screens )
2310 {
2311 for( SCH_ITEM* item : screen->Items() )
2312 items.push_back( item );
2313 }
2314
2315 if( items.size() < 2 )
2316 return 0;
2317
2318 for( SCH_ITEM* item : items )
2319 {
2320 if( !unique_stamps.insert( item ).second )
2321 {
2322 // Reset to fully random UUID. This may lose reference, but better to be
2323 // deterministic about it rather than to have duplicate UUIDs with random
2324 // side-effects.
2325 const_cast<KIID&>( item->m_Uuid ) = KIID();
2326
2327 if( SCH_SCREEN* screen = item->GetParentScreen() )
2328 screen->BumpConnectivityRevision();
2329
2330 count++;
2331
2332 // @todo If the item is a sheet, we need to descend the hierarchy from the sheet
2333 // and replace all instances of the changed UUID in sheet paths. Otherwise,
2334 // all instance paths with the sheet's UUID will get clobbered.
2335 }
2336 }
2337
2338 return count;
2339}
2340
2341
2343{
2344 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2345 {
2346 for( SCH_ITEM* item : screen->Items() )
2347 item->ClearEditFlags();
2348 }
2349}
2350
2351
2353{
2354 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2355 {
2356 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
2357 {
2358 if( item == aMarker )
2359 {
2360 screen->DeleteItem( item );
2361 return;
2362 }
2363 }
2364 }
2365}
2366
2367
2368void SCH_SCREENS::DeleteMarkers( enum MARKER_BASE::MARKER_T aMarkerType, int aErrorCode,
2369 bool aIncludeExclusions )
2370{
2371 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2372 {
2373 std::vector<SCH_ITEM*> markers;
2374
2375 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
2376 {
2377 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
2378 std::shared_ptr<RC_ITEM>rcItem = marker->GetRCItem();
2379
2380 if( marker->GetMarkerType() == aMarkerType
2381 && ( aErrorCode == ERCE_UNSPECIFIED || rcItem->GetErrorCode() == aErrorCode )
2382 && ( !marker->IsExcluded() || aIncludeExclusions ) )
2383 {
2384 markers.push_back( item );
2385 }
2386 }
2387
2388 for( SCH_ITEM* marker : markers )
2389 screen->DeleteItem( marker );
2390 }
2391}
2392
2393
2395 bool aIncludeExclusions )
2396{
2397 DeleteMarkers( aMarkerType, ERCE_UNSPECIFIED, aIncludeExclusions );
2398}
2399
2400
2402{
2403 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2404 screen->UpdateSymbolLinks( aReporter );
2405
2406 SCH_SCREEN* first = GetFirst();
2407
2408 if( !first )
2409 return;
2410
2411 SCHEMATIC* sch = first->Schematic();
2412
2413 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::UpdateSymbolLinks" );
2414
2415 // Replacing library symbols invalidates pointers retained by connectivity.
2416 sch->RebuildConnectivity();
2417}
2418
2419
2421{
2422 bool has_symbols = false;
2423
2424 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2425 {
2426 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
2427 {
2428 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2429 has_symbols = true;
2430
2431 if( !symbol->GetLibId().GetLibNickname().empty() )
2432 return false;
2433 }
2434 }
2435
2436 // return true (i.e. has no fully defined symbol) only if at least one symbol is found
2437 return has_symbols ? true : false;
2438}
2439
2440
2441size_t SCH_SCREENS::GetLibNicknames( wxArrayString& aLibNicknames )
2442{
2443 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2444 {
2445 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
2446 {
2447 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2448 const UTF8& nickname = symbol->GetLibId().GetLibNickname();
2449
2450 if( !nickname.empty() && ( aLibNicknames.Index( nickname ) == wxNOT_FOUND ) )
2451 aLibNicknames.Add( nickname );
2452 }
2453 }
2454
2455 return aLibNicknames.GetCount();
2456}
2457
2458
2459int SCH_SCREENS::ChangeSymbolLibNickname( const wxString& aFrom, const wxString& aTo )
2460{
2461 SCH_SCREEN* screen;
2462 int cnt = 0;
2463
2464 for( screen = GetFirst(); screen; screen = GetNext() )
2465 {
2466 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
2467 {
2468 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2469
2470 if( symbol->GetLibId().GetLibNickname().wx_str() != aFrom )
2471 continue;
2472
2473 LIB_ID id = symbol->GetLibId();
2474 id.SetLibNickname( aTo );
2475 symbol->SetLibId( id );
2476 cnt++;
2477 }
2478 }
2479
2480 return cnt;
2481}
2482
2483
2484bool SCH_SCREENS::HasSchematic( const wxString& aSchematicFileName )
2485{
2486 for( const SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2487 {
2488 if( screen->GetFileName() == aSchematicFileName )
2489 return true;
2490 }
2491
2492 return false;
2493}
2494
2495
2497{
2498 SCH_SCREEN* first = GetFirst();
2499
2500 if( !first )
2501 return;
2502
2503 SCHEMATIC* sch = first->Schematic();
2504
2505 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::BuildClientSheetPathList" );
2506
2507 // Don't build until we have a hierarchy to work with. This can be called before the hierarchy is built.
2508 if( !sch->HasHierarchy() )
2509 return;
2510
2511 for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
2512 curr_screen->GetClientSheetPaths().clear();
2513
2514 for( SCH_SHEET_PATH& sheetpath : sch->Hierarchy() )
2515 {
2516 SCH_SCREEN* used_screen = sheetpath.LastScreen();
2517
2518 // Search for the used_screen in list and add this unique sheet path:
2519 for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
2520 {
2521 if( used_screen == curr_screen )
2522 {
2523 curr_screen->GetClientSheetPaths().push_back( sheetpath );
2524 break;
2525 }
2526 }
2527 }
2528}
2529
2530
2532{
2533 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2534 screen->SetLegacySymbolInstanceData();
2535}
2536
2537
2539{
2540 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2541 screen->FixLegacyPowerSymbolMismatches();
2542}
2543
2544
2546{
2547 LOCALE_IO toggle;
2548
2549 // V6 schematics may specify model names in Value fields, which we don't do in V7.
2550 // Migrate by adding an equivalent model for these symbols.
2551
2552 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
2553 {
2554 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2555 SIM_MODEL::MigrateSimModel<SCH_SYMBOL>( *symbol, &Schematic()->Project() );
2556 }
2557}
2558
2559
2560void SCH_SCREENS::PruneOrphanedSymbolInstances( const wxString& aProjectName,
2561 const SCH_SHEET_LIST& aValidSheetPaths )
2562{
2563 if( aProjectName.IsEmpty() )
2564 return;
2565
2566 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2567 screen->PruneOrphanedSymbolInstances( aProjectName, aValidSheetPaths );
2568}
2569
2570
2571void SCH_SCREENS::PruneOrphanedSheetInstances( const wxString& aProjectName,
2572 const SCH_SHEET_LIST& aValidSheetPaths )
2573{
2574 if( aProjectName.IsEmpty() )
2575 return;
2576
2577 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2578 screen->PruneOrphanedSheetInstances( aProjectName, aValidSheetPaths );
2579}
2580
2581
2583{
2584 for( const SCH_SCREEN* screen : m_screens )
2585 {
2586 if( screen->HasSymbolFieldNamesWithWhiteSpace() )
2587 return true;
2588 }
2589
2590 return false;
2591}
2592
2593
2594std::set<wxString> SCH_SCREENS::GetVariantNames() const
2595{
2596 std::set<wxString> variantNames;
2597
2598 for( const SCH_SCREEN* screen : m_screens )
2599 {
2600 for( const wxString& variantName : screen->GetVariantNames() )
2601 variantNames.emplace( variantName );
2602 }
2603
2604 return variantNames;
2605}
2606
2607
2608void SCH_SCREENS::DeleteVariant( const wxString& aVariantName, SCH_COMMIT* aCommit )
2609{
2610 wxCHECK( !aVariantName.IsEmpty(), /* void */ );
2611
2612 for( SCH_SCREEN* screen : m_screens )
2613 screen->DeleteVariant( aVariantName, aCommit );
2614}
2615
2616
2617void SCH_SCREENS::RenameVariant( const wxString& aOldName, const wxString& aNewName,
2618 SCH_COMMIT* aCommit )
2619{
2620 wxCHECK( !aOldName.IsEmpty() && !aNewName.IsEmpty(), /* void */ );
2621
2622 for( SCH_SCREEN* screen : m_screens )
2623 screen->RenameVariant( aOldName, aNewName, aCommit );
2624}
2625
2626
2627void SCH_SCREENS::CopyVariant( const wxString& aSourceVariant, const wxString& aNewVariant,
2628 SCH_COMMIT* aCommit )
2629{
2630 wxCHECK( !aSourceVariant.IsEmpty() && !aNewVariant.IsEmpty(), /* void */ );
2631
2632 for( SCH_SCREEN* screen : m_screens )
2633 screen->CopyVariant( aSourceVariant, aNewVariant, aCommit );
2634}
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:175
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
void SetLineColor(const COLOR4D &aColor)
Definition eda_shape.h:171
std::vector< VECTOR2I > GetRectCorners() const
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:136
RENDER_SETTINGS * RenderSettings()
Definition plotter.h:167
virtual void SetCurrentLineWidth(int width, void *aData=nullptr)=0
Set the line width for the next drawing.
A small class to help profiling.
Definition profile.h:46
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition profile.h: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:190
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:200
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:304
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:536
virtual bool IsConnectable() const
Definition sch_item.h:545
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:558
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:424
EDA_ANGLE Angle() const
Get the angle between the start and end lines.
Definition sch_line.h:101
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
VECTOR2I GetEndPoint() const
Definition sch_line.h:145
VECTOR2I GetStartPoint() const
Definition sch_line.h:136
bool IsBus() const
Return true if the line is a bus.
void SetLineStyle(const LINE_STYLE aStyle)
Definition sch_line.cpp:408
bool IsEndPoint(const VECTOR2I &aPoint) const override
Test if aPt is an end point of this schematic object.
Definition sch_line.h:88
KIGFX::COLOR4D GetLineColor() const
Return COLOR4D::UNSPECIFIED if a custom color hasn't been set for this line.
Definition sch_line.cpp:395
void SetLineColor(const KIGFX::COLOR4D &aColor)
Definition sch_line.cpp:371
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:146
SCH_SCREEN * GetNext()
unsigned int m_index
Definition sch_screen.h:965
std::vector< SCH_SHEET * > m_sheets
Definition sch_screen.h:964
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:963
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:743
uint64_t m_connectivitySymbolRevision
Definition sch_screen.h:745
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:779
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:776
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:505
const uint64_t m_connectivityId
Definition sch_screen.h:742
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:763
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:767
double m_LastZoomLevel
last value for the zoom level, useful in Eeschema when changing the current displayed sheet to reuse ...
Definition sch_screen.h:739
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:749
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:748
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:744
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:511
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:765
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:709
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:770
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:762
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:773
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 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:746
SCH_LABEL_BASE * GetLabel(const VECTOR2I &aPosition, int aAccuracy=0) const
Return a label item located at aPosition.
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
std::optional< SCH_SHEET_PATH > GetSheetPathByKIIDPath(const KIID_PATH &aPath, bool aIncludeLastSheet=true) const
Finds a SCH_SHEET_PATH that matches the provided KIID_PATH.
bool HasPath(const KIID_PATH &aPath) const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Define a sheet pin (label) used in sheets to create hierarchical schematics.
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void CopyVariant(const KIID_PATH &aPath, const wxString &aSourceVariant, const wxString &aNewVariant)
void RemoveInstance(const KIID_PATH &aInstancePath)
wxString GetName() const
Definition sch_sheet.h:142
SCH_SHEET_PIN * GetPin(const VECTOR2I &aPosition)
Return the sheet pin item found at aPosition in the sheet.
void RemovePin(const SCH_SHEET_PIN *aSheetPin)
Remove aSheetPin from the sheet.
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
void DeleteVariant(const KIID_PATH &aPath, const wxString &aVariantName)
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition sch_sheet.h:521
Schematic symbol object.
Definition sch_symbol.h:73
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:133
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
wxString GetSchSymbolLibraryName() const
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool AddSheetPathReferenceEntryIfMissing(const KIID_PATH &aSheetPath)
Add an instance to the alternate references list (m_instances), if this entry does not already exist.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
std::vector< SCH_PIN * > GetAllLibPins() const
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:163
void SetSchSymbolLibraryName(const wxString &aName)
The name of the symbol in the schematic library symbol list.
Definition sch_symbol.h:178
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:182
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:474
@ LAYER_NOTES
Definition layer_ids.h:489
@ LAYER_BUS
Definition layer_ids.h:475
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