4
votes

Like the picture show blow, i have two coordinates, and i want to draw an ellipse which the major axis edges match these two point.

enter image description here

I have tried get the mid point between these two coordinates and draw an ellipse base on these one coordinate. The code like these, below function return the array of ellipse points which is just i want:

 function add_oval(centre, x, y) {
    var assemble = new Array();
    var angle;
    var dot;
    var tangent = x / y;
    for (i = 0; i < 36; i++) {
        angle = (2 * Math.PI / 36) * i;
        dot = [centre.lng + Math.sin(angle) * y * tangent, centre.lat + Math.cos(angle) * y];
        assemble.push(dot);
    }
    return assemble;
}

But the problem is, these can only draw a horizontal ellipse, i don't know how to change the angle.

Does someone know how to solve my problem?

2
You've to define the minor axis as well, in order to draw an ellipse.Teemu
@Teemu, i can make a specific value for minor axis, it doesn't matter.Jack Zhang

2 Answers

3
votes

Hint:

If there is no rotated ellipse feature in javascript, a workaround is to use a Bezier cubic approximation instead. Refer to the post How to create circle with Bézier curves? about how to approximate a circle with four Bezier arcs. Then an ellipse is just a stretched circle, and it suffices to stretch the control points the same way.

Start with a unit circle, scale the control point by the axis lengths, apply the desired rotation and translate to the desired center. The scaling and rotation parameters can be drawn from the given major axis (plus length of the minor).

An alternative is to use the parametric equations of the ellipse and draw it as a polyline.

3
votes

I would use basis vectors for this.

  1. ellipse definition

    ellipse

    So we know A,B 2D points. You need to define also scalar minor semi-axis size |b| to define your ellipse. so knowns are:

    A=!
    B=!
    |b|=!
    
  2. Mid point C

    That is easy it is half between A,B

    C.x=A.x + (B.x-A.x)/2
    C.y=A.y + (B.y-A.y)/2
    

    or average of A,B

    C.x = (A.x+B.x)/2
    C.y = (A.y+B.y)/2
    

    choose which you like more (it does not matter which). This point C will serve as basis vectors origin.

  3. Basis vectors a,b

    major semi-axis is easy as it is defined by CB or CA (also does not matter which for full ellipse)

    a.x = B.x-C.x
    a.y = B.y-C.y
    

    You can also use half of AB

    a.x = (B.x-A.x)/2
    a.y = (B.y-A.y)/2
    

    minor semi-axis b is worse and we know that is perpendicular to a so either exploit cross product of a with vector (0,0,1) in 3D ad rescale or use the fact that if you swap (x,y) to (y,-x) or (-y,x) you obtain 90 degree rotation in 2D. and rescale from size |a| to size |b| so:

    |a| = sqrt( a.x*a.x + a.y*a.y )
    b.x = a.y * |b|/|a|
    b.y =-a.x * |b|/|a|
    
  4. Ellipse

    Now we finally got everything we need for rendering. Any point on our ellipse parametrized by angle ang=<0,2.0*M_PI> where M_PI=3.1415926535897932384626433832795 is easy:

    x = C.x + a.x*cos(ang) + b.x*sin(ang)
    y = C.y + a.y*cos(ang) + b.y*sin(ang)
    

    So either add this into your for loop and render your ellipse with points as you have for now. Or render the ellipse as polyline with lines ... for example something like this in VCL/GDI (sorry I do not use javascript):

    bool e,e0;
    double ang,dang=2.0*M_PI/100.0; // 100 lines per 360 degree
    for (e=true,e0=true,ang=0.0;e;ang+=dang,e0=false)
     {
     if (ang>=2.0*M_PI) { ang=2.0*M_PI; e=false; } // reached end? 360 degree
     x = C.x + a.x*cos(ang) + b.x*sin(ang);
     y = C.y + a.y*cos(ang) + b.y*sin(ang);
     if (e0) Canvas->MoveTo(x,y); // first time is cursor moved to (x,y)
      else   Canvas->LineTo(x,y); // all the other iterations just draws a line from last cursor to (x,y) and also moves the cursor there
     }
    

Notes

  • point and vector in 2D is defined as set of 2 coordinates (x,y)
  • scalar is single value (standard number)
  • |a| means size of vector a
  • Above computations does not require that |a|>|b|
  • If the |b| is unknown you can use scaling of |a| For example let |b|/|a|=0.3