47 int aNSamples = 10000 )
49 const double a = aMajorR;
50 const double b = aMinorR;
51 const double cp = std::cos( aRotation.AsRadians() );
52 const double sp = std::sin( aRotation.AsRadians() );
54 double tStart = aIsArc ? aStartAngle.AsRadians() : 0.0;
55 double tEnd = aIsArc ? aEndAngle.AsRadians() : 2.0 *
M_PI;
60 double minX = std::numeric_limits<double>::max();
61 double maxX = std::numeric_limits<double>::lowest();
62 double minY = std::numeric_limits<double>::max();
63 double maxY = std::numeric_limits<double>::lowest();
65 for(
int i = 0; i <= aNSamples; ++i )
67 const double t = tStart + ( tEnd - tStart ) * i / aNSamples;
68 const double ct = std::cos( t );
69 const double st = std::sin( t );
70 const double x = aCenter.x + a * ct * cp - b * st * sp;
71 const double y = aCenter.y + a * ct * sp + b * st * cp;
73 minX = std::min( minX, x );
74 maxX = std::max( maxX, x );
75 minY = std::min( minY, y );
76 maxY = std::max( maxY, y );
79 const int ix =
static_cast<int>( std::floor( minX ) );
80 const int iy =
static_cast<int>( std::floor( minY ) );
81 const int ex =
static_cast<int>( std::ceil( maxX ) );
82 const int ey =
static_cast<int>( std::ceil( maxY ) );
140 const double expected = std::sqrt( (
double( a ) * a +
double( b ) * b ) / 2.0 );
151 std::mt19937
rng( 42 );
152 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
153 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
154 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
157 for(
int i = 0; i <
N; ++i )
160 int r1 = radiusDist(
rng );
161 int r2 = radiusDist(
rng );
187 std::mt19937
rng( 1337 );
188 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
189 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
190 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
191 std::uniform_real_distribution<double> sweepDist( 10.0, 350.0 );
196 for(
int i = 0; i <
N; ++i )
199 int r1 = radiusDist(
rng );
200 int r2 = radiusDist(
rng );
241 const double a = 1000.0;
242 const double b = 500.0;
244 const int N = 200000;
246 const double h = 2.0 *
M_PI /
N;
248 for(
int i = 0; i <
N; ++i )
250 const double t0 = i * h;
251 const double t1 = ( i + 1 ) * h;
252 auto f = [a, b](
double t )
254 const double s = std::sin( t ), c = std::cos( t );
255 return std::sqrt( a * a * s * s + b * b * c * c );
257 sum += ( t1 - t0 ) * ( f( t0 ) + 4 * f( 0.5 * ( t0 + t1 ) ) + f( t1 ) ) / 6.0;
262 BOOST_CHECK_CLOSE( e.
GetLength(), sum, 1e-4 );
331 const double got = std::sqrt(
static_cast<double>( c.
SquaredDistance( p,
true ) ) );
348 const int a = 500, b = 300;
352 BOOST_CHECK_LE(
std::abs( d - b ), 2.0 );
362 BOOST_CHECK(
chain.IsClosed() );
363 BOOST_CHECK_GT(
chain.PointCount(), 8 );
375 BOOST_CHECK( !
chain.IsClosed() );
376 BOOST_CHECK_LE( (
chain.CPoint( 0 ) -
VECTOR2I( 1000, 0 ) ).EuclideanNorm(), 2 );
377 BOOST_CHECK_LE( (
chain.CPoint( -1 ) -
VECTOR2I( -1000, 0 ) ).EuclideanNorm(), 2 );
385 const int maxErr = 10;
391 for(
int i = 0; i <
chain.PointCount(); ++i )
393 const double d = std::sqrt(
static_cast<double>( e.
SquaredDistance(
chain.CPoint( i ),
true ) ) );
394 maxObserved = std::max( maxObserved,
static_cast<int>( std::ceil( d ) ) );
397 BOOST_CHECK_LE( maxObserved, maxErr + 2 );
409 BOOST_CHECK_GT( fine, coarse );
445 BOOST_CHECK( !e.
Collide( s, 100,
nullptr,
nullptr ) );
456 BOOST_CHECK( !e.
Collide( s, 40,
nullptr,
nullptr ) );
471 BOOST_CHECK( e.
Collide( s, 0,
nullptr,
nullptr ) );
481 BOOST_CHECK( !e.
Collide( s, 100,
nullptr,
nullptr ) );
493 BOOST_CHECK( e.
Collide( yAxis, 0,
nullptr,
nullptr ) );
496 BOOST_CHECK( e.
Collide( crossing, 0,
nullptr,
nullptr ) );
510 BOOST_CHECK( arc.
Collide( crossing, 0,
nullptr,
nullptr ) );
515 BOOST_CHECK( !arc.
Collide( lower, 50,
nullptr,
nullptr ) );
516 BOOST_CHECK( arc.
Collide( lower, 150,
nullptr,
nullptr ) );
528 const SEG segments[] = {
535 for(
const SEG& s : segments )
549 BOOST_CHECK( e.
Collide( &c, 0,
nullptr,
nullptr ) );
559 BOOST_CHECK( !e.
Collide( &c, 0,
nullptr,
nullptr ) );
570 BOOST_CHECK( e.
Collide( &r, 0,
nullptr,
nullptr ) );
580 BOOST_CHECK( !e.
Collide( &r, 0,
nullptr,
nullptr ) );
590 BOOST_CHECK( e.
Collide( &r, 0,
nullptr,
nullptr ) );
603 BOOST_CHECK( e.
Collide( &
chain, 0,
nullptr,
nullptr ) );
615 chain.SetClosed(
true );
619 BOOST_CHECK( e.
Collide( &
chain, 0,
nullptr,
nullptr ) );
629 BOOST_CHECK( e.
Collide( &arc, 0,
nullptr,
nullptr ) );
639 BOOST_CHECK( a.
Collide( &b, 0,
nullptr,
nullptr ) );
649 BOOST_CHECK( !a.
Collide( &b, 0,
nullptr,
nullptr ) );
659 BOOST_CHECK( big.
Collide( &small, 0,
nullptr,
nullptr ) );
668 BOOST_CHECK( e.Collide( &r, 0, &
actual ) );
815 const std::string cpp = e.
Format(
true );
817 BOOST_CHECK( cpp.find(
"SHAPE_ELLIPSE" ) != std::string::npos );
818 BOOST_CHECK( cpp.find(
"100" ) != std::string::npos );
819 BOOST_CHECK( cpp.find(
"200" ) != std::string::npos );
820 BOOST_CHECK( cpp.find(
"500" ) != std::string::npos );
821 BOOST_CHECK( cpp.find(
"300" ) != std::string::npos );
823 const std::string plain = e.
Format(
false );
824 BOOST_CHECK( plain.find(
"500" ) != std::string::npos );
825 BOOST_CHECK( plain.find(
"300" ) != std::string::npos );
835 std::mt19937
rng( 12345 );
836 std::uniform_int_distribution<int> centerDist( -10000, 10000 );
837 std::uniform_int_distribution<int> radiusDist( 50, 2000 );
838 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
839 std::uniform_int_distribution<int> ptDist( -15000, 15000 );
842 int determinismFailures = 0;
844 for(
int i = 0; i <
N; ++i )
847 const int r1 = radiusDist(
rng );
848 const int r2 = radiusDist(
rng );
859 BOOST_CHECK_GT( bbox.
GetWidth(), 0 );
868 if( d1 != d2 || d2 != d3 )
869 ++determinismFailures;
883 std::mt19937
rng( 9999 );
884 std::uniform_int_distribution<int> centerDist( -5000, 5000 );
885 std::uniform_int_distribution<int> radiusDist( 100, 1500 );
886 std::uniform_real_distribution<double> angleDist( 0.0, 360.0 );
887 std::uniform_int_distribution<int> segDist( -8000, 8000 );
893 for(
int i = 0; i <
N; ++i )
896 const int r1 = radiusDist(
rng );
897 const int r2 = radiusDist(
rng );
908 bool bruteCollide =
chain.Collide( s,
clearance,
nullptr,
nullptr );
913 if( !bruteCollide && !e.
IsArc() )
919 if( analyticCollide != bruteCollide )
927 BOOST_CHECK_LE( mismatches,
N / 100 );
956 BOOST_CHECK_CLOSE( sweep, 90.0, 1e-6 );
971 BOOST_CHECK( !e.
IsArc() );
1054 return std::any_of( aPoints.begin(), aPoints.end(),
1057 return aPoint.Distance( aExpected ) <= 2;
1067 const std::vector<VECTOR2I> points = first.
Intersect( second );
1069 BOOST_REQUIRE_EQUAL( points.size(), 4 );
1071 const int offset =
KiROUND( 2000000.0 / std::sqrt( 5.0 ) );
1073 for(
int sx : { -1, 1 } )
1075 for(
int sy : { -1, 1 } )
1078 "no crossing near " << sx * offset <<
", " << sy * offset );
1091 BOOST_REQUIRE_EQUAL( points.size(), 4 );
1093 for(
const VECTOR2I& point : points )
1096 "point " << point.x <<
", " << point.y <<
" is off the ellipse" );
1099 BOOST_CHECK_MESSAGE( radial <= 2.0,
"point " << point.x <<
", " << point.y <<
" is off the circle" );
1109 const std::vector<VECTOR2I> points = ellipse.
Intersect( seg );
1111 BOOST_REQUIRE_EQUAL( points.size(), 2 );
1122 const std::vector<VECTOR2I> points = ellipse.
Intersect( arc );
1124 const int offset =
KiROUND( 2000000.0 / std::sqrt( 5.0 ) );
1126 BOOST_REQUIRE_EQUAL( points.size(), 1 );
1137 std::vector<VECTOR2I> ellipseToEllipse;
1141 std::vector<VECTOR2I> visitedCircle;
1145 std::vector<VECTOR2I> visitedEllipse;
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
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
Represent basic circle geometry with utility geometry functions.
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
std::vector< VECTOR2I > Intersect(const SHAPE_ELLIPSE &aOther) const
Find the points where this curve crosses another one.
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 constexpr EDA_ANGLE ANGLE_90
std::variant< LINE, HALF_LINE, SEG, CIRCLE, SHAPE_ARC, SHAPE_ELLIPSE, BOX2I > INTERSECTABLE_GEOM
A variant type that can hold any of the supported geometry types for intersection calculations.
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)
A visitor that visits INTERSECTABLE_GEOM variant objects with another (which is held as state: m_othe...
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
const SHAPE_LINE_CHAIN chain
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
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...
static bool containsPointNear(const std::vector< VECTOR2I > &aPoints, const VECTOR2I &aExpected)
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I