Given a fixed Angle, Width & Sagitta how can we calculate the horizontal and vertical radiuses of an ellipse?
I want to draw an elliptical arc that has a given arc width, height (Sagitta) and is a given angle of the ellipse.
In the below diagram the dashed black and yellow arc. To do this I need to know the 2 radiuses of the ellipse.
For a circle, one can easily calculate it's 1 radius give any 2 values of the angle, sagitta or width.
See the snippet below.
How can I adapt the function to work for an ellipse?
I the diagram the angle is so to speak symmetrical from -60 to 60 making an angle of 120. This is the case I really need i.e. where the arc reflects itself on both sides of either the vertical or horizontal axises.
In a case where the angle was 120 that started at 80 and ended at 200 there is no true sagitta just the highest point of the arc and a tight bounding box that would be much harder to solve if anyone has a solution also for that it would be a luxury.
var arcCalc = function(r, w, a, s) {
// to allow for object usage
if (r instanceof Object) {
w = r.w || r.width;
a = r.a || r.angle;
s = r.s || r.sagitta;
r = r.r || r.radius;
}
w = this.toPts(w);
s = this.toPts(s);
r = this.toPts(r);
var sin, cos, twoKnown;
sin = Math.sin;
cos = Math.cos;
// if we know any two arguments then we can work out the other ones
// if not we can't
twoKnown = +!r + +!w + +!a + +!s < 3;
// At this point of time we are trying to avoid throwing errors
// so for now just throw back the garbage we received
if (!twoKnown)
return {
radius: r,
width: w,
angle: a,
sagitta: s,
r: r,
w: w,
a: a,
s: s
};
if (a) {
a *= Math.PI / 180;
}
if (!r) {
if (!s) {
r = w / (2 * sin(a / 2));
} else if (!a) {
r = (s * s + 0.5 * w * (0.5 * w)) / (2 * s);
} else {
r = s / (1 - cos(a / 2));
}
}
// at this point we know we have r
if (!w) {
if (!s) {
w = 2 * r * sin(a / 2);
} else {
w = 2 * Math.sqrt(s * (2 * r - s));
}
}
// at this point we know we have r and w
if (!a) {
if (!s) {
// We added the round because
// w / (2*r) could come to 1.00000000001
// and then NaN would be produced
a = 2 * Math.asin(this.round(w / (2 * r)));
} else {
a = 2 * Math.acos(this.round(1 - s / r));
}
}
if (!s) {
s = r - r * cos(a / 2);
}
a *= 180 / Math.PI;
return {
radius: r,
width: w,
angle: a,
sagitta: s,
r: r,
w: w,
a: a,
s: s
};
};