首页 文章

如何调整椭圆的大小,使其始终接触左右边界?

提问于
浏览
1

我正在使用下面的c代码来计算我在画布上绘制的椭圆外侧的360点 . 我通过选择左边和右边为x1,y1,x2,y2来设置椭圆的大小 . 当用水平长轴(零度)计算椭圆时,椭圆接触左右边缘 . 当我计算具有45度长轴的椭圆时,椭圆的顶部和底部不再接触左右边缘 . 我需要以一定角度绘制椭圆,使其接触左右边界 . 要做到这一点,我需要绘制更大的椭圆,但我不知道如何计算更大的尺寸 . 有没有办法计算更大尺寸的椭圆,这样成角度的椭圆会触及原来的左右边界?

zero degree ellipse

45 degree ellipse

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}

现在我将Coeff添加到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度椭圆,可调整以触及边界 .

65 degree ellipse

3 回答

  • 0

    椭圆居中于 (0,0) ,旋转 t (您的 theta ),具有x坐标的等式

    x = a * cos(phi) * cos(t) + b * sin(phi) * sin(t)
    

    当导数为零时,到达极值点(左和右) x'=0

    dx/dphi = - a * sin(phi) * cos(t) +  b * cos(phi) * sin(t) = 0
    a * sin(phi) * cos(t) =  b * cos(phi) * sin(t)
    tg(phi) = b/a * tg(t)
    phiMax =  atan(b/a * tg(t))      {1}
    

    在第一个等式中替换该值并找到放大系数(极值半尺寸应等于半轴)

    Coeff * (a * cos(phiMax) * cos(t) + b * sin(phiMax) * sin(t)) = a
    Coeff = a / (a * cos(phiMax) * cos(t) + b * sin(phiMax) * sin(t))   {2}
    

    现在您可以实现公式 {1}{2} 并在计算中使用此系数,如下所示:

    x1 = Coeff * e.a * std::sin(phi);
    y1 = Coeff * e.b * std::cos(phi);
    
  • 1

    如果你的线相隔一段距离,对于一个偏心椭圆 e ,半长轴 a 的长度可以由 a = d / 2 (1 - e^2 * sin^2 (theta)) 给出,其中 theta 是椭圆的旋转角度 .

    例如, 0 的角度给出 a = d/2 ,根据定义,这是真的 . 如果角度为 pi/445 degrees ,则转换为 a = d / (2 - e^2) .

    我不完全确定这是否正确,但我会在一段时间内编辑这篇文章,以便你可以检查我的工作,如果你愿意的话 .

    此外,如果您不知道,椭圆的偏心率可以由 e^2 = 1 - (b/a)^2 给出,其中 ab 分别是半长轴和半短轴长度 . 对于椭圆,它的值介于0和1之间 .

    EDIT: 更正了公式

  • 3

    我认为对你有帮助的是,如果你看一下你的第一个插图,你可以使用(x,y)的原点,在x和y方向上将原始椭圆平分,这样你就有两条对称线 . x和y轴 . 然后,您将在原始椭圆上有4个感兴趣的点,这些点将是椭圆与x和-x轴以及y和-y轴相交或接触的位置 . 这将为此椭圆提供2个半径,短半径和长半径 . 您可以并且将需要将这些用于参考和计算;旋转椭圆后我想象它的原点(中心点)你需要使用一些三角法和矢量代数来确定与你的垂直相交的45度旋转线上椭圆边缘点的矢量长度差异线(x2y1,x2y2)找到这个距离一旦你知道距离然后使用一些矢量计算,你应该能够弄清楚这个椭圆的倾斜程度,直到它有一个接触这条垂直线的边缘点 . 你不必担心你的另一条垂直线(x1y1,x2y1),因为我们从这个椭圆的原点平分线旋转,并且有2条对称线 . 您可以预处理所有这些计算 . 获得所有旋转偏斜点的新坐标后,您可以刷新点的更新或绘图缓冲区 . 我将尝试用几张图片来证明这一点:

    Does Not Touch

    Zoomed In View

    要找到P2 - P1的距离应该相当容易 . 您应该已经知道垂直线的x值;并且要找到旋转线的y值应该很容易,因为你说它是45度旋转,它的斜率为1,该线的方程是y = x . 这应该可以很快地为您提供P2,并且计算量最小 . 为了找到P1,它应该几乎一样容易,因为它再次沿着y =线x,你知道这个椭圆的长半径的大小 . 然后你减去这两个点来给你这个距离 . 从那里你可以使用这个距离知道沿y = x线倾斜或拉伸这个椭圆的程度 . 然后重新计算所有点并使用基于偏斜值的新计算点更新绘图缓冲区 . 现在有两种方法来扭曲这种情况;一个是短半径不变的地方,它只是变得更长,看起来更加拉伸,而另一个是比例偏斜,如果长半径变大,那么短半径也是成比例的 . 我会留给你,以确定你想如何扭曲这个对象 .

相关问题