Подтвердить что ты не робот

Как вычислить центр эллипса на две точки и размеры радиуса

При работе над реализацией SVG для Internet Explorer, основанной на собственном формате VML, я столкнулся с проблемой перевода эллиптической дуги SVG на эллиптическую дугу VML.

В VML дуга задается следующим образом: два угла для двух точек на эллипсе и длины радиусов, В SVG дуга задается: двумя парами координат для двух точек на эллипсе и размерами градиента границы эллипса

Итак, возникает вопрос: как выразить углы двух точек на эллипсе на две пары их координат. Промежуточным вопросом может быть: Как найти центр эллипса по координатам пары точек на его кривой.

Обновить: дайте предварительное условие, говорящее, что эллипс обычно помещается (его радиусы параллельны оси линейной системы координат), поэтому не применяется поворот.

Обновление: этот вопрос не связан с элементом svg: ellipse, а скорее с "a" командой эллиптической дуги в элементе svg: path (Пути SVG: команды кривой эллиптической кривой)

4b9b3361

Ответ 1

Итак, решение здесь:

Параметризированная формула эллипса:

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

Положим на него известные координаты двух точек:

x1 = x0 + a * cos(t1)
x2 = x0 + a * cos(t2)
y1 = y0 + b * sin(t1)
y2 = y0 + b * sin(t2)

Теперь у нас есть система уравнений с 4 переменными: центр эллипса (x0/y0) и два угла t1, t2

Пусть вычитают уравнения, чтобы избавиться от центральных координат:

x1 - x2 = a * (cos(t1) - cos(t2))
y1 - y2 = b * (sin(t1) - sin(t2))

Это можно переписать (с формулами тождеств по продуктам) как:

(x1 - x2) / (2 * a) = sin((t1 + t2) / 2) * sin((t1 - t2) / 2)
(y2 - y1) / (2 * b) = cos((t1 + t2) / 2) * sin((t1 - t2) / 2)

Заменим некоторые из уравнений:

r1: (x1 - x2) / (2 * a)
r2: (y2 - y1) / (2 * b)
a1: (t1 + t2) / 2
a2: (t1 - t2) / 2

Тогда мы получим систему простых уравнений:

r1 = sin(a1) * sin(a2)
r2 = cos(a1) * sin(a2)

Разделение первого уравнения на второе дает:

a1 = arctan(r1/r2)

Добавление этого результата в первое уравнение дает:

a2 = arcsin(r2 / cos(arctan(r1/r2)))

Или, просто (с использованием композиций триггерных и обратных триг-функций):

a2 = arcsin(r2 / (1 / sqrt(1 + (r1/r2)^2)))

или еще проще:

a2 = arcsin(sqrt(r1^2 + r2^2))

Теперь исходную систему четырех уравнений можно разрешить с помощью простых и всех углов, а также координат центра затмения.

Ответ 2

Введенная вами ссылка на эллиптическую кривую включает ссылку на заметки об использовании эллиптической дуги.

Здесь вы найдете уравнения для преобразования от конечной точки к параметризации центра.

Вот моя реализация JavaScript этих уравнений, взятых из интерактивной демонстрации эллиптических дуговых путей, используя Sylvester.js для выполнения матричных и векторных вычислений.

// Calculate the centre of the ellipse
// Based on http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
var x1 = 150;  // Starting x-point of the arc
var y1 = 150;  // Starting y-point of the arc
var x2 = 400;  // End x-point of the arc
var y2 = 300;  // End y-point of the arc
var fA = 1;    // Large arc flag
var fS = 1;    // Sweep flag
var rx = 100;  // Horizontal radius of ellipse
var ry =  50;  // Vertical radius of ellipse
var phi = 0;   // Angle between co-ord system and ellipse x-axes

var Cx, Cy;

// Step 1: Compute (x1′, y1′)
var M = $M([
               [ Math.cos(phi), Math.sin(phi)],
               [-Math.sin(phi), Math.cos(phi)]
            ]);
var V = $V( [ (x1-x2)/2, (y1-y2)/2 ] );
var P = M.multiply(V);

var x1p = P.e(1);  // x1 prime
var y1p = P.e(2);  // y1 prime


// Ensure radii are large enough
// Based on http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
// Step (a): Ensure radii are non-zero
// Step (b): Ensure radii are positive
rx = Math.abs(rx);
ry = Math.abs(ry);
// Step (c): Ensure radii are large enough
var lambda = ( (x1p * x1p) / (rx * rx) ) + ( (y1p * y1p) / (ry * ry) );
if(lambda > 1)
{
    rx = Math.sqrt(lambda) * rx;
    ry = Math.sqrt(lambda) * ry;
}


// Step 2: Compute (cx′, cy′)
var sign = (fA == fS)? -1 : 1;
// Bit of a hack, as presumably rounding errors were making his negative inside the square root!
if((( (rx*rx*ry*ry) - (rx*rx*y1p*y1p) - (ry*ry*x1p*x1p) ) / ( (rx*rx*y1p*y1p) + (ry*ry*x1p*x1p) )) < 1e-7)
    var co = 0;
else
    var co = sign * Math.sqrt( ( (rx*rx*ry*ry) - (rx*rx*y1p*y1p) - (ry*ry*x1p*x1p) ) / ( (rx*rx*y1p*y1p) + (ry*ry*x1p*x1p) ) );
var V = $V( [rx*y1p/ry, -ry*x1p/rx] );
var Cp = V.multiply(co);

// Step 3: Compute (cx, cy) from (cx′, cy′)
var M = $M([
               [ Math.cos(phi), -Math.sin(phi)],
               [ Math.sin(phi),  Math.cos(phi)]
            ]);
var V = $V( [ (x1+x2)/2, (y1+y2)/2 ] );
var C = M.multiply(Cp).add(V);

Cx = C.e(1);
Cy = C.e(2);

Ответ 3

Эллипс не может быть определен только двумя точками. Даже круг (специальный осевой эллипс) определяется тремя точками.

Даже с тремя точками у вас будут бесконечные эллипсы, проходящие через эти три точки (подумайте: вращение).

Обратите внимание, что ограничивающий прямоугольник предлагает центр эллипса и, скорее всего, предполагает, что его основная и малая оси параллельны осям x, y (или y, x).

Ответ 4

Промежуточный вопрос довольно прост... вы этого не делаете. Вы работаете над центром эллипса из ограничивающего прямоугольника (а именно, центр ящика является центром эллипса, если эллипс центрирован в ящике).

Для вашего первого вопроса я бы посмотрел на полярную форму уравнения эллипса, которая доступна на Wikipedia. Вам нужно будет также изучить эксцентриситет эллипса.

Или вы можете перетащить значения из ограничивающей рамки... выработать, если точка находится на эллипсе и соответствует углу, и перебирать каждую точку в ограничивающей рамке.