使用plotly dash 画3d圆柱(Python)

plotly3D (3d charts in Python)可以画3维图形

在做圆柱的3D装箱项目,需要装箱的可视化,但是Mesh (3d mesh plots in Python)只能画三角形,所以需要用多个三角形拼成一个圆柱(想做立方体的可视化,可以进入使用plotly dash 画3d立方体_python 3d绘图立方体-CSDN博客):

1 画上下底面的边线:因为只能画直线,所以只能用n边形代替圆(我感觉30-50就足够了)

使用plotly dash 画3d圆柱(Python)_第1张图片

# 找圆柱底边 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 个点”做边画三角形。

使用plotly dash 画3d圆柱(Python)_第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')

3 拼侧面:以上一步计算出来的 上下“圆柱底边 各num_points 个点”做边画三角形。

使用plotly dash 画3d圆柱(Python)_第3张图片

        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 math

class Cylinder:
    def __init__(self, name, diameter,height,num = 0):
        self.name = name
        self.diameter = int(diameter)
        self.radius = int(diameter/2)
        self.height = int(height)
        self.num = num
        self.coordinate = None


def cylinder_copy(cylinder:Cylinder,height):
    new_cylinder = Cylinder(cylinder.name,cylinder.diameter,cylinder.height,cylinder.num)
    new_cylinder.coordinate = cylinder.coordinate+[height]
    return new_cylinder


class Box:
    def __init__(self, name, long,wide,height):
        self.name = name
        self.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,z

def toxyz(begin,end):
    # 通过开始结束位置确定立方体的8个顶点
    #        0       1                2         3               4         5         6         7
    x = [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,kk


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 轴上的坐标都为圆心的 z 坐标
    z_top = np.full(num_points, cylinder.coordinate[2]+cylinder.height)  # 在 z 轴上的坐标都为圆心的 z 坐标
    return x,y,z_underside,z_top



def 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 ranges
        scene_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 fig




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

代码结果展示:

使用plotly dash 画3d圆柱(Python)_第4张图片

多个圆柱展示:

使用plotly dash 画3d圆柱(Python)_第5张图片

你可能感兴趣的:(plotly,dash,3d)