目前我正在编写JavaScript代码,将对象放在椭圆上的屏幕上。
我试图找到解决其中一个问题的算法,椭圆将是完美的,但如果太昂贵,Beizier曲线也可以。
对不起,但不幸的是我的数学不允许我使用我找到的答案(https://mathoverflow.net/questions/28070/finding-n-points-that-are-equidistant-around-the-circumference-of-an-ellipse,Equidistant points across Bezier curves),所以我需要帮助才能将其翻译成代码或者只是建议如何这样做。
如果您需要查看我的问题,可以查看此文档的第二页: http://www.saccade.com/writing/graphics/RE-PARAM.PDF
答案 0 :(得分:0)
好的,我撤回了我的近距离投票你的问题与我链接的那些有点不同
已经使用了我的代码,所以这里是等距点的结果
//---------------------------------------------------------------------------
void draw()
{
TCanvas *scr=Form1->Canvas;
//if (scr->FHandle==NULL) return;
scr->Brush->Color=clWhite;
scr->Rectangle(0,0,Form1->ClientWidth,Form1->ClientHeight);
double x0,y0,rx,ry,n,l0,ll0;
x0=Form1->ClientWidth>>1; // ellipse position (midle of form)
y0=Form1->ClientHeight>>1;
rx=200; // ellipse a
ry=50; // ellipse b
n=33.0; // segments
//l0=2.0*M_PI*sqrt(0.5*((rx*rx)+(ry*ry)));
l0=(rx-ry)/(rx+ry); l0*=3.0*l0; l0=M_PI*(rx+ry)*(1.0+(l0/(10.0+sqrt(4.0-l0))));
// compute segment size
l0/=n; ll0=l0*l0;
int i,j,k,kd;
AnsiString s;
double a,da,x,y,xx,yy,ll,mm,r=2.0;
for (kd=10,k=0;;k++) // kd+1 passes
{
a=0.0; if (!k) da=0.0;
xx=rx*sin(a+0.5*da);
yy=ry*cos(a+0.5*da);
da=l0/sqrt((xx*xx)+(yy*yy));
x=x0+rx*cos(a);
y=y0+ry*sin(a);
if (k==kd) // draw in last pass only
{
scr->Pen->Color=clRed;
scr->MoveTo(x ,y );
scr->LineTo(x0,y0);
scr->Ellipse(x-r,y-r,x+r,y+r);
scr->Pen->Color=clBlue;
scr->Font->Color=clBlue;
}
for (i=n;i>0;i--)
{
// approximate angular step to match l0 (as start point for fitting)
xx=rx*sin(a+0.5*da);
yy=ry*cos(a+0.5*da);
da=l0/sqrt((xx*xx)+(yy*yy));
// next point position
xx=x; yy=y; a+=da;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
// fit it to be really l0
ll=((xx-x)*(xx-x))+((yy-y)*(yy-y)); ll=fabs(ll0-ll);
for (da*=0.1,a-=da,j=0;j<5;) // accuracy recursion layers
{
a+=da;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
mm=((xx-x)*(xx-x))+((yy-y)*(yy-y)); mm=fabs(ll0-mm);
if (mm>ll) { a-=da; da=-0.1*da; j++; } else ll=mm; // if acuracy stop lovering change direction
}
x=x0+rx*cos(a);
y=y0+ry*sin(a);
if (k==kd) // draw in last pass only
{
// draw the lines and dots
scr->MoveTo(xx,yy);
scr->LineTo(x ,y );
scr->Ellipse(x-r,y-r,x+r,y+r);
// print the difference^2
ll=((xx-x)*(xx-x))+((yy-y)*(yy-y));
s=AnsiString().sprintf("%.2lf",ll0-ll);
xx=0.5*(x+xx)+20.0*cos(a)-0.5*double(scr->TextWidth(s));
yy=0.5*(y+yy)+20.0*sin(a)-0.5*double(scr->TextHeight(s));
scr->TextOutA(xx,yy,s);
}
}
if (k==kd)
{
scr->MoveTo(x ,y );
scr->LineTo(x0,y0);
s=AnsiString().sprintf("%.4lf",2.0*M_PI-a);
xx=x+60.0*cos(a)-0.5*double(scr->TextWidth(s));
yy=y+60.0*sin(a)-0.5*double(scr->TextHeight(s));
scr->TextOutA(xx,yy,s);
break;
}
// rescale l0
a=2.0*M_PI/a; // a should be 2*PI if no error -> 1.0
l0*=0.5+0.5*a; // just iterate
ll0=l0*l0;
}
}
//---------------------------------------------------------------------------
它来自第二个链接 Q / A 的代码,但无论如何这都是它的作用
k/kd
循环整个事件kd
- 次
并且通过重新调整段大小l0,ll0
,它们更接近结果。在最后一次传球中,它也会绘制分段......传球次数越多,获得的精度就越高。使用当前的过度杀伤,它甚至可以处理rx=4.0*ry
偏心椭圆(反之亦然)。对于常见的省略号,kd=1,2 or 3
i
循环遍历所有细分
首先通过链接 Q / A 的公式估算步骤,然后通过大多数内部&#39; j使用段大小到l0
的迭代拟合。环
内部j
循环
只是步进角,看看段是否更接近所需大小,如果不改变步长方向及其大小10
次以提高准确度,j
的递归层越多,它就越精确
k/kd
循环 结束时
角度应为2*PI
,因此如果它或多或少,则相应地重新缩放l0
,但要避免振荡,请使用原始l0
尺寸的平均值
这就是全部