Performance UpdateDanglingState

Avoid O(N^2) by spatial sorting, don't run checks if the bounding boxes
don't overlap.
A second copy is ordered by type to help classes that only want to check
a few types having to walk the whole list.

(cherry picked from commit b7b64d959f)
This commit is contained in:
Yon Uriarte 2024-02-12 09:01:45 +01:00 committed by Wayne Stambaugh
parent ffd470d94d
commit 7d5583f687
16 changed files with 252 additions and 111 deletions

View File

@ -242,7 +242,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
{ {
KIGFX::VIEW* view = m_preview->GetView(); KIGFX::VIEW* view = m_preview->GetView();
std::vector<DANGLING_END_ITEM> endPoints; std::vector<DANGLING_END_ITEM> endPointsByType;
m_page = new PAGE_INFO( PAGE_INFO::Custom ); m_page = new PAGE_INFO( PAGE_INFO::Custom );
m_titleBlock = new TITLE_BLOCK; m_titleBlock = new TITLE_BLOCK;
@ -399,7 +399,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
pin->SetNumberTextSize( schIUScale.MilsToIU( 50 ) ); pin->SetNumberTextSize( schIUScale.MilsToIU( 50 ) );
pin->SetNameTextSize( schIUScale.MilsToIU( 50 ) ); pin->SetNameTextSize( schIUScale.MilsToIU( 50 ) );
endPoints.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) ); endPointsByType.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
symbol->AddDrawItem( pin ); symbol->AddDrawItem( pin );
pin = new LIB_PIN( symbol ); pin = new LIB_PIN( symbol );
@ -413,7 +413,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
pin->SetNumberTextSize( schIUScale.MilsToIU( 50 ) ); pin->SetNumberTextSize( schIUScale.MilsToIU( 50 ) );
pin->SetNameTextSize( schIUScale.MilsToIU( 50 ) ); pin->SetNameTextSize( schIUScale.MilsToIU( 50 ) );
endPoints.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) ); endPointsByType.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
symbol->AddDrawItem( pin ); symbol->AddDrawItem( pin );
pin = new LIB_PIN( symbol ); pin = new LIB_PIN( symbol );
@ -427,7 +427,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
pin->SetNumberTextSize( schIUScale.MilsToIU( 50 ) ); pin->SetNumberTextSize( schIUScale.MilsToIU( 50 ) );
pin->SetNameTextSize( schIUScale.MilsToIU( 50 ) ); pin->SetNameTextSize( schIUScale.MilsToIU( 50 ) );
endPoints.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) ); endPointsByType.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
symbol->AddDrawItem( pin ); symbol->AddDrawItem( pin );
addItem( symbol ); addItem( symbol );
@ -452,16 +452,19 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
if( sch_item && sch_item->IsConnectable() ) if( sch_item && sch_item->IsConnectable() )
{ {
sch_item->AutoplaceFields( nullptr, false ); sch_item->AutoplaceFields( nullptr, false );
sch_item->GetEndPoints( endPoints ); sch_item->GetEndPoints( endPointsByType );
} }
} }
std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
for( EDA_ITEM* item : m_previewItems ) for( EDA_ITEM* item : m_previewItems )
{ {
SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item ); SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
if( sch_item && sch_item->IsConnectable() ) if( sch_item && sch_item->IsConnectable() )
sch_item->UpdateDanglingState( endPoints, nullptr ); sch_item->UpdateDanglingState( endPointsByType, endPointsByPos, nullptr );
} }
zoomFitPreview(); zoomFitPreview();

View File

@ -312,8 +312,9 @@ void SCH_BUS_ENTRY_BASE::Rotate( const VECTOR2I& aCenter )
} }
bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath ) std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{ {
bool previousStateStart = m_isDanglingStart; bool previousStateStart = m_isDanglingStart;
bool previousStateEnd = m_isDanglingEnd; bool previousStateEnd = m_isDanglingEnd;
@ -324,9 +325,9 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
bool has_wire[2] = { false }; bool has_wire[2] = { false };
bool has_bus[2] = { false }; bool has_bus[2] = { false };
for( unsigned ii = 0; ii < aItemList.size(); ii++ ) for( unsigned ii = 0; ii < aItemListByType.size(); ii++ )
{ {
DANGLING_END_ITEM& item = aItemList[ii]; DANGLING_END_ITEM& item = aItemListByType[ii];
if( item.GetItem() == this ) if( item.GetItem() == this )
continue; continue;
@ -344,7 +345,7 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
case BUS_END: case BUS_END:
{ {
// The bus has created 2 DANGLING_END_ITEMs, one per end. // The bus has created 2 DANGLING_END_ITEMs, one per end.
DANGLING_END_ITEM& nextItem = aItemList[++ii]; DANGLING_END_ITEM& nextItem = aItemListByType[++ii];
if( IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), m_pos ) ) if( IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), m_pos ) )
has_bus[0] = true; has_bus[0] = true;
@ -371,17 +372,19 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
} }
bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath ) std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{ {
bool previousStateStart = m_isDanglingStart; bool previousStateStart = m_isDanglingStart;
bool previousStateEnd = m_isDanglingEnd; bool previousStateEnd = m_isDanglingEnd;
m_isDanglingStart = m_isDanglingEnd = true; m_isDanglingStart = m_isDanglingEnd = true;
for( unsigned ii = 0; ii < aItemList.size(); ii++ ) // TODO: filter using get_lower as we only use one item type
for( unsigned ii = 0; ii < aItemListByType.size(); ii++ )
{ {
DANGLING_END_ITEM& item = aItemList[ii]; DANGLING_END_ITEM& item = aItemListByType[ii];
if( item.GetItem() == this ) if( item.GetItem() == this )
continue; continue;
@ -391,7 +394,7 @@ bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aIt
case BUS_END: case BUS_END:
{ {
// The bus has created 2 DANGLING_END_ITEMs, one per end. // The bus has created 2 DANGLING_END_ITEMs, one per end.
DANGLING_END_ITEM& nextItem = aItemList[++ii]; DANGLING_END_ITEM& nextItem = aItemListByType[++ii];
if( IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), m_pos ) ) if( IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), m_pos ) )
m_isDanglingStart = false; m_isDanglingStart = false;

View File

@ -195,8 +195,9 @@ public:
BITMAPS GetMenuImage() const override; BITMAPS GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath = nullptr ) override; std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
/** /**
* Pointer to the bus item (usually a bus wire) connected to this bus-wire * Pointer to the bus item (usually a bus wire) connected to this bus-wire
@ -240,8 +241,9 @@ public:
BITMAPS GetMenuImage() const override; BITMAPS GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath = nullptr ) override; std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
/** /**
* Pointer to the bus items (usually bus wires) connected to this bus-bus * Pointer to the bus items (usually bus wires) connected to this bus-bus

View File

@ -392,3 +392,50 @@ static struct SCH_ITEM_DESC
} _SCH_ITEM_DESC; } _SCH_ITEM_DESC;
IMPLEMENT_ENUM_TO_WXANY( SCH_LAYER_ID ) IMPLEMENT_ENUM_TO_WXANY( SCH_LAYER_ID )
static bool lessYX( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
{
const auto aPos = a.GetPosition();
const auto bPos = b.GetPosition();
return aPos.y < bPos.y ? true : ( aPos.y > bPos.y ? false : aPos.x < bPos.x );
};
static bool lessType( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
{
return a.GetType() < b.GetType();
};
std::vector<DANGLING_END_ITEM>::iterator
DANGLING_END_ITEM_HELPER::get_lower_pos( std::vector<DANGLING_END_ITEM>& aItemListByPos,
const VECTOR2I& aPos )
{
DANGLING_END_ITEM needle = DANGLING_END_ITEM( PIN_END, nullptr, aPos );
auto start = aItemListByPos.begin();
auto end = aItemListByPos.end();
return std::lower_bound( start, end, needle, lessYX );
}
std::vector<DANGLING_END_ITEM>::iterator
DANGLING_END_ITEM_HELPER::get_lower_type( std::vector<DANGLING_END_ITEM>& aItemListByType,
const DANGLING_END_T& aType )
{
DANGLING_END_ITEM needle = DANGLING_END_ITEM( aType, nullptr, VECTOR2I{} );
auto start = aItemListByType.begin();
auto end = aItemListByType.end();
return std::lower_bound( start, end, needle, lessType );
}
void DANGLING_END_ITEM_HELPER::sort_dangling_end_items(
std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos )
{
// WIRE_END pairs must be kept together. Hence stable sort.
std::stable_sort( aItemListByType.begin(), aItemListByType.end(), lessType );
// Sort by y first, pins are more likely to share x than y.
std::sort( aItemListByPos.begin(), aItemListByPos.end(), lessYX );
}

View File

@ -137,6 +137,20 @@ private:
}; };
class DANGLING_END_ITEM_HELPER
{
public:
static std::vector<DANGLING_END_ITEM>::iterator
get_lower_pos( std::vector<DANGLING_END_ITEM>& aItemListByPos, const VECTOR2I& aPos );
static std::vector<DANGLING_END_ITEM>::iterator
get_lower_type( std::vector<DANGLING_END_ITEM>& aItemListByType, const DANGLING_END_T& aType );
/** Both contain the same information */
static void sort_dangling_end_items( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos );
};
typedef std::vector<SCH_ITEM*> SCH_ITEM_SET; typedef std::vector<SCH_ITEM*> SCH_ITEM_SET;
@ -352,12 +366,15 @@ public:
* If aSheet is passed a non-null pointer to a SCH_SHEET_PATH, the overridden method can * If aSheet is passed a non-null pointer to a SCH_SHEET_PATH, the overridden method can
* optionally use it to update sheet-local connectivity information * optionally use it to update sheet-local connectivity information
* *
* @param aItemList is the list of items to test item against. * @param aItemListByType is the list of items to test item against. It's sorted
* by item type, keeping WIRE_END pairs together.
* @param aItemListByPos is the same list but sorted first by Y then by X.
* @param aSheet is the sheet path to update connections for. * @param aSheet is the sheet path to update connections for.
* @return True if the dangling state has changed from it's current setting. * @return True if the dangling state has changed from it's current setting.
*/ */
virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath = nullptr ) std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr )
{ {
return false; return false;
} }

