|
@@ -1,193 +0,0 @@
|
|
|
-<template>
|
|
|
- <div ref="threeContainer" class="three-container"></div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script setup>
|
|
|
-import { ref, onMounted, onUnmounted, watch } from "vue";
|
|
|
-import * as THREE from "three";
|
|
|
-import { VTKParserFactory } from "../utils/parsers/VTKParserFactory";
|
|
|
-import { UnstructuredGridRenderer } from "../utils/renderers/UnstructuredGridRenderer";
|
|
|
-import { PolyDataRenderer } from "../utils/renderers/PolyDataRenderer";
|
|
|
-import {
|
|
|
- initScene,
|
|
|
- initCamera,
|
|
|
- initRenderer,
|
|
|
- animateScene,
|
|
|
- cleanupScene,
|
|
|
- initControls,
|
|
|
- initAxesHelper
|
|
|
-} from "../utils/threeUtils";
|
|
|
-
|
|
|
-const props = defineProps({
|
|
|
- vtkData: {
|
|
|
- type: Object,
|
|
|
- required: true,
|
|
|
- },
|
|
|
-});
|
|
|
-
|
|
|
-const threeContainer = ref(null);
|
|
|
-
|
|
|
-let scene, camera, renderer, controls, axesHelper;
|
|
|
-
|
|
|
-// 创建坐标系指示器
|
|
|
-const createAxesHelper = () => {
|
|
|
- const axesHelper = new THREE.AxesHelper(20); // 50 是坐标轴的长度
|
|
|
- axesHelper.position.set(-100, -100, 0); // 将坐标系指示器放置在左下角
|
|
|
- console.log("Axes helper added to scene:", axesHelper); // 调试日志
|
|
|
- // 添加标签
|
|
|
- const labels = ['X', 'Y', 'Z'];
|
|
|
- const colors = [0xff0000, 0x00ff00, 0x0000ff]; // 红、绿、蓝
|
|
|
- labels.forEach((label, index) => {
|
|
|
- const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ color: colors[index] }));
|
|
|
- sprite.position.set(60 * (index === 0 ? 1 : 0), 60 * (index === 1 ? 1 : 0), 60 * (index === 2 ? 1 : 0));
|
|
|
- axesHelper.add(sprite);
|
|
|
- });
|
|
|
- return axesHelper;
|
|
|
-};
|
|
|
-
|
|
|
-// 初始化场景
|
|
|
-const init = () => {
|
|
|
- scene = initScene();
|
|
|
- camera = initCamera();
|
|
|
- renderer = initRenderer(threeContainer.value);
|
|
|
- controls = initControls(camera, renderer);
|
|
|
- // 初始化 AxesHelper
|
|
|
- const { axesHelper, updateAxesHelperPosition } = initAxesHelper(scene, camera, renderer.domElement);
|
|
|
- return { updateAxesHelperPosition };
|
|
|
-};
|
|
|
-
|
|
|
-const adjustCameraToFit = (scene, camera) => {
|
|
|
- const box = new THREE.Box3().setFromObject(scene);
|
|
|
- const size = new THREE.Vector3();
|
|
|
- box.getSize(size);
|
|
|
-
|
|
|
- const maxDim = Math.max(size.x, size.y, size.z);
|
|
|
- const fov = camera.fov * (Math.PI / 180);
|
|
|
- let cameraZ = Math.abs(maxDim / Math.sin(fov / 2));
|
|
|
-
|
|
|
- const center = new THREE.Vector3();
|
|
|
- box.getCenter(center);
|
|
|
- camera.position.set(center.x, center.y, cameraZ);
|
|
|
- camera.lookAt(center);
|
|
|
-};
|
|
|
-
|
|
|
-// 渲染 VTK 数据
|
|
|
-const renderVTK = (vtkData) => {
|
|
|
- if (!vtkData) return;
|
|
|
- // 根据文件格式选择解析器
|
|
|
- const parser = VTKParserFactory.createParser(vtkData.datasetType);
|
|
|
- const parsedData = parser.parse(vtkData);
|
|
|
-
|
|
|
- // 根据文件格式选择渲染器
|
|
|
- let dataRenderer;
|
|
|
- switch (vtkData.datasetType) {
|
|
|
- case "UNSTRUCTURED_GRID":
|
|
|
- dataRenderer = new UnstructuredGridRenderer();
|
|
|
- break;
|
|
|
- case "POLYDATA":
|
|
|
- dataRenderer = new PolyDataRenderer();
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new Error(`Unsupported dataset type: ${vtkData.datasetType}`);
|
|
|
- }
|
|
|
-
|
|
|
- // 渲染数据
|
|
|
- dataRenderer.render(parsedData, scene);
|
|
|
-
|
|
|
- // 根据数据类型调整相机位置
|
|
|
- if (vtkData.datasetType === "UNSTRUCTURED_GRID") {
|
|
|
- adjustCameraForUnstructuredGrid(scene, camera);
|
|
|
- } else if (vtkData.datasetType === "POLYDATA") {
|
|
|
- adjustCameraForPolydata(scene, camera);
|
|
|
- }
|
|
|
-
|
|
|
- // adjustCameraToFit(scene, camera);
|
|
|
-};
|
|
|
-
|
|
|
-// 监听 vtkData 变化
|
|
|
-watch(
|
|
|
- () => props.vtkData,
|
|
|
- (newData) => {
|
|
|
- if (newData) {
|
|
|
- // 清空场景
|
|
|
- while (scene.children.length > 0) {
|
|
|
- scene.remove(scene.children[0]);
|
|
|
- }
|
|
|
-
|
|
|
- // 重新渲染 VTK 数据
|
|
|
- renderVTK(newData);
|
|
|
- }
|
|
|
- },
|
|
|
- { immediate: true }
|
|
|
-);
|
|
|
-
|
|
|
-// VTK 数据
|
|
|
-onMounted(() => {
|
|
|
- const { updateAxesHelperPosition } = init();
|
|
|
- animateScene(scene, camera, renderer, controls, () => {
|
|
|
- updateAxesHelperPosition(); // 更新 AxesHelper 的位置和方向
|
|
|
- });
|
|
|
- // 监听窗口大小变化
|
|
|
- window.addEventListener("resize", onWindowResize);
|
|
|
-});
|
|
|
-onUnmounted(() => {
|
|
|
- // 清理场景
|
|
|
- cleanupScene(renderer);
|
|
|
- // 移除窗口大小变化监听器
|
|
|
- window.removeEventListener("resize", onWindowResize);
|
|
|
-});
|
|
|
-
|
|
|
-const onWindowResize = () => {
|
|
|
- const width = threeContainer.value.clientWidth;
|
|
|
- const height = threeContainer.value.clientHeight;
|
|
|
- camera.aspect = width / height;
|
|
|
- camera.updateProjectionMatrix();
|
|
|
- renderer.setSize(width, height);
|
|
|
-};
|
|
|
-
|
|
|
-const adjustCameraForUnstructuredGrid = (scene, camera) => {
|
|
|
- const box = new THREE.Box3().setFromObject(scene);
|
|
|
- const size = new THREE.Vector3();
|
|
|
- box.getSize(size);
|
|
|
-
|
|
|
- const maxDim = Math.max(size.x, size.y, size.z);
|
|
|
- const fov = camera.fov * (Math.PI / 180);
|
|
|
- let cameraZ = Math.abs(maxDim / Math.sin(fov / 2));
|
|
|
-
|
|
|
- const center = new THREE.Vector3();
|
|
|
- box.getCenter(center);
|
|
|
- camera.position.set(center.x, center.y, cameraZ);
|
|
|
- camera.lookAt(center);
|
|
|
-};
|
|
|
-
|
|
|
-const adjustCameraForPolydata = (scene, camera) => {
|
|
|
- const box = new THREE.Box3().setFromObject(scene);
|
|
|
- // 手动设置边界框
|
|
|
- box.set(
|
|
|
- new THREE.Vector3(-100, -100, -100),
|
|
|
- new THREE.Vector3(100, 100, 100)
|
|
|
- );
|
|
|
- const size = new THREE.Vector3();
|
|
|
- box.getSize(size);
|
|
|
-
|
|
|
- console.log("Polydata bounding box:", box);
|
|
|
- console.log("Polydata size:", size);
|
|
|
-
|
|
|
- const maxDim = Math.max(size.x, size.y, size.z);
|
|
|
- const fov = camera.fov * (Math.PI / 180);
|
|
|
- let cameraZ = Math.abs(maxDim / Math.sin(fov / 2));
|
|
|
-
|
|
|
- const center = new THREE.Vector3();
|
|
|
- box.getCenter(center);
|
|
|
- camera.position.set(center.x, center.y, cameraZ * 0.8); // 调整相机距离
|
|
|
- camera.lookAt(center);
|
|
|
-};
|
|
|
-</script>
|
|
|
-
|
|
|
-<style>
|
|
|
-.three-container {
|
|
|
- width: 100%;
|
|
|
- height: calc(89vh - 8px); /* 给容器设置固定高度 */
|
|
|
- border: 1px solid #ccc; /* 可选:添加边框以便查看容器范围 */
|
|
|
-}
|
|
|
-</style>
|