plotly3D (3d charts in Python)可以画3维图形
在做圆柱的3D装箱项目,需要装箱的可视化,但是Mesh (3d mesh plots in Python)只能画三角形,所以需要用多个三角形拼成一个圆柱(想做立方体的可视化,可以进入使用plotly dash 画3d立方体_python 3d绘图立方体-CSDN博客):
1 画上下底面的边线:因为只能画直线,所以只能用n边形代替圆(我感觉30-50就足够了)
# 找圆柱底边 num_points 个点
def to_cylinder_point(cylinder:Cylinder):print(cylinder)# 设置圆形参数num_points = 30 # 圆形上的点的数量# 计算圆上的点的坐标theta = np.linspace(0, 2 * np.pi, num_points)x = cylinder.coordinate[0] + cylinder.radius * np.cos(theta)y = cylinder.coordinate[1] + cylinder.radius * np.sin(theta)z_underside = np.full(num_points, cylinder.coordinate[2]) z_top = np.full(num_points, cylinder.coordinate[2]+cylinder.height)return x,y,z_underside,z_top
# 画出下底边的轮廓
fig.add_scatter3d(x=x, y=y, z=z_bottom, mode="lines", line={'color': 'black', 'width': 2})
2 拼上下底面:以上下底面圆心为中心,上一步计算出来的“圆柱底边 num_points 个点”做边画三角形。
# 将圆心插入首位b_x = np.insert(x,0,p.coordinate[0])b_y =np.insert(y,0,p.coordinate[1])b_z = np.insert(z_bottom,0,p.coordinate[2])t_z = np.insert(z_top, 0, p.coordinate[2] + p.height)i, j, k = to_planes(len(b_x))# 画底面fig.add_mesh3d(x=b_x,y=b_y,z=b_z,i=i,j=j,k=k,color='pink')# 画顶面fig.add_mesh3d(x=b_x,y=b_y,z=t_z,i=i,j=j,k=k,color='pink')
3 拼侧面:以上一步计算出来的 上下“圆柱底边 各num_points 个点”做边画三角形。
s_x = np.concatenate((x,x))s_y = np.concatenate((y,y))s_z = np.concatenate((z_top,z_bottom))ii, jj, kk = to_side(len(s_z))# 画侧面fig.add_mesh3d(x=s_x,y=s_y,z=s_z,i=ii,j=jj,k=kk,color='pink')
所有代码:
import plotly.graph_objects as go
import numpy as np
import mathclass Cylinder:def __init__(self, name, diameter,height,num = 0):self.name = nameself.diameter = int(diameter)self.radius = int(diameter/2)self.height = int(height)self.num = numself.coordinate = Nonedef cylinder_copy(cylinder:Cylinder,height):new_cylinder = Cylinder(cylinder.name,cylinder.diameter,cylinder.height,cylinder.num)new_cylinder.coordinate = cylinder.coordinate+[height]return new_cylinderclass Box:def __init__(self, name, long,wide,height):self.name = nameself.long = int(long)self.wide = int(wide)self.height = int(height)def toline(cx,cy,cz):# 通过立方体的8个顶点,画出立方体的轮廓.cx(x轴8个坐标)x = [cx[0],cx[1],cx[2],cx[3],cx[0],cx[4],cx[5],cx[1],cx[5],cx[6],cx[2],cx[6],cx[7],cx[3],cx[7],cx[4]]y = [cy[0],cy[1],cy[2],cy[3],cy[0],cy[4],cy[5],cy[1],cy[5],cy[6],cy[2],cy[6],cy[7],cy[3],cy[7],cy[4]]z = [cz[0],cz[1],cz[2],cz[3],cz[0],cz[4],cz[5],cz[1],cz[5],cz[6],cz[2],cz[6],cz[7],cz[3],cz[7],cz[4]]return x,y,zdef toxyz(begin,end):# 通过开始结束位置确定立方体的8个顶点# 0 1 2 3 4 5 6 7x = [begin[0],begin[0],end[0],end[0],begin[0],begin[0],end[0],end[0]]y = [begin[1],end[1],end[1],begin[1],begin[1],end[1],end[1],begin[1]]z = [begin[2],begin[2],begin[2],begin[2],end[2],end[2],end[2],end[2]]return x,y,z# 根据圆的边线,填满圆
def to_planes(n):ii=[]jj=[]kk=[]for v in range(1,n):ii.append(0)jj.append(v)if v+1>=n:kk.append(1)else:kk.append(v+1)return ii,jj,kk# 根据圆上下底面的边线,填满侧边
def to_side(n):ii=[]jj=[]kk=[]half = int(n/2)for i in range(half):ii.append(i)if i+1>=half:jj.append(0)else:jj.append(i+1)kk.append(i+half)if i+1>=half:ii.append(0)else:ii.append(i+1)jj.append(i+half)if i+half+1>=n:kk.append(half)else:kk.append(i+half+1)return ii,jj,kkdef to_cylinder_point(cylinder:Cylinder):print(cylinder)# 设置圆形参数num_points = 30 # 圆形上的点的数量# 计算圆上的点的坐标theta = np.linspace(0, 2 * np.pi, num_points)x = cylinder.coordinate[0] + cylinder.radius * np.cos(theta)y = cylinder.coordinate[1] + cylinder.radius * np.sin(theta)z_underside = np.full(num_points, cylinder.coordinate[2]) # 在 z 轴上的坐标都为圆心的 z 坐标z_top = np.full(num_points, cylinder.coordinate[2]+cylinder.height) # 在 z 轴上的坐标都为圆心的 z 坐标return x,y,z_underside,z_topdef getfig(box:Box,position):box_xyz = toxyz([0, 0, 0], [box.long, box.wide, box.height])box_line = toline(box_xyz[0], box_xyz[1], box_xyz[2])fig=go.Figure(data=[go.Scatter3d(x=box_line[0],y=box_line[1],z=box_line[2],mode='lines',line={'color': 'black', 'width': 2})])for p in position:x, y, z_bottom, z_top = to_cylinder_point(p)# 画下底面的线fig.add_scatter3d(x=x, y=y, z=z_bottom, mode="lines", line={'color': 'black', 'width': 2})# 画顶面的线fig.add_scatter3d(x=x, y=y, z=z_top, mode="lines", line={'color': 'black', 'width': 2})b_x = np.insert(x,0,p.coordinate[0])b_y =np.insert(y,0,p.coordinate[1])b_z = np.insert(z_bottom,0,p.coordinate[2])t_z = np.insert(z_top, 0, p.coordinate[2] + p.height)i, j, k = to_planes(len(b_x))# 画底面fig.add_mesh3d(x=b_x,y=b_y,z=b_z,i=i,j=j,k=k,color='pink')# 画顶面fig.add_mesh3d(x=b_x,y=b_y,z=t_z,i=i,j=j,k=k,color='pink')s_x = np.concatenate((x,x))s_y = np.concatenate((y,y))s_z = np.concatenate((z_top,z_bottom))ii, jj, kk = to_side(len(s_z))# 画侧面fig.add_mesh3d(x=s_x,y=s_y,z=s_z,i=ii,j=jj,k=kk,color='pink')fig.update_layout(clickmode='event+select',# 设置xyz轴比例原本比例:draw axes in proportion to the proportion of their rangesscene_aspectmode='data',scene=dict(xaxis_title='x-长'+str(box.long)+'mm',yaxis_title='y-宽'+str(box.wide)+'mm',zaxis_title='z-高'+str(box.height)+'mm',xaxis=dict(backgroundcolor="rgb(230, 230,200)",gridcolor="white",showbackground=True,zerolinecolor="black", ),yaxis=dict(backgroundcolor="rgb(230, 230,200)",gridcolor="white",showbackground=True,zerolinecolor="black"),zaxis=dict(backgroundcolor="rgb(230, 230,200)",gridcolor="white",showbackground=True,zerolinecolor="black", ),),height=600,width=800,)return figcylinder = Cylinder('a',70,30)
cylinder.coordinate=[50+2*math.sqrt(3),70,10]box = Box('b',100,200,70)
fig = getfig(box,[cylinder])
fig.show()
代码结果展示:
多个圆柱展示: