3

我正在尝试沿样条线生成 3d 管。我有样条线的坐标(x1,y1,z1 - x2,y2,z2 - 等),您可以在黄色插图中看到。在这些点上,我需要生成圆,其顶点将在以后的体育场连接。圆需要垂直于样条的两条线段的“角”,以形成正确的管。请注意,出于说明目的,这些段保持较低。

[显然我不允许发布图片,所以请在此链接查看图片] http://img191.imageshack.us/img191/6863/18720019.jpg

我能够计算样条曲线每个点的每个环的顶点,但它们都在同一个平面上,即相同的角度。我需要根据他们的“腿”(例如 A 和 B 对 C)旋转它们。

我一直在思考这个问题并想到了以下几点:

  • 两条线段可以看作 2 个向量(在插图 A 和 B 中)
  • 角落(在 illustraton C 中)是需要计算顶点环的地方
  • 我需要找到所有顶点所在的平面
  • 然后我可以使用这个平面(=向量?)从中心点计算新向量,即 C
  • 并使用半径 * sin 和 cos 找到它们的 x,y,z

但是,我对此的数学部分真的很困惑。我读到了点积,但它返回一个标量,我不知道在这种情况下如何应用。

有人可以指出我正确的方向吗?

[编辑] 提供有关情况的更多信息:

我需要构造一个浮点缓冲区,它以 3 个一组描述顶点位置并将由 OpenGL ES 连接,给定另一个带有索引的缓冲区以形成多边形。

为了给管子赋予形状,我首先创建了一个浮点数组,它以 3 个为一组描述了 3d 空间中的控制点。

然后连同一个用于分段密度的变量,我将这些控制点传递给一个函数,该函数使用这些控制点创建一个 CatmullRom 样条曲线,并以另一个浮点数组的形式返回它 - 再次以 3 个为一组 - 描述catmull rom 样条。

在每个顶点上,我想创建一个顶点环,其密度也可以不同(平滑度/每个环的顶点数)。

所有以前的顶点(控制点和描述 catmull rom 样条的顶点)都被丢弃。

只有形成管环的顶点才会被传递给 OpenGL,Op​​enGL 反过来将连接这些顶点以形成最终的管。

我能够创建 catmullrom 样条,并在其顶点的位置创建环,但是,它们都位于相同角度的平面上,而不是遵循样条路径。

[/编辑]

谢谢!

4

4 回答 4

10

假设您有一条参数曲线,例如:

xx[t_] := Sin[t];
yy[t_] := Cos[t];
zz[t_] := t;  

这使: 替代文字

我们曲线的切向量由每个方向的导数形成。在我们的例子中

Tg[t_]:= {Cos[t], -Sin[t], 1}  

该向量的正交平面用于求解隐式方程:

Tg[t].{x - xx[t], y - yy[t], z - zz[t]} == 0  

在我们的例子中是:

-t + z + Cos[t] (x - Sin[t]) - (y - Cos[t]) Sin[t] == 0  

现在我们在那个平面上找到一个圆,以曲线为中心。IE:

c[{x_, y_, z_, t_}] := (x - xx[t])^2 + (y - yy[t])^2 + (z - zz[t])^2 == r^2  

求解这两个方程,你得到圆的方程:

替代文字

编辑

通过画很多圈,你可能会得到一个(效率不高的)管子:

替代文字

或者使用一个好的图形 3D 库:

替代文字

编辑

既然你坚持:) 这是一个计算路口圆的程序。

a = {1, 2, 3}; b = {3, 2, 1}; c = {2, 3, 4};
l1 = Line[{a, b}];
l2 = Line[{b, c}];

k = Cross[(b - a), (c - b)] + b; (*Cross Product*)
angle = -ArcCos[(a - b).(c - b)/(Norm[(a - b)] Norm[(c - b)])]/2;
q = RotationMatrix[angle, k - b].(a - b);
circle[t_] := (k - b)/Norm[k - b] Sin@t + (q)/Norm[q] Cos@t + b;

Show[{Graphics3D[{
    Red, l1,
    Blue, l2,
    Black, Line[{b, k}],
    Green, Line[{b, q + b}]}, Axes -> True],
  ParametricPlot3D[circle[t], {t, 0, 2 Pi}]}]

替代文字

编辑

在这里,您有通过这种方法构建的网格。这不漂亮,恕我直言:

替代文字

于 2010-12-22T02:23:54.300 回答
1

您需要查看微分几何中的 Fenet 公式。有关螺旋线的示例,请参见图 2.1。

曲面和曲线

于 2010-12-22T02:30:37.313 回答
1

我不知道您选择的语言是什么,但是如果您说 MatLab,那么已经有一些可用的实现了。即使您使用的是另一种语言,某些代码也可能足够清晰,可以激发重新实现的灵感。

关键是,如果你不想让你的管子在连接顶点时发生扭曲,你就无法在本地确定基础,而是需要沿着曲线传播它。jalexiou 提出的Frenet 框架是一种选择,但更简单的东西也可以正常工作。

我在我的成长时期做了一个简单的 MatLab 实现tubeplot.m(基于一个简单的非 Frenet 传播),并用谷歌搜索它,我可以看到来自 kth.se 的 Anders Sandberg 已经做了一个(重新?)同名的实现,可用在http://www.nada.kth.se/~asa/Ray/Tubeplot/tubeplot.html

TubePlot.m 插图

编辑: 以下是简单实现的伪代码tubeplot.m。我发现它非常健壮。

该计划是传播两条法线ab沿曲线传播,以便在曲线上的每个点处,与曲线ab切线将形成一个正交基,该基“尽可能接近”前一点中使用的基。使用这个基础,我们可以在管的圆周上找到点。

// *** Input/output ***
// v[0]..v[N-1]: Points on your curve as vectors
//               No neighbours should overlap
// nvert: Number of vertices around tube, integer.
// rtube: Radius of tube, float.
// xyz: (N, nvert)-array with vertices of the tube as vectors


// *** Initialization ***
// 1: Tangent vectors
for i=1 to N-2:
    dv[i]=v[i+1]-v[i-1]
dv[0]=v[1]-v[0], dv[N-1]=v[N-1]-v[N-2]

// 2: An initial value for a (must not be pararllel to dv[0]):
idx=<index of smallest component of abs(dv[0])>
a=[0,0,0], a[idx]=1.0

// *** Loop ***
for i = 0 to N-1:
    b=normalize(cross(a,dv[i]));
    a=normalize(cross(dv[i],b));
    for j = 0 to nvert-1:
        th=j*2*pi/nvert 
        xyz[i,j]=v[i] + cos(th)*rtube*a + sin(th)*rtube*b

cos实现细节:您可能可以通过预先计算and来加快速度sin。此外,为了获得稳健的性能,您应该将输入点融合得比 更接近,例如0.1*rtube,或至少测试所有向dv量均非零。

高温高压

于 2010-12-22T03:20:28.230 回答
0

取线段和向上向量的叉积会给你一个与它们都成直角的向量(除非线段正好向上或向下),我称之为水平。取水平和线段的叉积,得到另一个与线段和另一个垂直的向量(我们称之为垂直)。然后,您可以通过 lineStart + cos theta * Horizo​​ntal + sin theta * vertical 获取 0 - 2Pi 中的 theta 的圆坐标。

编辑:要获得两个线段之间中点的点,请使用两个线段向量的总和来找到平均值。

于 2010-12-21T22:04:45.360 回答