#javascript #svg #vector #геометрия #2d
Пытаюсь повторить полигон, тот что изображен зеленой линией на рисунке ниже. Пользовался этими советами: Совет первый Совет второй Оба дают результат с некоторым смещением вдоль окружностей. Помогите, пожалуйста, в чем моя ошибка. Jsfiddle проект Писал на JS, но подойдёт любое другое решение. Даже без кода, в чистой теории, в чем неверен мой подход. //
Ответы
Ответ 1
Поскольку нужны только внешние касательные (могут быть ещё внутренние), то подход может быть не слишком сложным: Пусть центр большей окружности 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
На картинке 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
Комментариев нет:
Отправить комментарий