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.
This commit is contained in:
Yon Uriarte 2024-02-12 09:01:45 +01:00 committed by Wayne Stambaugh
parent f3c2083018
commit b7b64d959f
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();
std::vector<DANGLING_END_ITEM> endPoints;
std::vector<DANGLING_END_ITEM> endPointsByType;
m_page = new PAGE_INFO( PAGE_INFO::Custom );
m_titleBlock = new TITLE_BLOCK;
@ -399,7 +399,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
pin->SetNumberTextSize( 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 );
pin = new LIB_PIN( symbol );
@ -413,7 +413,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
pin->SetNumberTextSize( 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 );
pin = new LIB_PIN( symbol );
@ -427,7 +427,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
pin->SetNumberTextSize( 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 );
addItem( symbol );
@ -452,16 +452,19 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
if( sch_item && sch_item->IsConnectable() )
{
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 )
{
SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
if( sch_item && sch_item->IsConnectable() )
sch_item->UpdateDanglingState( endPoints, nullptr );
sch_item->UpdateDanglingState( endPointsByType, endPointsByPos, nullptr );
}
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,
const SCH_SHEET_PATH* aPath )
bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{
bool previousStateStart = m_isDanglingStart;
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_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 )
continue;
@ -344,7 +345,7 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
case BUS_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 ) )
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,
const SCH_SHEET_PATH* aPath )
bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{
bool previousStateStart = m_isDanglingStart;
bool previousStateEnd = m_isDanglingEnd;
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 )
continue;
@ -391,7 +394,7 @@ bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aIt
case BUS_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 ) )
m_isDanglingStart = false;

View File

@ -195,8 +195,9 @@ public:
BITMAPS GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
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
@ -240,8 +241,9 @@ public:
BITMAPS GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
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

View File

@ -392,3 +392,50 @@ static struct SCH_ITEM_DESC
} _SCH_ITEM_DESC;
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;
@ -352,12 +366,15 @@ public:
* 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
*
* @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.
* @return True if the dangling state has changed from it's current setting.
*/
virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr )
virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr )
{
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,
const SCH_SHEET_PATH* aPath )
bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{
bool previousState = m_isDangling;
m_isDangling = true;
bool previousState = m_isDangling;
VECTOR2I text_pos = GetTextPos();
m_isDangling = true;
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 )
continue;
@ -1121,33 +1124,68 @@ bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemL
case LABEL_END:
case SHEET_LABEL_END:
case NO_CONNECT_END:
if( GetTextPos() == item.GetPosition() )
if( text_pos == item.GetPosition() )
{
m_isDangling = false;
if( aPath && item.GetType() != PIN_END )
AddConnectionTo( *aPath, static_cast<SCH_ITEM*>( item.GetItem() ) );
}
break;
case BUS_END:
m_connectionType = CONNECTION_TYPE::BUS;
KI_FALLTHROUGH;
default: break;
}
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(),
nextItem.GetPosition(), accuracy );
m_isDangling = !TestSegmentHit( text_pos, item.GetPosition(), nextItem.GetPosition(),
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 )
m_connectionType = CONNECTION_TYPE::NET;
auto sch_item = static_cast<SCH_ITEM*>( item.GetItem() );
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
// 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 );
sch_item->AddConnectionTo( *aPath, this );
}
break;
}
}
break;
default:
break;
}
if( !m_isDangling )
break;
}
if( m_isDangling )

View File

@ -306,8 +306,9 @@ public:
void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsDangling() const override { return m_isDangling; }
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,
const SCH_SHEET_PATH* aPath )
bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
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;
bool previousEndState = m_endIsDangling;
DANGLING_END_ITEM& item = *it;
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 )
continue;
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;
}
m_startIsDangling = 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;
}
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;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsStartDangling() const { return m_startIsDangling; }
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__ );
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 )
{
if( item->IsConnectable() )
item->GetEndPoints( endPoints );
item->GetEndPoints( endPointsByType );
};
auto update_state =
[&]( SCH_ITEM* item )
{
if( item->UpdateDanglingState( endPoints, aPath ) )
if( item->UpdateDanglingState( endPointsByType, endPointsByPos, aPath ) )
{
if( aChangedHandler )
(*aChangedHandler)( item );
( *aChangedHandler )( item );
}
};
for( SCH_ITEM* item : Items() )
{
getends( item );
item->RunOnChildren( getends );
get_ends( item );
item->RunOnChildren( get_ends );
}
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() )
{
update_state( item );
item->RunOnChildren( update_state );
}
if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
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,
const SCH_SHEET_PATH* aPath )
bool SCH_SHEET::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{
bool changed = false;
for( SCH_SHEET_PIN* sheetPin : m_pins )
changed |= sheetPin->UpdateDanglingState( aItemList );
changed |= sheetPin->UpdateDanglingState( aItemListByType, aItemListByPos );
return changed;
}

View File

@ -341,8 +341,9 @@ public:
void GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
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,
const SCH_SHEET_PATH* aPath )
bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath )
{
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;
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
// 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
@ -2084,17 +2089,15 @@ bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
case WIRE_END:
case NO_CONNECT_END:
case JUNCTION_END:
if( pos == each_item.GetPosition() )
pin->SetIsDangling( false );
pin->SetIsDangling( false );
do_break = true;
break;
default:
break;
}
if( !pin->IsDangling() )
if( do_break )
break;
}

View File

@ -758,8 +758,9 @@ public:
* @param aItemList is list of all #DANGLING_END_ITEM items to be tested.
* @return true if any pin's state has changed.
*/
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
std::vector<DANGLING_END_ITEM>& aItemListByPos,
const SCH_SHEET_PATH* aPath = nullptr ) override;
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 );
std::vector<DANGLING_END_ITEM> endPoints;
std::vector<DANGLING_END_ITEM> endPointsByType;
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.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 )
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 )
static_cast<SCH_ITEM*>( item )->UpdateDanglingState( internalPoints );
static_cast<SCH_ITEM*>( item )->UpdateDanglingState( endPointsByType,
endPointsByPos );
}