Allow cancelling of zone fills.
Fixes https://gitlab.com/kicad/code/kicad/issues/5035
This commit is contained in:
parent
77fd384da5
commit
3cf5db3ce5
|
@ -30,7 +30,8 @@ PROGRESS_REPORTER::PROGRESS_REPORTER( int aNumPhases ) :
|
||||||
m_phase( 0 ),
|
m_phase( 0 ),
|
||||||
m_numPhases( aNumPhases ),
|
m_numPhases( aNumPhases ),
|
||||||
m_progress( 0 ),
|
m_progress( 0 ),
|
||||||
m_maxProgress( 1 )
|
m_maxProgress( 1 ),
|
||||||
|
m_cancelled( false )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +91,10 @@ bool PROGRESS_REPORTER::KeepRefreshing( bool aWait )
|
||||||
while( m_progress < m_maxProgress && m_maxProgress > 0 )
|
while( m_progress < m_maxProgress && m_maxProgress > 0 )
|
||||||
{
|
{
|
||||||
if( !updateUI() )
|
if( !updateUI() )
|
||||||
|
{
|
||||||
|
m_cancelled.store( true );
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
wxMilliSleep( 20 );
|
wxMilliSleep( 20 );
|
||||||
}
|
}
|
||||||
|
@ -98,7 +102,13 @@ bool PROGRESS_REPORTER::KeepRefreshing( bool aWait )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return updateUI();
|
if( !updateUI() )
|
||||||
|
{
|
||||||
|
m_cancelled.store( true );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ class PROGRESS_REPORTER
|
||||||
*/
|
*/
|
||||||
virtual void SetTitle( const wxString& aTitle ) {}
|
virtual void SetTitle( const wxString& aTitle ) {}
|
||||||
|
|
||||||
|
bool IsCancelled() const { return m_cancelled.load(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -105,6 +106,7 @@ class PROGRESS_REPORTER
|
||||||
std::atomic_int m_numPhases;
|
std::atomic_int m_numPhases;
|
||||||
std::atomic_int m_progress;
|
std::atomic_int m_progress;
|
||||||
std::atomic_int m_maxProgress;
|
std::atomic_int m_maxProgress;
|
||||||
|
std::atomic_bool m_cancelled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -159,8 +159,8 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atomic<size_t> nextItem( 0 );
|
std::atomic<size_t> nextItem( 0 );
|
||||||
size_t parallelThreadCount =
|
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
|
||||||
std::min<size_t>( std::thread::hardware_concurrency(), aZones.size() );
|
aZones.size() );
|
||||||
std::vector<std::future<size_t>> returns( parallelThreadCount );
|
std::vector<std::future<size_t>> returns( parallelThreadCount );
|
||||||
|
|
||||||
auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
|
auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
|
||||||
|
@ -184,8 +184,13 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
zone->SetIsFilled( true );
|
zone->SetIsFilled( true );
|
||||||
|
|
||||||
if( m_progressReporter )
|
if( m_progressReporter )
|
||||||
|
{
|
||||||
m_progressReporter->AdvanceProgress();
|
m_progressReporter->AdvanceProgress();
|
||||||
|
|
||||||
|
if( m_progressReporter->IsCancelled() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,8 +211,13 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if( m_progressReporter )
|
if( m_progressReporter )
|
||||||
|
{
|
||||||
m_progressReporter->KeepRefreshing();
|
m_progressReporter->KeepRefreshing();
|
||||||
|
|
||||||
|
if( m_progressReporter->IsCancelled() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
|
status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
|
||||||
} while( status != std::future_status::ready );
|
} while( status != std::future_status::ready );
|
||||||
}
|
}
|
||||||
|
@ -219,11 +229,29 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
m_progressReporter->AdvancePhase();
|
m_progressReporter->AdvancePhase();
|
||||||
m_progressReporter->Report( _( "Removing insulated copper islands..." ) );
|
m_progressReporter->Report( _( "Removing insulated copper islands..." ) );
|
||||||
m_progressReporter->KeepRefreshing();
|
m_progressReporter->KeepRefreshing();
|
||||||
|
|
||||||
|
if( m_progressReporter->IsCancelled() )
|
||||||
|
{
|
||||||
|
if( m_commit )
|
||||||
|
m_commit->Revert();
|
||||||
|
|
||||||
|
connectivity->SetProgressReporter( nullptr );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connectivity->SetProgressReporter( m_progressReporter );
|
connectivity->SetProgressReporter( m_progressReporter );
|
||||||
connectivity->FindIsolatedCopperIslands( islandsList );
|
connectivity->FindIsolatedCopperIslands( islandsList );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
{
|
||||||
|
if( m_commit )
|
||||||
|
m_commit->Revert();
|
||||||
|
|
||||||
|
connectivity->SetProgressReporter( nullptr );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Now remove insulated copper islands and islands outside the board edge
|
// Now remove insulated copper islands and islands outside the board edge
|
||||||
bool outOfDate = false;
|
bool outOfDate = false;
|
||||||
|
|
||||||
|
@ -285,6 +313,15 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
|
|
||||||
if( aCheck && zone.m_zone->GetHashValue( layer ) != poly.GetHash() )
|
if( aCheck && zone.m_zone->GetHashValue( layer ) != poly.GetHash() )
|
||||||
outOfDate = true;
|
outOfDate = true;
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
{
|
||||||
|
if( m_commit )
|
||||||
|
m_commit->Revert();
|
||||||
|
|
||||||
|
connectivity->SetProgressReporter( nullptr );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +351,6 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
m_progressReporter->SetMaxProgress( toFill.size() );
|
m_progressReporter->SetMaxProgress( toFill.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nextItem = 0;
|
nextItem = 0;
|
||||||
|
|
||||||
auto tri_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
|
auto tri_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
|
||||||
|
@ -327,7 +363,12 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
num++;
|
num++;
|
||||||
|
|
||||||
if( m_progressReporter )
|
if( m_progressReporter )
|
||||||
|
{
|
||||||
m_progressReporter->AdvanceProgress();
|
m_progressReporter->AdvanceProgress();
|
||||||
|
|
||||||
|
if( m_progressReporter->IsCancelled() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
|
@ -347,8 +388,13 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if( m_progressReporter )
|
if( m_progressReporter )
|
||||||
|
{
|
||||||
m_progressReporter->KeepRefreshing();
|
m_progressReporter->KeepRefreshing();
|
||||||
|
|
||||||
|
if( m_progressReporter->IsCancelled() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
|
status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
|
||||||
} while( status != std::future_status::ready );
|
} while( status != std::future_status::ready );
|
||||||
}
|
}
|
||||||
|
@ -359,6 +405,15 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
||||||
m_progressReporter->AdvancePhase();
|
m_progressReporter->AdvancePhase();
|
||||||
m_progressReporter->Report( _( "Committing changes..." ) );
|
m_progressReporter->Report( _( "Committing changes..." ) );
|
||||||
m_progressReporter->KeepRefreshing();
|
m_progressReporter->KeepRefreshing();
|
||||||
|
|
||||||
|
if( m_progressReporter->IsCancelled() )
|
||||||
|
{
|
||||||
|
if( m_commit )
|
||||||
|
m_commit->Revert();
|
||||||
|
|
||||||
|
connectivity->SetProgressReporter( nullptr );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connectivity->SetProgressReporter( nullptr );
|
connectivity->SetProgressReporter( nullptr );
|
||||||
|
@ -751,18 +806,30 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
if( s_DumpZonesWhenFilling )
|
if( s_DumpZonesWhenFilling )
|
||||||
dumper->BeginGroup( "clipper-zone" );
|
dumper->BeginGroup( "clipper-zone" );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
knockoutThermalReliefs( aZone, aLayer, aRawPolys );
|
knockoutThermalReliefs( aZone, aLayer, aRawPolys );
|
||||||
|
|
||||||
if( s_DumpZonesWhenFilling )
|
if( s_DumpZonesWhenFilling )
|
||||||
dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" );
|
dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
buildCopperItemClearances( aZone, aLayer, clearanceHoles );
|
buildCopperItemClearances( aZone, aLayer, clearanceHoles );
|
||||||
|
|
||||||
if( s_DumpZonesWhenFilling )
|
if( s_DumpZonesWhenFilling )
|
||||||
dumper->Write( &aRawPolys, "clearance holes" );
|
dumper->Write( &aRawPolys, "clearance holes" );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
buildThermalSpokes( aZone, aLayer, thermalSpokes );
|
buildThermalSpokes( aZone, aLayer, thermalSpokes );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
// Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
|
// Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
|
||||||
// because the "real" subtract-clearance-holes has to be done after the spokes are added.
|
// because the "real" subtract-clearance-holes has to be done after the spokes are added.
|
||||||
static const bool USE_BBOX_CACHES = true;
|
static const bool USE_BBOX_CACHES = true;
|
||||||
|
@ -776,9 +843,13 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
testAreas.Inflate( half_min_width - epsilon, numSegs, intermediatecornerStrategy );
|
testAreas.Inflate( half_min_width - epsilon, numSegs, intermediatecornerStrategy );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
// Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed
|
// Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed
|
||||||
// things up a bit.
|
// things up a bit.
|
||||||
testAreas.BuildBBoxCaches();
|
testAreas.BuildBBoxCaches();
|
||||||
|
int interval = 0;
|
||||||
|
|
||||||
for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
|
for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
|
||||||
{
|
{
|
||||||
|
@ -791,6 +862,14 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( interval++ > 400 )
|
||||||
|
{
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Hit-test against other spokes
|
// Hit-test against other spokes
|
||||||
for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
|
for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
|
||||||
{
|
{
|
||||||
|
@ -802,6 +881,9 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
// Ensure previous changes (adding thermal stubs) do not add
|
// Ensure previous changes (adding thermal stubs) do not add
|
||||||
// filled areas outside the zone boundary
|
// filled areas outside the zone boundary
|
||||||
aRawPolys.BooleanIntersection( aSmoothedOutline, SHAPE_POLY_SET::PM_FAST );
|
aRawPolys.BooleanIntersection( aSmoothedOutline, SHAPE_POLY_SET::PM_FAST );
|
||||||
|
@ -810,6 +892,9 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
if( s_DumpZonesWhenFilling )
|
if( s_DumpZonesWhenFilling )
|
||||||
dumper->Write( &aRawPolys, "solid-areas-with-thermal-spokes" );
|
dumper->Write( &aRawPolys, "solid-areas-with-thermal-spokes" );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
|
aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
|
||||||
// Prune features that don't meet minimum-width criteria
|
// Prune features that don't meet minimum-width criteria
|
||||||
if( half_min_width - epsilon > epsilon )
|
if( half_min_width - epsilon > epsilon )
|
||||||
|
@ -818,6 +903,9 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
if( s_DumpZonesWhenFilling )
|
if( s_DumpZonesWhenFilling )
|
||||||
dumper->Write( &aRawPolys, "solid-areas-before-hatching" );
|
dumper->Write( &aRawPolys, "solid-areas-before-hatching" );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
// Now remove the non filled areas due to the hatch pattern
|
// Now remove the non filled areas due to the hatch pattern
|
||||||
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
|
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
|
||||||
addHatchFillTypeOnZone( aZone, aLayer, aRawPolys );
|
addHatchFillTypeOnZone( aZone, aLayer, aRawPolys );
|
||||||
|
@ -825,6 +913,9 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
|
||||||
if( s_DumpZonesWhenFilling )
|
if( s_DumpZonesWhenFilling )
|
||||||
dumper->Write( &aRawPolys, "solid-areas-after-hatching" );
|
dumper->Write( &aRawPolys, "solid-areas-after-hatching" );
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return;
|
||||||
|
|
||||||
// Re-inflate after pruning of areas that don't meet minimum-width criteria
|
// Re-inflate after pruning of areas that don't meet minimum-width criteria
|
||||||
if( aZone->GetFilledPolysUseThickness() )
|
if( aZone->GetFilledPolysUseThickness() )
|
||||||
{
|
{
|
||||||
|
@ -874,10 +965,13 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
|
||||||
if ( !aZone->BuildSmoothedPoly( smoothedPoly, &colinearCorners ) )
|
if ( !aZone->BuildSmoothedPoly( smoothedPoly, &colinearCorners ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if( m_progressReporter && m_progressReporter->IsCancelled() )
|
||||||
|
return false;
|
||||||
|
|
||||||
if( aZone->IsOnCopperLayer() )
|
if( aZone->IsOnCopperLayer() )
|
||||||
{
|
{
|
||||||
computeRawFilledArea(
|
computeRawFilledArea( aZone, aLayer, smoothedPoly, &colinearCorners, aRawPolys,
|
||||||
aZone, aLayer, smoothedPoly, &colinearCorners, aRawPolys, aFinalPolys );
|
aFinalPolys );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue