具有中心、半径和法线向量的圆圆周上的 3d 点
我的问题类似于 如何制作点轨道一条线,3D 但那里的答案似乎没有解决我的问题.而我正在寻找的是一个通用的解决方案.
My question is similar to How to Make a Point Orbit a Line, 3D but the answer there didn't seem to solve my problem. And what I am looking for is a general solution.
为了记录,我正在尝试解决 OpenGL ES (Java/Android) 中的一个问题.
For the record I am trying to solve an issue in OpenGL ES (Java/Android).
我有一个圆,它的中心有一个 3D 点、一个半径和一个 3D 矢量,指定圆所在平面的法线.
I have a circle with a 3D point for its center, a radius, and a 3D vector specifying the normal to the plane the circle lies in.
我需要找到表示圆周上点的 3D 点,该点与旋转"X 轴(根据法线向量旋转)成给定角度.
I need to find the 3D point representing the point on the circumference at a given angle from the 'rotated' X-axis (rotated according to the normal vector).
我已经在 Circle
类的成员函数 pointAt
中有一个实现,它在有限的情况下工作.具体来说,在我当前的实现中,我假设圆位于 XY 平面中并相应地返回一个点,然后,由于我知道圆实际上位于 XZ 平面中,我只需交换返回点中的 Y 和 Z 值就可以了.但是,这不是一个通用的解决方案,而这正是我所需要的.
I already have an implementation in a Circle
class of a member function, pointAt
, which works under limited circumstances. Specifically, in my current implementation I assume the circle lies in the X-Y plane and return a point accordingly and then, since I know the circle is actually lying in the X-Z plane I simply swap the Y and Z values in the returned point and it works. However, this is not a general solution and that is what I am going to need.
当我尝试 如何制作Point Orbit a Line, 3D,我得到的点离它们应该在的位置很远.
When I tried the algorithm given in How to Make a Point Orbit a Line, 3D, I got points pretty far removed from where they should have been.
那么,我怎样才能在这样一个圆的圆周上计算一个点呢?
So, how, can I calculate a point on the circumference of such a circle?
我想我的解释是不够的.我的假设是一个圆在 X-Y 平面上是正常"的,Z 方向的法向量为 (0, 0, 1) - 1.如果需要圆周上的一个点,则该点由以下定义:
I guess my explanation wasn't sufficient. My assumption is that a circle is 'normally' in the X-Y plane with a normal vector of (0, 0, 1) - 1 in the Z direction. If a point on the circumference is needed the point is defined by:
x = R*cos(a) + Cx
y = R*sin(a) + Cy
其中 R
是半径,Cx
和 Cy
是 X
和 Y
圆心坐标,a
是一个向量与圆心的夹角,与 X 轴平行.
where R
is the radius, Cx
and Cy
are the X
and Y
coordinates of the center of the circle, and a
is the angle from a vector through the circle's center point and parallel with the X-axis.
现在,如果圆没有指向 Z 轴的法线向量,而是某个任意 (x, y, z) 向量,我如何找到同一个点?
Now, if the circle doesn't have a normal vector pointing along the Z-axis but, instead, is some arbitrary (x, y, z) vector, how do I find that same point?
推荐答案
你需要一个新的坐标系来放置圆.与任何常见的坐标系一样,我们希望基向量彼此正交,并且每个长度为 1.我将基向量命名为 v1
、v2
和 v3
,它们依次对应 x、y 和 z.
What you need is a new coordinate system to place the circle. As any common coordinate system, we'll want the base vectors to be orthogonal to each other, and have length 1 each. I'll name the base vectors v1
, v2
, and v3
, which correspond to x, y, and z in order.
替换z的新基向量,即v3
由圆的法线向量给出.如果它还没有标准化,您需要在这里对其进行标准化:
The new base vector that replaces z, which is v3
is given by the normal vector of the circle. If it's not normalized yet, you'll want to normalize it here:
[ v3x ]
v3 = [ v3y ] = normalize(circleNormal)
[ v3z ]
接下来,我们将选择 v1
.这可以是与 v3
正交的任意向量.由于我们希望它代替 x 轴,我们可以选择它的 y 分量为 0:
Next, we'll chose v1
. This can be an arbitrary vector that is orthogonal to v3
. Since we want it to take the place of the x-axis, we can choose it to have an y-component of 0:
[ v3z ]
v1 = normalize([ 0 ])
[ -v3x]
注意这个向量与v3
的点积为0,说明这两个向量确实是正交的.如果圆的法向量正好指向 y 方向,则该向量将退化.如果您在使用中遇到问题,我会让您弄清楚如何处理.
Note that the dot product of this vector with v3
is 0, which means that the two vectors are indeed orthogonal. The vector will be degenerate if the normal vector of the circle points exactly in the y-direction. I'll let you figure out how to handle that if it's a concern in your usage.
现在我们只需要最后一个向量,它可以计算为其他两个的叉积:
Now we just need the last vector, which can be calculated as the cross product of the other two:
v2 = v3 x v1
因为 v1
和 v3
已经过标准化,并且是正交的,所以这已经被标准化了.
This will already be normalized since v1
and v3
were normalized, and are orthogonal.
有了这个新的基础,圆上的点现在可以计算为:
With this new basis, points on the circle can now be calculated as:
p = centerPoint + R * (cos(a) * v1 + sin(a) * v2)
让整个事情更接近代码形式(未经测试):
Putting the whole thing closer to code form (untested):
// Only needed if normal vector (nx, ny, nz) is not already normalized.
float s = 1.0f / (nx * nx + ny * ny + nz * nz);
float v3x = s * nx;
float v3y = s * ny;
float v3z = s * nz;
// Calculate v1.
s = 1.0f / (v3x * v3x + v3z * v3z);
float v1x = s * v3z;
float v1y = 0.0f;
float v1z = s * -v3x;
// Calculate v2 as cross product of v3 and v1.
// Since v1y is 0, it could be removed from the following calculations. Keeping it for consistency.
float v2x = v3y * v1z - v3z * v1y;
float v2y = v3z * v1x - v3x * v1z;
float v2z = v3x * v1y - v3y * v1x;
// For each circle point.
px = cx + r * (v1x * cos(a) + v2x * sin(a))
py = cy + r * (v1y * cos(a) + v2y * sin(a))
pz = cz + r * (v1z * cos(a) + v2z * sin(a))
相关文章