3D旋转连接球和汽缸(3D rotations to connect balls and cylin

2019-10-18 05:13发布

我一直在负责编写一个基于Python的插件生成的图表的STL模型的图形绘图程序。 作为一个对象的曲线图由顶点和边,其中一个顶点由3D球(的镶嵌二十面体)所表示的,和边缘为代表,在任一端的两个球连接的圆筒。 3D模型的最终结果是,它会被人抛弃了为3D打印的STL文件。 我能够生成用于球和气缸没有任何问题的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,其边缘)

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

(其中edgePosition是图中的两个顶点之间的中点,edgeThickness是被创建的圆柱体的半径,并且其边缘是这两个顶点之间的距离)。

如前所述,其预期不工作气缸的旋转。 这似乎做的X / Y平面内的正确的旋转,但只要边缘具有在所有三个分量(x,y和z)不同顶点,旋转失败。 下面是在x的不同的曲线图,和y分量的一个例子,而不是在z分量:

而这里的产生STL文件,如Makerware(这是用来3D模型发送到3D打印机)所示:

(左下方额外缸找位是什么目前我已经离开了在用于测试目的 - 在z轴,位于原点的方向指向一缸)。

如果我采取相同的图形和移动中间顶点出在Z轴,所以现在所有的边缘在所有三个轴涉及的角度,我得到的结果类似如下:

作为显示在应用程序:

产生的STL文件,如秀Makerware:

...并且从侧面看的是同一个模型:

正如你所看到的,汽缸绝对不与球满足像我认为他们会。 我的问题是这样的:我的方法做这个有缺陷的,或者是说我在我的轮换使得一些地方小,但重大的错误? 我敢肯定这不是一个问题与旋转功能本身,我已经能够独立核实他们的工作预期。 我也尝试创建一个旋转函数,它在偏航,俯仰和滚转和做所有这三个在一次,它似乎产生相同的结果,如下所示:

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

所以......任何人有什么我可能是做错了什么想法?

UPDATE:作为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

目前似乎仍然是一些错误,但这似乎是一个简单的测试用例来至少工作。

Answer 1:

旋转发生在连续的顺序,所以角度相互影响。 这是不可能使用一个模型欧拉他们在一次旋转。 这就是为什么基于第一静态情况下,你不能只是计算旋转。 试想把一个立方体,使其站立在它的角立柱。 是第一次旋转是45,但第二个是不是因为魔方已经被那个时候翻(绘制序列的每一步,看看会发生什么)。 太空旋转是不平凡的。

所以,你需要旋转一个角度,然后重新计算第二角度等等。 这也是为什么你的第一旋转作品的权利。 你只需要2转,除非你关心的是绕轴旋转具有一定的方向。

我会建议你使用轴角或矩阵,而不是做到这一点。 这主要是因为在轴角度这是微不足道的角度是沿着管的开始和结束的矢量之间的点和轴线是那些2.然后可以转换那些欧拉之间的交叉,如果你需要角度。 但或许你可以直接使用矩阵。 有关如何转换,以及如何旋转可直接计算见的想法: transformations.py由克里斯托夫Gohlke。 也见所附的C源程序。

我想我需要扩大这个答案有点

有一个非常简单的出路,这个问题是回避所有和许多其他人的问题。 答案是不使用欧拉角度旋转。 香港专业教育学院用了很多脑力的试图解释Euler旋转到最终解决更容易且无Euler旋转的问题。 为了证明,如果你想了解更多想出一些更多的答案,我会离开只是一个原因。

之所以大多数使用Euler旋转顺序是,你可能不理解欧拉角。 其实有只的,他们是很好的情况了一把。 没有自尊的程序员用Euler旋转来解决这个问题。 你要做的就是使用矢量数学来代替。

所以,你必须从源头上方向向量瞄准这通常是计算:

along = normalize(target-source)

这仅仅是你的矩阵的行(或列符号高达模型制作工具)中的一个,对应于您的气瓶原始方向(行只是XYZW),那么你需要垂直于该彼此载体之一。 选择一个任意矢量喜欢了(或左如果沿着朝上接近)。 第二行方向交叉的产品这件事矢量你一起。 最后把你的信源作为最后一行1中的最后一列。 完成完全形成描述气缸prition仿射矩阵。 更容易理解,因为你可以借鉴的载体。

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



文章来源: 3D rotations to connect balls and cylinders
标签: python math 3d