我使用下面的C++代码来计算我在画布上绘制的椭圆的外侧周围的360个点。我通过选择一个左边和右边作为x1,y1,x2,y2来设置椭圆的大小。当使用零度的水平主轴计算椭圆时,椭圆接触左边和右边。当我用45度长轴计算椭圆时,椭圆的顶部和底部不再接触左边和右边。我需要以一个角度绘制椭圆,以便触及左边界和右边界。要做到这一点,我需要绘制更大的椭圆,但我不知道如何计算更大的尺寸。有没有办法计算出较大的椭圆,这样成角度的椭圆会碰到原始的左右边界?如何调整椭圆的大小,使其始终接触左右边界?
double x1=0, y1=0, x2=0, y2=0, x3=0, y3=0, phi=0;
int ZeroX=0, ZeroY=0;
int NUM_POINTS_PER_CONTOUR = 360;
int p=0;
int Major_Axis_Center_X=0, Full_Major_Axis_X=0;
int Major_Axis_Center_Y=0, Full_Major_Axis_Y=0;
int Full_Minor_Axis_X=0;
double AngleOfMajorAxis=0;
UnicodeString temp;
struct ell {
double a; //e.a is semi-major size
double b; //e.b is semi-minor size
double theta;
double x0; //major axis center X
double y0; //major axis center Y
} e;
//seed Values
x1=50; x2=250;
y1=75; y2=275;
//Vertical Line LEFT edge
Canvas->MoveTo(x1, y1);
Canvas->LineTo(x1, y2);
//Vertical Line RIGHT edge
Canvas->MoveTo(x2, y1);
Canvas->LineTo(x2, y2);
Full_Major_Axis_X = (x2 - x1);
Full_Major_Axis_Y = (y2 - y1);
Major_Axis_Center_X = (x1 + (Full_Major_Axis_X/2));
Major_Axis_Center_Y = (y2 - (Full_Major_Axis_Y/2));
Full_Minor_Axis_X = (Full_Major_Axis_X/2);
//Seed values
e.a = (Full_Major_Axis_X/2); //e.a is semi-major size
e.b = (Full_Minor_Axis_X/2); //e.b is semi-minor size
e.x0 = Major_Axis_Center_X;
e.y0 = Major_Axis_Center_Y;
AngleOfMajorAxis = 45.0;
e.theta = DegToRad(AngleOfMajorAxis);
//Calculate 360 points around edge of ellipse
for (p=0; p<NUM_POINTS_PER_CONTOUR; p++) {
phi = p*2*M_PI/(double)NUM_POINTS_PER_CONTOUR;
x1 = e.a * std::sin(phi);
y1 = e.b * std::cos(phi);
x2 = x1 * std::cos(e.theta) + y1 * std::sin(e.theta);
y2 = y1 * std::cos(e.theta) - x1 * std::sin(e.theta);
x3 = x2 + e.x0;
y3 = y2 + e.y0;
if(p==0){
Canvas->MoveTo(x3, y3);
}
Canvas->LineTo(x3, y3);
}
编辑:这是最好的答案
我已经添加了两行代码,我上面的for循环
phiMax = atan(e.b/e.a * std::tan(e.theta)); // {1}
Coeff = e.a/(e.a * std::cos(phiMax) * std::cos(e.theta) + e.b * std::sin(phiMax) * std::sin(e.theta)); // {2}
现在我加把系数成for循环
//Calculate 360 points around edge of ellipse
for (p=0; p<NUM_POINTS_PER_CONTOUR; p++) {
phi = p*2*M_PI/(double)NUM_POINTS_PER_CONTOUR;
x1 = Coeff * e.a * std::sin(phi);
y1 = Coeff * e.b * std::cos(phi);
x2 = x1 * std::cos(e.theta) + y1 * std::sin(e.theta);
y2 = y1 * std::cos(e.theta) - x1 * std::sin(e.theta);
x3 = x2 + e.x0;
y3 = y2 + e.y0;
if(p==0){
Canvas->MoveTo(x3, y3);
}
Canvas->LineTo(x3, y3);
}
结果是椭圆的最宽部分总是接触左边界和右边界。这是最简单和最接近的答案。下面的图片显示了一个65度椭圆,调整后可以触及边界。
不熟悉计算几何,但是有没有一种有效的方法来验证ecllipse是否触及两侧,给出ecllipse的大小?如果是的话,也许你可以做一个二分搜索:不断调整椭圆的大小,如果它接触/相交的边,减小其大小,否则增加其大小,因为边界不是整数,你可以简单地运行这个切断百次,以便精度足够高,最终的大小就是答案 – shole
@shole,是的,我可以找到一个for循环的答案,但它很慢,我不知道它是正确的。我希望有一个公式可以给出确切的答案。 – homebase
即使你有一个公式,因为你没有处理整数,double/float数据类型会给你自己的精度问题(取决于你需要多少精度)。因此,使用或不使用公式不是主要问题,精度错误是。使用循环进行二进制搜索200次,精度将比1e-30高得多,这非常精确,基本上瓶颈又是数据类型的精度。如果您的验证过程高效,此方法非常有效。当然,使用公式会给你一个最好的O(1)算法:) – shole