Пытаюсь повторить полигон, тот что изображен зеленой линией на рисунке ниже. Пользовался этими советами:
Совет первый Совет второй
Оба дают результат с некоторым смещением вдоль окружностей. Помогите, пожалуйста, в чем моя ошибка.
Jsfiddle проект
Писал на JS, но подойдёт любое другое решение. Даже без кода, в чистой теории, в чем неверен мой подход.
//
Поскольку нужны только внешние касательные (могут быть ещё внутренние), то подход может быть не слишком сложным:
Пусть центр большей окружности CR
, меньшей cr
. Вектор разности d
, его длина и нормализованный вектор:
d = cr - CR
dlen = length(d)
ud = d / dlen
Общие касательные к окружностям разного радиуса пересекаются где-то в точке OP
. Касательная вместе с радиусами к точкам касания образует два подобных прямоугольных треугольника (поскольку радиус перпендикулярен касательной). Из подобия следует
Coeff = R / (R - r)
OP = CR + d * Coeff
Синус и косинус угла A
этого треугольника
ca = R / (dlen * Coeff)
sa = Sqrt(1-ca*ca)
Точки касания большой окружности могут быть получена поворотом вектора ud*R
на A
и -A
P.x = CR.x + ca * R * ud.x + sa * R * ud.y
P.y = CR.y - sa * R * ud.x + ca * R * ud.y
Q.x = CR.x + ca * R * ud.x - sa * R * ud.y
Q.y = CR.y + sa * R * ud.x + ca * R * ud.y
Аналогично для малой окружности с использованием её центра и радиуса.
Тест:
fiddle: (подправил последовательность точек и знаки углов)
let c1 = this.state.circles[0];
let c2 = this.state.circles[1];
let l = getVectorLen(c1,c2);
let v = {x: c2.x-c1.x, y: c2.y-c1.y};
let uv = {x: v.x / l, y: v.y / l};
let ca = (c2.r - c1.r) / l;
let sa = Math.sqrt(1 - ca*ca);
let ps = [
c1.x - ca * c1.r * uv.x - sa * c1.r * uv.y,
c1.y + sa * c1.r * uv.x - ca * c1.r * uv.y,
c1.x - ca * c1.r * uv.x + sa * c1.r * uv.y,
c1.y - sa * c1.r * uv.x - ca * c1.r * uv.y,
c2.x - ca * c2.r * uv.x + sa * c2.r * uv.y,
c2.y - sa * c2.r * uv.x - ca * c2.r * uv.y,
c2.x - ca * c2.r * uv.x - sa * c2.r * uv.y,
c2.y + sa * c2.r * uv.x - ca * c2.r * uv.y
];
На картинке 2 из вашего вопроса имеется две окружности с центрами в точках c1
и c2
радиусов r1
и r2
. Центры окружностей соединены прямой. Необходимо в каждой окружности провести 2 диаметра перпендикулярных отрезку, соединяющему центры. Точки пересечений диаметров с окружностью образуют искомый четырехугольник (трапецию).
circles: [
{ r: 20, x: 50, y: 150, f: 'black'}, // c1
{ r: 50, x: 150, y: 100, f: 'black'} // c2
]
Для решения необходимо определить угол alpha
между вектором c1c2
и осью Х. После чего будет понятно, под каким углом проходят диаметры. Нам потребуется поставить 4 точки, каждая из которых будет удалена от центра на расстояние радиуса под углом alpha + 90
или alpha - 90
.
Как известно, тангенс угла в прямоугольном треугольнике равен отношению длины противолежащего катета к прилежащему. Так что угол alpha
достаточно просто вычисляется с помощью формулы (не рассматриваем ситуацию когда x1=x2
):
let alpha = Math.atan( (c2.y - c1.y) / (c2.x-c1.x) );
Если нам известна исходная точка (x0, y0)
, и нам надо сдвинуться на расстояние R
под углом a
, то координаты новой точки будут иметь вид x1 = x0 + R*Cos(a)
и y1 = y0 + R*Sin(a)
.
В данном случае R
будет принимать значения r1
и r2
(радиусов окружностей), а угол с поворотом на 90 градусов - alpha + PI/2
и alpha - PI/2
.
В исходном виде формула для вычисления координат первой точки будет иметь вид
x1 = c1.x + Math.cos(alpha + Math.PI/2)*c1.r;
y1 = c1.y + Math.sin(alpha + Math.PI/2)*c1.r;
Для второй - то же самое с углом alpha - Math.PI/2
. Затем аналогичные равенства для окружности c2
.
Вспомнив тригонометрические формулы приведения (про углы α ± π/2
и -α
) все эти вычисления сводятся к следующему:
let cosA = Math.cos(alpha);
let sinA = Math.sin(alpha);
let ps = [
c1.x - sinA*c1.r, // x1
c1.y + cosA*c1.r, // y1
c1.x + sinA*c1.r, // x2
c1.y - cosA*c1.r, // y2
c2.x + sinA*c2.r, // x3
c2.y - cosA*c2.r, // y3
c2.x - sinA*c2.r, // x4
c2.y + cosA*c2.r, // y4
];
jsfidlle
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
У меня есть 2 input: ФИО и номер телефонаНужно, чтобы клиент в поле ФИО мог ввести только буквы, а в поле телефон - только цифры
Не могу придумать как получить элемент над которым произойдет действие onmouseup (то есть когда отпускаю перемещаемый элемент)