pcbnew: Remove all threading from dynamic ratsnest

The last remaining threaded operation in dynamic ratsnest was the
recalculation of the dynamic connectivity map.  Because we do not
require any of the extra features of the connectivity map, we can get
away with a lightweight move of the anchors to update the ratsnest.  The
resulting connectivity tree is not valid but it is not needed for the
ratsnest, which only needs a list of nets/anchors.
This commit is contained in:
Seth Hillbrand 2020-08-14 17:33:27 -07:00
parent ec5040aff5
commit b8b3d5c16d
7 changed files with 86 additions and 83 deletions

View File

@ -167,8 +167,6 @@ private:
void searchConnections();
void update();
void propagateConnections( BOARD_COMMIT* aCommit = nullptr );
template <class Container, class BItem>
@ -281,7 +279,6 @@ public:
void MarkNetAsDirty( int aNet );
void SetProgressReporter( PROGRESS_REPORTER* aReporter );
};
/**

View File

@ -95,6 +95,12 @@ void CONNECTIVITY_DATA::Build( const std::vector<BOARD_ITEM*>& aItems )
}
void CONNECTIVITY_DATA::Move( const VECTOR2I& aDelta )
{
m_connAlgo->ForEachAnchor( [&aDelta] ( CN_ANCHOR& anchor ) { anchor.Move( aDelta ); } );
}
void CONNECTIVITY_DATA::updateRatsnest()
{
#ifdef PROFILE
@ -255,24 +261,19 @@ void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_
}
void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems )
void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems,
const CONNECTIVITY_DATA* aDynamicData )
{
if( !aDynamicData )
return;
m_dynamicRatsnest.clear();
if( std::none_of( aItems.begin(), aItems.end(), []( const BOARD_ITEM* aItem )
{ return( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_PAD_T ||
aItem->Type() == PCB_ARC_T || aItem->Type() == PCB_ZONE_AREA_T ||
aItem->Type() == PCB_MODULE_T || aItem->Type() == PCB_VIA_T ); } ) )
// This gets connections between the stationary board and the
// moving selection
for( unsigned int nc = 1; nc < aDynamicData->m_nets.size(); nc++ )
{
return ;
}
CONNECTIVITY_DATA connData( aItems, true );
BlockRatsnestItems( aItems );
for( unsigned int nc = 1; nc < connData.m_nets.size(); nc++ )
{
auto dynNet = connData.m_nets[nc];
auto dynNet = aDynamicData->m_nets[nc];
if( dynNet->GetNodeCount() != 0 )
{
@ -291,6 +292,7 @@ void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>&
}
}
// This gets the ratsnest for internal connections in the moving set
const auto& edges = GetRatsnestForItems( aItems );
for( const auto& edge : edges )

View File

@ -125,6 +125,15 @@ public:
*/
bool Update( BOARD_ITEM* aItem );
/**
* Moves the connectivity list anchors. N.B., this does not move the bounding
* boxes for the the RTree, so the use of this function will invalidate the
* connectivity data for uses other than the dynamic ratsnest
*
* @param aDelta vector for movement of the tree
*/
void Move( const VECTOR2I& aDelta );
/**
* Function Clear()
* Erases the connectivity database.
@ -208,7 +217,8 @@ public:
* Calculates the temporary dynamic ratsnest (i.e. the ratsnest lines that)
* for the set of items aItems.
*/
void ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems );
void ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems,
const CONNECTIVITY_DATA* aDynamicData );
const std::vector<RN_DYNAMIC_LINE>& GetDynamicRatsnest() const
{
@ -257,6 +267,13 @@ public:
private:
void updateRatsnest();
/**
* Updates the item positions without modifying the dirtyNet flag. This is valid only when the
* item list contains all elements in the connectivity database
* @param aItems List of items with new positions
*/
void updateItemPositions( const std::vector<BOARD_ITEM*>& aItems );
void addRatsnestCluster( const std::shared_ptr<CN_CLUSTER>& aCluster );
std::shared_ptr<CN_CONNECTIVITY_ALGO> m_connAlgo;

View File

@ -81,6 +81,11 @@ public:
return m_pos;
}
void Move( const VECTOR2I& aPos )
{
m_pos += aPos;
}
const unsigned int Dist( const CN_ANCHOR& aSecond )
{
return ( m_pos - aSecond.Pos() ).EuclideanNorm();

View File

@ -390,6 +390,7 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
// Main loop: keep receiving events
do
{
VECTOR2I movement;
editFrame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
@ -421,7 +422,7 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
controls->ForceCursorPosition( true, m_cursor );
selection.SetReferencePoint( m_cursor );
VECTOR2I movement( m_cursor - prevPos );
movement = m_cursor - prevPos;
prevPos = m_cursor;
totalMovement += movement;
@ -494,7 +495,7 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
// start moving with the reference point attached to the cursor
grid.SetAuxAxes( false );
auto delta = m_cursor - selection.GetReferencePoint();
movement = m_cursor - selection.GetReferencePoint();
// Drag items to the current cursor position
for( EDA_ITEM* item : selection )
@ -503,7 +504,7 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
if( item->GetParent() && item->GetParent()->IsSelected() )
continue;
static_cast<BOARD_ITEM*>( item )->Move( delta );
static_cast<BOARD_ITEM*>( item )->Move( movement );
}
selection.SetReferencePoint( m_cursor );
@ -550,7 +551,7 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
}
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_toolMgr->RunAction( PCB_ACTIONS::updateLocalRatsnest, false );
m_toolMgr->RunAction( PCB_ACTIONS::updateLocalRatsnest, false, new VECTOR2I( movement ) );
}
else if( evt->IsCancelInteractive() || evt->IsActivate() )
@ -615,14 +616,11 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
// If canceled, we need to remove the dynamic ratsnest from the screen
if( restore_state )
{
m_toolMgr->RunAction( PCB_ACTIONS::hideDynamicRatsnest, true );
m_commit->Revert();
}
else
{
m_commit->Push( _( "Drag" ) );
}
m_toolMgr->RunAction( PCB_ACTIONS::hideDynamicRatsnest, true );
if( unselect )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@ -1292,7 +1290,7 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
});
}
}
item->Move( translation );
switch( rotationAnchor )
@ -1407,7 +1405,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
case PCB_GROUP_T:
dupe_item = static_cast<PCB_GROUP*>( orig_item )->DeepDuplicate();
break;
default:
// Silently drop other items (such as footprint texts) from duplication
break;

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -38,8 +38,7 @@ PCB_INSPECTION_TOOL::PCB_INSPECTION_TOOL() :
{
m_probingSchToPcb = false;
m_lastNetcode = -1;
m_slowRatsnest = false;
m_dynamicData = nullptr;
}
@ -103,10 +102,6 @@ bool PCB_INSPECTION_TOOL::Init()
selectionTool->GetToolMenu().AddSubMenu( netSubMenu );
menu.AddMenu( netSubMenu.get(), SELECTION_CONDITIONS::OnlyTypes( connectedTypes ) );
m_ratsnestTimer.SetOwner( this );
Connect( m_ratsnestTimer.GetId(), wxEVT_TIMER,
wxTimerEventHandler( PCB_INSPECTION_TOOL::ratsnestTimer ), NULL, this );
return true;
}
@ -429,6 +424,8 @@ int PCB_INSPECTION_TOOL::LocalRatsnestTool( const TOOL_EVENT& aEvent )
int PCB_INSPECTION_TOOL::UpdateSelectionRatsnest( const TOOL_EVENT& aEvent )
{
VECTOR2I* delta = aEvent.Parameter<VECTOR2I*>();
auto selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
auto& selection = selectionTool->GetSelection();
auto connectivity = getModel<BOARD>()->GetConnectivity();
@ -436,62 +433,30 @@ int PCB_INSPECTION_TOOL::UpdateSelectionRatsnest( const TOOL_EVENT& aEvent )
if( selection.Empty() )
{
connectivity->ClearDynamicRatsnest();
}
else if( m_slowRatsnest )
{
// Compute ratsnest only when user stops dragging for a moment
connectivity->HideDynamicRatsnest();
m_ratsnestTimer.Start( 20 );
delete m_dynamicData;
m_dynamicData = nullptr;
}
else
{
// Check how much time doest it take to calculate ratsnest
PROF_COUNTER counter;
calculateSelectionRatsnest();
counter.Stop();
// If it is too slow, then switch to 'slow ratsnest' mode when
// ratsnest is calculated when user stops dragging items for a moment
if( counter.msecs() > 25 )
{
m_slowRatsnest = true;
connectivity->HideDynamicRatsnest();
}
calculateSelectionRatsnest( *delta );
}
delete delta;
return 0;
}
int PCB_INSPECTION_TOOL::HideDynamicRatsnest( const TOOL_EVENT& aEvent )
{
getModel<BOARD>()->GetConnectivity()->HideDynamicRatsnest();
m_slowRatsnest = false;
getModel<BOARD>()->GetConnectivity()->ClearDynamicRatsnest();
delete m_dynamicData;
m_dynamicData = nullptr;
return 0;
}
void PCB_INSPECTION_TOOL::ratsnestTimer( wxTimerEvent& aEvent )
{
auto connectivity = getModel<BOARD>()->GetConnectivity();
m_ratsnestTimer.Stop();
/// Check how much time does it take to calculate ratsnest
PROF_COUNTER counter;
calculateSelectionRatsnest();
counter.Stop();
/// If the ratsnest is fast enough, turn the slow ratsnest off
if( counter.msecs() <= 25 )
m_slowRatsnest = false;
m_frame->GetCanvas()->RedrawRatsnest();
m_frame->GetCanvas()->Refresh();
}
void PCB_INSPECTION_TOOL::calculateSelectionRatsnest()
void PCB_INSPECTION_TOOL::calculateSelectionRatsnest( const VECTOR2I& aDelta )
{
SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
SELECTION& selection = selectionTool->GetSelection();
@ -515,7 +480,25 @@ void PCB_INSPECTION_TOOL::calculateSelectionRatsnest()
}
}
connectivity->ComputeDynamicRatsnest( items );
if( items.empty() || std::none_of( items.begin(), items.end(), []( const BOARD_ITEM* aItem )
{ return( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_PAD_T ||
aItem->Type() == PCB_ARC_T || aItem->Type() == PCB_ZONE_AREA_T ||
aItem->Type() == PCB_MODULE_T || aItem->Type() == PCB_VIA_T ); } ) )
{
return;
}
if( !m_dynamicData )
{
m_dynamicData = new CONNECTIVITY_DATA( items, true );
connectivity->BlockRatsnestItems( items );
}
else
{
m_dynamicData->Move( aDelta );
}
connectivity->ComputeDynamicRatsnest( items, m_dynamicData );
}

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -24,13 +24,14 @@
#ifndef __BOARD_STATISTICS_TOOL_H
#define __BOARD_STATISTICS_TOOL_H
#include <dialogs/dialog_board_statistics.h>
#include <dialogs/dialog_select_net_from_list.h>
#include <pcb_edit_frame.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_tool_base.h>
class CONNECTIVITY_DATA;
/**
* PCB_INSPECTION_TOOL
*
@ -93,7 +94,7 @@ private:
void ratsnestTimer( wxTimerEvent& aEvent );
///> Recalculates dynamic ratsnest for the current selection
void calculateSelectionRatsnest();
void calculateSelectionRatsnest( const VECTOR2I& aDelta );
bool highlightNet( const VECTOR2D& aPosition, bool aUseSelection );
@ -110,11 +111,11 @@ private:
bool m_probingSchToPcb; // Recursion guard when cross-probing to EESchema
int m_lastNetcode; // Used for toggling between last two highlighted nets
bool m_slowRatsnest; // Indicates current selection ratsnest will be slow to calculate
wxTimer m_ratsnestTimer; // Timer to initiate lazy ratsnest calculation (ie: when slow)
CONNECTIVITY_DATA* m_dynamicData; // Cached connectivity data from the selection
std::unique_ptr<DIALOG_SELECT_NET_FROM_LIST> m_listNetsDialog;
DIALOG_SELECT_NET_FROM_LIST::SETTINGS m_listNetsDialogSettings;
};
#endif //__BOARD_STATISTICS_TOOL_H