44 int aNSamples = 10000 )
46 const double a = aMajorR;
47 const double b = aMinorR;
48 const double cp = std::cos( aRotation.AsRadians() );
49 const double sp = std::sin( aRotation.AsRadians() );
51 double tStart = aIsArc ? aStartAngle.AsRadians() : 0.0;
52 double tEnd = aIsArc ? aEndAngle.AsRadians() : 2.0 *
M_PI;
57 double minX = std::numeric_limits<double>::max();
58 double maxX = std::numeric_limits<double>::lowest();
59 double minY = std::numeric_limits<double>::max();
60 double maxY = std::numeric_limits<double>::lowest();
62 for(
int i = 0; i <= aNSamples; ++i )
64 const double t = tStart + ( tEnd - tStart ) * i / aNSamples;
65 const double ct = std::cos( t );
66 const double st = std::sin( t );
67 const double x = aCenter.x + a * ct * cp - b * st * sp;
68 const double y = aCenter.y + a * ct * sp + b * st * cp;
70 minX = std::min( minX, x );
71 maxX = std::max( maxX, x );
72 minY = std::min( minY, y );
73 maxY = std::max( maxY, y );
76 const int ix =
static_cast<int>( std::floor( minX ) );
77 const int iy =
static_cast<int>( std::floor( minY ) );
78 const int ex =
static_cast<int>( std::ceil( maxX ) );
79 const int ey =
static_cast<int>( std::ceil( maxY ) );
137 const double expected = std::sqrt( (
double( a ) * a +
double( b ) * b ) / 2.0 );
148 std::mt19937
rng( 42 );
149 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
150 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
151 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
154 for(
int i = 0; i <
N; ++i )
157 int r1 = radiusDist(
rng );
158 int r2 = radiusDist(
rng );
184 std::mt19937
rng( 1337 );
185 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
186 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
187 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
188 std::uniform_real_distribution<double> sweepDist( 10.0, 350.0 );
193 for(
int i = 0; i <
N; ++i )
196 int r1 = radiusDist(
rng );
197 int r2 = radiusDist(
rng );
238 const double a = 1000.0;
239 const double b = 500.0;
241 const int N = 200000;
243 const double h = 2.0 *
M_PI /
N;
245 for(
int i = 0; i <
N; ++i )
247 const double t0 = i * h;
248 const double t1 = ( i + 1 ) * h;
249 auto f = [a, b](
double t )
251 const double s = std::sin( t ), c = std::cos( t );
252 return std::sqrt( a * a * s * s + b * b * c * c );
254 sum += ( t1 - t0 ) * ( f( t0 ) + 4 * f( 0.5 * ( t0 + t1 ) ) + f( t1 ) ) / 6.0;
259 BOOST_CHECK_CLOSE( e.
GetLength(), sum, 1e-4 );
328 const double got = std::sqrt(
static_cast<double>( c.
SquaredDistance( p,
true ) ) );
345 const int a = 500, b = 300;
349 BOOST_CHECK_LE(
std::abs( d - b ), 2.0 );
359 BOOST_CHECK(
chain.IsClosed() );
360 BOOST_CHECK_GT(
chain.PointCount(), 8 );
372 BOOST_CHECK( !
chain.IsClosed() );
373 BOOST_CHECK_LE( (
chain.CPoint( 0 ) -
VECTOR2I( 1000, 0 ) ).EuclideanNorm(), 2 );
374 BOOST_CHECK_LE( (
chain.CPoint( -1 ) -
VECTOR2I( -1000, 0 ) ).EuclideanNorm(), 2 );
382 const int maxErr = 10;
388 for(
int i = 0; i <
chain.PointCount(); ++i )
390 const double d = std::sqrt(
static_cast<double>( e.
SquaredDistance(
chain.CPoint( i ),
true ) ) );
391 maxObserved = std::max( maxObserved,
static_cast<int>( std::ceil( d ) ) );
394 BOOST_CHECK_LE( maxObserved, maxErr + 2 );
406 BOOST_CHECK_GT( fine, coarse );
442 BOOST_CHECK( !e.
Collide( s, 100,
nullptr,
nullptr ) );
453 BOOST_CHECK( !e.
Collide( s, 40,
nullptr,
nullptr ) );
468 BOOST_CHECK( e.
Collide( s, 0,
nullptr,
nullptr ) );
478 BOOST_CHECK( !e.
Collide( s, 100,
nullptr,
nullptr ) );
490 BOOST_CHECK( e.
Collide( yAxis, 0,
nullptr,
nullptr ) );
493 BOOST_CHECK( e.
Collide( crossing, 0,
nullptr,
nullptr ) );
507 BOOST_CHECK( arc.
Collide( crossing, 0,
nullptr,
nullptr ) );
512 BOOST_CHECK( !arc.
Collide( lower, 50,
nullptr,
nullptr ) );
513 BOOST_CHECK( arc.
Collide( lower, 150,
nullptr,
nullptr ) );
525 const SEG segments[] = {
532 for(
const SEG& s : segments )
546 BOOST_CHECK( e.
Collide( &c, 0,
nullptr,
nullptr ) );
556 BOOST_CHECK( !e.
Collide( &c, 0,
nullptr,
nullptr ) );
567 BOOST_CHECK( e.
Collide( &r, 0,
nullptr,
nullptr ) );
577 BOOST_CHECK( !e.
Collide( &r, 0,
nullptr,
nullptr ) );
587 BOOST_CHECK( e.
Collide( &r, 0,
nullptr,
nullptr ) );
600 BOOST_CHECK( e.
Collide( &
chain, 0,
nullptr,
nullptr ) );
612 chain.SetClosed(
true );
616 BOOST_CHECK( e.
Collide( &
chain, 0,
nullptr,
nullptr ) );
626 BOOST_CHECK( e.
Collide( &arc, 0,
nullptr,
nullptr ) );
636 BOOST_CHECK( a.
Collide( &b, 0,
nullptr,
nullptr ) );
646 BOOST_CHECK( !a.
Collide( &b, 0,
nullptr,
nullptr ) );
656 BOOST_CHECK( big.
Collide( &small, 0,
nullptr,
nullptr ) );
665 BOOST_CHECK( e.Collide( &r, 0, &
actual ) );
812 const std::string cpp = e.
Format(
true );
814 BOOST_CHECK( cpp.find(
"SHAPE_ELLIPSE" ) != std::string::npos );
815 BOOST_CHECK( cpp.find(
"100" ) != std::string::npos );
816 BOOST_CHECK( cpp.find(
"200" ) != std::string::npos );
817 BOOST_CHECK( cpp.find(
"500" ) != std::string::npos );
818 BOOST_CHECK( cpp.find(
"300" ) != std::string::npos );
820 const std::string plain = e.
Format(
false );
821 BOOST_CHECK( plain.find(
"500" ) != std::string::npos );
822 BOOST_CHECK( plain.find(
"300" ) != std::string::npos );
832 std::mt19937
rng( 12345 );
833 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
834 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
835 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
836 std::uniform_int_distribution<int> ptDist( -15000, 15000 );
839 int determinismFailures = 0;
841 for(
int i = 0; i <
N; ++i )
844 const int r1 = radiusDist(
rng );
845 const int r2 = radiusDist(
rng );
856 BOOST_CHECK_GT( bbox.
GetWidth(), 0 );
865 if( d1 != d2 || d2 != d3 )
866 ++determinismFailures;
880 std::mt19937
rng( 9999 );
881 std::uniform_int_distribution<int> centerDist( -5000, 5000 );
882 std::uniform_int_distribution<int> radiusDist( 100, 1500 );
883 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
884 std::uniform_int_distribution<int> segDist( -8000, 8000 );
890 for(
int i = 0; i <
N; ++i )
893 const int r1 = radiusDist(
rng );
894 const int r2 = radiusDist(
rng );
905 bool bruteCollide =
chain.Collide( s,
clearance,
nullptr,
nullptr );
910 if( !bruteCollide && !e.
IsArc() )
916 if( analyticCollide != bruteCollide )
924 BOOST_CHECK_LE( mismatches,
N / 100 );
953 BOOST_CHECK_CLOSE( sweep, 90.0, 1e-6 );
968 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