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 * Don't check the bounding box unless it's cached. Building it is about the same speed as
* test below and so just slows things down by doing potentially two tests. * 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 ) if( !m_closed || PointCount() < 3 )
return false; 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 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? if( m_polys.size() == 0 ) // empty set?
return false; return false;
// If there is a polygon specified, check the condition against that polygon // If there is a polygon specified, check the condition against that polygon
if( aSubpolyIndex >= 0 ) 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 // In any other case, check it against all polygons in the set
for( int polygonIdx = 0; polygonIdx < OutlineCount(); polygonIdx++ ) for( int polygonIdx = 0; polygonIdx < OutlineCount(); polygonIdx++ )
{ {
if( containsSingle( aP, polygonIdx, aIgnoreHoles, aIgnoreEdges ) ) if( containsSingle( aP, polygonIdx, aIgnoreHoles, aIgnoreEdges, aUseBBoxCaches ) )
return true; 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 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 // Check that the point is inside the outline
if( pointInPolygon( aP, m_polys[aSubpolyIndex][0], aIgnoreEdges ) ) 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), // If the point is inside a hole (and not on its edge),
// it is outside of the polygon // it is outside of the polygon
if( pointInPolygon( aP, hole, aIgnoreEdges ) ) if( pointInPolygon( aP, hole, aIgnoreEdges, aUseBBoxCaches ) )
return false; 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 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 * Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -305,6 +305,11 @@ public:
return bbox; return bbox;
} }
void GenerateBBoxCache()
{
m_bbox.Compute( m_points );
}
/** /**
* Function Collide() * Function Collide()
* *
@ -552,9 +557,11 @@ public:
* Checks if point aP lies inside a polygon (any type) defined by the line chain. * Checks if point aP lies inside a polygon (any type) defined by the line chain.
* For closed shapes only. * For closed shapes only.
* @param aPt point to check * @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). * @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() * Function PointOnEdge()

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * 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 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * @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, bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX& aClosestVertex,
int aClearance = 0 ); 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 * 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 aIgnoreHoles controls whether or not internal holes are considered
* @param aIgnoreEdges controls whether or not a check for the point lying exactly on * @param aIgnoreEdges controls whether or not a check for the point lying exactly on
* the polygon edge is made * 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 * @return true if the polygon contains the point
*/ */
bool Contains( const VECTOR2I& aP, int aSubpolyIndex = -1, bool aIgnoreHoles = false, 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) ///> Returns true if the set is empty (no polygons at all)
bool IsEmpty() const bool IsEmpty() const
@ -1118,12 +1127,6 @@ class SHAPE_POLY_SET : public SHAPE
bool IsVertexInHole( int aGlobalIdx ); bool IsVertexInHole( int aGlobalIdx );
private: private:
SHAPE_LINE_CHAIN& getContourForCorner( int aCornerId, int& aIndexWithinContour );
VECTOR2I& vertex( int aCornerId );
const VECTOR2I& cvertex( int aCornerId ) const;
void fractureSingle( POLYGON& paths ); void fractureSingle( POLYGON& paths );
void unfractureSingle ( POLYGON& path ); void unfractureSingle ( POLYGON& path );
void importTree( ClipperLib::PolyTree* tree ); void importTree( ClipperLib::PolyTree* tree );
@ -1146,7 +1149,7 @@ class SHAPE_POLY_SET : public SHAPE
const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode ); const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode );
bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath, bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath,
bool aIgnoreEdges ) const; bool aIgnoreEdges, bool aUseBBoxCaches = false ) const;
/** /**
* containsSingle function * 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 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 * @param aIgnoreEdges can be set to true to skip checking whether or not the point
* lies directly on the edge * 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 * @return bool - true if aP is inside aSubpolyIndex-th polygon; false in any other
* case. * case.
*/ */
bool containsSingle( const VECTOR2I& aP, int aSubpolyIndex, bool aIgnoreHoles = false, 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 * Operations ChamferPolygon and FilletPolygon are computed under the private chamferFillet
@ -1176,8 +1182,6 @@ class SHAPE_POLY_SET : public SHAPE
FILLETED FILLETED
}; };
/** /**
* Function chamferFilletPolygon * Function chamferFilletPolygon
* Returns the camfered or filleted version of the aIndex-th polygon in the set, depending * 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 // Remove areas that don't meet minimum-width criteria
testAreas.Inflate( -outline_half_thickness, numSegs, true ); testAreas.Inflate( -outline_half_thickness, numSegs, true );
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 ); buildThermalSpokes( aZone, thermalSpokes );
for( const SHAPE_LINE_CHAIN& spoke : 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 ); solidAreas.AddOutline( spoke );
continue; continue;
@ -714,7 +718,7 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone,
for( const SHAPE_LINE_CHAIN& other : thermalSpokes ) 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 ); solidAreas.AddOutline( spoke );
break; break;
@ -914,6 +918,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone,
} }
spoke.SetClosed( true ); spoke.SetClosed( true );
spoke.GenerateBBoxCache();
aSpokesList.push_back( std::move( spoke ) ); aSpokesList.push_back( std::move( spoke ) );
} }
} }