trame实现双视图(返场版)

话不多说直接上代码,库直接自己装,主播懒死了,记得替换成自己的shape文件

实现shp文件并排比对,也可以是更多的视图自己调整,拖动一个视图,另一个视图同步移动有待实现

"""
Shapefile多视图可视化
使用GeoPandas读取数据,VTK进行三角化处理,Trame实现多视图交互
两个视图分别展示不同的shp文件
"""

from trame.app import get_server
from trame.widgets import vuetify, vtk as vtk_widgets
from trame.ui.vuetify import SinglePageLayout

import geopandas as gpd  # 读取shp文件
import numpy as np
from vtkmodules.vtkCommonCore import vtkPoints
from vtkmodules.vtkCommonDataModel import vtkPolyData, vtkCellArray
from vtkmodules.vtkFiltersCore import vtkTriangleFilter  # 三角化后用这个读取器读取
from vtkmodules.vtkRenderingCore import (
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkPolyDataMapper,
    vtkActor,
)

# VTK初始化
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch  # noqa
import vtkmodules.vtkRenderingOpenGL2  # noqa

# -----------------------------------------------------------------------------
# Trame初始化
# -----------------------------------------------------------------------------

server = get_server(client_type="vue2")
state, ctrl = server.state, server.controller

state.trame__title = "双vtp视图对比"
state.layout_mode = "horizontal"  # 默认水平布局

# -----------------------------------------------------------------------------
# 数据处理函数
# -----------------------------------------------------------------------------

def shp_to_vtk_polygon(gdf):
    """将GeoDataFrame转换为VTK多边形数据"""
    points = vtkPoints()
    polys = vtkCellArray()

    for geom in gdf.geometry:
        if geom.geom_type == 'Polygon':
            coords = np.array(geom.exterior.coords)
        elif geom.geom_type == 'MultiPolygon':
            coords = np.concatenate([np.array(p.exterior.coords) for p in geom.geoms])
        else:
            continue

        point_ids = []
        for coord in coords:
            point_ids.append(points.InsertNextPoint(coord[0], coord[1], 0))

        polys.InsertNextCell(len(point_ids), point_ids)

    poly_data = vtkPolyData()
    poly_data.SetPoints(points)
    poly_data.SetPolys(polys)

    return poly_data

def load_and_process_shapefile(file_path, z_scale=1.0):
    """使用GeoPandas加载并处理Shapefile"""
    gdf = gpd.read_file(file_path)
    poly_data = shp_to_vtk_polygon(gdf)

    # 如果有Z坐标,可以在这里进行缩放
    points = poly_data.GetPoints()
    for i in range(points.GetNumberOfPoints()):
        x, y, z = points.GetPoint(i)
        points.SetPoint(i, x, y, z * z_scale)

    triangle_filter = vtkTriangleFilter()
    triangle_filter.SetInputData(poly_data)
    triangle_filter.PassLinesOn()
    triangle_filter.PassVertsOn()
    triangle_filter.Update()

    return triangle_filter.GetOutput()

# -----------------------------------------------------------------------------
# 主程序
# -----------------------------------------------------------------------------

# 读取和处理两个不同的Shapefile
SHAPEFILE_PATHS = [
    r"D:\Data\1\1.shp",  # 替换为第一个文件的实际路径
    r"D:\Data\1\1.shp",  # 替换为第二个文件的实际路径
]

# 为每个文件创建不同的视图配置
VIEW_CONFIGS = [
    {
        "name": "Shapefile 1",
        "background": (0.9, 0.9, 0.9),
        "color": (0.2, 0.4, 0.8),
        "file_path": SHAPEFILE_PATHS[0],
        "z_scale": 1.0
    },
    {
        "name": "Shapefile 2",
        "background": (0.8, 0.9, 1.0),
        "color": (0.4, 0.2, 0.6),
        "file_path": SHAPEFILE_PATHS[1],
        "z_scale": 1.0
    },
]

render_windows = []
html_views = []

