import { AbstractMesh, Vector3 } from "@babylonjs/core"; import { PointerEventTypes, PointerInfo } from "@babylonjs/core/Events/pointerEvents"; import { EventState, Observer } from "@babylonjs/core/Misc/observable"; import { classToClass, plainToClass } from "class-transformer"; import { PlanComponent } from "src/app/pages/plan/plan.component"; import { DataManager } from "../../controller/data-manager"; import { EventManager } from "../../controller/event-manager/event-manager"; import { Event_GetAllMarkPlanData } from "../../controller/event-manager/events/event-get-markplandata-success"; import { Event_KeyboardInput } from "../../controller/event-manager/events/event-keyboard-input"; import { Event_MarkInfoChange, MarkInfoChangeType } from "../../controller/event-manager/events/event-mark-info-change"; import { InputController } from "../../controller/inputController"; import { ModeManager, ModeType } from "../../controller/mode-manager"; import { SceneManager } from "../../controller/scene-manager"; import { ServeManager } from "../../controller/serve-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 { ArcRotateCameraData } from "../../model/data/camera-data"; import { BuildingType } from "../../model/data/institution/building/building-data"; import { MarkData, MarkKindType, MarkTagPos, MarkType } from "../../model/data/mark/mark-data"; import { AllMarkPlanData, MarkNodeData, MarkPlanData, WeatherType, WindDirectionType, EnvironmentData, NatureData } from "../../model/data/mark/mark-plan-data"; import { MarkTemplate } from "../../model/data/mark/mark-template-data"; import { ModelType } from "../../model/data/model-data/model-data"; import { FacilityType } from "../../model/data/model-data/model-data-facility"; import { BuildingInfo } from "../../model/info/building/building-info"; import { MarkNodeInfo } from "../../model/info/mark/mark-plan-info"; import { ModelInfo_mark } from "../../model/info/mark/model-info-mark"; import { ModelInfo_building } from "../../model/info/model/model-info-building"; import { ModelInfo_facility } from "../../model/info/model/model-info-facility"; import { LoadTool } from "../../tool/load-tool"; import { MeshPool, MeshPoolInfo } from "../../tool/mesh-pool"; import { ParticleSystemTool } from "../../tool/particle-system-tool"; import { SpeakingTool } from "../../tool/speaking-tool"; import { BuildingUIItem } from "../building-window/building-ui-item"; import { BuildingWindow } from "../building-window/building-window"; import { IndoorFloorUIItem } from "../indoor-window/indoor-floorui-item"; import { UIBase } from "../window-base/ui-base"; import { WeatherTool } from "./weather-tool"; export class MarkWindow extends UIBase { /** * 游离节点特殊名称 */ readonly c_leaveNodeName: string = ""; static instance: MarkWindow; static s_cameraData: ArcRotateCameraData = null;//预定义的相机数据 static s_preLoadMesh: boolean = false;//预加载所有标绘物(如果是false,则在选中每个标绘物的时候,进行预加载单个) /** * 天气工具 */ weatherTool: WeatherTool; /** * 喷水特效路径 */ static readonly c_water_particlePath = "assets/particlesystem/water/water.json"; enterIndoorObserver: Observer; //进入室内的监听者(一次性,用于选中节点切换时) enterOutDoorObserver: Observer;//进入室外的监听者(一次性,用于选中节点切换时) s_startEnterIndoorObserver: Observer; //开始进入室内的监听者(因UI操作切换) s_enterIndoorObserver: Observer; //进入室内的监听者(因UI操作切换) s_starteEnterOutDoorObserver: Observer;//开始进入室外的监听者(因UI操作切换) s_enterOutDoorObserver: Observer;//进入室外的监听者(因UI操作切换) /** * 中断一次线的创建 ,0表示可以开始创建,1-表示正在绘制, -1 表示阻止绘制 */ markLineIsBreak: number = -1; /** * 进攻路线 0-表示可以开始,1-表示正在绘制,-1 表示阻止绘制 */ mulArrowIsBreak_JG: number = -1; /** * 撤退路线 0-表示可以开始,1-表示正在绘制,-1 表示阻止绘制 */ mulArrowIsBreak_CT: number = -1; /** * 输油管 0-表示可以开始,1-表示正在绘制,-1 表示阻止绘制 */ mulLineIsBreak_SYG: number = -1; /** * 所有的标绘方案数据 */ allMarkPlanData: AllMarkPlanData = null; /** * 当前节点的拷贝信息,用于还原 */ currentMarkNodeDataCopy: MarkNodeData; /** * 当前节点的信息 */ currentMarkNodeInfo: MarkNodeInfo; /** * 当前选中的素材实例(运行时数据) */ currentMarkInfo: ModelInfo_mark; /** * 当前选中的素材预制体 */ currentMarkDataPrefab: MarkData; // /** // * 所有标绘物的预制体 // */ // allMarkPrefabInfo: AllMarkInfo = new AllMarkInfo(); isPickDown: boolean = false; //按下了 /** * 是否显示名称 */ isShowProperty3d: boolean = true; /** * 是否显示水源 */ isShowWaterSource = false; //#region 生命周期 onInit() { super.onInit(); MarkWindow.instance = this; let instance = this; instance.initPickEvent(); instance.initKeyboardInput(); ParticleSystemTool.Init(SceneManager.Instance.scene); ParticleSystemTool.instance.loadPrefab("water", MarkWindow.c_water_particlePath, false); //预加载喷水 this.preLoadMesh(); // 创建输入控制器 const control = new InputController(SceneManager.Instance.scene); this.weatherTool = new WeatherTool(SceneManager.Instance.defaultCamera, SceneManager.Instance.scene); SceneManager.Instance.scene.onBeforeRenderObservable.add(() => { instance.onUpdateShow(); }) } onOpen() { super.onOpen(); this.onShow(); } onClose() { super.onClose(); } onHide() { super.onHide(); this.selectMarkNode(null, null); SpeakingTool.Instance.clear(); } onShow() { super.onShow(); let instance = this; instance.getAllSandBoxTemplate();//获取模板 if (this.allMarkPlanData == null) { DataManager.initMarkData((data: AllMarkPlanData) => { instance.onGetAllMarkPlanData(data); MarkWindow.instance.selectMarkNode(null, null, true); //模拟选中空节点,创建游离节点 // console.log("标绘信息", data); // console.log(JSON.stringify(data)); }); } else { MarkWindow.instance.selectMarkNode(null, null, true); //模拟选中空节点,创建游离节点 } } /** * 不同单位,释放数据,下次重新请求 */ dispose() { this.allMarkPlanData = null; } //#endregion //#region 与前端通信 //请先监听 Event_GetAllMarkPlanData 事件,获取单位的标绘方案数据成功的事件。 // 注意EventManager 的引用路径: import { EventManager } from "src/babylon/controller/event-manager/event-manager"; // EventManager.addListener(Event_GetAllMarkPlanData,(data:Event_GetAllMarkPlanData)=> // { // //从服务器获取到方案数据 // }) //开启界面后,直接使用 MarkWindow.instance 访问实例对象 /** * 开启界面 */ static openWindow(): MarkWindow { // console.log("进入沙盘"); if (MarkWindow.instance == null) { SceneManager.s_markWindow = UIManager.open(MarkWindow); } else { UIManager.show(MarkWindow.instance); MarkWindow.instance.selectMarkNode(null, null, true); //模拟选中空节点,创建游离节点 } return MarkWindow.instance; } /** * 关闭界面 */ static closeWindow() { if (MarkWindow.instance != null) { MarkWindow.instance.shouWaterSource(false); UIManager.hide(MarkWindow.instance); } // console.log("退出沙盘"); } /** * 整体保存当前单位的标绘数据 * 先整体保存 */ saveAllMarkPlanData() { // this.savCurrentNodeData(); DataManager.saveallMarkPlanData(); // if (this.currentMarkNodeInfo != null) { // this.currentMarkNodeDataCopy = classToClass(this.currentMarkNodeInfo.nodeData); //更新备份数据 // } } /** * 保存至已有节点 * @param markPlanId 方案id,一级节点ID * @param nodeId 节点id,二级节点id * @param newName 是否要覆盖原有的名字 */ saveToOldNode(markPlanId: number, nodeId: number, newName?: string) { let markPlaneData = DataManager.allMarkPlanData.getMarkPlanById(markPlanId); if (markPlaneData == null) { console.error("没找到标绘方案:" + markPlanId) return null; } this.savCurrentNodeData(this.currentMarkNodeDataCopy); let oldNodeData = markPlaneData.getNodeById(nodeId); let copyNodeData = classToClass(this.currentMarkNodeDataCopy);//覆盖数据 copyNodeData.id = oldNodeData.id; copyNodeData.index = oldNodeData.index; if (newName != null && newName != this.c_leaveNodeName) { copyNodeData.name = newName; } if (copyNodeData.name == this.c_leaveNodeName) //如果来自空节点,则保留原名 { copyNodeData.name = oldNodeData.name; } //console.log("记录的数据", copyNodeData.texture, this.currentMarkNodeInfo.nodeData.texture); markPlaneData.setNodeData(nodeId, copyNodeData);//覆盖数据 this.saveAllMarkPlanData(); } /** * 新建新节点并保存 * @param markPlanId 方案id,一级节点ID * @param name 新节点名称 */ createNewNodeAndSave(markPlanId: number, name: string) { let newNode = this.createMarkNodeData(markPlanId, name); this.saveToOldNode(markPlanId, newNode.id, name); } /** * 在沙盘节点中点击UI、 切换楼层或室内外,相当于清空 */ changeBuilding(isOutdoor: boolean = false, buildingId: string = null, floorId: string = null) { // console.log("沙盘内切换", isOutdoor, buildingId, floorId); if (this.currentMarkNodeInfo == null) { this.selectMarkNode(null, null, true); return; } else { let environmentData = this.currentMarkNodeInfo.nodeData.getEnvironmentDataByValue(isOutdoor, buildingId, floorId); if (environmentData == null) { //新增环境 environmentData = this.currentMarkNodeInfo.nodeData.addEnvironment(buildingId, isOutdoor, floorId); } else { //已有环境 } environmentData.isNow = true; this.currentMarkNodeInfo.nodeData.changeNowEnvironmentData(environmentData.id); let belongToPlanID = null; if (this.currentMarkNodeInfo.belongToPlanData != null) { belongToPlanID = this.currentMarkNodeInfo.belongToPlanData.id; } this.selectMarkNode(belongToPlanID, this.currentMarkNodeInfo.nodeData.id, true); } } /** * 选中具体的方案子节点 * @param planId 方案 * @param nodeId 节点 * @param changeBuildingByUI 是否在沙盘状态下,点UI切层、建筑 * @param readDescribe 朗读描述 */ selectMarkNode(planId: number, nodeId: number, changeBuildingByUI: boolean = false, readDescribe = false) { // //还原数据 // if (this.currentMarkNodeDataCopy != null && reData) { // let oldPlaneData = this.currentMarkNodeInfo.belongToPlanData; // oldPlaneData.setNodeData(this.currentMarkNodeDataCopy.id, this.currentMarkNodeDataCopy); // this.currentMarkNodeDataCopy = null; // } let nodeCopy: MarkNodeData; if (changeBuildingByUI) //从ui点击切层, { // console.log(this.currentMarkNodeInfo); if (this.currentMarkNodeInfo == null)//没有当前的markInfo,创建一个游离的节点 { // console.log("拷贝游离节点"); nodeCopy = this.createLeaveNode(); this.savCurrentNodeData(nodeCopy); } else //并且当前有拷贝的markinfo { nodeCopy = classToClass(this.currentMarkNodeInfo.nodeData); } } this.clearNodeInfo(); let markPlanData: MarkPlanData = null; if (DataManager.allMarkPlanData == null) { return; } //更新新节点 markPlanData = DataManager.allMarkPlanData.getMarkPlanById(planId); if (markPlanData != null) { //表示不是取消选中 if (nodeCopy == null) { nodeCopy = classToClass(markPlanData.getNodeById(nodeId)); } } else { if (nodeCopy == null) { // console.log("拷贝游离节点 2"); nodeCopy = this.createLeaveNode(); this.savCurrentNodeData(nodeCopy); } } if (nodeCopy != null) { //清空 this.currentMarkNodeDataCopy = nodeCopy;//更新备份数据 this.currentMarkNodeInfo = new MarkNodeInfo(markPlanData, this.currentMarkNodeDataCopy); //this.currentMarkNodeDataCopy = classToClass(this.currentMarkNodeInfo.nodeData); //更新备份数据 this.updateNodeInfo(readDescribe); PlanComponent.instance.updateBeforePlanNode(); // let instance = this; // if (readDescribe) { //镜头移动完,开始说话 // setTimeout(() => { // instance.readDescribe(nodeCopy.describe); // }, MarkNodeData.speakWaitTime * 1000); // } } } /** * 新建方案(一级节点) * @param name 新方案名称 */ createMarkPlaneData(name: string): MarkPlanData { let result = DataManager.allMarkPlanData.createPlanData(name); return result; } /** * 删除方案 * @param id */ deleteMarkPlaneData(id: number) { if (this.currentMarkNodeInfo != null) { this.currentMarkNodeInfo.clearAllMarkDataAndInfo(); } this.currentMarkNodeInfo = null; this.currentMarkNodeDataCopy = null; DataManager.allMarkPlanData.deletePlanData(id); this.saveAllMarkPlanData(); } /** * 新建标绘节点(二级节点) * @param markPlanId 要在哪个方案下新建节点 * @param name 新建的节点名称 */ createMarkNodeData(markPlanId: number, name: string) { let markPlaneData = DataManager.allMarkPlanData.getMarkPlanById(markPlanId); if (markPlaneData == null) { console.error("没找到标绘方案:" + markPlanId) return null; } let result = markPlaneData.createMarkNode(name); this.savCurrentNodeData(result); return result; } /** * 删除标绘节点(二级节点) * @param markPlanId 要删哪个方案下的节点 * @param id 节点的id */ deleteMarkNodeData(markPlanId: number, id: number) { let markPlan = DataManager.allMarkPlanData.getMarkPlanById(markPlanId); if (markPlan == null) { console.error("没找到方案:" + markPlanId + "==无法删除节点" + id); } else { // if (this.currentMarkNodeInfo != null && this.currentMarkNodeInfo.nodeData.id == id) { // this.currentMarkNodeInfo.clearAllMarkDataAndInfo(); // this.currentMarkNodeInfo = null; // this.currentMarkNodeDataCopy = null; // } markPlan.deleteMarkNode(id); this.saveAllMarkPlanData(); } } /** * 选中标记素材模板(由前端调用) * @param select */ selectMarkDataPrefab(select: boolean, data: MarkData) { if (select) { this.currentMarkDataPrefab = data; this.preLoadOneMesh(data); } else { this.currentMarkDataPrefab = null; } this.setMultiPointOnSelectPrefab(select, data) } /** * 选中标绘素材模板 (从前端通知3d) * @param markData * @param select */ selectMarkDataPrefabFrom3d(markData: MarkData, select: boolean) { //通知前端 (一般是右键取消) 最后需要其调用 selectMarkDataPrefab if (select) { } else { if (markData != null) { this.selectMarkDataPrefab(false, markData) //ThreeDimensionalHomeComponent.instance.beforeOneIcon = null } this.markLineIsBreak = -1; this.mulArrowIsBreak_JG = -1; this.mulArrowIsBreak_CT = -1; this.mulLineIsBreak_SYG = -1; } } /** * 选中标绘素材实例(由前端调用) * @param markData * @param select */ selectMarkData(markData: MarkData, select: boolean) { if (select) { let markInfo = this.currentMarkNodeInfo.getMarkInfo(markData.tagPos, markData.type, markData.key); if (this.currentMarkInfo != null && this.currentMarkInfo != markInfo) { this.currentMarkInfo.onSelect(false); } this.currentMarkInfo = markInfo; markInfo.onSelect(select); } else { if (this.currentMarkInfo != null) { this.currentMarkInfo.onSelect(false); } this.currentMarkInfo = null; } } /** * 选中标绘素材实例 (从3d通知前端) * @param markData * @param select */ // markInfo.markData //通知前端 最后需要其调用 selectMarkData selectMarkDataFrom3d(markInfo: ModelInfo_mark, select: boolean) { if (select) { PlanComponent.instance.selectSandTableMark(markInfo.markData, select) } else { if (markInfo != null) { PlanComponent.instance.selectSandTableMark(markInfo.markData, select) } } } /** * 打开属性界面 */ openProperty(markInfo: ModelInfo_mark) { if (markInfo != null) { PlanComponent.instance.getSandTableNature(markInfo.markData); } } /** * 更新属性 * @param markInfo */ updateProperty() { if (this.currentMarkInfo != null) { this.currentMarkInfo.updateProperty(); } } /** * 显示三维属性 * @param show */ showProperty3d(show: boolean) { this.currentMarkNodeInfo.markInfos.forEach((value: ModelInfo_mark[], key: MarkTagPos) => { for (let i = 0; i < value.length; i++) { value[i].showFollowUI(show); } }); this.isShowProperty3d = show; } /** * 清空力量 */ clearForce() { if (this.currentMarkNodeInfo != null) { this.currentMarkNodeInfo.clearAllMarkDataAndInfo(); } this.saveAllMarkPlanData(); } /**显示水源 */ shouWaterSource(show: boolean) { this.isShowWaterSource = show; let facility_water: ModelInfo_facility[] = []; let buildingWindow = StatusManager.getStatus(BuildingStatus).buildingWindow; let buildingUIItems = buildingWindow.buildingUIItems; if (buildingUIItems != null) { for (let i = 0; i < buildingUIItems.length; i++) { let l_item = buildingUIItems[i]; facility_water = facility_water.concat(this.getAllWaterSource(l_item.buildingInfo.ModelInfo)); } } if (StatusManager.s_currentStatus instanceof IndoorStatus) { let indoorWindow = StatusManager.s_currentStatus.indoorWindow; let indoorUIItem = indoorWindow.currentFloorUIItem; // console.log(indoorUIItem.buildingInfo); if (indoorUIItem.buildingInfo != null) { facility_water = facility_water.concat(this.getAllWaterSource(indoorUIItem.buildingInfo.ModelInfo)); } } for (let i = 0; i < facility_water.length; i++) { facility_water[i].showFollowUI(show); } } /** * 获取当前节点的原数据 */ getCurrentNodeData() { if (this.currentMarkNodeInfo == null) { return null; } else { return this.currentMarkNodeInfo.nodeData; } } /** * 改变自然-天气 */ changeNature_weater(weather: WeatherType) { if (this.currentMarkNodeInfo == null) { return; } this.currentMarkNodeInfo.nodeData.natureData.weather = weather; this.changeNatureEffect(true, this.currentMarkNodeInfo.nodeData.natureData); } /** * 改变温度 * @param temperature */ changeNature_temperature(temperature: number) { if (this.currentMarkNodeInfo == null) { return; } this.currentMarkNodeInfo.nodeData.natureData.temperature = temperature; this.changeNatureEffect(true, this.currentMarkNodeInfo.nodeData.natureData); } /** * 改变风向 * @param temperature */ changeNature_windDirection(windDirection: WindDirectionType) { if (this.currentMarkNodeInfo == null) { return; } this.currentMarkNodeInfo.nodeData.natureData.windDirection = windDirection; this.changeNatureEffect(true, this.currentMarkNodeInfo.nodeData.natureData); } /** * 改变风速 * @param temperature */ changeNature_windPower(windPower: number) { if (this.currentMarkNodeInfo == null) { return; } this.currentMarkNodeInfo.nodeData.natureData.windPower = windPower; } /** * 播放或暂停演出系统 * @param play false 表示暂停 */ playOrPauseShow(play: boolean) { } /** * 跳至某一节点 */ skipToNode(nodeID: string) { } //#endregion //#region 演出系统 /** * 当前演出剩余时间 */ currentShowTime: number; /** * 当前节点的完整演出时间 */ totalShowTime: number; /** * 是否正在演出 */ isPlayingShow: boolean = false; /** * 播放 * @param id */ playMarkNode(id: number) { //通知前端 } /** * 每帧更新 */ onUpdateShow() { if (this.isPlayingShow) { if (this.currentShowTime > 0) { this.currentShowTime -= SceneManager.Instance.scene.deltaTime * 0.001; if (this.currentShowTime <= 0) { let l_currentMarkNodeData: MarkNodeData = this.currentMarkNodeInfo.nodeData; //播放下一个节点 let l_nextNode = this.getNextNode(l_currentMarkNodeData.id); } } } } //#endregion //#region 事件、回调类 //初始化pick事件 initPickEvent() { let instance = this; SceneManager.Instance.scene.onPointerObservable.add( instance.onPointerObservable ); } /** * 点击事件的监听 * @param eventData * @param eventState */ onPointerObservable(eventData: PointerInfo, eventState: EventState) { let instance = MarkWindow.instance; if (!instance.isShow || ModeManager.currentMode != ModeType.Edit) { //查看模式不能调整预案 return; } let pickMesh: AbstractMesh = null; let readyCreateMark = false;//准备创建标绘物 如果点在了标绘物上,就不创建(除了水带) let pickPos: Vector3 = null; switch (eventData.type) { case PointerEventTypes.POINTERUP: instance.isPickDown = false; if (eventData.event.button == 0) { //左键正常 if (eventData.pickInfo.hit && !SceneManager.s_isPointerDrag) { if (instance.currentMarkDataPrefab != null) { let worldPos = eventData.pickInfo.pickedPoint; if (instance.currentMarkDataPrefab.type == MarkType.JJX) { if (instance.markLineIsBreak > 0) { instance.markLineIsBreak = 0; return; } else { instance.markLineIsBreak = 1; } } else if (instance.currentMarkDataPrefab.type == MarkType.JGLX) { if (instance.mulArrowIsBreak_JG > 0) { return; } else { instance.mulArrowIsBreak_JG = 1; } } else if (instance.currentMarkDataPrefab.type == MarkType.CT) { if (instance.mulArrowIsBreak_CT > 0) { return; } else { instance.mulArrowIsBreak_CT = 1; } } else if (instance.currentMarkDataPrefab.type == MarkType.SYG) { if (instance.mulLineIsBreak_SYG > 0) { return; } else { instance.mulLineIsBreak_SYG = 1; } } readyCreateMark = true; pickPos = worldPos; pickMesh = eventData.pickInfo.pickedMesh; // return; } } // if (!SceneManager.s_isPointerDrag && !ToolbarWindow.instance.isMeshAdsorb) { // GizmoTool.onPickMeshInfoObservable.notifyObservers(null);//取消之前选择 // } } else { //右键取消 // instance.selectMarkDataFrom3d(instance.currentMarkInfo, false); //暂时没有右键取消选中实例的功能 if (!SceneManager.s_isPointerDrag) { instance.selectMarkDataPrefabFrom3d(instance.currentMarkDataPrefab, false) if (instance.currentMarkNodeInfo != null) { //取消选中 instance.selectMarkDataFrom3d(instance.currentMarkInfo, false); } } } break; case PointerEventTypes.POINTERDOWN: if (eventData.pickInfo.hit && !instance.isPickDown) { pickMesh = eventData.pickInfo.pickedMesh; instance.isPickDown = true; } break; case PointerEventTypes.POINTERPICK: if (eventData.pickInfo.hit) { pickMesh = eventData.pickInfo.pickedMesh; } break; case PointerEventTypes.POINTERDOUBLETAP: if (eventData.pickInfo.hit) { pickMesh = eventData.pickInfo.pickedMesh; } break; } if (pickMesh != null) { //是标绘物 let l_markInfo = instance.getMarkInfoFromMesh(eventData.pickInfo.pickedMesh); if (l_markInfo != null) { if (instance.currentMarkDataPrefab != null && instance.currentMarkDataPrefab.markKindType != MarkKindType.Effect && instance.currentMarkDataPrefab.type != MarkType.MHTK && instance.currentMarkDataPrefab.type != MarkType.SYG) //特效可以放在标绘物上 { readyCreateMark = false; } if (eventData.type == PointerEventTypes.POINTERDOUBLETAP) { //双击标绘物,打开任务界面 // console.log("打开属性面板"); instance.openProperty(l_markInfo); readyCreateMark = false; //双击,必然不创建标绘物 } else if (eventData.type == PointerEventTypes.POINTERDOWN) { if (eventData.event.button == 0)//左键 { if (!instance.isCreateMultiPointMark()) { // console.log("选中标绘物", l_markInfo); instance.selectMarkDataFrom3d(l_markInfo, true); } } } else if (eventData.type == PointerEventTypes.POINTERPICK) { if (eventData.event.button == 0)//左键 { if (!instance.isCreateMultiPointMark()) { //instance.selectMarkDataFrom3d(l_markInfo, true); } } else if (eventData.event.button == 1) {//中键 //聚焦 l_markInfo.lookAt(); } else { } } } else { // console.log("不是标绘物", pickMesh); } } //创建标绘物 if (readyCreateMark) { instance.createNewMark(pickPos, instance.currentMarkDataPrefab, true); } } /** * 从服务器获取到所有的标绘信息 * @param data */ onGetAllMarkPlanData(data: AllMarkPlanData) { this.allMarkPlanData = data; //DisposalPlanComponent.instance.allMarkPlanData = this.allMarkPlanData Event_GetAllMarkPlanData.dispatch(true, data); } /** * 初始化键盘输入 */ initKeyboardInput() { let instance = this; EventManager.addListener(Event_KeyboardInput, (eventData: Event_KeyboardInput) => { instance.onKeyboardInput(eventData); }) } /** * 接收到键盘事件 * @param eventData */ onKeyboardInput(eventData: Event_KeyboardInput) { if (eventData.data != null && eventData.data.key == "Delete") // 删除。 后期看是否加入 Backspace 退格 { this.deleteMarkInfo(this.currentMarkInfo); } } //#endregion //#region 查询类 //获取当前选中的建筑信息 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; } /** * 根据mesh,查找 * @param mesh */ getMarkInfoFromMesh(mesh: AbstractMesh) { if (mesh == null) { return null; } let result: ModelInfo_mark = null; if (this.currentMarkNodeInfo == null || this.currentMarkNodeInfo.markInfos == null) { return null; } this.currentMarkNodeInfo.markInfos.forEach((value: ModelInfo_mark[], key: MarkTagPos) => { for (let i = 0; i < value.length; i++) { if (mesh.uniqueId == value[i].modelBox.uniqueId) { result = value[i]; break; } let children = value[i].modelBox.getChildMeshes(); for (let j = 0; j < children.length; j++) { if (children != null) { if (mesh.uniqueId == children[j].uniqueId) { result = value[i]; break; } } } } }) return result; } /** * 获取当前方案下,下一个节点,null表示没有了 */ getNextNode(id: number) { let result: MarkNodeInfo = null; return result; } //#endregion //#region 修改类 /** * 创建一个游离的节点,用于没有选中已经创建的节点时,存放标绘信息 */ createLeaveNode() { let result = new MarkNodeData(0, this.c_leaveNodeName); return result; } /** * 保存当前节点的数据(主要是环境数据和相机数据) */ savCurrentNodeData(markNodeData: MarkNodeData = null, environId: number = null) { if (markNodeData == null) { if (this.currentMarkNodeInfo == null) { return; } else { markNodeData = this.currentMarkNodeInfo.nodeData; environId = markNodeData.getCurrentEnvironmentData().id; } } let environmentData: EnvironmentData = markNodeData.getEnvironmentData(environId) if (environmentData == null) { environmentData = markNodeData.addEnvironment(null, false, null); } if (StatusManager.s_currentStatus instanceof BuildingStatus) { environmentData.isOutdoor = true; } else { environmentData.isOutdoor = false; let indoorStatus = StatusManager.s_currentStatus as IndoorStatus; environmentData.buildingId = indoorStatus.buildingInfo.buildingData.normalData.key; environmentData.floorId = indoorStatus.indoorWindow.currentFloorUIItem.getIndoorKey(); } if (markNodeData.cameraData == null) { markNodeData.cameraData = new ArcRotateCameraData(); } markNodeData.cameraData.getDataFromCamera(SceneManager.Instance.defaultCamera); markNodeData.showZP = BuildingWindow.instance.currentZPShow; // console.log("记录节点", markNodeData); } /** * 创建新标记物 * @param pickedPoint * @param currentMarkInstanceData * @param isNew 新放置的 */ createNewMark(worldPosition: Vector3, currentMarkDataPrefab: MarkData, isNew: boolean) { if (this.currentMarkNodeInfo == null) { //现在,取消选中节点时会创建并选中一个游离节点,用于承接标绘物,以允许不选节点就标绘,所以此处应永远不会走进来 //ThreeDimensionalHomeComponent.instance.openSnackBar("请创建或选择方案的节点后,再进行标绘"); // alert("请创建或选择方案的节点后,再进行标绘"); return; } let markDataId = this.currentMarkNodeInfo.getNextMarkDataId(); let instance = this; //设置位置等 let newMarkInfo = this.createMark(markDataId, currentMarkDataPrefab, true, worldPosition, null, false, true, (modelInfo: ModelInfo_mark) => { instance.selectMarkDataFrom3d(modelInfo, true); }); return newMarkInfo; } //创建设备 createMark( markId: number,//用于新建 markData: MarkData,//新创建时,这是模板; 有数据是,即为元数据 isNew = false, //新创建、还是还原旧数据 position: Vector3,//新创建的位置 buildingInfo: BuildingInfo = null,//所属建筑 isLocalPos = false,//是否是局部坐标 select = false, onSuccess?: (modelInfo: ModelInfo_mark) => void ): ModelInfo_mark { let instance = this; if (buildingInfo == null) { buildingInfo = this.getCurrentBuildingInfo(); } let markInfo: ModelInfo_mark; let newMarkData: MarkData = null; if (isNew) { newMarkData = classToClass(markData); newMarkData.key = markId.toString(); newMarkData.belongtoBuildingId = buildingInfo.ModelInfo.key; newMarkData.transformData.position = position.clone(); } else { newMarkData = markData; } let startEnvironmentData = instance.currentMarkNodeInfo.nodeData.getCurrentEnvironmentData();//加载发起时的环境信息 let createTag = isNew ? LoadTool.c_tag_createMark : undefined; MeshPool.importMesh(ModelType.Mark, newMarkData, isNew, true, createTag, (box, meshes, meshPoolInfo: MeshPoolInfo) => { let currentEnvironmentData = instance.currentMarkNodeInfo.nodeData.getCurrentEnvironmentData();//加载发起时的环境信息 if (startEnvironmentData != currentEnvironmentData) { meshPoolInfo.dispose(); return; } markInfo = meshPoolInfo.modelInfo as ModelInfo_mark; markInfo.belongToBuilding = buildingInfo; instance.setMarkTransform(isLocalPos, isNew, buildingInfo, markInfo.modelBox, markInfo); // markInfo.modelBox.isPickable = true; //避免超大的透明选中区 // console.log("成功创建模型", markInfo); instance.currentMarkNodeInfo.addMarkInfo(markInfo, isNew); markInfo.onCreate(isNew); Event_MarkInfoChange.dispatch(MarkInfoChangeType.Create, markInfo); // console.log("测试播放动画", markInfo.animationGroups); // if (markInfo.animationGroups != null && markInfo.animationGroups.length > 0) { // markInfo.animationGroups[0].play();//完善正式逻辑时,注释掉此行 // } if (onSuccess) { onSuccess(markInfo); } }) return markInfo; } /** * 清空节点的运行时数据 * 清空标记物 */ clearNodeInfo() { if (this.currentMarkInfo != null) { this.selectMarkDataFrom3d(this.currentMarkInfo, false); } if (this.currentMarkNodeInfo != null) { this.currentMarkNodeInfo.disposeInfo(); this.currentMarkNodeInfo = null; } this.changeNatureEffect(false, null); this.shouWaterSource(false); //ThreeDimensionalHomeComponent.instance.toggleHeadwaters = false; } /** * 更新节点数据至表现层 * 摄像机、楼层、室内外的更新 * 标记物的重新创建 * @param readDescribe: 是否阅读介绍 */ updateNodeInfo(readDescribe = false) { let environmentData = this.currentMarkNodeInfo.nodeData.getCurrentEnvironmentData(); let cameraData = this.currentMarkNodeInfo.nodeData.cameraData; let showZP = this.currentMarkNodeInfo.nodeData.showZP; let instance = this; if (environmentData.isOutdoor) //要在室外 { if (StatusManager.s_currentStatus instanceof IndoorStatus) { //设置相机信息//相机位置设置问题 异步、动画冲突问题 MarkWindow.s_cameraData = cameraData; instance.clearEnterObserver(true); instance.enterOutDoorObserver = BuildingStatus.enterSuccessObservable.add((eventData: BuildingUIItem) => { //记录不分建筑,但初始化分建筑 //if (eventData.buildingInfo.buildingData.normalData.key == environmentData.buildingId) { instance.onEnterSuccess(eventData.buildingInfo, eventData.buildingInfo.buildingData.normalData.key); //} }) //切到室外 StatusManager.s_currentStatus.indoorWindow.onBtnToOutDoor(false); } else if (StatusManager.s_currentStatus instanceof BuildingStatus) { //this.currentMarkNodeInfo.nodeData.cameraData.setDataToCamera(SceneManager.Instance.defaultCamera); // let camera = SceneManager.Instance.defaultCamera; // if (cameraData != null) { // BabylonTool.AnimMoveCameraTargetAB(camera, 60, cameraData.target, cameraData.radius, cameraData.alpha, cameraData.beta); // } //仅此分支生效 //动画还原相机,结束后开始阅读 BuildingWindow.instance.revoverCamera(cameraData, showZP, (() => { if (readDescribe) { instance.readDescribe(instance.currentMarkNodeInfo.nodeData.describe); } })); instance.clearEnterObserver(true); let updateMark = false;//更新了标绘物 //为了复制功能,不再匹配key,而是在第一个主建筑进入时更新标绘物 for (let i = 0; i < StatusManager.s_currentStatus.buildingWindow.buildingUIItems.length; i++) { let buildingInfo = StatusManager.s_currentStatus.buildingWindow.buildingUIItems[i].buildingInfo if (!updateMark && buildingInfo.buildingData.buildingType == BuildingType.Normal) { updateMark = true; instance.onEnterSuccess(buildingInfo, buildingInfo.buildingData.normalData.key); } } } else { console.log("非法状态切换", StatusManager.s_currentStatus); return; } } else { //要在室内 if (StatusManager.s_currentStatus instanceof BuildingStatus) { //相机位置设置问题 异步、动画冲突问题 MarkWindow.s_cameraData = cameraData; //切到室内 let buildingUIItem: BuildingUIItem = StatusManager.s_currentStatus.buildingWindow.getBuildingUIItem(environmentData.buildingId); instance.clearEnterObserver(false); instance.enterIndoorObserver = IndoorStatus.enterSuccessObservable.add((eventData: IndoorFloorUIItem) => { if (eventData.getIndoorKey() == environmentData.floorId) { instance.onEnterSuccess(eventData.buildingInfo, eventData.buildingInfo.ModelInfo.key); } }) buildingUIItem.enterIndoor(environmentData.floorId, false); } else if (StatusManager.s_currentStatus instanceof IndoorStatus) { //相机位置设置问题 异步、动画冲突问题 MarkWindow.s_cameraData = cameraData; let buildingUIItem = StatusManager.getStatus(BuildingStatus).buildingWindow.getBuildingUIItem(environmentData.buildingId); instance.clearEnterObserver(false); instance.enterIndoorObserver = IndoorStatus.enterSuccessObservable.add((eventData: IndoorFloorUIItem) => { if (eventData.getIndoorKey() == environmentData.floorId) { instance.onEnterSuccess(eventData.buildingInfo, eventData.buildingInfo.ModelInfo.key); } }) buildingUIItem.enterIndoor(environmentData.floorId, false); } else { console.log("非法状态切换", StatusManager.s_currentStatus); return; } } this.changeNatureEffect(true, this.currentMarkNodeInfo.nodeData.natureData); } enterSuccessKey: Map = new Map(); /** * 进入建筑成功 * @param buildingInfo */ onEnterSuccess(buildingInfo: BuildingInfo, key: string) { if (!this.isShow) { return; } let instance = this; let environmentData = this.currentMarkNodeInfo.nodeData.getCurrentEnvironmentData(); if (instance.enterSuccessKey.has(key)) { return; } instance.enterSuccessKey.set(key, buildingInfo); for (let i = 0; i < environmentData.markDatas.length; i++) { let markData = environmentData.markDatas[i]; //if (markData.belongtoBuildingId == key) { //为了复制功能,不再匹配key this.createMark(0, markData, false, null, buildingInfo, true, null, (modelInfo: ModelInfo_mark) => { modelInfo.showFollowUI(instance.isShowProperty3d); }); //} } this.shouWaterSource(this.isShowWaterSource); } /** * 删除标记物 */ deleteMarkInfo(markInfo: ModelInfo_mark) { if (markInfo == null) { return; } else { if (markInfo == this.currentMarkInfo) { this.selectMarkDataFrom3d(markInfo, false); } this.currentMarkNodeInfo.removeMarkInfo(markInfo); } } //#endregion //#region 工具类 /** * 根据原数据,查找运行时数据 - 标记元素 * @param data */ getMarkInfoByMarkData(data: AllMarkPlanData) { } //设置设备transform信息 setMarkTransform(isLocalPos: boolean, isNew: boolean, buildingInfo: BuildingInfo, newMark: AbstractMesh, markInfo?: ModelInfo_mark) { //如果是局部坐标,要先设置父节点 if (isLocalPos) { buildingInfo.ModelInfo.steMarkParent(markInfo); } let markData = markInfo.markData; let halfY = newMark.scaling.y * 0.5; if (!isNew) { halfY = 0; } let originalScaling = markData.transformData.originalScaling.clone(); if (!originalScaling.equals(newMark.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 = markData.transformData.scaling.divide(markData.transformData.originalScaling); markData.transformData.originalScaling = newMark.absoluteScaling.clone(); markData.transformData.scaling = markData.transformData.originalScaling.multiply(scaleSize); } newMark.position = markData.transformData.position.add( new Vector3(0, halfY, 0) ); newMark.scaling = markData.transformData.scaling; newMark.rotation = markData.transformData.rotation; if (markData.transformData.rotationQuaternion != null) { newMark.rotationQuaternion = markData.transformData.rotationQuaternion; } //如果是世界坐标,则最后设置父节点 if (!isLocalPos) { buildingInfo.ModelInfo.steMarkParent(markInfo); } markData.transformData.position = newMark.position; } /** * 清空进入场景的监听者 * @param outDoor */ clearEnterObserver(outDoor: boolean) { this.enterSuccessKey.clear(); if (outDoor) { if (this.enterOutDoorObserver != null) { BuildingStatus.enterSuccessObservable.remove(this.enterOutDoorObserver); this.enterOutDoorObserver = null; } } else { if (this.enterIndoorObserver != null) { IndoorStatus.enterSuccessObservable.remove(this.enterIndoorObserver); this.enterIndoorObserver = null; } } } /** * 正在创建多点的标绘物 */ isCreateMultiPointMark() { return !(this.markLineIsBreak < 0 && this.mulArrowIsBreak_JG < 0 && this.mulArrowIsBreak_CT) } /** * 当选中预设时,设置多点创建物的状态 * @param select */ setMultiPointOnSelectPrefab(select: boolean, data: MarkData) { if (select == false) { return; } if (data.type == MarkType.JJX) { this.markLineIsBreak = 0; } else { this.markLineIsBreak = -1; } if (data.type == MarkType.JGLX) { this.mulArrowIsBreak_JG = 0; } else { this.mulArrowIsBreak_JG = -1; } if (data.type == MarkType.CT) { this.mulArrowIsBreak_CT = 0; } else { this.mulArrowIsBreak_CT = -1 } } /** * 查找建筑内所有水源 * @param buildingInfo */ getAllWaterSource(buildingInfo: ModelInfo_building) { let result = []; for (let i = 0; i < buildingInfo.facilityInfos.length; i++) { let item = buildingInfo.facilityInfos[i]; if (this.isWaterSouce(item.type)) { result = result.concat(item.facilityInfo); } } return result; } /** * 是水源类型 * @param type */ isWaterSouce(type: FacilityType) { let result = false; return result; } /** * 改变自然效果 * @param show * @param natureData */ changeNatureEffect(show: boolean, natureData: NatureData) { if (show) { this.weatherTool.changeWeatherEffect(natureData.weather); this.weatherTool.changeWindDirection(natureData.windDirection); this.weatherTool.changeWindPower(natureData.windPower); } else { this.weatherTool.show(show); } } /** * 预加载模型 */ preLoadMesh() { if (MarkWindow.s_preLoadMesh) { for (let i = 0; i < DataManager.allMarkData.marks_Disaster.length; i++) { MeshPool.importMesh(ModelType.Mark, DataManager.allMarkData.marks_Disaster[i], true, false, LoadTool.c_tag_preloadMark, (meshBox: AbstractMesh, meshes: AbstractMesh[], result: MeshPoolInfo) => { MeshPool.disposeMesh(result); }); } for (let i = 0; i < DataManager.allMarkData.marks_Outside.length; i++) { MeshPool.importMesh(ModelType.Mark, DataManager.allMarkData.marks_Outside[i], true, false, LoadTool.c_tag_preloadMark, (meshBox: AbstractMesh, meshes: AbstractMesh[], result: MeshPoolInfo) => { MeshPool.disposeMesh(result); }); } for (let i = 0; i < DataManager.allMarkData.marks_Inside.length; i++) { MeshPool.importMesh(ModelType.Mark, DataManager.allMarkData.marks_Inside[i], true, false, LoadTool.c_tag_preloadMark, (meshBox: AbstractMesh, meshes: AbstractMesh[], result: MeshPoolInfo) => { MeshPool.disposeMesh(result); }); } for (let i = 0; i < DataManager.allMarkData.marks_Other.length; i++) { MeshPool.importMesh(ModelType.Mark, DataManager.allMarkData.marks_Other[i], true, false, LoadTool.c_tag_preloadMark, (meshBox: AbstractMesh, meshes: AbstractMesh[], result: MeshPoolInfo) => { MeshPool.disposeMesh(result); }); } } } /** * 预加载一个标绘物 * @param data */ preLoadOneMesh(data: MarkData) { if (!MarkWindow.s_preLoadMesh && MeshPool.Instance.getMeshPrefab(data.resPath, data.resName) == null) { MeshPool.importMesh(ModelType.Mark, data, true, true, LoadTool.c_tag_preloadMark, (meshBox: AbstractMesh, meshes: AbstractMesh[], result: MeshPoolInfo) => { MeshPool.disposeMesh(result); }, true); } } /** * 朗读描述 * @param describe */ readDescribe(describe: string) { if (describe != null) { SpeakingTool.Instance.clear(); SpeakingTool.Instance.speak(describe); } } //#endregion //#region 应急模板 /** * 所有应急模板 */ allSandBoxTemplate: MarkTemplate[]; /** * 获取所有沙盒模板 */ getAllSandBoxTemplate() { let instance = this; this.allSandBoxTemplate = []; ServeManager.instance.getAllMarkTemplate((data: any) => { if (data == null) { instance.allSandBoxTemplate = []; } else { // console.log("getAllSandBoxTemplate", data); instance.allSandBoxTemplate = data; } }); } /** * 根据模板创建一个应急预案 * @param id */ addMarkPlanByTemplate(id: number) { let instance = this; ServeManager.instance.getOneMarkTemplate(id, (data: any) => { let value = plainToClass(MarkPlanData, data); instance.allMarkPlanData.createPlanDataByTemplate(value); instance.saveAllMarkPlanData(); }) } /** * 保存为模板 * @param id * @param name * @param data */ saveToSandBoxTemplate(data: MarkPlanData) { let name: string = data.name; let id: number = Math.ceil(new Date().getTime() * 0.001); let instance = this; ServeManager.instance.saveOneMarkTemplate(id, name, data, (data: string) => { instance.getAllSandBoxTemplate(); }); } /** * 删除模板 * @param id */ deleteSandBoxTemplate(id: number) { let instance = this; ServeManager.instance.deleteSandBoxTemplate(id, () => { instance.getAllSandBoxTemplate(); }); } //#endregion }