使用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就足够了)

python 复制代码
# 找圆柱底边 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
python 复制代码
# 画出下底边的轮廓
fig.add_scatter3d(x=x, y=y, z=z_bottom, mode="lines", line={'color': 'black', 'width': 2})

2 拼上下底面:以上下底面圆心为中心,上一步计算出来的"圆柱底边 num_points 个点"做边画三角形。

python 复制代码
        # 将圆心插入首位
        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 个点"做边画三角形。

python 复制代码
        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')

所有代码:

python 复制代码
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()

代码结果展示:

多个圆柱展示:

相关推荐
摆烂仙君1 小时前
3D意识(3D Awareness)浅析
人工智能·深度学习·计算机视觉·3d
whuzhang161 天前
3dgs通俗讲解
3d
3DVisionary1 天前
3D-DIC与机器学习协同模拟材料应力-应变本构行为研究
人工智能·机器学习·3d·3d-dic技术 机器学习·应力-应变本构行为·卷积神经网络(ecnn)·数字图像相关法(dic)
千鼎数字孪生-可视化1 天前
3D模型给可视化大屏带来了哪些创新,都涉及到哪些技术栈。
ui·3d·信息可视化·数据分析
huoyingcg2 天前
3D Mapping秀制作:沉浸式光影盛宴 3D mapping show
科技·3d·动画·虚拟现实
不要不开心了3 天前
Scala内容
开发语言·pytorch·flask·scala·dash
luoganttcc3 天前
FastPillars:一种易于部署的基于支柱的 3D 探测器
3d
工业3D_大熊3 天前
3D Web轻量化引擎HOOPS Communicator在装配件管理上的具体优势
3d·3d web轻量化·3d渲染·3d模型可视化·工业3d·web端3d可视化·3d复杂模型轻量化
在下胡三汉3 天前
3dmax批量转glb/gltf/fbx/osgb/stl/3ds/dae/obj/skp格式导出转换插件,无需一个个打开max,材质贴图在
3d·材质·贴图
xhload3d3 天前
智能网联汽车云控平台 | 图扑数字孪生
3d·gis·智慧城市·html5·webgl·数字孪生·可视化·工业互联网·车联网·智慧交通·智能网联·汽车云控