screenFront/src/views/FactoryViewEdit/threeMap.vue

956 lines
38 KiB
Vue
Raw Normal View History

2023-05-12 08:41:33 +00:00
<template>
<div class="container" ref="container"></div>
</template>
<script setup lang='ts'>
import { ref, onMounted, defineExpose } from 'vue';
import * as THREE from 'three';
import * as TWEEN from '@tweenjs/tween.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import * as SceneUtils from 'three/examples/jsm/utils/SceneUtils.js';
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import { DragControls } from "@/utils/DragControls";
// import { DragControls } from 'three/examples/jsm/controls/DragControls.js';
import { useFactoryStore } from "@/store/module/Factory"
import { useRouter } from 'vue-router';
import { updateCoordinateByPoint } from "@/http/AerialView/index"
import { ElNotification } from 'element-plus'
import { useI18n } from 'vue-i18n'
let { t } = useI18n();
const store = useFactoryStore();
const router = useRouter();
const container = ref();
let iw = 1920;
let ih = 1080;
const boxObjects: any = ref([]);
let scene: any = null; //场景
let camera: any = null; //相机
let canvas: any = null; //用作渲染的canvas
let renderer: any = null; //渲染器
let controls: any = null; //控制器
let labelRenderer: any = null; //2D渲染器
let labelControls: any = null; //2D控制器
const group = new THREE.Group();//用于将建筑物的各个零件组合起来
let timer: any = null;
let dragControls: any = null;
let cssRender: any = null;
let saveTipDom: any = null;
const requires = {
'粉尘': require('@/assets/img/Factory/fenchen.jpg'),
'烟雾': require('@/assets/img/Factory/yanwu.jpg'),
'TVOC/甲醛': require('@/assets/img/Factory/tvoc.jpg'),
'噪音': require('@/assets/img/Factory/shengyin.jpg'),
'火花': require('@/assets/img/Factory/huohua.jpg'),
'电力': require('@/assets/img/Factory/dianlu.jpg'),
'气压': require('@/assets/img/Factory/qiya.jpg'),
'水压': require('@/assets/img/Factory/shuiya.jpg'),
'温湿度': require('@/assets/img/Factory/wendu.jpg'),
'网关': require('@/assets/img/Factory/wangguan.jpg'),
'燃气': require('@/assets/img/Factory/ranqi.jpg'),
'设备': require('@/assets/img/Factory/shebei.jpg'),
'ny': require("@/assets/img/Factory/ny.jpg"),
'wood': require("@/assets/img/Factory/wood.jpg"),
// 'wall1': require("@/assets/img/Factory/floor1.jpeg"),
'wall1': require("@/assets/img/Factory/wall1.jpg"),
'tile': require("@/assets/img/Factory/tile.jpg"),
'door': require("@/assets/img/Factory/door.jpg"),
'sky': require("@/assets/img/Factory/sky.jpg"),
}
const workerShopRoute = {
'大件车间地板': '/MechanicalViewDajian',
'焊接车间地板': '/MechanicalViewHanjie',
'机加车间地板': '/MechanicalViewJijia',
'精加车间地板': '/MechanicalViewJingjia',
'精饰车间地板': '/MechanicalViewJingshi',
}
let getSensorDataTimer = null;
let getDevDataTimer = null;
const normal_size = { baseWidth: 10, baseHeght: 10, baseLength: 10 };//正常大小
const small_size = { baseWidth: 8, baseHeght: 8, baseLength: 8 };//缩小的大小
const coordinate = {}
/**
* @函数功能:
* @param {*} val 重置画布宽高值
* @出口参数:
* @函数备注:
*/
function reset(val: any) {
//宽高为0时跳出该方法
if (!val.oWidth && !val.oHeight) return;
// mapSize.width=val.width
// mapSize.height=val.height
// 更新修改相机比例
container.value.style.width = val.oWidth;
container.value.style.height = val.oHeight;
camera.aspect = val.oWidth / val.oHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
//处理返回操作时dom层数变多问题
if (document.getElementsByClassName("cssrender").length > 1) {
document.getElementsByClassName("cssrender")[1].remove();
}
// 更新画布大小
renderer.setSize(
val.oWidth, // 宽度
val.oHeight // 高度
);
labelRenderer.setSize(
val.oWidth, // 宽度
val.oHeight // 高度
);
// 更新画布像素比
renderer.setPixelRatio(container.value.devicePixelRatio);
//重置盒子尺寸
}
defineExpose({
reset,
});
const init = () => {
canvas = container.value;
//创建场景
scene = new THREE.Scene();
//创建一个透视相机
camera = new THREE.PerspectiveCamera(45, iw / ih, 1, 3000);
// 创建渲染器
renderer = new THREE.WebGLRenderer();
// 设置渲染器的初始颜色
renderer.setClearColor(new THREE.Color(0xeeeeee));
// 设置输出canvas画面的大小
renderer.setSize(iw, ih)
// 设置渲染物体阴影
renderer.shadowMap.enabled = true;
//设置2D渲染器
labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(iw, ih);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = 0;
labelRenderer.domElement.style.outline = "none";
canvas.appendChild(labelRenderer.domElement);
//创建环境光
const hjLight = new THREE.AmbientLight(0xffffff);
//添加环境光至场景
scene.add(hjLight);
// 定位相机,并且指向场景中心
camera.position.x = 0;
camera.position.y = 820; //650
camera.position.z = 0; //600
// camera.position.x = 0;
// camera.position.y = 650; //650
// camera.position.z = 600; //600
camera.lookAt(scene.position)
renderer.render(scene, camera)
// 将渲染器输出添加html元素中
canvas.appendChild(renderer.domElement);
//添加房子的group到场景中
scene.add(group);
// 创建controls对象;
controls = new OrbitControls(camera, labelRenderer.domElement)
// labelControls = new OrbitControls(camera, labelRenderer.domElement)
// 监听控制器的鼠标事件,执行渲染内容
controls.addEventListener('change', () => {
clearInterval(timer)
renderer.render(scene, camera)
labelRenderer.render(scene, camera)
})
/**-------------------------------结束后注释------------------------------------------------- */
controls.mouseButtons = {
// LEFT: ,
MIDDLE: THREE.MOUSE.DOLLY,
RIGHT: THREE.MOUSE.PAN
};
//创建地面
createGround()
//创建仓库1
createHouse(`${t('messages.store')}1`, { baseWidth: 262, baseHeght: 30, baseLength: 53 }, { x: -322, y: 0, z: -304 })
//创建仓库2
createHouse(`${t('messages.store')}2`, { baseWidth: 262, baseHeght: 30, baseLength: 53 }, { x: 136, y: 0, z: -304 })
//创建综合楼 baseWidth: 114, baseHeght: 50, baseLength: 353 x: -397, y: 0, z: 11
createHouse(t('messages.SynthesizeRoom'), { baseWidth: 114, baseHeght: 50, baseLength: 353 }, { x: -397, y: 0, z: -11 })
/**
* 创建综合楼里的墙
*/
createUseWall('综合楼的墙1', { baseWidth: 1, baseHeght: 50, baseLength: 159 }, { x: -413, y: 0, z: -26.5 })
createUseWall('综合楼的墙2', { baseWidth: 41, baseHeght: 50, baseLength: 1 }, { x: -413, y: 0, z: -26.5 })
createUseWall('综合楼的墙3', { baseWidth: 1, baseHeght: 50, baseLength: 159 }, { x: -382, y: 0, z: -26.5 })
createUseWall('综合楼的墙4', { baseWidth: 41, baseHeght: 50, baseLength: 1 }, { x: -341, y: 0, z: -26.5 })
createUseWall('综合楼的墙3', { baseWidth: 45, baseHeght: 50, baseLength: 1 }, { x: -410, y: 0, z: 30 })
createUseWall('综合楼的墙4', { baseWidth: 45, baseHeght: 50, baseLength: 1 }, { x: -341, y: 0, z: 30 })
createUseWall('综合楼的墙5', { baseWidth: 45, baseHeght: 50, baseLength: 1 }, { x: -410, y: 0, z: 87.5 })
createUseWall('综合楼的墙6', { baseWidth: 45, baseHeght: 50, baseLength: 1 }, { x: -341, y: 0, z: 79.5 })
createUseWall('综合楼的墙7', { baseWidth: 1, baseHeght: 50, baseLength: 57 }, { x: -410, y: 0, z: 87 })
createUseWall('综合楼的墙8', { baseWidth: 1, baseHeght: 50, baseLength: 69 }, { x: -385, y: 0, z: 99 })
createUseWall('综合楼的墙9', { baseWidth: 1, baseHeght: 50, baseLength: 63 }, { x: -435, y: 0, z: 150 })
createUseWall('综合楼的墙10', { baseWidth: 1, baseHeght: 50, baseLength: 63 }, { x: -435, y: 0, z: 150 })
createUseWall('综合楼的墙11', { baseWidth: 1, baseHeght: 50, baseLength: 40 }, { x: -421, y: 0, z: 138.5 })
createUseWall('综合楼的墙12', { baseWidth: 36, baseHeght: 50, baseLength: 1 }, { x: -385, y: 0, z: 99.5 })
createUseWall('综合楼的墙13', { baseWidth: 36, baseHeght: 50, baseLength: 1 }, { x: -385, y: 0, z: 139.5 })
createUseWall('综合楼的墙14', { baseWidth: 44, baseHeght: 50, baseLength: 1 }, { x: -410, y: 0, z: 150.5 })
createUseWall('综合楼的墙15', { baseWidth: 1, baseHeght: 50, baseLength: 16 }, { x: -409, y: 0, z: 165.5 })
createUseWall('综合楼的墙16', { baseWidth: 1, baseHeght: 50, baseLength: 27 }, { x: -384, y: 0, z: 165.5 })
//汽车部地板
const mesh_qcb = createFloor(t('messages.ExternalWork'), 42, 160, { x: -362, y: 0, z: -105 })
createLableObj(mesh_qcb, t('messages.ExternalWork'), { x: 0, y: 0, z: 0 })
//创建产学研 baseWidth: 21, baseHeght: 25, baseLength: 32 x: -495, y: 0, z: -102.5
createHouse(t('messages.WaterRoom'), { baseWidth: 21, baseHeght: 25, baseLength: 32 }, { x: -495, y: 0, z: -102.5 })
createHouse(t('messages.SecurityRoom'), { baseWidth: 21, baseHeght: 25, baseLength: 32 }, { x: -495, y: 0, z: -70.5 })
//创建盈瑞安办公区 baseWidth: 90, baseHeght: 30, baseLength: 159 x: -399, y: 0, z: 245
createHouse(t('messages.productStudyDevelopment'), { baseWidth: 90, baseHeght: 30, baseLength: 159 }, { x: -399, y: 0, z: 245 })
/**盈瑞安办公区里的墙 */
createUseWall('盈瑞安办公区的墙1', { baseWidth: 90, baseHeght: 30, baseLength: 1 }, { x: -354.5, y: 0, z: 195.5 })
createUseWall('盈瑞安办公区的墙2', { baseWidth: 90, baseHeght: 30, baseLength: 1 }, { x: -354.5, y: 0, z: 246.5 })
createUseWall('盈瑞安办公区的墙3', { baseWidth: 90, baseHeght: 30, baseLength: 1 }, { x: -354.5, y: 0, z: 271.5 })
//创建车间1 baseWidth: 573, baseHeght: 30, baseLength: 238 x: -17.5, y: 0, z: -137.5
createHouse('车间1', { baseWidth: 573, baseHeght: 30, baseLength: 238 }, { x: -17.5, y: 0, z: -137.5 }, false)
/**车间一内的墙 */
createUseWall('车间1的墙1', { baseWidth: 1, baseHeght: 30, baseLength: 238 }, { x: -228, y: 0, z: -18.5 })
createUseWall('车间1的墙2', { baseWidth: 1, baseHeght: 30, baseLength: 238 }, { x: -37, y: 0, z: -18.5 })
createUseWall('车间1的墙3', { baseWidth: 1, baseHeght: 30, baseLength: 238 }, { x: 37, y: 0, z: -18.5 })
createUseWall('车间1的墙4', { baseWidth: 1, baseHeght: 30, baseLength: 238 }, { x: 73, y: 0, z: -18.5 })
createUseWall('车间1的墙5', { baseWidth: 76, baseHeght: 30, baseLength: 1 }, { x: -228, y: 0, z: -95.5 })
createUseWall('车间1的墙5', { baseWidth: 192, baseHeght: 30, baseLength: 1 }, { x: -37, y: 0, z: -194.5 })
createUseWall('车间1的墙5', { baseWidth: 40, baseHeght: 30, baseLength: 1 }, { x: 2, y: 0, z: -105.5 })
createUseWall('车间1的墙5', { baseWidth: 40, baseHeght: 30, baseLength: 1 }, { x: 2, y: 0, z: -62.5 })
//机械设计及行政办公区
const mesh_hr = createFloor(t('messages.machineDesign'), 45, 120, { x: -431, y: 0, z: 102 })
createLableObj(mesh_hr, t('messages.machineDesign'), { x: 0, y: 60, z: 0 })
//电控车间
const mesh_dkcj = createFloor(t('messages.ControllerRoom'), 76.5, 237, { x: -266, y: 0, z: -138.5 })
createLableObj(mesh_dkcj, t('messages.ControllerRoom'), { x: 0, y: 60, z: 0 })
//服装军团
const mesh_fzjt = createFloor(t('messages.FuZhuangLegion'), 192, 236.5, { x: -133, y: 0, z: -138 })
createLableObj(mesh_fzjt, t('messages.FuZhuangLegion'), { x: 0, y: 60, z: 0 })
//配套车间
const mesh_ptcj = createFloor(t('messages.BigPeiTao'), 110, 236.5, { x: 18.5, y: 0, z: -138 })
createLableObj(mesh_ptcj, t('messages.BigPeiTao'), { x: 0, y: 60, z: 0 })
//家纺军团
const mesh_jfjt = createFloor(t('messages.JiaFangLegion'), 200, 118, { x: 168.5, y: 0, z: -197 })
createLableObj(mesh_jfjt, t('messages.JiaFangLegion'), { x: 0, y: 60, z: 0 })
//医防军团
const mesh_yfjt = createFloor(t('messages.YiFangLegion'), 200, 119, { x: 168.5, y: 0, z: -78 })
createLableObj(mesh_yfjt, `${t('messages.twoLou')}-${t('messages.YiFangLegion')}`, { x: 0, y: 60, z: 0 })
createHouse('配套车间办公室', { baseWidth: 26, baseHeght: 25, baseLength: 54 }, { x: 24, y: 0, z: -80.5 }, false)
//创建车间2-1 baseWidth: 147, baseHeght: 30, baseLength: 263 x: -230.5, y: 0, z: 176
createHouse('车间2-1', { baseWidth: 147, baseHeght: 30, baseLength: 263 }, { x: -230.5, y: 0, z: 176 }, false)
createUseWall('车间2-1的墙1', { baseWidth: 1, baseHeght: 30, baseLength: 227 }, { x: -237, y: 0, z: 269.5 })
createUseWall('车间2-1的墙2', { baseWidth: 32, baseHeght: 30, baseLength: 1 }, { x: -207, y: 0, z: 147.5 })
createUseWall('车间2-1的墙3', { baseWidth: 27, baseHeght: 30, baseLength: 1 }, { x: -158, y: 0, z: 147.5 })
createUseWall('车间2-1的墙4', { baseWidth: 32, baseHeght: 30, baseLength: 1 }, { x: -207, y: 0, z: 183.5 })
createUseWall('车间2-1的墙5', { baseWidth: 27, baseHeght: 30, baseLength: 1 }, { x: -158, y: 0, z: 183.5 })
//汽车军团
const mesh_qcjt = createFloor(t('messages.QiCheLegion'), 67, 263, { x: -270.5, y: 0, z: 176 })
createLableObj(mesh_qcjt, t('messages.QiCheLegion'), { x: 0, y: 60, z: 0 })
//精加车间
const mesh_jjcj = createFloor('精加车间', 82, 263, { x: -198, y: 0, z: 176 })
createLableObj(mesh_jjcj, t('messages.JingJiaRoom'), { x: 0, y: 60, z: 0 })
//创建车间2-2 baseWidth: 95, baseHeght: 30, baseLength: 263 x: -84.5, y: 0, z: 176
createHouse(t('messages.JiJiaRoom'), { baseWidth: 95, baseHeght: 30, baseLength: 263 }, { x: -84.5, y: 0, z: 176 })
//创建车间2-3 baseWidth: 161, baseHeght: 30, baseLength: 263 x: 65.5, y: 0, z: 176
createHouse('车间2-3', { baseWidth: 161, baseHeght: 30, baseLength: 263 }, { x: 65.5, y: 0, z: 176 }, false)
createUseWall('车间2-3的墙1', { baseWidth: 1, baseHeght: 30, baseLength: 263 }, { x: 60, y: 0, z: 307 })
//大件车间
const mesh_djcj = createFloor('大件车间', 75, 263, { x: 22, y: 0, z: 176 })
createLableObj(mesh_djcj, t('messages.DaJianRoom'), { x: 0, y: 60, z: 0 })
//精饰车间
const mesh_jscj = createFloor('精饰车间', 88, 263, { x: 101.5, y: 0, z: 176 })
createLableObj(mesh_jscj, t('messages.JingShiRoom'), { x: 0, y: 60, z: 0 })
//精饰车间内的房子
createHouse(t('messages.ManualSandblastingRoom'), { baseWidth: 26, baseHeght: 30, baseLength: 28 }, { x: 73.62, y: 0, z: 59.15 })
createHouse(`${t('messages.DryingRoom')}B`, { baseWidth: 28, baseHeght: 30, baseLength: 46 }, { x: 130.77, y: 0, z: 67.69 })
createHouse(t('messages.GrindingRoom'), { baseWidth: 24, baseHeght: 30, baseLength: 42 }, { x: 132.77, y: 0, z: 141.03 })
createHouse('冷冻式空气干燥机', { baseWidth: 14, baseHeght: 20, baseLength: 18 }, { x: 66.69, y: 0, z: 123.32 }, false)
createHouse('喷砂罐', { baseWidth: 14, baseHeght: 20, baseLength: 18 }, { x: 66.69, y: 0, z: 158.41 }, false)
createHouse('抛丸机', { baseWidth: 19, baseHeght: 20, baseLength: 74 }, { x: 83.84, y: 0, z: 144.21 }, false)
createHouse(t('messages.PowderSprayingRoom'), { baseWidth: 32, baseHeght: 20, baseLength: 65 }, { x: 75.94, y: 0, z: 235.64 })
createHouse(t('messages.DaJianPaintingRoom'), { baseWidth: 27, baseHeght: 20, baseLength: 44 }, { x: 132.10, y: 0, z: 220.20 })
//创建车间2-4 baseWidth: 85, baseHeght: 30, baseLength: 263 x: 224, y: 0, z: 176
createHouse(t('messages.HanJieRoom'), { baseWidth: 85, baseHeght: 30, baseLength: 263 }, { x: 224, y: 0, z: 176 })
createHouse(t('messages.boilerRoom'), { baseWidth: 25, baseHeght: 20, baseLength: 30 }, { x: 252.30, y: 0, z: 60.87 })
//创建食堂 baseWidth: 71, baseHeght: 30, baseLength: 124 x: 312.5, y: 0, z: 221.5
createHouse(t('messages.canteen'), { baseWidth: 71, baseHeght: 30, baseLength: 124 }, { x: 312.5, y: 0, z: 221.5 })
//创建宿舍楼3 baseWidth: 56, baseHeght: 30, baseLength: 216 x: 393, y: 0, z: -147
createHouse(`${t('messages.EmployeeApartment')}-9`, { baseWidth: 56, baseHeght: 30, baseLength: 216 }, { x: 393, y: 0, z: -147 })
//创建宿舍楼1 baseWidth: 56, baseHeght: 30, baseLength: 132 x: 389, y: 0, z: 106.5
createHouse(`${t('messages.EmployeeApartment')}-10`, { baseWidth: 56, baseHeght: 30, baseLength: 132 }, { x: 393, y: 0, z: 106.5 })
//创建宿舍楼2 baseWidth: 56, baseHeght: 30, baseLength: 132 x: 389, y: 0, z: 106.5
createHouse(`${t('messages.EmployeeApartment')}-11`, { baseWidth: 56, baseHeght: 30, baseLength: 132 }, { x: 393, y: 0, z: 243.5 })
//创建围墙 baseWidth: 966, baseHeght: 5, baseLength: 677 x: 24, y: 0, z: 0
createHouse('围墙', { baseWidth: 966, baseHeght: 15, baseLength: 677 }, { x: -24, y: 0, z: 0 }, false)
//创建东气泵房 baseWidth: 23, baseHeght: 30, baseLength: 16 x: -119.5, y: 0, z: 313.5
createHouse(t('messages.eastAirPumpRoom'), { baseWidth: 23, baseHeght: 25, baseLength: 16 }, { x: -119.5, y: 0, z: 316.5 })
//鼠标在canvas画布上点击事件 问题待解决
//设置3D渲染器
// initCss3DScene()
setTipDom()
sethoveMesh()
//创建综合楼
//创建天空盒
createSkyBox()
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
function onPointerMove(event: any) {
// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
pointer.x = (event.clientX / iw) * 2 - 1;
pointer.y = -(event.clientY / ih) * 2 + 1;
}
//animate()
//鼠标在canvas画布上点击事件
labelRenderer.domElement.addEventListener('mouseup', function (event: any) {
clearInterval(timer)
// .offsetY、.offsetX以canvas画布左上角为坐标原点,单位px
const px = event.offsetX;
const py = event.offsetY;
//屏幕坐标px、py转WebGL标准设备坐标x、y
//width、height表示canvas画布宽高度
const x = (px / iw) * 2 - 1;
const y = -(py / ih) * 2 + 1;
console.log("鼠标点击位置", "x:" + x, "y:" + y);
console.log("鼠标点击位置", "px:" + px, "py:" + py);
//创建一个射线投射器`Raycaster`
const raycaster = new THREE.Raycaster();
//.setFromCamera()计算射线投射器`Raycaster`的射线属性.ray
// 形象点说就是在点击位置创建一条射线,射线穿过的模型代表选中
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
//.intersectObjects([mesh1, mesh2, mesh3])对参数中的网格模型对象进行射线交叉计算
// 未选中对象返回空数组[],选中一个对象数组1个元素选中两个对象数组两个元素
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
var selected = intersects[0]; //取第一个物体
console.log("坐标", "{x:" + selected.point.x.toFixed(2) + ",y:" + (selected.point.y.toFixed(2) - 1) + ",z:" + selected.point.z.toFixed(2) + "}");
let workerShop = intersects[0]?.object?.name
if (workerShopRoute.hasOwnProperty(workerShop)) {
//router.push({ path: workerShopRoute[workerShop]})
}
}
console.log("点击了", intersects[0]?.object?.name);
// intersects.length大于0说明说明选中了模型
// if (intersects.length > 0) {
// // 选中模型的第一个模型,设置为红色
// intersects[0].object.material.color.set(0xff0000);
// }
renderer.render(scene, camera)
})
controls.target = new THREE.Vector3(0, 0, 0)
// const raycaster = new THREE.Raycaster()
let mouse = new THREE.Vector2()
let intersects = null
labelRenderer.domElement.addEventListener('dblclick', function (event: any) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObject(scene, true);
if (intersects.length > 0) {
let boxMaxY = new THREE.Box3().setFromObject(intersects[0].object).max.y
let distance = boxMaxY + 200
let angel = Math.PI / 3.5
let position = {
x: intersects[0].object.position.x + Math.cos(angel) * distance,
y: intersects[0].object.position.y + Math.cos(angel) * distance,
z: intersects[0].object.position.z + Math.sin(angel) * distance
}
let tween = new TWEEN.Tween(camera.position).to(position, 1000)
let tween1 = new TWEEN.Tween(controls.target).to(intersects[0].object.position, 1000)
controls.enabled = false;
tween.onComplete(function () {
controls.enabled = true;
})
// console.log("点击了", intersects[0]?.object?.name);
tween.start()
tween1.start()
}
});
//控制对象的透明度来实现闪烁效果
function reader(torus: any) {
if (torus.startVal > 1) {
torus.direction = 'down'
}
if (torus.startVal < 0) {
torus.direction = 'up'
}
if (torus.direction === 'up') {
torus.startVal += 0.01
torus.material.opacity = torus.startVal
} else {
torus.startVal -= 0.01
torus.material.opacity = torus.startVal
}
// console.log(torus.material.opacity);
}
//定制渲染函数
let T0 = +new Date() //设置时间差
function render() {
let T1 = +new Date()
// let t = T1 - T0 //获取时间间隔
renderer.render(scene, camera)
//旋转立方体,每次绕y轴旋转0.01弧度每一秒渲染0.001弧度
//box.rotateY(0.001 * t)
// if (t >= 2000) {
// return
// }
boxObjects.value.forEach((element: any) => {
let color1 = 0x88e76a
let color2 = 0xff0000
//判断是否是更新的传感器数据
if (store.updateSensorData.hasOwnProperty(element.sensor_id)) {
// console.log(store.updateSensorData,'store.updateSensorData');
// console.log(element,'element');
let color = store.updateSensorData[element.sensor_id].status ? color1 : color2
element.devStatus = store.updateSensorData[element.sensor_id].status
element.material.color = new THREE.Color(color)
}
// reader(element)
});
TWEEN.update()
controls.update()
labelRenderer.render(scene, camera)
store.clearupdateSensorData()
// reader(mesh_qcjt)
window.requestAnimationFrame(render) //避免掉帧,就是一帧接一帧,逐帧,预备加载下一帧
}
render()
}
type positionType = {
x: number,
y: number,
z: number
}
//创建房子
function createHouse(houseName: string, size = { baseWidth: 40, baseHeght: 4, baseLength: 60 }, position: positionType = { x: 80, y: 1, z: 0 }, isFloor = true) {
const { baseWidth, baseHeght, baseLength } = size
const { x, y, z } = position;
const faWallPosition = [-baseWidth / 2 + x, 0, -baseLength / 2 + z]
if (isFloor) {
//创建地板
if (houseName == t('messages.JiJiaRoom')) {
const mesh = createFloor('机加车间', baseWidth, baseLength, position)
createLableObj(mesh, t('messages.JiJiaRoom'), { x: 0, y: 60, z: 0 })
} else if (houseName == t('messages.HanJieRoom')) {
const mesh = createFloor('焊接车间', baseWidth, baseLength, position)
createLableObj(mesh, t('messages.HanJieRoom'), { x: 0, y: 60, z: 0 })
} else {
const mesh = createFloor('houseName', baseWidth, baseLength, position)
createLableObj(mesh, houseName, { x: 0, y: 60, z: 0 })
}
}
//创建左右墙
let leftWall = createWall(1, baseHeght, baseLength)
leftWall.name = houseName + '左侧的墙'
leftWall.rotateY(Math.PI / 2);
leftWall.position.set((-baseWidth / 2 + x + 1), baseHeght / 2 + y, z);
group.add(leftWall)
const rightWall = leftWall.clone();
rightWall.position.set((baseWidth / 2 + x), baseHeght / 2 + y, z);
rightWall.name = houseName + "右侧的墙";
group.add(rightWall);
//创建前后墙
const frontWall = createWall(1, baseHeght, baseWidth)
frontWall.position.set((1 / 2 + x), baseHeght / 2 + y, (baseLength / 2 + z));
frontWall.name = houseName + "前方的墙";
group.add(frontWall);
const rearWall = frontWall.clone();
rearWall.position.set((1 / 2 + x), baseHeght / 2 + y, (-baseLength / 2 + z));
rearWall.name = houseName + "后方的墙";
group.add(rearWall);
// //不带门的墙
// createNoDoorWall(baseWidth,baseHeght,baseLength,position)
// //创建带门的墙
// createDoorWall(baseWidth,baseHeght,baseLength,position)
// let { roof, width } = createRoof(baseWidth,baseHeght,baseLength,position);
// let leftRoof = roof.clone();
// leftRoof.rotateX(THREE.MathUtils.degToRad(30));
// leftRoof.position.set(-baseWidth / 3 + 1+x, baseHeght+2+y, z);
// leftRoof.name = "左屋顶";
// group.add(leftRoof);
// //创建门
// createDoor(baseWidth,baseLength,position)
}
// 新建2D标签
function createLableObj(mesh: any, text: string, vector: positionType) {
let laberDiv = document.createElement('div');//创建div容器
laberDiv.className = 'laber_name';
laberDiv.textContent = text;
let pointLabel = new CSS2DObject(laberDiv);
pointLabel.position.set(vector.x, vector.y, vector.z);
mesh.add(pointLabel);
}
type sizeType = {
baseWidth: number,
baseHeght: number,
baseLength: number
}
//创建能用的墙
function createUseWall(name: string, size: sizeType, position: positionType, issensor: boolean = false): void {
let Wall = createWall(size.baseWidth, size.baseHeght, size.baseLength)
Wall.name = name
Wall.rotateY(Math.PI / 2);
Wall.position.set((-size.baseWidth / 2 + position.x + 1), size.baseHeght / 2 + position.y, -size.baseLength / 2 + position.z);
group.add(Wall)
return Wall
}
/**
* 创建立方体 用作传感器
* @param size 立方体的长宽高
* @param boxposition 立方体的位置
* @param boxcolor 立方体的颜色
* @param shadow 是否渲染到阴影贴图当中
*/
const createBox = (size: sizeType, boxposition: positionType, boxcolor: number, shadow: boolean = true, result: any = {}, icon: string): object => {
const wallTexture = new THREE.TextureLoader().load(requires[icon]);
const wall = new THREE.BoxGeometry(size.baseWidth, size.baseHeght, size.baseLength);
const wallMaterial = new THREE.MeshPhongMaterial({
map: wallTexture,
color: boxcolor,
transparent: true,
});
//墙体的网格
const wallMesh = new THREE.Mesh(wall, wallMaterial);
// 绑定自定义数据 添加标签
wallMesh.name = result.name
wallMesh.devStatus = result.status
wallMesh.direction = 'up'
wallMesh.startVal = 1
//用于更新状态判断
wallMesh.sensor_id = result.id
// 物体移动位置
// wallMesh.position.set((-size.baseWidth / 2 + boxposition.x + 1), size.baseHeght / 2 + boxposition.y, -size.baseLength / 2 + boxposition.z);
wallMesh.position.set(boxposition.x, size.baseHeght / 2 + boxposition.y, boxposition.z);
// 对象是否渲染到阴影贴图当中
wallMesh.castShadow = shadow;
// 将立方体添加到场景中
group.add(wallMesh)
boxObjects.value.push(wallMesh)
return wallMesh
}
//创建地面
function createGround() {
//require('@/assets/img/Factory/cao.png')
//导入材质
const groundTexture = new THREE.TextureLoader().load(requires.ny);
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.repeat.set(100, 100);
const ground = new THREE.PlaneGeometry(1014, 681);
const groundMaterial = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
map: groundTexture,
// color: 0x00ff00,
// transparent: true,
// opacity: 0.2,
});
const groundMesh = new THREE.Mesh(ground, groundMaterial);
groundMesh.name = "地面";//设置name属性
groundMesh.rotateX(-Math.PI / 2);//旋转用于呈现一个水平的地面
scene.add(groundMesh);
}
//创建地板,可以理解为地基
function createFloor(houseName: string, baseWidth: number, baseLength: number, position: positionType) {
const texture = new THREE.TextureLoader().load(requires.wood);
//设置地板大小由于后面将要生成墙体存在设置为1的厚度因此这里对地板的xz均-2
const floor = new THREE.BoxGeometry(baseWidth - 2, 1, baseLength);
const material = new THREE.MeshPhongMaterial({ map: texture, transparent: true });
const mesh = new THREE.Mesh(floor, material);
const { x, y, z } = position
mesh.position.set(x, y + 1 / 2, z);
mesh.name = houseName + "地板";
group.add(mesh);
return mesh;
}
//创建左右两边墙体
function createWall(baseWidth: number = 10, baseHeght: number, baseLength: number) {
const wallTexture = new THREE.TextureLoader().load(requires.wall1);
const wall = new THREE.BoxGeometry(baseLength, baseHeght, baseWidth);
const wallMaterial = new THREE.MeshPhongMaterial({
map: wallTexture,
});
//墙体的网格
const wallMesh = new THREE.Mesh(wall, wallMaterial);
return wallMesh;
}
//不规则墙体
function genwallShape(baseWidth: number, baseHeght: number, baseLength: number) {
const shape = new THREE.Shape();
let height = baseHeght;//墙的高度
shape.moveTo(0, 0); //起点
shape.lineTo(0, height); //墙体高度
shape.lineTo(baseWidth / 2 - 1, height + 5); //墙体顶点
shape.lineTo(baseWidth / 2 - 1, height + 6); //墙体顶点
shape.lineTo(baseWidth / 2 + 1, height + 6); //墙体顶点
shape.lineTo(baseWidth / 2 + 1, height + 5); //墙体顶点
shape.lineTo(baseWidth, height);
shape.lineTo(baseWidth, 0);
shape.lineTo(0, 0);
return { shape };
}
//创建不规则墙体
function createIrregularWall(shape: any, position: any) {
const extrudeSettings = {
depth: 1,//定义深度由于挤压几何体的点位都是xy坐标组成的二位平面这个参数定义向z轴的延展长度即为墙的厚度
bevelEnabled: false,
};
const wallTexture = new THREE.TextureLoader().load(requires.wall1);
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
wallTexture.repeat.set(0.05, 0.05);
const material = new THREE.MeshPhongMaterial({ map: wallTexture });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(...position);
group.add(mesh);
return mesh;
}
//创建不带门的不规则墙体
function createNoDoorWall(baseWidth: number, baseHeght: number, baseLength: number, position: positionType) {
const { x, y, z } = position
let { shape } = genwallShape(baseWidth, baseHeght, baseLength);
let mesh = createIrregularWall(shape, [-baseWidth / 2 + x, 0, -baseLength / 2 + z]);
mesh.name = "带门的墙对面的墙";
}
//带门的墙体
function createDoorWall(baseWidth: number, baseHeght: number, baseLength: number, position: positionType) {
const { x, y, z } = position
let { shape } = genwallShape(baseWidth, baseHeght, baseLength);
const door = new THREE.Path();
//门的位置
door.moveTo(baseWidth / 2 + 5, 0);
door.lineTo(baseWidth / 2 + 5, 5);
door.lineTo(baseWidth / 2 - 5, 6);
door.lineTo(baseWidth / 2 - 5, 0);
door.lineTo(baseWidth / 2 + 5, 0);
// 形状上的孔洞
shape.holes.push(door);
let mesh = createIrregularWall(shape, [
-baseWidth / 2 + x,
y,
baseLength / 2 - 1 + z,
]);
mesh.name = "带门的墙";
}
//创建屋顶
function createRoof(baseWidth: number, baseHeght: number, baseLength: number, position: positionType) {
const { x, y, z } = position
//屋顶宽
let width = Math.sqrt((baseWidth / 2) ** 2 + 5 ** 2) + 5;//+5让有一点屋檐的效果
const geometry = new THREE.BoxGeometry(baseLength / 2, width, 1);
const texture = new THREE.TextureLoader().load(requires.tile);
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2);
const material = new THREE.MeshPhongMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateZ(THREE.MathUtils.degToRad(75));
mesh.rotateY(-Math.PI / 2);
mesh.position.set(baseWidth / 3 - 1 + x, baseHeght + 2 + y, 0 + z);
mesh.name = "右屋顶";
group.add(mesh);
return { roof: mesh, width };
}
//创建门
function createDoor(baseWidth: number, baseLength: number, position: positionType) {
const { x, y, z } = position;
const texture = new THREE.TextureLoader().load(requires.door);
const door = new THREE.BoxGeometry(3, 5, 0.5);
const material = new THREE.MeshPhongMaterial({
map: texture,
transparent: true,
opacity: 1,
});
const doorMesh = new THREE.Mesh(door, material);
// doorMesh.rotateY(Math.PI / 2);
// doorMesh.position.set(-baseLength / 2, 7, 0);
doorMesh.name = "门";
//以下代码做出了更改
const doorGroup = new THREE.Group();//添加一个门的父级
doorGroup.name = "门的包裹";
doorGroup.position.set(-5 + x, 8 + y, baseLength / 2 + z);//通过父级来改变门的旋转轴
//现在这个是相对于父级
doorMesh.position.x = 5;
doorGroup.add(doorMesh);
group.add(doorGroup);
return doorGroup;
}
//天空盒
function createSkyBox() {
const texture = new THREE.TextureLoader().load(requires.sky);
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
// texture.repeat.set(1, 1);
const skyBox = new THREE.SphereGeometry(900, 100, 100);
const material = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.BackSide,
});
const skyBoxMesh = new THREE.Mesh(skyBox, material);
scene.add(skyBoxMesh);
}
function setTipDom() {
const domTag = document.createElement("div");
domTag.setAttribute("id2", "tipId");
// domTag.innerText='电流'
domTag.style.fontSize = "14px";
domTag.style.backgroundColor = "rgba(0,0,0,.5)";
domTag.style.padding = "5px";
domTag.style.borderRadius = "2px";
domTag.style.color = "#fff";
domTag.style.visibility = "hidden";
// domTag.innerText = mesh.name;
const iTagDomCss3 = new CSS2DObject(domTag);
iTagDomCss3.position.z = 2;
iTagDomCss3.position.y = 0;
scene.add(iTagDomCss3);
saveTipDom = iTagDomCss3;
}
//3D标签初始化
// function initCss3DScene() {
// cssRender = new CSS3DRenderer();
// cssRender.setSize(iw, ih);
// cssRender.domElement.style.position = "absolute";
// cssRender.domElement.style.top = '0';
// cssRender.domElement.style.outline = "none";
// cssRender.domElement.className = "cssrender";
// canvas.appendChild(cssRender.domElement);
// }
function sethoveMesh() {
dragControls = new DragControls(
boxObjects.value,
camera,
labelRenderer.domElement
);
// dragControls.deactivate();
dragControls.addEventListener("hoveron", function (event: any) {
saveTipDom.element.innerHTML = `${event.object.name}:${event.object.devStatus ? t('messages.offline') : t('messages.offline')
}`;
saveTipDom.element.style.visibility = "visible";
saveTipDom.position.x = event.object.position.x;
saveTipDom.position.y = event.object.position.y + 5;
saveTipDom.position.z = event.object.position.z - 20;
saveTipDom.visible = true;
});
dragControls.addEventListener("hoveroff", function (event: any) {
saveTipDom.element.style.visibility = "hidden";
saveTipDom.position.x = 0;
saveTipDom.position.y = 9999;
saveTipDom.visible = false;
});
dragControls.addEventListener("dragend", function (event: any) {
// console.log(event);
//event.object.sensor_id
//console.log(`"x":${event.object.position.x}, "y":${event.object.position.z}`);
// coordinate[event.object.sensor_id] = { "x": event.object.position.x.toFixed(2), "y": event.object.position.z.toFixed(2) }
// console.log(JSON.stringify(coordinate), 'coordinate 坐标');
let data = { 'id': event.object.sensor_id, 'x': event.object.position.x.toFixed(2), 'y': event.object.position.z.toFixed(2) }
updateCoordinateByPoint(data).then((res: any) => {
if (res.code == 200) {
ElNotification({
message: '移动位置成功',
duration: 2000,
type: 'success'
})
}
})
});
}
onMounted(() => {
// console.log(container.value.offsetWidth,'container');
//初始化场景
init()
/**创建传感器 */
getSensorDataTimer = setInterval(() => {
if (store.sensorList.length > 0) {
store.sensorList.forEach((element: any) => {
let state = element.status ? 0x88e76a : 0xff0000;
let wallMesh = createBox(small_size, { x: element.x, y: 0, z: element.y }, state, true, element, element.icon)
});
clearInterval(getSensorDataTimer)
}
}, 100)
getDevDataTimer = setInterval(() => {
if (store.devdataList.length > 0) {
store.devdataList.forEach((element: any) => {
let state = element.status ? 0x88e76a : 0xff0000;
let wallMesh = createBox(small_size, { x: element.x, y: 0, z: element.y }, state, false, element, element.icon)
});
clearInterval(getDevDataTimer)
}
}, 100)
// const length = store.result.length
// //获取store中的数据长度
// setInterval(() => {
// //获得一个随机整数
// const random = Math.floor(Math.random() * length)
// const tempdata: any = store.result[random]
// tempdata.status = !store.result[random]?.status
// store.updateResult(tempdata)
// }, 5000)
})
</script>
<style>
/* @import url("@/assets/iconfont.css"); */
.laber_name {
color: #FFF;
font-family: sans-serif;
padding: 2px;
background: rgba(0, 0, 0, 0.6);
}
</style>