48 int aNSamples = 10000 )
50 const double a = aMajorR;
51 const double b = aMinorR;
52 const double cp = std::cos( aRotation.AsRadians() );
53 const double sp = std::sin( aRotation.AsRadians() );
55 double tStart = aIsArc ? aStartAngle.AsRadians() : 0.0;
56 double tEnd = aIsArc ? aEndAngle.AsRadians() : 2.0 *
M_PI;
61 double minX = std::numeric_limits<double>::max();
62 double maxX = std::numeric_limits<double>::lowest();
63 double minY = std::numeric_limits<double>::max();
64 double maxY = std::numeric_limits<double>::lowest();
66 for(
int i = 0; i <= aNSamples; ++i )
68 const double t = tStart + ( tEnd - tStart ) * i / aNSamples;
69 const double ct = std::cos( t );
70 const double st = std::sin( t );
71 const double x = aCenter.x + a * ct * cp - b * st * sp;
72 const double y = aCenter.y + a * ct * sp + b * st * cp;
74 minX = std::min( minX, x );
75 maxX = std::max( maxX, x );
76 minY = std::min( minY, y );
77 maxY = std::max( maxY, y );
80 const int ix =
static_cast<int>( std::floor( minX ) );
81 const int iy =
static_cast<int>( std::floor( minY ) );
82 const int ex =
static_cast<int>( std::ceil( maxX ) );
83 const int ey =
static_cast<int>( std::ceil( maxY ) );
141 const double expected = std::sqrt( (
double( a ) * a +
double( b ) * b ) / 2.0 );
152 std::mt19937
rng( 42 );
153 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
154 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
155 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
158 for(
int i = 0; i <
N; ++i )
161 int r1 = radiusDist(
rng );
162 int r2 = radiusDist(
rng );
188 std::mt19937
rng( 1337 );
189 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
190 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
191 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
192 std::uniform_real_distribution<double> sweepDist( 10.0, 350.0 );
197 for(
int i = 0; i <
N; ++i )
200 int r1 = radiusDist(
rng );
201 int r2 = radiusDist(
rng );
242 const double a = 1000.0;
243 const double b = 500.0;
245 const int N = 200000;
247 const double h = 2.0 *
M_PI /
N;
249 for(
int i = 0; i <
N; ++i )
251 const double t0 = i * h;
252 const double t1 = ( i + 1 ) * h;
253 auto f = [a, b](
double t )
255 const double s = std::sin( t ), c = std::cos( t );
256 return std::sqrt( a * a * s * s + b * b * c * c );
258 sum += ( t1 - t0 ) * ( f( t0 ) + 4 * f( 0.5 * ( t0 + t1 ) ) + f( t1 ) ) / 6.0;
263 BOOST_CHECK_CLOSE( e.
GetLength(), sum, 1e-4 );
332 const double got = std::sqrt(
static_cast<double>( c.
SquaredDistance( p,
true ) ) );
349 const int a = 500, b = 300;
353 BOOST_CHECK_LE(
std::abs( d - b ), 2.0 );
363 BOOST_CHECK(
chain.IsClosed() );
364 BOOST_CHECK_GT(
chain.PointCount(), 8 );
376 BOOST_CHECK( !
chain.IsClosed() );
377 BOOST_CHECK_LE( (
chain.CPoint( 0 ) -
VECTOR2I( 1000, 0 ) ).EuclideanNorm(), 2 );
378 BOOST_CHECK_LE( (
chain.CPoint( -1 ) -
VECTOR2I( -1000, 0 ) ).EuclideanNorm(), 2 );
386 const int maxErr = 10;
392 for(
int i = 0; i <
chain.PointCount(); ++i )
394 const double d = std::sqrt(
static_cast<double>( e.
SquaredDistance(
chain.CPoint( i ),
true ) ) );
395 maxObserved = std::max( maxObserved,
static_cast<int>( std::ceil( d ) ) );
398 BOOST_CHECK_LE( maxObserved, maxErr + 2 );
410 BOOST_CHECK_GT( fine, coarse );
446 BOOST_CHECK( !e.
Collide( s, 100,
nullptr,
nullptr ) );
457 BOOST_CHECK( !e.
Collide( s, 40,
nullptr,
nullptr ) );
472 BOOST_CHECK( e.
Collide( s, 0,
nullptr,
nullptr ) );
482 BOOST_CHECK( !e.
Collide( s, 100,
nullptr,
nullptr ) );
494 BOOST_CHECK( e.
Collide( yAxis, 0,
nullptr,
nullptr ) );
497 BOOST_CHECK( e.
Collide( crossing, 0,
nullptr,
nullptr ) );
511 BOOST_CHECK( arc.
Collide( crossing, 0,
nullptr,
nullptr ) );
516 BOOST_CHECK( !arc.
Collide( lower, 50,
nullptr,
nullptr ) );
517 BOOST_CHECK( arc.
Collide( lower, 150,
nullptr,
nullptr ) );
529 const SEG segments[] = {
536 for(
const SEG& s : segments )
550 BOOST_CHECK( e.
Collide( &c, 0,
nullptr,
nullptr ) );
560 BOOST_CHECK( !e.
Collide( &c, 0,
nullptr,
nullptr ) );
571 BOOST_CHECK( e.
Collide( &r, 0,
nullptr,
nullptr ) );
581 BOOST_CHECK( !e.
Collide( &r, 0,
nullptr,
nullptr ) );
591 BOOST_CHECK( e.
Collide( &r, 0,
nullptr,
nullptr ) );
604 BOOST_CHECK( e.
Collide( &
chain, 0,
nullptr,
nullptr ) );
616 chain.SetClosed(
true );
620 BOOST_CHECK( e.
Collide( &
chain, 0,
nullptr,
nullptr ) );
630 BOOST_CHECK( e.
Collide( &arc, 0,
nullptr,
nullptr ) );
640 BOOST_CHECK( a.
Collide( &b, 0,
nullptr,
nullptr ) );
650 BOOST_CHECK( !a.
Collide( &b, 0,
nullptr,
nullptr ) );
660 BOOST_CHECK( big.
Collide( &small, 0,
nullptr,
nullptr ) );
669 BOOST_CHECK( e.Collide( &r, 0, &
actual ) );
816 const std::string cpp = e.
Format(
true );
818 BOOST_CHECK( cpp.find(
"SHAPE_ELLIPSE" ) != std::string::npos );
819 BOOST_CHECK( cpp.find(
"100" ) != std::string::npos );
820 BOOST_CHECK( cpp.find(
"200" ) != std::string::npos );
821 BOOST_CHECK( cpp.find(
"500" ) != std::string::npos );
822 BOOST_CHECK( cpp.find(
"300" ) != std::string::npos );
824 const std::string plain = e.
Format(
false );
825 BOOST_CHECK( plain.find(
"500" ) != std::string::npos );
826 BOOST_CHECK( plain.find(
"300" ) != std::string::npos );
836 std::mt19937
rng( 12345 );
837 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
838 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
839 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
840 std::uniform_int_distribution<int> ptDist( -15000, 15000 );
843 int determinismFailures = 0;
845 for(
int i = 0; i <
N; ++i )
848 const int r1 = radiusDist(
rng );
849 const int r2 = radiusDist(
rng );
860 BOOST_CHECK_GT( bbox.
GetWidth(), 0 );
869 if( d1 != d2 || d2 != d3 )
870 ++determinismFailures;
884 std::mt19937
rng( 9999 );
885 std::uniform_int_distribution<int> centerDist( -5000, 5000 );
886 std::uniform_int_distribution<int> radiusDist( 100, 1500 );
887 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
888 std::uniform_int_distribution<int> segDist( -8000, 8000 );
894 for(
int i = 0; i <
N; ++i )
897 const int r1 = radiusDist(
rng );
898 const int r2 = radiusDist(
rng );
909 bool bruteCollide =
chain.Collide( s,
clearance,
nullptr,
nullptr );
914 if( !bruteCollide && !e.
IsArc() )
920 if( analyticCollide != bruteCollide )
928 BOOST_CHECK_LE( mismatches,
N / 100 );
957 BOOST_CHECK_CLOSE( sweep, 90.0, 1e-6 );
972 BOOST_CHECK( !e.
IsArc() );
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
VECTOR2I::extended_type ecoord
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
void SetRotation(const EDA_ANGLE &aAngle)
int GetMajorRadius() const
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
const VECTOR2I & GetCenter() const
void SetMajorRadius(int aRadius)
SEG::ecoord SquaredDistance(const VECTOR2I &aP, bool aOutlineOnly=false) const override
const EDA_ANGLE & GetStartAngle() const
const EDA_ANGLE & GetEndAngle() const
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
const std::string Format(bool aCplusPlus=true) const override
Serialize the ellipse.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the ellipse across a horizontal or vertical axis passing through aRef.
const EDA_ANGLE & GetRotation() const
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
int GetMinorRadius() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
static constexpr EDA_ANGLE ANGLE_0
static thread_local boost::mt19937 rng
@ LEFT_RIGHT
Flip left to right (around the Y axis)
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
const SHAPE_LINE_CHAIN chain
BOOST_AUTO_TEST_CASE(ConstructorSwapsMajorMinor)
static BOX2I bruteForceEllipseBBox(const VECTOR2I &aCenter, int aMajorR, int aMinorR, const EDA_ANGLE &aRotation, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aEndAngle, bool aIsArc, int aNSamples=10000)
Compute a bounding box by sampling 10,000 points around the ellipse Used as ground truth to verify BB...
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I