Browse Source

Check stacked pins for overlapping numbers

If a stacked pin contains [1-3], it should conflict with pins 1, 2 and 3
even if they do not have the same stacked notation

Fixes https://gitlab.com/kicad/code/kicad/issues/21775
pull/19/head
Seth Hillbrand 2 months ago
parent
commit
b22a674d4c
  1. 148
      eeschema/symbol_checker.cpp
  2. 2
      qa/tests/eeschema/test_pin_stacked_layout.cpp
  3. 33
      qa/tests/eeschema/test_stacked_pin_conversion.cpp

148
eeschema/symbol_checker.cpp

@ -41,101 +41,153 @@ void CheckDuplicatePins( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
wxString msg;
std::vector<SCH_PIN*> pinList = aSymbol->GetPins();
// Test for duplicates:
// Sort pins by pin num, so 2 duplicate pins
// (pins with the same number) will be consecutive in list
sort( pinList.begin(), pinList.end(), sort_by_pin_number );
struct LOGICAL_PIN
{
SCH_PIN* pin;
wxString number;
};
for( unsigned ii = 1; ii < pinList.size(); ii++ )
std::vector<LOGICAL_PIN> logicalPins;
logicalPins.reserve( pinList.size() );
for( SCH_PIN* pin : pinList )
{
SCH_PIN* pin = pinList[ii - 1];
SCH_PIN* next = pinList[ii];
bool valid = false;
std::vector<wxString> numbers = pin->GetStackedPinNumbers( &valid );
if( pin->GetNumber() != next->GetNumber() )
if( !valid || numbers.empty() )
{
logicalPins.push_back( { pin, pin->GetNumber() } );
continue;
}
for( const wxString& number : numbers )
logicalPins.push_back( { pin, number } );
}
sort( logicalPins.begin(), logicalPins.end(),
[]( const LOGICAL_PIN& lhs, const LOGICAL_PIN& rhs )
{
int result = lhs.number.Cmp( rhs.number );
if( result == 0 )
result = lhs.pin->GetBodyStyle() - rhs.pin->GetBodyStyle();
if( result == 0 )
result = lhs.pin->GetUnit() - rhs.pin->GetUnit();
if( result == 0 && lhs.pin != rhs.pin )
return lhs.pin < rhs.pin;
return result < 0;
} );
for( unsigned ii = 1; ii < logicalPins.size(); ii++ )
{
LOGICAL_PIN& prev = logicalPins[ii - 1];
LOGICAL_PIN& next = logicalPins[ii];
if( prev.number != next.number )
continue;
if( prev.pin == next.pin )
continue;
// Pins are not duplicated only if they are in different body styles
// (but GetBodyStyle() == 0 means common to all body styles)
if( pin->GetBodyStyle() != 0 && next->GetBodyStyle() != 0 )
if( prev.pin->GetBodyStyle() != 0 && next.pin->GetBodyStyle() != 0 )
{
if( pin->GetBodyStyle() != next->GetBodyStyle() )
if( prev.pin->GetBodyStyle() != next.pin->GetBodyStyle() )
continue;
}
wxString pinName;
wxString nextName;
if( !pin->GetName().IsEmpty() )
pinName = " '" + pin->GetName() + "'";
if( !prev.pin->GetName().IsEmpty() )
pinName = " '" + prev.pin->GetName() + "'";
if( !next.pin->GetName().IsEmpty() )
nextName = " '" + next.pin->GetName() + "'";
auto formatNumberForMessage = []( const SCH_PIN* pin, const wxString& logicalNumber )
{
wxString shown = pin->GetNumber();
if( shown == logicalNumber )
return logicalNumber;
return wxString::Format( wxT( "%s (%s)" ), logicalNumber, shown );
};
if( !next->GetName().IsEmpty() )
nextName = " '" + next->GetName() + "'";
wxString prevNumber = formatNumberForMessage( prev.pin, prev.number );
wxString nextNumber = formatNumberForMessage( next.pin, next.number );
if( aSymbol->IsMultiBodyStyle() && next->GetBodyStyle() )
if( aSymbol->IsMultiBodyStyle() && next.pin->GetBodyStyle() )
{
if( pin->GetUnit() == 0 || next->GetUnit() == 0 )
if( prev.pin->GetUnit() == 0 || next.pin->GetUnit() == 0 )
{
msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
" conflicts with pin %s%s at location <b>(%s, %s)</b>"
" in %s body style." ),
next->GetNumber(),
nextNumber,
nextName,
aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
pin->GetNumber(),
pin->GetName(),
aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).Lower() );
aUnitsProvider->MessageTextFromValue( next.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next.pin->GetPosition().y ),
prevNumber,
prev.pin->GetName(),
aUnitsProvider->MessageTextFromValue( prev.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -prev.pin->GetPosition().y ),
aSymbol->GetBodyStyleDescription( prev.pin->GetBodyStyle(), true ).Lower() );
}
else
{
msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
" conflicts with pin %s%s at location <b>(%s, %s)</b>"
" in units %s and %s of %s body style." ),
next->GetNumber(),
nextNumber,
nextName,
aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
pin->GetNumber(),
aUnitsProvider->MessageTextFromValue( next.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next.pin->GetPosition().y ),
prevNumber,
pinName,
aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
aSymbol->GetUnitDisplayName( next->GetUnit(), false ),
aSymbol->GetUnitDisplayName( pin->GetUnit(), false ),
aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).Lower() );
aUnitsProvider->MessageTextFromValue( prev.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -prev.pin->GetPosition().y ),
aSymbol->GetUnitDisplayName( next.pin->GetUnit(), false ),
aSymbol->GetUnitDisplayName( prev.pin->GetUnit(), false ),
aSymbol->GetBodyStyleDescription( prev.pin->GetBodyStyle(), true ).Lower() );
}
}
else
{
if( pin->GetUnit() == 0 || next->GetUnit() == 0 )
if( prev.pin->GetUnit() == 0 || next.pin->GetUnit() == 0 )
{
msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
" conflicts with pin %s%s at location <b>(%s, %s)</b>." ),
next->GetNumber(),
nextNumber,
nextName,
aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
pin->GetNumber(),
aUnitsProvider->MessageTextFromValue( next.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next.pin->GetPosition().y ),
prevNumber,
pinName,
aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ) );
aUnitsProvider->MessageTextFromValue( prev.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -prev.pin->GetPosition().y ) );
}
else
{
msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
" conflicts with pin %s%s at location <b>(%s, %s)</b>"
" in units %s and %s." ),
next->GetNumber(),
nextNumber,
nextName,
aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
pin->GetNumber(),
aUnitsProvider->MessageTextFromValue( next.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -next.pin->GetPosition().y ),
prevNumber,
pinName,
aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
aSymbol->GetUnitDisplayName( next->GetUnit(), false ),
aSymbol->GetUnitDisplayName( pin->GetUnit(), false ) );
aUnitsProvider->MessageTextFromValue( prev.pin->GetPosition().x ),
aUnitsProvider->MessageTextFromValue( -prev.pin->GetPosition().y ),
aSymbol->GetUnitDisplayName( next.pin->GetUnit(), false ),
aSymbol->GetUnitDisplayName( prev.pin->GetUnit(), false ) );
}
}

