Как рассчитать SVG траекторию дуги между двумя точками вдоль среза цилиндра - PullRequest
1 голос
/ 05 июня 2019

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

arc section AB of cylinder

Как состояние docs , дуги SVG определяются как: "A rx ry x-axis-rotation large-arc-flag sweep-flag x y"

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

  1. Так что, очевидно, я знаю свои начальные и конечные точки (AB).
  2. Я предполагаю, что ry и в цилиндре, и в срезе равны.
  3. rx - половина гипотенузы среза.
  4. θ - это вращение оси X ... Я думаю?

    • Здесь я думаю, что у меня проблемы. Как вы можете видеть на втором изображении, когда я пытаюсь преобразовать все мои пути линий в дуги, некоторые из ars получаются идеальными, когда они не повернуты (они параллельны оси x в прямоугольной плоскости, что означает, что они следуйте пути дуги основного цилиндрического эллипса), однако, с вращением происходит нечто смешное. Когда я включаю флаг большой дуги, становится очевидным, что нарисованные эллипсы совсем не совпадают с моим цилиндром.

    • Я вполне уверен, что гипотенуза рассчитывается правильно, так как установка θ в ноль дает мне диаметр цилиндра, поэтому я немного сбит с толку относительно того, где я иду не так.

drawing star seems to be causing over/under rotation errors

TLDR: Учитывая данные, которые я привел на рисунке 1, как бы вы нарисовали дугу AB.

РЕДАКТИРОВАТЬ 1: Вот SVG цилиндра и линии для игры. Опять же, я пытаюсь сделать линию дугой, чтобы она соответствовала поверхности цилиндра, чтобы она соответствовала эллиптической дуге, образованной срезом в цилиндре.

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <path id="cylinder" fill="none" stroke="#000000" stroke-width="2" d="M 0 32 a148 32 0 0 0 296 0 a148 32 0 0 0 -296 0 v185 a148 32 0 0 0 296 0 v-185"/>
    <path id="line_should_become_arc" fill="none" stroke="#000000" stroke-width="2" d="M 37 106 L 259 148"/>
</svg>

Ответы [ 3 ]

2 голосов
/ 05 июня 2019

Возможно, вы хотите что-то вроде этого
(Я не знаком с JS, поэтому не знаю, как предоставить расчетные параметры для кривых SVG)

Угол AB в прямоугольных координатах составляет 15 градусов, 1/cos(15)=1.035 - коэффициент для rx. Y-координаты синей дуги намеренно смещены на 10 пикселей

enter image description here

<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
  <path d="M50 50 L50 250" stroke="black" fill="transparent"/>
  <path d="M50 250 A100 40 0 0 0 250 250" stroke="black" fill="transparent"/>
  <path d="M250 250 L250 50 A100 40 0 0 0 50 50 A100 40 0 0 0 250 50" stroke="black" fill="transparent"/>
  <path d="M50 150 A103.5 40 15 0 0 250 200 A103.5 40 15 0 0 50 150" stroke="black" fill="transparent"/>
  <path d="M100 210 A103.5 40 15 0 0 200 232" stroke="blue" fill="transparent"/>
</svg>
1 голос
/ 06 июня 2019

Я предполагаю следующее: у вас есть трехмерная система координат Oxyz и правый круговой цилиндр с радиусом a, ось которого, проходящая вдоль середины цилиндра, совпадает с осью Oy.Тогда круговое основание цилиндра перпендикулярно оси Oy и поэтому параллельно (или совпадает с) координатной плоскостью Oxz.В этой системе координат цилиндр можно описать как все трехмерные точки со свойством

[x; y; z] such that x^2 + z^2 = a^2, while y is arbitrary or D <= y < = U.  

. Я предполагаю, что цилиндр проецируется из системы координат 3D Oxyz на плоскость координат Oxy, так что полученная окружностьпо пересечению цилиндра с координатной плоскостью Oxz, проецируется как эллипс с большой осью длины a, выровненной с осью Ox, и малой осью длины b, выровненной с осью Oz.На твоей картинке a = cylinder rx и b = ry.

Эта информация позволяет нам определить направление проекции:

direction = [0; b; a]

, т.е. для любой точки P = [x_3D;y_3D;z_3D] в трехмерной системе Oxyz мы берем прямую через P и параллельны вектору direction, а ее пересечение с Oxy является проекцией P на Oxy.Формула для этого:

[x_3D; y_3D; z_3D] ---> [x_3D; y_3D - (b/a)*z_3D]

i.e.
x = x_3D
y = y_3D - (b/a)*z_3D