View File

@ -1101,16 +1101,19 @@ bool SCH_LABEL_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy
} }
bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath ) std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{ {
bool previousState = m_isDangling; bool previousState = m_isDangling;
m_isDangling = true; VECTOR2I text_pos = GetTextPos();
m_isDangling = true;
m_connectionType = CONNECTION_TYPE::NONE; m_connectionType = CONNECTION_TYPE::NONE;
for( unsigned ii = 0; ii < aItemList.size(); ii++ ) for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, text_pos );
it < aItemListByPos.end() && it->GetPosition() == text_pos; it++ )
{ {
DANGLING_END_ITEM& item = aItemList[ii]; DANGLING_END_ITEM& item = *it;
if( item.GetItem() == this ) if( item.GetItem() == this )
continue; continue;
@ -1121,33 +1124,68 @@ bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemL
case LABEL_END: case LABEL_END:
case SHEET_LABEL_END: case SHEET_LABEL_END:
case NO_CONNECT_END: case NO_CONNECT_END:
if( GetTextPos() == item.GetPosition() ) if( text_pos == item.GetPosition() )
{ {
m_isDangling = false; m_isDangling = false;
if( aPath && item.GetType() != PIN_END ) if( aPath && item.GetType() != PIN_END )
AddConnectionTo( *aPath, static_cast<SCH_ITEM*>( item.GetItem() ) ); AddConnectionTo( *aPath, static_cast<SCH_ITEM*>( item.GetItem() ) );
} }
break; break;
case BUS_END: default: break;
m_connectionType = CONNECTION_TYPE::BUS; }
KI_FALLTHROUGH;
case WIRE_END: if( !m_isDangling )
break;
}
if( m_isDangling )
{
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_type( aItemListByType, BUS_END );
it < aItemListByType.end() && it->GetType() == BUS_END; it++ )
{ {
DANGLING_END_ITEM& nextItem = aItemList[++ii]; DANGLING_END_ITEM& item = *it;
DANGLING_END_ITEM& nextItem = *( ++it );
int accuracy = 1; // We have rounding issues with an accuracy of 0 int accuracy = 1; // We have rounding issues with an accuracy of 0
m_isDangling = !TestSegmentHit( GetTextPos(), item.GetPosition(), m_isDangling = !TestSegmentHit( text_pos, item.GetPosition(), nextItem.GetPosition(),
nextItem.GetPosition(), accuracy ); accuracy );
if( !m_isDangling ) if( m_isDangling )
continue;
m_connectionType = CONNECTION_TYPE::BUS;
// Add the line to the connected items, since it won't be picked
// up by a search of intersecting connection points
if( aPath )
{ {
if( m_connectionType != CONNECTION_TYPE::BUS ) auto sch_item = static_cast<SCH_ITEM*>( item.GetItem() );
m_connectionType = CONNECTION_TYPE::NET; AddConnectionTo( *aPath, sch_item );
sch_item->AddConnectionTo( *aPath, this );
}
break;
}
if( m_isDangling )
{
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_type( aItemListByType, WIRE_END );
it < aItemListByType.end() && it->GetType() == WIRE_END; it++ )
{
DANGLING_END_ITEM& item = *it;
DANGLING_END_ITEM& nextItem = *( ++it );
int accuracy = 1; // We have rounding issues with an accuracy of 0
m_isDangling = !TestSegmentHit( text_pos, item.GetPosition(),
nextItem.GetPosition(), accuracy );
if( m_isDangling )
continue;
m_connectionType = CONNECTION_TYPE::NET;
// Add the line to the connected items, since it won't be picked // Add the line to the connected items, since it won't be picked
// up by a search of intersecting connection points // up by a search of intersecting connection points
@ -1157,16 +1195,9 @@ bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemL
AddConnectionTo( *aPath, sch_item ); AddConnectionTo( *aPath, sch_item );
sch_item->AddConnectionTo( *aPath, this ); sch_item->AddConnectionTo( *aPath, this );
} }
break;
} }
} }
break;
default:
break;
}
if( !m_isDangling )
break;
} }
if( m_isDangling ) if( m_isDangling )

View File

@ -306,8 +306,9 @@ public:
void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override; void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath = nullptr ) override; std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsDangling() const override { return m_isDangling; } bool IsDangling() const override { return m_isDangling; }
void SetIsDangling( bool aIsDangling ) { m_isDangling = aIsDangling; } void SetIsDangling( bool aIsDangling ) { m_isDangling = aIsDangling; }

View File

@ -610,44 +610,56 @@ void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
} }
bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath ) std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{ {
if( IsConnectable() ) if( !IsConnectable() )
return false;
bool previousStartState = m_startIsDangling;
bool previousEndState = m_endIsDangling;
m_startIsDangling = m_endIsDangling = true;
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, m_start );
it < aItemListByPos.end() && it->GetPosition() == m_start; it++ )
{ {
bool previousStartState = m_startIsDangling; DANGLING_END_ITEM& item = *it;
bool previousEndState = m_endIsDangling;
m_startIsDangling = m_endIsDangling = true; if( item.GetItem() == this )
continue;
for( DANGLING_END_ITEM item : aItemList ) if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
|| ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
{ {
if( item.GetItem() == this ) m_startIsDangling = false;
continue; break;
if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
|| ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
{
if( m_start == item.GetPosition() )
m_startIsDangling = false;
if( m_end == item.GetPosition() )
m_endIsDangling = false;
if( !m_startIsDangling && !m_endIsDangling )
break;
}
} }
// We only use the bus dangling state for automatic line starting, so we don't care if it
// has changed or not (and returning true will result in extra work)
if( IsBus() )
return false;
return previousStartState != m_startIsDangling || previousEndState != m_endIsDangling;
} }
return false; for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, m_end );
it < aItemListByPos.end() && it->GetPosition() == m_end; it++ )
{
DANGLING_END_ITEM& item = *it;
if( item.GetItem() == this )
continue;
if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
|| ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
{
m_endIsDangling = false;
break;
}
}
// We only use the bus dangling state for automatic line starting, so we don't care if it
// has changed or not (and returning true will result in extra work)
if( IsBus() )
return false;
return previousStartState != m_startIsDangling || previousEndState != m_endIsDangling;
} }

View File

@ -254,8 +254,9 @@ public:
void GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList ) override; void GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath = nullptr ) override; std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsStartDangling() const { return m_startIsDangling; } bool IsStartDangling() const { return m_startIsDangling; }
bool IsEndDangling() const { return m_endIsDangling; } bool IsEndDangling() const { return m_endIsDangling; }

View File

@ -1361,36 +1361,46 @@ void SCH_SCREEN::TestDanglingEnds( const SCH_SHEET_PATH* aPath,
{ {
PROF_TIMER timer( __FUNCTION__ ); PROF_TIMER timer( __FUNCTION__ );
std::vector<DANGLING_END_ITEM> endPoints; std::vector<DANGLING_END_ITEM> endPointsByPos;
std::vector<DANGLING_END_ITEM> endPointsByType;
auto getends = auto get_ends =
[&]( SCH_ITEM* item ) [&]( SCH_ITEM* item )
{ {
if( item->IsConnectable() ) if( item->IsConnectable() )
item->GetEndPoints( endPoints ); item->GetEndPoints( endPointsByType );
}; };
auto update_state = auto update_state =
[&]( SCH_ITEM* item ) [&]( SCH_ITEM* item )
{ {
if( item->UpdateDanglingState( endPoints, aPath ) ) if( item->UpdateDanglingState( endPointsByType, endPointsByPos, aPath ) )
{ {
if( aChangedHandler ) if( aChangedHandler )
(*aChangedHandler)( item ); ( *aChangedHandler )( item );
} }
}; };
for( SCH_ITEM* item : Items() ) for( SCH_ITEM* item : Items() )
{ {
get_ends( item );
getends( item ); item->RunOnChildren( get_ends );
item->RunOnChildren( getends );
} }
PROF_TIMER sortTimer( "SCH_SCREEN::TestDanglingEnds pre-sort" );
endPointsByPos = endPointsByType;
DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
sortTimer.Stop();
if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
sortTimer.Show();
for( SCH_ITEM* item : Items() ) for( SCH_ITEM* item : Items() )
{ {
update_state( item ); update_state( item );
item->RunOnChildren( update_state ); item->RunOnChildren( update_state );
} }
if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) ) if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
timer.Show(); timer.Show();
} }

View File

@ -1000,13 +1000,14 @@ void SCH_SHEET::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
} }
bool SCH_SHEET::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool SCH_SHEET::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath ) std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{ {
bool changed = false; bool changed = false;
for( SCH_SHEET_PIN* sheetPin : m_pins ) for( SCH_SHEET_PIN* sheetPin : m_pins )
changed |= sheetPin->UpdateDanglingState( aItemList ); changed |= sheetPin->UpdateDanglingState( aItemListByType, aItemListByPos );
return changed; return changed;
} }

