Я хочу знать координаты вершины эллипса при заданном угле. Центр эллипса находится на x = 0 и y = 0. Большая полуось равна x и имеет значение 1. Малая полуось - это y и имеет значение 0,38. Угол переменный.
Я перепробовал все в этом сообщении Stack Exchange, но ничего не получилось:
Вероятно, неправильные не данные решения, а моя интеграция их в JavaScript.
Например, это не работает:
a = 1
b = 0.38
function getAngle(x1, y1, x2, y2) {
return Math.atan((y2 - y1) / (x2 - x1)) * 180 / Math.PI
}
angle = getAngle(0,0,0.3,0.7)
x = (a*b*Math.cos(angle))
/
Math.sqrt(
(a*Math.cos(angle))**2 +
(b*Math.sin(angle))**2
)
y = (a*b*Math.sin(angle))
/
Math.sqrt(
(a*Math.cos(angle))**2 +
(b*Math.sin(angle))**2
)
console.info({x,y})
Вывод:
{
"x": -0.35112437558647797,
"y": -0.3823646436315567
}
Как вы можете видеть на этом изображении, результат не является вершиной эллипса:
Как найти координаты точки эллипса на основе угла?
Такой эллипс представляет собой просто окружность, масштабированную с коэффициентом 0,38 по оси Y.
Рассуждения, которые я бы применил, чтобы понять ответ, заключались бы в том, чтобы изменить масштабирование.
Если бы вы масштабировали всю ось Y чертежа с коэффициентом 1/0,38≈2,63, то эллипс выглядел бы как круг. Но тогда угол синей линии был бы другим. Потому что у него будет слот не 0,7/0,3, а 2,63×0,7/0,3.
И этот угол также будет углом пересечения точки этой синей линии и эллипса. Это параметрическая координата пересечения эллипса.
Поскольку эта параметрическая координата не зависит от масштабирования, она остается неизменной даже при текущем масштабе 0,38.
Итак, вывод такой
let angle = Math.atan((0.7/0.3)*a/b);
let x = a*Math.cos(angle);
let y = b*Math.sin(angle);
Демонстрация:
let a=1;
let b=0.38;
let canvas=document.getElementById('canvas');
let ctx = canvas.getContext("2d");
let y0=120;
let x0=100;
let sc=150;
ctx.strokeStyle='#000000';
// Axis
ctx.beginPath();
ctx.moveTo(0,y0);
ctx.lineTo(300,y0);
ctx.stroke();
ctx.moveTo(x0,0);
ctx.lineTo(x0,300);
ctx.stroke();
// Ellipse
ctx.strokeStyle='#ff0000';
ctx.beginPath();
ctx.moveTo(x0+sc*a,y0);
ctx.ellipse(x0,y0,sc*a, sc*b, 0, 0, 6.28);
ctx.stroke();
// Blue line
ctx.strokeStyle='#0000ff';
ctx.beginPath();
ctx.moveTo(x0,y0);
ctx.lineTo(x0+0.3*sc, y0-0.7*sc);
ctx.stroke();
// Intersection coordinate. The next 3 lines are my answer
// (all the lines before, and after the next 3, are just
// what is needed for drawing)
let angle = Math.atan((0.7/0.3)*a/b);
let x = a*Math.cos(angle);
let y = b*Math.sin(angle);
// Draw a yellow box at this point. It should intersect both ellipse and line
ctx.fillStyle='#888800';
ctx.beginPath();
ctx.fillRect(x0+x*sc-5, y0-y*sc-5, 10, 10);
<canvas id=canvas width=300 height=200>
</canvas>
Теперь вы можете заметить, что он не отвечает строго на вопрос в заголовке вашего вопроса. Он не дает координаты точки эллипса на основе угла. Поскольку angle здесь не угол синей линии, а угол, который она имела бы, если бы мы масштабировали диаграмму так, чтобы эллипс выглядел как круг.
Но из тела вашего вопроса и, более того, из вашего кода кажется, что ваш реальный вопрос - это «поиск точки в эллипсе на основе наклона линии 0,7/0,3».
Но если вы действительно хотите найти точку по углу (угол синей линии, вам просто нужно использовать tan, чтобы получить наклон, прежде чем масштабировать и использовать atan, чтобы получить реальный угол, который нам нужен.
Так
let parametricAngle = Math.atan(Math.tan(inputAngle)*a/b);
let x=a*Math.cos(parametricAngle);
let y=b*Math.sin(parametricAngle);
Потрясающие! +1. Я пытался сделать это с помощью холста масштаба и перевода, но это тоже не сработало.
Удивительно и намного проще, чем другие решения, которые я нашел и которые я не мог заставить работать! Было бы просто добавить ограничение переменного центра эллипса? Если его центр не 0; 0, а, например, 0,5; 3, было бы просто применить это решение?
@papillon Это ничего не меняет или почти не меняет. Кстати, вы можете видеть, что в моем фрагменте javascript в реальности центр не (0,0), а (x0,y0)=(100,120), поскольку (0,0) на холсте будет в углу холста . Итак, если у вас есть синяя линия, проходящая через центр (x0, y0) и другую точку (x1, y1), (x1-x0) становится новым 0,3 вашего примера, а (y1-y0) новым 0,7. Таким образом, угол точки равен atan((y1-y0)/(x1-x0)), а то, что я назвал parametricAngle (это угол, который вы должны передать cos и sin), равен atan((y1-y0)/(x1-x0)*a/b).
Затем из этого parametricAngle=Math.atan((y1-y0)/(x1-x0)*a/b) вы можете узнать точку пересечения, которая является x=x0+a*Math.cos(parametricAngle); и y=y0+b*Math.sin(parametricAngle);.
Примерно так, как я сделал во фрагменте. Где x0, y0 равно 100 и 120. А x1-x0 0,3, y1-y0 0,7. Единственная разница в том, что в сниппете я сказал y=y0-b*Math.sin(parametricAngle), поэтому - вместо +. Это потому, что в холсте ось y направлена вниз, и я хотел сымитировать ваш график, где ось y по традиции направлена вверх.
Обратите внимание, что в защиту решений, которые вы получили на Math.SE, они отвечают на первоначальный вопрос. Это не «как я нахожу пересечение эллипса и прямой», а «как я нахожу точку эллипса под углом angle». Мой ответ на это также проще (просто вычислить parametricAngle=Math.atan(Math.tan(angle)*a/b). А затем вычислить cos и sin этого. Что в конце приводит к выражению x=a*Math.cos(Math.atan(Math.tan(angle)*a/b)) и y=b*Math.sin(Math.atan(Math.tan(angle)*a/b))
Такие sin, cos, tan atan — операции достаточно высокого уровня. Это может быть проще понять, но компьютеру немного сложнее вычислить. А те sin(atan(tan(...))) и cos(atan(tan(...))) имеют более простую формулировку (с точки зрения компьютера, а не с вашей :D). Ответы формы Math.SE — это более простые выражения.
В вашем случае это будет означать, что директор синей линии dx,dy обозначен как dx=0.3; dy=0.7;, x и y можно вычислить как x=a*b*/Math.sqrt(b*b+a*a*dy*dy/dx/dx) и y=b*Math.sqrt(1-x*x/a/a)
Очень ясно, спасибо @chrslg! :)
Просто инверсия из решения Math.SE (которое называет y тем, что я называю x, и x тем, что я называю y). Но вне этого они являются одними и теми же ценностями. И быстрее вычисляются. Даже если немного сложнее объяснить
Отвечает ли это на ваш вопрос? OpenGL Ellipse с проблемами начального/конечного угла см. [Edit2] Быстрое аналитическое решение O (1) в моем ответе там