2
qa/tests/eeschema/test_pin_stacked_layout.cpp

@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations )
bool overlaps = boxIntersectsLine( textBbox, pinStart, pinEnd );
// Log detailed info for debugging
wxLogMessage( wxT("Rotation %s, Pin %s: pos=(%d,%d) textPos=(%d,%d) pinLine=(%d,%d)-(%d,%d) textBox=(%d,%d,%dx%d) overlap=%s"),
wxLogDebug( wxT("Rotation %s, Pin %s: pos=(%d,%d) textPos=(%d,%d) pinLine=(%d,%d)-(%d,%d) textBox=(%d,%d,%dx%d) overlap=%s"),
rotName, pin->GetNumber(),
pinStart.x, pinStart.y,
numberInfo.m_TextPosition.x, numberInfo.m_TextPosition.y,

33
qa/tests/eeschema/test_stacked_pin_conversion.cpp

@ -21,6 +21,11 @@
#include <sch_pin.h>
#include <lib_symbol.h>
#include <eeschema_test_utils.h>
#include <units_provider.h>
#include <base_units.h>
extern void CheckDuplicatePins( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
UNITS_PROVIDER* aUnitsProvider );
struct STACKED_PIN_CONVERSION_FIXTURE
{
@ -739,4 +744,32 @@ BOOST_AUTO_TEST_CASE( TestAlphanumericRangeCollapsing )
}
BOOST_AUTO_TEST_CASE( TestDuplicatePinDetectionWithStackedNotation )
{
UNITS_PROVIDER unitsProvider( schIUScale, EDA_UNITS::MILS );
SCH_PIN* stacked = new SCH_PIN( m_symbol.get() );
stacked->SetNumber( wxT( "[1-3]" ) );
stacked->SetPosition( VECTOR2I( 0, 0 ) );
m_symbol->AddDrawItem( stacked );
SCH_PIN* single = new SCH_PIN( m_symbol.get() );
single->SetNumber( wxT( "2" ) );
single->SetPosition( VECTOR2I( schIUScale.MilsToIU( 100 ), 0 ) );
m_symbol->AddDrawItem( single );
std::vector<wxString> messages;
CheckDuplicatePins( m_symbol.get(), messages, &unitsProvider );
BOOST_REQUIRE_EQUAL( messages.size(), 1 );
BOOST_CHECK( messages.front().Contains( wxT( "Duplicate pin 2" ) ) );
BOOST_CHECK( messages.front().Contains( wxT( "[1-3]" ) ) );
single->SetNumber( wxT( "5" ) );
messages.clear();
CheckDuplicatePins( m_symbol.get(), messages, &unitsProvider );
BOOST_CHECK( messages.empty() );
}
BOOST_AUTO_TEST_SUITE_END()
Loading…
Cancel
Save