gpt4 book ai didi

java - 如何找到椭圆上扫过给定区域的点?

转载 作者:行者123 更新时间:2023-11-30 04:03:47 24 4
gpt4 key购买 nike

我正在研究将椭圆划分为大小相等的线段的问题。已提出这个问题,但答案建议进行数值积分,以便我可以尝试。此代码使扇区短路,因此集成本身不应覆盖超过 90 度。积分本身是通过计算中间三角形的面积来完成的。下面是我尝试过的代码,但在某些情况下它的扫描角度超过 90 度。

public class EllipseModel {

protected double r_x;
protected double r_y;

private double a,a2;
private double b,b2;

boolean flip;

double area;
double sector_area;

double radstep;
double rot;

int xp,yp;

double deviation;

public EllipseModel(double r_x, double r_y, double deviation)
{
this.r_x = r_x;
this.r_y = r_y;
this.deviation = deviation;

if (r_x < r_y) {
flip = true;
a = r_y;
b = r_x;
xp = 1;
yp = 0;
rot = Math.PI/2d;
} else {
flip = false;
xp = 0;
yp = 1;
a = r_x;
b = r_y;
rot = 0d;
}

a2 = a * a;
b2 = b * b;

area = Math.PI * r_x * r_y;
sector_area = area / 4d;

radstep = (2d * deviation) / a;
}

public double getArea() {
return area;
}

public double[] getSweep(double sweep_area)
{
System.out.println(String.format("getSweep(%f) a = %f b = %f deviation = %f",sweep_area,a,b,deviation));
double[] ret = new double[2];
double[] next = new double[2];
double t_base, t_height, swept,x_mid,y_mid;
double t_area;

sweep_area = sweep_area % area;

if (sweep_area < 0d) {
sweep_area = area + sweep_area;
}

if (sweep_area == 0d) {
ret[0] = r_x;
ret[1] = 0d;
return ret;
}

double sector = Math.floor(sweep_area/sector_area);
double theta = Math.PI * sector/2d;
double theta_last = theta;

System.out.println(String.format("- Theta start = %f",Math.toDegrees(theta)));

ret[xp] = a * Math.cos(theta + rot);
ret[yp] = (1 + (((theta / Math.PI) % 2d) * -2d)) * Math.sqrt((1 - ( (ret[xp] * ret[xp])/a2)) * b2);

next[0] = ret[0];
next[1] = ret[1];

swept = sector * sector_area;

System.out.println(String.format("- Sweeping for %f sector_area=%f",sweep_area-swept,sector_area));

int c = 0;

while(swept < sweep_area) {

c++;
ret[0] = next[0];
ret[1] = next[1];

theta_last = theta;
theta += radstep;

// calculate next point
next[xp] = a * Math.cos(theta + rot);
next[yp] = (1 + (((theta / Math.PI) % 2d) * -2d)) * // selects +/- sqrt
Math.sqrt((1 - ( (ret[xp] * ret[xp])/a2)) * b2);

// calculate midpoint
x_mid = (ret[xp] + next[xp]) / 2d;
y_mid = (ret[yp] + next[yp]) / 2d;

// calculate triangle metrics
t_base = Math.sqrt( ( (ret[0] - next[0]) * (ret[0] - next[0]) ) + ( (ret[1] - next[1]) * (ret[1] - next[1])));
t_height = Math.sqrt((x_mid * x_mid) + (y_mid * y_mid));

// add triangle area to swept
t_area = 0.5d * t_base * t_height;
swept += t_area;

}

System.out.println(String.format("- Theta end = %f (%d)",Math.toDegrees(theta_last),c));

return ret;
}
}

在输出中,我看到以下情况,它扫过 116 度。

getSweep(40840.704497) a = 325.000000 b = 200.000000 deviation = 0.166667
- Theta start = 0.000000
- Sweeping for 40840.704497 sector_area=51050.880621
- Theta end = 116.354506 (1981)