View File

@ -341,8 +341,9 @@ public:
void GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList ) override; void GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath = nullptr ) override; std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsConnectable() const override { return true; } bool IsConnectable() const override { return true; }

View File

@ -2055,8 +2055,9 @@ void SCH_SYMBOL::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
} }
bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath ) std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{ {
bool changed = false; bool changed = false;
@ -2067,8 +2068,12 @@ bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos; VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
for( DANGLING_END_ITEM& each_item : aItemList ) auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
bool do_break = false;
for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
{ {
DANGLING_END_ITEM& each_item = *it;
// Some people like to stack pins on top of each other in a symbol to indicate // Some people like to stack pins on top of each other in a symbol to indicate
// internal connection. While technically connected, it is not particularly useful // internal connection. While technically connected, it is not particularly useful
// to display them that way, so skip any pins that are in the same symbol as this // to display them that way, so skip any pins that are in the same symbol as this
@ -2084,17 +2089,15 @@ bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
case WIRE_END: case WIRE_END:
case NO_CONNECT_END: case NO_CONNECT_END:
case JUNCTION_END: case JUNCTION_END:
pin->SetIsDangling( false );
if( pos == each_item.GetPosition() ) do_break = true;
pin->SetIsDangling( false );
break; break;
default: default:
break; break;
} }
if( !pin->IsDangling() ) if( do_break )
break; break;
} }

View File

@ -758,8 +758,9 @@ public:
* @param aItemList is list of all #DANGLING_END_ITEM items to be tested. * @param aItemList is list of all #DANGLING_END_ITEM items to be tested.
* @return true if any pin's state has changed. * @return true if any pin's state has changed.
*/ */
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
const SCH_SHEET_PATH* aPath = nullptr ) override; std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
VECTOR2I GetPinPhysicalPosition( const LIB_PIN* Pin ) const; VECTOR2I GetPinPhysicalPosition( const LIB_PIN* Pin ) const;

View File

@ -379,12 +379,14 @@ SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTO
getViewControls()->SetCrossHairCursorPosition( m_busUnfold.entry->GetEnd(), false ); getViewControls()->SetCrossHairCursorPosition( m_busUnfold.entry->GetEnd(), false );
std::vector<DANGLING_END_ITEM> endPoints; std::vector<DANGLING_END_ITEM> endPointsByType;
for( SCH_ITEM* item : screen->Items().Overlapping( m_busUnfold.entry->GetBoundingBox() ) ) for( SCH_ITEM* item : screen->Items().Overlapping( m_busUnfold.entry->GetBoundingBox() ) )
item->GetEndPoints( endPoints ); item->GetEndPoints( endPointsByType );
m_busUnfold.entry->UpdateDanglingState( endPoints ); std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
m_busUnfold.entry->UpdateDanglingState( endPointsByType, endPointsByPos );
m_busUnfold.entry->SetEndDangling( false ); m_busUnfold.entry->SetEndDangling( false );
m_busUnfold.label->SetIsDangling( false ); m_busUnfold.label->SetIsDangling( false );

View File

@ -586,8 +586,14 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
for( EDA_ITEM* item : selection ) for( EDA_ITEM* item : selection )
static_cast<SCH_ITEM*>( item )->GetEndPoints( internalPoints ); static_cast<SCH_ITEM*>( item )->GetEndPoints( internalPoints );
std::vector<DANGLING_END_ITEM> endPointsByType = internalPoints;
std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType,
endPointsByPos );
for( EDA_ITEM* item : selection ) for( EDA_ITEM* item : selection )
static_cast<SCH_ITEM*>( item )->UpdateDanglingState( internalPoints ); static_cast<SCH_ITEM*>( item )->UpdateDanglingState( endPointsByType,
endPointsByPos );
} }