Performance improvement for zone filling.

This commit is contained in:
Jeff Young 2019-07-05 23:45:57 +01:00
parent 50f6844e71
commit 7ee6afeace
5 changed files with 56 additions and 26 deletions

View File

@ -349,12 +349,14 @@ int SHAPE_LINE_CHAIN::PathLength( const VECTOR2I& aP ) const
}
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aPt, int aAccuracy ) const
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUseBBoxCache ) const
{
/*
* Don't check the bounding box. Building it is about the same speed as the rigorous
* test below and so just slows things down by doing potentially two tests.
* Don't check the bounding box unless it's cached. Building it is about the same speed as
* the rigorous test below and so just slows things down by doing potentially two tests.
*/
if( aUseBBoxCache && !m_bbox.Contains( aPt ) )
return false;
if( !m_closed || PointCount() < 3 )
return false;

View File

@ -1391,20 +1391,32 @@ bool SHAPE_POLY_SET::CollideEdge( const VECTOR2I& aPoint,
}
void SHAPE_POLY_SET::BuildBBoxCaches()
{
for( int polygonIdx = 0; polygonIdx < OutlineCount(); polygonIdx++ )
{
Outline( polygonIdx ).GenerateBBoxCache();
for( int holeIdx = 0; holeIdx < HoleCount( polygonIdx ); holeIdx++ )
Hole( polygonIdx, holeIdx ).GenerateBBoxCache();
}
}
bool SHAPE_POLY_SET::Contains( const VECTOR2I& aP, int aSubpolyIndex, bool aIgnoreHoles,
bool aIgnoreEdges ) const
bool aIgnoreEdges, bool aUseBBoxCaches ) const
{
if( m_polys.size() == 0 ) // empty set?
return false;
// If there is a polygon specified, check the condition against that polygon
if( aSubpolyIndex >= 0 )
return containsSingle( aP, aSubpolyIndex, aIgnoreHoles, aIgnoreEdges );
return containsSingle( aP, aSubpolyIndex, aIgnoreHoles, aIgnoreEdges, aUseBBoxCaches );
// In any other case, check it against all polygons in the set
for( int polygonIdx = 0; polygonIdx < OutlineCount(); polygonIdx++ )
{
if( containsSingle( aP, polygonIdx, aIgnoreHoles, aIgnoreEdges ) )
if( containsSingle( aP, polygonIdx, aIgnoreHoles, aIgnoreEdges, aUseBBoxCaches ) )
return true;
}
@ -1431,7 +1443,7 @@ void SHAPE_POLY_SET::RemoveVertex( VERTEX_INDEX aIndex )
bool SHAPE_POLY_SET::containsSingle( const VECTOR2I& aP, int aSubpolyIndex, bool aIgnoreHoles,
bool aIgnoreEdges ) const
bool aIgnoreEdges, bool aUseBBoxCaches ) const
{
// Check that the point is inside the outline
if( pointInPolygon( aP, m_polys[aSubpolyIndex][0], aIgnoreEdges ) )
@ -1445,7 +1457,7 @@ bool SHAPE_POLY_SET::containsSingle( const VECTOR2I& aP, int aSubpolyIndex, bool
// If the point is inside a hole (and not on its edge),
// it is outside of the polygon
if( pointInPolygon( aP, hole, aIgnoreEdges ) )
if( pointInPolygon( aP, hole, aIgnoreEdges, aUseBBoxCaches ) )
return false;
}
}
@ -1458,9 +1470,9 @@ bool SHAPE_POLY_SET::containsSingle( const VECTOR2I& aP, int aSubpolyIndex, bool
bool SHAPE_POLY_SET::pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath,
bool aIgnoreEdges ) const
bool aIgnoreEdges, bool aUseBBoxCaches ) const
{
return aPath.PointInside( aP, aIgnoreEdges ? 1 : 0 );
return aPath.PointInside( aP, aIgnoreEdges ? 1 : 0, aUseBBoxCaches );
}

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (C) 2013-2017
* Copyright (C) 2013-2019
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -305,6 +305,11 @@ public:
return bbox;
}
void GenerateBBoxCache()
{
m_bbox.Compute( m_points );
}
/**
* Function Collide()
*
@ -552,9 +557,11 @@ public:
* Checks if point aP lies inside a polygon (any type) defined by the line chain.
* For closed shapes only.
* @param aPt point to check
* @param aUseBBoxCache gives better peformance if the bounding boxe caches have been
* generated.
* @return true if the point is inside the shape (edge is not treated as being inside).
*/
bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0 ) const;
bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0, bool aUseBBoxCache = false ) const;
/**
* Function PointOnEdge()

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 CERN
* Copyright (C) 2015-2019 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
*
@ -971,6 +971,12 @@ class SHAPE_POLY_SET : public SHAPE
bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX& aClosestVertex,
int aClearance = 0 );
/**
* Constructs BBoxCaches for Contains(), below. These caches MUST be built before a
* group of calls to Contains(). They are NOT kept up-to-date by editing actions.
*/
void BuildBBoxCaches();
/**
* Returns true if a given subpolygon contains the point aP
*
@ -979,10 +985,13 @@ class SHAPE_POLY_SET : public SHAPE
* @param aIgnoreHoles controls whether or not internal holes are considered
* @param aIgnoreEdges controls whether or not a check for the point lying exactly on
* the polygon edge is made
* @param aUseBBoxCaches gives faster performance when multiple calls are made with no
* editing in between, but the caller MUST cache the bbox caches
* before calling (via BuildBBoxCaches(), above)
* @return true if the polygon contains the point
*/
bool Contains( const VECTOR2I& aP, int aSubpolyIndex = -1, bool aIgnoreHoles = false,
bool aIgnoreEdges = false ) const;
bool aIgnoreEdges = false, bool aUseBBoxCaches = false ) const;
///> Returns true if the set is empty (no polygons at all)
bool IsEmpty() const
@ -1118,12 +1127,6 @@ class SHAPE_POLY_SET : public SHAPE
bool IsVertexInHole( int aGlobalIdx );
private:
SHAPE_LINE_CHAIN& getContourForCorner( int aCornerId, int& aIndexWithinContour );
VECTOR2I& vertex( int aCornerId );
const VECTOR2I& cvertex( int aCornerId ) const;
void fractureSingle( POLYGON& paths );
void unfractureSingle ( POLYGON& path );
void importTree( ClipperLib::PolyTree* tree );
@ -1146,7 +1149,7 @@ class SHAPE_POLY_SET : public SHAPE
const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode );
bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath,
bool aIgnoreEdges ) const;
bool aIgnoreEdges, bool aUseBBoxCaches = false ) const;
/**
* containsSingle function
@ -1159,11 +1162,14 @@ class SHAPE_POLY_SET : public SHAPE
* @param aIgnoreHoles can be set to true to ignore internal holes in the polygon
* @param aIgnoreEdges can be set to true to skip checking whether or not the point
* lies directly on the edge
* @param aUseBBoxCaches gives faster performance when multiple calls are made with no
* editing in between, but the caller MUST cache the bbox caches
* before calling (via BuildBBoxCaches(), above)
* @return bool - true if aP is inside aSubpolyIndex-th polygon; false in any other
* case.
*/
bool containsSingle( const VECTOR2I& aP, int aSubpolyIndex, bool aIgnoreHoles = false,
bool aIgnoreEdges = false ) const;
bool aIgnoreEdges = false, bool aUseBBoxCaches = false ) const;
/**
* Operations ChamferPolygon and FilletPolygon are computed under the private chamferFillet
@ -1176,8 +1182,6 @@ class SHAPE_POLY_SET : public SHAPE
FILLETED
};
/**
* Function chamferFilletPolygon
* Returns the camfered or filleted version of the aIndex-th polygon in the set, depending

View File

@ -701,12 +701,16 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone,
// Remove areas that don't meet minimum-width criteria
testAreas.Inflate( -outline_half_thickness, numSegs, true );
testAreas.Inflate( outline_half_thickness, numSegs, true );
testAreas.BuildBBoxCaches();
static const bool USE_BBOX_CACHES = true;
buildThermalSpokes( aZone, thermalSpokes );
for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
{
if( testAreas.Contains( spoke.CPoint( 3 ), -1, false, true ) )
const VECTOR2I& testPt = spoke.CPoint( 3 );
if( testAreas.Contains( testPt, -1, false, true, USE_BBOX_CACHES ) )
{
solidAreas.AddOutline( spoke );
continue;
@ -714,7 +718,7 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone,
for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
{
if( &other != &spoke && other.PointInside( spoke.CPoint( 3 ), 1 ) )
if( &other != &spoke && other.PointInside( testPt, 1, USE_BBOX_CACHES ) )
{
solidAreas.AddOutline( spoke );
break;
@ -914,6 +918,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone,
}
spoke.SetClosed( true );
spoke.GenerateBBoxCache();
aSpokesList.push_back( std::move( spoke ) );
}
}