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.CompareLibId( 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.CompareLibId( 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 LIB_SYMBOL* libSymbol = m_flatList[ii].GetLibPart();
627
628 if( m_flatList[ii].m_isNew ) // Not yet annotated
629 {
630 if( m_flatList[ii].m_numRef >= 0 )
631 tmp << m_flatList[ii].m_numRefStr;
632 else
633 tmp = wxT( "?" );
634
635 if( ( m_flatList[ii].m_unit > 0 ) && ( m_flatList[ii].m_unit < 0x7FFFFFFF )
636 && libSymbol && libSymbol->GetUnitCount() > 1 )
637 {
638 msg.Printf( _( "Item not annotated: %s%s (unit %d)" ),
639 m_flatList[ii].GetRef(),
640 tmp,
641 m_flatList[ii].m_unit );
642 }
643 else
644 {
645 msg.Printf( _( "Item not annotated: %s%s" ), m_flatList[ii].GetRef(), tmp );
646 }
647
648 aHandler( ERCE_UNANNOTATED, msg, &m_flatList[ii], nullptr );
649 error++;
650 break;
651 }
652
653 // Error if unit number selected does not exist (greater than the number of units in
654 // the symbol). This can happen if a symbol has changed in a library after a
655 // previous annotation.
656 if( libSymbol && std::max( libSymbol->GetUnitCount(), 1 ) < m_flatList[ii].m_unit )
657 {
658 if( m_flatList[ii].m_numRef >= 0 )
659 tmp << m_flatList[ii].m_numRefStr;
660 else
661 tmp = wxT( "?" );
662
663 msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)" ),
664 m_flatList[ii].GetRef(),
665 tmp,
666 m_flatList[ii].GetSymbol()->SubReference( m_flatList[ii].GetUnit() ),
667 m_flatList[ii].m_unit,
668 libSymbol->GetUnitCount() );
669
670 aHandler( ERCE_EXTRA_UNITS, msg, &m_flatList[ii], nullptr );
671 error++;
672 break;
673 }
674 }
675
676 // count the duplicated elements (if all are annotated)
677 int imax = m_flatList.size() - 1;
678
679 for( int ii = 0; ii < imax; ii++ )
680 {
681 msg.Empty();
682 tmp.Empty();
683 tmp2.Empty();
684
685 SCH_REFERENCE& first = m_flatList[ii];
686 SCH_REFERENCE& second = m_flatList[ii + 1];
687
688 if( ( first.CompareRef( second ) != 0 )
689 || ( first.m_numRef != second.m_numRef ) )
690 {
691 continue;
692 }
693
694 // Same reference found. If same unit, error!
695 if( first.m_unit == second.m_unit )
696 {
697 if( first.m_numRef >= 0 )
698 tmp << first.m_numRefStr;
699 else
700 tmp = wxT( "?" );
701
702 msg.Printf( _( "Duplicate items %s%s%s\n" ),
703 first.GetRef(),
704 tmp,
705 first.GetLibPart() && first.GetLibPart()->GetUnitCount() > 1
706 ? first.GetSymbol()->SubReference( first.GetUnit() )
707 : wxString( wxT( "" ) ) );
708
709 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &m_flatList[ii+1] );
710 error++;
711 continue;
712 }
713
714 /* Test error if units are different but number of parts per package
715 * too high (ex U3 ( 1 part) and we find U3B this is an error) */
716 if( first.GetLibPart() && second.GetLibPart()
717 && first.GetLibPart()->GetUnitCount() != second.GetLibPart()->GetUnitCount() )
718 {
719 if( first.m_numRef >= 0 )
720 tmp << first.m_numRefStr;
721 else
722 tmp = wxT( "?" );
723
724 if( second.m_numRef >= 0 )
725 tmp2 << second.m_numRefStr;
726 else
727 tmp2 = wxT( "?" );
728
729 msg.Printf( _( "Differing unit counts for item %s%s%s and %s%s%s\n" ),
730 first.GetRef(),
731 tmp,
732 first.GetSymbol()->SubReference( first.GetUnit() ),
733 second.GetRef(),
734 tmp2,
735 first.GetSymbol()->SubReference( second.GetUnit() ) );
736
737 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &second );
738 error++;
739 continue;
740 }
741
742 // Error if values are different between units, for the same reference
743 if( first.CompareValue( second ) != 0 )
744 {
745 msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
746 first.GetRef(),
747 first.m_numRef,
748 first.GetSymbol()->SubReference( first.GetUnit() ),
749 first.m_value,
750 second.GetRef(),
751 second.m_numRef,
752 first.GetSymbol()->SubReference( second.GetUnit() ),
753 second.m_value );
754
755 aHandler( ERCE_DIFFERENT_UNIT_VALUE, msg, &first, &second );
756 error++;
757 }
758 }
759
760 return error;
761}
762
763
765{
766 wxASSERT( aSymbol != nullptr );
767
768 m_rootSymbol = aSymbol;
769
770 // Ensure the symbol has instance data for the current sheet path so that the unit selection
771 // remains consistent even when loading a sheet without symbol instance records (for example
772 // when editing a subsheet directly).
773 SCH_SYMBOL_INSTANCE instance;
774
775 if( !aSymbol->GetInstance( instance, aSheetPath.Path(), false ) )
776 {
777 instance.m_Path = aSheetPath.Path();
778 instance.m_Reference = aSymbol->GetRef( &aSheetPath, false );
779
780 if( instance.m_Reference.IsEmpty() )
781 instance.m_Reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
782
783 instance.m_Unit = aSymbol->GetUnit();
784 aSymbol->AddHierarchicalReference( instance );
785 }
786
787 m_unit = aSymbol->GetUnitSelection( &aSheetPath );
788 m_footprint = aSymbol->GetFootprintFieldText( &aSheetPath, RESOLVED );
789 m_sheetPath = aSheetPath;
790 m_isNew = false;
791 m_flag = 0;
792 m_symbolUuid = aSymbol->m_Uuid;
793 m_symbolPos = aSymbol->GetPosition();
794 m_sheetNum = 0;
795
796 if( aSymbol->GetRef( &aSheetPath ).IsEmpty() )
797 aSymbol->SetRef( &aSheetPath, wxT( "DefRef?" ) );
798
799 wxString ref = aSymbol->GetRef( &aSheetPath );
800 SetRef( ref );
801
802 m_numRef = -1;
803
804 wxString value = aSymbol->GetValue( &aSheetPath, RESOLVED );
805
806 if( value.IsEmpty() )
807 value = wxT( "~" );
808
809 m_value = std::move( value );
810}
811
812
814{
815 if( m_numRef < 0 )
816 m_ref += '?';
817 else
818 m_ref = TO_UTF8( GetRef() << GetRefNumber() );
819
820 m_rootSymbol->SetRef( &m_sheetPath, From_UTF8( m_ref.c_str() ) );
821 m_rootSymbol->SetUnit( m_unit );
822 m_rootSymbol->SetUnitSelection( &m_sheetPath, m_unit );
823}
824
825
827{
828 wxCHECK( m_rootSymbol && m_rootSymbol->GetLibSymbolRef()
829 && !m_rootSymbol->GetRef( &m_sheetPath ).IsEmpty(), false );
830
831 return m_rootSymbol->GetLibSymbolRef()->IsPower()
832 || m_rootSymbol->GetRef( &m_sheetPath )[0] == wxUniChar( '#' );
833}
834
835
837{
838 std::string refText = GetRefStr();
839
840 m_numRef = -1;
841 m_numRefStr.Clear();
842
843 int ll = refText.length() - 1;
844
845 if( refText[ll] == '?' )
846 {
847 m_isNew = true;
848
849 refText.erase( ll ); // delete last char
850
851 SetRefStr( refText );
852 }
853 else if( isdigit( refText[ll] ) == 0 )
854 {
855 m_isNew = true;
856 }
857 else
858 {
859 while( ll >= 0 )
860 {
861 if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
862 {
863 ll--;
864 }
865 else
866 {
867 if( isdigit( refText[ll + 1] ) )
868 {
869 // null terminated C string into cp
870 const char* cp = refText.c_str() + ll + 1;
871
872 m_numRef = atoi( cp );
873 }
874
875 m_numRefStr = std::string( refText, ll + 1 );
876 refText.erase( ll + 1 );
877 break;
878 }
879 }
880
881 SetRefStr( refText );
882 }
883}
884
885
887{
888 std::string refText = GetRefStr();
889
890 if( refText.empty() )
891 return false;
892
893 int ll = (int) refText.length() - 1;
894
895 return ( refText[ll] == '?' ) || isdigit( refText[ll] );
896}
897
898
899bool SCH_REFERENCE::GetSymbolDNP( const wxString& aVariant ) const
900{
901 wxCHECK( m_rootSymbol, false );
902
903 return m_rootSymbol->GetDNP( &m_sheetPath, aVariant );
904}
905
906
907bool SCH_REFERENCE::GetSymbolExcludedFromBOM( const wxString& aVariant ) const
908{
909 wxCHECK( m_rootSymbol, false );
910
911 return m_rootSymbol->GetExcludedFromBOM( &m_sheetPath, aVariant );
912}
913
914
915bool SCH_REFERENCE::GetSymbolExcludedFromSim( const wxString& aVariant ) const
916{
917 wxCHECK( m_rootSymbol, false );
918
919 return m_rootSymbol->GetExcludedFromSim( &m_sheetPath, aVariant );
920}
921
922
924{
925 wxCHECK( m_rootSymbol, false );
926
927 return m_rootSymbol->GetExcludedFromBoard();
928}
929
930
931bool SCH_REFERENCE::GetSymbolExcludedFromPosFiles( const wxString& aVariant ) const
932{
933 wxCHECK( m_rootSymbol, false );
934
935 return m_rootSymbol->GetExcludedFromPosFiles( &m_sheetPath, aVariant );
936}
937
938
939wxString SCH_REFERENCE::formatRefStr( int aNumber ) const
940{
941 // To avoid a risk of duplicate, for power symbols the ref number is 0nnn instead of nnn.
942 // Just because sometimes only power symbols are annotated
943 if( GetSymbol() && GetLibPart() && GetLibPart()->IsPower() )
944 return wxString::Format( "0%d", aNumber );
945
946 return wxString::Format( "%d", aNumber );
947}
948
949
950void SCH_REFERENCE::SetSymbolDNP( bool aEnable, const wxString& aVariant )
951{
952 wxCHECK( m_rootSymbol, /* void */ );
953
954 m_rootSymbol->SetDNP( aEnable, &m_sheetPath, aVariant );
955}
956
957
958void SCH_REFERENCE::SetSymbolExcludedFromBOM( bool aEnable, const wxString& aVariant )
959{
960 wxCHECK( m_rootSymbol, /* void */ );
961
962 m_rootSymbol->SetExcludedFromBOM( aEnable, &m_sheetPath, aVariant );
963}
964
965
966void SCH_REFERENCE::SetSymbolExcludedFromSim( bool aEnable, const wxString& aVariant )
967{
968 wxCHECK( m_rootSymbol, /* void */ );
969
970 m_rootSymbol->SetExcludedFromSim( aEnable, &m_sheetPath, aVariant );
971}
972
973
975{
976 wxCHECK( m_rootSymbol, /* void */ );
977
978 m_rootSymbol->SetExcludedFromBoard( aEnable );
979}
980
981
982void SCH_REFERENCE::SetSymbolExcludedFromPosFiles( bool aEnable, const wxString& aVariant )
983{
984 wxCHECK( m_rootSymbol, /* void */ );
985
986 m_rootSymbol->SetExcludedFromPosFiles( aEnable, &m_sheetPath, aVariant );
987}
988
989
990#if defined( DEBUG )
991void SCH_REFERENCE_LIST::Show( const char* aPrefix )
992{
993 printf( "%s\n", aPrefix );
994
995 for( unsigned i = 0; i < m_flatList.size(); ++i )
996 {
997 SCH_REFERENCE& schref = m_flatList[i];
998
999 printf( " [%-2d] ref:%-8s num:%-3d lib_part:%s\n", i, schref.m_ref.ToStdString().c_str(),
1000 schref.m_numRef, TO_UTF8( schref.GetLibPart()->GetName() ) );
1001 }
1002}
1003#endif
const KIID m_Uuid
Definition eda_item.h:599
Define a library symbol object.
Definition lib_symbol.h:114
wxString GetName() const override
Definition lib_symbol.h:183
int GetUnitCount() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:139
int GetUnit() const
Definition sch_item.h:243
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 ...
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 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).
SCH_SYMBOL * GetSymbol() const
bool GetSymbolExcludedFromPosFiles(const wxString &aVariant=wxEmptyString) 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)
bool IsSplitNeeded() const
Determine if this reference needs to be split or if it likely already has been.
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.
int CompareLibId(const SCH_REFERENCE &item) const
KIID m_symbolUuid
UUID of the symbol.
bool GetSymbolExcludedFromSim(const wxString &aVariant=wxEmptyString) const
void SetSymbolExcludedFromPosFiles(bool aEnable, const wxString &aVariant=wxEmptyString)
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:73
wxString SubReference(int aUnit, bool aAddSeparator=true) const
const wxString GetFootprintFieldText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
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:895
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
const wxString GetValue(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const override
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.
@ RESOLVED
Definition common.h:95
#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.
static wxString From_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition idf_helpers.h:44
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
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.
A simple container for schematic symbol instance information.
@ REFERENCE
Field Reference of part, i.e. "IC21".
std::string path