Implement ClearArcs() and check curved polys don't get a booleanOp
We cannot (yet) support passing several curved outlines through clipper. In these cases, the caller should ClearArcs() before processing.
This commit is contained in:
parent
260a9d0540
commit
778c64de88
|
@ -424,6 +424,13 @@ public:
|
||||||
*/
|
*/
|
||||||
const SHAPE_LINE_CHAIN Reverse() const;
|
const SHAPE_LINE_CHAIN Reverse() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all arc references in the line chain, resulting in a chain formed
|
||||||
|
* only of straight segments. Any arcs in the chain are removed and only the
|
||||||
|
* piecewise linear approximation remains.
|
||||||
|
*/
|
||||||
|
void ClearArcs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return length of the line chain in Euclidean metric.
|
* Return length of the line chain in Euclidean metric.
|
||||||
*
|
*
|
||||||
|
|
|
@ -550,9 +550,15 @@ public:
|
||||||
///< Return the area of this poly set
|
///< Return the area of this poly set
|
||||||
double Area();
|
double Area();
|
||||||
|
|
||||||
|
///< Count the number of arc shapes present
|
||||||
|
int ArcCount() const;
|
||||||
|
|
||||||
///< Appends all the arcs in this polyset to \a aArcBuffer
|
///< Appends all the arcs in this polyset to \a aArcBuffer
|
||||||
void GetArcs( std::vector<SHAPE_ARC>& aArcBuffer ) const;
|
void GetArcs( std::vector<SHAPE_ARC>& aArcBuffer ) const;
|
||||||
|
|
||||||
|
///< Removes all arc references from all the outlines and holes in the polyset
|
||||||
|
void ClearArcs();
|
||||||
|
|
||||||
///< Appends a vertex at the end of the given outline/hole (default: the last outline)
|
///< Appends a vertex at the end of the given outline/hole (default: the last outline)
|
||||||
/**
|
/**
|
||||||
* Add a new vertex to the contour indexed by \p aOutline and \p aHole (defaults to the
|
* Add a new vertex to the contour indexed by \p aOutline and \p aHole (defaults to the
|
||||||
|
|
|
@ -121,7 +121,6 @@ ClipperLib::Path SHAPE_LINE_CHAIN::convertToClipper( bool aRequiredOrientation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//TODO(SH): Adjust this into two functions: one to convert and one to split the arc into two arcs
|
|
||||||
void SHAPE_LINE_CHAIN::convertArc( ssize_t aArcIndex )
|
void SHAPE_LINE_CHAIN::convertArc( ssize_t aArcIndex )
|
||||||
{
|
{
|
||||||
if( aArcIndex < 0 )
|
if( aArcIndex < 0 )
|
||||||
|
@ -515,6 +514,13 @@ const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHAPE_LINE_CHAIN::ClearArcs()
|
||||||
|
{
|
||||||
|
for( ssize_t arcIndex = m_arcs.size() - 1; arcIndex >= 0; --arcIndex )
|
||||||
|
convertArc( arcIndex );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
long long int SHAPE_LINE_CHAIN::Length() const
|
long long int SHAPE_LINE_CHAIN::Length() const
|
||||||
{
|
{
|
||||||
long long int l = 0;
|
long long int l = 0;
|
||||||
|
|
|
@ -490,6 +490,20 @@ double SHAPE_POLY_SET::Area()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SHAPE_POLY_SET::ArcCount() const
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
for( const POLYGON& poly : m_polys )
|
||||||
|
{
|
||||||
|
for( size_t i = 0; i < poly.size(); i++ )
|
||||||
|
retval += poly[i].ArcCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHAPE_POLY_SET::GetArcs( std::vector<SHAPE_ARC>& aArcBuffer ) const
|
void SHAPE_POLY_SET::GetArcs( std::vector<SHAPE_ARC>& aArcBuffer ) const
|
||||||
{
|
{
|
||||||
for( const POLYGON& poly : m_polys )
|
for( const POLYGON& poly : m_polys )
|
||||||
|
@ -503,6 +517,16 @@ void SHAPE_POLY_SET::GetArcs( std::vector<SHAPE_ARC>& aArcBuffer ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHAPE_POLY_SET::ClearArcs()
|
||||||
|
{
|
||||||
|
for( POLYGON& poly : m_polys )
|
||||||
|
{
|
||||||
|
for( size_t i = 0; i < poly.size(); i++ )
|
||||||
|
poly[i].ClearArcs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aOtherShape,
|
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aOtherShape,
|
||||||
POLYGON_MODE aFastMode )
|
POLYGON_MODE aFastMode )
|
||||||
{
|
{
|
||||||
|
@ -513,6 +537,13 @@ void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET
|
||||||
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape,
|
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape,
|
||||||
const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode )
|
const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode )
|
||||||
{
|
{
|
||||||
|
if( ( aShape.OutlineCount() > 1 || aOtherShape.OutlineCount() > 0 )
|
||||||
|
&& ( aShape.ArcCount() > 0 || aOtherShape.ArcCount() > 0 ) )
|
||||||
|
{
|
||||||
|
wxFAIL_MSG( "Boolean ops on curved polygons are not supported. You should call "
|
||||||
|
"ClearArcs() before carrying out the boolean operation." );
|
||||||
|
}
|
||||||
|
|
||||||
ClipperLib::Clipper c;
|
ClipperLib::Clipper c;
|
||||||
|
|
||||||
c.StrictlySimple( aFastMode == PM_STRICTLY_SIMPLE );
|
c.StrictlySimple( aFastMode == PM_STRICTLY_SIMPLE );
|
||||||
|
|
|
@ -95,6 +95,16 @@ BOOST_AUTO_TEST_CASE( ArcToPolylineLargeCoords )
|
||||||
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
||||||
BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // Adding 1 point, removing 3
|
BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // Adding 1 point, removing 3
|
||||||
BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should still have three arcs
|
BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should still have three arcs
|
||||||
|
|
||||||
|
// Test ClearArcs
|
||||||
|
base_chain.SetClosed( true );
|
||||||
|
double areaPriorToArcRemoval = base_chain.Area();
|
||||||
|
base_chain.ClearArcs();
|
||||||
|
|
||||||
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
||||||
|
BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // We should have the same number of points
|
||||||
|
BOOST_CHECK_EQUAL( base_chain.ArcCount(), 0 ); // All arcs should have been removed
|
||||||
|
BOOST_CHECK_EQUAL( base_chain.Area(), areaPriorToArcRemoval ); // Area should not have changed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,9 @@ BOOST_AUTO_TEST_CASE( TestSimplify )
|
||||||
std::map<std::string, SHAPE_POLY_SET> polysToTest =
|
std::map<std::string, SHAPE_POLY_SET> polysToTest =
|
||||||
{
|
{
|
||||||
{ "Case 1: Single polygon", testData.holeyCurvedPolySingle },
|
{ "Case 1: Single polygon", testData.holeyCurvedPolySingle },
|
||||||
{ "Case 2: Multi polygon", testData.holeyCurvedPolyMulti }
|
//{ "Case 2: Multi polygon", testData.holeyCurvedPolyMulti } // This test fails right now:
|
||||||
|
// clipper seems to not handle
|
||||||
|
// multiple outlines correctly
|
||||||
};
|
};
|
||||||
|
|
||||||
for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
|
for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
|
||||||
|
@ -92,7 +94,8 @@ BOOST_AUTO_TEST_CASE( TestIntersectUnion )
|
||||||
std::map<std::string, SHAPE_POLY_SET> polysToTest = {
|
std::map<std::string, SHAPE_POLY_SET> polysToTest = {
|
||||||
{ "Case 1: Single polygon", testData.holeyCurvedPolySingle },
|
{ "Case 1: Single polygon", testData.holeyCurvedPolySingle },
|
||||||
//{ "Case 2: Multi polygon", testData.holeyCurvedPolyMulti } // This test fails right now:
|
//{ "Case 2: Multi polygon", testData.holeyCurvedPolyMulti } // This test fails right now:
|
||||||
// multiple polys unsupported
|
// clipper seems to not handle
|
||||||
|
// multiple outlines correctly
|
||||||
};
|
};
|
||||||
|
|
||||||
for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
|
for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
|
||||||
|
@ -102,6 +105,11 @@ BOOST_AUTO_TEST_CASE( TestIntersectUnion )
|
||||||
SHAPE_POLY_SET testPoly = testCase.second;
|
SHAPE_POLY_SET testPoly = testCase.second;
|
||||||
SHAPE_POLY_SET opPoly = testData.holeyCurvedPolyInter;
|
SHAPE_POLY_SET opPoly = testData.holeyCurvedPolyInter;
|
||||||
|
|
||||||
|
// Remove all arcs before any booleanOps
|
||||||
|
// @todo Remove the below two lines when boolean ops can be carried out on curved polys
|
||||||
|
opPoly.ClearArcs();
|
||||||
|
testPoly.ClearArcs();
|
||||||
|
|
||||||
BOOST_CHECK( GEOM_TEST::IsPolySetValid( testPoly ) );
|
BOOST_CHECK( GEOM_TEST::IsPolySetValid( testPoly ) );
|
||||||
BOOST_CHECK( GEOM_TEST::IsPolySetValid( opPoly ) );
|
BOOST_CHECK( GEOM_TEST::IsPolySetValid( opPoly ) );
|
||||||
|
|
||||||
|
@ -128,4 +136,36 @@ BOOST_AUTO_TEST_CASE( TestIntersectUnion )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test SHAPE_POLY_SET::ClearArcs
|
||||||
|
*/
|
||||||
|
BOOST_AUTO_TEST_CASE( TestClearArcs )
|
||||||
|
{
|
||||||
|
KI_TEST::CommonTestData testData;
|
||||||
|
|
||||||
|
std::map<std::string, SHAPE_POLY_SET> polysToTest = {
|
||||||
|
{ "Case 1: Single polygon", testData.holeyCurvedPolySingle },
|
||||||
|
{ "Case 2: Intersect polygon", testData.holeyCurvedPolyInter },
|
||||||
|
{ "Case 3: Multi polygon", testData.holeyCurvedPolyMulti }
|
||||||
|
};
|
||||||
|
|
||||||
|
for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
|
||||||
|
{
|
||||||
|
BOOST_TEST_CONTEXT( testCase.first )
|
||||||
|
{
|
||||||
|
SHAPE_POLY_SET testPoly = testCase.second;
|
||||||
|
double originalArea = testPoly.Area();
|
||||||
|
testPoly.ClearArcs();
|
||||||
|
|
||||||
|
BOOST_CHECK( GEOM_TEST::IsPolySetValid( testPoly ) );
|
||||||
|
BOOST_CHECK_EQUAL( testPoly.Area(), originalArea ); // Area should not have changed
|
||||||
|
|
||||||
|
std::vector<SHAPE_ARC> arcBuffer;
|
||||||
|
testPoly.GetArcs( arcBuffer );
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL( arcBuffer.size(), 0 ); // All arcs should have been removed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
Loading…
Reference in New Issue