python - 3D旋转以连 catch 和圆柱体

标签 python math 3d

我的任务是为图形绘制程序编写一个基于python的插件,该程序可生成图形的STL模型。图形是由顶点和边组成的对象,其中顶点由3D球(棋盘形二十面体)表示,边缘由圆柱体表示,圆柱体的两端均与两个球相连。 3D模型的最终结果是将其转储到STL文件中进行3D打印。我能够为球和圆柱体生成3D模型,而没有任何问题,但是在生成整体模型以及使球和圆柱体正确连接方面存在一些问题。

我最初的想法是在原点创建棋盘形二十面体,然后将其平移到顶点位置。这很好。然后,对于每个边缘,我将在原点处创建一个圆柱体,将其旋转到正确的角度,使其指向正确的方向,然后将其平移到两个顶点之间的中点,以便将圆柱体的端部嵌入在二十面体中。这就是问题所在。我在正确设置旋转方面遇到一些困难。为了计算旋转,我正在做以下事情:

首先,我发现两点之间的角度如下(其中源和目标都是图中的顶点,属于我当前正在处理的边):

        deltaX = source.x - target.x
        deltaY = source.y - target.y
        deltaZ = source.z - target.z

        xyAngle = math.atan2(deltaX, deltaY) 
        xzAngle = math.atan2(deltaX, deltaZ) 
        yzAngle = math.atan2(deltaY, deltaZ)


正在计算的角度似乎是合理的,据我所知,确实代表了顶点之间的角度。例如,如果我在(1,1,0)处有一个顶点,在(3,3,0)处有另一个顶点,则连接它们的角边缘的确在两个顶点之间显示为45度角。 (即-135度,取决于哪个顶点是源顶点,哪个顶点是目标顶点)。

一旦计算出角度,就创建一个圆柱体并将其旋转计算出的角度,就像这样,使用我创建的其他一些类:
                        c =气缸()
                        c.createCylinder(edgeThickness,edgeLength)

        c.rotateX(-yzAngle)
        c.rotateY(xzAngle)
        c.rotateZ(-xyAngle)
        c.translate(edgePosition.x, edgePosition.y, edgePosition.z)


(其中edgePosition是图形中两个顶点之间的中点,edgeThickness是要创建的圆柱的半径,edgeLength是两个顶点之间的距离)。

如前所述,汽缸的旋转无法正常工作。它似乎在x / y平面上进行了正确的旋转,但是一旦边缘的顶点在所有三个分量(x,y和z)中都不同时,旋转就会失败。这是一个图形示例,该图形的x和y分量不同,但z分量无差异:



这是生成的STL文件,如Makerware所示(用于将3D模型发送到3D打印机):



(左下角的额外圆柱体外观是我目前用于测试目的的东西-指向z轴方向的圆柱体,位于原点)。

如果我使用同一张图并在z轴上移出中间顶点,那么现在所有边缘在所有三个轴上都包含角度,那么我得到的结果如下所示:

如应用中所示:



生成的STL文件,如Makerware中所示:



...以及从侧面看的相同模型:



如您所见,汽缸肯定没有像我想的那样碰到球。我的问题是这样的:我执行此操作的方法是否有缺陷,还是我在轮换中犯了一些小但严重的错误?我很确定旋转功能本身不是问题,因为我已经能够独立验证它们是否按预期工作。我还尝试创建一个旋转函数,该函数接受偏航,俯仰和横滚并同时执行所有三个操作,并且看起来会产生相同的结果,如下所示:

c.rotateYawPitchRoll(xzAngle, -yzAngle, -xyAngle)


那么...有人对我可能做错了什么有任何想法吗?

更新:正如joojaa所指出的,这是计算正确角度及其应用顺序的结合。为了使事情正常进行,我首先计算x轴上的旋转,如下所示:

zyAngle = math.atan2(deltaVector.z, deltaVector.y)


其中deltaVector是目标向量与源向量之间的差。但是此旋转尚未应用!下一步是计算y轴上的旋转,如下所示:

angle = vector.angleBetweenVectors(vector(target.x - source.x, target.y - source.y, target.z - source.z), vector(target.x - source.x, target.y - source.y, 0.0))


一旦计算了两个旋转,就可以以相反的顺序应用它们!首先是x,然后是y:

c.rotateY(angle)
c.rotateX(-zyAngle) #... where c is a cylinder object


似乎仍然存在一些错误,但这似乎至少对一个简单的测试用例有效。

最佳答案

旋转以连续顺序发生,因此角度会相互影响。无法使用欧拉模型一次旋转它们。这就是为什么您不能仅基于第一个静态情况计算旋转的原因。想象一下转动一个立方体,使其直立在其角上。是的,第一次旋转是45,但是第二次旋转不是,因为到那个时候立方体已经旋转了(绘制序列的每一步,看看会发生什么)。空间旋转并非无关紧要。

因此,您需要旋转一个角度,然后重新计算第二个角度,依此类推。这也是为什么您的第一次轮播正常进行的原因。除非您有兴趣确保围绕轴的旋转具有特定方向,否则您只需要旋转2次即可。

我建议您改用轴角或矩阵。主要是因为在轴角度中这是微不足道的,角度是沿管的起点和终点向量之间的点,而轴是这两个角度之间的交叉点。然后,可以根据需要将其转换为欧拉角。但是可能您可以直接使用矩阵。有关如何转换以及如何直接计算轮换的想法,请参见:Christoph Gohlke的transformations.py。另请参见随附的c源代码。

我想我需要扩大这个答案

解决这个问题的真正方法很简单,那就是避免您和其他所有人的问题。答案是不要使用欧拉角旋转。 Ive用了很多脑力来解释欧拉旋转到最终没有欧拉旋转就更容易解决的问题。为了证明这一点,如果您想更多地思考更多答案,我将只留下一个原因。

大多数使用Euler旋转序列的原因是您可能不了解Euler角。实际上,只有少数情况是好的。没有自尊的程序员可以使用Euler旋转来解决此问题。您要做的是改为使用向量数学。

因此,您具有通常从源到目标的方向向量:

along = normalize(target-source)


这只是矩阵行之一(或列表示法由模型制造商决定),它与圆柱体的原始方向相对应(行仅为x y z w),那么您需要另一个垂直于该矩阵的向量。选择一个任意向量,例如up(如果您的手指指向接近up,则向左选择)。将您的向上矢量与乘积交叉用于第二行方向。最后将您的来源放在最后一列中,最后一列中加上1。完成的完整仿射矩阵描述了圆柱体定价。因为可以绘制矢量,所以更容易理解。

有较短的方法,但是这一方法很容易理解。

关于python - 3D旋转以连 catch 和圆柱体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16975412/

相关文章:

python - 压缩 if 语句以提供更准确的输出

python - Scikit-learn 中仅针对 DataFrame 的一部分进行 One-Hot 编码

python - 如何将 3D 模型转换为点数组

javascript - 3D 模型同比例,三个 JS

javascript - CSS FPS View 闪烁和卡住

python - 在多个值之后将一个大逗号分隔行拆分为多行

python - ":"的 pandas read_table usecols 错误

c++ - 快速计算 3 维空间中的粒子接近度

c++ - 如何计算插值三角曲面的主曲率?

java - 循环产生意想不到的结果