1

我已经做了一个可以在 python 上旋转的立方体,但现在我想为这些面着色,以便在旋转时识别每个面。下面的代码:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from itertools import product, combinations
from numpy import sin, cos

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("auto")
ax.set_autoscale_on(True)


#dibujar cubo
r = [-10, 10]
for s, e in combinations(np.array(list(product(r,r,r))), 2):
    if np.sum(np.abs(s-e)) == r[1]-r[0]:
        ax.plot3D(*zip(s,e), color="b")


#dibujar punto
#ax.scatter([0],[0],[0],color="g",s=100)

d = [-2, 2]
theta = np.radians(45)
for s, e in combinations(np.array(list(product(d,d,d))), 2):
    if np.sum(np.abs(s-e)) == d[1]-d[0]:
        s_rotated = [s[0]*cos(theta)-s[1]*sin(theta),
                     s[0]*sin(theta)+s[1]*cos(theta),
                     s[2]]
        e_rotated = [e[0]*cos(theta)-e[1]*sin(theta),
                     e[0]*sin(theta)+e[1]*cos(theta),
                     e[2]]
        ax.plot3D(*zip(s_rotated,e_rotated), color="g")
plt.show()

所以我想画里面的立方体。有什么帮助吗?谢谢!

4

2 回答 2

1

您可以使用补丁。

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from itertools import product, combinations
from numpy import sin, cos
from matplotlib.patches import Rectangle, Circle, PathPatch
import mpl_toolkits.mplot3d.art3d as art3d

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("auto")
ax.set_autoscale_on(True)


r = [-10, 10]
for s, e in combinations(np.array(list(product(r,r,r))), 2):
    if np.sum(np.abs(s-e)) == r[1]-r[0]:
        ax.plot3D(*zip(s,e), color="b")

colors = ['b', 'g', 'r', 'c', 'm', 'y']
for i, (z, zdir) in enumerate(product([-2,2], ['x','y','z'])):
    side = Rectangle((-2, -2), 4, 4, facecolor=colors[i])
    ax.add_patch(side)
    art3d.pathpatch_2d_to_3d(side, z=z, zdir=zdir)


plt.show()

在此处输入图像描述

如果您需要比在 xy 平面中更广泛地旋转,您可以使用 Poly3Dcollection。这只是绘制立方体的顶部和底部。您希望如何生成顶点将取决于您正在执行的操作的详细信息。

from mpl_toolkits.mplot3d import Axes3D, art3d
import matplotlib.pyplot as plt
import numpy as np
from itertools import product, combinations
from numpy import sin, cos


fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("auto")
ax.set_autoscale_on(True)


r = [-10, 10]
for s, e in combinations(np.array(list(product(r,r,r))), 2):
    if np.sum(np.abs(s-e)) == r[1]-r[0]:
        ax.plot3D(*zip(s,e), color="b")


btm = np.array([[-2, -2, -2],
                [-2, 2, -2],
                [ 2, 2, -2],
                [2, -2,-2]])
top = np.array([[-2, -2, 2],
                [-2, 2, 2],
                [ 2, 2, 2],
                [2, -2,2]])
theta = np.radians(45) 
rot_mx = np.array([[cos(theta), sin(theta), 0],
                    [-sin(theta), cos(theta), 0],
                    [          0,          0, 1]])

btm = np.dot(btm, rot_mx)
side = art3d.Poly3DCollection([btm])
side.set_color('r')
ax.add_collection3d(side)

top = np.dot(top, rot_mx)
side = art3d.Poly3DCollection([top])
side.set_color('g')
ax.add_collection3d(side)


plt.show()

在此处输入图像描述

于 2013-09-19T01:37:19.257 回答
0

您所寻找的效果将难以达到,原因如下:

  • matplotlib知道它是一个立方体,所以你需要计算平面上的点来着色。

  • Matplotlib 3D 绘图是将 3D 数据投影到 2D 中,这在绘制直线和平面的交点时尤其明显: 在此处输入图像描述 当直线低于平面时,它看起来不像,你可以通过设置来规避这个问题alpha低于线时,线的透明度会降低。这意味着您需要根据旋转来计算哪些平面是“面向”观察者的,可以交互地改变!

  • 无法在 matplotlib 3d 中绘制某些东西,您可以使用 2D,plt.fill_between但此功能不会扩展到 3D。

虽然前两个问题理论上可以通过写出立方体的数学来解决,定义平面和相对于观察者的可见性,最后一个我真的不知道你会如何解决。本质上,您需要编写 fill between,该函数使用 3D 阴影多边形填充区域。

有了这种令人沮丧的前景,我可以建议一些替代方案,只需在每个面上添加一些对角线交叉,因为您已经检查了顶点是否在同一条边上,您只需要检查它们是否是对角线,相应地绘制和着色。

或者转移到旨在执行此类操作的图形绘图工具。如果您对乳胶有任何经验,请尝试tikz 3D 绘图,它将代码与非常漂亮的输出相结合,尽管它有点不合时宜。

编辑:这是如何放入crosses多维数据集的:

for 循环中的if语句检查点s和之间的距离e。由于这样做的方式,它不会检查实际差异,而是检查两者之间有多少向量长度,这可以通过打印np.sum(np.abs(s-e))返回的长度来检查4812。所以我们想要那些被两个向量分开的,也就是说我们在另一个if语句中添加

elif np.sum(np.abs(s-e))== 2 * (d[1]-d[0]):
    s_rotated = [s[0]*cos(theta)-s[1]*sin(theta),
                 s[0]*sin(theta)+s[1]*cos(theta),
                 s[2]]
    e_rotated = [e[0]*cos(theta)-e[1]*sin(theta),
                 e[0]*sin(theta)+e[1]*cos(theta),
                 e[2]]
    ax.plot3D(*zip(s_rotated,e_rotated), color="r")

它以红色绘制由两个向量长度分隔的所有点 在此处输入图像描述

显然,您希望以不同的颜色绘制每个十字,这对于当前形式的代码是不可能的。这是因为我们只检查点之间的长度,需要有一种方法来区分不同的点集。

我不确定执行此操作的最佳方法,因此将停在这里,在我看来,您需要停止遍历所有点组合并实际正确标记点。

于 2013-09-18T20:25:23.110 回答