3D旋转连接球和圆筒圆筒

2023-09-08 10:44:03 作者:轉角遇到愛

我一直在负责编写一个基于Python的插件,图形绘图程序,生成一个图的STL模型。的曲线图是由顶点和边,其中一个顶点重新$ P $由3D球psented(一个镶嵌化二十面体)的一个目的,以及边缘重新psented与气缸,与两个球连接$ P $在任结束。 3D模型的最终结果是,它会被人抛弃了为3D打印的STL文件。我能够生成3D模型的球和圆筒没有任何问题,但我有一些问题产生的总体模型,并得到了球,气瓶连接正确。

I've been tasked with writing a python based plugin for a graph drawing program that generates an STL model of a graph. A graph being an object made up of vertices and edges, where a vertex is represented by a 3D ball (a tessellated icosahedron), and an edge is represented with a cylinder that connects with two balls at either end. The end result of the 3D model is that it will get dumped out to an STL file for 3D printing. I'm able to generate the 3D models for the balls and cylinders without any issues, but I'm having some issues generating the overall model, and getting the balls and cylinders to connect properly.

我最初的想法是在原点创建镶嵌二十面体,然后把它们翻译出来到顶点的位置。这工作得很好。我然后,对每个边缘上,我将创建一个气缸在原点,其转动到正确的角度,以使其指向正确的方向,然后将其转换成在两个顶点之间的中点,使得缸的端部被嵌入在二十面体。这就是事情的进展是错误的。我有一些困难,得到正确的旋转。要计算的旋转,我做了以下内容:

My original idea was to create tessellated icosahedrons at the origin, then translate them out to the positions of the vertices. This works fine. I then, for each edge, I would create a cylinder at the origin, rotate it to the correct angle so that it points in the correct direction, then translate it to the midpoint between the two vertices so that the ends of the cylinders are embedded in the icosahedrons. This is where things are going wrong. I'm having some difficulties getting the rotations correct. To calculate the rotations, I'm doing the following:

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

First, I find the angle between the two points as follows (where source and target are both vertices in the graph, belonging to the edge that I'm currently processing):

        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)

被计算的角度似乎是合理的,而据我所知,的确需要重新present顶点之间的角度。例如,如果我有一个顶点在(1,1,0)和其他顶点在(3,3,0),角边缘连接它们不显示为两个顶点之间的45度角。 (即,或-135度,这取决于其顶点是源极和哪个是目标)。

The angles being calculated seem reasonable, and as far as I can tell, do actually represent the angle between the vertices. For example, if I have a vertex at (1, 1, 0) and another vertex at (3, 3, 0), the angle edge connecting them does show up as a 45 degree angle between the two vertices. (That, or -135 degrees, depending which vertex is the source and which is the target).

在我的角度来计算,我创建一个圆柱体,并已计算出的,像这样的角度旋转,使用,我已经创造了一些其他类:                         C =缸()                         c.createCylinder(edgeThickness,其边缘)

Once I have the angles calculated, I create a cylinder and rotate it by the angles that have been calculated, like so, using some other classes that I've created: c = cylinder() c.createCylinder(edgeThickness, edgeLength)

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

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

(Where edgePosition is the midpoint between the two vertices in the graph, edgeThickness is the radius of the cylinder being created, and edgeLength is the distance between the two vertices).

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

As mentioned, its the rotating of the cylinders that doesn't work as expected. It seems to do the correct rotation on the x/y plane, but as soon as an edge has vertices that differ in all three components (x, y, and z), the rotation fails. Here's an example of a graph that differs in the x, and y components, but not in the z component:

和这里的得到的STL文件,如在Makerware(这是用于发送3D模型到3D打印机)所示:

And here's the resulting STL file, as seen in Makerware (which is used to send the 3D models to the 3D printer):

(额外的气缸看在左下位是我一直目前留在用于测试目的 - 的气缸指向z轴的方向上,位于原点)。

