deep-engine-demo/packages/demo/src/panels/TunnelScene/PointCloud/PointCloudStressDisplayPanel.vue
2026-04-19 18:46:28 +08:00

164 lines
3.5 KiB
Vue

<template>
<n-collapse-item name="pointCloudStressDisplay" title="试样内部应力点云显示">
<div class="panel-section">
<div class="button-group">
<n-button :disabled="hasCloud" size="small" type="primary" @click="create">创建</n-button>
<n-button :disabled="!hasCloud" size="small" type="error" @click="remove">移除</n-button>
</div>
<template v-if="hasCloud">
<div class="control-row">
<div class="control-label">粒子大小</div>
</div>
<div class="slider-container">
<n-slider v-model:value="pointSize" :max="0.02" :min="0.001" :step="0.001" @update:value="onPointSizeChange"/>
</div>
<div class="control-row">
<div class="control-label">强度过滤</div>
</div>
<div class="slider-container">
<n-slider v-model:value="intensityRange" :max="1" :min="0" :step="0.01" range @update:value="onFilterChange"/>
</div>
</template>
</div>
</n-collapse-item>
</template>
<script lang="ts" setup>
import {onUnmounted, ref} from "vue";
import {NButton, NCollapseItem, NSlider} from "naive-ui";
import {useBus} from "@/hooks";
import {PointCloud, PointCloudTool} from "@deep/engine";
//------ 点云面板升级 开始------
/**
* 点云可见状态。
*/
const hasCloud = ref(false);
/**
* 点云强度过滤范围。
*/
const intensityRange = ref<[number, number]>([0, 1]);
/**
* 点云粒子大小。
*/
const pointSize = ref<number>(0.01);
/**
* 场景总线实例。
*/
const bus = useBus();
/**
* 当前应力点云实例。
*/
let cloud: PointCloud | null = null;
/**
* 创建应力点云。
* @returns {void}
*/
const create = (): void => {
const viewer = bus.getViewer();
const pointCloudData = PointCloudTool.generateNoisePointCloudData({
min: [-2.5, -2.5, -2.5],
max: [2.5, 2.5, 2.5],
size: 170,
threshold: 0,
});
cloud = new PointCloud(viewer, {
name: "应力点云场",
pointCloudData,
pointSize: pointSize.value,
colorStops: [
{color: "#0000FF", step: 0.0},
{color: "#00FF00", step: 0.33},
{color: "#FFFF00", step: 0.66},
{color: "#FF0000", step: 1.0},
],
});
// 创建后立即同步一次过滤范围与粒子大小。
cloud.filterByIntensity(intensityRange.value[0], intensityRange.value[1]);
cloud.setPointSize(pointSize.value);
bus.triggerSceneTreeUpdate();
hasCloud.value = true;
};
/**
* 移除应力点云。
* @returns {void}
*/
const remove = (): void => {
if (cloud) {
cloud.dispose();
cloud = null;
}
hasCloud.value = false;
bus.triggerSceneTreeUpdate();
};
/**
* 响应强度过滤范围变更。
* @returns {void}
*/
const onFilterChange = (): void => {
cloud?.filterByIntensity(intensityRange.value[0], intensityRange.value[1]);
};
/**
* 响应粒子大小变更。
* @returns {void}
*/
const onPointSizeChange = (): void => {
cloud?.setPointSize(pointSize.value);
};
/**
* 组件销毁时清理点云。
* @returns {void}
*/
onUnmounted((): void => {
remove();
});
//------ 点云面板升级 结束------
</script>
<style scoped>
.panel-section {
padding: 8px 0;
}
.button-group {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
.button-group .n-button {
flex: 1;
}
.control-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.control-label {
font-size: 12px;
font-weight: 500;
color: #555;
}
.slider-container {
margin: 0 0 16px 0;
padding: 0 4px;
}
</style>