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

代码结果展示:

多个圆柱展示:

相关推荐
Dave.B20 小时前
【VTK实战】vtkDepthImageToPointCloud:从2D深度图到3D点云,手把手教你落地3D扫描/AR场景
算法·计算机视觉·3d·ar·vtk
IT古董1 天前
【第五章:计算机视觉-计算机视觉在工业制造领域中的应用】1.工业缺陷分割-(1)工业品缺陷风格基础知识:割任务定义、数据集介绍
计算机视觉·3d·自动驾驶
wenjie学长1 天前
[3dmax自研插件]——3ds Max 智能材质检查器
3d·3dmax插件·材质·模型材质贴图检查·拖拽使用
xhload3d2 天前
智慧钢厂高炉冶炼仿真分析 | 图扑数字孪生
3d·智慧城市·html5·webgl·数字孪生·可视化·热力图·智慧工厂·工业互联网·工业组态·高炉炼铁·数字工厂·高炉炉体·智慧高炉·高炉
lrh30252 天前
Custom SRP 12 - HDR
3d·unity·srp·render pipeline
开发游戏的老王3 天前
虚幻引擎虚拟制片入门教程 之 3D渲染基础知识:模型、材质、贴图、UV等
3d·虚幻·材质·模型·着色器·uv
Kingsdesigner3 天前
从AI画稿到3D虚拟时装:Illustrator与Substance 3D的服装设计工作流
人工智能·3d·illustrator·substance 3d·sampler·stager·数字时尚
程序猿阿伟3 天前
《3D动作游戏受击反馈:从模板化硬直到沉浸式打击感的开发拆解》
前端·网络·3d
Bar_artist3 天前
AI 颠覆室内设计:SpatialGen 实现 “一句话生成 3D 房间”
人工智能·3d
CG_MAGIC3 天前
3D 云渲染:不止于高效,更是创作的革新之力
3d·3dmax·渲云渲染