(The extra cylinder looking bit in the bottom left is something I've currently left in for testing purposes - a cylinder that points in the direction of the z axis, located at the origin).

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

If I take that same graph and move the middle vertex out in the z axis, so now all the edges involve angles in all three axis, I get a result something like the following:

由于展示的应用程序:

由此产生的STL文件,展示在Makerware:

The resulting STL file, as show in Makerware:

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

...and that same model as viewed from the side:

正如你所看到的,气缸绝对没有达到与球像我认为他们会。我的问题是:是我的方法做这个有缺陷的,或者是一些小而关键的错误,我在我的轮换使得地方?我是pretty的肯定这不是一个问题与旋转功能本身,我已经能够独立地验证它们正常工作。我也尝试创建一个旋转函数,它在偏航,俯仰和滚转和做所有三个一次,似乎产生同样的结果,像这样:

As you can see, the cylinders definitely aren't meeting up with the balls like I thought they would. My question is this: Is my approach to doing this flawed, or is it some small but critical mistake that I'm making somewhere in my rotations? I'm pretty sure it isn't a problem with the rotation functions themselves, as I've been able to independently verify that they work as expected. I also tried creating a rotate function that takes in a yaw, pitch, and roll and does all three at once, and it seemed to generate the same result, like so:

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

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

So... anyone have any ideas on what I might be doing wrong?

更新:由于joojaa指出,这是计算正确的角度,以及他们被应用的顺序的组合。为了把事情的工作,我先计算在x轴的旋转,如下:

UPDATE: As joojaa pointed out, it was a combination of calculating the correct angles as well as the order that they were applied. In order to get things working, I first calculate the rotation on the x axis, as follows:

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

其中deltaVector是目标和源向量之间的差。这种旋转还没有应用,但!下一步骤是计算在y轴的旋转,如下:

where deltaVector is the difference between the target and source vectors. This rotation is not yet applied though! The next step is to calculate the rotation on the y axis, as follows:

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

Once both rotations are calculated, they are then applied... in the reverse order! First, the x, then the y:

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

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

There still seems to be a few bugs, but this seems to at least work for a simple test case.

推荐答案

旋转发生在连续的顺序,所以角度相互影响。因此不可能使用欧拉模型来转了它们。这就是为什么基于第一静态情况下,你不能只计算旋转。试想把一个立方体,使其站在了角落里直立。是第一个旋转是45,但第二个是不是因为多维数据集已经打开到那个时候(绘制序列的每个步骤,并看看会发生什么)。空间旋转是不平凡的。

Rotation happens in successive order, so the angles affect each other. It is not possible to use a Euler model to rotate them at once. This is why you can not just calculate the rotations based on the first static situation. Just imagine turning a cube so that it is standing on its corner upright. Yes the first rotation is 45 but the second is not since the cube is already turned by that time (draw a each step of the sequence and see what happens). Space rotations aren't trivial.

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

So you need to rotate one angle then re calculate the second angle and so forth. This is also why your first rotation works right. You only need 2 rotations unless your interested in making sure the rotation around the shaft has a certain direction.

我会建议你使用轴角或矩阵,而不是要做到这一点。主要是因为在轴的角度,这是微不足道的角度之间的点沿管道起点和终点矢量和轴的2。然后,您可以将那些欧拉之间的交叉角度,如果你需要。但是,也许你只是可以直接使用矩阵。有关转换怎么怎么样的旋转直接计算理念看:的 transformations.py 通过克里斯托夫Gohlke。另请参阅随附的C源代码。

I would suggest you use axis angles or matrices instead to do this. Mainly because in axis angles this is trivial the angle is the dot between the along tube start and end vectors and the axis is the cross between those 2. You can then convert those to Euler angles if you need. But probably you can just use the matrix directly. For ideas on how conversions and how the rotation could directly be calculated see: transformations.py by Christoph Gohlke. Also see the accompanying c source.

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

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

There is a really easy way out for this question that sidesteps all your and many other persons problems. The answer is do not use Euler angle rotation. Ive used a lot of brainpower to try to explain Euler rotations to problems that are ultimately solved more easily without Euler rotations. To justify i will leave just one reason for this if you want more think up of some more answers.

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

The reason most to use Euler rotation sequences is that you probably don't understand Euler angles. There are in fact only a handful of situations where they are good. No self respecting programmer uses Euler rotations to solve this issue. What you do is you use vector math instead.

所以,你必须从源头上方向向量的目标通常是计算:

So you have the direction vector from the source to target which is usually calculated:

along = normalize(target-source)

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

this is simply one of your matrix rows (or column notation is up to model maker), the one that corresponds to your cylinders original direction (the rows are just x y z w), then you need another vector perpendicular to this one. Choose a arbitrary vector like up (or left if your along is pointing close to up). cross product this up vector by your along for the second row direction. and finally put your source as the last row with 1 in the last column. Done fully formed affine matrix describing the cylinders prition. Much easier to understand since you can draw the vectors.

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

There are shorter ways but this one is easy to understand.