Files
2025-12-09 20:22:03 +08:00

286 lines
9.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
export default class ParkingAreaMap3d {
constructor(_element) {
this._initScene(_element);
this.shapes = [];
}
/**
* 初始化场景
*/
initScene() {
this.scene = new THREE.Scene();
}
/**
* 初始化相机
*/
initCamera() {
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// position and point the camera to the center of the scene
this.camera.position.z = 5;
//this.camera.lookAt(this.scene.position);
}
/**
* 初始化渲染器
*/
initRenderer(_element) {
// create a render and set the size
this.renderer = new THREE.WebGLRenderer();
this.renderer.setClearColor(new THREE.Color(0xFFFFFF));
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.antialias = true;
this.renderer.alpha = true;
this.renderer.precision = 'mediump'
// add the output of the renderer to the html element
this.container = document.getElementById(_element);
this.container.appendChild(this.renderer.domElement);
}
initControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
// 设置控制器阻尼让控制器更有真是效果必须在动画循环里调用update
//this.controls.enableDamping = true;
// 禁用旋转功能
this.controls.enableRotate = false;
this.controls.minPolarAngle = 0;
this.controls.maxPolarAngle = 90 / 180 * Math.PI;
}
/**
* 初始化灯光
*/
initLight() {
this.light = new THREE.SpotLight(0xffffff);
this.light.position.set(-300, 600, -400);
this.light.castShadow = true;
this.scene.add(this.light);
this.scene.add(new THREE.AmbientLight(0x404040));
}
update() {
this.controls.update();
this.upDownShap();
}
_initScene(_element) {
this.initScene();
this.initCamera();
this.initRenderer(_element);
this.initLight();
this.initControls();
let _that = this;
function animate() {
requestAnimationFrame(animate);
_that.renderer.render(_that.scene, _that.camera);
_that.update(_that);
}
animate();
// addEventListener('click', function (event) {
// _that.onMouseDblclick(event, _that)
// }, false);
// window.addEventListener('mousemove', function (event) {
// _that.onMouseMove(event, _that)
// }, false);
}
getObjectByName(_objName) {
return this.scene.getObjectByName(_objName);
}
getObjectPosition(targetObject) {
let targetCenter = new THREE.Vector3();
// targetObject.updateMatrixWorld(true); // 确保目标物体的世界矩阵是最新的
// targetObject.getWorldPosition(targetCenter); // 将目标物体的世界位置存储到 targetCenter 中
// // 将源物体的位置设置为目标物体的中心位置
// console.log(targetCenter);
let box = new THREE.Box3().setFromObject(targetObject);
targetCenter.x = (box.max.x + box.min.x) / 2;
targetCenter.y = box.min.y;
targetCenter.z = (box.max.z + box.min.z) / 2;
return { x: targetCenter.x, y: targetCenter.y, z: targetCenter.z };
}
getObjectHeight(targetObject) {
let box = new THREE.Box3().setFromObject(targetObject);
// 获取包围盒的高度
let height = box.max.y - box.min.y;
return height;
}
upDownShap() {
if (!this.shapes || this.shapes.length < 1) {
return;
}
// 设置移动的速度和幅度
let speed = 1.5; // 移动速度
let amplitude = 5; // 移动幅度
this.shapes.forEach(shape => {
let newYPosition = shape.y + amplitude * Math.sin(speed * Date.now() / 1000);
shape.object.position.y = newYPosition;
})
}
lookAtObject(_object) {
// 将相机移动到物体位置并面对物体
let _pos = this.getObjectPosition(_object);
this.camera.position.set(_pos.x, _pos.y, _pos.z);
this.camera.lookAt(_object.position);
}
clearThree(obj) {
while (obj.children.length > 0) {
this.clearThree(obj.children[0])
obj.remove(obj.children[0]);
}
if (obj.geometry) obj.geometry.dispose()
if (obj.material) {
//in case of map, bumpMap, normalMap, envMap ...
Object.keys(obj.material).forEach(prop => {
if (!obj.material[prop])
return
if (typeof obj.material[prop].dispose === 'function')
obj.material[prop].dispose()
})
obj.material.dispose()
}
}
resetScene() {
this.clearThree(this.scene);
}
addText(_objName, _text, _position) {
let _that = this;
const loader = new FontLoader();
loader.load('/js/three/examples/fonts/helvetiker_regular.typeface.json', function (font) {
const geometry = new TextGeometry(_text, {
font: font,
size: 0.15,
height: 0.05
});
let material = new THREE.MeshBasicMaterial({ color: 0xffffff , transparent: true, opacity: 1 }); // 创建材质
let mesh = new THREE.Mesh(geometry, material); // 创建网格并添加到场景中
mesh.name = _objName;
//mesh.scale.set(10, 10, 10)
mesh.position.set(_position.x, _position.y+0.6, _position.z);
//mesh.rotateX(270 / 180 * Math.PI)
_that.scene.add(mesh); // 将锥形对象添加到场景中
});
}
createParkingSpace(x, y, z, parkingSpaceSize) {
console.log(parkingSpaceSize)
const parkingSpaceDepth = 0.1; // 车位的厚度
let _color = 0x00FF00;
if(parkingSpaceSize.color){
_color = parkingSpaceSize.color;
}
const parkingSpaceMaterial = new THREE.MeshBasicMaterial({ color: _color }); // 灰色材质
const geometry = new THREE.BoxGeometry(parkingSpaceSize.width, parkingSpaceSize.height, parkingSpaceDepth);
const mesh = new THREE.Mesh(geometry, parkingSpaceMaterial);
mesh.position.set(x, y, z); // 设置车位位置
this.scene.add(mesh); // 将车位添加到场景中
return mesh; // 返回车位对象以便后续管理
}
/**
* 初始化车位
* @param {车位列表} pSpaces
*/
initParkingSpace(pSpaces) {
this.resetScene();
let sWidth = 0.5;
let sHeight = 1;
let lineSpaceLenght = 50;
let roadHeight = 1;
// 创建多个车位
const spaceBetween = 0.1; // 车位之间的间隔
//如果车位数没有超过lineSpaceLenght 那么lineSpaceLenght 修改为车位数
if(pSpaces.length < lineSpaceLenght && pSpaces.length > 20){
lineSpaceLenght = 20;
}else if(pSpaces.length < lineSpaceLenght){
lineSpaceLenght = pSpaces.length;
}
let pWidth = sWidth * lineSpaceLenght + lineSpaceLenght * spaceBetween + roadHeight *2;
let totalLines = Math.ceil(pSpaces.length / (2 * lineSpaceLenght));
let pHeight = sHeight * 2 * totalLines + roadHeight * (totalLines + 1);
//todo 添加一个车位平面
// 创建一个停车场平面
const planeGeometry = new THREE.PlaneGeometry(pWidth, pHeight); // 10x10的平面
const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x808080 }); // 灰色材质
const parkingLotPlane = new THREE.Mesh(planeGeometry, planeMaterial);
// 将停车场平面添加到场景中
this.scene.add(parkingLotPlane);
let _x = 0;
let _y = pHeight / 2 - sHeight / 2 - sHeight;
let _textX = 0;
let _textY = _y + sHeight/4 - spaceBetween *2 ;
for (let i = 0; i < pSpaces.length; i++) {
_x = -pWidth / 2 + (i%lineSpaceLenght) * (sWidth + spaceBetween) + sWidth/2 + roadHeight;
_textX = _x;
if (i%lineSpaceLenght == 0 && i != 0 ) {
_y -= (sHeight+spaceBetween);
_textY = _y - sHeight/4 - sHeight - spaceBetween *2 ;
}
if(i% (2*lineSpaceLenght) == 0 && i != 0){
_y -= roadHeight;
_textY = _y + sHeight/4 - spaceBetween *2 ;
}
console.log(pWidth, pHeight, _x, _y);
this.createParkingSpace(_x, _y, 0, {
width: sWidth,
height: sHeight,
color:pSpaces[i].psColor
}); // 创建车位并设置位置
if(pSpaces[i].num.length>1 ){
_textX = _x -sWidth/2
}
this.addText(pSpaces[i].num,pSpaces[i].num+"",{
x:_textX,
y:_textY,
z:0
})
}
}
}