for config in VIEW_CONFIGS:
    # 处理数据
    processed_data = load_and_process_shapefile(config["file_path"], config["z_scale"])

    # 创建Mapper
    mapper = vtkPolyDataMapper()
    mapper.SetInputData(processed_data)

    # 创建Actor
    actor = vtkActor()
    actor.SetMapper(mapper)
    actor.GetProperty().SetColor(config["color"])
    actor.GetProperty().SetLineWidth(1.5)

    # 创建渲染器和窗口
    renderer = vtkRenderer()
    renderer.SetBackground(config["background"])
    render_window = vtkRenderWindow()
    render_window.AddRenderer(renderer)
    render_window.SetWindowName(config["name"])

    # 设置交互方式
    render_window_interactor = vtkRenderWindowInteractor()
    render_window_interactor.SetRenderWindow(render_window)
    render_window_interactor.GetInteractorStyle().SetCurrentStyleToTrackballCamera()

    # 添加Actor并初始化视图
    renderer.AddActor(actor)
    renderer.ResetCamera()

    render_windows.append(render_window)

# -----------------------------------------------------------------------------
# Trame用户界面
# -----------------------------------------------------------------------------

with SinglePageLayout(server) as layout:
    layout.icon.click = ctrl.reset_camera
    layout.title.set_text("并排shp视图对比")

    with layout.toolbar:
        vuetify.VSpacer()
        vuetify.VDivider(vertical=True, classes="mx-2")
        with vuetify.VBtn(icon=True, click=ctrl.reset_all_views):
            vuetify.VIcon("mdi-camera-reset")
        vuetify.VDivider(vertical=True, classes="mx-2")
        with vuetify.VBtn(icon=True, click=ctrl.update_all_views):
            vuetify.VIcon("mdi-refresh")
        vuetify.VDivider(vertical=True, classes="mx-2")
        vuetify.VSelect(
            label="视图布局",
            items=[
                {"text": "水平布局", "value": "horizontal"},
                {"text": "垂直布局", "value": "vertical"},
            ],
            v_model=("layout_mode",),
            dense=True,
            hide_details=True,
            style="max-width: 120px;",
        )

    with layout.content:
        # 使用条件渲染实现布局切换
        with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"):
            # 水平布局
            with vuetify.VRow(v_if="layout_mode === 'horizontal'", classes="pa-0 ma-0 fill-height"):
                with vuetify.VCol(classes="pa-1 ma-0 fill-height"):
                    view1 = vtk_widgets.VtkRemoteView(
                        render_windows[0],
                        ref="view1",
                        interactive_ratio=1,
                        style="height: 100%;",
                    )
                    html_views.append(view1)
                with vuetify.VCol(classes="pa-1 ma-0 fill-height"):
                    view2 = vtk_widgets.VtkRemoteView(
                        render_windows[1],
                        ref="view2",
                        interactive_ratio=1,
                        style="height: 100%;",
                    )
                    html_views.append(view2)

            # 垂直布局
            with vuetify.VCol(v_if="layout_mode === 'vertical'", classes="pa-0 ma-0 fill-height"):
                with vuetify.VRow(classes="pa-1 ma-0", style="height: 50%;"):
                    view1 = vtk_widgets.VtkRemoteView(
                        render_windows[0],
                        ref="view1",
                        interactive_ratio=1,
                        style="height: 100%;",
                    )
                    html_views.append(view1)
                with vuetify.VRow(classes="pa-1 ma-0", style="height: 50%;"):
                    view2 = vtk_widgets.VtkRemoteView(
                        render_windows[1],
                        ref="view2",
                        interactive_ratio=1,
                        style="height: 100%;",
                    )
                    html_views.append(view2)

    # 定义控制函数
    def reset_all_views():
        for view in html_views:
            view.reset_camera()

    def update_all_views():
        for view in html_views:
            view.update()

    ctrl.reset_all_views = reset_all_views
    ctrl.update_all_views = update_all_views

# -----------------------------------------------------------------------------
# 启动应用
# -----------------------------------------------------------------------------

if __name__ == "__main__":
    server.start(port=1234)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值