有没有办法修复积分公式以创建一个返回扫过给定区域的椭圆上的点的函数?使用此代码的应用程序将总面积除以所需的段数,然后使用此代码确定每个段开始和结束的角度。不幸的是,它没有按预期工作。

* 编辑 *我相信上述集成失败了,因为底数和高度公式不正确。

最佳答案

无需使用椭圆参数方程进行转换...

x=x0+rx*cos(a)
y=y0+ry*sin(a)

其中 a = < 0 , 2.0*M_PI >

  • 如果根据上面的方程将椭圆除以从中心到 x,y 的线
  • 角度 a 均匀增大
  • 那么这些段将具有相同的大小
顺便说一句。如果应用仿射变换,您将得到相同的结果(甚至相同的方程)

此代码会将椭圆划分为大小均匀的 block :

double a,da,x,y,x0=0,y0=0,rx=50,ry=20;  // ellipse x0,y0,rx,ry
int i,N=32; // divided to N = segments
da=2.0*M_PI/double(N);

for (a=0.0,i=0;i<N;i++,a+=da)
{
x=x0+(rx*cos(a));
y=y0+(ry*sin(a));
// draw_line(x0,y0,x,y);
}

这就是 N=5 的情况

ellipse division

[编辑1]

从你的评论中我不明白你现在到底想要实现什么

  • 抱歉,我的英语水平很糟糕
  • 好吧,我假设这两种可能性(如果您需要不同的东西,请指定更接近的)

0.但首先需要一些全局或成员的东西

double x0,y0,rx,ry; // ellipse parameters

// [Edit2] sorry forgot to add these constants but they are I thin straight forward
const double pi=M_PI;
const double pi2=2.0*M_PI;
// [/Edit2]

double atanxy(double x,double y) // atan2 return < 0 , 2.0*M_PI >
{
int sx,sy;
double a;
const double _zero=1.0e-30;
sx=0; if (x<-_zero) sx=-1; if (x>+_zero) sx=+1;
sy=0; if (y<-_zero) sy=-1; if (y>+_zero) sy=+1;
if ((sy==0)&&(sx==0)) return 0;
if ((sx==0)&&(sy> 0)) return 0.5*pi;
if ((sx==0)&&(sy< 0)) return 1.5*pi;
if ((sy==0)&&(sx> 0)) return 0;
if ((sy==0)&&(sx< 0)) return pi;
a=y/x; if (a<0) a=-a;
a=atan(a);
if ((x>0)&&(y>0)) a=a;
if ((x<0)&&(y>0)) a=pi-a;
if ((x<0)&&(y<0)) a=pi+a;
if ((x>0)&&(y<0)) a=pi2-a;
return a;
}

1.点在线段内吗?

bool is_pnt_in_segment(double x,double y,int segment,int segments) 
{
double a;
a=atanxy(x-x0,y-y0); // get sweep angle
a/=2.0*M_PI; // convert angle to a = <0,1>
if (a>=1.0) a=0.0; // handle extreme case where a was = 2 Pi
a*=segments; // convert to segment index a = <0,segments)
a-=double(segment );
// return floor(a); // this is how to change this function to return points segment id
// of course header should be slightly different: int get_pnt_segment_id(double x,double y,int segments)
if (a< 0.0) return false; // is lower then segment
if (a>=1.0) return false; // is higher then segment
return true;
}

2.获取线段区域的边缘点

void get_edge_pnt(double &x,double &y,int segment,int segments)
{
double a;
a=2.0*M_PI/double(segments);
a*=double(segment); // this is segments start edge point
//a*=double(segment+1); // this is segments end edge point
x=x0+(rx*cos(a));
y=y0+(ry*sin(a));
}

展位:

  • x,y 是点
  • 分段数。
  • segment 是扫描区域 < 0,segments )

关于java - 如何找到椭圆上扫过给定区域的点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21277355/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com