Rework ruleAreas to avoid stale pointers.
1) UpdateRuleAreasInScreens() is going to reset the rule area caches on all SCH_RULE_AREAs. This means that every SCH_ITEM in the screen that *had* a rule area cache is going to get it cleared. So we might as well just up-front clear the caches of all SCH_ITEMs, avoiding the need to use the (possibly stale) pointers inside SCH_RULE_AREA::m_items. 2) UpdateRuleAreasInScreens() also sets the repaint flag on all SCH_DIRECTIVE_LABELs, so there's no need to worry about them elsewhere. 3) SCH_RULE_AREA::m_prev_items could also contain stale pointers. We avoid this one by converting it to KIIDs. Fixes https://gitlab.com/kicad/code/kicad/-/issues/21120
This commit is contained in:
+32
-68
@@ -198,21 +198,22 @@ wxString SCH_RULE_AREA::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool
|
||||
}
|
||||
|
||||
|
||||
void SCH_RULE_AREA::ResetCaches( KIGFX::SCH_VIEW* view )
|
||||
void SCH_RULE_AREA::resetCaches()
|
||||
{
|
||||
// Save the current state
|
||||
m_prev_items = m_items;
|
||||
m_prev_directives = m_directives;
|
||||
m_prev_items = m_itemIDs;
|
||||
m_prev_directives = m_directiveIDs;
|
||||
|
||||
// Reset the rule area
|
||||
clearContainedItems();
|
||||
clearDirectives( view );
|
||||
// Do NOT assume these pointers are valid.
|
||||
m_items.clear();
|
||||
m_itemIDs.clear();
|
||||
m_directives.clear();
|
||||
m_directiveIDs.clear();
|
||||
}
|
||||
|
||||
|
||||
void SCH_RULE_AREA::RefreshContainedItemsAndDirectives(
|
||||
SCH_SCREEN* screen, KIGFX::SCH_VIEW* view,
|
||||
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>>& forceUpdateRuleAreas )
|
||||
void SCH_RULE_AREA::RefreshContainedItemsAndDirectives( SCH_SCREEN* screen )
|
||||
{
|
||||
EE_RTREE& items = screen->Items();
|
||||
const BOX2I boundingBox = GetBoundingBox();
|
||||
@@ -228,13 +229,9 @@ void SCH_RULE_AREA::RefreshContainedItemsAndDirectives(
|
||||
assert( labelConnectionPoints.size() == 1 );
|
||||
|
||||
if( GetPolyShape().CollideEdge( labelConnectionPoints[0], nullptr, 5 ) )
|
||||
addDirective( label, view );
|
||||
addDirective( label );
|
||||
}
|
||||
|
||||
// If directives have changed, we need to force an update of the contained items connectivity
|
||||
if( m_directives != m_prev_directives )
|
||||
forceUpdateRuleAreas.push_back( { this, screen } );
|
||||
|
||||
// Next find any connectable items which lie within the rule area
|
||||
EE_RTREE::EE_TYPE ruleAreaItems = items.Overlapping( boundingBox );
|
||||
|
||||
@@ -280,17 +277,6 @@ void SCH_RULE_AREA::RefreshContainedItemsAndDirectives(
|
||||
}
|
||||
|
||||
|
||||
std::unordered_set<SCH_ITEM*> SCH_RULE_AREA::GetPastAndPresentContainedItems() const
|
||||
{
|
||||
std::unordered_set<SCH_ITEM*> items = m_items;
|
||||
|
||||
for( SCH_ITEM* item : m_prev_items )
|
||||
items.insert( item );
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>>
|
||||
SCH_RULE_AREA::UpdateRuleAreasInScreens( std::unordered_set<SCH_SCREEN*>& screens,
|
||||
KIGFX::SCH_VIEW* view )
|
||||
@@ -301,17 +287,26 @@ SCH_RULE_AREA::UpdateRuleAreasInScreens( std::unordered_set<SCH_SCREEN*>& screen
|
||||
{
|
||||
// First reset all item caches - must be done first to ensure two rule areas
|
||||
// on the same item don't overwrite each other's caches
|
||||
for( SCH_ITEM* ruleAreaAsItem : screen->Items().OfType( SCH_RULE_AREA_T ) )
|
||||
for( SCH_ITEM* item : screen->Items() )
|
||||
{
|
||||
SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( ruleAreaAsItem );
|
||||
ruleArea->ResetCaches( view );
|
||||
if( item->Type() == SCH_RULE_AREA_T )
|
||||
static_cast<SCH_RULE_AREA*>( item )->resetCaches();
|
||||
|
||||
if( item->Type() == SCH_DIRECTIVE_LABEL_T && view )
|
||||
view->Update( item, KIGFX::REPAINT );
|
||||
|
||||
item->ClearRuleAreasCache();
|
||||
}
|
||||
|
||||
// Secondly refresh the contained items
|
||||
for( SCH_ITEM* ruleAreaAsItem : screen->Items().OfType( SCH_RULE_AREA_T ) )
|
||||
{
|
||||
SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( ruleAreaAsItem );
|
||||
ruleArea->RefreshContainedItemsAndDirectives( screen, view, forceUpdateRuleAreas );
|
||||
|
||||
ruleArea->RefreshContainedItemsAndDirectives( screen );
|
||||
|
||||
if( ruleArea->m_directiveIDs != ruleArea->m_prev_directives )
|
||||
forceUpdateRuleAreas.push_back( { ruleArea, screen } );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,6 +326,12 @@ const std::unordered_set<SCH_DIRECTIVE_LABEL*>& SCH_RULE_AREA::GetDirectives() c
|
||||
}
|
||||
|
||||
|
||||
const std::unordered_set<KIID>& SCH_RULE_AREA::GetPastContainedItems() const
|
||||
{
|
||||
return m_prev_items;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<std::pair<wxString, SCH_ITEM*>> SCH_RULE_AREA::GetResolvedNetclasses() const
|
||||
{
|
||||
std::vector<std::pair<wxString, SCH_ITEM*>> resolvedNetclasses;
|
||||
@@ -362,19 +363,6 @@ const std::vector<std::pair<wxString, SCH_ITEM*>> SCH_RULE_AREA::GetResolvedNetc
|
||||
}
|
||||
|
||||
|
||||
void SCH_RULE_AREA::ResetDirectivesAndItems( KIGFX::SCH_VIEW* view )
|
||||
{
|
||||
for( SCH_DIRECTIVE_LABEL* label : m_directives )
|
||||
{
|
||||
label->ClearConnectedRuleAreas();
|
||||
view->Update( label, KIGFX::REPAINT );
|
||||
}
|
||||
|
||||
for( SCH_ITEM* item : m_items )
|
||||
item->ClearRuleAreasCache();
|
||||
}
|
||||
|
||||
|
||||
void SCH_RULE_AREA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
|
||||
{
|
||||
aList.emplace_back( _( "Rule Area" ), wxEmptyString );
|
||||
@@ -396,27 +384,11 @@ void SCH_RULE_AREA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PAN
|
||||
}
|
||||
|
||||
|
||||
void SCH_RULE_AREA::addDirective( SCH_DIRECTIVE_LABEL* label, KIGFX::SCH_VIEW* view )
|
||||
void SCH_RULE_AREA::addDirective( SCH_DIRECTIVE_LABEL* label )
|
||||
{
|
||||
label->AddConnectedRuleArea( this );
|
||||
m_directives.insert( label );
|
||||
|
||||
if( view )
|
||||
view->Update( label, KIGFX::REPAINT );
|
||||
}
|
||||
|
||||
|
||||
void SCH_RULE_AREA::clearDirectives( KIGFX::SCH_VIEW* view )
|
||||
{
|
||||
for( SCH_DIRECTIVE_LABEL* label : m_directives )
|
||||
{
|
||||
label->ClearConnectedRuleAreas();
|
||||
|
||||
if( view )
|
||||
view->Update( label, KIGFX::REPAINT );
|
||||
}
|
||||
|
||||
m_directives.clear();
|
||||
m_directiveIDs.insert( label->m_Uuid );
|
||||
}
|
||||
|
||||
|
||||
@@ -424,15 +396,7 @@ void SCH_RULE_AREA::addContainedItem( SCH_ITEM* item )
|
||||
{
|
||||
item->AddRuleAreaToCache( this );
|
||||
m_items.insert( item );
|
||||
}
|
||||
|
||||
|
||||
void SCH_RULE_AREA::clearContainedItems()
|
||||
{
|
||||
for( SCH_ITEM* item : m_items )
|
||||
item->ClearRuleAreasCache();
|
||||
|
||||
m_items.clear();
|
||||
m_itemIDs.insert( item->m_Uuid );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-20
@@ -95,16 +95,8 @@ public:
|
||||
|
||||
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override;
|
||||
|
||||
/// Reset all item and directive caches, saving the current state first.
|
||||
void ResetCaches( KIGFX::SCH_VIEW* view );
|
||||
|
||||
/// Refresh the list of items which this rule area affects.
|
||||
void RefreshContainedItemsAndDirectives(
|
||||
SCH_SCREEN* screen, KIGFX::SCH_VIEW* view,
|
||||
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>>& forceUpdateRuleAreas );
|
||||
|
||||
/// Fetch all items which were, or are, within the rule area.
|
||||
std::unordered_set<SCH_ITEM*> GetPastAndPresentContainedItems() const;
|
||||
void RefreshContainedItemsAndDirectives( SCH_SCREEN* screen );
|
||||
|
||||
/// Update all rule area connectvity / caches in the given sheet paths.
|
||||
///
|
||||
@@ -115,6 +107,8 @@ public:
|
||||
/// Return a set of all items contained within the rule area.
|
||||
const std::unordered_set<SCH_ITEM*>& GetContainedItems() const;
|
||||
|
||||
const std::unordered_set<KIID>& GetPastContainedItems() const;
|
||||
|
||||
/// Return the set of all directive labels attached to the rule area border.
|
||||
const std::unordered_set<SCH_DIRECTIVE_LABEL*>& GetDirectives() const;
|
||||
|
||||
@@ -123,24 +117,18 @@ public:
|
||||
/// @return The resolved netclass (if any), and the SCH_ITEM providing the declaration.
|
||||
const std::vector<std::pair<wxString, SCH_ITEM*>> GetResolvedNetclasses() const;
|
||||
|
||||
/// Clear and resets items and directives attached to this rule area.
|
||||
void ResetDirectivesAndItems( KIGFX::SCH_VIEW* view );
|
||||
|
||||
/// Get the message panel info for the rule area.
|
||||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
|
||||
|
||||
protected:
|
||||
/// Add a directive label which applies to items within ths rule area.
|
||||
void addDirective( SCH_DIRECTIVE_LABEL* label, KIGFX::SCH_VIEW* view );
|
||||
|
||||
/// Clear the list of directives.
|
||||
void clearDirectives( KIGFX::SCH_VIEW* view );
|
||||
void addDirective( SCH_DIRECTIVE_LABEL* label );
|
||||
|
||||
/// Add an item to the list of items which this rule area affects.
|
||||
void addContainedItem( SCH_ITEM* item );
|
||||
|
||||
/// Clear the list of items which this rule area affects.
|
||||
void clearContainedItems();
|
||||
/// Reset all item and directive caches, saving the current state first.
|
||||
void resetCaches();
|
||||
|
||||
protected:
|
||||
bool m_excludedFromSim;
|
||||
@@ -150,15 +138,17 @@ protected:
|
||||
|
||||
/// All #SCH_ITEM objects currently contained or intersecting the rule area.
|
||||
std::unordered_set<SCH_ITEM*> m_items;
|
||||
std::unordered_set<KIID> m_itemIDs;
|
||||
|
||||
/// All #SCH_DIRECTIVE_LABEL objectss attached to the rule area border.
|
||||
std::unordered_set<SCH_DIRECTIVE_LABEL*> m_directives;
|
||||
std::unordered_set<KIID> m_directiveIDs;
|
||||
|
||||
/// All #SCH_ITEM objectss contained or intersecting the rule area in the previous update.
|
||||
std::unordered_set<SCH_ITEM*> m_prev_items;
|
||||
std::unordered_set<KIID> m_prev_items;
|
||||
|
||||
/// All SCH_DIRECTIVE_LABEL objects attached to the rule area border in the previous update.
|
||||
std::unordered_set<SCH_DIRECTIVE_LABEL*> m_prev_directives;
|
||||
std::unordered_set<KIID> m_prev_directives;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+19
-13
@@ -1382,10 +1382,6 @@ void SCHEMATIC::RecalculateConnections( SCH_COMMIT* aCommit, SCH_CLEANUP_FLAGS a
|
||||
if( item->Type() == SCH_RULE_AREA_T )
|
||||
{
|
||||
SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( item );
|
||||
|
||||
// Clear item and directive associations for this rule area
|
||||
ruleArea->ResetDirectivesAndItems( aSchView );
|
||||
|
||||
changed_rule_areas.insert( { ruleArea, screen } );
|
||||
}
|
||||
else if( item->IsConnectable() )
|
||||
@@ -1408,11 +1404,24 @@ void SCHEMATIC::RecalculateConnections( SCH_COMMIT* aCommit, SCH_CLEANUP_FLAGS a
|
||||
|
||||
// If a SCH_RULE_AREA was changed, we need to add all past and present contained items to
|
||||
// update their connectivity
|
||||
for( const std::pair<SCH_RULE_AREA*, SCH_SCREEN*>& changedRuleArea : changed_rule_areas )
|
||||
{
|
||||
for( SCH_ITEM* containedItem : changedRuleArea.first->GetPastAndPresentContainedItems() )
|
||||
addItemToChangeSet( { containedItem, nullptr, changedRuleArea.second } );
|
||||
}
|
||||
std::map<KIID, EDA_ITEM*> itemMap;
|
||||
list.FillItemMap( itemMap );
|
||||
|
||||
auto addPastAndPresentContainedItems =
|
||||
[&]( SCH_RULE_AREA* changedRuleArea, SCH_SCREEN* screen )
|
||||
{
|
||||
for( const KIID& pastItem : changedRuleArea->GetPastContainedItems() )
|
||||
{
|
||||
if( itemMap.contains( pastItem ) )
|
||||
addItemToChangeSet( { static_cast<SCH_ITEM*>( itemMap[pastItem] ), nullptr, screen } );
|
||||
}
|
||||
|
||||
for( SCH_ITEM* containedItem : changedRuleArea->GetContainedItems() )
|
||||
addItemToChangeSet( { containedItem, nullptr, screen } );
|
||||
};
|
||||
|
||||
for( const auto& [changedRuleArea, screen] : changed_rule_areas )
|
||||
addPastAndPresentContainedItems( changedRuleArea, screen );
|
||||
|
||||
// Add all changed items, and associated items, to the change set
|
||||
for( CHANGED_ITEM& changed_item_data : changed_connectable_items )
|
||||
@@ -1436,10 +1445,7 @@ void SCHEMATIC::RecalculateConnections( SCH_COMMIT* aCommit, SCH_CLEANUP_FLAGS a
|
||||
std::vector<SHAPE*> borderShapes = ruleArea->MakeEffectiveShapes( true );
|
||||
|
||||
if( ruleArea->GetPolyShape().CollideEdge( labelConnectionPoints[0], nullptr, 5 ) )
|
||||
{
|
||||
for( SCH_ITEM* containedItem : ruleArea->GetPastAndPresentContainedItems() )
|
||||
addItemToChangeSet( { containedItem, nullptr, changed_item_data.screen } );
|
||||
}
|
||||
addPastAndPresentContainedItems( ruleArea, changed_item_data.screen );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user