KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_reference_list.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) 1992-2018 jean-pierre Charras <jp.charras at wanadoo.fr>
5 * Copyright (C) 1992-2011 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
26
27#include <sch_reference_list.h>
28#include <core/kicad_algo.h>
29
30#include <wx/regex.h>
31#include <algorithm>
32#include <vector>
33#include <unordered_set>
34
35#include <string_utils.h>
36#include <erc/erc_settings.h>
37#include <refdes_tracker.h>
38#include <sch_symbol.h>
39#include <sch_edit_frame.h>
40
41
42void SCH_REFERENCE_LIST::RemoveItem( unsigned int aIndex )
43{
44 if( aIndex < m_flatList.size() )
45 m_flatList.erase( m_flatList.begin() + aIndex );
46}
47
48
50{
51 for( unsigned ii = 0; ii < GetCount(); ii++ )
52 {
53 if( m_flatList[ii].IsSameInstance( aItem ) )
54 return true;
55 }
56
57 return false;
58}
59
60
62{
63 for( unsigned ii = 0; ii < GetCount(); ii++ )
64 {
65 if( m_flatList[ii].IsSameInstance( aItem ) )
66 return &m_flatList[ii];
67 }
68
69 return nullptr;
70}
71
72
74{
75 int ii = item1.CompareRef( item2 );
76
77 if( ii == 0 )
78 ii = item1.m_sheetNum - item2.m_sheetNum;
79
80 if( ii == 0 )
81 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
82
83 if( ii == 0 )
84 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
85
86 if( ii == 0 )
87 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
88 else
89 return ii < 0;
90}
91
92
94{
95 int ii = item1.CompareRef( item2 );
96
97 if( ii == 0 )
98 ii = item1.m_sheetNum - item2.m_sheetNum;
99
100 if( ii == 0 )
101 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
102
103 if( ii == 0 )
104 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
105
106 if( ii == 0 )
107 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
108 else
109 return ii < 0;
110}
111
112
114 const SCH_REFERENCE& item2 )
115{
116 int ii = item1.CompareRef( item2 );
117
118 if( ii == 0 )
119 ii = item1.CompareValue( item2 );
120
121 if( ii == 0 )
122 ii = item1.m_unit - item2.m_unit;
123
124 if( ii == 0 )
125 ii = item1.m_sheetNum - item2.m_sheetNum;
126
127 if( ii == 0 )
128 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
129
130 if( ii == 0 )
131 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
132
133 if( ii == 0 )
134 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
135 else
136 return ii < 0;
137}
138
139
141 const SCH_REFERENCE& item2 )
142{
143 int ii = StrNumCmp( item1.GetRef(), item2.GetRef(), false );
144
145 if( ii == 0 )
146 ii = item1.m_unit - item2.m_unit;
147
148 if( ii == 0 )
149 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
150 else
151 return ii < 0;
152}
153
154
156 const SCH_REFERENCE& item2 )
157{
158 int ii = item1.m_sheetPath.Cmp( item2.m_sheetPath );
159
160 if( ii == 0 )
161 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
162 else
163 return ii < 0;
164}
165
166
168{
169 return item1.m_rootSymbol < item2.m_rootSymbol;
170}
171
172
173int SCH_REFERENCE_LIST::FindRefByFullPath( const wxString& aFullPath ) const
174{
175 for( size_t i = 0; i < m_flatList.size(); ++i )
176 {
177 if( m_flatList[i].GetFullPath() == aFullPath )
178 return i;
179 }
180
181 return -1;
182}
183
184
185int SCH_REFERENCE_LIST::FindRef( const wxString& aRef ) const
186{
187 for( size_t i = 0; i < m_flatList.size(); ++i )
188 {
189 if( m_flatList[i].GetRef() == aRef )
190 return i;
191 }
192
193 return -1;
194}
195
196
197void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList,
198 int aMinRefId ) const
199{
200 aIdList.clear();
201
202 for( const SCH_REFERENCE& ref : m_flatList )
203 {
204 // Don't add new references to the list as we will reannotate those
205 if( m_flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId && !ref.m_isNew )
206 aIdList.push_back( ref.m_numRef );
207 }
208
209 std::sort( aIdList.begin(), aIdList.end() );
210
211 // Ensure each reference number appears only once. If there are symbols with
212 // multiple parts per package the same number will be stored for each part.
213 alg::remove_duplicates( aIdList );
214}
215
216
217std::vector<int> SCH_REFERENCE_LIST::GetUnitsMatchingRef( const SCH_REFERENCE& aRef ) const
218{
219 std::vector<int> unitsList;
220
221 // Always add this reference to the list
222 unitsList.push_back( aRef.m_unit );
223
224 for( SCH_REFERENCE ref : m_flatList )
225 {
226 if( ref.CompareValue( aRef ) != 0 )
227 continue;
228
229 if( ref.CompareLibName( aRef ) != 0 )
230 continue;
231
232 // Split if needed before comparing ref and number
233 if( ref.IsSplitNeeded() )
234 ref.Split();
235
236 if( ref.CompareRef( aRef ) != 0 )
237 continue;
238
239 if( ref.m_numRef != aRef.m_numRef )
240 continue;
241
242 unitsList.push_back( ref.m_unit );
243 }
244
245 std::sort( unitsList.begin(), unitsList.end() );
246
247 // Ensure each reference number appears only once. If there are symbols with
248 // multiple parts per package the same number will be stored for each part.
249 alg::remove_duplicates( unitsList );
250
251 return unitsList;
252}
253
254
256 const std::vector<int>& aRequiredUnits ) const
257{
258 // Create a map of references indexed by reference number, only including those with the same
259 // reference prefix as aRef
260 std::map<int, std::vector<SCH_REFERENCE>> refNumberMap;
261
262 for( const SCH_REFERENCE& ref : m_flatList )
263 {
264 // search only for the current reference prefix:
265 if( ref.CompareRef( aRef ) != 0 )
266 continue;
267
268 if( ref.m_isNew )
269 continue; // It will be reannotated
270
271 refNumberMap[ref.m_numRef].push_back( ref );
272 }
273
274 return m_refDesTracker->GetNextRefDesForUnits( aRef, refNumberMap, aRequiredUnits, aMinValue );
275}
276
277
278std::vector<SCH_SYMBOL_INSTANCE> SCH_REFERENCE_LIST::GetSymbolInstances() const
279{
280 std::vector<SCH_SYMBOL_INSTANCE> retval;
281
282 for( const SCH_REFERENCE& ref : m_flatList )
283 {
284 SCH_SYMBOL_INSTANCE instance;
285 instance.m_Path = ref.GetSheetPath().Path();
286 instance.m_Reference = ref.GetRef();
287 instance.m_Unit = ref.GetUnit();
288
289 retval.push_back( instance );
290 }
291
292 return retval;
293}
294
295
296// A helper function to build a full reference string of a SCH_REFERENCE item
297wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
298{
299 wxString fullref;
300 fullref = aItem.GetRef() + aItem.GetRefNumber();
301
302 if( aUnitNumber < 0 )
303 fullref << ".." << aItem.GetUnit();
304 else
305 fullref << ".." << aUnitNumber;
306
307 return fullref;
308}
309
310
312 ANNOTATE_ALGO_T aAlgoOption,
313 int aStartNumber,
314 const SCH_REFERENCE_LIST& aAdditionalRefs,
315 bool aStartAtCurrent,
316 SCH_SHEET_LIST* aHierarchy )
317{
319
320 // All multi-unit symbols always locked to ensure consistent re-annotation
321 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
322
323 for( size_t i = 0; i < GetCount(); i++ )
324 {
325 SCH_REFERENCE& ref = m_flatList[i];
326 wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
327
328 // Update sheet numbers based on the reference's sheet's position within the full
329 // hierarchy; we do this now before we annotate so annotation by sheet number * X
330 // works correctly.
331 if( aHierarchy )
332 {
333 SCH_SHEET_PATH* path = aHierarchy->FindSheetForPath( &ref.GetSheetPath() );
334 wxCHECK2_MSG( path, continue,
335 wxS( "Attempting to annotate item on sheet not part of the "
336 "hierarchy?" ) );
337
338 ref.SetSheetNumber( path->GetPageNumberAsInt() );
339 }
340
341 // Never lock unassigned references
342 if( refstr[refstr.Len() - 1] == '?' )
343 continue;
344
345 ref.m_isNew = true; // We want to reannotate all references
346
347 lockedSymbols[refstr].AddItem( ref );
348 }
349
350 AnnotateByOptions( aSortOption, aAlgoOption, aStartNumber, lockedSymbols, aAdditionalRefs,
351 aStartAtCurrent );
352}
353
354
355void SCH_REFERENCE_LIST::ReannotateDuplicates( const SCH_REFERENCE_LIST& aAdditionalReferences, ANNOTATE_ALGO_T aAlgoOption )
356{
357 ReannotateByOptions( UNSORTED, aAlgoOption, 0, aAdditionalReferences, true, nullptr );
358}
359
360
362 ANNOTATE_ALGO_T aAlgoOption,
363 int aStartNumber,
364 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
365 const SCH_REFERENCE_LIST& aAdditionalRefs,
366 bool aStartAtCurrent )
367{
368 switch( aSortOption )
369 {
370 default:
373 }
374
375 bool useSheetNum;
376 int idStep;
377
378 switch( aAlgoOption )
379 {
380 default:
382 useSheetNum = false;
383 idStep = 1;
384 break;
385
387 useSheetNum = true;
388 idStep = 100;
389 aStartAtCurrent = false; // Not implemented for sheet # * 100
390 break;
391
393 useSheetNum = true;
394 idStep = 1000;
395 aStartAtCurrent = false; // Not implemented for sheet # * 1000
396 break;
397 }
398
399 Annotate( useSheetNum, idStep, aStartNumber, aLockedUnitMap, aAdditionalRefs, aStartAtCurrent );
400}
401
402
403void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
404 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
405 const SCH_REFERENCE_LIST& aAdditionalRefs,
406 bool aStartAtCurrent )
407{
408 if( !m_refDesTracker )
409 {
410 wxLogError( wxS( "No reference tracker set for SCH_REFERENCE_LIST::Annotate()" ) );
411 return;
412 }
413
414 if ( m_flatList.size() == 0 )
415 return;
416
417 size_t originalSize = GetCount();
418
419 // For multi units symbols, store the list of already used full references.
420 // The algorithm tries to allocate the new reference to symbols having the same
421 // old reference.
422 // This algo works fine as long as the previous annotation has no duplicates.
423 // But when a hierarchy is reannotated with this option, the previous annotation can
424 // have duplicate references, and obviously we must fix these duplicate.
425 // therefore do not try to allocate a full reference more than once when trying
426 // to keep this order of multi units.
427 // inUseRefs keep trace of previously allocated references
428 std::unordered_set<wxString> inUseRefs;
429
430 for( size_t i = 0; i < aAdditionalRefs.GetCount(); i++ )
431 {
432 SCH_REFERENCE additionalRef = aAdditionalRefs[i];
433 additionalRef.Split();
434
435 // Add the additional reference to the multi-unit set if annotated
436 if( !additionalRef.m_isNew )
437 inUseRefs.insert( buildFullReference( additionalRef ) );
438
439 // We don't want to reannotate the additional references even if not annotated
440 // so we change the m_isNew flag to be false after splitting
441 additionalRef.m_isNew = false;
442 AddItem( additionalRef ); //add to this container
443 }
444
445 int LastReferenceNumber = 0;
446
447 /* calculate index of the first symbol with the same reference prefix
448 * than the current symbol. All symbols having the same reference
449 * prefix will receive a reference number with consecutive values:
450 * IC .. will be set to IC4, IC4, IC5 ...
451 */
452 unsigned first = 0;
453
454 // calculate the last used number for this reference prefix:
455 int minRefId;
456
457 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
458 if( aUseSheetNum )
459 minRefId = m_flatList[first].m_sheetNum * aSheetIntervalId + 1;
460 else
461 minRefId = aStartNumber + 1;
462
463
464 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
465 {
466 auto& ref_unit = m_flatList[ii];
467
468 if( ref_unit.m_flag )
469 continue;
470
471 // Check whether this symbol is in aLockedUnitMap.
472 const SCH_REFERENCE_LIST* lockedList = nullptr;
473
474 for( const SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
475 {
476 unsigned n_refs = pair.second.GetCount();
477
478 for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
479 {
480 const SCH_REFERENCE &thisRef = pair.second[thisRefI];
481
482 if( thisRef.IsSameInstance( ref_unit ) )
483 {
484 lockedList = &pair.second;
485 break;
486 }
487 }
488
489 if( lockedList != nullptr )
490 break;
491 }
492
493 if( ( m_flatList[first].CompareRef( ref_unit ) != 0 )
494 || ( aUseSheetNum && ( m_flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
495 {
496 // New reference found: we need a new ref number for this reference
497 first = ii;
498
499 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
500 if( aUseSheetNum )
501 minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
502 else
503 minRefId = aStartNumber + 1;
504 }
505
506 // Find references greater than current reference (unless not annotated)
507 if( aStartAtCurrent && ref_unit.m_numRef > 0 )
508 minRefId = ref_unit.m_numRef;
509
510 wxCHECK( ref_unit.GetLibPart(), /* void */ );
511
512 // Annotation of one part per package symbols (trivial case).
513 if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
514 {
515 if( ref_unit.m_isNew )
516 {
517 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, {} );
518 ref_unit.m_numRef = LastReferenceNumber;
519 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
520 }
521
522 ref_unit.m_flag = 1;
523 ref_unit.m_isNew = false;
524 continue;
525 }
526
527 // If this symbol is in aLockedUnitMap, copy the annotation to all
528 // symbols that are not it
529 if( lockedList != nullptr )
530 {
531 unsigned n_refs = lockedList->GetCount();
532 std::vector<int> units = lockedList->GetUnitsMatchingRef( ref_unit );
533
534 if( ref_unit.m_isNew )
535 {
536 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
537 ref_unit.m_numRef = LastReferenceNumber;
538 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
539 ref_unit.m_isNew = false;
540 ref_unit.m_flag = 1;
541 }
542
543 for( unsigned lockedRefI = 0; lockedRefI < n_refs; ++lockedRefI )
544 {
545 const SCH_REFERENCE& lockedRef = ( *lockedList )[lockedRefI];
546
547 if( lockedRef.IsSameInstance( ref_unit ) )
548 {
549 // This is the symbol we're currently annotating. Hold the unit!
550 ref_unit.m_unit = lockedRef.m_unit;
551
552 // lock this new full reference
553 inUseRefs.insert( buildFullReference( ref_unit ) );
554 }
555
556 if( lockedRef.CompareValue( ref_unit ) != 0 )
557 continue;
558
559 if( lockedRef.CompareLibName( ref_unit ) != 0 )
560 continue;
561
562 // Find the matching symbol
563 for( unsigned jj = ii + 1; jj < m_flatList.size(); jj++ )
564 {
565 if( !lockedRef.IsSameInstance( m_flatList[jj] ) )
566 continue;
567
568 wxString ref_candidate = buildFullReference( ref_unit, lockedRef.m_unit );
569
570 // propagate the new reference and unit selection to the "old" symbol,
571 // if this new full reference is not already used (can happens when initial
572 // multiunits symbols have duplicate references)
573 if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
574 {
575 m_flatList[jj].m_numRef = ref_unit.m_numRef;
576 m_flatList[jj].m_numRefStr = ref_unit.m_numRefStr;
577 m_flatList[jj].m_isNew = false;
578 m_flatList[jj].m_flag = 1;
579
580 // lock this new full reference
581 inUseRefs.insert( ref_candidate );
582 break;
583 }
584 }
585 }
586 }
587 else if( ref_unit.m_isNew )
588 {
589 // Reference belonging to multi-unit symbol that has not yet been annotated. We don't
590 // know what group this might belong to, so just find the first unused reference for
591 // this specific unit. The other units will be annotated in the following passes.
592 std::vector<int> units = { ref_unit.GetUnit() };
593 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
594 ref_unit.m_numRef = LastReferenceNumber;
595 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
596 ref_unit.m_isNew = false;
597 ref_unit.m_flag = 1;
598 }
599 }
600
601 // Remove aAdditionalRefs references
602 m_flatList.erase( m_flatList.begin() + originalSize, m_flatList.end() );
603
604 wxASSERT( originalSize == GetCount() ); // Make sure we didn't make a mistake
605}
606
607
609{
610 int error = 0;
611 wxString tmp;
612 wxString tmp2;
613 wxString msg;
614
616
617 // Split reference designators into name (prefix) and number: IC1 becomes IC, and 1.
619
620 // count not yet annotated items or annotation error.
621 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
622 {
623 msg.Empty();
624 tmp.Empty();
625
626 if( m_flatList[ii].m_isNew ) // Not yet annotated
627 {
628 if( m_flatList[ii].m_numRef >= 0 )
629 tmp << m_flatList[ii].m_numRefStr;
630 else
631 tmp = wxT( "?" );
632
633 if( ( m_flatList[ii].m_unit > 0 ) && ( m_flatList[ii].m_unit < 0x7FFFFFFF )
634 && m_flatList[ii].GetLibPart()->GetUnitCount() > 1 )
635 {
636 msg.Printf( _( "Item not annotated: %s%s (unit %d)" ),
637 m_flatList[ii].GetRef(),
638 tmp,
639 m_flatList[ii].m_unit );
640 }
641 else
642 {
643 msg.Printf( _( "Item not annotated: %s%s" ), m_flatList[ii].GetRef(), tmp );
644 }
645
646 aHandler( ERCE_UNANNOTATED, msg, &m_flatList[ii], nullptr );
647 error++;
648 break;
649 }
650
651 // Error if unit number selected does not exist (greater than the number of units in
652 // the symbol). This can happen if a symbol has changed in a library after a
653 // previous annotation.
654 if( std::max( m_flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < m_flatList[ii].m_unit )
655 {
656 if( m_flatList[ii].m_numRef >= 0 )
657 tmp << m_flatList[ii].m_numRefStr;
658 else
659 tmp = wxT( "?" );
660
661 msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)" ),
662 m_flatList[ii].GetRef(),
663 tmp,
664 m_flatList[ii].GetSymbol()->SubReference( m_flatList[ii].GetUnit() ),
665 m_flatList[ii].m_unit,
666 m_flatList[ii].GetLibPart()->GetUnitCount() );
667
668 aHandler( ERCE_EXTRA_UNITS, msg, &m_flatList[ii], nullptr );
669 error++;
670 break;
671 }
672 }
673
674 // count the duplicated elements (if all are annotated)
675 int imax = m_flatList.size() - 1;
676
677 for( int ii = 0; ii < imax; ii++ )
678 {
679 msg.Empty();
680 tmp.Empty();
681 tmp2.Empty();
682
683 SCH_REFERENCE& first = m_flatList[ii];
684 SCH_REFERENCE& second = m_flatList[ii + 1];
685
686 if( ( first.CompareRef( second ) != 0 )
687 || ( first.m_numRef != second.m_numRef ) )
688 {
689 continue;
690 }
691
692 // Same reference found. If same unit, error!
693 if( first.m_unit == second.m_unit )
694 {
695 if( first.m_numRef >= 0 )
696 tmp << first.m_numRefStr;
697 else
698 tmp = wxT( "?" );
699
700 msg.Printf( _( "Duplicate items %s%s%s\n" ),
701 first.GetRef(),
702 tmp,
703 first.GetLibPart()->GetUnitCount() > 1 ? first.GetSymbol()->SubReference( first.GetUnit() )
704 : wxString( wxT( "" ) ) );
705
706 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &m_flatList[ii+1] );
707 error++;
708 continue;
709 }
710
711 /* Test error if units are different but number of parts per package
712 * too high (ex U3 ( 1 part) and we find U3B this is an error) */
713 if( first.GetLibPart()->GetUnitCount() != second.GetLibPart()->GetUnitCount() )
714 {
715 if( first.m_numRef >= 0 )
716 tmp << first.m_numRefStr;
717 else
718 tmp = wxT( "?" );
719
720 if( second.m_numRef >= 0 )
721 tmp2 << second.m_numRefStr;
722 else
723 tmp2 = wxT( "?" );
724
725 msg.Printf( _( "Differing unit counts for item %s%s%s and %s%s%s\n" ),
726 first.GetRef(),
727 tmp,
728 first.GetSymbol()->SubReference( first.GetUnit() ),
729 second.GetRef(),
730 tmp2,
731 first.GetSymbol()->SubReference( second.GetUnit() ) );
732
733 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &second );
734 error++;
735 continue;
736 }
737
738 // Error if values are different between units, for the same reference
739 if( first.CompareValue( second ) != 0 )
740 {
741 msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
742 first.GetRef(),
743 first.m_numRef,
744 first.GetSymbol()->SubReference( first.GetUnit() ),
745 first.m_value,
746 second.GetRef(),
747 second.m_numRef,
748 first.GetSymbol()->SubReference( second.GetUnit() ),
749 second.m_value );
750
751 aHandler( ERCE_DIFFERENT_UNIT_VALUE, msg, &first, &second );
752 error++;
753 }
754 }
755
756 return error;
757}
758
759
761{
762 wxASSERT( aSymbol != nullptr );
763
764 m_rootSymbol = aSymbol;
765
766 // Ensure the symbol has instance data for the current sheet path so that the unit selection
767 // remains consistent even when loading a sheet without symbol instance records (for example
768 // when editing a subsheet directly).
769 SCH_SYMBOL_INSTANCE instance;
770
771 if( !aSymbol->GetInstance( instance, aSheetPath.Path(), false ) )
772 {
773 instance.m_Path = aSheetPath.Path();
774 instance.m_Reference = aSymbol->GetRef( &aSheetPath, false );
775
776 if( instance.m_Reference.IsEmpty() )
777 instance.m_Reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
778
779 instance.m_Unit = aSymbol->GetUnit();
780 aSymbol->AddHierarchicalReference( instance );
781 }
782
783 m_unit = aSymbol->GetUnitSelection( &aSheetPath );
784 m_footprint = aSymbol->GetFootprintFieldText( true, &aSheetPath, false );
785 m_sheetPath = aSheetPath;
786 m_isNew = false;
787 m_flag = 0;
788 m_symbolUuid = aSymbol->m_Uuid;
789 m_symbolPos = aSymbol->GetPosition();
790 m_sheetNum = 0;
791
792 if( aSymbol->GetRef( &aSheetPath ).IsEmpty() )
793 aSymbol->SetRef( &aSheetPath, wxT( "DefRef?" ) );
794
795 wxString ref = aSymbol->GetRef( &aSheetPath );
796 SetRef( ref );
797
798 m_numRef = -1;
799
800 wxString value = aSymbol->GetValue( false, &aSheetPath, false );
801
802 if( value.IsEmpty() )
803 value = wxT( "~" );
804
805 m_value = std::move( value );
806}
807
808
810{
811 if( m_numRef < 0 )
812 m_ref += '?';
813 else
814 m_ref = TO_UTF8( GetRef() << GetRefNumber() );
815
816 m_rootSymbol->SetRef( &m_sheetPath, From_UTF8( m_ref.c_str() ) );
817 m_rootSymbol->SetUnit( m_unit );
818 m_rootSymbol->SetUnitSelection( &m_sheetPath, m_unit );
819}
820
821
823{
824 wxCHECK( m_rootSymbol && m_rootSymbol->GetLibSymbolRef()
825 && !m_rootSymbol->GetRef( &m_sheetPath ).IsEmpty(), false );
826
827 return m_rootSymbol->GetLibSymbolRef()->IsPower()
828 || m_rootSymbol->GetRef( &m_sheetPath )[0] == wxUniChar( '#' );
829}
830
831
833{
834 std::string refText = GetRefStr();
835
836 m_numRef = -1;
837 m_numRefStr.Clear();
838
839 int ll = refText.length() - 1;
840
841 if( refText[ll] == '?' )
842 {
843 m_isNew = true;
844
845 refText.erase( ll ); // delete last char
846
847 SetRefStr( refText );
848 }
849 else if( isdigit( refText[ll] ) == 0 )
850 {
851 m_isNew = true;
852 }
853 else
854 {
855 while( ll >= 0 )
856 {
857 if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
858 {
859 ll--;
860 }
861 else
862 {
863 if( isdigit( refText[ll + 1] ) )
864 {
865 // null terminated C string into cp
866 const char* cp = refText.c_str() + ll + 1;
867
868 m_numRef = atoi( cp );
869 }
870
871 m_numRefStr = std::string( refText, ll + 1 );
872 refText.erase( ll + 1 );
873 break;
874 }
875 }
876
877 SetRefStr( refText );
878 }
879}
880
881
883{
884 std::string refText = GetRefStr();
885
886 if( refText.empty() )
887 return false;
888
889 int ll = refText.length() - 1;
890
891 return ( refText[ll] == '?' ) || isdigit( refText[ll] );
892}
893
894
895wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList,
896 const wxString& refDelimiter,
897 const wxString& refRangeDelimiter )
898{
899 wxString retVal;
900 size_t i = 0;
901
902 while( i < aList.size() )
903 {
904 wxString ref = aList[ i ].GetRef();
905 int numRef = aList[ i ].m_numRef;
906
907 size_t range = 1;
908
909 while( i + range < aList.size()
910 && aList[ i + range ].GetRef() == ref
911 && aList[ i + range ].m_numRef == int( numRef + range ) )
912 {
913 range++;
914
915 if( range == 2 && refRangeDelimiter.IsEmpty() )
916 break;
917 }
918
919 if( !retVal.IsEmpty() )
920 retVal << refDelimiter;
921
922 if( range == 1 )
923 {
924 retVal << ref << aList[ i ].GetRefNumber();
925 }
926 else if( range == 2 || refRangeDelimiter.IsEmpty() )
927 {
928 retVal << ref << aList[ i ].GetRefNumber();
929 retVal << refDelimiter;
930 retVal << ref << aList[ i + 1 ].GetRefNumber();
931 }
932 else
933 {
934 retVal << ref << aList[ i ].GetRefNumber();
935 retVal << refRangeDelimiter;
936 retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
937 }
938
939 i+= range;
940 }
941
942 return retVal;
943}
944
945
946bool SCH_REFERENCE::GetSymbolDNP( const wxString& aVariant ) const
947{
948 wxCHECK( m_rootSymbol, false );
949
950 return m_rootSymbol->GetDNP( &m_sheetPath, aVariant );
951}
952
953
954bool SCH_REFERENCE::GetSymbolExcludedFromBOM( const wxString& aVariant ) const
955{
956 wxCHECK( m_rootSymbol, false );
957
958 return m_rootSymbol->GetExcludedFromBOM( &m_sheetPath, aVariant );
959}
960
961
962bool SCH_REFERENCE::GetSymbolExcludedFromSim( const wxString& aVariant ) const
963{
964 wxCHECK( m_rootSymbol, false );
965
966 return m_rootSymbol->GetExcludedFromSim( &m_sheetPath, aVariant );
967}
968
969
971{
972 wxCHECK( m_rootSymbol, false );
973
974 return m_rootSymbol->GetExcludedFromBoard();
975}
976
977
978wxString SCH_REFERENCE::formatRefStr( int aNumber ) const
979{
980 // To avoid a risk of duplicate, for power symbols the ref number is 0nnn instead of nnn.
981 // Just because sometimes only power symbols are annotated
982 if( GetSymbol() && GetLibPart() && GetLibPart()->IsPower() )
983 return wxString::Format( "0%d", aNumber );
984
985 return wxString::Format( "%d", aNumber );
986}
987
988
989void SCH_REFERENCE::SetSymbolDNP( bool aEnable, const wxString& aVariant )
990{
991 wxCHECK( m_rootSymbol, /* void */ );
992
993 m_rootSymbol->SetDNP( aEnable, &m_sheetPath, aVariant );
994}
995
996
997void SCH_REFERENCE::SetSymbolExcludedFromBOM( bool aEnable, const wxString& aVariant )
998{
999 wxCHECK( m_rootSymbol, /* void */ );
1000
1001 m_rootSymbol->SetExcludedFromBOM( aEnable, &m_sheetPath, aVariant );
1002}
1003
1004
1005void SCH_REFERENCE::SetSymbolExcludedFromSim( bool aEnable, const wxString& aVariant )
1006{
1007 wxCHECK( m_rootSymbol, /* void */ );
1008
1009 m_rootSymbol->SetExcludedFromSim( aEnable, &m_sheetPath, aVariant );
1010}
1011
1012
1014{
1015 wxCHECK( m_rootSymbol, /* void */ );
1016
1017 m_rootSymbol->SetExcludedFromBoard( aEnable );
1018}
1019
1020
1021#if defined( DEBUG )
1022void SCH_REFERENCE_LIST::Show( const char* aPrefix )
1023{
1024 printf( "%s\n", aPrefix );
1025
1026 for( unsigned i = 0; i < m_flatList.size(); ++i )
1027 {
1028 SCH_REFERENCE& schref = m_flatList[i];
1029
1030 printf( " [%-2d] ref:%-8s num:%-3d lib_part:%s\n", i, schref.m_ref.ToStdString().c_str(),
1031 schref.m_numRef, TO_UTF8( schref.GetLibPart()->GetName() ) );
1032 }
1033}
1034#endif
const KIID m_Uuid
Definition eda_item.h:531
wxString GetName() const override
Definition lib_symbol.h:141
int GetUnitCount() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
int GetUnit() const
Definition sch_item.h:233
SCH_REFERENCE * FindItem(const SCH_REFERENCE &aItem)
void ReannotateByOptions(ANNOTATE_ORDER_T aSortOption, ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent, SCH_SHEET_LIST *aHierarchy)
Forces reannotation of the provided references.
static bool sortByRefAndValue(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
static bool sortBySymbolPtr(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
bool Contains(const SCH_REFERENCE &aItem) const
Return true if aItem exists in this list.
void AnnotateByOptions(enum ANNOTATE_ORDER_T aSortOption, enum ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, const SCH_MULTI_UNIT_REFERENCE_MAP &aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent)
Annotate the references by the provided options.
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, const SCH_MULTI_UNIT_REFERENCE_MAP &aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent=false)
Set the reference designators in the list that have not been annotated.
void SortByYCoordinate()
Sort the list of references by Y position.
static bool sortByTimeStamp(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
int FindRef(const wxString &aPath) const
Search the list for a symbol with a given reference.
void SortByXCoordinate()
Sort the list of references by X position.
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
int FindFirstUnusedReference(const SCH_REFERENCE &aRef, int aMinValue, const std::vector< int > &aRequiredUnits) const
Return the first unused reference number from the properties given in aRef, ensuring all of the units...
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
std::shared_ptr< REFDES_TRACKER > m_refDesTracker
A list of previously used reference designators.
void SortByRefAndValue()
Sort the list of references by value.
std::vector< int > GetUnitsMatchingRef(const SCH_REFERENCE &aRef) const
Return all the unit numbers for a given reference, comparing library reference, value,...
std::vector< SCH_REFERENCE > m_flatList
static bool sortByReferenceOnly(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
void GetRefsInUse(int aIndex, std::vector< int > &aIdList, int aMinRefId) const
Add all the reference designator numbers greater than aMinRefId to aIdList skipping the reference at ...
static wxString Shorthand(std::vector< SCH_REFERENCE > aList, const wxString &refDelimiter, const wxString &refRangeDelimiter)
Return a shorthand string representing all the references in the list.
int FindRefByFullPath(const wxString &aFullPath) const
Search the list for a symbol with the given KIID path (as string).
std::vector< SCH_SYMBOL_INSTANCE > GetSymbolInstances() const
void AddItem(const SCH_REFERENCE &aItem)
void RemoveItem(unsigned int aIndex)
Remove an item from the list of references.
void ReannotateDuplicates(const SCH_REFERENCE_LIST &aAdditionalReferences, ANNOTATE_ALGO_T aAlgoOption)
Convenience function for the Paste Unique functionality.
static bool sortByYPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
int CheckAnnotation(ANNOTATION_ERROR_HANDLER aErrorHandler)
Check for annotations errors.
A helper to define a symbol's reference designator in a schematic.
void SetSymbolExcludedFromBoard(bool aEnable)
const SCH_SHEET_PATH & GetSheetPath() const
void SetSymbolExcludedFromBOM(bool aEnable, const wxString &aVariant=wxEmptyString)
SCH_SYMBOL * m_rootSymbol
The symbol associated the reference object.
int m_unit
The unit number for symbol with multiple parts per package.
SCH_SHEET_PATH m_sheetPath
The sheet path for this reference.
wxString m_footprint
The footprint assigned.
wxString formatRefStr(int aNumber) const
int CompareLibName(const SCH_REFERENCE &item) const
int CompareRef(const SCH_REFERENCE &item) const
void SetRef(const wxString &aReference)
bool AlwaysAnnotate() const
Verify the reference should always be automatically annotated.
wxString m_numRefStr
The numeric part in original string form (may have leading zeroes).
bool m_isNew
True if not yet annotated.
bool GetSymbolExcludedFromBOM(const wxString &aVariant=wxEmptyString) const
bool GetSymbolDNP(const wxString &aVariant=wxEmptyString) const
void Split()
Attempt to split the reference designator into a name (U) and number (1).
bool IsSplitNeeded()
Determine if this reference needs to be split or if it likely already has been.
SCH_SYMBOL * GetSymbol() const
wxString m_ref
Symbol reference prefix, without number (for IC1, this is IC) )
void SetSymbolExcludedFromSim(bool aEnable, const wxString &aVariant=wxEmptyString)
wxString GetRef() const
int m_sheetNum
The sheet number for the reference.
void SetRefStr(const std::string &aReference)
int m_numRef
The numeric part of the reference designator.
bool GetSymbolExcludedFromBoard() const
LIB_SYMBOL * GetLibPart() const
void SetSheetNumber(int aSheetNumber)
const char * GetRefStr() const
bool IsSameInstance(const SCH_REFERENCE &other) const
Return whether this reference refers to the same symbol instance (symbol and sheet) as another.
KIID m_symbolUuid
UUID of the symbol.
bool GetSymbolExcludedFromSim(const wxString &aVariant=wxEmptyString) const
int GetUnit() const
wxString m_value
The symbol value.
VECTOR2I m_symbolPos
The physical position of the symbol in schematic used to annotate by X or Y position.
wxString GetRefNumber() const
int CompareValue(const SCH_REFERENCE &item) const
void Annotate()
Update the annotation of the symbol according the current object state.
void SetSymbolDNP(bool aEnable, const wxString &aVariant=wxEmptyString)
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
SCH_SHEET_PATH * FindSheetForPath(const SCH_SHEET_PATH *aPath)
Return a pointer to the first SCH_SHEET_PATH object (not necessarily the only one) matching the provi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
Schematic symbol object.
Definition sch_symbol.h:69
wxString SubReference(int aUnit, bool aAddSeparator=true) const
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) const override
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) const
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
VECTOR2I GetPosition() const override
Definition sch_symbol.h:885
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
#define _(s)
@ ERCE_UNANNOTATED
Symbol has not been annotated.
@ ERCE_DUPLICATE_REFERENCE
More than one symbol with the same reference.
@ ERCE_EXTRA_UNITS
Symbol has more units than are defined.
@ ERCE_DIFFERENT_UNIT_VALUE
Units of same symbol have different values.
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition kicad_algo.h:157
wxString buildFullReference(const SCH_REFERENCE &aItem, int aUnitNumber=-1)
std::function< void(ERCE_T aType, const wxString &aMsg, SCH_REFERENCE *aItemA, SCH_REFERENCE *aItemB)> ANNOTATION_ERROR_HANDLER
Define a standard error handler for annotation errors.
ANNOTATE_ORDER_T
Schematic annotation order options.
@ UNSORTED
Annotate by position of symbol in the schematic sheet object list.
@ SORT_BY_X_POSITION
Annotate by X position from left to right.
@ SORT_BY_Y_POSITION
Annotate by Y position from top to bottom.
ANNOTATE_ALGO_T
Schematic annotation type options.
@ SHEET_NUMBER_X_1000
Annotate using the first free reference number starting at the sheet number * 1000.
@ INCREMENTAL_BY_REF
Annotate incrementally using the first free reference number.
@ SHEET_NUMBER_X_100
Annotate using the first free reference number starting at the sheet number * 100.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
wxString From_UTF8(const char *cstring)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
A simple container for schematic symbol instance information.
@ REFERENCE
Field Reference of part, i.e. "IC21".
std::string path