如何计算沿圆柱体切片的两点之间的SVG路径弧

时间:2019-06-05 00:15:17

标签: math svg geometry trigonometry

我正在尝试利用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 个答案:

答案 0 :(得分:2)

也许您想要这样的东西
(我不熟悉JS,所以不知道如何为SVG曲线提供计算出的参数)

AB在直角坐标系中的角度为15度,recv()-rx的系数。故意将蓝弧的Y坐标偏移10个像素

enter image description here

1/cos(15)=1.035

答案 1 :(得分:1)

即插即用。唯一需要付出努力的就是Arc命令中的两个标志。

我从示例SVG的两个路径端点开始,并从形成圆柱体顶部的圆弧获得了rx和ry。但是您没有提供任何theta,所以我选择了一个theta,然后不得不调整端点,以使切片与圆柱壁对齐。

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>

答案 2 :(得分:1)

我假设以下条件:您有一个3D坐标系Oxyz和一个半径为a的右圆柱,其轴线沿着圆柱的中间延伸,与Oy轴线重合。然后,圆柱体的圆形底部垂直于轴线Oy,因此平行于(或与)坐标平面Oxz一致。在此坐标系中,圆柱可以描述为所有具有属性

的3D点
[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 rxb = ry上。

此信息使我们能够确定投影方向:

direction = [0; b; a]

即对于任何一点P = [x_3D; y_3D; [z_3D]在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)]

是圆柱上半个空间中轴线Oz为正的点,并且

[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)

变成圆柱表面上的3D曲线

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

这是一个螺旋线。

现在,将为您提供输入

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

您的目标是找到通过A和B的Oxy曲线方程,它是3D圆柱体上螺旋线的投影。

第一步:恢复圆柱体上分别突出到A和B的3D点A_3D和B_3D。使用上面的公式(假设A_3D和B_3D位于Oz的正侧)

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)];

第2步:在[s;中代表A_3D和B_3D; 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:在[s; 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]投影到坐标Oxy平面上:

x = a*cos(s/a)    
y = y_A + m*(s - s_A) - b*sin(s/a)