Skip to content

TIN 三角网 3D 可视化

dimine_python_sdk.lib.visualization 提供基于 PyVista 的 TIN 三角网 3D 渲染功能,支持多角度视图和灵活的图片输出。

注意:此模块为纯 Python 实现,不依赖 DmPyBindInterface.pyd,无需运行 Dimine 桌面客户端即可使用。


安装

PyVista 为可选依赖,需手动安装:

# pip
pip install dimine-python-sdk[vis]

# uv
uv add dimine-python-sdk --extra vis

# 或直接安装 pyvista
pip install pyvista

快速开始

基础渲染

import numpy as np
from dimine_python_sdk.models.types import TINGeometry
from dimine_python_sdk.lib.visualization import render_tin, CameraAngle, TinRenderConfig

# 创建一个简单的 TIN 网格
tin = TINGeometry(
    faces=np.array([[0, 1, 2], [0, 2, 3]], dtype=np.int32),
    points=np.array(
        [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.5]],
        dtype=np.float32,
    ),
)

# 配置渲染参数
config = TinRenderConfig(
    angles=[
        CameraAngle(name="top", preset="top"),
        CameraAngle(name="isometric", preset="isometric"),
    ],
    mode="combined",
)

# 输出到文件
result = render_tin(tin, config, output_path="tin_output.png")
print(result["output_files"])
# ['tin_output.png']

交互式显示

不指定 output_path 时,返回 Plotter 对象用于交互浏览:

result = render_tin(tin, config)
for plotter in result["plotters"]:
    plotter.show()

核心 API

render_tin()

def render_tin(
    geometries: Union[TINGeometry, List[TINGeometry]],
    config: TinRenderConfig,
    output_path: Optional[str] = None,
    output_prefix: str = "tin_render",
    image_format: str = "png",
) -> Dict[str, Any]:

参数:

参数 类型 默认值 说明
geometries TINGeometry \| List[TINGeometry] 待渲染的三角网几何体
config TinRenderConfig 渲染配置(角度、模式、样式等)
output_path str \| None None 输出路径。separate 模式为目录,combined 模式为文件。None 时返回 Plotter 对象
output_prefix str "tin_render" 输出文件前缀(仅 separate 模式)
image_format str "png" 图像格式(png、jpg、svg 等)

返回值 Dict[str, Any]

