import { EventManager } from "@angular/platform-browser"; import { AbstractMesh, Color3, EventState, Mesh, PickingInfo, PointerEventTypes, PointerInfo, Ray, RayHelper, Vector3 } from "@babylonjs/core"; import { classToClass } from "class-transformer"; import { PlanComponent } from "src/app/pages/plan/plan.component"; import { ModelChangeType } from "../../controller/data-manager"; import { Event_KeyboardInput } from "../../controller/event-manager/events/event-keyboard-input"; import { Event_ModelInfoChange } from "../../controller/event-manager/events/event-modelinfo-change"; 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 { Game } from "../../game"; import { JYZInfoMoudleType } from "../../model/data/institution/jyz-show-data"; import { ModelData_facility, FacilityType } from "../../model/data/model-data/model-data-facility"; import { BuildingInfo } from "../../model/info/building/building-info"; import { ModelInfo } from "../../model/info/model/model-info"; import { ModelInfo_facility, FacilityInfoByType } from "../../model/info/model/model-info-facility"; import { GizmoTool } from "../../tool/gizmo-tool"; import { TsTool } from "../../tool/ts-tool"; import { BuildingWindow } from "../building-window/building-window"; import { FacilityWindow } from "../facility-window/facility-window"; import { UIBase } from "../window-base/ui-base"; import { FacilityInfoUIItem } from "./facilityinfo-ui-item"; //所有放在场景中的设备 信息界面 export class FacilityInfoInSceneWindow extends UIBase { static instance: FacilityInfoInSceneWindow; three: PlanComponent;//前端组件 // scrollView: ScrollViewer; // content: StackPanel; /** * 当前选中的所有设备UI */ currentFacility: FacilityInfoUIItem[] = []; /** * 当前显示的所有设备UI */ facilityInfoUIItemes: FacilityInfoUIItem[] = []; copyFacilityInfo: CopyFacilityInfo = new CopyFacilityInfo(); isMultiselect: boolean = false;//多选状态 //#region 前端对接 /** * 更新UI显示 */ updateUI() { //this.three.getAllCensusList(this.facilityInfoUIItemes || []); } /** * 改变多选状态 * @param isMultiselect true表示多选。 默认是false */ changeMultiSelect(isMultiselect: boolean) { this.isMultiselect = isMultiselect; } /** * 复制选中的设备 */ copyFacility() { this.copyFacilityInfo.facilityData = []; for (let i = 0; i < this.currentFacility.length; i++) { let data = classToClass(this.currentFacility[i].modelInfo.modelData); this.copyFacilityInfo.facilityData.push(data as ModelData_facility); } if (StatusManager.s_currentStatus instanceof IndoorStatus) { this.copyFacilityInfo.outDoor = false; this.copyFacilityInfo.buildingKey = StatusManager.s_currentStatus.indoorWindow.currentFloorUIItem.getIndoorKey(); } else if (StatusManager.s_currentStatus instanceof BuildingStatus) { this.copyFacilityInfo.outDoor = true; this.copyFacilityInfo.buildingKey = StatusManager.s_currentStatus.currentBuildingInfo.buildingData.normalData.key; } return this.copyFacilityInfo; } /** * 单选设备 * @param facilityInfoUIItem null表示取消选中 */ selectFacilityItem(facilityInfoUIItem: FacilityInfoUIItem) { if (facilityInfoUIItem == null)//取消选中 { if (this.currentFacility != null) { for (let i = 0; i < this.currentFacility.length; i++) { this.currentFacility[i].onSelect(false); } this.currentFacility = []; } } else { if (this.currentFacility != null) { for (let i = 0; i < this.currentFacility.length; i++) { this.currentFacility[i].onSelect(false); } this.currentFacility = []; this.currentFacility.push(facilityInfoUIItem); facilityInfoUIItem.onSelect(true); } } } /** * 多选设备 * @param items * @param select true表示选中,false表示取消选中 */ multiSelectFacilityItem(items: FacilityInfoUIItem[], select: boolean) { if (items == null) { return; } for (let i = 0; i < items.length; i++) { if (select) { items[i].onSelect(true); let isRepet = false;//重复的 for (let j = 0; j < this.currentFacility.length; j++) { if (this.currentFacility[j] == items[i]) { isRepet = true; break; } } if (!isRepet) { this.currentFacility.push(items[i]); // console.log("添加进选中"); } } else { items[i].onSelect(false); TsTool.arrayRemove(this.currentFacility, items[i]) // console.log("取消选中", items[i].getID(), this.currentFacility); } } } //选中,通知前端 selectFacilityItemToThree(facilityInfoUIItem: FacilityInfoUIItem[], isChecked?: boolean) { this.three = PlanComponent.instance; if (this.isMultiselect) { // 多选 if (isChecked) { //选中 } else { //取消选中 } } else { // 单选 if (isChecked) { //选中 this.three.beforeOnefacilityInfo = facilityInfoUIItem[0].getID(); this.three.getPropertyData(facilityInfoUIItem[0]) } else { //取消选中 // this.three.isShowRightNature = false this.three.beforeOnefacilityInfo = null } } } /** * 显示某种type的消防设备,null表示全都 * @param facilityType */ showFacilityByType(facilityType: FacilityType, show: boolean) { if (ModeManager.currentMode == ModeType.Look) { for (let i = 0; i < this.facilityInfoUIItemes.length; i++) { let l_facilityData = (this.facilityInfoUIItemes[i].modelInfo.modelData) as ModelData_facility; if (facilityType == null || facilityType == l_facilityData.facilityType) { this.facilityInfoUIItemes[i].modelInfo.setEnable(show); } else if (show) { this.facilityInfoUIItemes[i].modelInfo.setEnable(false); } } // for (let i = 0; i < this.facilityInfoUIItemes.length; i++) { // let l_facilityData = (this.facilityInfoUIItemes[i].modelInfo.modelData) as ModelData_facility; // if (facilityType == null || facilityType == l_facilityData.facilityType) { // this.facilityInfoUIItemes[i].modelInfo.setIconEnable(show); // } // } } else { for (let i = 0; i < this.facilityInfoUIItemes.length; i++) { let l_facilityData = (this.facilityInfoUIItemes[i].modelInfo.modelData) as ModelData_facility; if (facilityType == null || facilityType == l_facilityData.facilityType) { this.facilityInfoUIItemes[i].modelInfo.setIconEnable(show); } } } } /** * 根据类型获取设备在UI中的显示状态 * @param facilityType */ getFacilityUIShowType(facilityType: FacilityType): boolean { // for (let i = 0; i < this.three.allFacilityInfoUIItemes.length; i++) { // let item = this.three.allFacilityInfoUIItemes[i]; // if (item.type == facilityType) { // return item.isShow; // } // } return true; } /** * 删除某一类设备 * @param facilityType */ deleteFacilityByType(facilityType: FacilityType) { let needDelete: FacilityInfoUIItem[] = []; for (let i = 0; i < this.facilityInfoUIItemes.length; i++) { if ((this.facilityInfoUIItemes[i].modelInfo.modelData as ModelData_facility).facilityType == facilityType) { needDelete.push(this.facilityInfoUIItemes[i]); } } for (let i = 0; i < needDelete.length; i++) { needDelete[i].askDelete(false);//不再单独询问 } } //#endregion //#region 生命周期 onInit() { super.onInit(); FacilityInfoInSceneWindow.instance = this; // this.three = ThreeDimensionalHomeComponent.instance; // EventManager.addListener(Event_ModelInfoChange, this.onModelInfoChange); GizmoTool.onPickMeshInfoObservable.add(this.onClickModel); this.currentFacility = []; this.initKeyboardInput(); this.initDragInput(); this.initPickEvent(); } onClose() { super.onClose(); //EventManager.removeCallback(Event_ModelInfoChange, this.onModelInfoChange); GizmoTool.onPickMeshInfoObservable.removeCallback(this.onClickModel); } //#endregion //#region 键盘输入 /** * 初始化键盘输入 */ initKeyboardInput() { let instance = this; // EventManager.addListener(Event_KeyboardInput, (eventData: Event_KeyboardInput) => { // instance.onKeyboardInput(eventData); // }) } /** * 接收到键盘事件 * @param eventData */ onKeyboardInput(eventData: Event_KeyboardInput) { if (eventData.data.key == "Delete") // 删除。 后期看是否加入 Backspace 退格 { } else if (eventData.data.key == "X") //室内消火栓吸附墙 { // 没做完,先搁置 // let testNum = 5;//检测次数 // let distance = 1;//检测距离 // if (this.currentFacility != null) { // for (let i = 0; i < this.currentFacility.length; i++) { // let l_facility = this.currentFacility[i]; // if (l_facility.modelInfo.modelBox == null) { // continue; // } // if (l_facility.getType() == FacilityType.SNXHS) //室内消火栓 // { // let start = l_facility.modelInfo.modelBox.absolutePosition.clone(); // for (let x = -1; i < 2; i += 2) //x取1或-1 // { // for (let z = -testNum; z < testNum; z++) { // let dir = new Vector3(x, 0, z); // let ray = new Ray(start, dir, distance); // let rayHelper = new RayHelper(ray);//射线辅助器 // rayHelper.show(SceneManager.Instance.scene);//debug射线,用于调试 // let pickingInfo = SceneManager.Instance.scene.pickWithRay(ray, (mesh: AbstractMesh) => { // if (TsTool.stringContain(mesh.name, "SNXHS")) { // return false; // } // else { // return true; // } // }); // let normal = pickingInfo.getNormal(true); // console.log(pickingInfo); // } // } // } // } // } } } //#endregion //#region gizmo拖拽输入 /** * gizmo拖拽输入 */ isGizmoDrag_pos: boolean = false; lastGizmoMesh_Pos: Vector3 = Vector3.Zero(); /** * 初始化拖拽输入 * 当多选时,移动一个要同时移动其他设备 */ initDragInput() { let instance = this; GizmoTool.s_gizmoManager.gizmos.positionGizmo.onDragStartObservable.add((eventData) => { instance.isGizmoDrag_pos = true; instance.saveLastGizmoMeshInfo(); }); GizmoTool.s_gizmoManager.gizmos.positionGizmo.onDragEndObservable.add((eventData) => { instance.isGizmoDrag_pos = false; }); Game.instance.scene.onBeforeRenderObservable.add(() => { if (!instance.isGizmoDrag_pos) { return; } if (instance.isDragFacility()) { let offset = GizmoTool.s_nowPickAim.modelBox.position.subtract(instance.lastGizmoMesh_Pos); for (let i = 0; i < instance.currentFacility.length; i++) { if (instance.currentFacility[i].modelInfo != (GizmoTool.s_nowPickAim as ModelInfo_facility)) { // instance.currentFacility[i].modelInfo.modelData.transformData.position.x += offset.x; // instance.currentFacility[i].modelInfo.modelData.transformData.position.y += offset.y; // instance.currentFacility[i].modelInfo.modelData.transformData.position.z += offset.z; instance.currentFacility[i].modelInfo.modelBox.position.x += offset.x; instance.currentFacility[i].modelInfo.modelBox.position.y += offset.y; instance.currentFacility[i].modelInfo.modelBox.position.z += offset.z; } else { //console.log("移动的本体", i); } } instance.saveLastGizmoMeshInfo(); } }) } /** * 保存上一帧的数据 * @param facilityInfoInSceneWindow */ saveLastGizmoMeshInfo() { if (GizmoTool.s_nowPickAim != null && GizmoTool.s_nowPickAim instanceof ModelInfo_facility) { this.lastGizmoMesh_Pos = GizmoTool.s_nowPickAim.modelBox.position.clone(); } } /** * 是否拖拽选中的设备 */ isDragFacility() { if (this.currentFacility == null || this.currentFacility.length < 2) { return false; } if (GizmoTool.s_nowPickAim != null && GizmoTool.s_nowPickAim instanceof ModelInfo_facility) { for (let i = 0; i < this.currentFacility.length; i++) { if (this.currentFacility[i].modelInfo == GizmoTool.s_nowPickAim) { return true; } } return false; } else { return false; } } //#endregion //#region 鼠标输入 //初始化pick事件 initPickEvent() { SceneManager.Instance.scene.onPointerObservable.add( this.onPointerObservable ); } //鼠标交互监听 onPointerObservable(eventData: PointerInfo, eventState: EventState) { let instance = FacilityInfoInSceneWindow.instance; switch (eventData.type) { case PointerEventTypes.POINTERUP: if (eventData.event.button == 0) { //左键正常 if (eventData.pickInfo.hit && !SceneManager.s_isPointerDrag) { instance.selectJYJFrom3D(eventData.pickInfo); } } else { //右键 } break; case PointerEventTypes.POINTERPICK: // console.log(eventData.event); break; } } /** * 选中加油机时,高亮颜色 */ static readonly c_selectJYJColor = Color3.Green(); /** * 当前选中的加油机 */ currentSelectJYJInfo: ModelInfo_facility; /** * 三维中通过点击模型获取加油机(或油罐) * @param pickInfo null 表示取消选中 */ selectJYJFrom3D(pickInfo: PickingInfo) { if (this.currentSelectJYJInfo != null) { this.playJYJSelectEffect(false, this.currentSelectJYJInfo); this.currentSelectJYJInfo = null; } if (pickInfo == null) { return; } let allJYJInfo: ModelInfo_facility[] = []; try { let facilityInfosByType = BuildingWindow.instance.currentBuidngItem.buildingInfo.ModelInfo.facilityInfos; let currentMoudle = BuildingWindow.instance.currentJYZInfoMoudleType; for (let i = 0; i < facilityInfosByType.length; i++) { if ((currentMoudle == null || currentMoudle == JYZInfoMoudleType.JYJ) && facilityInfosByType[i].type == FacilityType.JY_JYJ || (currentMoudle == null || currentMoudle == JYZInfoMoudleType.YG) && facilityInfosByType[i].type == FacilityType.JY_YG) { allJYJInfo = allJYJInfo.concat(facilityInfosByType[i].facilityInfo); } } } catch (error) { console.log("点击没找到", error); } let result: ModelInfo_facility = null; for (let i = 0; i < allJYJInfo.length; i++) { let childMesh = allJYJInfo[i].models; childMesh.push(allJYJInfo[i].modelBox); for (let j = 0; j < childMesh.length; j++) { if (pickInfo.pickedMesh == childMesh[j]) { result = allJYJInfo[i]; console.log("通过点击,找到加油机了"); break; } } } if (result != null) { this.playJYJSelectEffect(true, result); let facilityItem: FacilityInfoUIItem = FacilityInfoInSceneWindow.instance.getFacilityItem(result); console.log("场景中选中设备", facilityItem); //通知前端 FacilityInfoInSceneWindow.instance.selectFacilityItemToThree([facilityItem], true); } } /** * 展示加油机(或油罐)选中的效果 * @param play false,表示还原 */ playJYJSelectEffect(play: boolean, facilityInfo: ModelInfo_facility) { if (play) { let facilityData = facilityInfo.modelData as ModelData_facility; if (facilityData.facilityType != FacilityType.JY_JYJ && facilityData.facilityType != FacilityType.JY_YG) { //只有加油机和油罐有高亮显示 return; } } if (play) { this.currentSelectJYJInfo = facilityInfo; //正在展示加油机或油罐 if (BuildingWindow.instance.currentJYZInfoMoudleType == JYZInfoMoudleType.JYJ || BuildingWindow.instance.currentJYZInfoMoudleType == JYZInfoMoudleType.YG) { SceneManager.Instance.removeFromHighLight(facilityInfo.modelBox as Mesh); } SceneManager.Instance.addToHighLight(facilityInfo.modelBox as Mesh, FacilityInfoInSceneWindow.c_selectJYJColor); } else { SceneManager.Instance.removeFromHighLight(facilityInfo.modelBox as Mesh); //正在展示加油机或油罐 if (BuildingWindow.instance.currentJYZInfoMoudleType == JYZInfoMoudleType.JYJ || BuildingWindow.instance.currentJYZInfoMoudleType == JYZInfoMoudleType.YG) { SceneManager.Instance.addToHighLight(facilityInfo.modelBox as Mesh, ModelInfo_facility.c_hightLightColor); } } } //#endregion //创建所有设备UI createAllFacilities(facilityByType: FacilityInfoByType[]) { this.clearFacilityInfoUIItemes(); for (let i = 0; i < facilityByType.length; i++) { for (let j = 0; j < facilityByType[i].facilityInfo.length; j++) { this.addFacilityItem(facilityByType[i].facilityInfo[j]); } } //通知ui更新 //this.three.getAllCensusList(this.facilityInfoUIItemes || []); } //清空设备UI item clearFacilityInfoUIItemes() { this.facilityInfoUIItemes.length = 0; this.currentFacility = []; //this.three.getAllCensusList(this.facilityInfoUIItemes || []); } //模型变化 onModelInfoChange(modelInfoChange: Event_ModelInfoChange) { let instance: FacilityInfoInSceneWindow = FacilityInfoInSceneWindow.instance; if (modelInfoChange.modeleInfo instanceof ModelInfo_facility) { if (instance.isCurrentBuildingOrIndoor(modelInfoChange.modeleInfo.belongToBuilding)) {//严格隶属当前选中的建筑 if (modelInfoChange.modelChangeType == ModelChangeType.Add) { instance.addFacilityItem(modelInfoChange.modeleInfo); //console.log("此建筑中添加", modelInfoChange.modeleInfo); } else if (modelInfoChange.modelChangeType == ModelChangeType.Remove) { instance.removeFacilityItem(modelInfoChange.modeleInfo); //console.log("此建筑中移除", modelInfoChange.modeleInfo); } } else { // console.log("不是此建筑"); } // instance.three = ThreeDimensionalHomeComponent.instance; //instance.three.getAllCensusList(instance.facilityInfoUIItemes || []); } else { // 无设备 时 // instance.three = ThreeDimensionalHomeComponent.instance; //instance.three.getAllCensusList(instance.facilityInfoUIItemes || []); } } //添加一个设备到UI addFacilityItem(facilityInfo: ModelInfo_facility) { let facilityInfoUIItem = new FacilityInfoUIItem(facilityInfo, this); this.facilityInfoUIItemes.push(facilityInfoUIItem); if (facilityInfo.isNew) { if (this.isMultiselect) { this.multiSelectFacilityItem([facilityInfoUIItem], true); } else { this.selectFacilityItem(facilityInfoUIItem); } // facilityInfo.setSelectEnable(true); // this.selectFacilityItemToThree(facilityInfoUIItem); } //this.onClickModel(facilityInfoUIItem); } //移除设备Item removeFacilityItem(facilityInfo: ModelInfo_facility) { let value = this.getFacilityItem(facilityInfo); TsTool.arrayRemove(this.currentFacility, value); if (value != null) { value.dispose(); } } //获取item getFacilityItem(facilityInfo: ModelInfo_facility): FacilityInfoUIItem { let result: FacilityInfoUIItem; if (this.facilityInfoUIItemes == undefined && this.facilityInfoUIItemes == null) { result = null; } else { for (let i = 0; i < this.facilityInfoUIItemes.length; i++) { if (this.facilityInfoUIItemes[i].modelInfo == facilityInfo) { result = this.facilityInfoUIItemes[i]; break; } } } return result; } //根据info找到相应的item,然后模拟选中 selectFacilityInfo(facilityInfo: ModelInfo_facility) { let item: FacilityInfoUIItem = null; for (let i = 0; i < this.facilityInfoUIItemes.length; i++) { if (this.facilityInfoUIItemes[i].modelInfo == facilityInfo) { item = this.facilityInfoUIItemes[i]; break; } } if (item == null) { item = new FacilityInfoUIItem(facilityInfo, this); } if (this.isMultiselect) { this.multiSelectFacilityItem([item], !item.isSelect); } else { // if (item.isSelect) { // //this.selectFacilityItem(null);//取消选中 // } // else { this.selectFacilityItem(item); // } } } //当点击了模型 onClickModel(model: ModelInfo | FacilityInfoUIItem) { } /** * 设备是否属于当前选中的建筑 * @param belongToBuilding */ isCurrentBuildingOrIndoor(belongToBuilding: BuildingInfo) { if (StatusManager.s_currentStatus instanceof BuildingStatus) { let buildingWindow = StatusManager.getStatus(BuildingStatus).buildingWindow; return (buildingWindow != null && buildingWindow.currentBuidngItem != null && buildingWindow.currentBuidngItem.buildingInfo == belongToBuilding) } else if (StatusManager.s_currentStatus instanceof IndoorStatus) { let indoorKey = StatusManager.getStatus(IndoorStatus).indoorWindow.currentFloorUIItem.getIndoorKey(); return belongToBuilding.ModelInfo.key == indoorKey; } } /** * 取消选中当前选中的所有设备 * @param select */ cancleAllCurrectFacilityItem() { if (this.currentFacility == null) { return; } this.selectFacilityItemToThree(this.currentFacility, false); for (let i = 0; i < this.currentFacility.length; i++) { this.currentFacility[i].onSelect(false); } this.currentFacility = []; } } /** * 复制的设备信息 */ export class CopyFacilityInfo { outDoor: boolean;//室外 buildingKey: String; facilityData: ModelData_facility[]; }