import { AbstractMesh, EventState, Mesh, MeshBuilder, PointerEventTypes, PointerInfo, Vector3, } from '@babylonjs/core'; import { Control, Image, Rectangle, } from '@babylonjs/gui'; import { PlanComponent } from 'src/app/pages/plan/plan.component'; import { ConfigManager } from '../../controller/config-manager'; import { DataManager, ModelChangeType } from '../../controller/data-manager'; import { Event_ChangeFacility } from '../../controller/event-manager/events/event-change-facility'; import { InfoManager } from '../../controller/info-manager'; import { ModeManager, ModeType } from '../../controller/mode-manager'; import { SceneManager } from '../../controller/scene-manager'; import { BuildingStatus } from '../../controller/status/building-status'; import { IndoorStatus } from '../../controller/status/indoor-status'; import { StatusManager } from '../../controller/status/status-manager'; import { UIManager } from '../../controller/ui-manager'; import { FacilityPosType, ModelData_facility, FacilityShowType, FacilityType } from '../../model/data/model-data/model-data-facility'; import { TransformData } from '../../model/data/transform-data'; import { BuildingInfo } from '../../model/info/building/building-info'; import { AreaInfo } from '../../model/info/model/facilityinfo-tool/facility-area'; import { ModelInfo_facility } from '../../model/info/model/model-info-facility'; import { BabylonTool } from '../../tool/babylon-tool'; import { BabylonUIStyleTool } from '../../tool/babylon-ui-style-tool'; import { GizmoTool } from '../../tool/gizmo-tool'; import { TsTool } from '../../tool/ts-tool'; import { BuildingWindow } from '../building-window/building-window'; import { CopyFacilityInfo, FacilityInfoInSceneWindow } from '../facilityinfoinscene-window/facilityinfoinscene-window'; import { ToolbarWindow } from '../toolbar-window/toobar-window'; import { UIBase } from '../window-base/ui-base'; import { FacilityUIItem } from './facility-ui-item'; //设备界面 export class FacilityWindow extends UIBase { three: PlanComponent;//前端组件 allFacilityUIItemes: FacilityUIItem[] = []; static s_currentFacilityItem: FacilityUIItem; static instance: FacilityWindow; createIconRoot: Rectangle;//创建状态的跟随icon createIcon: Image; static readonly c_createIcon_width = 40; createIndex = 0; //临时的创建序号 onInit() { FacilityWindow.instance = this; super.onInit(); SceneManager.Instance.scene.onBeforeRenderObservable.add(this.onUpdate); this.initPickEvent(); } onOpen() { super.onOpen(); } onClose() { super.onClose(); } onUpdate() { FacilityWindow.instance.createIconFollow(); } /** * 更新创建状态指示icon */ updateCreateIcon() { if (ModeManager.currentMode == ModeType.Look)//查看模式无效 { return; } if (this.createIconRoot == null) { this.createIconRoot = new Rectangle("CreateFacilityIcon"); this.createIconRoot.clipChildren = false; UIManager.Instance.uiRoot.addControl(this.createIconRoot); this.createIconRoot.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; this.createIconRoot.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; BabylonUIStyleTool.setStyle_size(this.createIconRoot, FacilityWindow.c_createIcon_width + "px", "70px"); this.createIconRoot.thickness = 0; let line = new Rectangle("line"); this.createIconRoot.addControl(line); line.width = "3px"; line.thickness = 0; line.background = BabylonUIStyleTool.c_color_blue; line.shadowBlur = 5; line.shadowColor = BabylonUIStyleTool.c_color_blue; this.createIcon = new Image("createIcon"); this.createIconRoot.addControl(this.createIcon); this.createIcon.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; BabylonUIStyleTool.setStyle_size(this.createIcon, FacilityWindow.c_createIcon_width + "px", FacilityWindow.c_createIcon_width + "px"); } if (FacilityWindow.s_currentFacilityItem != null) { let imageURL = FacilityWindow.s_currentFacilityItem.getIconURL(); if (this.createIcon.source != imageURL) { this.createIcon.source = imageURL; // this.createIcon.sourceLeft = 50.5; } } } /** * 创建指示器跟随 */ createIconFollow() { if (this.createIconRoot != null) { if (FacilityWindow.s_currentFacilityItem == null) { this.createIconRoot.isVisible = false; } else { this.createIconRoot.isVisible = true; this.createIconRoot.left = SceneManager.Instance.scene.pointerX - FacilityWindow.c_createIcon_width * 0.5; this.createIconRoot.top = SceneManager.Instance.scene.pointerY - 40 - ConfigManager.c_size_facilityIconSize; } } } //更新室内或室外的设备信息 updateAllFacilities(facilityPosType: FacilityPosType) { this.clearAllFacilityUIItemes(); this.clearCurrentFacility(); let facilities: ModelData_facility[]; if (facilityPosType == FacilityPosType.In) { facilities = DataManager.allFacilityData.indoor; } else { // console.log("=====updateAllFacilities====="); // console.log(DataManager.allFacilityData); facilities = DataManager.allFacilityData.outdoor; } let instance = this; //为了避免多个模型同时加载、导致indexDB创建冲突,所以先加载一个,保证indexDB创建完成 BabylonTool.importMeshSync(null, "mesh/indexdb/gd/", "GD.gltf", undefined, "GD_indexDB", (meshes) => { meshes[0].dispose(); for (let i = 0; i < facilities.length; i++) { let facilityUIItem: FacilityUIItem = new FacilityUIItem( facilities[i], null, null ); instance.allFacilityUIItemes.push(facilityUIItem); } console.log("所有可用的设备", instance.allFacilityUIItemes); PlanComponent.instance.getAllIcons(instance) }) instance.three = PlanComponent.instance } //清空可用设施列表 clearAllFacilityUIItemes() { for (let i = 0; i < this.allFacilityUIItemes.length; i++) { this.allFacilityUIItemes[i].dispose(); } this.allFacilityUIItemes = []; } //清空当前选中的设施 clearCurrentFacility() { if (FacilityWindow.s_currentFacilityItem != null) { FacilityWindow.s_currentFacilityItem.onSelect(null); FacilityWindow.s_currentFacilityItem = null; } } //点击了消防设施按钮 onClickFacilityBtn(select: FacilityUIItem) { let oldItem = FacilityWindow.s_currentFacilityItem; FacilityWindow.s_currentFacilityItem = select; FacilityWindow.s_currentFacilityItem.onSelect(true); if (oldItem != null) { oldItem.onSelect(false); if (FacilityWindow.s_currentFacilityItem == oldItem) { FacilityWindow.s_currentFacilityItem = null; } } this.updateCreateIcon(); } //初始化pick事件 initPickEvent() { SceneManager.Instance.scene.onPointerObservable.add( this.onPointerObservable ); } //鼠标交互监听 onPointerObservable(eventData: PointerInfo, eventState: EventState) { if (ModeManager.currentMode == ModeType.Look)//查看模式无效 { return; } let instance = FacilityWindow.instance; switch (eventData.type) { case PointerEventTypes.POINTERUP: if (eventData.event.button == 0) { //左键正常 if (eventData.pickInfo.hit && !SceneManager.s_isPointerDrag) { if (FacilityWindow.s_currentFacilityItem != null) { instance.createNewFacilityByPos(eventData.pickInfo.pickedPoint); return; } } if (!SceneManager.s_isPointerDrag && !ToolbarWindow.instance.isMeshAdsorb) { GizmoTool.onPickMeshInfoObservable.notifyObservers(null);//取消之前选择 } } else { //右键取消 instance.three.unSelectBottomIcon(); } break; case PointerEventTypes.POINTERPICK: // console.log(eventData.event); break; } } //寻找设备预设 getFacilityPrefab(resName: string): Mesh { let result = null; // console.log("查找设备" + resName); for (let i = 0; i < this.allFacilityUIItemes.length; i++) { if (this.allFacilityUIItemes[i].facilityData.resName == resName) { result = this.allFacilityUIItemes[i].meshPrefab as Mesh; // console.log("设备找到" + resName); break; } } // console.log(result); return result; } //异步获取预制 getFacilityPrefabSync(resName: string): Promise { let thisWindow = this; //为了方便调用其方法 let myPromise = new Promise(function (resolve, reject) { let result: Mesh = thisWindow.getFacilityPrefab(resName);//先获取已经加载好的 if (result == null) {//没获取到,则开始轮询 let intervalid = setInterval(function () { //轮询方法 let l_result: Mesh = thisWindow.getFacilityPrefab(resName); if (l_result != null) { clearInterval(intervalid);//停止轮询intervalid resolve(l_result); //成功返回结果 } }, 500); } else { resolve(result);//成功返回结果 } }); return myPromise; } //创建新的设施(用世界坐标) createNewFacilityByPos(worldPosition: Vector3) { let facilityData = FacilityWindow.s_currentFacilityItem.facilityData.clone( this.createIndex.toString() ); facilityData.transformData.position = worldPosition.clone(); this.createNewFacility(facilityData); } /** * 根据mesh创建设备 * @param mesh * @param type */ createNewFacilityByMesh(mesh: AbstractMesh, type: FacilityType) { let facilityData = this.createFacilityDataFromMesh(mesh, type); //let facilityInfo = this.createFacilityInfoFromMesh(facilityData, mesh, buildingInfo); if (!this.isRepeatFacilityFromMesh(type, mesh.id)) //不重复 { console.log("获取到设备" + type, mesh); this.createNewFacility(facilityData, mesh); } } /** * 创建新的设施(用data) * @param facilityData * @param mesh 默认null表示利用根据数据加载模型,不是null表示已经准备好了 */ createNewFacility(facilityData: ModelData_facility, mesh: AbstractMesh = null) { let currentBuidngItem = StatusManager.getStatus(BuildingStatus) .buildingWindow.currentBuidngItem; if (currentBuidngItem == null) { alert("请先选中目标建筑"); // ThreeDimensionalHomeComponent.instance.openSnackBar("请先选中目标建筑"); return } Event_ChangeFacility.dispatch(facilityData, ModelChangeType.Add, null); this.createFacility(facilityData, true, undefined, false, true, mesh, (modelInfo) => { GizmoTool.onPickMeshInfoObservable.notifyObservers(modelInfo); }); } /** * 粘贴复制的设备到当前建筑 * @param copyFacilityInfo */ pasteFacility(copyFacilityInfo: CopyFacilityInfo) { let isSameFloor = true;//同层内粘贴 if (StatusManager.s_currentStatus instanceof BuildingStatus) { if (!copyFacilityInfo.outDoor) { isSameFloor = false; } } else if (StatusManager.s_currentStatus instanceof IndoorStatus) { if (copyFacilityInfo.outDoor) { isSameFloor = false; } else if (copyFacilityInfo.buildingKey != StatusManager.s_currentStatus.indoorWindow.currentFloorUIItem.getIndoorKey()) { isSameFloor = false; } } //取消之前的所有选中 FacilityInfoInSceneWindow.instance.cancleAllCurrectFacilityItem(); for (let i = 0; i < copyFacilityInfo.facilityData.length; i++) { let facilityData = copyFacilityInfo.facilityData[i].clone(this.createIndex.toString()); if (isSameFloor)//同层粘贴,略作偏移 { facilityData.transformData.position.x += 5; } Event_ChangeFacility.dispatch(facilityData, ModelChangeType.Add, null); this.createFacility(facilityData, false, undefined, true, true, null, (modelInfo) => { //GizmoTool.onPickMeshInfoObservable.notifyObservers(modelInfo); modelInfo.onStopLongPress(null, null); }); } } /** * 用户移除设备(等待UI调用) * @param modelInfo_facility */ disposeFacility(modelInfo_facility: ModelInfo_facility) { let modelData = modelInfo_facility.modelData; let buildingInfo: BuildingInfo = modelInfo_facility.belongToBuilding; buildingInfo.ModelInfo.removeFacilityInfo(modelInfo_facility, true); InfoManager.removeModelInfo(modelInfo_facility); // GizmoTool.leaveTheGizmoAim(modelInfo_facility); // 看是否取消对坐标轴位置的标注 Event_ChangeFacility.dispatch(modelData, ModelChangeType.Remove, null); } //创建设备 createFacility( facilityData: ModelData_facility, isNew = false, buildingInfo: BuildingInfo = null, isLocalPos = false, select = false, mesh: AbstractMesh = null, //null 表示利用根据数据加载模型,不是null表示已经准备好了 onSuccess?: (modelInfo: ModelInfo_facility) => void ): ModelInfo_facility { BuildingWindow.instance.getUVMat(facilityData.facilityType, mesh); if (buildingInfo == null) { buildingInfo = this.getCurrentBuildingInfo(); } let defaultMesh: AbstractMesh = null; if (mesh == null) { defaultMesh = MeshBuilder.CreateBox(facilityData.key, { size: 1 }); defaultMesh.isVisible = false; } else { defaultMesh = mesh; } let facilityInfo = InfoManager.newModelInfo_facility( facilityData.key, facilityData, null, defaultMesh, buildingInfo, isNew ); if (facilityInfo.facilityShowType == FacilityShowType.ModelAndTag) { //模型类的,等加载完模型再设置transform信息,因为要把模型的position等数值和数据层的position等数据指向同一引用,方便后续调整后的同步 } else { this.setFacilityTransform(isLocalPos, isNew, facilityData, buildingInfo, defaultMesh, facilityInfo); } facilityInfo.belongToBuilding = buildingInfo; if (facilityInfo.facilityShowType == FacilityShowType.ModelAndTag && mesh == null) { this.getFacilityPrefabSync(facilityData.resName).then((mesh) => { let prefab = mesh; let newFacility = SceneManager.cloneMesh( facilityData.key, facilityInfo, prefab ); facilityInfo.modelBox = newFacility; this.setFacilityTransform(isLocalPos, isNew, facilityData, buildingInfo, newFacility, facilityInfo); if (onSuccess) { onSuccess(facilityInfo); } }); } else if (facilityInfo.facilityShowType == FacilityShowType.AreaAndTag) { let facilityData = facilityInfo.modelData as ModelData_facility; if (facilityData.areaPoints.length == 0) { facilityData.areaPoints = facilityData.newAreapPoints(); } facilityInfo.areaInfo = new AreaInfo(facilityData.areaPoints, facilityInfo); if (onSuccess) { onSuccess(facilityInfo); } } // if (select) { // GizmoTool.onPickMeshInfoObservable.notifyObservers(facilityInfo); // } //添加到建筑信息 let oldCreateNum = Number(facilityData.key); if (oldCreateNum >= this.createIndex) { this.createIndex = oldCreateNum + 1; } return facilityInfo; } //设置设备transform信息 setFacilityTransform(isLocalPos: boolean, isNew: boolean, facilityData: ModelData_facility, buildingInfo: BuildingInfo, newFacility: AbstractMesh, facilityInfo?: ModelInfo_facility) { //如果是局部坐标,要先设置父节点 if (isLocalPos) { buildingInfo.ModelInfo.setFacilityParent(facilityInfo); } let halfY = newFacility.scaling.y * 0.5; if (!isNew) { halfY = 0; } let originalScaling = facilityData.transformData.originalScaling.clone(); if (!originalScaling.equals(newFacility.absoluteScaling))//原始缩放不同,表示换了模型 { // let scaleSize = new Vector3(facilityData.transformData.scaling.x / facilityData.transformData.originalScaling.x, facilityData.transformData.scaling.y / facilityData.transformData.originalScaling.y, facilityData.transformData.scaling.z / facilityData.transformData.originalScaling.z); let scaleSize = facilityData.transformData.scaling.divide(facilityData.transformData.originalScaling); facilityData.transformData.originalScaling = newFacility.absoluteScaling.clone(); facilityData.transformData.scaling = facilityData.transformData.originalScaling.multiply(scaleSize); } newFacility.position = facilityData.transformData.position.add( new Vector3(0, halfY, 0) ); newFacility.position = facilityData.transformData.position; newFacility.position.y += halfY; // newFacility.scaling = facilityData.transformData.scaling; // newFacility.rotation = facilityData.transformData.rotation; if (facilityData.transformData.rotationQuaternion != null) { newFacility.rotationQuaternion = facilityData.transformData.rotationQuaternion; } //如果是世界坐标,则最后设置父节点 if (!isLocalPos) { buildingInfo.ModelInfo.setFacilityParent(facilityInfo); } } //获取当前选中的建筑信息 getCurrentBuildingInfo(): BuildingInfo { let buildingInfo: BuildingInfo = null; if (StatusManager.s_currentStatus instanceof BuildingStatus) { buildingInfo = StatusManager.getStatus(BuildingStatus) .buildingWindow.currentBuidngItem.buildingInfo; } else if (StatusManager.s_currentStatus instanceof IndoorStatus) { buildingInfo = StatusManager.getStatus(IndoorStatus) .indoorWindow.currentFloorUIItem.buildingInfo; } return buildingInfo; } //#region 从已有模型创建设备 /** * 从模型中创建消防设备信息 * @param mesh */ createFacilityByMesh(mesh: AbstractMesh) { if (TsTool.stringContain(mesh.name, FacilityType.XF_MHQ_GF_4)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_MHQ_GF_4); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_MHQ_GF_8)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_MHQ_GF_8); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_MHQ_GF_35)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_MHQ_GF_35); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_MHQ_PT_4)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_MHQ_PT_4); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_MHQ_PT_8)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_MHQ_PT_8); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_MHQ_PT_35)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_MHQ_PT_35); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_MHT)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_MHT); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_XFCM)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_XFCM); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_XFF)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_XFF); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_XFQ)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_XFQ); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_XFS)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_XFS); } else if (TsTool.stringContain(mesh.name, FacilityType.XF_XFT)) { this.createNewFacilityByMesh(mesh, FacilityType.XF_XFT); } } /** * 从模型中创建安全疏散相关信息 * @param mesh */ createAQSSFromMesh(mesh: AbstractMesh) { if (TsTool.stringContain(mesh.name, FacilityType.AQSS_SSD)) { this.createNewFacilityByMesh(mesh, FacilityType.AQSS_SSD); } else if (TsTool.stringContain(mesh.name, FacilityType.AQSS_TSLX)) { this.createNewFacilityByMesh(mesh, FacilityType.AQSS_TSLX); } } /** * 从模型中创建加油站相关信息 * @param mesh */ createOilingByMesh(mesh: AbstractMesh) { if (TsTool.stringContain(mesh.name, FacilityType.JY_JYJ)) { // console.log("找到加油机", mesh) this.createNewFacilityByMesh(mesh, FacilityType.JY_JYJ); } else if (TsTool.stringContain(mesh.name, FacilityType.JY_SYGX)) { // console.log("找到输油管线", mesh) this.createNewFacilityByMesh(mesh, FacilityType.JY_SYGX); } else if (TsTool.stringContain(mesh.name, FacilityType.JY_YG)) { // console.log("找到油罐", mesh) this.createNewFacilityByMesh(mesh, FacilityType.JY_YG); } else if (TsTool.stringContain(mesh.name, FacilityType.JY_YQHSGX)) { // console.log("找到油气回收", mesh) this.createNewFacilityByMesh(mesh, FacilityType.JY_YQHSGX); } } /** * 从模型创建阻挡物信息 * @param mesh */ createStopByMesh(mesh: AbstractMesh) { if (TsTool.stringContain(mesh.name, FacilityType.ZD_YG)) { this.createNewFacilityByMesh(mesh, FacilityType.ZD_YG); } if (TsTool.stringContain(mesh.name, FacilityType.ZD_SYGX)) { this.createNewFacilityByMesh(mesh, FacilityType.ZD_SYGX); } if (TsTool.stringContain(mesh.name, FacilityType.ZD_YQHSGX)) { this.createNewFacilityByMesh(mesh, FacilityType.ZD_YQHSGX); } if (TsTool.stringContain(mesh.name, FacilityType.ZD_XF)) { console.log("找到消防阻挡物", mesh.name); this.createNewFacilityByMesh(mesh, FacilityType.ZD_XF); } if (TsTool.stringContain(mesh.name, FacilityType.ZD_ZP)) { this.createNewFacilityByMesh(mesh, FacilityType.ZD_ZP); } } /** * 用已有mesh创建设备 * @param mesh * @param type */ createFacilityDataFromMesh(mesh: AbstractMesh, type: FacilityType) { let name = ConfigManager.getFacilityTypeName(type); let result = new ModelData_facility(mesh.name, type, name, mesh.id, new TransformData(), FacilityPosType.In); return result; } /** * 用已有mesh和设备data创建设备Info(暂时不用) * @param facilityData * @param mesh * @param buildingInfo */ createFacilityInfoFromMesh(facilityData: ModelData_facility, mesh: AbstractMesh, buildingInfo: BuildingInfo) { let facilityInfo = InfoManager.newModelInfo_facility( facilityData.key, facilityData, null, mesh, buildingInfo, true ); return facilityInfo; } /** * 来自建筑中的设备 是否重复 */ isRepeatFacilityFromMesh(type: FacilityType, id: string) { let currentBuidngItem = StatusManager.getStatus(BuildingStatus) .buildingWindow.currentBuidngItem; if (currentBuidngItem == null) { alert("请先选中目标建筑"); // ThreeDimensionalHomeComponent.instance.openSnackBar("请先选中目标建筑"); return true; } let result = false; let facilityInfoByTypes = currentBuidngItem.buildingInfo.ModelInfo.facilityInfos; if (facilityInfoByTypes != null) { for (let i = 0; i < facilityInfoByTypes.length; i++) { if (facilityInfoByTypes[i].type == type) { let infos = facilityInfoByTypes[i].facilityInfo; for (let j = 0; j < infos.length; j++) { if (infos[j].modelData.resName == id) { result = true; console.log("重复的设备,不添加"); break; } } } } } return result; } //#endregion }