How can I paint the faces of a cube?

泄露秘密 提交于 2020-01-25 02:17:27

问题


I have done a cube that can be rotated on python but now I want to colour the faces for me to identify each face when it's rotated. The code below:

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()

So I want to paint the cube that is inside. Any help? Thank you!


回答1:


You can use patches.

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()

If you need to rotate more generally than in the x-y plane, you can use Poly3Dcollection. This just draws the top and bottom of the cube. How you want to generate the vertices will depend on the details of what you're doing.

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()




回答2:


The effect your looking for will be difficult to achieve for the following reasons:

  • matplotlib doesn't know it is a cube, so you will need to calculate the points in the plane to colour.

  • Matplotlib 3D plotting is a projection of 3D data into 2D, this is particularly apparent when plotting the intersection of a line and a plane:

    when the line is below the plane it doesn't look like it is, you can circumvent this by say setting the transparency, alpha of the line to be less when below the line. What this means is you will need to calculated, based on the rotation which planes are "front facing" to the viewer which can change interactively!
  • The is no way to paint something in matplotlib 3d, for 2D you can use plt.fill_between but this function does not extend to 3D.

While the first two problems can in theory be solved by writing out the mathematics of the cube, defining the planes and there visibility with respect to the viewer, the last I really don't know how you would solve. Essentially you need to write fill between, a function that fills in the area with shaded polygons in 3D.

With this depressing outlook I can suggest some alternatives, just add some diagonal crosses to each face, since you already check if the vertices are on the same edge you just need to check if they are diagonal, plot and colour accordingly.

Or move to a graphical plotting tool which is designed to do this sort of thing. If you have any experience with latex then try tikz 3D plotting it combines code with very pretty output, although it is a bit of a faf.

Edit: Here is how one would put crosses into the cube:

The if statement in the for loop checks the distance between the points s and e. Due to the way this is done it does not check the actual difference but rather how many vector lengths separate the two, this can be checked by printing np.sum(np.abs(s-e)) which returns lengths of 4, 8 and 12. So we want those separated by two vectors, that is we add in another if statement

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")

which draws all points separated by two vector lengths in red

Clearly you would like to plot each cross in a different color, this is not possible with the code in it's current form. This is because we check only the lengths between points, one needs to have a way to distinguish between different sets of points.

I'm unsure of the best way to do this and so will stop here, in my opinion you need to stop just running through all combinations of points and actually label the points properly.



来源:https://stackoverflow.com/questions/18853563/how-can-i-paint-the-faces-of-a-cube

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!