Annotate schematic: fix annotation bug with multi-unit parts when these parts have a duplicate reference.

It happens only with option "Reset, but keep order of multi-unit parts, because the algo tried
to propagate the new reference to parts having the same old reference,
without testing if this old reference was duplicated.

Fixes: lp:1769250
https://bugs.launchpad.net/kicad/+bug/1769250
This commit is contained in:
jean-pierre charras 2018-05-08 09:46:25 +02:00
parent ad6956b05d
commit 44bf92ae64
2 changed files with 54 additions and 13 deletions

View File

@ -1,12 +1,12 @@
/** /**
* @file component_references_lister.cpp * @file component_references_lister.cpp
* @brief Code for creating a flat list of components needed for annotation and BOM. * @brief functions to create a component flat list and to annotate schematic.
*/ */
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 1992-2011 jean-pierre Charras <jp.charras at wanadoo.fr> * Copyright (C) 1992-2018 jean-pierre Charras <jp.charras at wanadoo.fr>
* Copyright (C) 1992-2011 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 1992-2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
* *
@ -32,6 +32,7 @@
#include <wx/regex.h> #include <wx/regex.h>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <unordered_set>
#include <fctsys.h> #include <fctsys.h>
#include <kicad_string.h> #include <kicad_string.h>
@ -271,6 +272,17 @@ int SCH_REFERENCE_LIST::CreateFirstFreeRefId( std::vector<int>& aIdList, int aFi
} }
// A helper function to build a full reference string of a SCH_REFERENCE item
wxString buildFullReference( const SCH_REFERENCE& aItem )
{
wxString fullref;
fullref = aItem.GetRef() + aItem.GetRefNumber();
fullref << ".." << aItem.GetUnit();
return fullref;
}
void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap ) SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap )
{ {
@ -305,6 +317,18 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int
else else
minRefId = aStartNumber + 1; minRefId = aStartNumber + 1;
// For multi units components, when "keep order of multi unit" option is selected,
// store the list of already used full references.
// The algorithm try to allocate the new reference to components having the same
// old reference.
// This algo works fine as long as the previous annotation has no duplicates.
// But when a hierarchy is reannotated with this option, the previous anotation can
// have duplicate references, and obviously we must fix these duplicate.
// therefore do not try to allocate a full reference more than once when trying
// to keep this order of multi units.
// inUseRefs keep trace of previously allocated references
std::unordered_set<wxString> inUseRefs;
// This is the list of all Id already in use for a given reference prefix. // This is the list of all Id already in use for a given reference prefix.
// Will be refilled for each new reference prefix. // Will be refilled for each new reference prefix.
std::vector<int>idList; std::vector<int>idList;
@ -345,7 +369,8 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int
if( aUseSheetNum ) if( aUseSheetNum )
minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId; minRefId = componentFlatList[ii].m_SheetNum * aSheetIntervalId;
LastReferenceNumber = componentFlatList.GetLastReference( ii, minRefId ); LastReferenceNumber = GetLastReference( ii, minRefId );
#else #else
// when using sheet number, ensure ref number >= sheet number* aSheetIntervalId // when using sheet number, ensure ref number >= sheet number* aSheetIntervalId
if( aUseSheetNum ) if( aUseSheetNum )
@ -399,30 +424,47 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int
if( lockedList != NULL ) if( lockedList != NULL )
{ {
unsigned n_refs = lockedList->GetCount(); unsigned n_refs = lockedList->GetCount();
for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI ) for( unsigned thisRefI = 0; thisRefI < n_refs; ++thisRefI )
{ {
SCH_REFERENCE &thisRef = (*lockedList)[thisRefI]; SCH_REFERENCE &thisRef = (*lockedList)[thisRefI];
if( thisRef.IsSameInstance( componentFlatList[ii] ) ) if( thisRef.IsSameInstance( componentFlatList[ii] ) )
{ {
// This is the component we're currently annotating. Hold the unit! // This is the component we're currently annotating. Hold the unit!
componentFlatList[ii].m_Unit = thisRef.m_Unit; componentFlatList[ii].m_Unit = thisRef.m_Unit;
} }
if( thisRef.CompareValue( componentFlatList[ii] ) != 0 ) continue; if( thisRef.CompareValue( componentFlatList[ii] ) != 0 )
if( thisRef.CompareLibName( componentFlatList[ii] ) != 0 ) continue; continue;
if( thisRef.CompareLibName( componentFlatList[ii] ) != 0 )
continue;
// Find the matching component // Find the matching component
for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ ) for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
{ {
if( ! thisRef.IsSameInstance( componentFlatList[jj] ) ) continue; if( ! thisRef.IsSameInstance( componentFlatList[jj] ) )
continue;
wxString ref_candidate = buildFullReference( componentFlatList[ii] );
// propagate the new reference and unit selection to the "old" component,
// if this new full reference is not already used (can happens when initial
// multiunits components have duplicate references)
if( inUseRefs.find( ref_candidate ) == inUseRefs.end() )
{
componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef; componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
componentFlatList[jj].m_Unit = thisRef.m_Unit; componentFlatList[jj].m_Unit = thisRef.m_Unit;
componentFlatList[jj].m_IsNew = false; componentFlatList[jj].m_IsNew = false;
componentFlatList[jj].m_Flag = 1; componentFlatList[jj].m_Flag = 1;
// lock this new full reference
inUseRefs.insert( ref_candidate );
break; break;
} }
} }
} }
}
else else
{ {

View File

@ -3,7 +3,7 @@
* *
* Copyright (C) 1992-2011 jean-pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr> * Copyright (C) 1992-2011 jean-pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
* Copyright (C) 1992-2011 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 1992-2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 KiCad Developers, see authors.txt for contributors. * Copyright (C) 1992-2018 KiCad Developers, see authors.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -416,7 +416,6 @@ public:
} }
/** /**
* Function GetUnit
* searches the sorted list of components for a another component with the same * searches the sorted list of components for a another component with the same
* reference and a given part unit. Use this method to manage components with * reference and a given part unit. Use this method to manage components with
* multiple parts per package. * multiple parts per package.