(есть еще один вариант для направления: direction = [0; - b; a], если проекция выполняется «из-под» оси Oxz вместо «над», но давайте придерживаться «над»") И наоборот, если нам дана точка [x;y] на плоскости координат Oxy 2D можно восстановить две точки на поверхности цилиндра, которые выступают на [x;y]:

[x; y] ---> [x; y + (b/a)*sqrt(a^2 - x^2);  sqrt(a^2 - x^2)]

, которая является точкой на цилиндре в полупространстве, где ось O положительна, и

[x; y] ---> [x; y - (b/a)*sqrt(a^2 - x^2);  - sqrt(a^2 - x^2)]

, которая находится на цилиндре в полупространстве, гдеось) z отрицательна.

Поверхность цилиндра можно параметризовать, взяв плоский плоский прямоугольник и согнув его в 3D, склеив два параллельных ребра, чтобы образовать правильный круговой цилиндр.Это преобразование можно записать в виде

[s; y] ---> [a*cos(s/a);  y;  a*sin(s/a)]

i.e.
x = a*cos(s/a)
y = y
z = a*sin(s/a) 

Тогда общая прямая линия на плоском квадрате

y = y0 + m*(s - s0)

превращается в трехмерную кривую, лежащую на поверхности цилиндра

x = a*cos(s/a)
y = y0 + m*(s - s0)
z = a*sin(s/a) 

, который является спиралью.

Теперь, вы задаетесь как

a, b, A = [xA; yA], B = [xB; yB]

Ваша цель - найти уравнение кривой в Окси, которая проходит через А и Ви которая является проекцией спирали на цилиндр в 3D.

Шаг 1: Восстановите трехмерные точки A_3D и B_3D на цилиндре, которые проецируются на A и B соответственно.Используя формулы выше (и предположим, что, скажем, A_3D и B_3D находятся на положительной стороне унции)

A_3D = [xA; yA + (b/a)*sqrt(a^2 - xA^2);  sqrt(a^2 - xA^2)];
B_3D = [xB; yB + (b/a)*sqrt(a^2 - xB^2);  sqrt(a^2 - xB^2)];

Step2: Представляет A_3D и B_3D в [s;y] координаты поверхности цилиндра:

s_A = a*arccos(xA);
y_A = yA + (b/a)*sqrt(a^2 - xA^2);

s_B = a*arccos(xB);
y_B = yB + (b/a)*sqrt(a^2 - xB^2);

Шаг 3: Построить прямую линию в [с;y] координаты:

m = (y_B - y_A) / (s_B - s_A) 
  = (yB + (b/a)*sqrt(a^2-xB^2) - yA - (b/a)*sqrt(a^2-xA^2)) / (a*arccos(xB) - a*arccos(xA))
  = ((yB - yA) + (b/a)*(sqrt(a^2-xB^2) - sqrt(a^2-xA^2))) / (a*arccos(xB) - a*arccos(xA));

y = y_A + m*(s - s_A);

Шаг 4: Представьте его в 3D в виде спирали:

x_3D = a*cos(s/a)
y_3D = y_A + m*(s - s_A)
z_3D = a*sin(s/a)

Шаг 5: Проецируйтеспираль из цилиндра на координатную плоскость Окси, вдоль direction = [0; b; a]:

x = a*cos(s/a)    
y = y_A + m*(s - s_A) - b*sin(s/a)  
1 голос
/ 05 июня 2019

Это в значительной степени подключи и играй. Единственное, что потребовало некоторых усилий - это два флага в команде Arc.

Я начал с двух конечных точек пути из вашего примера SVG и получил rx и ry от дуги, которая образует вершину цилиндра. Но вы не предоставили никакой тэты, поэтому я выбрал одну, и мне пришлось отрегулировать конечные точки так, чтобы срез выровнялся со стенками цилиндра.

var arc = document.getElementById("line_should_become_arc");
var slice = document.getElementById("slice");

var Ax = 57, Ay = 126;
var Bx = 279, By = 168;

var rx = 148;
var ry = 32;
var theta = 14;  // 14 deg

var slice_rx = rx / Math.cos(theta * Math.PI / 180);

arc.setAttribute("d", ['M', Ax,Ay, 'A', slice_rx, ry, theta, 0, 0, Bx,By].join(' '));

slice.setAttribute("d", ['M', Ax,Ay, 'A', slice_rx, ry, theta, 1, 1, Bx,By].join(' '));
<svg width="400" height="400">
    <path id="cylinder" fill="none" stroke="#000000" stroke-width="2" d="M 0 32 a148 32 0 0 0 296 0 a148 32 0 0 0 -296 0 v185 a148 32 0 0 0 296 0 v-185"/>
    <path id="slice" fill="none" stroke="#000000" stroke-width="2" d="M 0,0"/>
    <path id="line_should_become_arc" fill="none" stroke="#f00" stroke-width="2" d="M 0,0"/>
</svg>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...