Maaajaaa
Maaajaaa

Reputation: 186

What's the correct way to implement the ellipse equation in C?

I am trying to render ellipse on plotter powered by an MCU so there is low memory to work with and integer arithmetics is preffered.

I've got this equation

elipse equation

and I tried to implement it in C in the following way:

y = sqrt( (b*b) * ( 1 - ( (x*x) / (a*a) )));

where y, b, x and a are integer values but the results where wrong .

Q1 Is this correct implementation of ellipse equation?

Q2 Are there any other ways to do this?

Upvotes: 1

Views: 273

Answers (2)

Spektre
Spektre

Reputation: 51845

  1. for plotting the ellipse (outline by lines) is the parametric equation the best.

    Here axis aligned ellipse:

    x=x0+a*cos(t);
    y=y0+b*sin(t);
    

    where:

    • (x0,y0) is the ellipse center
    • a,b are the semi-axises
    • t is angular parameter t=<0,2*M_PI>

      1. So form a loop where t goes the full circle with some small enough step
      2. compute (x,y) per each step of t
      3. interpolate/render line per each step (from last to new point)

    as your x,y,x0,y0,a,b are integers either convert them to float/double or create integer table for cos[],sin[] for example:

    • int tcos[360],tsin[360];

    where tcos[i]=float(1000.0*cos(float(i)*M_PI/180.0)); now on use just integers like:

    for (i=0;i<360;i++)
     {
     x=x0+(a*tcos(i))/1000;
     y=y0+(b*tsin(i))/1000;
     //...
     }
    
  2. If you need pixel perfect rendering or render filled ellipse

    Then you need use different approach (the same as your equation)

    1. loop one axis with pixel step
    2. compute the other axis coordinate
    3. render both pixels/or fill the line

    for example axis aligned (0,0) centered ellipse:

    for (x=-a;x<=a;x++)
     {
     y = sqrt( (b*b) - ( (x*x*b*b) / (a*a) )));
     // render pixels: (x,+y) and (x,-y) or join them by line
     }
    

    if you need integer sqrt then implement one (instead of using math.h) for example:

    int bits(DWORD p)
        {
        DWORD m=0x80000000; int b=32;
        for (;m;m>>=1,b--)
         if (p>=m) break;
        return b;
        }
    
    DWORD sqrt(const DWORD &x)
        {
        DWORD m,a;
        m=(bits(x)>>1); // bits(x) just return position of MSB nonzero bit can use m=16; instead
        if (m) m=1<<m; else m=1;
        for (a=0;m;m>>=1) { a|=m; if (a*a>x) a^=m; }
        return a;
        }
    

    where DWORD is unsigned 32 bit int data type.

  3. for filling you do not need the sqrt

    You can instead loop through the area and decide if the pixel is inside or not:

    for (y=-b;y<=b;y++)
     for (x=-a;x<=a;x++)
      if ( (y*y) <= ( (b*b) - ( (x*x*b*b) / (a*a) ) ) )
       // render pixel: (x,y)
    

Upvotes: 2

Maaajaaa
Maaajaaa

Reputation: 186

The implementation is correct. I set y,b,x and a as double values this fixed the wrong output.

Upvotes: -1

Related Questions