向量数学,如何在两个向量之间找到平面上的坐标

3
我正在尝试沿着样条线生成一个3D管道。我有样条线的坐标(x1,y1,z1-x2,y2,z2-等),你可以在黄色的插图中看到。在这些点上,我需要生成圆,它们的顶点稍后将连接。为了形成正确的管道,圆需要垂直于样条线的两条线段的“角落”。请注意,出于说明目的,线段保持较低。

(显然,我不被允许发布图片,请在此链接中查看图像)http://img191.imageshack.us/img191/6863/18720019.jpg

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

我已经考虑了这个问题,并想到了以下解决办法:

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

然而,我对数学部分非常困惑。我读过点积但不知道如何在这种情况下应用。

有人可以指点我吗?

【编辑】 为了提供更多关于情况的信息:

我需要构建一个浮点缓冲区,其中-每组3个-描述顶点位置,并将通过OpenGL ES连接,给定另一个缓冲区与索引以形成多边形。

为了赋予管的形状,我首先创建了一个浮点数组,其中-每组3个-描述三维空间中的控制点。

然后,我将控制点与一个分段密度变量一起传递给一个函数,该函数使用这些控制点创建CatmullRom样条,并以另一个浮点数组的形式返回,其中-再次以3组为单位-描述catmull rom样条的顶点。
在每个这些顶点上,我想创建一个环形顶点,其密度(每个环的平滑程度/顶点数)也可能不同。
所有以前的顶点(控制点和描述catmull rom样条的顶点)都被丢弃了。
只有形成管道环的顶点将被传递到OpenGL,然后连接这些顶点形成最终的管道。
我已经能够创建catmullrom样条,并在其顶点位置创建环,但它们都在相同角度的平面上,而不是沿着样条路径。

谢谢!我对这个论坛的专业水平和活跃程度感到非常惊讶,所以我会注册一个账户,并开始分享我的知识 :) 我将从2) 开始。 - Will Kru
4个回答

10
假设您有一个参数曲线,例如:
xx[t_] := Sin[t];
yy[t_] := Cos[t];
zz[t_] := t;  

这给出:

alt text

曲线的切向量由每个方向上的导数形成。在我们的情况下,

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  

现在我们在该平面上找到了一个圆,其圆心在曲线上,即:

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

解决两个方程,您可以得到圆的方程式: alt text 希望能对你有所帮助! 编辑 通过画很多圆,您可以得到一个(不是很高效的)管道: alt text 或者使用一个好的3D图形库: alt text 编辑 既然您坚持:)这里有一个计算交叉点处圆的程序。
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}]}]

alt text

编辑

这里是使用该方法构建的网格。在我看来并不美观:

alt text


@Will,样条基本上是一个参数曲线。您只需使用样条的参数方程并选择要放置圆的位置即可。 - Dr. belisarius
@Will,你的问题不够清晰,因为你在第一句话中提到了样条曲线,但没有提到OpenGL。此外,OpenGL也不在你的标签中。请重新表述你的问题。另外:计算样条曲线非常容易... - Dr. belisarius
@Will 同时请注意:按照您的方式构建的管道可能不包含样条,因为它们将直接通过顶点路由,而样条将不存在。 - Dr. belisarius
@belisarius 我创建了一个Catmull-Rom样条曲线,它将始终穿过控制点本身。在图像中,您可以将样条曲线密度视为1,即仅包含控制点。 - Will Kru
@Will 环是居中的,但视觉效果很奇怪。 - Dr. belisarius
显示剩余9条评论

1

我不知道你选择的编程语言是什么,但如果你会使用MatLab,已经有一些可用的实现了。即使你使用另一种语言,其中的一些代码也可能足够清晰,以启发重新实现。

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

在我的形成阶段,我做了一个简单的MatLab实现,称为 tubeplot.m(基于简单的非 Frenet 传播),通过谷歌搜索,我可以看到来自 kth.se 的Anders Sandberg已经完成了一个同名(重新?)实现,可以在http://www.nada.kth.se/~asa/Ray/Tubeplot/tubeplot.html上获得。

TubePlot.m illustration

编辑: 以下是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

实现细节:通过预计算cossin,您可能可以加速处理速度。另外,为了获得稳健的性能,应该将输入点融合在比如0.1*rtube更近的距离内,或者至少测试所有dv向量都是非零的。

希望对你有所帮助


这是在Android平台上的JAVA。这看起来确实像我想要的东西,但是.m文件对我来说是无法阅读的,因为它似乎不是常见的代码。 - Will Kru

1

您需要了解微分几何中的 Frenet 公式。请参考图2.1,其中有一个螺旋线的示例。

曲面和曲线


+1 我在回答中只使用了与该问题相关的部分。 - Dr. belisarius

0

对线段和上向量进行叉积运算将会得到一个垂直于两者的向量(除非线段恰好指向上方或下方),我将其称为水平向量。对水平向量和线段进行叉积运算,将会得到另一个与线段和前一个向量垂直的向量(我们称之为垂直向量)。然后,通过使用公式 lineStart + cos theta * horizontal + sin theta * vertical,其中 theta 取值范围为 0 - 2Pi,可以得到圆形坐标。

编辑:要获取两个线段中点的坐标,可以使用两个线段向量的和来计算平均值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接