Eeschema: Force output ordering

The RTree does not have a deterministic iterator, so extracting items
may be in arbitrary order, causing issues as the schematic appears to
change when comparing to previous revisions.

This uses the SCH_ITEM comparison operator to for ordering by type, then
by custom sorting within type.

For the netlist, we choose the first available unit in the sheet for
each component.

Fixes #3811 | https://gitlab.com/kicad/code/kicad/issues/3811
This commit is contained in:
Seth Hillbrand 2020-01-28 07:42:42 -08:00
parent 128ec782dd
commit 55eb687184
7 changed files with 68 additions and 5 deletions

View File

@ -212,7 +212,30 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeComponents()
for( unsigned i = 0; i < sheetList.size(); i++ )
{
auto cmp = []( const SCH_COMPONENT* a, const SCH_COMPONENT* b ) {
return a->GetField( REFERENCE )->GetText() < b->GetField( REFERENCE )->GetText();
};
std::set<SCH_COMPONENT*, decltype( cmp )> ordered_components( cmp );
for( auto item : sheetList[i].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
{
auto comp = static_cast<SCH_COMPONENT*>( item );
auto test = ordered_components.insert( comp );
if( !test.second )
{
if( ( *( test.first ) )->GetUnit() > comp->GetUnit() )
{
ordered_components.erase( test.first );
ordered_components.insert( comp );
}
}
}
for( auto item : ordered_components )
{
SCH_COMPONENT* comp = findNextComponent( item, &sheetList[i] );

View File

@ -1714,7 +1714,7 @@ bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const
if( Type() != aItem.Type() )
return Type() < aItem.Type();
SCH_COMPONENT* component = (SCH_COMPONENT*) &aItem;
auto component = static_cast<const SCH_COMPONENT*>( &aItem );
EDA_RECT rect = GetBodyBoundingBox();
@ -1727,7 +1727,7 @@ bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const
if( m_Pos.y != component->m_Pos.y )
return m_Pos.y < component->m_Pos.y;
return false;
return GetTimeStamp() < aItem.GetTimeStamp();
}

View File

@ -171,8 +171,18 @@ void SCH_ITEM::SwapData( SCH_ITEM* aItem )
bool SCH_ITEM::operator < ( const SCH_ITEM& aItem ) const
{
wxCHECK_MSG( false, this->Type() < aItem.Type(),
wxT( "Less than operator not defined for " ) + GetClass() );
bool retval = ( Type() < aItem.Type() );
if( Type() != aItem.Type() )
return Type() < aItem.Type();
if( GetTimeStamp() != aItem.GetTimeStamp() )
return GetTimeStamp() < aItem.GetTimeStamp();
if( GetPosition().x != aItem.GetPosition().x )
return GetPosition().x < aItem.GetPosition().x;
return GetPosition().y < aItem.GetPosition().y;
}

View File

@ -23,10 +23,12 @@
#include <algorithm>
#include <boost/algorithm/string/join.hpp>
#include <cctype>
#include <set>
#include <wx/mstream.h>
#include <wx/filename.h>
#include <wx/tokenzr.h>
#include <pgm_base.h>
#include <gr_text.h>
#include <kiway.h>
@ -1877,7 +1879,15 @@ void SCH_LEGACY_PLUGIN::Format( SCH_SCREEN* aScreen )
saveBusAlias( alias );
}
// Enforce item ordering
auto cmp = []( const SCH_ITEM* a, const SCH_ITEM* b ) { return *a < *b; };
std::multiset<SCH_ITEM*, decltype( cmp )> save_map( cmp );
for( auto item : aScreen->Items() )
save_map.insert( item );
for( auto& item : save_map )
{
switch( item->Type() )
{

View File

@ -689,7 +689,7 @@ bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
if( Type() != aItem.Type() )
return Type() < aItem.Type();
SCH_LINE* line = (SCH_LINE*) &aItem;
auto line = static_cast<const SCH_LINE*>( &aItem );
if( GetLength() != line->GetLength() )
return GetLength() < line->GetLength();

View File

@ -263,6 +263,24 @@ void SCH_TEXT::SwapData( SCH_ITEM* aItem )
}
bool SCH_TEXT::operator<( const SCH_ITEM& aItem ) const
{
if( Type() != aItem.Type() )
return Type() < aItem.Type();
auto other = static_cast<const SCH_TEXT*>( &aItem );
if( GetPosition().x != other->GetPosition().x )
return GetPosition().x < other->GetPosition().x;
if( GetPosition().y != other->GetPosition().y )
return GetPosition().y < other->GetPosition().y;
return GetText() < other->GetText();
}
int SCH_TEXT::GetPenSize() const
{
int pensize = GetThickness();

View File

@ -270,6 +270,8 @@ public:
const EDA_RECT GetBoundingBox() const override;
bool operator<( const SCH_ITEM& aItem ) const override;
int GetPenSize() const override;
// Geometric transforms (used in block operations):