123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- <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>
|