From 28e433cc541a6c8774578e80b8431b18cd9dee81 Mon Sep 17 00:00:00 2001 From: Yon Uriarte Date: Mon, 12 Feb 2024 09:01:45 +0100 Subject: [PATCH] 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 b7b64d959f37f00bb0d14b007c3b3908196e1024) --- .../dialogs/panel_eeschema_color_settings.cpp | 15 ++-- eeschema/sch_bus_entry.cpp | 23 ++--- eeschema/sch_bus_entry.h | 10 ++- eeschema/sch_item.cpp | 47 ++++++++++ eeschema/sch_item.h | 23 ++++- eeschema/sch_label.cpp | 85 +++++++++++++------ eeschema/sch_label.h | 5 +- eeschema/sch_line.cpp | 72 +++++++++------- eeschema/sch_line.h | 5 +- eeschema/sch_screen.cpp | 26 ++++-- eeschema/sch_sheet.cpp | 7 +- eeschema/sch_sheet.h | 5 +- eeschema/sch_symbol.cpp | 19 +++-- eeschema/sch_symbol.h | 5 +- eeschema/tools/sch_line_wire_bus_tool.cpp | 8 +- eeschema/tools/sch_move_tool.cpp | 8 +- 16 files changed, 252 insertions(+), 111 deletions(-) diff --git a/eeschema/dialogs/panel_eeschema_color_settings.cpp b/eeschema/dialogs/panel_eeschema_color_settings.cpp index d9de2c4c81..a2d9e4e98c 100644 --- a/eeschema/dialogs/panel_eeschema_color_settings.cpp +++ b/eeschema/dialogs/panel_eeschema_color_settings.cpp @@ -238,7 +238,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems() { KIGFX::VIEW* view = m_preview->GetView(); - std::vector endPoints; + std::vector endPointsByType; m_page = new PAGE_INFO( PAGE_INFO::Custom ); m_titleBlock = new TITLE_BLOCK; @@ -396,7 +396,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems() pin->SetNumber( wxT( "1" ) ); pin->SetName( wxT( "-" ) ); - 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 ); @@ -408,7 +408,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems() pin->SetNumber( wxT( "2" ) ); pin->SetName( wxT( "+" ) ); - 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 ); @@ -420,7 +420,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems() pin->SetNumber( wxT( "3" ) ); pin->SetName( wxT( "OUT" ) ); - endPoints.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) ); + endPointsByType.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) ); symbol->AddDrawItem( pin ); addItem( symbol ); @@ -445,16 +445,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 endPointsByPos = endPointsByType; + DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos ); + for( EDA_ITEM* item : m_previewItems ) { SCH_ITEM* sch_item = dynamic_cast( item ); if( sch_item && sch_item->IsConnectable() ) - sch_item->UpdateDanglingState( endPoints, nullptr ); + sch_item->UpdateDanglingState( endPointsByType, endPointsByPos, nullptr ); } zoomFitPreview(); diff --git a/eeschema/sch_bus_entry.cpp b/eeschema/sch_bus_entry.cpp index 37a4221f02..06f93f26ca 100644 --- a/eeschema/sch_bus_entry.cpp +++ b/eeschema/sch_bus_entry.cpp @@ -304,8 +304,9 @@ void SCH_BUS_ENTRY_BASE::Rotate( const VECTOR2I& aCenter ) } -bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath ) +bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath ) { bool previousStateStart = m_isDanglingStart; bool previousStateEnd = m_isDanglingEnd; @@ -316,9 +317,9 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& 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; @@ -336,7 +337,7 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& 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; @@ -363,17 +364,19 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& aI } -bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath ) +bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector& aItemListByType, + std::vector& 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; @@ -383,7 +386,7 @@ bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector& 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; diff --git a/eeschema/sch_bus_entry.h b/eeschema/sch_bus_entry.h index 4526c9bad4..a45e6a3f30 100644 --- a/eeschema/sch_bus_entry.h +++ b/eeschema/sch_bus_entry.h @@ -188,8 +188,9 @@ public: BITMAPS GetMenuImage() const override; - bool UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath = nullptr ) override; + bool UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath = nullptr ) override; /** * Pointer to the bus item (usually a bus wire) connected to this bus-wire @@ -233,8 +234,9 @@ public: BITMAPS GetMenuImage() const override; - bool UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath = nullptr ) override; + bool UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath = nullptr ) override; /** * Pointer to the bus items (usually bus wires) connected to this bus-bus diff --git a/eeschema/sch_item.cpp b/eeschema/sch_item.cpp index 0d0b09c38e..e91e8dde0c 100644 --- a/eeschema/sch_item.cpp +++ b/eeschema/sch_item.cpp @@ -316,3 +316,50 @@ void SCH_ITEM::Plot( PLOTTER* aPlotter, bool aBackground ) const { wxFAIL_MSG( wxT( "Plot() method not implemented for class " ) + GetClass() ); } + + +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::iterator +DANGLING_END_ITEM_HELPER::get_lower_pos( std::vector& 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::iterator +DANGLING_END_ITEM_HELPER::get_lower_type( std::vector& 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& aItemListByType, + std::vector& 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 ); +} diff --git a/eeschema/sch_item.h b/eeschema/sch_item.h index 8a6e7c2c20..1440f570d2 100644 --- a/eeschema/sch_item.h +++ b/eeschema/sch_item.h @@ -133,6 +133,20 @@ private: }; +class DANGLING_END_ITEM_HELPER +{ +public: + static std::vector::iterator + get_lower_pos( std::vector& aItemListByPos, const VECTOR2I& aPos ); + + static std::vector::iterator + get_lower_type( std::vector& aItemListByType, const DANGLING_END_T& aType ); + + /** Both contain the same information */ + static void sort_dangling_end_items( std::vector& aItemListByType, + std::vector& aItemListByPos ); +}; + typedef std::vector SCH_ITEM_SET; @@ -329,12 +343,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& aItemList, - const SCH_SHEET_PATH* aPath = nullptr ) + virtual bool UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath = nullptr ) { return false; } diff --git a/eeschema/sch_label.cpp b/eeschema/sch_label.cpp index d1bcf33907..7142b59bf6 100644 --- a/eeschema/sch_label.cpp +++ b/eeschema/sch_label.cpp @@ -868,16 +868,19 @@ bool SCH_LABEL_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy } -bool SCH_LABEL_BASE::UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath ) +bool SCH_LABEL_BASE::UpdateDanglingState( std::vector& aItemListByType, + std::vector& 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; @@ -888,33 +891,68 @@ bool SCH_LABEL_BASE::UpdateDanglingState( std::vector& 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( 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( 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 @@ -924,16 +962,9 @@ bool SCH_LABEL_BASE::UpdateDanglingState( std::vector& aItemL AddConnectionTo( *aPath, sch_item ); sch_item->AddConnectionTo( *aPath, this ); } + break; } } - break; - - default: - break; - } - - if( !m_isDangling ) - break; } if( m_isDangling ) diff --git a/eeschema/sch_label.h b/eeschema/sch_label.h index 7c39c30542..06dd180c7e 100644 --- a/eeschema/sch_label.h +++ b/eeschema/sch_label.h @@ -187,8 +187,9 @@ public: void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override; - bool UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath = nullptr ) override; + bool UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath = nullptr ) override; bool IsDangling() const override { return m_isDangling; } void SetIsDangling( bool aIsDangling ) { m_isDangling = aIsDangling; } diff --git a/eeschema/sch_line.cpp b/eeschema/sch_line.cpp index e13a590389..7229a4a6e0 100644 --- a/eeschema/sch_line.cpp +++ b/eeschema/sch_line.cpp @@ -580,44 +580,56 @@ void SCH_LINE::GetEndPoints( std::vector & aItemList ) } -bool SCH_LINE::UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath ) +bool SCH_LINE::UpdateDanglingState( std::vector& aItemListByType, + std::vector& 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; } diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h index 3559872fa1..1dcd9713bd 100644 --- a/eeschema/sch_line.h +++ b/eeschema/sch_line.h @@ -251,8 +251,9 @@ public: void GetEndPoints( std::vector& aItemList ) override; - bool UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath = nullptr ) override; + bool UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath = nullptr ) override; bool IsStartDangling() const { return m_startIsDangling; } bool IsEndDangling() const { return m_endIsDangling; } diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index 091b594bd4..3eb738e19c 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -1370,36 +1370,46 @@ void SCH_SCREEN::TestDanglingEnds( const SCH_SHEET_PATH* aPath, { PROF_TIMER timer( __FUNCTION__ ); - std::vector endPoints; + std::vector endPointsByPos; + std::vector 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(); } diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index 3500c09e70..0c3136f9e6 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -984,13 +984,14 @@ void SCH_SHEET::GetEndPoints( std::vector & aItemList ) } -bool SCH_SHEET::UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath ) +bool SCH_SHEET::UpdateDanglingState( std::vector& aItemListByType, + std::vector& 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; } diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h index f0fff99a4e..fcf072b505 100644 --- a/eeschema/sch_sheet.h +++ b/eeschema/sch_sheet.h @@ -343,8 +343,9 @@ public: void GetEndPoints( std::vector & aItemList ) override; - bool UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath = nullptr ) override; + bool UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath = nullptr ) override; bool IsConnectable() const override { return true; } diff --git a/eeschema/sch_symbol.cpp b/eeschema/sch_symbol.cpp index 8ba6c92de5..734f139f66 100644 --- a/eeschema/sch_symbol.cpp +++ b/eeschema/sch_symbol.cpp @@ -1954,8 +1954,9 @@ void SCH_SYMBOL::GetEndPoints( std::vector & aItemList ) } -bool SCH_SYMBOL::UpdateDanglingState( std::vector& aItemList, - const SCH_SHEET_PATH* aPath ) +bool SCH_SYMBOL::UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath ) { bool changed = false; @@ -1966,8 +1967,12 @@ bool SCH_SYMBOL::UpdateDanglingState( std::vector& 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 @@ -1983,17 +1988,15 @@ bool SCH_SYMBOL::UpdateDanglingState( std::vector& 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; } diff --git a/eeschema/sch_symbol.h b/eeschema/sch_symbol.h index aef86a626b..e3c9a34f58 100644 --- a/eeschema/sch_symbol.h +++ b/eeschema/sch_symbol.h @@ -662,8 +662,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& aItemList, - const SCH_SHEET_PATH* aPath = nullptr ) override; + bool UpdateDanglingState( std::vector& aItemListByType, + std::vector& aItemListByPos, + const SCH_SHEET_PATH* aPath = nullptr ) override; VECTOR2I GetPinPhysicalPosition( const LIB_PIN* Pin ) const; diff --git a/eeschema/tools/sch_line_wire_bus_tool.cpp b/eeschema/tools/sch_line_wire_bus_tool.cpp index 4dc9fc17d9..c08b8a16a5 100644 --- a/eeschema/tools/sch_line_wire_bus_tool.cpp +++ b/eeschema/tools/sch_line_wire_bus_tool.cpp @@ -406,12 +406,14 @@ SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTO getViewControls()->SetCrossHairCursorPosition( m_busUnfold.entry->GetEnd(), false ); - std::vector endPoints; + std::vector 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 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 ); diff --git a/eeschema/tools/sch_move_tool.cpp b/eeschema/tools/sch_move_tool.cpp index 93877ba22f..fa2af3bb88 100644 --- a/eeschema/tools/sch_move_tool.cpp +++ b/eeschema/tools/sch_move_tool.cpp @@ -569,8 +569,14 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent ) for( EDA_ITEM* item : selection ) static_cast( item )->GetEndPoints( internalPoints ); + std::vector endPointsByType = internalPoints; + std::vector endPointsByPos = endPointsByType; + DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, + endPointsByPos ); + for( EDA_ITEM* item : selection ) - static_cast( item )->UpdateDanglingState( internalPoints ); + static_cast( item )->UpdateDanglingState( endPointsByType, + endPointsByPos ); } // Generic setup