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, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
30
31#include <sch_reference_list.h>
32#include <core/kicad_algo.h>
33
34#include <wx/regex.h>
35#include <algorithm>
36#include <vector>
37#include <unordered_set>
38
39#include <string_utils.h>
40#include <erc/erc_settings.h>
41#include <refdes_tracker.h>
42#include <sch_symbol.h>
43#include <sch_edit_frame.h>
44
45
46void SCH_REFERENCE_LIST::RemoveItem( unsigned int aIndex )
47{
48 if( aIndex < m_flatList.size() )
49 m_flatList.erase( m_flatList.begin() + aIndex );
50}
51
52
54{
55 for( unsigned ii = 0; ii < GetCount(); ii++ )
56 {
57 if( m_flatList[ii].IsSameInstance( aItem ) )
58 return true;
59 }
60
61 return false;
62}
63
64
66{
67 for( unsigned ii = 0; ii < GetCount(); ii++ )
68 {
69 if( m_flatList[ii].IsSameInstance( aItem ) )
70 return &m_flatList[ii];
71 }
72
73 return nullptr;
74}
75
76
78{
79 int ii = item1.CompareRef( item2 );
80
81 if( ii == 0 )
82 ii = item1.m_sheetNum - item2.m_sheetNum;
83
84 if( ii == 0 )
85 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
86
87 if( ii == 0 )
88 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
89
90 if( ii == 0 )
91 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
92 else
93 return ii < 0;
94}
95
96
98{
99 int ii = item1.CompareRef( item2 );
100
101 if( ii == 0 )
102 ii = item1.m_sheetNum - item2.m_sheetNum;
103
104 if( ii == 0 )
105 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
106
107 if( ii == 0 )
108 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
109
110 if( ii == 0 )
111 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
112 else
113 return ii < 0;
114}
115
116
118 const SCH_REFERENCE& item2 )
119{
120 int ii = item1.CompareRef( item2 );
121
122 if( ii == 0 )
123 ii = item1.CompareValue( item2 );
124
125 if( ii == 0 )
126 ii = item1.m_unit - item2.m_unit;
127
128 if( ii == 0 )
129 ii = item1.m_sheetNum - item2.m_sheetNum;
130
131 if( ii == 0 )
132 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
133
134 if( ii == 0 )
135 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
136
137 if( ii == 0 )
138 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
139 else
140 return ii < 0;
141}
142
143
145 const SCH_REFERENCE& item2 )
146{
147 int ii = StrNumCmp( item1.GetRef(), item2.GetRef(), false );
148
149 if( ii == 0 )
150 ii = item1.m_unit - item2.m_unit;
151
152 if( ii == 0 )
153 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
154 else
155 return ii < 0;
156}
157
158
160 const SCH_REFERENCE& item2 )
161{
162 int ii = item1.m_sheetPath.Cmp( item2.m_sheetPath );
163
164 if( ii == 0 )
165 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
166 else
167 return ii < 0;
168}
169
170
172{
173 return item1.m_rootSymbol < item2.m_rootSymbol;
174}
175
176
177int SCH_REFERENCE_LIST::FindRefByFullPath( const wxString& aFullPath ) const
178{
179 for( size_t i = 0; i < m_flatList.size(); ++i )
180 {
181 if( m_flatList[i].GetFullPath() == aFullPath )
182 return i;
183 }
184
185 return -1;
186}
187
188
189int SCH_REFERENCE_LIST::FindRef( const wxString& aRef ) const
190{
191 for( size_t i = 0; i < m_flatList.size(); ++i )
192 {
193 if( m_flatList[i].GetRef() == aRef )
194 return i;
195 }
196
197 return -1;
198}
199
200
201void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList,
202 int aMinRefId ) const
203{
204 aIdList.clear();
205
206 for( const SCH_REFERENCE& ref : m_flatList )
207 {
208 // Don't add new references to the list as we will reannotate those
209 if( m_flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId && !ref.m_isNew )
210 aIdList.push_back( ref.m_numRef );
211 }
212
213 std::sort( aIdList.begin(), aIdList.end() );
214
215 // Ensure each reference number appears only once. If there are symbols with
216 // multiple parts per package the same number will be stored for each part.
217 alg::remove_duplicates( aIdList );
218}
219
220
221std::vector<int> SCH_REFERENCE_LIST::GetUnitsMatchingRef( const SCH_REFERENCE& aRef ) const
222{
223 std::vector<int> unitsList;
224
225 // Always add this reference to the list
226 unitsList.push_back( aRef.m_unit );
227
228 for( SCH_REFERENCE ref : m_flatList )
229 {
230 if( ref.CompareValue( aRef ) != 0 )
231 continue;
232
233 if( ref.CompareLibName( aRef ) != 0 )
234 continue;
235
236 // Split if needed before comparing ref and number
237 if( ref.IsSplitNeeded() )
238 ref.Split();
239
240 if( ref.CompareRef( aRef ) != 0 )
241 continue;
242
243 if( ref.m_numRef != aRef.m_numRef )
244 continue;
245
246 unitsList.push_back( ref.m_unit );
247 }
248
249 std::sort( unitsList.begin(), unitsList.end() );
250
251 // Ensure each reference number appears only once. If there are symbols with
252 // multiple parts per package the same number will be stored for each part.
253 alg::remove_duplicates( unitsList );
254
255 return unitsList;
256}
257
258
260 const std::vector<int>& aRequiredUnits ) const
261{
262 // Create a map of references indexed by reference number, only including those with the same
263 // reference prefix as aRef
264 std::map<int, std::vector<SCH_REFERENCE>> refNumberMap;
265
266 for( const SCH_REFERENCE& ref : m_flatList )
267 {
268 // search only for the current reference prefix:
269 if( ref.CompareRef( aRef ) != 0 )
270 continue;
271
272 if( ref.m_isNew )
273 continue; // It will be reannotated
274
275 refNumberMap[ref.m_numRef].push_back( ref );
276 }
277
278 return m_refDesTracker->GetNextRefDesForUnits( aRef, refNumberMap, aRequiredUnits, aMinValue );
279}
280
281
282std::vector<SCH_SYMBOL_INSTANCE> SCH_REFERENCE_LIST::GetSymbolInstances() const
283{
284 std::vector<SCH_SYMBOL_INSTANCE> retval;
285
286 for( const SCH_REFERENCE& ref : m_flatList )
287 {
288 SCH_SYMBOL_INSTANCE instance;
289 instance.m_Path = ref.GetSheetPath().Path();
290 instance.m_Reference = ref.GetRef();
291 instance.m_Unit = ref.GetUnit();
292
293 retval.push_back( instance );
294 }
295
296 return retval;
297}
298
299
300// A helper function to build a full reference string of a SCH_REFERENCE item
301wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
302{
303 wxString fullref;
304 fullref = aItem.GetRef() + aItem.GetRefNumber();
305
306 if( aUnitNumber < 0 )
307 fullref << ".." << aItem.GetUnit();
308 else
309 fullref << ".." << aUnitNumber;
310
311 return fullref;
312}
313
314
316 ANNOTATE_ALGO_T aAlgoOption,
317 int aStartNumber,
318 const SCH_REFERENCE_LIST& aAdditionalRefs,
319 bool aStartAtCurrent,
320 SCH_SHEET_LIST* aHierarchy )
321{
323
324 // All multi-unit symbols always locked to ensure consistent re-annotation
325 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
326
327 for( size_t i = 0; i < GetCount(); i++ )
328 {
329 SCH_REFERENCE& ref = m_flatList[i];
330 wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
331
332 // Update sheet numbers based on the reference's sheet's position within the full
333 // hierarchy; we do this now before we annotate so annotation by sheet number * X
334 // works correctly.
335 if( aHierarchy )
336 {
337 SCH_SHEET_PATH* path = aHierarchy->FindSheetForPath( &ref.GetSheetPath() );
338 wxCHECK2_MSG( path, continue,
339 wxS( "Attempting to annotate item on sheet not part of the "
340 "hierarchy?" ) );
341
342 ref.SetSheetNumber( path->GetPageNumberAsInt() );
343 }
344
345 // Never lock unassigned references
346 if( refstr[refstr.Len() - 1] == '?' )
347 continue;
348
349 ref.m_isNew = true; // We want to reannotate all references
350
351 lockedSymbols[refstr].AddItem( ref );
352 }
353
354 AnnotateByOptions( aSortOption, aAlgoOption, aStartNumber, lockedSymbols, aAdditionalRefs,
355 aStartAtCurrent );
356}
357
358
359void SCH_REFERENCE_LIST::ReannotateDuplicates( const SCH_REFERENCE_LIST& aAdditionalReferences, ANNOTATE_ALGO_T aAlgoOption )
360{
361 ReannotateByOptions( UNSORTED, aAlgoOption, 0, aAdditionalReferences, true, nullptr );
362}
363
364
366 ANNOTATE_ALGO_T aAlgoOption,
367 int aStartNumber,
368 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
369 const SCH_REFERENCE_LIST& aAdditionalRefs,
370 bool aStartAtCurrent )
371{
372 switch( aSortOption )
373 {
374 default:
377 }
378
379 bool useSheetNum;
380 int idStep;
381
382 switch( aAlgoOption )
383 {
384 default:
386 useSheetNum = false;
387 idStep = 1;
388 break;
389
391 useSheetNum = true;
392 idStep = 100;
393 aStartAtCurrent = false; // Not implemented for sheet # * 100
394 break;
395
397 useSheetNum = true;
398 idStep = 1000;
399 aStartAtCurrent = false; // Not implemented for sheet # * 1000
400 break;
401 }
402
403 Annotate( useSheetNum, idStep, aStartNumber, aLockedUnitMap, aAdditionalRefs, aStartAtCurrent );
404}
405
406
407void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
408 const SCH_MULTI_UNIT_REFERENCE_MAP& aLockedUnitMap,
409 const SCH_REFERENCE_LIST& aAdditionalRefs,
410 bool aStartAtCurrent )
411{
412 if( !m_refDesTracker )
413 {
414 wxLogError( wxS( "No reference tracker set for SCH_REFERENCE_LIST::Annotate()" ) );
415 return;
416 }
417
418 if ( m_flatList.size() == 0 )
419 return;
420
421 size_t originalSize = GetCount();
422
423 // For multi units symbols, store the list of already used full references.
424 // The algorithm tries to allocate the new reference to symbols having the same
425 // old reference.
426 // This algo works fine as long as the previous annotation has no duplicates.
427 // But when a hierarchy is reannotated with this option, the previous annotation can
428 // have duplicate references, and obviously we must fix these duplicate.
429 // therefore do not try to allocate a full reference more than once when trying
430 // to keep this order of multi units.
431 // inUseRefs keep trace of previously allocated references
432 std::unordered_set<wxString> inUseRefs;
433
434 for( size_t i = 0; i < aAdditionalRefs.GetCount(); i++ )
435 {
436 SCH_REFERENCE additionalRef = aAdditionalRefs[i];
437 additionalRef.Split();
438
439 // Add the additional reference to the multi-unit set if annotated
440 if( !additionalRef.m_isNew )
441 inUseRefs.insert( buildFullReference( additionalRef ) );
442
443 // We don't want to reannotate the additional references even if not annotated
444 // so we change the m_isNew flag to be false after splitting
445 additionalRef.m_isNew = false;
446 AddItem( additionalRef ); //add to this container
447 }
448
449 int LastReferenceNumber = 0;
450
451 /* calculate index of the first symbol with the same reference prefix
452 * than the current symbol. All symbols having the same reference
453 * prefix will receive a reference number with consecutive values:
454 * IC .. will be set to IC4, IC4, IC5 ...
455 */
456 unsigned first = 0;
457
458 // calculate the last used number for this reference prefix:
459 int minRefId;
460
461 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
462 if( aUseSheetNum )
463 minRefId = m_flatList[first].m_sheetNum * aSheetIntervalId + 1;
464 else
465 minRefId = aStartNumber + 1;
466
467
468 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
469 {
470 auto& ref_unit = m_flatList[ii];
471
472 if( ref_unit.m_flag )
473 continue;
474
475 // Check whether this symbol is in aLockedUnitMap.
476 const SCH_REFERENCE_LIST* lockedList = nullptr;
477
478 for( const SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
479 {
480 unsigned n_refs = pair.second.GetCount();
481
482 for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
483 {
484 const SCH_REFERENCE &thisRef = pair.second[thisRefI];
485
486 if( thisRef.IsSameInstance( ref_unit ) )
487 {
488 lockedList = &pair.second;
489 break;
490 }
491 }
492
493 if( lockedList != nullptr )
494 break;
495 }
496
497 if( ( m_flatList[first].CompareRef( ref_unit ) != 0 )
498 || ( aUseSheetNum && ( m_flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
499 {
500 // New reference found: we need a new ref number for this reference
501 first = ii;
502
503 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
504 if( aUseSheetNum )
505 minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
506 else
507 minRefId = aStartNumber + 1;
508 }
509
510 // Find references greater than current reference (unless not annotated)
511 if( aStartAtCurrent && ref_unit.m_numRef > 0 )
512 minRefId = ref_unit.m_numRef;
513
514 wxCHECK( ref_unit.GetLibPart(), /* void */ );
515
516 // Annotation of one part per package symbols (trivial case).
517 if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
518 {
519 if( ref_unit.m_isNew )
520 {
521 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, {} );
522 ref_unit.m_numRef = LastReferenceNumber;
523 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
524 }
525
526 ref_unit.m_flag = 1;
527 ref_unit.m_isNew = false;
528 continue;
529 }
530
531 // If this symbol is in aLockedUnitMap, copy the annotation to all
532 // symbols that are not it
533 if( lockedList != nullptr )
534 {
535 unsigned n_refs = lockedList->GetCount();
536 std::vector<int> units = lockedList->GetUnitsMatchingRef( ref_unit );
537
538 if( ref_unit.m_isNew )
539 {
540 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
541 ref_unit.m_numRef = LastReferenceNumber;
542 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
543 ref_unit.m_isNew = false;
544 ref_unit.m_flag = 1;
545 }
546
547 for( unsigned lockedRefI = 0; lockedRefI < n_refs; ++lockedRefI )
548 {
549 const SCH_REFERENCE& lockedRef = ( *lockedList )[lockedRefI];
550
551 if( lockedRef.IsSameInstance( ref_unit ) )
552 {
553 // This is the symbol we're currently annotating. Hold the unit!
554 ref_unit.m_unit = lockedRef.m_unit;
555
556 // lock this new full reference
557 inUseRefs.insert( buildFullReference( ref_unit ) );
558 }
559
560 if( lockedRef.CompareValue( ref_unit ) != 0 )
561 continue;
562
563 if( lockedRef.CompareLibName( ref_unit ) != 0 )
564 continue;
565
566 // Find the matching symbol
567 for( unsigned jj = ii + 1; jj < m_flatList.size(); jj++ )
568 {
569 if( !lockedRef.IsSameInstance( m_flatList[jj] ) )
570 continue;
571
572 wxString ref_candidate = buildFullReference( ref_unit, lockedRef.m_unit );
573
574 // propagate the new reference and unit selection to the "old" symbol,
575 // if this new full reference is not already used (can happens when initial
576 // multiunits symbols have duplicate references)
577 if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
578 {
579 m_flatList[jj].m_numRef = ref_unit.m_numRef;
580 m_flatList[jj].m_numRefStr = ref_unit.m_numRefStr;
581 m_flatList[jj].m_isNew = false;
582 m_flatList[jj].m_flag = 1;
583
584 // lock this new full reference
585 inUseRefs.insert( ref_candidate );
586 break;
587 }
588 }
589 }
590 }
591 else if( ref_unit.m_isNew )
592 {
593 // Reference belonging to multi-unit symbol that has not yet been annotated. We don't
594 // know what group this might belong to, so just find the first unused reference for
595 // this specific unit. The other units will be annotated in the following passes.
596 std::vector<int> units = { ref_unit.GetUnit() };
597 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
598 ref_unit.m_numRef = LastReferenceNumber;
599 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
600 ref_unit.m_isNew = false;
601 ref_unit.m_flag = 1;
602 }
603 }
604
605 // Remove aAdditionalRefs references
606 m_flatList.erase( m_flatList.begin() + originalSize, m_flatList.end() );
607
608 wxASSERT( originalSize == GetCount() ); // Make sure we didn't make a mistake
609}
610
611
613{
614 int error = 0;
615 wxString tmp;
616 wxString tmp2;
617 wxString msg;
618
620
621 // Split reference designators into name (prefix) and number: IC1 becomes IC, and 1.
623
624 // count not yet annotated items or annotation error.
625 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
626 {
627 msg.Empty();
628 tmp.Empty();
629
630 if( m_flatList[ii].m_isNew ) // Not yet annotated
631 {
632 if( m_flatList[ii].m_numRef >= 0 )
633 tmp << m_flatList[ii].m_numRefStr;
634 else
635 tmp = wxT( "?" );
636
637 if( ( m_flatList[ii].m_unit > 0 ) && ( m_flatList[ii].m_unit < 0x7FFFFFFF )
638 && m_flatList[ii].GetLibPart()->GetUnitCount() > 1 )
639 {
640 msg.Printf( _( "Item not annotated: %s%s (unit %d)" ),
641 m_flatList[ii].GetRef(),
642 tmp,
643 m_flatList[ii].m_unit );
644 }
645 else
646 {
647 msg.Printf( _( "Item not annotated: %s%s" ), m_flatList[ii].GetRef(), tmp );
648 }
649
650 aHandler( ERCE_UNANNOTATED, msg, &m_flatList[ii], nullptr );
651 error++;
652 break;
653 }
654
655 // Error if unit number selected does not exist (greater than the number of units in
656 // the symbol). This can happen if a symbol has changed in a library after a
657 // previous annotation.
658 if( std::max( m_flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < m_flatList[ii].m_unit )
659 {
660 if( m_flatList[ii].m_numRef >= 0 )
661 tmp << m_flatList[ii].m_numRefStr;
662 else
663 tmp = wxT( "?" );
664
665 msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)" ),
666 m_flatList[ii].GetRef(),
667 tmp,
668 m_flatList[ii].GetSymbol()->SubReference( m_flatList[ii].GetUnit() ),
669 m_flatList[ii].m_unit,
670 m_flatList[ii].GetLibPart()->GetUnitCount() );
671
672 aHandler( ERCE_EXTRA_UNITS, msg, &m_flatList[ii], nullptr );
673 error++;
674 break;
675 }
676 }
677
678 // count the duplicated elements (if all are annotated)
679 int imax = m_flatList.size() - 1;
680
681 for( int ii = 0; ii < imax; ii++ )
682 {
683 msg.Empty();
684 tmp.Empty();
685 tmp2.Empty();
686
687 SCH_REFERENCE& first = m_flatList[ii];
688 SCH_REFERENCE& second = m_flatList[ii + 1];
689
690 if( ( first.CompareRef( second ) != 0 )
691 || ( first.m_numRef != second.m_numRef ) )
692 {
693 continue;
694 }
695
696 // Same reference found. If same unit, error!
697 if( first.m_unit == second.m_unit )
698 {
699 if( first.m_numRef >= 0 )
700 tmp << first.m_numRefStr;
701 else
702 tmp = wxT( "?" );
703
704 msg.Printf( _( "Duplicate items %s%s%s\n" ),
705 first.GetRef(),
706 tmp,
707 first.GetLibPart()->GetUnitCount() > 1 ? first.GetSymbol()->SubReference( first.GetUnit() )
708 : wxString( wxT( "" ) ) );
709
710 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &m_flatList[ii+1] );
711 error++;
712 continue;
713 }
714
715 /* Test error if units are different but number of parts per package
716 * too high (ex U3 ( 1 part) and we find U3B this is an error) */
717 if( 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( true, &aSheetPath, false );
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( false, &aSheetPath, false );
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 = refText.length() - 1;
894
895 return ( refText[ll] == '?' ) || isdigit( refText[ll] );
896}
897
898
899wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList,
900 const wxString& refDelimiter,
901 const wxString& refRangeDelimiter )
902{
903 wxString retVal;
904 size_t i = 0;
905
906 while( i < aList.size() )
907 {
908 wxString ref = aList[ i ].GetRef();
909 int numRef = aList[ i ].m_numRef;
910
911 size_t range = 1;
912
913 while( i + range < aList.size()
914 && aList[ i + range ].GetRef() == ref
915 && aList[ i + range ].m_numRef == int( numRef + range ) )
916 {
917 range++;
918
919 if( range == 2 && refRangeDelimiter.IsEmpty() )
920 break;
921 }
922
923 if( !retVal.IsEmpty() )
924 retVal << refDelimiter;
925
926 if( range == 1 )
927 {
928 retVal << ref << aList[ i ].GetRefNumber();
929 }
930 else if( range == 2 || refRangeDelimiter.IsEmpty() )
931 {
932 retVal << ref << aList[ i ].GetRefNumber();
933 retVal << refDelimiter;
934 retVal << ref << aList[ i + 1 ].GetRefNumber();
935 }
936 else
937 {
938 retVal << ref << aList[ i ].GetRefNumber();
939 retVal << refRangeDelimiter;
940 retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
941 }
942
943 i+= range;
944 }
945
946 return retVal;
947}
948
949
950bool SCH_REFERENCE::GetSymbolDNP( const wxString& aVariant ) const
951{
952 wxCHECK( m_rootSymbol, false );
953
954 return m_rootSymbol->GetDNP( &m_sheetPath, aVariant );
955}
956
957
958bool SCH_REFERENCE::GetSymbolExcludedFromBOM( const wxString& aVariant ) const
959{
960 wxCHECK( m_rootSymbol, false );
961
962 return m_rootSymbol->GetExcludedFromBOM( &m_sheetPath, aVariant );
963}
964
965
966bool SCH_REFERENCE::GetSymbolExcludedFromSim( const wxString& aVariant ) const
967{
968 wxCHECK( m_rootSymbol, false );
969
970 return m_rootSymbol->GetExcludedFromSim( &m_sheetPath, aVariant );
971}
972
973
975{
976 wxCHECK( m_rootSymbol, false );
977
978 return m_rootSymbol->GetExcludedFromBoard();
979}
980
981
982wxString SCH_REFERENCE::formatRefStr( int aNumber ) const
983{
984 // To avoid a risk of duplicate, for power symbols the ref number is 0nnn instead of nnn.
985 // Just because sometimes only power symbols are annotated
986 if( GetSymbol() && GetLibPart() && GetLibPart()->IsPower() )
987 return wxString::Format( "0%d", aNumber );
988
989 return wxString::Format( "%d", aNumber );
990}
991
992
993void SCH_REFERENCE::SetSymbolDNP( bool aEnable, const wxString& aVariant )
994{
995 wxCHECK( m_rootSymbol, /* void */ );
996
997 m_rootSymbol->SetDNP( aEnable, &m_sheetPath, aVariant );
998}
999
1000
1001void SCH_REFERENCE::SetSymbolExcludedFromBOM( bool aEnable, const wxString& aVariant )
1002{
1003 wxCHECK( m_rootSymbol, /* void */ );
1004
1005 m_rootSymbol->SetExcludedFromBOM( aEnable, &m_sheetPath, aVariant );
1006}
1007
1008
1009void SCH_REFERENCE::SetSymbolExcludedFromSim( bool aEnable, const wxString& aVariant )
1010{
1011 wxCHECK( m_rootSymbol, /* void */ );
1012
1013 m_rootSymbol->SetExcludedFromSim( aEnable, &m_sheetPath, aVariant );
1014}
1015
1016
1018{
1019 wxCHECK( m_rootSymbol, /* void */ );
1020
1021 m_rootSymbol->SetExcludedFromBoard( aEnable );
1022}
1023
1024
1025#if defined( DEBUG )
1026void SCH_REFERENCE_LIST::Show( const char* aPrefix )
1027{
1028 printf( "%s\n", aPrefix );
1029
1030 for( unsigned i = 0; i < m_flatList.size(); ++i )
1031 {
1032 SCH_REFERENCE& schref = m_flatList[i];
1033
1034 printf( " [%-2d] ref:%-8s num:%-3d lib_part:%s\n", i, schref.m_ref.ToStdString().c_str(),
1035 schref.m_numRef, TO_UTF8( schref.GetLibPart()->GetName() ) );
1036 }
1037}
1038#endif
const KIID m_Uuid
Definition eda_item.h:522
wxString GetName() const override
Definition lib_symbol.h:146
int GetUnitCount() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:118
int GetUnit() const
Definition sch_item.h:238
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
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:76
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
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:854
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:161
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