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
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 <sch_symbol.h>
42#include <sch_edit_frame.h>
43
44
45void SCH_REFERENCE_LIST::RemoveItem( unsigned int aIndex )
46{
47 if( aIndex < m_flatList.size() )
48 m_flatList.erase( m_flatList.begin() + aIndex );
49}
50
51
53{
54 for( unsigned ii = 0; ii < GetCount(); ii++ )
55 {
56 if( m_flatList[ii].IsSameInstance( aItem ) )
57 return true;
58 }
59
60 return false;
61}
62
63
65{
66 int ii = item1.CompareRef( item2 );
67
68 if( ii == 0 )
69 ii = item1.m_sheetNum - item2.m_sheetNum;
70
71 if( ii == 0 )
72 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
73
74 if( ii == 0 )
75 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
76
77 if( ii == 0 )
78 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
79 else
80 return ii < 0;
81}
82
83
85{
86 int ii = item1.CompareRef( item2 );
87
88 if( ii == 0 )
89 ii = item1.m_sheetNum - item2.m_sheetNum;
90
91 if( ii == 0 )
92 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
93
94 if( ii == 0 )
95 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
96
97 if( ii == 0 )
98 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
99 else
100 return ii < 0;
101}
102
103
105 const SCH_REFERENCE& item2 )
106{
107 int ii = item1.CompareRef( item2 );
108
109 if( ii == 0 )
110 ii = item1.CompareValue( item2 );
111
112 if( ii == 0 )
113 ii = item1.m_unit - item2.m_unit;
114
115 if( ii == 0 )
116 ii = item1.m_sheetNum - item2.m_sheetNum;
117
118 if( ii == 0 )
119 ii = item1.m_symbolPos.x - item2.m_symbolPos.x;
120
121 if( ii == 0 )
122 ii = item1.m_symbolPos.y - item2.m_symbolPos.y;
123
124 if( ii == 0 )
125 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
126 else
127 return ii < 0;
128}
129
130
132 const SCH_REFERENCE& item2 )
133{
134 int ii = StrNumCmp( item1.GetRef(), item2.GetRef(), false );
135
136 if( ii == 0 )
137 ii = item1.m_unit - item2.m_unit;
138
139 if( ii == 0 )
140 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
141 else
142 return ii < 0;
143}
144
145
147 const SCH_REFERENCE& item2 )
148{
149 int ii = item1.m_sheetPath.Cmp( item2.m_sheetPath );
150
151 if( ii == 0 )
152 return item1.m_symbolUuid < item2.m_symbolUuid; // ensure a deterministic sort
153 else
154 return ii < 0;
155}
156
157
158int SCH_REFERENCE_LIST::FindRefByFullPath( const wxString& aFullPath ) const
159{
160 for( size_t i = 0; i < m_flatList.size(); ++i )
161 {
162 if( m_flatList[i].GetFullPath() == aFullPath )
163 return i;
164 }
165
166 return -1;
167}
168
169
170int SCH_REFERENCE_LIST::FindRef( const wxString& aRef ) const
171{
172 for( size_t i = 0; i < m_flatList.size(); ++i )
173 {
174 if( m_flatList[i].GetRef() == aRef )
175 return i;
176 }
177
178 return -1;
179}
180
181
182void SCH_REFERENCE_LIST::GetRefsInUse( int aIndex, std::vector< int >& aIdList,
183 int aMinRefId ) const
184{
185 aIdList.clear();
186
187 for( const SCH_REFERENCE& ref : m_flatList )
188 {
189 // Don't add new references to the list as we will reannotate those
190 if( m_flatList[aIndex].CompareRef( ref ) == 0 && ref.m_numRef >= aMinRefId && !ref.m_isNew )
191 aIdList.push_back( ref.m_numRef );
192 }
193
194 std::sort( aIdList.begin(), aIdList.end() );
195
196 // Ensure each reference number appears only once. If there are symbols with
197 // multiple parts per package the same number will be stored for each part.
198 alg::remove_duplicates( aIdList );
199}
200
201
202std::vector<int> SCH_REFERENCE_LIST::GetUnitsMatchingRef( const SCH_REFERENCE& aRef ) const
203{
204 std::vector<int> unitsList;
205
206 // Always add this reference to the list
207 unitsList.push_back( aRef.m_unit );
208
209 for( SCH_REFERENCE ref : m_flatList )
210 {
211 if( ref.CompareValue( aRef ) != 0 )
212 continue;
213
214 if( ref.CompareLibName( aRef ) != 0 )
215 continue;
216
217 // Split if needed before comparing ref and number
218 if( ref.IsSplitNeeded() )
219 ref.Split();
220
221 if( ref.CompareRef( aRef ) != 0 )
222 continue;
223
224 if( ref.m_numRef != aRef.m_numRef )
225 continue;
226
227 unitsList.push_back( ref.m_unit );
228 }
229
230 std::sort( unitsList.begin(), unitsList.end() );
231
232 // Ensure each reference number appears only once. If there are symbols with
233 // multiple parts per package the same number will be stored for each part.
234 alg::remove_duplicates( unitsList );
235
236 return unitsList;
237}
238
239
241 const std::vector<int>& aRequiredUnits ) const
242{
243 // Create a map of references indexed by reference number, only including those with the same
244 // reference prefix as aRef
245 std::map<int, std::vector<SCH_REFERENCE>> refNumberMap;
246
247 for( const SCH_REFERENCE& ref : m_flatList )
248 {
249 // search only for the current reference prefix:
250 if( ref.CompareRef( aRef ) != 0 )
251 continue;
252
253 if( ref.m_isNew )
254 continue; // It will be reannotated
255
256 refNumberMap[ref.m_numRef].push_back( ref );
257 }
258
259 // Start at the given minimum value
260 int minFreeNumber = aMinValue;
261
262 for( ; refNumberMap[minFreeNumber].size() > 0; ++minFreeNumber )
263 {
264 auto isNumberInUse = [&]() -> bool
265 {
266 for( const int& unit : aRequiredUnits )
267 {
268 for( const SCH_REFERENCE& ref : refNumberMap[minFreeNumber] )
269 {
270 if( ref.CompareLibName( aRef ) || ref.CompareValue( aRef )
271 || ref.GetUnit() == unit )
272 {
273 return true;
274 }
275 }
276 }
277
278 return false;
279 };
280
281 if( !isNumberInUse() )
282 return minFreeNumber;
283 }
284
285 return minFreeNumber;
286}
287
288
289std::vector<SCH_SYMBOL_INSTANCE> SCH_REFERENCE_LIST::GetSymbolInstances() const
290{
291 std::vector<SCH_SYMBOL_INSTANCE> retval;
292
293 for( const SCH_REFERENCE& ref : m_flatList )
294 {
295 SCH_SYMBOL_INSTANCE instance;
296 instance.m_Path = ref.GetSheetPath().Path();
297 instance.m_Reference = ref.GetRef();
298 instance.m_Unit = ref.GetUnit();
299
300 retval.push_back( instance );
301 }
302
303 return retval;
304}
305
306
307int SCH_REFERENCE_LIST::createFirstFreeRefId( std::vector<int>& aIdList, int aFirstValue )
308{
309 int expectedId = aFirstValue;
310
311 // We search for expected Id a value >= aFirstValue.
312 // Skip existing Id < aFirstValue
313 unsigned ii = 0;
314
315 for( ; ii < aIdList.size(); ii++ )
316 {
317 if( expectedId <= aIdList[ii] )
318 break;
319 }
320
321 // Ids are sorted by increasing value, from aFirstValue
322 // So we search from aFirstValue the first not used value, i.e. the first hole in list.
323 for( ; ii < aIdList.size(); ii++ )
324 {
325 if( expectedId != aIdList[ii] ) // This id is not yet used.
326 {
327 // Insert this free Id, in order to keep list sorted
328 aIdList.insert( aIdList.begin() + ii, expectedId );
329 return expectedId;
330 }
331
332 expectedId++;
333 }
334
335 // All existing Id are tested, and all values are found in use.
336 // So Create a new one.
337 aIdList.push_back( expectedId );
338 return expectedId;
339}
340
341
342// A helper function to build a full reference string of a SCH_REFERENCE item
343wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
344{
345 wxString fullref;
346 fullref = aItem.GetRef() + aItem.GetRefNumber();
347
348 if( aUnitNumber < 0 )
349 fullref << ".." << aItem.GetUnit();
350 else
351 fullref << ".." << aUnitNumber;
352
353 return fullref;
354}
355
356
358 ANNOTATE_ALGO_T aAlgoOption,
359 int aStartNumber,
360 const SCH_REFERENCE_LIST& aAdditionalRefs,
361 bool aStartAtCurrent,
362 SCH_SHEET_LIST* aHierarchy )
363{
365
366 // All multi-unit symbols always locked to ensure consistent re-annotation
367 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
368
369 for( size_t i = 0; i < GetCount(); i++ )
370 {
371 SCH_REFERENCE& ref = m_flatList[i];
372 wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
373
374 // Update sheet numbers based on the reference's sheet's position within the full
375 // hierarchy; we do this now before we annotate so annotation by sheet number * X
376 // works correctly.
377 if( aHierarchy )
378 {
379 SCH_SHEET_PATH* path = aHierarchy->FindSheetForPath( &ref.GetSheetPath() );
380 wxCHECK2_MSG( path, continue,
381 wxS( "Attempting to annotate item on sheet not part of the "
382 "hierarchy?" ) );
383
384 ref.SetSheetNumber( path->GetVirtualPageNumber() );
385 }
386
387 // Never lock unassigned references
388 if( refstr[refstr.Len() - 1] == '?' )
389 continue;
390
391 ref.m_isNew = true; // We want to reannotate all references
392
393 lockedSymbols[refstr].AddItem( ref );
394 }
395
396 AnnotateByOptions( aSortOption, aAlgoOption, aStartNumber, lockedSymbols, aAdditionalRefs,
397 aStartAtCurrent );
398}
399
400
402{
403 ReannotateByOptions( UNSORTED, INCREMENTAL_BY_REF, 0, aAdditionalReferences, true, nullptr );
404}
405
406
408 ANNOTATE_ALGO_T aAlgoOption,
409 int aStartNumber,
410 SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap,
411 const SCH_REFERENCE_LIST& aAdditionalRefs,
412 bool aStartAtCurrent )
413{
414 switch( aSortOption )
415 {
416 default:
419 }
420
421 bool useSheetNum;
422 int idStep;
423
424 switch( aAlgoOption )
425 {
426 default:
428 useSheetNum = false;
429 idStep = 1;
430 break;
431
433 useSheetNum = true;
434 idStep = 100;
435 aStartAtCurrent = false; // Not implemented for sheet # * 100
436 break;
437
439 useSheetNum = true;
440 idStep = 1000;
441 aStartAtCurrent = false; // Not implemented for sheet # * 1000
442 break;
443 }
444
445 Annotate( useSheetNum, idStep, aStartNumber, aLockedUnitMap, aAdditionalRefs, aStartAtCurrent );
446}
447
448
449void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
450 SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap,
451 const SCH_REFERENCE_LIST& aAdditionalRefs, bool aStartAtCurrent )
452{
453 if ( m_flatList.size() == 0 )
454 return;
455
456 size_t originalSize = GetCount();
457
458 // For multi units symbols, store the list of already used full references.
459 // The algorithm tries to allocate the new reference to symbols having the same
460 // old reference.
461 // This algo works fine as long as the previous annotation has no duplicates.
462 // But when a hierarchy is reannotated with this option, the previous annotation can
463 // have duplicate references, and obviously we must fix these duplicate.
464 // therefore do not try to allocate a full reference more than once when trying
465 // to keep this order of multi units.
466 // inUseRefs keep trace of previously allocated references
467 std::unordered_set<wxString> inUseRefs;
468
469 for( size_t i = 0; i < aAdditionalRefs.GetCount(); i++ )
470 {
471 SCH_REFERENCE additionalRef = aAdditionalRefs[i];
472 additionalRef.Split();
473
474 // Add the additional reference to the multi-unit set if annotated
475 if( !additionalRef.m_isNew )
476 inUseRefs.insert( buildFullReference( additionalRef ) );
477
478 // We don't want to reannotate the additional references even if not annotated
479 // so we change the m_isNew flag to be false after splitting
480 additionalRef.m_isNew = false;
481 AddItem( additionalRef ); //add to this container
482 }
483
484 int LastReferenceNumber = 0;
485
486 /* calculate index of the first symbol with the same reference prefix
487 * than the current symbol. All symbols having the same reference
488 * prefix will receive a reference number with consecutive values:
489 * IC .. will be set to IC4, IC4, IC5 ...
490 */
491 unsigned first = 0;
492
493 // calculate the last used number for this reference prefix:
494 int minRefId;
495
496 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
497 if( aUseSheetNum )
498 minRefId = m_flatList[first].m_sheetNum * aSheetIntervalId + 1;
499 else
500 minRefId = aStartNumber + 1;
501
502
503 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
504 {
505 auto& ref_unit = m_flatList[ii];
506
507 if( ref_unit.m_flag )
508 continue;
509
510 // Check whether this symbol is in aLockedUnitMap.
511 SCH_REFERENCE_LIST* lockedList = nullptr;
512
513 for( SCH_MULTI_UNIT_REFERENCE_MAP::value_type& pair : aLockedUnitMap )
514 {
515 unsigned n_refs = pair.second.GetCount();
516
517 for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
518 {
519 SCH_REFERENCE &thisRef = pair.second[thisRefI];
520
521 if( thisRef.IsSameInstance( ref_unit ) )
522 {
523 lockedList = &pair.second;
524 break;
525 }
526 }
527
528 if( lockedList != nullptr )
529 break;
530 }
531
532 if( ( m_flatList[first].CompareRef( ref_unit ) != 0 )
533 || ( aUseSheetNum && ( m_flatList[first].m_sheetNum != ref_unit.m_sheetNum ) ) )
534 {
535 // New reference found: we need a new ref number for this reference
536 first = ii;
537
538 // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
539 if( aUseSheetNum )
540 minRefId = ref_unit.m_sheetNum * aSheetIntervalId + 1;
541 else
542 minRefId = aStartNumber + 1;
543 }
544
545 // Find references greater than current reference (unless not annotated)
546 if( aStartAtCurrent && ref_unit.m_numRef > 0 )
547 minRefId = ref_unit.m_numRef;
548
549 wxCHECK( ref_unit.GetLibPart(), /* void */ );
550
551 // Annotation of one part per package symbols (trivial case).
552 if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
553 {
554 if( ref_unit.m_isNew )
555 {
556 std::vector<int> idList;
557 GetRefsInUse( first, idList, minRefId );
558 LastReferenceNumber = createFirstFreeRefId( idList, minRefId );
559 ref_unit.m_numRef = LastReferenceNumber;
560 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
561 }
562
563 ref_unit.m_flag = 1;
564 ref_unit.m_isNew = false;
565 continue;
566 }
567
568 // If this symbol is in aLockedUnitMap, copy the annotation to all
569 // symbols that are not it
570 if( lockedList != nullptr )
571 {
572 unsigned n_refs = lockedList->GetCount();
573 std::vector<int> units = lockedList->GetUnitsMatchingRef( ref_unit );
574
575 if( ref_unit.m_isNew )
576 {
577 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
578 ref_unit.m_numRef = LastReferenceNumber;
579 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
580 ref_unit.m_isNew = false;
581 ref_unit.m_flag = 1;
582 }
583
584 for( unsigned lockedRefI = 0; lockedRefI < n_refs; ++lockedRefI )
585 {
586 SCH_REFERENCE& lockedRef = ( *lockedList )[lockedRefI];
587
588 if( lockedRef.IsSameInstance( ref_unit ) )
589 {
590 // This is the symbol we're currently annotating. Hold the unit!
591 ref_unit.m_unit = lockedRef.m_unit;
592
593 // lock this new full reference
594 inUseRefs.insert( buildFullReference( ref_unit ) );
595 }
596
597 if( lockedRef.CompareValue( ref_unit ) != 0 )
598 continue;
599
600 if( lockedRef.CompareLibName( ref_unit ) != 0 )
601 continue;
602
603 // Find the matching symbol
604 for( unsigned jj = ii + 1; jj < m_flatList.size(); jj++ )
605 {
606 if( !lockedRef.IsSameInstance( m_flatList[jj] ) )
607 continue;
608
609 wxString ref_candidate = buildFullReference( ref_unit, lockedRef.m_unit );
610
611 // propagate the new reference and unit selection to the "old" symbol,
612 // if this new full reference is not already used (can happens when initial
613 // multiunits symbols have duplicate references)
614 if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
615 {
616 m_flatList[jj].m_numRef = ref_unit.m_numRef;
617 m_flatList[jj].m_numRefStr = ref_unit.m_numRefStr;
618 m_flatList[jj].m_isNew = false;
619 m_flatList[jj].m_flag = 1;
620
621 // lock this new full reference
622 inUseRefs.insert( ref_candidate );
623 break;
624 }
625 }
626 }
627 }
628 else if( ref_unit.m_isNew )
629 {
630 // Reference belonging to multi-unit symbol that has not yet been annotated. We don't
631 // know what group this might belong to, so just find the first unused reference for
632 // this specific unit. The other units will be annotated in the following passes.
633 std::vector<int> units = { ref_unit.GetUnit() };
634 LastReferenceNumber = FindFirstUnusedReference( ref_unit, minRefId, units );
635 ref_unit.m_numRef = LastReferenceNumber;
636 ref_unit.m_numRefStr = ref_unit.formatRefStr( LastReferenceNumber );
637 ref_unit.m_isNew = false;
638 ref_unit.m_flag = 1;
639 }
640 }
641
642 // Remove aAdditionalRefs references
643 m_flatList.erase( m_flatList.begin() + originalSize, m_flatList.end() );
644
645 wxASSERT( originalSize == GetCount() ); // Make sure we didn't make a mistake
646}
647
648
650{
651 int error = 0;
652 wxString tmp;
653 wxString tmp2;
654 wxString msg;
655
657
658 // Split reference designators into name (prefix) and number: IC1 becomes IC, and 1.
660
661 // count not yet annotated items or annotation error.
662 for( unsigned ii = 0; ii < m_flatList.size(); ii++ )
663 {
664 msg.Empty();
665 tmp.Empty();
666
667 if( m_flatList[ii].m_isNew ) // Not yet annotated
668 {
669 if( m_flatList[ii].m_numRef >= 0 )
670 tmp << m_flatList[ii].m_numRefStr;
671 else
672 tmp = wxT( "?" );
673
674 if( ( m_flatList[ii].m_unit > 0 ) && ( m_flatList[ii].m_unit < 0x7FFFFFFF )
675 && m_flatList[ii].GetLibPart()->GetUnitCount() > 1 )
676 {
677 msg.Printf( _( "Item not annotated: %s%s (unit %d)" ),
678 m_flatList[ii].GetRef(),
679 tmp,
680 m_flatList[ii].m_unit );
681 }
682 else
683 {
684 msg.Printf( _( "Item not annotated: %s%s" ), m_flatList[ii].GetRef(), tmp );
685 }
686
687 aHandler( ERCE_UNANNOTATED, msg, &m_flatList[ii], nullptr );
688 error++;
689 break;
690 }
691
692 // Error if unit number selected does not exist (greater than the number of units in
693 // the symbol). This can happen if a symbol has changed in a library after a
694 // previous annotation.
695 if( std::max( m_flatList[ii].GetLibPart()->GetUnitCount(), 1 ) < m_flatList[ii].m_unit )
696 {
697 if( m_flatList[ii].m_numRef >= 0 )
698 tmp << m_flatList[ii].m_numRefStr;
699 else
700 tmp = wxT( "?" );
701
702 msg.Printf( _( "Error: symbol %s%s%s (unit %d) exceeds units defined (%d)" ),
703 m_flatList[ii].GetRef(),
704 tmp,
705 m_flatList[ii].GetSymbol()->SubReference( m_flatList[ii].GetUnit() ),
706 m_flatList[ii].m_unit,
707 m_flatList[ii].GetLibPart()->GetUnitCount() );
708
709 aHandler( ERCE_EXTRA_UNITS, msg, &m_flatList[ii], nullptr );
710 error++;
711 break;
712 }
713 }
714
715 // count the duplicated elements (if all are annotated)
716 int imax = m_flatList.size() - 1;
717
718 for( int ii = 0; ii < imax; ii++ )
719 {
720 msg.Empty();
721 tmp.Empty();
722 tmp2.Empty();
723
724 SCH_REFERENCE& first = m_flatList[ii];
725 SCH_REFERENCE& second = m_flatList[ii + 1];
726
727 if( ( first.CompareRef( second ) != 0 )
728 || ( first.m_numRef != second.m_numRef ) )
729 {
730 continue;
731 }
732
733 // Same reference found. If same unit, error!
734 if( first.m_unit == second.m_unit )
735 {
736 if( first.m_numRef >= 0 )
737 tmp << first.m_numRefStr;
738 else
739 tmp = wxT( "?" );
740
741 msg.Printf( _( "Duplicate items %s%s%s\n" ),
742 first.GetRef(),
743 tmp,
744 first.GetLibPart()->GetUnitCount() > 1 ? first.GetSymbol()->SubReference( first.GetUnit() )
745 : wxString( wxT( "" ) ) );
746
747 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &m_flatList[ii+1] );
748 error++;
749 continue;
750 }
751
752 /* Test error if units are different but number of parts per package
753 * too high (ex U3 ( 1 part) and we find U3B this is an error) */
754 if( first.GetLibPart()->GetUnitCount() != second.GetLibPart()->GetUnitCount() )
755 {
756 if( first.m_numRef >= 0 )
757 tmp << first.m_numRefStr;
758 else
759 tmp = wxT( "?" );
760
761 if( second.m_numRef >= 0 )
762 tmp2 << second.m_numRefStr;
763 else
764 tmp2 = wxT( "?" );
765
766 msg.Printf( _( "Differing unit counts for item %s%s%s and %s%s%s\n" ),
767 first.GetRef(),
768 tmp,
769 first.GetSymbol()->SubReference( first.GetUnit() ),
770 second.GetRef(),
771 tmp2,
772 first.GetSymbol()->SubReference( second.GetUnit() ) );
773
774 aHandler( ERCE_DUPLICATE_REFERENCE, msg, &first, &second );
775 error++;
776 continue;
777 }
778
779 // Error if values are different between units, for the same reference
780 if( first.CompareValue( second ) != 0 )
781 {
782 msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
783 first.GetRef(),
784 first.m_numRef,
785 first.GetSymbol()->SubReference( first.GetUnit() ),
786 first.m_value,
787 second.GetRef(),
788 second.m_numRef,
789 first.GetSymbol()->SubReference( second.GetUnit() ),
790 second.m_value );
791
792 aHandler( ERCE_DIFFERENT_UNIT_VALUE, msg, &first, &second );
793 error++;
794 }
795 }
796
797 return error;
798}
799
800
802{
803 wxASSERT( aSymbol != nullptr );
804
805 m_rootSymbol = aSymbol;
806 m_unit = aSymbol->GetUnitSelection( &aSheetPath );
807 m_footprint = aSymbol->GetFootprintFieldText( true, &aSheetPath, false );
808 m_sheetPath = aSheetPath;
809 m_isNew = false;
810 m_flag = 0;
811 m_symbolUuid = aSymbol->m_Uuid;
812 m_symbolPos = aSymbol->GetPosition();
813 m_sheetNum = 0;
814
815 if( aSymbol->GetRef( &aSheetPath ).IsEmpty() )
816 aSymbol->SetRef( &aSheetPath, wxT( "DefRef?" ) );
817
818 wxString ref = aSymbol->GetRef( &aSheetPath );
819 SetRef( ref );
820
821 m_numRef = -1;
822
823 if( aSymbol->GetValue( false, &aSheetPath, false ).IsEmpty() )
824 aSymbol->SetValueFieldText( wxT( "~" ) );
825
826 m_value = aSymbol->GetValue( false, &aSheetPath, false );
827}
828
829
831{
832 if( m_numRef < 0 )
833 m_ref += '?';
834 else
835 m_ref = TO_UTF8( GetRef() << GetRefNumber() );
836
840}
841
842
844{
846 && !m_rootSymbol->GetRef( &m_sheetPath ).IsEmpty(), false );
847
848 return m_rootSymbol->GetLibSymbolRef()->IsPower()
849 || m_rootSymbol->GetRef( &m_sheetPath )[0] == wxUniChar( '#' );
850}
851
852
854{
855 std::string refText = GetRefStr();
856
857 m_numRef = -1;
858 m_numRefStr.Clear();
859
860 int ll = refText.length() - 1;
861
862 if( refText[ll] == '?' )
863 {
864 m_isNew = true;
865
866 refText.erase( ll ); // delete last char
867
868 SetRefStr( refText );
869 }
870 else if( isdigit( refText[ll] ) == 0 )
871 {
872 m_isNew = true;
873 }
874 else
875 {
876 while( ll >= 0 )
877 {
878 if( (refText[ll] <= ' ' ) || isdigit( refText[ll] ) )
879 {
880 ll--;
881 }
882 else
883 {
884 if( isdigit( refText[ll + 1] ) )
885 {
886 // null terminated C string into cp
887 const char* cp = refText.c_str() + ll + 1;
888
889 m_numRef = atoi( cp );
890 }
891
892 m_numRefStr = std::string( refText, ll + 1 );
893 refText.erase( ll + 1 );
894 break;
895 }
896 }
897
898 SetRefStr( refText );
899 }
900}
901
902
904{
905 std::string refText = GetRefStr();
906
907 int ll = refText.length() - 1;
908
909 return ( refText[ll] == '?' ) || isdigit( refText[ll] );
910}
911
912
913wxString SCH_REFERENCE_LIST::Shorthand( std::vector<SCH_REFERENCE> aList,
914 const wxString& refDelimiter,
915 const wxString& refRangeDelimiter )
916{
917 wxString retVal;
918 size_t i = 0;
919
920 while( i < aList.size() )
921 {
922 wxString ref = aList[ i ].GetRef();
923 int numRef = aList[ i ].m_numRef;
924
925 size_t range = 1;
926
927 while( i + range < aList.size()
928 && aList[ i + range ].GetRef() == ref
929 && aList[ i + range ].m_numRef == int( numRef + range ) )
930 {
931 range++;
932
933 if( range == 2 && refRangeDelimiter.IsEmpty() )
934 break;
935 }
936
937 if( !retVal.IsEmpty() )
938 retVal << refDelimiter;
939
940 if( range == 1 )
941 {
942 retVal << ref << aList[ i ].GetRefNumber();
943 }
944 else if( range == 2 || refRangeDelimiter.IsEmpty() )
945 {
946 retVal << ref << aList[ i ].GetRefNumber();
947 retVal << refDelimiter;
948 retVal << ref << aList[ i + 1 ].GetRefNumber();
949 }
950 else
951 {
952 retVal << ref << aList[ i ].GetRefNumber();
953 retVal << refRangeDelimiter;
954 retVal << ref << aList[ i + ( range - 1 ) ].GetRefNumber();
955 }
956
957 i+= range;
958 }
959
960 return retVal;
961}
962
963
964wxString SCH_REFERENCE::formatRefStr( int aNumber ) const
965{
966 // To avoid a risk of duplicate, for power symbols the ref number is 0nnn instead of nnn.
967 // Just because sometimes only power symbols are annotated
968 if( GetSymbol() && GetLibPart() && GetLibPart()->IsPower() )
969 return wxString::Format( "0%d", aNumber );
970
971 return wxString::Format( "%d", aNumber );
972}
973
974
975#if defined( DEBUG )
976void SCH_REFERENCE_LIST::Show( const char* aPrefix )
977{
978 printf( "%s\n", aPrefix );
979
980 for( unsigned i = 0; i < m_flatList.size(); ++i )
981 {
982 SCH_REFERENCE& schref = m_flatList[i];
983
984 printf( " [%-2d] ref:%-8s num:%-3d lib_part:%s\n", i, schref.m_ref.ToStdString().c_str(),
985 schref.m_numRef, TO_UTF8( schref.GetLibPart()->GetName() ) );
986 }
987}
988#endif
const KIID m_Uuid
Definition: eda_item.h:488
wxString GetName() const override
Definition: lib_symbol.h:148
int GetUnitCount() const override
virtual void SetUnit(int aUnit)
Definition: sch_item.h:232
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
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 int createFirstFreeRefId(std::vector< int > &aIdList, int aFirstValue)
Search for the first free reference number in aListId of reference numbers in use.
static bool sortByRefAndValue(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
bool Contains(const SCH_REFERENCE &aItem) const
Return true if aItem exists in this list.
void SortByYCoordinate()
Sort the list of references by Y position.
void AnnotateByOptions(enum ANNOTATE_ORDER_T aSortOption, enum ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent)
Annotate the references by the provided options.
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 Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, 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 SortByXCoordinate()
Sort the list of references by X position.
static bool sortByXPosition(const SCH_REFERENCE &item1, const SCH_REFERENCE &item2)
size_t GetCount() const
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).
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 ...
void ReannotateDuplicates(const SCH_REFERENCE_LIST &aAdditionalReferences)
Convenience function for the Paste Unique functionality.
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.
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.
const SCH_SHEET_PATH & GetSheetPath() const
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.
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) )
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.
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.
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.
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...
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:77
wxString SubReference(int aUnit, bool aAddSeparator=true) const
Definition: sch_symbol.cpp:824
void SetValueFieldText(const wxString &aValue)
Definition: sch_symbol.cpp:885
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const override
Definition: sch_symbol.cpp:875
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
Definition: sch_symbol.cpp:747
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const
Definition: sch_symbol.cpp:891
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:798
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:833
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
Definition: sch_symbol.cpp:849
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:185
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:705
#define _(s)
@ ERCE_UNANNOTATED
Symbol has not been annotated.
Definition: erc_settings.h:82
@ ERCE_DUPLICATE_REFERENCE
More than one symbol with the same reference.
Definition: erc_settings.h:85
@ ERCE_EXTRA_UNITS
Symbol has more units than are defined.
Definition: erc_settings.h:83
@ ERCE_DIFFERENT_UNIT_VALUE
Units of same symbol have different values.
Definition: erc_settings.h:84
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition: kicad_algo.h:183
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.
Definition: string_utils.h:403
A simple container for schematic symbol instance information.