Учитывая фиксированный угол, ширину и сагитту, как мы можем рассчитать горизонтальные и вертикальные радиусы эллипса? - PullRequest
1 голос
/ 30 января 2020

Учитывая фиксированный угол, ширину и сагитту, как мы можем рассчитать горизонтальный и вертикальный радиусы эллипса?

Я хочу нарисовать эллиптическую ар c, которая имеет данную ширину ар c, высота (Сагитта) и является заданным углом эллипса.
На приведенной ниже диаграмме пунктирная черная и желтая ar c. Для этого мне нужно знать 2 радиуса эллипса.

Для круга можно легко рассчитать его 1 радиус, дать любые 2 значения угла, сагитты или ширины.
См. Фрагмент ниже .
Как я могу настроить функцию для работы с эллипсом? На графике угол, так сказать, симметричен от -60 до 60, образуя угол 120. Это тот случай, который мне действительно нужен, т.е. когда ar c отражает себя с обеих сторон вертикальной или горизонтальной осей.
В случае, когда угол был 120, который начинался в 80 и заканчивался в 200, нет истинной сагитты, только самая высокая точка ar c и жесткая ограничивающая рамка, которую будет гораздо труднее решить, если у кого-то есть решение также для этого это было бы роскошью.

Ellipse

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
  };
};

1 Ответ

3 голосов
/ 30 января 2020

Даны угол альфа, ширина и сагитта. Радиус r круга можно рассчитать по альфе, а ширину по формуле синуса. Аналогично, x - sagitta следует из формулы косинуса.

Чтобы найти y, мы масштабируем чертеж в направлении x с коэффициентом y/x. Это превратит эллипс в круг радиуса y. Он преобразует точку в [x-sagitta, width/2] в [(x-sagitta)*y/x, width/2]. Эта преобразованная точка должна быть на окружности с радиусом y. Мы получаем квадратное c уравнение в y:

((x-sagitta)*y/x)^2 + (width/2)^2 = y^2.

Его положительное решение -

y = width * x * sqrt(1 / (sagitta * (2 * x - sagitta))) / 2.

при условии это 2*x > sagitta. Что уменьшает до cos(alpha/2) > 0 или alpha < 180°. Конечно, экстремальные комбинации сагитты, ширины и альфы могут привести к чрезвычайно вытянутым эллипсам.

При возобновлении это дает (r - радиус круга, х и у - оси эллипса):

r = width / 2 / sin(alpha / 2)
x = r * cos(alpha / 2) + sagitta
y = width * x / sqrt(sagitta * (2 * x - sagitta)) / 2

Печать всего с использованием Python и matplotlib гарантирует, что уравнения имеют смысл:

from matplotlib import pyplot as plt
from matplotlib.patches import Ellipse
from math import sqrt, sin, cos, atan, pi

sagitta = 15
alpha = 120 * pi / 180
width = 100

r = width / 2 / sin(alpha / 2)
x = r * cos(alpha / 2) + sagitta
y = width * x / sqrt(sagitta * (2 * x - sagitta)) / 2

ax = plt.gca()
ax.plot([r * cos(alpha / 2), 0, r * cos(alpha / 2)], [- r * sin(alpha / 2), 0, r * sin(alpha / 2)], ls='-',
        color='crimson')

ellipse = Ellipse((0, 0), 2 * x, 2 * y, color='purple', linewidth=1, fill=False, ls='-')
circle = Ellipse((0, 0), 2 * r, 2 * r, color='tomato', linewidth=1, fill=False, ls='-.')

lim = max(x, y) * 1.05
ax.set_xlim(-lim, lim)
ax.set_ylim(-lim, lim)
ax.axhline(0, color='silver')
ax.axvline(0, color='silver')
ax.plot([x-sagitta, x-sagitta], [width/2, -width/2], color='limegreen', ls='--')
ax.plot([x-sagitta, x], [0, 0], color='brown', ls='--')
ax.add_patch(ellipse)
ax.add_patch(circle)
ax.text(x-sagitta, width/2, ' [x-s, w/2]')
ax.set_aspect(1)
plt.show()

resulting plot

...