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.
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?
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.
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?
Share Improve this question edited Aug 24, 2016 at 7:03 Spektre 51.9k12 gold badges121 silver badges398 bronze badges asked Aug 23, 2016 at 10:12 Jack ZhangJack Zhang 2,8065 gold badges26 silver badges34 bronze badges 2- 5 You've to define the minor axis as well, in order to draw an ellipse. – Teemu Commented Aug 23, 2016 at 10:16
- @Teemu, i can make a specific value for minor axis, it doesn't matter. – Jack Zhang Commented Aug 24, 2016 at 3:41
2 Answers
Reset to default 5Hint:
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.
I would use basis vectors for this.
ellipse definition
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|=!
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.Basis vectors
a,b
major semi-axis is easy as it is defined by
CB
orCA
(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 toa
so either exploit cross product ofa
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|
Ellipse
Now we finally got everything we need for rendering. Any point on our ellipse parametrized by angle
ang=<0,2.0*M_PI>
whereM_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 vectora
- Above putations does not require that
|a|>|b|
- If the
|b|
is unknown you can use scaling of|a|
For example let|b|/|a|=0.3