QA: Test arc to polylines - this has a bug
Add unit test of SHAPE_ARC::ConvertToPolyline.
This function has a bug when the arc is of zero radius. This
test shows the bug, but does not fix it yet.
(cherry picked from commit ce84c19a38
)
This commit is contained in:
parent
d18b12c1a3
commit
98f78f534c
|
@ -31,6 +31,7 @@
|
|||
#include <geometry/shape_poly_set.h>
|
||||
|
||||
#include <unit_test_utils/numeric.h>
|
||||
#include <unit_test_utils/unit_test_utils.h>
|
||||
|
||||
/**
|
||||
* @brief Utility functions for testing geometry functions.
|
||||
|
@ -81,7 +82,7 @@ bool IsInQuadrant( const VECTOR2<T>& aPoint, QUADRANT aQuadrant )
|
|||
/*
|
||||
* @Brief Check if both ends of a segment are in Quadrant 1
|
||||
*/
|
||||
bool SegmentCompletelyInQuadrant( const SEG& aSeg, QUADRANT aQuadrant )
|
||||
inline bool SegmentCompletelyInQuadrant( const SEG& aSeg, QUADRANT aQuadrant )
|
||||
{
|
||||
return IsInQuadrant( aSeg.A, aQuadrant)
|
||||
&& IsInQuadrant( aSeg.B, aQuadrant );
|
||||
|
@ -90,7 +91,7 @@ bool SegmentCompletelyInQuadrant( const SEG& aSeg, QUADRANT aQuadrant )
|
|||
/*
|
||||
* @brief Check if at least one end of the segment is in Quadrant 1
|
||||
*/
|
||||
bool SegmentEndsInQuadrant( const SEG& aSeg, QUADRANT aQuadrant )
|
||||
inline bool SegmentEndsInQuadrant( const SEG& aSeg, QUADRANT aQuadrant )
|
||||
{
|
||||
return IsInQuadrant( aSeg.A, aQuadrant )
|
||||
|| IsInQuadrant( aSeg.B, aQuadrant );
|
||||
|
@ -99,14 +100,66 @@ bool SegmentEndsInQuadrant( const SEG& aSeg, QUADRANT aQuadrant )
|
|||
/*
|
||||
* @brief Check if a segment is entirely within a certain radius of a point.
|
||||
*/
|
||||
bool SegmentCompletelyWithinRadius( const SEG& aSeg, const VECTOR2I& aPt,
|
||||
const int aRadius )
|
||||
inline bool SegmentCompletelyWithinRadius( const SEG& aSeg, const VECTOR2I& aPt, const int aRadius )
|
||||
{
|
||||
// This is true iff both ends of the segment are within the radius
|
||||
return ( ( aSeg.A - aPt ).EuclideanNorm() < aRadius )
|
||||
&& ( ( aSeg.B - aPt ).EuclideanNorm() < aRadius );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that two points are the given distance apart, within the given tolerance.
|
||||
*
|
||||
* @tparam T the dimension type
|
||||
* @param aPtA the first point
|
||||
* @param aPtB the second point
|
||||
* @param aExpDist the expected distance
|
||||
* @param aTol the permitted tolerance
|
||||
*/
|
||||
template <typename T>
|
||||
bool IsPointAtDistance( const VECTOR2<T>& aPtA, const VECTOR2<T>& aPtB, T aExpDist, T aTol )
|
||||
{
|
||||
const int dist = ( aPtB - aPtA ).EuclideanNorm();
|
||||
const bool ok = KI_TEST::IsWithin( dist, aExpDist, aTol );
|
||||
|
||||
if( !ok )
|
||||
{
|
||||
BOOST_TEST_INFO( "Points not at expected distance: distance is " << dist << ", expected "
|
||||
<< aExpDist );
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate for checking a set of points is within a certain tolerance of
|
||||
* a circle
|
||||
* @param aPoints the points to check
|
||||
* @param aCentre the circle centre
|
||||
* @param aRad the circle radius
|
||||
* @param aTolEnds the tolerance for the endpoint-centre distance
|
||||
* @return true if predicate met
|
||||
*/
|
||||
template <typename T>
|
||||
bool ArePointsNearCircle(
|
||||
const std::vector<VECTOR2<T>>& aPoints, const VECTOR2<T>& aCentre, T aRad, T aTol )
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for( unsigned i = 0; i < aPoints.size(); ++i )
|
||||
{
|
||||
if( !IsPointAtDistance( aPoints[i], aCentre, aRad, aTol ) )
|
||||
{
|
||||
BOOST_TEST_INFO( "Point " << i << " " << aPoints[i] << " is not within tolerance ("
|
||||
<< aTol << ") of radius (" << aRad << ") from centre point "
|
||||
<< aCentre );
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check if two vectors are perpendicular
|
||||
*
|
||||
|
@ -135,7 +188,7 @@ bool ArePerpendicular( const VECTOR2<T>& a, const VECTOR2<T>& b, double aToleran
|
|||
* @param aSize: the side width (must be divisible by 2 if want to avoid rounding)
|
||||
* @param aCentre: the centre of the square
|
||||
*/
|
||||
SHAPE_LINE_CHAIN MakeSquarePolyLine( int aSize, const VECTOR2I& aCentre )
|
||||
inline SHAPE_LINE_CHAIN MakeSquarePolyLine( int aSize, const VECTOR2I& aCentre )
|
||||
{
|
||||
SHAPE_LINE_CHAIN polyLine;
|
||||
|
||||
|
@ -154,8 +207,7 @@ SHAPE_LINE_CHAIN MakeSquarePolyLine( int aSize, const VECTOR2I& aCentre )
|
|||
/*
|
||||
* @brief Fillet every polygon in a set and return a new set
|
||||
*/
|
||||
SHAPE_POLY_SET FilletPolySet( SHAPE_POLY_SET& aPolySet, int aRadius,
|
||||
int aError )
|
||||
inline SHAPE_POLY_SET FilletPolySet( SHAPE_POLY_SET& aPolySet, int aRadius, int aError )
|
||||
{
|
||||
SHAPE_POLY_SET filletedPolySet;
|
||||
|
||||
|
@ -169,6 +221,27 @@ SHAPE_POLY_SET FilletPolySet( SHAPE_POLY_SET& aPolySet, int aRadius,
|
|||
return filletedPolySet;
|
||||
}
|
||||
|
||||
} // namespace GEOM_TEST
|
||||
|
||||
BOOST_TEST_PRINT_NAMESPACE_OPEN
|
||||
{
|
||||
template <>
|
||||
struct print_log_value<SHAPE_LINE_CHAIN>
|
||||
{
|
||||
inline void operator()( std::ostream& os, const SHAPE_LINE_CHAIN& c )
|
||||
{
|
||||
os << "SHAPE_LINE_CHAIN: " << c.PointCount() << " points: [\n";
|
||||
|
||||
for( int i = 0; i < c.PointCount(); ++i )
|
||||
{
|
||||
os << " " << i << ": " << c.CPoint( i ) << "\n";
|
||||
}
|
||||
|
||||
os << "]";
|
||||
}
|
||||
};
|
||||
}
|
||||
BOOST_TEST_PRINT_NAMESPACE_CLOSE
|
||||
|
||||
|
||||
#endif // GEOM_TEST_UTILS_H
|
|
@ -23,10 +23,13 @@
|
|||
|
||||
#include <geometry/shape_arc.h>
|
||||
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
#include <unit_test_utils/geometry.h>
|
||||
#include <unit_test_utils/numeric.h>
|
||||
#include <unit_test_utils/unit_test_utils.h>
|
||||
|
||||
#include "geom_test_utils.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( ShapeArc )
|
||||
|
||||
|
@ -281,4 +284,96 @@ BOOST_AUTO_TEST_CASE( BasicCPAGeom )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
struct ARC_TO_POLYLINE_CASE
|
||||
{
|
||||
std::string m_ctx_name;
|
||||
ARC_CENTRE_PT_ANGLE m_geom;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Predicate for checking a polyline has all the points on (near) a circle of
|
||||
* given centre and radius
|
||||
* @param aPolyline the polyline to check
|
||||
* @param aCentre the circle centre
|
||||
* @param aRad the circle radius
|
||||
* @param aTolEnds the tolerance for the endpoint-centre distance
|
||||
* @return true if predicate met
|
||||
*/
|
||||
bool ArePolylinePointsNearCircle(
|
||||
const SHAPE_LINE_CHAIN& aPolyline, const VECTOR2I& aCentre, int aRad, int aTolEnds )
|
||||
{
|
||||
std::vector<VECTOR2I> points;
|
||||
|
||||
for( int i = 0; i < aPolyline.PointCount(); ++i )
|
||||
{
|
||||
points.push_back( aPolyline.CPoint( i ) );
|
||||
}
|
||||
|
||||
return GEOM_TEST::ArePointsNearCircle( points, aCentre, aRad, aTolEnds );
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXPECTED_FAILURES
|
||||
|
||||
// Failure in zero-radius case
|
||||
BOOST_AUTO_TEST_CASE( ArcToPolyline, *boost::unit_test::expected_failures( 1 ) )
|
||||
{
|
||||
const std::vector<ARC_TO_POLYLINE_CASE> cases = {
|
||||
{
|
||||
"Zero rad",
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
180,
|
||||
},
|
||||
},
|
||||
{
|
||||
"Semicircle",
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ -10, 0 },
|
||||
180,
|
||||
},
|
||||
},
|
||||
{
|
||||
"Larger semicircle",
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ -1000, 0 },
|
||||
180,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const int width = 0;
|
||||
const double accuracy = 1.0;
|
||||
|
||||
for( const auto& c : cases )
|
||||
{
|
||||
BOOST_TEST_CONTEXT( c.m_ctx_name )
|
||||
{
|
||||
const SHAPE_ARC this_arc{ c.m_geom.m_center_point, c.m_geom.m_start_point,
|
||||
c.m_geom.m_center_angle, width };
|
||||
|
||||
const SHAPE_LINE_CHAIN chain = this_arc.ConvertToPolyline( accuracy );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Polyline has " << chain.PointCount() << " points" );
|
||||
|
||||
BOOST_CHECK_EQUAL( chain.CPoint( 0 ), c.m_geom.m_start_point );
|
||||
|
||||
const int radius = ( c.m_geom.m_center_point - c.m_geom.m_start_point ).EuclideanNorm();
|
||||
const int tol = 2;
|
||||
|
||||
BOOST_CHECK_PREDICATE( ArePolylinePointsNearCircle,
|
||||
( chain )( c.m_geom.m_center_point )( radius )( tol ) );
|
||||
|
||||
// TODO: check midpoints are near circle too
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_EXPECTED_FAILURES
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Reference in New Issue