Performance enhancements for connectivity.
1) Generate SHAPE_POLY_SET triangulation by outline so they can be shared between connectivity system and other clients. 2) Don't add items to connectivity when reading board; we're going to do a total rebuild anyway. 3) Use multithreading when caching triangulation.
This commit is contained in:
parent
98b9c6e2a1
commit
5c9e718407
|
@ -125,7 +125,7 @@ public:
|
|||
TRIANGULATED_POLYGON* parent;
|
||||
};
|
||||
|
||||
TRIANGULATED_POLYGON();
|
||||
TRIANGULATED_POLYGON( int aSourceOutline );
|
||||
TRIANGULATED_POLYGON( const TRIANGULATED_POLYGON& aOther );
|
||||
~TRIANGULATED_POLYGON();
|
||||
|
||||
|
@ -154,6 +154,8 @@ public:
|
|||
|
||||
size_t GetTriangleCount() const { return m_triangles.size(); }
|
||||
|
||||
int GetSourceOutlineIndex() const { return m_sourceOutline; }
|
||||
|
||||
std::deque<TRI>& Triangles() { return m_triangles; }
|
||||
const std::deque<TRI>& Triangles() const { return m_triangles; }
|
||||
|
||||
|
@ -169,6 +171,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
int m_sourceOutline;
|
||||
std::deque<TRI> m_triangles;
|
||||
std::deque<VECTOR2I> m_vertices;
|
||||
};
|
||||
|
|
|
@ -2246,8 +2246,7 @@ bool SHAPE_POLY_SET::IsTriangulationUpToDate() const
|
|||
}
|
||||
|
||||
|
||||
static void partitionPolyIntoRegularCellGrid( const SHAPE_POLY_SET& aPoly, int aSize,
|
||||
SHAPE_POLY_SET& aOut )
|
||||
static SHAPE_POLY_SET partitionPolyIntoRegularCellGrid( const SHAPE_POLY_SET& aPoly, int aSize )
|
||||
{
|
||||
BOX2I bb = aPoly.BBox();
|
||||
|
||||
|
@ -2255,7 +2254,7 @@ static void partitionPolyIntoRegularCellGrid( const SHAPE_POLY_SET& aPoly, int a
|
|||
double h = bb.GetHeight();
|
||||
|
||||
if( w == 0.0 || h == 0.0 )
|
||||
return;
|
||||
return aPoly;
|
||||
|
||||
int n_cells_x, n_cells_y;
|
||||
|
||||
|
@ -2306,13 +2305,13 @@ static void partitionPolyIntoRegularCellGrid( const SHAPE_POLY_SET& aPoly, int a
|
|||
ps1.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
ps2.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
aOut = ps1;
|
||||
|
||||
for( int i = 0; i < ps2.OutlineCount(); i++ )
|
||||
aOut.AddOutline( ps2.COutline( i ) );
|
||||
ps1.AddOutline( ps2.COutline( i ) );
|
||||
|
||||
if( !aOut.OutlineCount() )
|
||||
aOut = aPoly;
|
||||
if( ps1.OutlineCount() )
|
||||
return ps1;
|
||||
else
|
||||
return aPoly;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2338,46 +2337,60 @@ void SHAPE_POLY_SET::CacheTriangulation( bool aPartition )
|
|||
if( !recalculate )
|
||||
return;
|
||||
|
||||
SHAPE_POLY_SET tmpSet;
|
||||
auto triangulate =
|
||||
[]( SHAPE_POLY_SET& polySet, int forOutline,
|
||||
std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>& dest )
|
||||
{
|
||||
bool triangulationValid = false;
|
||||
|
||||
while( polySet.OutlineCount() > 0 )
|
||||
{
|
||||
if( !dest.empty() && dest.back()->GetTriangleCount() == 0 )
|
||||
dest.erase( dest.end() - 1 );
|
||||
|
||||
dest.push_back( std::make_unique<TRIANGULATED_POLYGON>( forOutline ) );
|
||||
PolygonTriangulation tess( *dest.back() );
|
||||
|
||||
// If the tessellation fails, we re-fracture the polygon, which will
|
||||
// first simplify the system before fracturing and removing the holes
|
||||
// This may result in multiple, disjoint polygons.
|
||||
if( !tess.TesselatePolygon( polySet.Polygon( 0 ).front() ) )
|
||||
{
|
||||
polySet.Fracture( PM_FAST );
|
||||
triangulationValid = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
polySet.DeletePolygon( 0 );
|
||||
triangulationValid = true;
|
||||
}
|
||||
|
||||
return triangulationValid;
|
||||
};
|
||||
|
||||
m_triangulatedPolys.clear();
|
||||
m_triangulationValid = true;
|
||||
|
||||
if( aPartition )
|
||||
{
|
||||
// This partitions into regularly-sized grids (1cm in Pcbnew)
|
||||
SHAPE_POLY_SET flattened( *this );
|
||||
flattened.ClearArcs();
|
||||
partitionPolyIntoRegularCellGrid( flattened, 1e7, tmpSet );
|
||||
for( int ii = 0; ii < OutlineCount(); ++ii )
|
||||
{
|
||||
// This partitions into regularly-sized grids (1cm in Pcbnew)
|
||||
SHAPE_POLY_SET flattened( Outline( ii ) );
|
||||
flattened.ClearArcs();
|
||||
SHAPE_POLY_SET partitions = partitionPolyIntoRegularCellGrid( flattened, 1e7 );
|
||||
|
||||
m_triangulationValid &= triangulate( partitions, ii, m_triangulatedPolys );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpSet = *this;
|
||||
SHAPE_POLY_SET tmpSet( *this );
|
||||
|
||||
if( tmpSet.HasHoles() )
|
||||
tmpSet.Fracture( PM_FAST );
|
||||
}
|
||||
|
||||
m_triangulatedPolys.clear();
|
||||
m_triangulationValid = false;
|
||||
|
||||
while( tmpSet.OutlineCount() > 0 )
|
||||
{
|
||||
if( !m_triangulatedPolys.empty() && m_triangulatedPolys.back()->GetTriangleCount() == 0 )
|
||||
m_triangulatedPolys.erase( m_triangulatedPolys.end() - 1 );
|
||||
|
||||
m_triangulatedPolys.push_back( std::make_unique<TRIANGULATED_POLYGON>() );
|
||||
PolygonTriangulation tess( *m_triangulatedPolys.back() );
|
||||
|
||||
// If the tessellation fails, we re-fracture the polygon, which will
|
||||
// first simplify the system before fracturing and removing the holes
|
||||
// This may result in multiple, disjoint polygons.
|
||||
if( !tess.TesselatePolygon( tmpSet.Polygon( 0 ).front() ) )
|
||||
{
|
||||
tmpSet.Fracture( PM_FAST );
|
||||
m_triangulationValid = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
tmpSet.DeletePolygon( 0 );
|
||||
m_triangulationValid = true;
|
||||
m_triangulationValid = triangulate( tmpSet, -1, m_triangulatedPolys );
|
||||
}
|
||||
|
||||
if( m_triangulationValid )
|
||||
|
@ -2496,6 +2509,7 @@ void SHAPE_POLY_SET::TRIANGULATED_POLYGON::AddTriangle( int a, int b, int c )
|
|||
|
||||
SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRIANGULATED_POLYGON( const TRIANGULATED_POLYGON& aOther )
|
||||
{
|
||||
m_sourceOutline = aOther.m_sourceOutline;
|
||||
m_vertices = aOther.m_vertices;
|
||||
m_triangles = aOther.m_triangles;
|
||||
|
||||
|
@ -2506,6 +2520,7 @@ SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRIANGULATED_POLYGON( const TRIANGULATED_P
|
|||
|
||||
SHAPE_POLY_SET::TRIANGULATED_POLYGON& SHAPE_POLY_SET::TRIANGULATED_POLYGON::operator=( const TRIANGULATED_POLYGON& aOther )
|
||||
{
|
||||
m_sourceOutline = aOther.m_sourceOutline;
|
||||
m_vertices = aOther.m_vertices;
|
||||
m_triangles = aOther.m_triangles;
|
||||
|
||||
|
@ -2516,7 +2531,8 @@ SHAPE_POLY_SET::TRIANGULATED_POLYGON& SHAPE_POLY_SET::TRIANGULATED_POLYGON::oper
|
|||
}
|
||||
|
||||
|
||||
SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRIANGULATED_POLYGON()
|
||||
SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRIANGULATED_POLYGON( int aSourceOutline ) :
|
||||
m_sourceOutline( aSourceOutline )
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
#include <iterator>
|
||||
#include <thread>
|
||||
#include <drc/drc_rtree.h>
|
||||
#include <pcb_base_frame.h>
|
||||
#include <board_design_settings.h>
|
||||
|
@ -55,6 +56,7 @@
|
|||
#include <tool/selection_conditions.h>
|
||||
#include <convert_shape_list_to_polygon.h>
|
||||
#include <wx/log.h>
|
||||
#include <progress_reporter.h>
|
||||
|
||||
// This is an odd place for this, but CvPcb won't link if it's in board_item.cpp like I first
|
||||
// tried it.
|
||||
|
@ -619,6 +621,44 @@ void BOARD::SetZoneSettings( const ZONE_SETTINGS& aSettings )
|
|||
}
|
||||
|
||||
|
||||
void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter )
|
||||
{
|
||||
if( aReporter )
|
||||
aReporter->Report( _( "Tessellating copper zones..." ) );
|
||||
|
||||
std::atomic<size_t> next( 0 );
|
||||
std::atomic<size_t> count_done( 0 );
|
||||
size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
|
||||
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
{
|
||||
std::thread t = std::thread(
|
||||
[ this, &count_done, &next ]( )
|
||||
{
|
||||
for( size_t i = next.fetch_add( 1 ); i < m_zones.size(); i = next.fetch_add( 1 ) )
|
||||
m_zones[i]->CacheTriangulation();
|
||||
|
||||
count_done++;
|
||||
} );
|
||||
|
||||
t.detach();
|
||||
}
|
||||
|
||||
// Finalize the triangulation threads
|
||||
while( count_done < parallelThreadCount )
|
||||
{
|
||||
if( aReporter && m_zones.size() )
|
||||
{
|
||||
aReporter->SetCurrentProgress( (double) count_done / (double) m_zones.size() );
|
||||
aReporter->KeepRefreshing();
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 30 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
|
||||
{
|
||||
if( aBoardItem == nullptr )
|
||||
|
@ -704,10 +744,12 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
|
|||
|
||||
aBoardItem->SetParent( this );
|
||||
aBoardItem->ClearEditFlags();
|
||||
m_connectivity->Add( aBoardItem );
|
||||
|
||||
if( aMode != ADD_MODE::BULK_INSERT && aMode != ADD_MODE::BULK_APPEND )
|
||||
{
|
||||
m_connectivity->Add( aBoardItem );
|
||||
InvokeListeners( &BOARD_LISTENER::OnBoardItemAdded, *this, aBoardItem );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -308,6 +308,8 @@ public:
|
|||
*/
|
||||
void FinalizeBulkRemove( std::vector<BOARD_ITEM*>& aRemovedItems );
|
||||
|
||||
void CacheTriangulation( PROGRESS_REPORTER* aReporter = nullptr );
|
||||
|
||||
/**
|
||||
* Get the first footprint on the board or nullptr.
|
||||
*
|
||||
|
|
|
@ -438,9 +438,6 @@ void CN_CONNECTIVITY_ALGO::Build( BOARD* aBoard, PROGRESS_REPORTER* aReporter )
|
|||
|
||||
delta = std::max( delta, size / 10 );
|
||||
|
||||
if( aReporter )
|
||||
aReporter->KeepRefreshing( false );
|
||||
|
||||
for( ZONE* zone : aBoard->Zones() )
|
||||
{
|
||||
Add( zone );
|
||||
|
|
|
@ -86,11 +86,16 @@ bool CONNECTIVITY_DATA::Update( BOARD_ITEM* aItem )
|
|||
|
||||
void CONNECTIVITY_DATA::Build( BOARD* aBoard, PROGRESS_REPORTER* aReporter )
|
||||
{
|
||||
aBoard->CacheTriangulation( aReporter );
|
||||
|
||||
std::unique_lock<KISPINLOCK> lock( m_lock, std::try_to_lock );
|
||||
|
||||
if( !lock )
|
||||
return;
|
||||
|
||||
if( aReporter )
|
||||
aReporter->Report( _( "Updating nets..." ) );
|
||||
|
||||
m_connAlgo.reset( new CN_CONNECTIVITY_ALGO );
|
||||
m_connAlgo->Build( aBoard, aReporter );
|
||||
|
||||
|
|
|
@ -292,12 +292,19 @@ public:
|
|||
{
|
||||
const SHAPE_POLY_SET& fill = aParent->GetFilledPolysList( aLayer );
|
||||
|
||||
m_triangulatedSubpoly = SHAPE_POLY_SET( fill.COutline( aSubpolyIndex ) );
|
||||
m_triangulatedSubpoly.CacheTriangulation();
|
||||
if( !fill.IsTriangulationUpToDate() )
|
||||
const_cast<SHAPE_POLY_SET&>( fill ).CacheTriangulation();
|
||||
|
||||
for( size_t ii = 0; ii < m_triangulatedSubpoly.TriangulatedPolyCount(); ++ii )
|
||||
m_triangulatedPoly = fill;
|
||||
|
||||
for( unsigned int ii = 0; ii < m_triangulatedPoly.TriangulatedPolyCount(); ++ii )
|
||||
{
|
||||
for( auto& tri : m_triangulatedSubpoly.TriangulatedPolygon( ii )->Triangles() )
|
||||
const auto* triangleSet = m_triangulatedPoly.TriangulatedPolygon( ii );
|
||||
|
||||
if( triangleSet->GetSourceOutlineIndex() != aSubpolyIndex )
|
||||
continue;
|
||||
|
||||
for( const SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI& tri : triangleSet->Triangles() )
|
||||
{
|
||||
BOX2I bbox = tri.BBox();
|
||||
const int mmin[2] = { bbox.GetX(), bbox.GetY() };
|
||||
|
@ -369,7 +376,7 @@ private:
|
|||
std::vector<VECTOR2I> m_testOutlinePoints;
|
||||
int m_subpolyIndex;
|
||||
PCB_LAYER_ID m_layer;
|
||||
SHAPE_POLY_SET m_triangulatedSubpoly;
|
||||
SHAPE_POLY_SET m_triangulatedPoly;
|
||||
RTree<const SHAPE*, int, 2, double> m_rTree;
|
||||
};
|
||||
|
||||
|
|
|
@ -929,7 +929,6 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
|||
std::vector<ZONE*> toFill;
|
||||
|
||||
// Rebuild list of nets (full ratsnest rebuild)
|
||||
progressReporter.Report( _( "Updating nets" ) );
|
||||
GetBoard()->BuildConnectivity( &progressReporter );
|
||||
|
||||
// Load project settings after setting up board; some of them depend on the nets list
|
||||
|
@ -970,7 +969,6 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
|||
if( filler.Fill( toFill ) )
|
||||
{
|
||||
commit.Push( _( "Convert Zone(s)" ) );
|
||||
progressReporter.Report( _( "Updating nets" ) );
|
||||
GetBoard()->BuildConnectivity( &progressReporter );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,23 +182,7 @@ void PCB_DRAW_PANEL_GAL::DisplayBoard( BOARD* aBoard, PROGRESS_REPORTER* aReport
|
|||
{
|
||||
m_view->Clear();
|
||||
|
||||
auto zones = aBoard->Zones();
|
||||
std::atomic<size_t> next( 0 );
|
||||
std::atomic<size_t> count_done( 0 );
|
||||
size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
|
||||
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
{
|
||||
std::thread t = std::thread( [ &count_done, &next, &zones ]( )
|
||||
{
|
||||
for( size_t i = next.fetch_add( 1 ); i < zones.size(); i = next.fetch_add( 1 ) )
|
||||
zones[i]->CacheTriangulation();
|
||||
|
||||
count_done++;
|
||||
} );
|
||||
|
||||
t.detach();
|
||||
}
|
||||
aBoard->CacheTriangulation();
|
||||
|
||||
if( m_drawingSheet )
|
||||
m_drawingSheet->SetFileName( TO_UTF8( aBoard->GetFileName() ) );
|
||||
|
@ -219,15 +203,6 @@ void PCB_DRAW_PANEL_GAL::DisplayBoard( BOARD* aBoard, PROGRESS_REPORTER* aReport
|
|||
for( PCB_MARKER* marker : aBoard->Markers() )
|
||||
m_view->Add( marker );
|
||||
|
||||
// Finalize the triangulation threads
|
||||
while( count_done < parallelThreadCount )
|
||||
{
|
||||
if( aReporter )
|
||||
aReporter->KeepRefreshing();
|
||||
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 30 ) );
|
||||
}
|
||||
|
||||
// Load zones
|
||||
for( ZONE* zone : aBoard->Zones() )
|
||||
m_view->Add( zone );
|
||||
|
|
|
@ -157,7 +157,6 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRepo
|
|||
if( filler.Fill( toFill ) )
|
||||
{
|
||||
reporter->AdvancePhase();
|
||||
reporter->Report( _( "Updating nets..." ) );
|
||||
board()->GetConnectivity()->Build( board(), reporter.get() );
|
||||
|
||||
commit.Push( _( "Fill Zone(s)" ), true, true, false );
|
||||
|
@ -215,7 +214,6 @@ int ZONE_FILLER_TOOL::ZoneFill( const TOOL_EVENT& aEvent )
|
|||
if( filler.Fill( toFill ) )
|
||||
{
|
||||
reporter->AdvancePhase();
|
||||
reporter->Report( _( "Updating nets..." ) );
|
||||
board()->GetConnectivity()->Build( board(), reporter.get() );
|
||||
|
||||
commit.Push( _( "Fill Zone(s)" ), true, true, false );
|
||||
|
|
Loading…
Reference in New Issue