Algorithm for shape calculation (Ellipse)

会有一股神秘感。 提交于 2019-11-30 15:07:38

OK as i understand you know common radius of circles R0 and their number N and want to know inside ellipse parameters and positions of everything.

If we convert ellipse to circle then we get this:

const int N=12; // number of satelite circles
const double R=10.0;    // radius of satelite circles
struct _circle { double x,y,r; } circle[N]; // satelite circles

int i;
double x,y,r,l,a,da;
x=0.0;  // start pos of first satelite circle
y=0.0;
r=R;
l=r+r;  // distance ang angle between satelite circle centers
a=0.0*deg;
da=divide(360.0*deg,N);
for (i=0;i<N;i++)
    {
    circle[i].x=x; x+=l*cos(a);
    circle[i].y=y; y+=l*sin(a);
    circle[i].r=r; a+=da;
    }
// inside circle params
_circle c;
r=divide(0.5*l,sin(0.5*da))-R;
c.x=circle[i].x;
c.y=circle[i].y+R+r;
c.r=r;

[Edit 1]

For ellipse its a whole new challenge (took me two hours to find all quirks out)

const int    N=20;      // number of satelite circles
const double R=10.0;    // satelite circles radius
const double E= 0.7;    // ellipse distortion ry=rx*E
struct _circle { double x,y,r; _circle() { x=0; y=0; r=0.0; } } circle[N];
struct _ellipse { double x,y,rx,ry; _ellipse() { x=0; y=0; rx=0.0; ry=0.0; } } ellipse;

int i,j,k;
double l,a,da,m,dm,x,y,q,r0;
l=double(N)*R;                          // circle cener lines polygon length
ellipse.x =0.0;                         // set ellipse parameters
ellipse.y =0.0;
r0=divide(l,M_PI*sqrt(0.5*(1.0+(E*E))))-R;// aprox radius to match ellipse length for start
l=R+R; l*=l;
m=1.0; dm=1.0; x=0.0;
for (k=0;k<5;k++)                       // aproximate ellipse size to the right size
    {
    dm=fabs(0.1*dm);                    // each k-iteration layer is 10x times more accurate
    if (x>l) dm=-dm;
    for (;;)
        {
        ellipse.rx=r0  *m;
        ellipse.ry=r0*E*m;
        for (a=0.0,i=0;i<N;i++)         // set circle parameters
            {
            q=(2.0*a)-atanxy(cos(a),sin(a)*E);
            circle[i].x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q));
            circle[i].y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q));
            circle[i].r=R;    
            da=divide(360*deg,N); a+=da;
            for (j=0;j<5;j++)           // aproximate next position to match 2R distance from current position
                {
                da=fabs(0.1*da);        // each j-iteration layer is 10x times more accurate
                q=(2.0*a)-atanxy(cos(a),sin(a)*E);
                x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q))-circle[i].x; x*=x;
                y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q))-circle[i].y; y*=y; x+=y;
                if (x>l) for (;;)       // if too far dec angle
                    {
                    a-=da;
                    q=(2.0*a)-atanxy(cos(a),sin(a)*E);
                    x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q))-circle[i].x; x*=x;
                    y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q))-circle[i].y; y*=y; x+=y;
                    if (x<=l) break;
                    }
                else if (x<l) for (;;)  // if too short inc angle
                    {
                    a+=da;
                    q=(2.0*a)-atanxy(cos(a),sin(a)*E);
                    x=ellipse.x+(ellipse.rx*cos(a))+(R*cos(q))-circle[i].x; x*=x;
                    y=ellipse.y+(ellipse.ry*sin(a))+(R*sin(q))-circle[i].y; y*=y; x+=y;
                    if (x>=l) break;
                    }
                else break;
                }
            }
        // check if last circle is joined as it should be
        x=circle[N-1].x-circle[0].x; x*=x;
        y=circle[N-1].y-circle[0].y; y*=y; x+=y;
        if (dm>0.0) { if (x>=l) break; }
        else        { if (x<=l) break; }
        m+=dm;
        }
    }

Well I know its a little messy code so here is some info:

  1. first it try to set as close ellipse rx,ry axises as possible

    ellipse length should be about N*R*2 which is polygon length of lines between circle centers

  2. try to compose circles so they are touching each other and the ellipse

    I use iteration of ellipse angle for that. Problem is that circles do not touch the ellipse in their position angle thats why there is q variable ... to compensate around ellipse normal. Look for yellowish-golden lines in image

  3. after placing circles check if the last one is touching the first

    if not interpolate the size of ellipse actually it scales the rx,ry by m variable up or down

  4. you can adjust accuracy

    by change of the j,k fors and/or change of dm,da scaling factors

  5. input parameter E should be at least 0.5 and max 1.0

    if not then there is high probability of misplacing circles because on very eccentric ellipses is not possible to fit circles (if N is too low). Ideal setting is 0.7<=E<=1.0 closser to 1 the safer the algorithm is

  6. atanxy(dx,dy) is the same as `atan(dy/dx)

    but it handles all 4 quadrants like atan2(dy,dx) by sign analysis of dx,dy

Hope it helps

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!