类型 说明
mode str 渲染模式 "separate""combined"
angles List[str] 使用的角度名称列表
output_files List[str] \| None 输出文件路径列表(output_pathNone 时为 None
plotters List[Plotter] \| None Plotter 对象列表(仅 output_path=None 时非空)
config TinRenderConfig 本次使用的配置对象

配置模型

CameraAngle — 相机角度

每个角度通过预设名称自定义坐标定义(二者择一):

from dimine_python_sdk.lib.visualization import CameraAngle

# 预设模式
CameraAngle(name="top", preset="top")

# 自定义模式: (camera_position, focal_point, view_up)
CameraAngle(
    name="custom_view",
    custom=((100.0, 50.0, 80.0), (0.0, 0.0, 0.0), (0.0, 0.0, 1.0)),
)

预设角度(采矿行业惯例,Z 轴朝上):

预设值 方向 用途
top 从 +Z 向下看 俯视图 / 平面图
bottom 从 -Z 向上看 仰视图
north 从 +Y 向 -Y 看 北视图
south 从 -Y 向 +Y 看 南视图
east 从 +X 向 -X 看 东视图
west 从 -X 向 +X 看 西视图
isometric 45° 3D 等轴测 等轴测视图

RenderOptions — 渲染选项

from dimine_python_sdk.lib.visualization import RenderOptions

RenderOptions(
    width=1024,              # 图像宽度(像素)
    height=768,              # 图像高度(像素)
    dpi=96,                  # 分辨率
    background_color="white", # 背景颜色
    show_edges=True,         # 显示网格边线
    edge_color="black",      # 边线颜色
    edge_width=1.0,          # 边线宽度
    mesh_opacity=1.0,        # 网格透明度 (0.0~1.0)
    show_axes=False,         # 显示坐标轴
    show_grid=False,         # 显示网格平面
    lighting=True,           # 启用光照
    smooth_shading=True,     # 启用平滑着色
)

TinSubplotLayout — 子图布局

用于 combined 模式下的子图排列:

from dimine_python_sdk.lib.visualization import TinSubplotLayout

TinSubplotLayout(
    rows=1,              # 子图行数
    cols=4,              # 子图列数
    title="多角度对比",   # 组合视图总标题
    spacing=0.1,         # 子图间距比例
    border=False,        # 是否显示子图边框
)

TinRenderConfig — 总配置

from dimine_python_sdk.lib.visualization import TinRenderConfig, CameraAngle

config = TinRenderConfig(
    angles=[
        CameraAngle(name="俯视图", preset="top"),
        CameraAngle(name="北视图", preset="north"),
        CameraAngle(name="东视图", preset="east"),
        CameraAngle(name="等轴测", preset="isometric"),
    ],
    mode="combined",          # "separate" | "combined"
    render_options=RenderOptions(width=1920, height=1080),
    layout=TinSubplotLayout(rows=1, cols=4, title="TIN 多角度视图"),
    colors=["#4C72B0"],       # 网格颜色(与 geometries 一一对应)
    labels=["地形曲面"],       # 图例标签
    show_legend=True,         # 显示图例
)

两种渲染模式

Separate 模式(mode="separate"

每个角度独立渲染为一个 Plotter 或图片文件:

config = TinRenderConfig(
    angles=[
        CameraAngle(name="top", preset="top"),
        CameraAngle(name="north", preset="north"),
        CameraAngle(name="east", preset="east"),
    ],
    mode="separate",
)

# 保存到目录,每个角度一个文件
result = render_tin(
    tin, config,
    output_path="./renders/",
    output_prefix="terrain",
)
# 生成: ./renders/terrain_top.png
#       ./renders/terrain_north.png
#       ./renders/terrain_east.png

Combined 模式(mode="combined"

所有角度合成在一张图中:

config = TinRenderConfig(
    angles=[
        CameraAngle(name="top", preset="top"),
        CameraAngle(name="north", preset="north"),
        CameraAngle(name="east", preset="east"),
        CameraAngle(name="isometric", preset="isometric"),
    ],
    mode="combined",
    layout=TinSubplotLayout(rows=2, cols=2, title="四视图对比"),
)

result = render_tin(tin, config, output_path="four_views.png")

不指定 layout 时,自动生成 1 行 N 列布局。


多几何体叠加

传入多个 TINGeometry,它们会叠加渲染在同一视图中:

tin1 = TINGeometry(faces=faces1, points=points1)  # 地形
tin2 = TINGeometry(faces=faces2, points=points2)  # 矿体

config = TinRenderConfig(
    angles=[CameraAngle(name="iso", preset="isometric")],
    mode="separate",
    colors=["#4C72B0", "#DD8452"],   # 地形蓝色,矿体橙色
    labels=["地形", "矿体"],
    show_legend=True,
)

result = render_tin([tin1, tin2], config, output_path="combined.png")

异常处理

from dimine_python_sdk.lib.visualization import (
    VisualizationError,
    MissingPyVistaError,
    TINRenderError,
    InvalidTINDataError,
    LayoutError,
)

try:
    result = render_tin(tin, config, output_path="output.png")
except MissingPyVistaError:
    print("请先安装 PyVista: pip install pyvista")
except InvalidTINDataError as e:
    print(f"TIN 数据无效: {e}")
except LayoutError as e:
    print(f"子图布局错误: {e}")
except TINRenderError as e:
    print(f"渲染失败: {e}")

异常层次:

VisualizationError(RuntimeError)
  ├── MissingPyVistaError      # PyVista 未安装
  ├── TINRenderError           # 渲染过程中出错
  │     └── InvalidTINDataError # 输入数据无效(空数据、形状错误、索引越界)
  └── LayoutError              # 子图布局配置错误

完整示例

import numpy as np
from dimine_python_sdk.models.types import TINGeometry
from dimine_python_sdk.lib.visualization import (
    render_tin,
    CameraAngle,
    TinRenderConfig,
    RenderOptions,
    TinSubplotLayout,
)

# 构建一个丘陵地形 TIN
np.random.seed(42)
n = 50
x = np.random.uniform(0, 100, n)
y = np.random.uniform(0, 100, n)
z = 10 * np.sin(x / 10) * np.cos(y / 10) + np.random.normal(0, 1, n)
points = np.column_stack([x, y, z]).astype(np.float32)

# 使用 Delaunay 三角剖分生成面
from scipy.spatial import Delaunay
tri = Delaunay(points[:, :2])
faces = tri.simplices.astype(np.int32)

tin = TINGeometry(faces=faces, points=points)

# 配置四视图
config = TinRenderConfig(
    angles=[
        CameraAngle(name="俯视图", preset="top"),
        CameraAngle(name="北视图", preset="north"),
        CameraAngle(name="东视图", preset="east"),
        CameraAngle(name="等轴测", preset="isometric"),
    ],
    mode="combined",
    render_options=RenderOptions(
        width=1920,
        height=1080,
        background_color="#F5F5F5",
        show_edges=True,
        edge_width=0.5,
        mesh_opacity=0.9,
        smooth_shading=True,
    ),
    layout=TinSubplotLayout(rows=2, cols=2, title="地形 TIN 四视图"),
    colors=["#6BAED6"],
    labels=["地形曲面"],
    show_legend=False,
)

result = render_tin(tin, config, output_path="terrain_views.png")
print(f"输出文件: {result['output_files']}")