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

标签 c++ geometry

我正在使用下面的 C++ 代码来计算我在 Canvas 上绘制的椭圆外侧周围的 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}

现在我将系数添加到 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

最佳答案

椭圆以 (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); 

关于c++ - 如何调整椭圆的大小,使其始终触及左右边界?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38780218/

相关文章:

c++ - 如何设置单个静态控件c++的文本和背景颜色?

C++ DirectX - 对 2D 网格进行纹理化

c++ - 指向数组元素的指针打印内存地址而不是元素的值

Java 圆形(6 段)

android - 按轴计算 Canvas 中的点坐标

ios - 如何找到两个 Sprite 之间接触点的法向量

c++ - 从 VBA 访问 C++ 中的嵌套结构

c++ - 输入数据到二维数组这是如何工作的?

ios - 为什么给 addArcWithCenter 一个 0 度的 startAngle 会使它从 90 度开始?

java - 在多边形的线上选择一个随机点