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 (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <stack>
28#include <wx/filefn.h>
29
30#include <eda_item.h>
31#include <id.h>
32#include <string_utils.h>
33#include <kiway.h>
34#include <plotters/plotter.h>
35#include <project.h>
36#include <reporter.h>
37#include <sch_draw_panel.h>
38#include <sch_edit_frame.h>
39#include <sch_item.h>
40
41#include <symbol_library.h>
42#include <connection_graph.h>
43#include <lib_pin.h>
44#include <lib_shape.h>
45#include <sch_symbol.h>
46#include <sch_junction.h>
47#include <sch_line.h>
48#include <sch_marker.h>
49#include <sch_sheet.h>
50#include <sch_sheet_pin.h>
51#include <sch_text.h>
52#include <schematic.h>
53#include <symbol_lib_table.h>
54#include <tool/common_tools.h>
55#include <sim/sim_model.h> // For V6 to V7 simulation model migration.
56#include <sim/sim_value.h> //
57#include <locale_io.h>
58
59#include <algorithm>
60
61// TODO(JE) Debugging only
62#include <core/profile.h>
63#include "sch_bus_entry.h"
64#include "sim/sim_model_ideal.h"
65
66/*
67 * Flag to enable profiling of the TestDanglingEnds() function.
68 * @ingroup trace_env_vars
69 */
70static const wxChar DanglingProfileMask[] = wxT( "DANGLING_PROFILE" );
71
73 BASE_SCREEN( aParent, SCH_SCREEN_T ),
74 m_fileFormatVersionAtLoad( 0 ),
75 m_paper( wxT( "A4" ) ),
76 m_isReadOnly( false ),
77 m_fileExists( false )
78{
80 m_refCount = 0;
81 m_zoomInitialized = false;
82 m_LastZoomLevel = 1.0;
83
84 // Suitable for schematic only. For symbol_editor and viewlib, must be set to true
85 m_Center = false;
86
88}
89
90
92{
95}
96
97
99{
100 wxCHECK_MSG( GetParent() && GetParent()->Type() == SCHEMATIC_T, nullptr,
101 wxT( "SCH_SCREEN must have a SCHEMATIC parent!" ) );
102
103 return static_cast<SCHEMATIC*>( GetParent() );
104}
105
106
108{
109 for( const std::pair<const wxString, LIB_SYMBOL*>& libSymbol : m_libSymbols )
110 delete libSymbol.second;
111
112 m_libSymbols.clear();
113}
114
115
116void SCH_SCREEN::SetFileName( const wxString& aFileName )
117{
118 wxASSERT( aFileName.IsEmpty() || wxIsAbsolutePath( aFileName ) );
119
120 m_fileName = aFileName;
121}
122
123
125{
126 m_refCount++;
127}
128
129
131{
132 wxCHECK_RET( m_refCount != 0, wxT( "Screen reference count already zero. Bad programmer!" ) );
133 m_refCount--;
134}
135
136
137bool SCH_SCREEN::HasItems( KICAD_T aItemType ) const
138{
139 EE_RTREE::EE_TYPE sheets = m_rtree.OfType( aItemType );
140
141 return sheets.begin() != sheets.end();
142}
143
144
145bool SCH_SCREEN::ClassOf( const EDA_ITEM* aItem )
146{
147 return aItem && SCH_SCREEN_T == aItem->Type();
148}
149
150
151void SCH_SCREEN::Append( SCH_ITEM* aItem, bool aUpdateLibSymbol )
152{
153 if( aItem->Type() != SCH_SHEET_PIN_T && aItem->Type() != SCH_FIELD_T )
154 {
155 // Ensure the item can reach the SCHEMATIC through this screen
156 aItem->SetParent( this );
157
158 if( aItem->Type() == SCH_SYMBOL_T && aUpdateLibSymbol )
159 {
160 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
161
162 if( symbol->GetLibSymbolRef() )
163 {
164 symbol->GetLibSymbolRef()->GetDrawItems().sort();
165
166 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
167
168 if( it == m_libSymbols.end() || !it->second )
169 {
171 new LIB_SYMBOL( *symbol->GetLibSymbolRef() );
172 }
173 else
174 {
175 // The original library symbol may have changed since the last time
176 // it was added to the schematic. If it has changed, then a new name
177 // must be created for the library symbol list to prevent all of the
178 // other schematic symbols referencing that library symbol from changing.
179 LIB_SYMBOL* foundSymbol = it->second;
180
181 foundSymbol->GetDrawItems().sort();
182
183 if( *foundSymbol != *symbol->GetLibSymbolRef() )
184 {
185 wxString newName;
186 std::vector<wxString> matches;
187
188 getLibSymbolNameMatches( *symbol, matches );
189 foundSymbol = nullptr;
190
191 for( const wxString& libSymbolName : matches )
192 {
193 it = m_libSymbols.find( libSymbolName );
194
195 if( it == m_libSymbols.end() )
196 continue;
197
198 foundSymbol = it->second;
199
200 wxCHECK2( foundSymbol, continue );
201
202 wxString tmp = symbol->GetLibSymbolRef()->GetName();
203
204 // Temporarily update the new symbol library symbol name so it
205 // doesn't fail on the name comparison below.
206 symbol->GetLibSymbolRef()->SetName( foundSymbol->GetName() );
207
208 if( *foundSymbol == *symbol->GetLibSymbolRef() )
209 {
210 newName = libSymbolName;
211 symbol->GetLibSymbolRef()->SetName( tmp );
212 break;
213 }
214
215 symbol->GetLibSymbolRef()->SetName( tmp );
216 foundSymbol = nullptr;
217 }
218
219 if( !foundSymbol )
220 {
221 int cnt = 1;
222
223 newName.Printf( wxT( "%s_%d" ),
225 cnt );
226
227 while( m_libSymbols.find( newName ) != m_libSymbols.end() )
228 {
229 cnt += 1;
230 newName.Printf( wxT( "%s_%d" ),
232 cnt );
233 }
234 }
235
236 // Update the schematic symbol library link as this symbol only exists
237 // in the schematic.
238 symbol->SetSchSymbolLibraryName( newName );
239
240 if( !foundSymbol )
241 {
242 // Update the schematic symbol library link as this symbol does not
243 // exist in any symbol library.
244 LIB_ID newLibId( wxEmptyString, newName );
245 LIB_SYMBOL* newLibSymbol = new LIB_SYMBOL( *symbol->GetLibSymbolRef() );
246
247 newLibSymbol->SetLibId( newLibId );
248 newLibSymbol->SetName( newName );
249 symbol->SetLibSymbol( newLibSymbol->Flatten().release() );
250 m_libSymbols[newName] = newLibSymbol;
251 }
252 }
253 }
254 }
255 }
256
257 m_rtree.insert( aItem );
259 }
260}
261
262
264{
265 wxCHECK_RET( aScreen, "Invalid screen object." );
266
267 // No need to descend the hierarchy. Once the top level screen is copied, all of its
268 // children are copied as well.
269 for( SCH_ITEM* aItem : aScreen->m_rtree )
270 Append( aItem );
271
272 aScreen->Clear( false );
273}
274
275
276void SCH_SCREEN::Clear( bool aFree )
277{
278 if( aFree )
279 {
280 FreeDrawList();
282 }
283 else
284 {
285 m_rtree.clear();
286 }
287
288 // Clear the project settings
290
291 m_titles.Clear();
292}
293
294
296{
297 // We don't know which order we will encounter dependent items (e.g. pins or fields), so
298 // we store the items to be deleted until we've fully cleared the tree before deleting
299 std::vector<SCH_ITEM*> delete_list;
300
301 std::copy_if( m_rtree.begin(), m_rtree.end(), std::back_inserter( delete_list ),
302 []( SCH_ITEM* aItem )
303 {
304 return ( aItem->Type() != SCH_SHEET_PIN_T && aItem->Type() != SCH_FIELD_T );
305 } );
306
307 m_rtree.clear();
308
309 for( SCH_ITEM* item : delete_list )
310 delete item;
311}
312
313
314void SCH_SCREEN::Update( SCH_ITEM* aItem, bool aUpdateLibSymbol )
315{
316 if( Remove( aItem, aUpdateLibSymbol ) )
317 Append( aItem, aUpdateLibSymbol );
318}
319
320
321bool SCH_SCREEN::Remove( SCH_ITEM* aItem, bool aUpdateLibSymbol )
322{
323 bool retv = m_rtree.remove( aItem );
324
325 // Check if the library symbol for the removed schematic symbol is still required.
326 if( retv && aItem->Type() == SCH_SYMBOL_T && aUpdateLibSymbol )
327 {
328 SCH_SYMBOL* removedSymbol = static_cast<SCH_SYMBOL*>( aItem );
329
330 bool removeUnusedLibSymbol = true;
331
332 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
333 {
334 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
335
336 if( removedSymbol->GetSchSymbolLibraryName() == symbol->GetSchSymbolLibraryName() )
337 {
338 removeUnusedLibSymbol = false;
339 break;
340 }
341 }
342
343 if( removeUnusedLibSymbol )
344 {
345 auto it = m_libSymbols.find( removedSymbol->GetSchSymbolLibraryName() );
346
347 if( it != m_libSymbols.end() )
348 {
349 delete it->second;
350 m_libSymbols.erase( it );
351 }
352 }
353 }
354
355 return retv;
356}
357
358
360{
361 wxCHECK_RET( aItem, wxT( "Cannot delete invalid item from screen." ) );
362
363 // Markers are not saved in the file, no need to flag as modified.
364 // TODO: Maybe we should have a listing somewhere of items that aren't saved?
365 if( aItem->Type() != SCH_MARKER_T )
367
368 Remove( aItem );
369
370 if( aItem->Type() == SCH_SHEET_PIN_T )
371 {
372 // This structure is attached to a sheet, get the parent sheet object.
373 SCH_SHEET_PIN* sheetPin = (SCH_SHEET_PIN*) aItem;
374 SCH_SHEET* sheet = sheetPin->GetParent();
375 wxCHECK_RET( sheet, wxT( "Sheet pin parent not properly set, bad programmer!" ) );
376 sheet->RemovePin( sheetPin );
377 return;
378 }
379
380 delete aItem;
381}
382
383
384bool SCH_SCREEN::CheckIfOnDrawList( const SCH_ITEM* aItem ) const
385{
386 return m_rtree.contains( aItem, true );
387}
388
389
390SCH_ITEM* SCH_SCREEN::GetItem( const VECTOR2I& aPosition, int aAccuracy, KICAD_T aType ) const
391{
392 BOX2I bbox;
393 bbox.SetOrigin( aPosition );
394 bbox.Inflate( aAccuracy );
395
396 for( SCH_ITEM* item : Items().Overlapping( aType, bbox ) )
397 {
398 if( item->HitTest( aPosition, aAccuracy ) )
399 return item;
400 }
401
402 return nullptr;
403}
404
405
406std::set<SCH_ITEM*> SCH_SCREEN::MarkConnections( SCH_LINE* aSegment, bool aSecondPass )
407{
408#define PROCESSED CANDIDATE // Don't use SKIP_STRUCT; IsConnected() returns false if it's set.
409
410 std::set<SCH_ITEM*> retval;
411 std::stack<SCH_LINE*> to_search;
412
413 wxCHECK_MSG( aSegment && aSegment->Type() == SCH_LINE_T, retval, wxT( "Invalid pointer." ) );
414
415 to_search.push( aSegment );
416
417 while( !to_search.empty() )
418 {
419 SCH_ITEM* item = to_search.top();
420 to_search.pop();
421
422 if( item->HasFlag( PROCESSED ) )
423 continue;
424
425 item->SetFlags( PROCESSED );
426
427 for( SCH_ITEM* candidate : Items().Overlapping( SCH_LINE_T, item->GetBoundingBox() ) )
428 {
429 SCH_LINE* line = static_cast<SCH_LINE*>( candidate );
430
431 if( line->HasFlag( PROCESSED ) )
432 continue;
433
434 // Skip connecting lines on different layers (e.g. buses)
435 if( item->GetLayer() != line->GetLayer() )
436 continue;
437
438 for( VECTOR2I pt : { line->GetStartPoint(), line->GetEndPoint() } )
439 {
440 if( item->IsConnected( pt ) )
441 {
442 SCH_ITEM* junction = GetItem( pt, 0, SCH_JUNCTION_T );
443 SCH_ITEM* pin = GetItem( pt, 0, SCH_PIN_T );
444
445 if( item->IsSelected() && aSecondPass )
446 {
447 if( junction )
448 retval.insert( junction );
449
450 retval.insert( line );
451 to_search.push( line );
452 }
453 else if( !junction && !pin )
454 {
455 retval.insert( line );
456 to_search.push( line );
457 }
458
459 break;
460 }
461 else if( line->GetLayer() == LAYER_NOTES && item->GetLayer() == LAYER_NOTES )
462 {
463 retval.insert( line );
464 to_search.push( line );
465 }
466 }
467 }
468 }
469
470 for( SCH_ITEM* item : Items() )
471 item->ClearTempFlags();
472
473 return retval;
474}
475
476
477bool SCH_SCREEN::IsJunction( const VECTOR2I& aPosition ) const
478{
479 bool hasExplicitJunction;
480 bool hasBusEntry;
481 bool isJunction = doIsJunction( aPosition, false, &hasExplicitJunction, &hasBusEntry );
482
483 return isJunction;
484}
485
486
487bool SCH_SCREEN::IsExplicitJunction( const VECTOR2I& aPosition ) const
488{
489 bool hasExplicitJunction;
490 bool hasBusEntry;
491 bool isJunction = doIsJunction( aPosition, false, &hasExplicitJunction, &hasBusEntry );
492
493 return isJunction && !hasBusEntry;
494}
495
496
497bool SCH_SCREEN::IsExplicitJunctionNeeded( const VECTOR2I& aPosition ) const
498{
499 bool hasExplicitJunction;
500 bool hasBusEntry;
501 bool isJunction = doIsJunction( aPosition, false, &hasExplicitJunction, &hasBusEntry );
502
503 return isJunction && !hasBusEntry && !hasExplicitJunction;
504}
505
507 SPIN_STYLE aDefaultOrientation,
508 const SCH_SHEET_PATH* aSheet ) const
509{
510 auto ret = aDefaultOrientation;
511 for( SCH_ITEM* item : Items().Overlapping( aPosition ) )
512 {
513 if( item->GetEditFlags() & STRUCT_DELETED )
514 continue;
515
516 switch( item->Type() )
517 {
519 {
520 auto busEntry = static_cast<const SCH_BUS_WIRE_ENTRY*>( item );
521 if( busEntry->m_connected_bus_item )
522 {
523 // bus connected, take the bus direction into consideration ony if it is
524 // vertical or horizontal
525 auto bus = static_cast<const SCH_LINE*>( busEntry->m_connected_bus_item );
526 if( bus->Angle().AsDegrees() == 90.0 )
527 {
528 // bus is vertical -> label shall be horizontal and
529 // shall be placed to the side where the bus entry is
530 if( aPosition.x < bus->GetPosition().x )
531 ret = SPIN_STYLE::LEFT;
532 else if( aPosition.x > bus->GetPosition().x )
533 ret = SPIN_STYLE::RIGHT;
534 }
535 else if( bus->Angle().AsDegrees() == 0.0 )
536 {
537 // bus is horizontal -> label shall be vertical and
538 // shall be placed to the side where the bus entry is
539 if( aPosition.y < bus->GetPosition().y )
540 ret = SPIN_STYLE::UP;
541 else if( aPosition.y > bus->GetPosition().y )
542 ret = SPIN_STYLE::BOTTOM;
543 }
544 }
545 }
546 break;
547
548 case SCH_LINE_T:
549 {
550 auto line = static_cast<const SCH_LINE*>( item );
551 // line angles goes between -90 and 90 degrees, but normalize
552 auto angle = line->Angle().Normalize90().AsDegrees();
553
554 if( -45 < angle && angle <= 45 )
555 {
556 if( line->GetStartPoint().x <= line->GetEndPoint().x )
557 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::RIGHT : SPIN_STYLE::LEFT;
558 else
559 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::LEFT : SPIN_STYLE::RIGHT;
560 }
561 else
562 {
563 if( line->GetStartPoint().y <= line->GetEndPoint().y )
564 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::BOTTOM : SPIN_STYLE::UP;
565 else
566 ret = line->GetEndPoint() == aPosition ? SPIN_STYLE::UP : SPIN_STYLE::BOTTOM;
567 }
568 }
569 break;
570
571 case SCH_SYMBOL_T:
572 {
573 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
574
575 for( SCH_PIN* pin : symbol->GetPins( aSheet ) )
576 {
577 if( pin->GetPosition() == aPosition )
578 {
579 if( pin->GetOrientation() == PIN_ORIENTATION::PIN_RIGHT )
580 ret = SPIN_STYLE::LEFT;
581 else if( pin->GetOrientation() == PIN_ORIENTATION::PIN_LEFT )
582 ret = SPIN_STYLE::RIGHT;
583 else if( pin->GetOrientation() == PIN_ORIENTATION::PIN_UP )
584 ret = SPIN_STYLE::BOTTOM;
585 else if( pin->GetOrientation() == PIN_ORIENTATION::PIN_DOWN )
586 ret = SPIN_STYLE::UP;
587
588 switch( static_cast<SYMBOL_ORIENTATION_T>(
589 symbol->GetOrientation() & ( ~( SYM_MIRROR_X | SYM_MIRROR_Y ) ) ) )
590 {
592 case SYM_ORIENT_90:
593 if( ret == SPIN_STYLE::UP )
594 ret = SPIN_STYLE::LEFT;
595 else if( ret == SPIN_STYLE::BOTTOM )
596 ret = SPIN_STYLE::RIGHT;
597 else if( ret == SPIN_STYLE::LEFT )
598 ret = SPIN_STYLE::BOTTOM;
599 else if( ret == SPIN_STYLE::RIGHT )
600 ret = SPIN_STYLE::UP;
601
602 if( symbol->GetOrientation() & SYM_MIRROR_X )
603 {
604 if( ret == SPIN_STYLE::UP )
605 ret = SPIN_STYLE::BOTTOM;
606 else if( ret == SPIN_STYLE::BOTTOM )
607 ret = SPIN_STYLE::UP;
608 }
609
610 if( symbol->GetOrientation() & SYM_MIRROR_Y )
611 {
612 if( ret == SPIN_STYLE::LEFT )
613 ret = SPIN_STYLE::RIGHT;
614 else if( ret == SPIN_STYLE::RIGHT )
615 ret = SPIN_STYLE::LEFT;
616 }
617 break;
619 case SYM_ORIENT_270:
620 if( ret == SPIN_STYLE::UP )
621 ret = SPIN_STYLE::RIGHT;
622 else if( ret == SPIN_STYLE::BOTTOM )
623 ret = SPIN_STYLE::LEFT;
624 else if( ret == SPIN_STYLE::LEFT )
625 ret = SPIN_STYLE::UP;
626 else if( ret == SPIN_STYLE::RIGHT )
627 ret = SPIN_STYLE::BOTTOM;
628
629 if( symbol->GetOrientation() & SYM_MIRROR_X )
630 {
631 if( ret == SPIN_STYLE::UP )
632 ret = SPIN_STYLE::BOTTOM;
633 else if( ret == SPIN_STYLE::BOTTOM )
634 ret = SPIN_STYLE::UP;
635 }
636
637 if( symbol->GetOrientation() & SYM_MIRROR_Y )
638 {
639 if( ret == SPIN_STYLE::LEFT )
640 ret = SPIN_STYLE::RIGHT;
641 else if( ret == SPIN_STYLE::RIGHT )
642 ret = SPIN_STYLE::LEFT;
643 }
644 break;
645 case SYM_ORIENT_180:
646 if( ret == SPIN_STYLE::UP )
647 ret = SPIN_STYLE::BOTTOM;
648 else if( ret == SPIN_STYLE::BOTTOM )
649 ret = SPIN_STYLE::UP;
650 else if( ret == SPIN_STYLE::LEFT )
651 ret = SPIN_STYLE::RIGHT;
652 else if( ret == SPIN_STYLE::RIGHT )
653 ret = SPIN_STYLE::LEFT;
654
655 if( symbol->GetOrientation() & SYM_MIRROR_X )
656 {
657 if( ret == SPIN_STYLE::UP )
658 ret = SPIN_STYLE::BOTTOM;
659 else if( ret == SPIN_STYLE::BOTTOM )
660 ret = SPIN_STYLE::UP;
661 }
662
663 if( symbol->GetOrientation() & SYM_MIRROR_Y )
664 {
665 if( ret == SPIN_STYLE::LEFT )
666 ret = SPIN_STYLE::RIGHT;
667 else if( ret == SPIN_STYLE::RIGHT )
668 ret = SPIN_STYLE::LEFT;
669 }
670 break;
671 case SYM_ORIENT_0:
672 case SYM_NORMAL:
673 default:
674 if( symbol->GetOrientation() & SYM_MIRROR_X )
675 {
676 if( ret == SPIN_STYLE::UP )
677 ret = SPIN_STYLE::BOTTOM;
678 else if( ret == SPIN_STYLE::BOTTOM )
679 ret = SPIN_STYLE::UP;
680 }
681
682 if( symbol->GetOrientation() & SYM_MIRROR_Y )
683 {
684 if( ret == SPIN_STYLE::LEFT )
685 ret = SPIN_STYLE::RIGHT;
686 else if( ret == SPIN_STYLE::RIGHT )
687 ret = SPIN_STYLE::LEFT;
688 }
689 break;
690 }
691
692 break;
693 }
694 }
695 }
696 break;
697 default: break;
698 }
699 }
700 return ret;
701}
702
703
705{
706 bool hasExplicitJunction;
707 bool hasBusEntry;
708 bool isJunction = doIsJunction( aPosition, true, &hasExplicitJunction, &hasBusEntry );
709
710 return isJunction && !hasBusEntry;
711}
712
713
714
715bool SCH_SCREEN::doIsJunction( const VECTOR2I& aPosition, bool aBreakCrossings,
716 bool* aHasExplicitJunctionDot, bool* aHasBusEntry ) const
717{
718 enum layers { WIRES = 0, BUSES };
719
720 *aHasExplicitJunctionDot = false;
721 *aHasBusEntry = false;
722
723 bool breakLines[ 2 ] = { false };
724 std::unordered_set<int> exitAngles[ 2 ];
725 std::vector<const SCH_LINE*> midPointLines[ 2 ];
726
727 // A pin at 90° still shouldn't match a line at 90° so just give pins unique numbers
728 int uniqueAngle = 10000;
729
730 for( const SCH_ITEM* item : Items().Overlapping( aPosition ) )
731 {
732 if( item->GetEditFlags() & STRUCT_DELETED )
733 continue;
734
735 switch( item->Type() )
736 {
737 case SCH_JUNCTION_T:
738 if( item->HitTest( aPosition, -1 ) )
739 *aHasExplicitJunctionDot = true;
740
741 break;
742
743 case SCH_LINE_T:
744 {
745 const SCH_LINE* line = static_cast<const SCH_LINE*>( item );
746 int layer;
747
748 if( line->GetStartPoint() == line->GetEndPoint() )
749 break;
750 else if( line->GetLayer() == LAYER_WIRE )
751 layer = WIRES;
752 else if( line->GetLayer() == LAYER_BUS )
753 layer = BUSES;
754 else
755 break;
756
757 if( line->IsConnected( aPosition ) )
758 {
759 breakLines[ layer ] = true;
760 exitAngles[ layer ].insert( line->GetAngleFrom( aPosition ) );
761 }
762 else if( line->HitTest( aPosition, -1 ) )
763 {
764 if( aBreakCrossings )
765 breakLines[ layer ] = true;
766
767 // Defer any line midpoints until we know whether or not we're breaking them
768 midPointLines[ layer ].push_back( line );
769 }
770 }
771 break;
772
774 if( item->IsConnected( aPosition ) )
775 {
776 breakLines[ BUSES ] = true;
777 exitAngles[ BUSES ].insert( uniqueAngle++ );
778 breakLines[ WIRES ] = true;
779 exitAngles[ WIRES ].insert( uniqueAngle++ );
780 *aHasBusEntry = true;
781 }
782
783 break;
784
785 case SCH_SYMBOL_T:
786 case SCH_SHEET_T:
787 if( item->IsConnected( aPosition ) )
788 {
789 breakLines[ WIRES ] = true;
790 exitAngles[ WIRES ].insert( uniqueAngle++ );
791 }
792
793 break;
794
795 default:
796 break;
797 }
798 }
799
800 for( int layer : { WIRES, BUSES } )
801 {
802 if( breakLines[ layer ] )
803 {
804 for( const SCH_LINE* line : midPointLines[ layer ] )
805 {
806 exitAngles[ layer ].insert( line->GetAngleFrom( aPosition ) );
807 exitAngles[ layer ].insert( line->GetReverseAngleFrom( aPosition ) );
808 }
809 }
810 }
811
812 return exitAngles[ WIRES ].size() >= 3 || exitAngles[ BUSES ].size() >= 3;
813}
814
815
816bool SCH_SCREEN::IsTerminalPoint( const VECTOR2I& aPosition, int aLayer ) const
817{
818 wxCHECK_MSG( aLayer == LAYER_NOTES || aLayer == LAYER_BUS || aLayer == LAYER_WIRE, false,
819 wxT( "Invalid layer type passed to SCH_SCREEN::IsTerminalPoint()." ) );
820
821 SCH_SHEET_PIN* sheetPin;
822 SCH_LABEL_BASE* label;
823
824 switch( aLayer )
825 {
826 case LAYER_BUS:
827 if( GetBus( aPosition ) )
828 return true;
829
830 sheetPin = GetSheetPin( aPosition );
831
832 if( sheetPin && sheetPin->IsConnected( aPosition ) )
833 return true;
834
835 label = GetLabel( aPosition );
836
837 if( label && !label->IsNew() && label->IsConnected( aPosition ) )
838 return true;
839
840 break;
841
842 case LAYER_NOTES:
843 if( GetLine( aPosition ) )
844 return true;
845
846 break;
847
848 case LAYER_WIRE:
849 if( GetItem( aPosition, 1, SCH_BUS_WIRE_ENTRY_T ) )
850 return true;
851
852 if( GetItem( aPosition, 1, SCH_JUNCTION_T ) )
853 return true;
854
855 if( GetPin( aPosition, nullptr, true ) )
856 return true;
857
858 if( GetWire( aPosition ) )
859 return true;
860
861 label = GetLabel( aPosition, 1 );
862
863 if( label && !label->IsNew() && label->IsConnected( aPosition ) )
864 return true;
865
866 sheetPin = GetSheetPin( aPosition );
867
868 if( sheetPin && sheetPin->IsConnected( aPosition ) )
869 return true;
870
871 break;
872
873 default:
874 break;
875 }
876
877 return false;
878}
879
880
882{
883 wxCHECK_RET( Schematic(), "Cannot call SCH_SCREEN::UpdateSymbolLinks with no SCHEMATIC" );
884
885 wxString msg;
886 std::unique_ptr< LIB_SYMBOL > libSymbol;
887 std::vector<SCH_SYMBOL*> symbols;
888 SYMBOL_LIB_TABLE* libs = Schematic()->Prj().SchSymbolLibTable();
889
890 // This will be a nullptr if an s-expression schematic is loaded.
891 SYMBOL_LIBS* legacyLibs = Schematic()->Prj().SchLibs();
892
893 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
894 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
895
896 // Remove them from the R tree. There bounding box size may change.
897 for( SCH_SYMBOL* symbol : symbols )
898 Remove( symbol );
899
900 // Clear all existing symbol links.
902
903 for( SCH_SYMBOL* symbol : symbols )
904 {
905 LIB_SYMBOL* tmp = nullptr;
906 libSymbol.reset();
907
908 // If the symbol is already in the internal library, map the symbol to it.
909 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
910
911 if( ( it != m_libSymbols.end() ) )
912 {
913 if( aReporter )
914 {
915 msg.Printf( _( "Setting schematic symbol '%s %s' library identifier to '%s'." ),
916 symbol->GetField( REFERENCE_FIELD )->GetText(),
917 symbol->GetField( VALUE_FIELD )->GetText(),
918 UnescapeString( symbol->GetLibId().Format() ) );
919 aReporter->ReportTail( msg, RPT_SEVERITY_INFO );
920 }
921
922 // Internal library symbols are already flattened so just make a copy.
923 symbol->SetLibSymbol( new LIB_SYMBOL( *it->second ) );
924 continue;
925 }
926
927 if( !symbol->GetLibId().IsValid() )
928 {
929 if( aReporter )
930 {
931 msg.Printf( _( "Schematic symbol reference '%s' library identifier is not valid. "
932 "Unable to link library symbol." ),
933 UnescapeString( symbol->GetLibId().Format() ) );
934 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
935 }
936
937 continue;
938 }
939
940 // LIB_TABLE_BASE::LoadSymbol() throws an IO_ERROR if the library nickname
941 // is not found in the table so check if the library still exists in the table
942 // before attempting to load the symbol.
943 if( !libs->HasLibrary( symbol->GetLibId().GetLibNickname() ) && !legacyLibs )
944 {
945 if( aReporter )
946 {
947 msg.Printf( _( "Symbol library '%s' not found and no fallback cache library "
948 "available. Unable to link library symbol." ),
949 symbol->GetLibId().GetLibNickname().wx_str() );
950 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
951 }
952
953 continue;
954 }
955
956 if( libs->HasLibrary( symbol->GetLibId().GetLibNickname() ) )
957 {
958 try
959 {
960 tmp = libs->LoadSymbol( symbol->GetLibId() );
961 }
962 catch( const IO_ERROR& ioe )
963 {
964 if( aReporter )
965 {
966 msg.Printf( _( "I/O error %s resolving library symbol %s" ), ioe.What(),
967 UnescapeString( symbol->GetLibId().Format() ) );
968 aReporter->ReportTail( msg, RPT_SEVERITY_ERROR );
969 }
970 }
971 }
972
973 if( !tmp && legacyLibs && legacyLibs->GetLibraryCount() )
974 {
975 SYMBOL_LIB& legacyCacheLib = legacyLibs->back();
976
977 // It better be the cache library.
978 wxCHECK2( legacyCacheLib.IsCache(), continue );
979
980 wxString id = symbol->GetLibId().Format();
981
982 id.Replace( ':', '_' );
983
984 if( aReporter )
985 {
986 msg.Printf( _( "Falling back to cache to set symbol '%s:%s' link '%s'." ),
987 symbol->GetField( REFERENCE_FIELD )->GetText(),
988 symbol->GetField( VALUE_FIELD )->GetText(),
989 UnescapeString( id ) );
990 aReporter->ReportTail( msg, RPT_SEVERITY_WARNING );
991 }
992
993 tmp = legacyCacheLib.FindSymbol( id );
994 }
995
996 if( tmp )
997 {
998 // We want a full symbol not just the top level child symbol.
999 libSymbol = tmp->Flatten();
1000 libSymbol->SetParent();
1001
1002 m_libSymbols.insert( { symbol->GetSchSymbolLibraryName(),
1003 new LIB_SYMBOL( *libSymbol.get() ) } );
1004
1005 if( aReporter )
1006 {
1007 msg.Printf( _( "Setting schematic symbol '%s %s' library identifier to '%s'." ),
1008 symbol->GetField( REFERENCE_FIELD )->GetText(),
1009 symbol->GetField( VALUE_FIELD )->GetText(),
1010 UnescapeString( symbol->GetLibId().Format() ) );
1011 aReporter->ReportTail( msg, RPT_SEVERITY_INFO );
1012 }
1013 }
1014 else
1015 {
1016 if( aReporter )
1017 {
1018 msg.Printf( _( "No library symbol found for schematic symbol '%s %s'." ),
1019 symbol->GetField( REFERENCE_FIELD )->GetText(),
1020 symbol->GetField( VALUE_FIELD )->GetText() );
1021 aReporter->ReportTail( msg, RPT_SEVERITY_ERROR );
1022 }
1023 }
1024
1025 symbol->SetLibSymbol( libSymbol.release() );
1026 }
1027
1028 // Changing the symbol may adjust the bbox of the symbol. This re-inserts the
1029 // item with the new bbox
1030 for( SCH_SYMBOL* symbol : symbols )
1031 Append( symbol );
1032}
1033
1034
1036{
1037 std::vector<SCH_SYMBOL*> symbols;
1038
1039 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1040 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
1041
1042 for( SCH_SYMBOL* symbol : symbols )
1043 {
1044 // Changing the symbol may adjust the bbox of the symbol; remove and reinsert it afterwards.
1045 m_rtree.remove( symbol );
1046
1047 auto it = m_libSymbols.find( symbol->GetSchSymbolLibraryName() );
1048
1049 LIB_SYMBOL* libSymbol = nullptr;
1050
1051 if( it != m_libSymbols.end() )
1052 libSymbol = new LIB_SYMBOL( *it->second );
1053
1054 symbol->SetLibSymbol( libSymbol );
1055
1056 m_rtree.insert( symbol );
1057 }
1058}
1059
1060
1062{
1063 for( SCH_ITEM* item : Items() )
1064 item->SetConnectivityDirty( true );
1065}
1066
1067
1068void SCH_SCREEN::Print( const RENDER_SETTINGS* aSettings )
1069{
1070 // Ensure links are up to date, even if a library was reloaded for some reason:
1071 std::vector<SCH_ITEM*> junctions;
1072 std::vector<SCH_ITEM*> bitmaps;
1073 std::vector<SCH_ITEM*> other;
1074
1075 for( SCH_ITEM* item : Items() )
1076 {
1077 if( item->IsMoving() )
1078 continue;
1079
1080 if( item->Type() == SCH_JUNCTION_T )
1081 junctions.push_back( item );
1082 else if( item->Type() == SCH_BITMAP_T )
1083 bitmaps.push_back( item );
1084 else
1085 other.push_back( item );
1086 }
1087
1089 std::stable_sort( other.begin(), other.end(),
1090 []( const SCH_ITEM* a, const SCH_ITEM* b )
1091 {
1092 if( a->Type() == b->Type() )
1093 return a->GetLayer() > b->GetLayer();
1094
1095 return a->Type() < b->Type();
1096 } );
1097
1098 for( SCH_ITEM* item : bitmaps )
1099 item->Print( aSettings, VECTOR2I( 0, 0 ) );
1100
1101 for( SCH_ITEM* item : other )
1102 item->PrintBackground( aSettings, VECTOR2I( 0, 0 ) );
1103
1104 for( SCH_ITEM* item : other )
1105 item->Print( aSettings, VECTOR2I( 0, 0 ) );
1106
1107 for( SCH_ITEM* item : junctions )
1108 item->Print( aSettings, VECTOR2I( 0, 0 ) );
1109}
1110
1111
1112void SCH_SCREEN::Plot( PLOTTER* aPlotter ) const
1113{
1114 // Ensure links are up to date, even if a library was reloaded for some reason:
1115 std::vector<SCH_ITEM*> junctions;
1116 std::vector<SCH_ITEM*> bitmaps;
1117 std::vector<SCH_SYMBOL*> symbols;
1118 std::vector<SCH_ITEM*> other;
1119
1120 for( SCH_ITEM* item : Items() )
1121 {
1122 if( item->IsMoving() )
1123 continue;
1124
1125 if( item->Type() == SCH_JUNCTION_T )
1126 junctions.push_back( item );
1127 else if( item->Type() == SCH_BITMAP_T )
1128 bitmaps.push_back( item );
1129 else
1130 other.push_back( item );
1131
1132 // Where the symbols overlap each other, we need to plot the text items a second
1133 // time to get them on top of the overlapping element. This collection is in addition
1134 // to the symbols already collected in `other`
1135 if( item->Type() == SCH_SYMBOL_T )
1136 {
1137 for( SCH_ITEM* sym : m_rtree.Overlapping( SCH_SYMBOL_T, item->GetBoundingBox() ) )
1138 {
1139 if( sym != item )
1140 {
1141 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
1142 break;
1143 }
1144 }
1145 }
1146 }
1147
1149 std::sort( other.begin(), other.end(),
1150 []( const SCH_ITEM* a, const SCH_ITEM* b )
1151 {
1152 if( a->Type() == b->Type() )
1153 return a->GetLayer() > b->GetLayer();
1154
1155 return a->Type() > b->Type();
1156 } );
1157
1158 int defaultPenWidth = aPlotter->RenderSettings()->GetDefaultPenWidth();
1159 constexpr bool background = true;
1160
1161 // Bitmaps are drawn first to ensure they are in the background
1162 // This is particularly important for the wxPostscriptDC (used in *nix printers) as
1163 // the bitmap PS command clears the screen
1164 for( const SCH_ITEM* item : bitmaps )
1165 {
1166 aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
1167 item->Plot( aPlotter, background );
1168 }
1169
1170 for( const SCH_ITEM* item : other )
1171 {
1172 aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
1173 item->Plot( aPlotter, background );
1174 }
1175
1176 for( const SCH_ITEM* item : other )
1177 {
1178 aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
1179 item->Plot( aPlotter, !background );
1180 }
1181
1182 // After plotting the symbols as a group above (in `other`), we need to overplot the pins
1183 // and symbols to ensure that they are always visible
1184 for( const SCH_SYMBOL* sym :symbols )
1185 {
1186 aPlotter->SetCurrentLineWidth( std::max( sym->GetPenWidth(), defaultPenWidth ) );
1187
1188 for( SCH_FIELD field : sym->GetFields() )
1189 field.Plot( aPlotter, false );
1190
1191 sym->PlotPins( aPlotter );
1192
1193 if( sym->GetDNP() )
1194 sym->PlotDNP( aPlotter );
1195 }
1196
1197 for( const SCH_ITEM* item : junctions )
1198 {
1199 aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
1200 item->Plot( aPlotter, !background );
1201 }
1202}
1203
1204
1206{
1207 for( SCH_ITEM* item : Items() )
1208 item->ClearTempFlags();
1209}
1210
1211
1212LIB_PIN* SCH_SCREEN::GetPin( const VECTOR2I& aPosition, SCH_SYMBOL** aSymbol,
1213 bool aEndPointOnly ) const
1214{
1215 SCH_SYMBOL* candidate = nullptr;
1216 LIB_PIN* pin = nullptr;
1217
1218 for( SCH_ITEM* item : Items().Overlapping( SCH_SYMBOL_T, aPosition ) )
1219 {
1220 candidate = static_cast<SCH_SYMBOL*>( item );
1221
1222 if( aEndPointOnly )
1223 {
1224 pin = nullptr;
1225
1226 if( !candidate->GetLibSymbolRef() )
1227 continue;
1228
1229 std::vector<LIB_PIN*> pins;
1230 candidate->GetLibPins( pins );
1231
1232 for( LIB_PIN* test_pin : pins )
1233 {
1234 if( candidate->GetPinPhysicalPosition( test_pin ) == aPosition )
1235 {
1236 pin = test_pin;
1237 break;
1238 }
1239 }
1240
1241 if( pin )
1242 break;
1243 }
1244 else
1245 {
1246 pin = (LIB_PIN*) candidate->GetDrawItem( aPosition, LIB_PIN_T );
1247
1248 if( pin )
1249 break;
1250 }
1251 }
1252
1253 if( pin && aSymbol )
1254 *aSymbol = candidate;
1255
1256 return pin;
1257}
1258
1259
1261{
1262 SCH_SHEET_PIN* sheetPin = nullptr;
1263
1264 for( SCH_ITEM* item : Items().Overlapping( SCH_SHEET_T, aPosition ) )
1265 {
1266 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1267
1268 sheetPin = sheet->GetPin( aPosition );
1269
1270 if( sheetPin )
1271 break;
1272 }
1273
1274 return sheetPin;
1275}
1276
1277
1278size_t SCH_SCREEN::CountConnectedItems( const VECTOR2I& aPos, bool aTestJunctions ) const
1279{
1280 size_t count = 0;
1281
1282 for( const SCH_ITEM* item : Items().Overlapping( aPos ) )
1283 {
1284 if( ( item->Type() != SCH_JUNCTION_T || aTestJunctions ) && item->IsConnected( aPos ) )
1285 count++;
1286 }
1287
1288 return count;
1289}
1290
1291
1292void SCH_SCREEN::ClearAnnotation( SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
1293{
1294
1295 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1296 {
1297 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1298
1299 symbol->ClearAnnotation( aSheetPath, aResetPrefix );
1300 }
1301}
1302
1303
1305{
1306 if( GetClientSheetPaths().size() <= 1 ) // No need for alternate reference
1307 return;
1308
1309 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1310 {
1311 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1312
1313 // Add (when not existing) all sheet path entries
1314 for( const SCH_SHEET_PATH& sheet : GetClientSheetPaths() )
1315 symbol->AddSheetPathReferenceEntryIfMissing( sheet.Path() );
1316 }
1317}
1318
1319
1320void SCH_SCREEN::GetHierarchicalItems( std::vector<SCH_ITEM*>* aItems ) const
1321{
1322 for( SCH_ITEM* item : Items() )
1323 {
1324 if( item->IsType( { SCH_SYMBOL_T, SCH_SHEET_T, SCH_LABEL_LOCATE_ANY_T } ) )
1325 aItems->push_back( item );
1326 }
1327}
1328
1329
1330void SCH_SCREEN::GetSheets( std::vector<SCH_ITEM*>* aItems ) const
1331{
1332 for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
1333 aItems->push_back( item );
1334
1335 std::sort( aItems->begin(), aItems->end(),
1336 []( EDA_ITEM* a, EDA_ITEM* b ) -> bool
1337 {
1338 if( a->GetPosition().x == b->GetPosition().x )
1339 {
1340 // Ensure deterministic sort
1341 if( a->GetPosition().y == b->GetPosition().y )
1342 return a->m_Uuid < b->m_Uuid;
1343
1344 return a->GetPosition().y < b->GetPosition().y;
1345 }
1346 else
1347 {
1348 return a->GetPosition().x < b->GetPosition().x;
1349 }
1350 } );
1351}
1352
1353
1355 std::function<void( SCH_ITEM* )>* aChangedHandler ) const
1356{
1357 PROF_TIMER timer( __FUNCTION__ );
1358
1359 std::vector<DANGLING_END_ITEM> endPoints;
1360
1361 auto getends =
1362 [&]( SCH_ITEM* item )
1363 {
1364 if( item->IsConnectable() )
1365 item->GetEndPoints( endPoints );
1366 };
1367 auto update_state =
1368 [&]( SCH_ITEM* item )
1369 {
1370 if( item->UpdateDanglingState( endPoints, aPath ) )
1371 {
1372 if( aChangedHandler )
1373 (*aChangedHandler)( item );
1374 }
1375 };
1376
1377 for( SCH_ITEM* item : Items() )
1378 {
1379
1380 getends( item );
1381 item->RunOnChildren( getends );
1382 }
1383
1384 for( SCH_ITEM* item : Items() )
1385 {
1386 update_state( item );
1387 item->RunOnChildren( update_state );
1388 }
1389 if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
1390 timer.Show();
1391}
1392
1393
1394SCH_LINE* SCH_SCREEN::GetLine( const VECTOR2I& aPosition, int aAccuracy, int aLayer,
1395 SCH_LINE_TEST_T aSearchType ) const
1396{
1397 // an accuracy of 0 had problems with rounding errors; use at least 1
1398 aAccuracy = std::max( aAccuracy, 1 );
1399
1400 for( SCH_ITEM* item : Items().Overlapping( aPosition, aAccuracy ) )
1401 {
1402 if( item->Type() != SCH_LINE_T )
1403 continue;
1404
1405 if( item->GetLayer() != aLayer )
1406 continue;
1407
1408 if( !item->HitTest( aPosition, aAccuracy ) )
1409 continue;
1410
1411 switch( aSearchType )
1412 {
1413 case ENTIRE_LENGTH_T:
1414 return (SCH_LINE*) item;
1415
1417 if( !( (SCH_LINE*) item )->IsEndPoint( aPosition ) )
1418 return (SCH_LINE*) item;
1419 break;
1420
1421 case END_POINTS_ONLY_T:
1422 if( ( (SCH_LINE*) item )->IsEndPoint( aPosition ) )
1423 return (SCH_LINE*) item;
1424 }
1425 }
1426
1427 return nullptr;
1428}
1429
1430
1431std::vector<SCH_LINE*> SCH_SCREEN::GetBusesAndWires( const VECTOR2I& aPosition,
1432 bool aIgnoreEndpoints ) const
1433{
1434 std::vector<SCH_LINE*> retVal;
1435
1436 for( SCH_ITEM* item : Items().Overlapping( SCH_LINE_T, aPosition ) )
1437 {
1438 if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } ) )
1439 {
1440 SCH_LINE* wire = static_cast<SCH_LINE*>( item );
1441
1442 if( aIgnoreEndpoints && wire->IsEndPoint( aPosition ) )
1443 continue;
1444
1445 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), aPosition ) )
1446 retVal.push_back( wire );
1447 }
1448 }
1449
1450 return retVal;
1451}
1452
1453
1454std::vector<VECTOR2I> SCH_SCREEN::GetConnections() const
1455{
1456 std::vector<VECTOR2I> retval;
1457
1458 for( SCH_ITEM* item : Items() )
1459 {
1460 // Avoid items that are changing
1461 if( !( item->GetEditFlags() & ( IS_MOVING | IS_DELETED ) ) )
1462 {
1463 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1464 retval.insert( retval.end(), pts.begin(), pts.end() );
1465 }
1466 }
1467
1468 // We always have some overlapping connection points. Drop duplicates here
1469 std::sort( retval.begin(), retval.end(),
1470 []( const VECTOR2I& a, const VECTOR2I& b ) -> bool
1471 {
1472 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1473 } );
1474 retval.erase( std::unique( retval.begin(), retval.end() ), retval.end() );
1475
1476 return retval;
1477}
1478
1479
1480std::vector<VECTOR2I> SCH_SCREEN::GetNeededJunctions( const std::deque<EDA_ITEM*>& aItems ) const
1481{
1482 std::vector<VECTOR2I> pts;
1483 std::vector<VECTOR2I> connections = GetConnections();
1484
1485 for( const EDA_ITEM* edaItem : aItems )
1486 {
1487 const SCH_ITEM* item = dynamic_cast<const SCH_ITEM*>( edaItem );
1488
1489 if( !item || !item->IsConnectable() )
1490 continue;
1491
1492 std::vector<VECTOR2I> new_pts = item->GetConnectionPoints();
1493 pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
1494
1495 // If the item is a line, we also add any connection points from the rest of the schematic
1496 // that terminate on the line after it is moved.
1497 if( item->Type() == SCH_LINE_T )
1498 {
1499 SCH_LINE* line = (SCH_LINE*) item;
1500
1501 for( const VECTOR2I& pt : connections )
1502 {
1503 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1504 pts.push_back( pt );
1505 }
1506 }
1507 }
1508
1509 // We always have some overlapping connection points. Drop duplicates here
1510 std::sort( pts.begin(), pts.end(),
1511 []( const VECTOR2I& a, const VECTOR2I& b ) -> bool
1512 {
1513 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1514 } );
1515
1516 pts.erase( unique( pts.begin(), pts.end() ), pts.end() );
1517
1518 // We only want the needed junction points, remove all the others
1519 pts.erase( std::remove_if( pts.begin(), pts.end(),
1520 [this]( const VECTOR2I& a ) -> bool
1521 {
1522 return !IsExplicitJunctionNeeded( a );
1523 } ),
1524 pts.end() );
1525
1526 return pts;
1527}
1528
1529
1530SCH_LABEL_BASE* SCH_SCREEN::GetLabel( const VECTOR2I& aPosition, int aAccuracy ) const
1531{
1532 for( SCH_ITEM* item : Items().Overlapping( aPosition, aAccuracy ) )
1533 {
1534 switch( item->Type() )
1535 {
1536 case SCH_LABEL_T:
1537 case SCH_GLOBAL_LABEL_T:
1538 case SCH_HIER_LABEL_T:
1540 if( item->HitTest( aPosition, aAccuracy ) )
1541 return static_cast<SCH_LABEL_BASE*>( item );
1542
1543 break;
1544
1545 default:
1546 ;
1547 }
1548 }
1549
1550 return nullptr;
1551}
1552
1553
1555{
1556 wxCHECK( aLibSymbol, /* void */ );
1557
1558 wxString libSymbolName = aLibSymbol->GetLibId().Format().wx_str();
1559
1560 auto it = m_libSymbols.find( libSymbolName );
1561
1562 if( it != m_libSymbols.end() )
1563 {
1564 delete it->second;
1565 m_libSymbols.erase( it );
1566 }
1567
1568 m_libSymbols[libSymbolName] = aLibSymbol;
1569}
1570
1571
1572void SCH_SCREEN::AddBusAlias( std::shared_ptr<BUS_ALIAS> aAlias )
1573{
1574 m_aliases.insert( aAlias );
1575}
1576
1577
1579{
1580 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1581 {
1582 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1583
1584 // Add missing value and footprint instance data for legacy schematics.
1585 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstanceReferences() )
1586 {
1587 symbol->AddHierarchicalReference( instance.m_Path, instance.m_Reference,
1588 instance.m_Unit );
1589 }
1590 }
1591}
1592
1593
1595{
1596 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
1597 {
1598 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1599
1600 // Fix pre-8.0 legacy power symbols with invisible pins
1601 // that have mismatched pin names and value fields
1602 if( symbol->GetLibSymbolRef()
1603 && symbol->GetLibSymbolRef()->IsPower()
1604 && symbol->GetAllLibPins().size() > 0
1605 && symbol->GetAllLibPins()[0]->IsGlobalPower()
1606 && !symbol->GetAllLibPins()[0]->IsVisible() )
1607 {
1608 symbol->SetValueFieldText( symbol->GetAllLibPins()[0]->GetName() );
1609 }
1610 }
1611}
1612
1613
1615 std::vector<wxString>& aMatches )
1616{
1617 wxString searchName = aSymbol.GetLibId().GetUniStringLibId();
1618
1619 if( m_libSymbols.find( searchName ) != m_libSymbols.end() )
1620 aMatches.emplace_back( searchName );
1621
1622 searchName = aSymbol.GetLibId().GetUniStringLibItemName() + wxS( "_" );
1623
1624 long tmp;
1625 wxString suffix;
1626
1627 for( auto& pair : m_libSymbols )
1628 {
1629 if( pair.first.StartsWith( searchName, &suffix ) && suffix.ToLong( &tmp ) )
1630 aMatches.emplace_back( pair.first );
1631 }
1632
1633 return aMatches.size();
1634}
1635
1636
1637#if defined(DEBUG)
1638void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
1639{
1640 // for now, make it look like XML, expand on this later.
1641 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n";
1642
1643 for( const SCH_ITEM* item : Items() )
1644 item->Show( nestLevel + 1, os );
1645
1646 NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
1647}
1648#endif
1649
1650
1652{
1653 m_index = 0;
1654 buildScreenList( aSheet );
1655}
1656
1657
1659{
1660}
1661
1662
1664{
1665 m_index = 0;
1666
1667 if( m_screens.size() > 0 )
1668 return m_screens[0];
1669
1670 return nullptr;
1671}
1672
1673
1675{
1676 if( m_index < m_screens.size() )
1677 m_index++;
1678
1679 return GetScreen( m_index );
1680}
1681
1682
1683SCH_SCREEN* SCH_SCREENS::GetScreen( unsigned int aIndex ) const
1684{
1685 if( aIndex < m_screens.size() )
1686 return m_screens[ aIndex ];
1687
1688 return nullptr;
1689}
1690
1691
1692SCH_SHEET* SCH_SCREENS::GetSheet( unsigned int aIndex ) const
1693{
1694 if( aIndex < m_sheets.size() )
1695 return m_sheets[ aIndex ];
1696
1697 return nullptr;
1698}
1699
1700
1702{
1703 if( aScreen == nullptr )
1704 return;
1705
1706 for( const SCH_SCREEN* screen : m_screens )
1707 {
1708 if( screen == aScreen )
1709 return;
1710 }
1711
1712 m_screens.push_back( aScreen );
1713 m_sheets.push_back( aSheet );
1714}
1715
1716
1718{
1719 if( aSheet && aSheet->Type() == SCH_SHEET_T )
1720 {
1721 SCH_SCREEN* screen = aSheet->GetScreen();
1722
1723 wxCHECK_RET( screen, "No screen for aSheet" );
1724
1725 addScreenToList( screen, aSheet );
1726
1727 for( SCH_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
1728 buildScreenList( static_cast<SCH_SHEET*>( item ) );
1729 }
1730}
1731
1732
1734{
1735 SCH_SCREEN* first = GetFirst();
1736
1737 if( !first )
1738 return;
1739
1740 SCHEMATIC* sch = first->Schematic();
1741
1742 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::ClearAnnotationOfNewSheetPaths" );
1743
1744 // Clear the annotation for symbols inside new sheetpaths not already in aInitialSheetList
1745 SCH_SCREENS screensList( sch->Root() ); // The list of screens, shared by sheet paths
1746 screensList.BuildClientSheetPathList(); // build the shared by sheet paths, by screen
1747
1748 // Search for new sheet paths, not existing in aInitialSheetPathList
1749 // and existing in sheetpathList
1750 for( SCH_SHEET_PATH& sheetpath : sch->GetSheets() )
1751 {
1752 bool path_exists = false;
1753
1754 for( const SCH_SHEET_PATH& existing_sheetpath: aInitialSheetPathList )
1755 {
1756 if( existing_sheetpath.Path() == sheetpath.Path() )
1757 {
1758 path_exists = true;
1759 break;
1760 }
1761 }
1762
1763 if( !path_exists )
1764 {
1765 // A new sheet path is found: clear the annotation corresponding to this new path:
1766 SCH_SCREEN* curr_screen = sheetpath.LastScreen();
1767
1768 // Clear annotation and create the AR for this path, if not exists,
1769 // when the screen is shared by sheet paths.
1770 // Otherwise ClearAnnotation do nothing, because the F1 field is used as
1771 // reference default value and takes the latest displayed value
1772 curr_screen->EnsureAlternateReferencesExist();
1773 curr_screen->ClearAnnotation( &sheetpath, false );
1774 }
1775 }
1776}
1777
1778
1780{
1781 std::vector<SCH_ITEM*> items;
1782 int count = 0;
1783
1784 auto timestamp_cmp = []( const EDA_ITEM* a, const EDA_ITEM* b ) -> bool
1785 {
1786 return a->m_Uuid < b->m_Uuid;
1787 };
1788
1789 std::set<EDA_ITEM*, decltype( timestamp_cmp )> unique_stamps( timestamp_cmp );
1790
1791 for( SCH_SCREEN* screen : m_screens )
1792 screen->GetHierarchicalItems( &items );
1793
1794 if( items.size() < 2 )
1795 return 0;
1796
1797 for( EDA_ITEM* item : items )
1798 {
1799 if( !unique_stamps.insert( item ).second )
1800 {
1801 // Reset to fully random UUID. This may lose reference, but better to be
1802 // deterministic about it rather than to have duplicate UUIDs with random
1803 // side-effects.
1804 const_cast<KIID&>( item->m_Uuid ) = KIID();
1805 count++;
1806
1807 // @todo If the item is a sheet, we need to decend the heirarchy from the sheet
1808 // and repace all instances of the changed UUID in sheet paths. Otherwise,
1809 // all instance paths with the sheet's UUID will get clobbered.
1810 }
1811 }
1812
1813 return count;
1814}
1815
1816
1818{
1819 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
1820 {
1821 for( SCH_ITEM* item : screen->Items() )
1822 item->ClearEditFlags();
1823 }
1824}
1825
1826
1828{
1829 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
1830 {
1831 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
1832 {
1833 if( item == aMarker )
1834 {
1835 screen->DeleteItem( item );
1836 return;
1837 }
1838 }
1839 }
1840}
1841
1842
1843void SCH_SCREENS::DeleteMarkers( enum MARKER_BASE::TYPEMARKER aMarkerType, int aErrorCode,
1844 bool aIncludeExclusions )
1845{
1846 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
1847 {
1848 std::vector<SCH_ITEM*> markers;
1849
1850 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
1851 {
1852 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
1853 std::shared_ptr<RC_ITEM>rcItem = marker->GetRCItem();
1854
1855 if( marker->GetMarkerType() == aMarkerType
1856 && ( aErrorCode == ERCE_UNSPECIFIED || rcItem->GetErrorCode() == aErrorCode )
1857 && ( !marker->IsExcluded() || aIncludeExclusions ) )
1858 {
1859 markers.push_back( item );
1860 }
1861 }
1862
1863 for( SCH_ITEM* marker : markers )
1864 screen->DeleteItem( marker );
1865 }
1866}
1867
1868
1870 bool aIncludeExclusions )
1871{
1872 DeleteMarkers( aMarkerType, ERCE_UNSPECIFIED, aIncludeExclusions );
1873}
1874
1875
1877{
1878 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
1879 screen->UpdateSymbolLinks( aReporter );
1880
1881 SCH_SCREEN* first = GetFirst();
1882
1883 if( !first )
1884 return;
1885
1886 SCHEMATIC* sch = first->Schematic();
1887
1888 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::UpdateSymbolLinks" );
1889
1890 SCH_SHEET_LIST sheets = sch->GetSheets();
1891
1892 // All of the library symbols have been replaced with copies so the connection graph
1893 // pointers are stale.
1894 if( sch->ConnectionGraph() )
1895 sch->ConnectionGraph()->Recalculate( sheets, true );
1896}
1897
1898
1900{
1901 bool has_symbols = false;
1902
1903 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
1904 {
1905 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
1906 {
1907 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1908 has_symbols = true;
1909
1910 if( !symbol->GetLibId().GetLibNickname().empty() )
1911 return false;
1912 }
1913 }
1914
1915 // return true (i.e. has no fully defined symbol) only if at least one symbol is found
1916 return has_symbols ? true : false;
1917}
1918
1919
1920size_t SCH_SCREENS::GetLibNicknames( wxArrayString& aLibNicknames )
1921{
1922 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
1923 {
1924 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
1925 {
1926 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1927 const UTF8& nickname = symbol->GetLibId().GetLibNickname();
1928
1929 if( !nickname.empty() && ( aLibNicknames.Index( nickname ) == wxNOT_FOUND ) )
1930 aLibNicknames.Add( nickname );
1931 }
1932 }
1933
1934 return aLibNicknames.GetCount();
1935}
1936
1937
1938int SCH_SCREENS::ChangeSymbolLibNickname( const wxString& aFrom, const wxString& aTo )
1939{
1940 SCH_SCREEN* screen;
1941 int cnt = 0;
1942
1943 for( screen = GetFirst(); screen; screen = GetNext() )
1944 {
1945 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
1946 {
1947 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1948
1949 if( symbol->GetLibId().GetLibNickname() != aFrom )
1950 continue;
1951
1952 LIB_ID id = symbol->GetLibId();
1953 id.SetLibNickname( aTo );
1954 symbol->SetLibId( id );
1955 cnt++;
1956 }
1957 }
1958
1959 return cnt;
1960}
1961
1962
1963bool SCH_SCREENS::HasSchematic( const wxString& aSchematicFileName )
1964{
1965 for( const SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
1966 {
1967 if( screen->GetFileName() == aSchematicFileName )
1968 return true;
1969 }
1970
1971 return false;
1972}
1973
1974
1975bool SCH_SCREENS::CanCauseCaseSensitivityIssue( const wxString& aSchematicFileName ) const
1976{
1977 wxString lhsLower;
1978 wxString rhsLower;
1979 wxFileName lhs;
1980 wxFileName rhs = aSchematicFileName;
1981
1982 wxCHECK( rhs.IsAbsolute(), false );
1983
1984 for( const SCH_SCREEN* screen : m_screens )
1985 {
1986 lhs = screen->GetFileName();
1987
1988 if( lhs.GetPath() != rhs.GetPath() )
1989 continue;
1990
1991 lhsLower = lhs.GetFullName().Lower();
1992 rhsLower = rhs.GetFullName().Lower();
1993
1994 if( lhsLower == rhsLower && lhs.GetFullName() != rhs.GetFullName() )
1995 return true;
1996 }
1997
1998 return false;
1999}
2000
2001
2003{
2004 SCH_SCREEN* first = GetFirst();
2005
2006 if( !first )
2007 return;
2008
2009 SCHEMATIC* sch = first->Schematic();
2010
2011 wxCHECK_RET( sch, "Null schematic in SCH_SCREENS::BuildClientSheetPathList" );
2012
2013 for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
2014 curr_screen->GetClientSheetPaths().clear();
2015
2016 for( SCH_SHEET_PATH& sheetpath : sch->GetSheets() )
2017 {
2018 SCH_SCREEN* used_screen = sheetpath.LastScreen();
2019
2020 // Search for the used_screen in list and add this unique sheet path:
2021 for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
2022 {
2023 if( used_screen == curr_screen )
2024 {
2025 curr_screen->GetClientSheetPaths().push_back( sheetpath );
2026 break;
2027 }
2028 }
2029 }
2030}
2031
2032
2034{
2035 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2036 screen->SetLegacySymbolInstanceData();
2037}
2038
2039
2041{
2042 for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
2043 screen->FixLegacyPowerSymbolMismatches();
2044}
2045
2046
2048{
2049 LOCALE_IO toggle;
2050
2051 // V6 schematics may specify model names in Value fields, which we don't do in V7.
2052 // Migrate by adding an equivalent model for these symbols.
2053
2054 for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
2055 {
2056 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2057 SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( *symbol, &Schematic()->Prj() );
2058 }
2059}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
Handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:41
int m_virtualPageNumber
An integer based page number used for printing a range of pages.
Definition: base_screen.h:119
bool m_Center
Center on screen.
Definition: base_screen.h:96
int m_pageCount
The number of BASE_SCREEN objects in this design.
Definition: base_screen.h:111
void SetContentModified(bool aModified=true)
Definition: base_screen.h:59
void InitDataPoints(const VECTOR2I &aPageSizeInternalUnits)
Definition: base_screen.cpp:46
void SetOrigin(const Vec &pos)
Definition: box2.h:203
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:507
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr)
Updates the connection graph for the given list of sheets.
EDA_ANGLE Normalize90()
Definition: eda_angle.h:277
double AsDegrees() const
Definition: eda_angle.h:149
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
const KIID m_Uuid
Definition: eda_item.h:482
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
bool IsSelected() const
Definition: eda_item.h:106
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
EDA_ITEM * GetParent() const
Definition: eda_item.h:99
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:127
bool IsNew() const
Definition: eda_item.h:103
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
bool remove(SCH_ITEM *aItem)
Remove an item from the tree.
Definition: sch_rtree.h:78
void insert(SCH_ITEM *aItem)
Insert an item into the tree.
Definition: sch_rtree.h:59
bool contains(const SCH_ITEM *aItem, bool aRobust=false) const
Determine if a given item exists in the tree.
Definition: sch_rtree.h:125
iterator end()
Returns a read/write iterator that points to one past the last element in the EE_RTREE.
Definition: sch_rtree.h:285
iterator begin()
Returns a read/write iterator that points to the first element in the EE_RTREE N.B.
Definition: sch_rtree.h:276
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
void clear()
Remove all items from the RTree.
Definition: sch_rtree.h:111
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
int GetDefaultPenWidth() const
Definition: kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
wxString GetUniStringLibId() const
Definition: lib_id.h:148
UTF8 Format() const
Definition: lib_id.cpp:118
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition: lib_id.h:112
int SetLibNickname(const UTF8 &aNickname)
Override the logical library name portion of the LIB_ID to aNickname.
Definition: lib_id.cpp:99
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:87
Define a library symbol object.
Definition: lib_symbol.h:99
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:546
LIB_ID GetLibId() const override
Definition: lib_symbol.h:163
wxString GetName() const override
Definition: lib_symbol.h:160
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Definition: lib_symbol.cpp:615
void SetLibId(const LIB_ID &aLibId)
Definition: lib_symbol.h:164
virtual void SetName(const wxString &aName)
Definition: lib_symbol.cpp:599
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
bool IsExcluded() const
Definition: marker_base.h:97
std::shared_ptr< RC_ITEM > GetRCItem() const
Definition: marker_base.h:105
enum TYPEMARKER GetMarkerType() const
Definition: marker_base.h:95
void sort()
Definition: multivector.h:248
const VECTOR2I GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition: page_info.h:161
Base plotter engine class.
Definition: plotter.h:104
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:135
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:47
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition: profile.h:103
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
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:99
Holds all the data relating to one schematic.
Definition: schematic.h:75
CONNECTION_GRAPH * ConnectionGraph() const override
Definition: schematic.h:146
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:100
SCH_SHEET & Root() const
Definition: schematic.h:105
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:90
Class for a wire to bus entry.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:52
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:150
virtual bool IsConnectable() const
Definition: sch_item.h:362
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:257
bool IsConnected(const VECTOR2I &aPoint) const
Test the item to see if it is connected to aPoint.
Definition: sch_item.cpp:138
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:377
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: sch_line.cpp:806
int GetAngleFrom(const VECTOR2I &aPoint) const
Definition: sch_line.cpp:431
EDA_ANGLE Angle() const
Gets the angle between the start and end lines.
Definition: sch_line.h:107
VECTOR2I GetEndPoint() const
Definition: sch_line.h:145
VECTOR2I GetStartPoint() const
Definition: sch_line.h:140
bool IsEndPoint(const VECTOR2I &aPoint) const
Definition: sch_line.h:94
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:673
SCH_SCREEN * GetNext()
unsigned int m_index
Definition: sch_screen.h:814
std::vector< SCH_SHEET * > m_sheets
Definition: sch_screen.h:813
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 buildScreenList(SCH_SHEET *aSheet)
void DeleteMarkers(enum MARKER_BASE::TYPEMARKER aMarkerTyp, int aErrorCode, bool aIncludeExclusions=true)
Delete all markers of a particular type and error code.
void FixLegacyPowerSymbolMismatches()
Fix legacy power symbols that have mismatched value text fields and invisible power pin names.
SCH_SCREEN * GetFirst()
int ChangeSymbolLibNickname(const wxString &aFrom, const wxString &aTo)
Change all of the symbol library nicknames.
SCH_SCREENS(SCH_SHEET *aSheet)
void BuildClientSheetPathList()
built the list of sheet paths sharing a screen for each screen in use
void ClearAnnotationOfNewSheetPaths(SCH_SHEET_LIST &aInitialSheetPathList)
Clear the annotation for the symbols inside new sheetpaths when a complex hierarchy is modified and n...
bool CanCauseCaseSensitivityIssue(const wxString &aSchematicFileName) const
Check aSchematicFileName for a potential file name case sensitivity issue.
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...
void DeleteAllMarkers(enum MARKER_BASE::TYPEMARKER aMarkerType, bool aIncludeExclusions)
Delete all electronic rules check markers of aMarkerType from all the screens in the list.
std::vector< SCH_SCREEN * > m_screens
Definition: sch_screen.h:812
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::map< wxString, LIB_SYMBOL * > m_libSymbols
Library symbols required for this schematic.
Definition: sch_screen.h:634
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)
Definition: sch_screen.cpp:151
void AddLibSymbol(LIB_SYMBOL *aLibSymbol)
Add aLibSymbol to the library symbol map.
void AddBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
Add a bus alias definition (and transfers ownership of the pointer).
void FixLegacyPowerSymbolMismatches()
Fix legacy power symbols that have mismatched value text fields and invisible power pin names.
bool HasItems(KICAD_T aItemType) const
Definition: sch_screen.cpp:137
void Clear(bool aFree=true)
Delete all draw items and clears the project settings.
Definition: sch_screen.cpp:276
LIB_PIN * GetPin(const VECTOR2I &aPosition, SCH_SYMBOL **aSymbol=nullptr, bool aEndPointOnly=false) const
Test the screen for a symbol pin item at aPosition.
std::vector< SCH_SHEET_PATH > & GetClientSheetPaths()
Return the number of times this screen is used.
Definition: sch_screen.h:178
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in this schematic from the project SYMB...
Definition: sch_screen.cpp:881
SCH_LINE * GetWire(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition: sch_screen.h:429
int m_refCount
Definition: sch_screen.h:602
TITLE_BLOCK m_titles
Definition: sch_screen.h:615
void TestDanglingEnds(const SCH_SHEET_PATH *aPath=nullptr, std::function< void(SCH_ITEM *)> *aChangedHandler=nullptr) const
Test all of the connectable objects in the schematic for unused connection points.
void EnsureAlternateReferencesExist()
For screens shared by many sheetpaths (complex hierarchies): to be able to clear or modify any refere...
std::vector< SCH_LINE * > GetBusesAndWires(const VECTOR2I &aPosition, bool aIgnoreEndpoints=false) const
Return buses and wires passing through aPosition.
int m_modification_sync
Definition: sch_screen.h:619
double m_LastZoomLevel
last value for the zoom level, useful in Eeschema when changing the current displayed sheet to reuse ...
Definition: sch_screen.h:597
bool IsExplicitJunction(const VECTOR2I &aPosition) const
Indicates that a junction dot is necessary at the given location.
Definition: sch_screen.cpp:487
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
void Print(const RENDER_SETTINGS *aSettings)
Print all the items in the screen to aDC.
void DecRefCount()
Definition: sch_screen.cpp:130
std::set< SCH_ITEM * > MarkConnections(SCH_LINE *aSegment, bool aSecondPass)
Return all wires and junctions connected to aSegment which are not connected any symbol pin.
Definition: sch_screen.cpp:406
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.
Definition: sch_screen.cpp:390
bool IsExplicitJunctionAllowed(const VECTOR2I &aPosition) const
Indicates that a juction dot may be placed at the given location.
Definition: sch_screen.cpp:704
void clearLibSymbols()
Definition: sch_screen.cpp:107
wxString m_fileName
Definition: sch_screen.h:600
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:816
void UpdateLocalLibSymbolLinks()
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in this schematic with the local projec...
void IncRefCount()
Definition: sch_screen.cpp:124
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:116
static bool ClassOf(const EDA_ITEM *aItem)
Definition: sch_screen.cpp:145
void SetLegacySymbolInstanceData()
Update the symbol value and footprint instance data for legacy designs.
SCH_LINE * GetBus(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition: sch_screen.h:435
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:321
SCH_SCREEN(EDA_ITEM *aParent=nullptr)
Definition: sch_screen.cpp:72
SCHEMATIC * Schematic() const
Definition: sch_screen.cpp:98
EE_RTREE m_rtree
Definition: sch_screen.h:617
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
Indicates that a junction dot is necessary at the given location, and does not yet exist.
Definition: sch_screen.cpp:497
SCH_SHEET_PIN * GetSheetPin(const VECTOR2I &aPosition) const
Test the screen if aPosition is a sheet label object.
void Plot(PLOTTER *aPlotter) const
Plot all the schematic objects to aPlotter.
void FreeDrawList()
Free all the items from the schematic associated with the screen.
Definition: sch_screen.cpp:295
virtual wxString GetClass() const override
Return the class name.
Definition: sch_screen.h:123
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
Definition: sch_screen.cpp:314
void SetConnectivityDirty()
bool m_zoomInitialized
Definition: sch_screen.h:622
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:614
bool IsJunction(const VECTOR2I &aPosition) const
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:477
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
Definition: sch_screen.cpp:384
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
Definition: sch_screen.cpp:506
void ClearAnnotation(SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear the annotation for the symbols in aSheetPath on the screen.
bool doIsJunction(const VECTOR2I &aPosition, bool aBreakCrossings, bool *aHasExplicitJunctionDot, bool *aHasBusEntry) const
Definition: sch_screen.cpp:715
size_t CountConnectedItems(const VECTOR2I &aPos, bool aTestJunctions) const
void MigrateSimModels()
Migrate any symbols having V6 simulation models to their V7 equivalents.
void DeleteItem(SCH_ITEM *aItem)
Removes aItem from the linked list and deletes the object.
Definition: sch_screen.cpp:359
std::set< std::shared_ptr< BUS_ALIAS >, BusAliasCmp > m_aliases
List of bus aliases stored in this screen.
Definition: sch_screen.h:631
size_t getLibSymbolNameMatches(const SCH_SYMBOL &aSymbol, std::vector< wxString > &aMatches)
Return a list of potential library symbol matches for aSymbol.
SCH_LABEL_BASE * GetLabel(const VECTOR2I &aPosition, int aAccuracy=0) const
Return a label item located at aPosition.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
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.
Definition: sch_sheet_pin.h:66
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:57
SCH_SHEET_PIN * GetPin(const VECTOR2I &aPosition)
Return the sheet pin item found at aPosition in the sheet.
Definition: sch_sheet.cpp:581
void RemovePin(const SCH_SHEET_PIN *aSheetPin)
Remove aSheetPin from the sheet.
Definition: sch_sheet.cpp:379
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
Schematic symbol object.
Definition: sch_symbol.h:81
void GetLibPins(std::vector< LIB_PIN * > &aPinsList) const
Populate a vector with all the pins from the library object.
void SetLibId(const LIB_ID &aName)
Definition: sch_symbol.cpp:287
LIB_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 > & GetInstanceReferences() const
Definition: sch_symbol.h:140
void SetValueFieldText(const wxString &aValue)
Definition: sch_symbol.cpp:836
wxString GetSchSymbolLibraryName() const
Definition: sch_symbol.cpp:293
bool AddSheetPathReferenceEntryIfMissing(const KIID_PATH &aSheetPath)
Add an instance to the alternate references list (m_instanceReferences), if this entry does not alrea...
VECTOR2I GetPinPhysicalPosition(const LIB_PIN *Pin) const
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
Definition: sch_symbol.cpp:563
void SetSchSymbolLibraryName(const wxString &aName)
The name of the symbol in the schematic library symbol list.
Definition: sch_symbol.h:186
int GetOrientation() const
Get the display symbol orientation.
const LIB_ID & GetLibId() const
Definition: sch_symbol.h:173
std::vector< LIB_PIN * > GetAllLibPins() const
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:190
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
Definition: sch_symbol.cpp:302
A collection of SYMBOL_LIB objects.
int GetLibraryCount()
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
Object used to load, save, search, and otherwise manipulate symbol library files.
bool IsCache() const
LIB_SYMBOL * FindSymbol(const wxString &aName) const
Find LIB_SYMBOL by aName.
void Clear()
Definition: title_block.h:113
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:71
bool empty() const
Definition: utf8.h:103
wxString wx_str() const
Definition: utf8.cpp:45
static const wxChar DanglingProfileMask[]
#define _(s)
#define IS_DELETED
#define STRUCT_DELETED
flag indication structures to be erased
#define IS_MOVING
Item being moved.
@ ERCE_UNSPECIFIED
Definition: erc_settings.h:38
PROJECT & Prj()
Definition: kicad.cpp:571
@ LAYER_WIRE
Definition: layer_ids.h:349
@ LAYER_NOTES
Definition: layer_ids.h:363
@ LAYER_BUS
Definition: layer_ids.h:350
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
SYMBOL_ORIENTATION_T
enum used in RotationMiroir()
@ SYM_ORIENT_270
@ SYM_ROTATE_CLOCKWISE
@ SYM_ROTATE_COUNTERCLOCKWISE
@ SYM_MIRROR_Y
@ SYM_ORIENT_180
@ SYM_MIRROR_X
@ SYM_NORMAL
@ SYM_ORIENT_90
@ SYM_ORIENT_0
static const wxChar DanglingProfileMask[]
Definition: sch_screen.cpp:70
#define PROCESSED
SCH_LINE_TEST_T
Definition: sch_screen.h:71
@ ENTIRE_LENGTH_T
Definition: sch_screen.h:72
@ EXCLUDE_END_POINTS_T
Definition: sch_screen.h:74
@ END_POINTS_ONLY_T
Definition: sch_screen.h:73
wxString UnescapeString(const wxString &aSource)
const double IU_PER_MILS
Definition: base_units.h:78
The EE_TYPE struct provides a type-specific auto-range iterator to the RTree.
Definition: sch_rtree.h:192
iterator begin()
Definition: sch_rtree.h:222
iterator end()
Definition: sch_rtree.h:227
A simple container for schematic symbol instance information.
Definition for symbol library class.
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
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:42
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ SCH_LINE_T
Definition: typeinfo.h:145
@ SCH_SYMBOL_T
Definition: typeinfo.h:155
@ SCH_FIELD_T
Definition: typeinfo.h:154
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:153
@ SCH_LABEL_T
Definition: typeinfo.h:150
@ SCH_SHEET_T
Definition: typeinfo.h:157
@ SCH_MARKER_T
Definition: typeinfo.h:140
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:152
@ LIB_PIN_T
Definition: typeinfo.h:201
@ SCH_SCREEN_T
Definition: typeinfo.h:185
@ SCHEMATIC_T
Definition: typeinfo.h:187
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:156
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:143
@ SCH_BITMAP_T
Definition: typeinfo.h:147
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:151
@ SCH_JUNCTION_T
Definition: typeinfo.h:141
@ SCH_PIN_T
Definition: typeinfo.h:158
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588