【问题标题】:How can I paint the faces of a cube?如何绘制立方体的面?
【发布时间】:2013-09-17 15:13:19
【问题描述】:

我已经做了一个可以在 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()

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

【问题讨论】:

    标签: python colors matplotlib cube


    【解决方案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()
    

    如果您需要比在 x-y 平面中更广泛地旋转,您可以使用 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()
    

    【讨论】:

    • 你好,格雷格!,太好了!但是现在我无法旋转它,那么我该如何使用使旋转成为可能的代码呢?
    • @DiegoMartínezGiardini 我已经修改了我的答案来解决这个问题。 Poly3DCollection 对象更加灵活。添加剩余的面现在留作练习。您只需要通过提供顶点列表来创建 Poly3DCollection 对象。然后你使用 set_color 方法...设置颜色。
    【解决方案2】:

    您想要的效果很难达到,原因如下:

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

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

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

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

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

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

    编辑:下面是如何将crosses 放入立方体中:

    for 循环中的if 语句检查点se 之间的距离。由于这样做的方式,它不会检查实际差异,而是检查两者之间有多少向量长度,这可以通过打印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")
    

    它用红色绘制由两个向量长度分隔的所有点

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

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

    【讨论】:

    • 但是我如何在每张脸上画出对角线十字,我被卡住了!我需要绘制面部的原因是为了识别每个面部,但是在每个面部上绘制“x”是一个很好的选择!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 2022-11-25
    相关资源
    最近更新 更多