183 changed files with 52500 additions and 896 deletions
@ -0,0 +1,232 @@
|
||||
import { MarkKindType, MarkType, MarkTagPos } from "../model/data/mark/mark-data"; |
||||
import { FacilityPosType, FacilityType } from "../model/data/model-data/model-data-facility"; |
||||
|
||||
//配置、常量管理器
|
||||
export class ConfigManager { |
||||
static readonly c_resPath_assetsRoot = 'assets/'; //资源根目录
|
||||
|
||||
static readonly c_resPath_institutionsRoot = 'institutions/'; //单位
|
||||
static readonly c_reaPath_facilityProperty = "facilityProperty";//设备属性资源(一般是图片)
|
||||
static readonly c_resPath_facilitiesRoot = 'facilities/'; //设备资源
|
||||
static readonly c_resPath_facilityIcon = "images/facility/";// 设备icon
|
||||
|
||||
|
||||
static readonly c_size_facilityIconSize = 40;//设备icon的大小
|
||||
|
||||
static readonly c_time_longPress = 500;//长按时间(毫秒)
|
||||
|
||||
|
||||
/** |
||||
* 获取设备icon的url |
||||
* @param type 设备的类型 |
||||
* @param pos 设备的位置(室内还是室外) |
||||
*/ |
||||
static getFacilityIconUrl(type: FacilityType, pos: FacilityPosType): string { |
||||
|
||||
let result = ConfigManager.c_resPath_assetsRoot + "images/facility/" + pos + "/" + type + ".png"; |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 根据设备类型获取名称 |
||||
* @param type 设备类型 |
||||
*/ |
||||
static getFacilityTypeName(type: FacilityType): string { |
||||
let result = "未知"; |
||||
switch (type) { |
||||
case FacilityType.AQCK: result = "安全出口"; break; |
||||
case FacilityType.DSXHS: result = "地上消火栓"; break; |
||||
case FacilityType.DXXHS: result = "地下消火栓"; break; |
||||
case FacilityType.SZDSXHS: result = "市政地上消火栓"; break; |
||||
case FacilityType.SZDXXHS: result = "市政地下消火栓"; break; |
||||
case FacilityType.DSSBJHQ: result = "地上水泵接合器"; break; |
||||
case FacilityType.DXSBJHQ: result = "地下水泵接合器"; break; |
||||
case FacilityType.QBSBJHQ: result = "墙壁式接合器"; break; |
||||
case FacilityType.DGNSBJHQ: result = "多功能接合器"; break; |
||||
case FacilityType.GD: result = "高度"; break; |
||||
case FacilityType.PL: result = "毗邻"; break; |
||||
case FacilityType.JTQ: result = "禁停区"; break; |
||||
case FacilityType.JJQ: result = "集结区"; break; |
||||
case FacilityType.TPBZ: result = "图片标注"; break; |
||||
|
||||
case FacilityType.XKS: result = "消控室"; break; |
||||
case FacilityType.BF: result = "泵房"; break; |
||||
case FacilityType.SX: result = "水箱"; break; |
||||
case FacilityType.LSXFB: result = "立式消防泵"; break; |
||||
case FacilityType.WSXFB: result = "卧式消防泵"; break; |
||||
case FacilityType.CYXFB: result = "柴油消防泵"; break; |
||||
case FacilityType.FHFQ: result = "防火分区"; break; |
||||
case FacilityType.SNXHS: result = "室内消火栓"; break; |
||||
case FacilityType.FHM: result = "防火门"; break; |
||||
case FacilityType.FHJL: result = "防火卷帘"; break; |
||||
case FacilityType.SSLT: result = "疏散楼梯"; break; |
||||
case FacilityType.XFDT: result = "消防电梯"; break; |
||||
case FacilityType.PTDT: result = "普通电梯"; break; |
||||
case FacilityType.WXY: result = "危险源"; break; |
||||
case FacilityType.ZDQY: result = "重点区域"; break; |
||||
case FacilityType.DWBZ: result = "点位标注"; break; |
||||
case FacilityType.HT: result = "货梯"; break; |
||||
|
||||
case FacilityType.BNC: result = "避难层"; break;//特殊
|
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 查询某设备所处位置类型(室内还是室外) |
||||
* @param facilityType
|
||||
*/ |
||||
static getPosType(facilityType: FacilityType): FacilityPosType { |
||||
let result = FacilityPosType.Indoor; |
||||
|
||||
switch (facilityType) { |
||||
case FacilityType.AQCK: |
||||
case FacilityType.DSXHS: |
||||
case FacilityType.DXXHS: |
||||
case FacilityType.SZDXXHS: |
||||
case FacilityType.SZDSXHS: |
||||
case FacilityType.DSSBJHQ: |
||||
case FacilityType.DXSBJHQ: |
||||
case FacilityType.QBSBJHQ: |
||||
case FacilityType.DGNSBJHQ: |
||||
case FacilityType.GD: |
||||
case FacilityType.PL: |
||||
case FacilityType.JTQ: |
||||
case FacilityType.JJQ: |
||||
case FacilityType.TPBZ: result = FacilityPosType.Outdoor; break; |
||||
case FacilityType.DWBZ: |
||||
case FacilityType.ZDQY: |
||||
case FacilityType.WXY: result = FacilityPosType.Public; break; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
|
||||
//#region 事态标绘
|
||||
|
||||
/** |
||||
* 事态标绘的名称配置 |
||||
*/ |
||||
static s_markName = new Map<MarkType, string>([ |
||||
[MarkType.SYA, "伤员"], |
||||
[MarkType.SYB, "伤员"], |
||||
[MarkType.SYC, "伤员"], |
||||
[MarkType.SYD, "伤员"], |
||||
[MarkType.ZQR, "知情人"], |
||||
[MarkType.WXP, "危险品"], |
||||
[MarkType.ZWD, "杂物堆"], |
||||
[MarkType.PCD, "破拆点"], |
||||
[MarkType.H, "火"], |
||||
[MarkType.TPH, "突破火"], |
||||
[MarkType.SNH, "室内火"], |
||||
[MarkType.YWA, "烟雾"], |
||||
[MarkType.YWB, "烟雾"], |
||||
[MarkType.YWC, "烟雾"], |
||||
[MarkType.MHF, "灭火服"], |
||||
[MarkType.JYF, "救援服"], |
||||
[MarkType.GRF, "隔热服"], |
||||
[MarkType.FHF, "防化服"], |
||||
[MarkType.BHF, "避火服"], |
||||
[MarkType.YWXFY, "义务消防员"], |
||||
[MarkType.AQS, "安全哨"], |
||||
[MarkType.MTC, "摩托车"], |
||||
[MarkType.XLC, "巡逻车"], |
||||
[MarkType.SGC, "水罐车"], |
||||
[MarkType.PMC, "泡沫车"], |
||||
[MarkType.GPC, "高喷车"], |
||||
[MarkType.DGPTC, "登高平台车"], |
||||
[MarkType.YTC, "云梯车"], |
||||
[MarkType.QXJYC, "抢险救援车"], |
||||
[MarkType.QCC, "器材车"], |
||||
[MarkType.ZMC, "照明车"], |
||||
[MarkType.PCC, "破拆车"], |
||||
[MarkType.PYC, "排烟车"], |
||||
[MarkType.ZHC, "指挥车"], |
||||
[MarkType.GCGSC, "高层供水车"], |
||||
[MarkType.KQHXCQC, "空气呼吸充气车"], |
||||
[MarkType.GA, "公安"], |
||||
[MarkType.JJ, "交警"], |
||||
[MarkType.YS, "医生"], |
||||
[MarkType.QXRY, "抢修人员"], |
||||
[MarkType.JHC, "救护车"], |
||||
[MarkType.JC, "警车"], |
||||
[MarkType.DLQXC, "电力抢修车"], |
||||
[MarkType.RQQXC, "燃气抢修车"], |
||||
[MarkType.GSQXC, "供水抢修车"], |
||||
[MarkType.HBJCC, "环保检测车"], |
||||
[MarkType.JTYSC, "交通运输车"], |
||||
[MarkType.WSFYC, "卫生防疫车"], |
||||
[MarkType.YJTXC, "应急通信车"], |
||||
[MarkType.JCA, "轿车"], |
||||
[MarkType.JCB, "轿车"], |
||||
[MarkType.JCC, "轿车"], |
||||
[MarkType.DSZ, "董事长"], |
||||
[MarkType.JL, "经理"], |
||||
[MarkType.FZ, "副总"], |
||||
[MarkType.MS, "秘书"], |
||||
[MarkType.ZJ, "总监"], |
||||
[MarkType.ZG, "主管"], |
||||
[MarkType.ZZ, "组长"], |
||||
[MarkType.QT, "前台"], |
||||
[MarkType.SJS, "设计师"], |
||||
[MarkType.CXY, "程序员"], |
||||
[MarkType.ZYA, "职员"], |
||||
[MarkType.ZYB, "职员"], |
||||
[MarkType.JG, "技工"], |
||||
[MarkType.BA, "保安"], |
||||
[MarkType.JJX, "警戒线"], |
||||
[MarkType.SD, "水带"], |
||||
[MarkType.JGLX, "进攻路线"], |
||||
[MarkType.CT, "撤退"],
|
||||
[MarkType.ZHB, "指挥部"], |
||||
[MarkType.LT6, "6米拉梯"], |
||||
[MarkType.LT15, "15米拉梯"], |
||||
[MarkType.FSQ, "分水器"], |
||||
[MarkType.STB, "手抬泵"], |
||||
[MarkType.SP, "水炮"], |
||||
[MarkType.WZ, "文字"], |
||||
[MarkType.JJQ, "集结区"], |
||||
[MarkType.QYSDA, "区域设定"], |
||||
[MarkType.QYSDB, "区域设定"], |
||||
]); |
||||
|
||||
/** |
||||
* 获取事态标绘素材的名称 |
||||
* @param type
|
||||
*/ |
||||
static getMarkName(type: MarkType) { |
||||
if (ConfigManager.s_markName.has(type)) { |
||||
return ConfigManager.s_markName.get(type); |
||||
} |
||||
else { |
||||
return "未知"; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取事态标绘模型的路径 |
||||
* @param type
|
||||
* @param pos
|
||||
*/ |
||||
static getMarkModelPath(pos: MarkTagPos, type: MarkType): string { |
||||
|
||||
let result = ConfigManager.c_resPath_assetsRoot + "mark/" + pos.toLocaleLowerCase() + "/" + type.toLocaleLowerCase() + "/"; |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 获取事态标绘素材的图标 |
||||
* @param type
|
||||
* @param pos
|
||||
*/ |
||||
static getMarkIconUrl(pos: MarkTagPos, type: MarkType): string { |
||||
|
||||
let result = ConfigManager.c_resPath_assetsRoot + "images/mark/" + pos.toLocaleLowerCase() + "/" + type.toLocaleLowerCase() + ".png"; |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
} |
@ -0,0 +1,646 @@
|
||||
import { Quaternion, Vector3 } from '@babylonjs/core'; |
||||
import { |
||||
BuildingData, |
||||
BuildingData_ChemicalPlant, |
||||
BuildingData_Environment, |
||||
BuildingData_Normal, |
||||
BuildingType, |
||||
} from '../model/data/institution/building/building-data'; |
||||
import { |
||||
FacilityPosType, |
||||
FacilityType, |
||||
ModelData_facility, |
||||
} from '../model/data/model-data/model-data-facility'; |
||||
import { |
||||
InstitutionData, |
||||
NormalData, |
||||
} from '../model/data/institution/institution-data'; |
||||
import { |
||||
BuildingPosType, |
||||
ModelData, |
||||
|
||||
} from '../model/data/model-data/model-data'; |
||||
import { ModelData_building } from '../model/data/model-data/model-data-building'; |
||||
import { TransformData } from '../model/data/transform-data'; |
||||
import { BabylonTool } from '../tool/babylon-tool'; |
||||
import { AllFacilityData } from '../model/data/institution/facility/all-facility-data'; |
||||
import { plainToClass } from 'class-transformer'; |
||||
import { ConfigManager } from './config-manager'; |
||||
import { ModelEditData } from '../model/data/model-data/model-edit-data'; |
||||
import { ServeManager } from './serve-manager'; |
||||
import { InsitutionDataSimple } from '../model/data/institution/institution-data-simple'; |
||||
import { PropertyData_Base } from '../model/data/institution/facility/property-data/property-data-base'; |
||||
import { PropertyData_AQCK } from '../model/data/institution/facility/property-data/outdoor/property-data-aqck'; |
||||
import { PropertyData_public } from '../model/data/institution/facility/property-data/property-data-public'; |
||||
import { TsTool } from '../tool/ts-tool'; |
||||
import { PropertyData_Base_XHS } from '../model/data/institution/facility/property-data/base/property-data-base-xhs'; |
||||
import { PropertyData_Base_SBJHQ } from '../model/data/institution/facility/property-data/base/property-data-base-sbjhq'; |
||||
import { PropertyData_PL } from '../model/data/institution/facility/property-data/outdoor/property-data-pl'; |
||||
import { PropertyData_Base_IMG } from '../model/data/institution/facility/property-data/base/property-data-base-img'; |
||||
import { PropertyData_Base_XFB } from '../model/data/institution/facility/property-data/base/property-data-base-xfb'; |
||||
import { PropertyData_FHFQ } from '../model/data/institution/facility/property-data/indoor/property-data-fhfq'; |
||||
import { PropertyData_SSLT } from '../model/data/institution/facility/property-data/indoor/property-data-sslt'; |
||||
import { PropertyData_XFDT } from '../model/data/institution/facility/property-data/indoor/property-data-xfdt'; |
||||
import { PropertyData_ZDQY } from '../model/data/institution/facility/property-data/indoor/property-data-zdqy'; |
||||
import { PropertyData_DWBZ } from '../model/data/institution/facility/property-data/indoor/property-data-dwbz'; |
||||
import { PropertyData_GD } from '../model/data/institution/facility/property-data/outdoor/property-data-gd'; |
||||
import { ModeManager, ModeType } from './mode-manager'; |
||||
import { AllMarkData } from '../model/data/mark/all-mark-data'; |
||||
import { AllMarkPlanData } from '../model/data/mark/mark-plan-data'; |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { PropertyData_Q } from '../model/data/institution/facility/property-data/outdoor/property-data-q'; |
||||
|
||||
class Test { |
||||
id: string; |
||||
} |
||||
|
||||
//数据管理器
|
||||
export class DataManager { |
||||
|
||||
static institutionData_simple: InsitutionDataSimple;//当前单位简易信息
|
||||
static institutionData: InstitutionData; //当前单位信息
|
||||
|
||||
static allFacilityData: AllFacilityData; //所有可用的设备数据(将来读取自配置表)
|
||||
|
||||
/** |
||||
* 态势标绘的素材库 |
||||
*/ |
||||
static allMarkData: AllMarkData; |
||||
|
||||
/** |
||||
* 当前单位的标绘方案信息 |
||||
*/ |
||||
static allMarkPlanData: AllMarkPlanData; |
||||
|
||||
static initDebugData(institutionKey: string, onSuccess?: (key: string) => void, onError?: (key: string, error: string) => void) { |
||||
|
||||
//本地捏造消防设备列表信息
|
||||
DataManager.initDebugData_facility(); |
||||
if (ModeManager.currentMode == ModeType.Look) { |
||||
DataManager.initDebugData_mark(); |
||||
} |
||||
|
||||
let dataFromServe = true;//true-表示数据来自服务器,false-表示来自本地捏造
|
||||
|
||||
if (dataFromServe) { |
||||
|
||||
ServeManager.instance.getInstitutionData(institutionKey, (key, result) => { |
||||
if (onSuccess) { |
||||
DataManager.institutionData = plainToClass(InstitutionData, result); |
||||
DataManager.institutionData.normalData.name = DataManager.institutionData_simple.name; |
||||
// console.log(DataManager.institutionData);
|
||||
onSuccess(key); |
||||
} |
||||
}, (key, error) => { |
||||
|
||||
if (onError) { |
||||
console.error("获取单位信息失败" + key); |
||||
onError(key, error); |
||||
} |
||||
|
||||
console.error("获取单位信息失败,本地捏造数据"); |
||||
DataManager.initDebugData_institution(); |
||||
if (onSuccess) { |
||||
onSuccess(key); |
||||
} |
||||
}); |
||||
} |
||||
else { |
||||
//本地捏造测试数据
|
||||
DataManager.initDebugData_institution(); |
||||
onSuccess(DataManager.institutionData.normalData.key); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
//初始化单位数据
|
||||
static initDebugData_institution() { |
||||
DataManager.institutionData = new InstitutionData(); |
||||
|
||||
DataManager.institutionData.normalData = new NormalData(); |
||||
DataManager.institutionData.normalData.key = 'Institution001'; |
||||
DataManager.institutionData.normalData.name = '单位001'; |
||||
|
||||
DataManager.institutionData.environmentDatas = [ |
||||
new BuildingData_Environment(), |
||||
]; |
||||
DataManager.institutionData.environmentDatas[0].normalData = new NormalData(); |
||||
DataManager.institutionData.environmentDatas[0].normalData.key = |
||||
'environment001'; |
||||
DataManager.institutionData.environmentDatas[0].normalData.name = '环境001'; |
||||
|
||||
let environmentTransform = new TransformData(); //用于测试建筑的数据还原效果
|
||||
environmentTransform.originalScaling = new Vector3(961.66, 5.17, 962.6); |
||||
environmentTransform.position = new Vector3(0, -2.939, 0); |
||||
environmentTransform.scaling = environmentTransform.originalScaling.clone(); |
||||
|
||||
DataManager.institutionData.environmentDatas[0].outdoorData = new ModelEditData(); |
||||
DataManager.institutionData.environmentDatas[0].outdoorData.index = 1; |
||||
let resPath_en = DataManager.getResPath_building( |
||||
DataManager.institutionData.normalData.key.toLowerCase(), |
||||
DataManager.institutionData.environmentDatas[0].normalData.key.toLocaleLowerCase(), |
||||
BuildingPosType.Environment, |
||||
'modelEn001' |
||||
); |
||||
DataManager.institutionData.environmentDatas[0].outdoorData.modelData = new ModelData_building( |
||||
'modelEn001', |
||||
'环境001', |
||||
BuildingPosType.Environment, |
||||
'Terrain.gltf', |
||||
environmentTransform, |
||||
resPath_en |
||||
); |
||||
|
||||
DataManager.institutionData.environmentDatas[0].describe = '这是环境'; |
||||
|
||||
let facilityTransform = new TransformData(); |
||||
facilityTransform.position = new Vector3(-137, 3.3, 150); |
||||
facilityTransform.rotationQuaternion = Quaternion.FromEulerAngles( |
||||
0, |
||||
80 / BabylonTool.c_radian1, |
||||
0 |
||||
); |
||||
facilityTransform.originalScaling = new Vector3(0.39, 0.7, 0.37); |
||||
facilityTransform.scaling = facilityTransform.originalScaling.multiplyByFloats( |
||||
2, |
||||
2, |
||||
2 |
||||
); |
||||
// let facilityData = new ModelData_facility(
|
||||
// 'facility001',
|
||||
// FacilityType.DSXHS,
|
||||
// '地上消火栓',
|
||||
// 'DXXHS.gltf',
|
||||
// facilityTransform,
|
||||
// FacilityPosType.Outdoor
|
||||
// );
|
||||
// DataManager.institutionData.environmentDatas[0].outdoorData.facilities = [
|
||||
// facilityData,
|
||||
// ];
|
||||
|
||||
DataManager.institutionData.normalBuildingDatas = [ |
||||
new BuildingData_Normal(), |
||||
]; |
||||
|
||||
DataManager.institutionData.normalBuildingDatas[0].normalData = new NormalData(); |
||||
DataManager.institutionData.normalBuildingDatas[0].buildingType = |
||||
BuildingType.Normal; |
||||
DataManager.institutionData.normalBuildingDatas[0].normalData.key = |
||||
'building001'; |
||||
DataManager.institutionData.normalBuildingDatas[0].normalData.name = |
||||
'大楼001'; |
||||
DataManager.institutionData.normalBuildingDatas[0].describe = |
||||
'一个普通大楼'; |
||||
|
||||
DataManager.institutionData.normalBuildingDatas[0].outdoorData = new ModelEditData(); |
||||
DataManager.institutionData.normalBuildingDatas[0].outdoorData.index = 1; |
||||
let resPath_out = DataManager.getResPath_building( |
||||
DataManager.institutionData.normalData.key.toLowerCase(), |
||||
DataManager.institutionData.normalBuildingDatas[0].normalData.key.toLocaleLowerCase(), |
||||
BuildingPosType.OutDoor, |
||||
'modelOut001' |
||||
); |
||||
DataManager.institutionData.normalBuildingDatas[0].outdoorData.modelData = new ModelData_building( |
||||
'modelOut001', |
||||
'外观模型1', |
||||
BuildingPosType.OutDoor, |
||||
'ZhuTi.gltf', |
||||
new TransformData(), |
||||
resPath_out |
||||
); |
||||
|
||||
DataManager.institutionData.normalBuildingDatas[0].indoorsData = []; |
||||
|
||||
let indoorData1 = new ModelEditData(); |
||||
DataManager.institutionData.normalBuildingDatas[0].indoorsData.push( |
||||
indoorData1 |
||||
); |
||||
indoorData1.index = 1; |
||||
let resPath_inDoor1 = DataManager.getResPath_building( |
||||
DataManager.institutionData.normalData.key.toLowerCase(), |
||||
DataManager.institutionData.normalBuildingDatas[0].normalData.key.toLocaleLowerCase(), |
||||
BuildingPosType.Indoor, |
||||
'nei1' |
||||
); |
||||
indoorData1.modelData = new ModelData_building( |
||||
'nei1', |
||||
'室内模型1层', |
||||
BuildingPosType.Indoor, |
||||
'nei1.gltf', |
||||
null, |
||||
resPath_inDoor1 |
||||
); |
||||
|
||||
let indoorData2 = new ModelEditData(); |
||||
DataManager.institutionData.normalBuildingDatas[0].indoorsData.push( |
||||
indoorData2 |
||||
); |
||||
indoorData2.index = 2; |
||||
let resPath_inDoor2 = DataManager.getResPath_building( |
||||
DataManager.institutionData.normalData.key.toLowerCase(), |
||||
DataManager.institutionData.normalBuildingDatas[0].normalData.key.toLocaleLowerCase(), |
||||
BuildingPosType.Indoor, |
||||
'nei2' |
||||
); |
||||
indoorData2.modelData = new ModelData_building( |
||||
'nei2', |
||||
'室内模型2层', |
||||
BuildingPosType.Indoor, |
||||
'nei2.gltf', |
||||
null, |
||||
resPath_inDoor2 |
||||
); |
||||
indoorData2.facilities = []; |
||||
|
||||
let indoorData2FacilityTransform = new TransformData(); |
||||
indoorData2FacilityTransform.position = new Vector3(-6, -3.1, 29); |
||||
indoorData2FacilityTransform.rotationQuaternion = Quaternion.FromEulerAngles( |
||||
0, |
||||
30 / BabylonTool.c_radian1, |
||||
0 |
||||
); |
||||
// let indoorData2FacilityData = new ModelData_facility(
|
||||
// 'indoor2_facility001',
|
||||
// FacilityType.DSXHS,
|
||||
// '地下消火栓1',
|
||||
// 'DSXHS.gltf',
|
||||
// indoorData2FacilityTransform,
|
||||
// FacilityPosType.Indoor
|
||||
// );
|
||||
// indoorData2.facilities.push(indoorData2FacilityData);
|
||||
} |
||||
|
||||
|
||||
|
||||
//获取建筑资源完整路径
|
||||
static getResPath_building( |
||||
institutionKey: string, |
||||
buildingKey: string, |
||||
buildingPosType: BuildingPosType, |
||||
key: string |
||||
): string { |
||||
let result = |
||||
ConfigManager.c_resPath_institutionsRoot + |
||||
institutionKey.toLocaleLowerCase() + |
||||
'/' + |
||||
buildingKey.toLocaleLowerCase() + |
||||
'/' + |
||||
buildingPosType + |
||||
'/' + |
||||
key + |
||||
'/'; |
||||
return result; |
||||
} |
||||
|
||||
//获取属性所需文件的路径
|
||||
static getResPath_facilityProperty(institutionKey: string, |
||||
buildingKey: string, facilityType: FacilityType, facilityKey: string, key: string) { |
||||
|
||||
let result = |
||||
ConfigManager.c_resPath_institutionsRoot + |
||||
institutionKey.toLocaleLowerCase() + |
||||
'/' + |
||||
buildingKey.toLocaleLowerCase() + |
||||
'/' + |
||||
ConfigManager.c_reaPath_facilityProperty + |
||||
"/" + |
||||
facilityType.toLocaleLowerCase() + |
||||
'/' + |
||||
facilityKey.toLocaleLowerCase() + |
||||
"/"; |
||||
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
//获取设备资源完整路径
|
||||
static getResPath_facility(facilityPosType: FacilityPosType, type: FacilityType): string { |
||||
let result = "facilities/"; |
||||
|
||||
result += facilityPosType.toString() + "/"; |
||||
|
||||
result += DataManager.getResName_facility(type).toLocaleLowerCase(); |
||||
result += "/"; |
||||
return result; |
||||
} |
||||
|
||||
//获取设备的资源名(有些是公用的)
|
||||
static getResName_facility(type: FacilityType): string { |
||||
let result = type.toString(); |
||||
switch (type) { |
||||
case FacilityType.XKS: |
||||
case FacilityType.BF: |
||||
case FacilityType.SX: |
||||
case FacilityType.FHM: |
||||
case FacilityType.FHJL: |
||||
case FacilityType.SSLT: |
||||
case FacilityType.XFDT: |
||||
case FacilityType.PTDT: |
||||
case FacilityType.HT: |
||||
case FacilityType.WXY: result = "Location"; break; |
||||
|
||||
} |
||||
return result; |
||||
} |
||||
|
||||
//初始化设备信息
|
||||
static initDebugData_facility() { |
||||
DataManager.allFacilityData = AllFacilityData.CreateAllFacilityData(); |
||||
} |
||||
|
||||
/** |
||||
* 初始化态势标绘的素材库 |
||||
*/ |
||||
static initDebugData_mark() { |
||||
DataManager.allMarkData = AllMarkData.CreateAllMarkData(); |
||||
console.log(DataManager.allMarkData, "态势标会"); |
||||
} |
||||
|
||||
static init(simpleData: InsitutionDataSimple, onSuccess?: (key: string) => void) { |
||||
DataManager.institutionData_simple = simpleData; |
||||
DataManager.initDebugData(simpleData.key, onSuccess); |
||||
} |
||||
|
||||
/** |
||||
* 新建当前单位的标绘信息 |
||||
*/ |
||||
static initAllMarkPlaneData() { |
||||
DataManager.allMarkPlanData = new AllMarkPlanData(); |
||||
DataManager.allMarkPlanData.institutionID = DataManager.institutionData.normalData.key; |
||||
DataManager.allMarkPlanData.datas = []; |
||||
return DataManager.allMarkPlanData; |
||||
} |
||||
|
||||
/** |
||||
* 初始化当前建筑的 态势标绘信息 |
||||
*/ |
||||
static initMarkData(onSuccess?: (data: AllMarkPlanData) => void) { |
||||
ServeManager.instance.getMarkData(DataManager.institutionData.normalData.key, (institutionID: string, data: string) => { |
||||
if (data == null) //新建单位的标绘信息
|
||||
{ |
||||
DataManager.initAllMarkPlaneData(); |
||||
} |
||||
else //读取已有的标绘信息
|
||||
{ |
||||
DataManager.allMarkPlanData = plainToClass(AllMarkPlanData, data); |
||||
} |
||||
if (onSuccess != null) { |
||||
onSuccess(DataManager.allMarkPlanData); |
||||
} |
||||
}, (institutionID: string, data: any) => { |
||||
if (data instanceof HttpErrorResponse && data.status == 404) { |
||||
//404,新增单位标绘数据,不算错误
|
||||
} |
||||
else { |
||||
ModeManager.log("获取态势标会失败" + institutionID, data); |
||||
} |
||||
|
||||
}) |
||||
} |
||||
|
||||
|
||||
|
||||
//#region 创建类方法
|
||||
|
||||
/** |
||||
* 新建建筑 |
||||
* @param key
|
||||
* @param name
|
||||
* @param buildingType
|
||||
*/ |
||||
static createBuilding(key: string, name: string, buildingType: BuildingType): BuildingData { |
||||
let result = false; |
||||
if (buildingType == null) { |
||||
throw new Error('create building buildingType is null'); |
||||
} |
||||
|
||||
if (key == null) { |
||||
throw new Error('create building key is null'); |
||||
} |
||||
|
||||
if (name == null || name == "") { |
||||
throw new Error('create building name is null'); |
||||
} |
||||
|
||||
|
||||
let normalData = new NormalData(key, name); |
||||
|
||||
let newBuilding: BuildingData_Normal | BuildingData_Environment | BuildingData_ChemicalPlant; |
||||
switch (buildingType) { |
||||
case BuildingType.Normal: |
||||
newBuilding = new BuildingData_Normal(); |
||||
|
||||
DataManager.institutionData.normalBuildingDatas.push(newBuilding as BuildingData_Normal); |
||||
break; |
||||
case BuildingType.Environment: |
||||
newBuilding = new BuildingData_Environment(); |
||||
DataManager.institutionData.environmentDatas.push(newBuilding as BuildingData_Environment); |
||||
|
||||
break; |
||||
case BuildingType.ChemicalPlant: |
||||
newBuilding = new BuildingData_ChemicalPlant(); |
||||
DataManager.institutionData.chemicalPlantData.push(newBuilding as BuildingData_ChemicalPlant); |
||||
break; |
||||
} |
||||
newBuilding.normalData = normalData; |
||||
|
||||
return newBuilding; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 创建属性 |
||||
* @param key
|
||||
* @param facilityType
|
||||
*/ |
||||
static createPropertyData(key: string, facilityType: FacilityType): PropertyData_Base { |
||||
let result: PropertyData_Base = null; |
||||
switch (facilityType) { |
||||
case FacilityType.AQCK: result = new PropertyData_AQCK(key, "", false, "安全出口", ""); break; //安全出口
|
||||
case FacilityType.DSXHS: |
||||
case FacilityType.DXXHS: |
||||
case FacilityType.SZDSXHS: |
||||
case FacilityType.SZDXXHS: result = new PropertyData_Base_XHS(key, "", false, "", "", "", facilityType); break; |
||||
case FacilityType.DSSBJHQ: |
||||
case FacilityType.DXSBJHQ: |
||||
case FacilityType.QBSBJHQ: |
||||
case FacilityType.DGNSBJHQ: result = new PropertyData_Base_SBJHQ(key, "", "", "", "", facilityType); break; |
||||
case FacilityType.GD: result = new PropertyData_GD(key, "-"); break; |
||||
case FacilityType.PL: result = new PropertyData_PL(key, 0, "", []); break; |
||||
case FacilityType.JTQ: |
||||
case FacilityType.JJQ: result = new PropertyData_Q(key, "", "", "", null, facilityType); break; |
||||
case FacilityType.TPBZ: |
||||
case FacilityType.XKS: |
||||
case FacilityType.BF: |
||||
case FacilityType.SX: result = new PropertyData_Base_IMG(key, "", "", "", facilityType); break; |
||||
case FacilityType.LSXFB: |
||||
case FacilityType.WSXFB: |
||||
case FacilityType.CYXFB: result = new PropertyData_Base_XFB(key, "", "", "", "", "", "", facilityType); break; |
||||
case FacilityType.FHFQ: result = new PropertyData_FHFQ(key, "", ""); break; |
||||
case FacilityType.SSLT: result = new PropertyData_SSLT(key, "", "", ""); break; |
||||
case FacilityType.XFDT: result = new PropertyData_XFDT(key, "", "", ""); break; |
||||
case FacilityType.WXY: result = new PropertyData_Base_IMG(key, "", "", "", facilityType); break; |
||||
case FacilityType.ZDQY: result = new PropertyData_ZDQY(key, "", "", "", "", "", []); break; |
||||
case FacilityType.DWBZ: result = new PropertyData_DWBZ(key, "", ""); break; |
||||
//其他在表格中显示无
|
||||
} |
||||
|
||||
if (result == null) { |
||||
result = new PropertyData_public(key, facilityType); |
||||
} |
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 新建标绘方案 |
||||
* @param name
|
||||
*/ |
||||
static createMarkPlane(name: string) { |
||||
if (DataManager.allMarkPlanData == null) { |
||||
console.error("当前单位没有标绘方案,无法新建"); |
||||
return; |
||||
} |
||||
|
||||
let index = 0; |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 查询类方法
|
||||
/** |
||||
* 根据类型查询建筑列表 |
||||
* @param buildingType 建筑类型 |
||||
*/ |
||||
static getBuildingDataListByType(buildingType: BuildingType): BuildingData_Normal[] | BuildingData_Environment[] | BuildingData_ChemicalPlant[] { |
||||
let buildingDatas: BuildingData_Normal[] | BuildingData_Environment[] | BuildingData_ChemicalPlant[]; |
||||
|
||||
switch (buildingType) { |
||||
case BuildingType.Normal: |
||||
buildingDatas = DataManager.institutionData.normalBuildingDatas; |
||||
break; |
||||
case BuildingType.Environment: |
||||
buildingDatas = DataManager.institutionData.environmentDatas; |
||||
break; |
||||
case BuildingType.ChemicalPlant: |
||||
buildingDatas = DataManager.institutionData.chemicalPlantData; |
||||
break; |
||||
} |
||||
|
||||
return buildingDatas; |
||||
|
||||
} |
||||
//#endregion
|
||||
|
||||
//#region 修改和删除类方法
|
||||
|
||||
//删除一个当前单位的buildingData
|
||||
static deleteOneBuildingData(buildingType: BuildingType, key: string) { |
||||
let buildingDatas = DataManager.getBuildingDataListByType(buildingType); |
||||
|
||||
for (let i = 0; i < buildingDatas.length; i++) { |
||||
if (buildingDatas[i].normalData.key == key) { |
||||
TsTool.arrayRemove(buildingDatas, buildingDatas[i]); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 保存当前的标绘信息 |
||||
*/ |
||||
static saveallMarkPlanData() { |
||||
console.log("当前标绘", DataManager.allMarkPlanData); |
||||
ServeManager.instance.saveMarkData(DataManager.allMarkPlanData); |
||||
} |
||||
//#endregion
|
||||
|
||||
|
||||
//#region 文件修改类
|
||||
|
||||
/** |
||||
* 创建manifest 类文件 |
||||
* @param fileName //资源文件名,例如 zhuti.gltf
|
||||
* @param version //版本号
|
||||
*/ |
||||
static createFile_manifest(fileName: string, version: number): File { |
||||
let file; |
||||
let data = []; |
||||
|
||||
let info = { |
||||
"version": version, |
||||
"enableSceneOffline": true, |
||||
"enableTexturesOffline": true |
||||
}; |
||||
|
||||
data.push(JSON.stringify(info)); |
||||
|
||||
|
||||
let properties = { type: 'text/cache-manifest' }; // 设置文件的 mime-type.
|
||||
try { |
||||
// 使用文件构造函数指定文件名,如果 ...
|
||||
file = new File(data, fileName + ".manifest", properties); |
||||
} catch (e) { |
||||
// ... 如果不支持Blob构造函数,请退回到Blob构造函数。
|
||||
file = new Blob(data, properties); |
||||
} |
||||
|
||||
console.log("创建版本号" + version); |
||||
|
||||
return file; |
||||
} |
||||
|
||||
/** |
||||
* 创建版本文件(版本号+1) |
||||
* @param indoorData
|
||||
*/ |
||||
static createManifestFile(modelData: ModelData): File { |
||||
modelData.version += 1; |
||||
let manifestFile = DataManager.createFile_manifest(modelData.resName, modelData.version); |
||||
|
||||
return manifestFile; |
||||
} |
||||
|
||||
/** |
||||
* 读取版本文件中的版本号 |
||||
* @param file
|
||||
*/ |
||||
static readFile_manifest(file: File, onLoad: (result) => void): number { |
||||
let version = 1; |
||||
|
||||
var reader = new FileReader(); |
||||
reader.onload = function (evt) { // 指定异步读写后触发的函数
|
||||
ModeManager.log(evt.target.result); |
||||
let object = JSON.parse(evt.target.result as string); |
||||
onLoad(object.version); |
||||
}; |
||||
reader.readAsText(file); |
||||
|
||||
return version; |
||||
|
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
} |
||||
|
||||
//模型信息变化类型
|
||||
export enum ModelChangeType { |
||||
Add, |
||||
Remove, |
||||
Update, |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
|
||||
/** |
||||
* 事件基础类 |
||||
*/ |
||||
export class Event_Base { |
||||
|
||||
//属性 自定义
|
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,138 @@
|
||||
import { EventState, Observable, Observer, TransformNode } from "@babylonjs/core"; |
||||
import { Event_Base } from "./event-base"; |
||||
|
||||
/** |
||||
* 事件管理器 |
||||
*/ |
||||
export class EventManager { |
||||
|
||||
//#region 单例
|
||||
private static instance: EventManager; |
||||
|
||||
public static get Instcane() { |
||||
if (EventManager.instance == null) { |
||||
EventManager.instance = new EventManager(); |
||||
} |
||||
|
||||
return EventManager.instance; |
||||
|
||||
} |
||||
//#endregion
|
||||
|
||||
//#region event 实例管理
|
||||
//所有实例化的event
|
||||
private static s_allEventContainer: any[]; |
||||
|
||||
//创建event实例
|
||||
private static createEvent<T extends Event_Base>(c: { new(): T }): EventContainer<T> { |
||||
let newEvent = null; |
||||
if (newEvent == null) { |
||||
newEvent = new EventContainer<T>(c); |
||||
EventManager.s_allEventContainer.push(newEvent); |
||||
} |
||||
|
||||
return newEvent; |
||||
} |
||||
|
||||
//获取event实例
|
||||
private static getEvent<T extends Event_Base>(c: { new(): T }): EventContainer<T> { |
||||
|
||||
if (EventManager.s_allEventContainer == null) { |
||||
EventManager.s_allEventContainer = []; |
||||
} |
||||
let result = null; |
||||
for (let i = 0; i < EventManager.s_allEventContainer.length; i++) { |
||||
|
||||
if (EventManager.s_allEventContainer[i].key == c.name) { |
||||
result = (EventManager.s_allEventContainer[i]); |
||||
// console.log("找到已有的event" + (c.name));
|
||||
return result; |
||||
|
||||
} |
||||
} |
||||
|
||||
result = EventManager.createEvent<T>(c); |
||||
|
||||
// console.log("新建event" + result);
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
/** |
||||
* 添加监听 |
||||
* @param callback 事件派发时的回调 |
||||
*/ |
||||
static addListener<T extends Event_Base>(c: { new(): T }, callback: (eventData: T, eventState: EventState) => void, |
||||
mask?: number, |
||||
insertFirst?: boolean, |
||||
scope?: any, |
||||
unregisterOnFirstCall?: boolean): Observer<T> { |
||||
|
||||
let instance = EventManager.getEvent<T>(c); |
||||
|
||||
|
||||
return instance.observable.add(callback, mask, insertFirst, scope, unregisterOnFirstCall); |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* 移除监听者 |
||||
* @param observer 要移除的观察者 |
||||
*/ |
||||
static removeListener<T extends Event_Base>(c: { new(): T }, observer: Observer<T>) { |
||||
let instance = EventManager.getEvent<T>(c); |
||||
if (instance == null) { |
||||
return; |
||||
} |
||||
instance.observable.remove(observer); |
||||
} |
||||
|
||||
/** |
||||
* 移除监听者(通过回调) |
||||
* @param callback
|
||||
*/ |
||||
static removeCallback<T extends Event_Base>(c: { new(): T }, callback: (eventData: T, eventState: EventState) => void, |
||||
mask?: number, |
||||
insertFirst?: boolean, |
||||
scope?: any, |
||||
unregisterOnFirstCall?: boolean) { |
||||
let instance = EventManager.getEvent<T>(c); |
||||
if (instance == null) { |
||||
return; |
||||
} |
||||
|
||||
instance.observable.removeCallback(callback); |
||||
} |
||||
|
||||
/** |
||||
* 派发事件 |
||||
* @param eventData 派发的信息 |
||||
*/ |
||||
static dispatch<T extends Event_Base>(c: { new(): T }, eventData: T) { |
||||
let instance = EventManager.getEvent<T>(c); |
||||
if (instance == null) { |
||||
return; |
||||
} |
||||
instance.observable.notifyObservers(eventData); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 事件容器 |
||||
*/ |
||||
class EventContainer<T extends Event_Base> { |
||||
key: string; |
||||
observable: Observable<T>; |
||||
constructor(c: { new(): T }) { |
||||
|
||||
this.key = c.name; |
||||
// console.log("EventContainer===" + this.key);
|
||||
this.observable = new Observable<T>(); |
||||
} |
||||
} |
@ -0,0 +1,31 @@
|
||||
|
||||
|
||||
import { ModelData } from "src/app/babylon/model/data/model-data/model-data"; |
||||
import { BuildingInfo } from "src/app/babylon/model/info/building/building-info"; |
||||
import { ModelChangeType } from "../../data-manager"; |
||||
import { Event_Base } from "../event-base"; |
||||
import { EventManager } from "../event-manager"; |
||||
|
||||
export class Event_ChangeFacility extends Event_Base { |
||||
|
||||
modeleData: ModelData; |
||||
modelChangeType: ModelChangeType; |
||||
belongtoBuilding: BuildingInfo;//属于哪个建筑
|
||||
|
||||
initInfo(modeleData: ModelData, |
||||
modelChangeType: ModelChangeType, |
||||
belongtoBuilding: BuildingInfo) { |
||||
this.modeleData = modeleData; |
||||
this.modelChangeType = modelChangeType; |
||||
this.belongtoBuilding = belongtoBuilding; |
||||
} |
||||
|
||||
static dispatch(modeleData: ModelData, |
||||
modelChangeType: ModelChangeType, |
||||
belongtoBuilding: BuildingInfo) { |
||||
let eventInfo = new Event_ChangeFacility(); |
||||
eventInfo.initInfo(modeleData, modelChangeType, belongtoBuilding); |
||||
|
||||
EventManager.dispatch(Event_ChangeFacility, eventInfo); |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
|
||||
import { AllMarkPlanData } from "src/app/babylon/model/data/mark/mark-plan-data"; |
||||
import { Event_Base } from "../event-base"; |
||||
import { EventManager } from "../event-manager"; |
||||
|
||||
/** |
||||
* 获取单位的标绘方案信息的结果 |
||||
*/ |
||||
export class Event_GetAllMarkPlanData extends Event_Base { |
||||
|
||||
success: boolean; |
||||
data: AllMarkPlanData; |
||||
|
||||
static dispatch(success: boolean, data: AllMarkPlanData) { |
||||
let info = new Event_GetAllMarkPlanData(); |
||||
info.success = success; |
||||
info.data = data; |
||||
|
||||
EventManager.dispatch(Event_GetAllMarkPlanData, info); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,17 @@
|
||||
import { Event_Base } from "../event-base"; |
||||
import { EventManager } from "../event-manager"; |
||||
|
||||
/** |
||||
* 键盘输入事件 |
||||
*/ |
||||
export class Event_KeyboardInput extends Event_Base { |
||||
|
||||
data: KeyboardEvent; |
||||
|
||||
static dispatch(ev: KeyboardEvent) { |
||||
let eventData = new Event_KeyboardInput(); |
||||
eventData.data = ev; |
||||
EventManager.dispatch<Event_KeyboardInput>(Event_KeyboardInput, eventData); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,44 @@
|
||||
|
||||
import { ModelInfo_mark } from "src/app/babylon/model/info/mark/model-info-mark"; |
||||
import { Event_Base } from "../event-base"; |
||||
import { EventManager } from "../event-manager"; |
||||
|
||||
/** |
||||
* MarkInfo(标绘物运行时数据)发生变化 |
||||
*/ |
||||
export class Event_MarkInfoChange extends Event_Base { |
||||
|
||||
eventType: MarkInfoChangeType; |
||||
|
||||
markInfo: ModelInfo_mark; |
||||
|
||||
static dispatch(eventType: MarkInfoChangeType, markInfo: ModelInfo_mark) { |
||||
|
||||
let eventInfo = new Event_MarkInfoChange(); |
||||
eventInfo.eventType = eventType; |
||||
eventInfo.markInfo = markInfo; |
||||
|
||||
EventManager.dispatch(Event_MarkInfoChange, eventInfo); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 标绘物运行时数据发生变化 |
||||
*/ |
||||
export enum MarkInfoChangeType { |
||||
|
||||
/** |
||||
* 创建 |
||||
*/ |
||||
Create, |
||||
|
||||
/** |
||||
* 选中 |
||||
*/ |
||||
Select, |
||||
/** |
||||
* 取消选中 |
||||
*/ |
||||
UnSelect, |
||||
|
||||
} |
@ -0,0 +1,33 @@
|
||||
|
||||
import { ModelInfo } from "src/app/babylon/model/info/model/model-info"; |
||||
import { ModelChangeType } from "../../data-manager"; |
||||
import { Event_Base } from "../event-base"; |
||||
import { EventManager } from "../event-manager"; |
||||
|
||||
/** |
||||
* modelInfo发生变化 |
||||
*/ |
||||
export class Event_ModelInfoChange extends Event_Base { |
||||
|
||||
//属性
|
||||
modeleInfo: ModelInfo; |
||||
modelChangeType: ModelChangeType; |
||||
|
||||
|
||||
setInfo(modelInfo: ModelInfo, modelChangeType: ModelChangeType) { |
||||
|
||||
this.modeleInfo = modelInfo; |
||||
this.modelChangeType = modelChangeType; |
||||
} |
||||
|
||||
/** |
||||
* 派发事件 |
||||
* @param modeleInfo
|
||||
* @param modelChangeType
|
||||
*/ |
||||
static dispatch(modeleInfo: ModelInfo, modelChangeType: ModelChangeType) { |
||||
let eventData = new Event_ModelInfoChange(); |
||||
eventData.setInfo(modeleInfo, modelChangeType); |
||||
EventManager.dispatch<Event_ModelInfoChange>(Event_ModelInfoChange, eventData); |
||||
} |
||||
} |
@ -0,0 +1,228 @@
|
||||
|
||||
import { AbstractMesh } from "@babylonjs/core"; |
||||
import { MarkData } from "../model/data/mark/mark-data"; |
||||
import { ModelData } from "../model/data/model-data/model-data"; |
||||
import { FacilityType, ModelData_facility } from "../model/data/model-data/model-data-facility"; |
||||
import { ModelEditData } from "../model/data/model-data/model-edit-data"; |
||||
import { TransformData } from "../model/data/transform-data"; |
||||
import { BuildingInfo } from "../model/info/building/building-info"; |
||||
import { ModelInfo_mark } from "../model/info/mark/model-info-mark"; |
||||
import { ModelInfo } from "../model/info/model/model-info"; |
||||
import { ModelInfo_building } from "../model/info/model/model-info-building"; |
||||
import { FacilityInfoByType, ModelInfo_facility } from "../model/info/model/model-info-facility"; |
||||
import { GizmoTool } from "../tool/gizmo-tool"; |
||||
import { TsTool } from "../tool/ts-tool"; |
||||
import { FacilityWindow } from "../view/facility-window/facility-window"; |
||||
import { FacilityInfoInSceneWindow } from "../view/facilityinfoinscene-window/facilityinfoinscene-window"; |
||||
import { ModelChangeType } from "./data-manager"; |
||||
import { Event_ModelInfoChange } from "./event-manager/events/event-modelinfo-change"; |
||||
import { ModeManager, ModeType } from "./mode-manager"; |
||||
import { SceneManager } from "./scene-manager"; |
||||
|
||||
//运行时数据管理器
|
||||
export class InfoManager { |
||||
static s_currentTransformData: TransformData; //当前模型的transform信息
|
||||
static s_currentMesh: AbstractMesh; //当前选中的mesh
|
||||
|
||||
// static s_allBuildingInfos: ModelInfo_building[] = []; //所有实例化的建筑(室外)
|
||||
|
||||
// static s_allFactivityInfos_outdoor: FacilityInfoByType[] = []; //所有实例化的设备(室外)
|
||||
|
||||
// static s_allFactivityInfos_indoor: FacilityInfoByType[] = []; //所有实例化的设备(室内)
|
||||
|
||||
// static s_onModelInfoChangeObservable: Observable<ModelInfoChange>; //模型信息变化事件
|
||||
|
||||
// static s_onModelEnableChangeObservable: Observable<AbstractMesh>; //模型状态变化事件
|
||||
|
||||
static init() { |
||||
SceneManager.Instance.scene.onBeforeRenderObservable.add(InfoManager.onBeforeRender); |
||||
GizmoTool.onPickMeshInfoObservable.add(InfoManager.onPickMesh); |
||||
} |
||||
|
||||
static onBeforeRender() { |
||||
if (InfoManager.s_currentTransformData != null) { |
||||
InfoManager.s_currentTransformData.position = |
||||
InfoManager.s_currentMesh.position; |
||||
InfoManager.s_currentTransformData.rotation = |
||||
InfoManager.s_currentMesh.rotation; |
||||
InfoManager.s_currentTransformData.rotationQuaternion = |
||||
InfoManager.s_currentMesh.rotationQuaternion; |
||||
InfoManager.s_currentTransformData.scaling = |
||||
InfoManager.s_currentMesh.scaling; |
||||
InfoManager.s_currentMesh.absoluteScaling; |
||||
} |
||||
} |
||||
static onPickMesh(modelInfo: ModelInfo) { |
||||
if (modelInfo != null) { |
||||
InfoManager.s_currentMesh = modelInfo.modelBox; |
||||
InfoManager.s_currentTransformData = modelInfo.modelData.transformData; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
//加入管理
|
||||
static addModelInfo(modelInfo: ModelInfo) { |
||||
Event_ModelInfoChange.dispatch(modelInfo, ModelChangeType.Add); |
||||
} |
||||
|
||||
/** |
||||
* 创建一个建筑模型info |
||||
* @param key
|
||||
* @param modelData
|
||||
* @param models
|
||||
* @param modelBox
|
||||
*/ |
||||
static newModelInfo_building(key: string, |
||||
modelData: ModelData, |
||||
models: AbstractMesh[], |
||||
modelBox: AbstractMesh): ModelInfo_building { |
||||
let result = new ModelInfo_building(key, |
||||
modelData, |
||||
models, |
||||
modelBox); |
||||
InfoManager.addModelInfo(result); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 新建设备 info |
||||
* @param key
|
||||
* @param modelData
|
||||
* @param models
|
||||
* @param modelBox
|
||||
*/ |
||||
static newModelInfo_facility(key: string, |
||||
modelData: ModelData, |
||||
models: AbstractMesh[], |
||||
modelBox: AbstractMesh, |
||||
belongToBuilding: BuildingInfo, |
||||
isNew: boolean): ModelInfo_facility { |
||||
let result = new ModelInfo_facility(key, |
||||
modelData, |
||||
models, |
||||
modelBox, |
||||
belongToBuilding, |
||||
isNew |
||||
); |
||||
if (belongToBuilding != null) //表示游离态的设备
|
||||
{ |
||||
InfoManager.addFacilityInfoToTypeList(result, belongToBuilding.ModelInfo.facilityInfos); |
||||
} |
||||
InfoManager.addModelInfo(result); |
||||
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 新建标绘物 info |
||||
* @param key
|
||||
* @param modelData
|
||||
* @param models
|
||||
* @param modelBox
|
||||
*/ |
||||
static newModelInfo_mark( |
||||
markData: MarkData, |
||||
models: AbstractMesh[], |
||||
modelBox: AbstractMesh, |
||||
belongToBuilding: BuildingInfo, |
||||
isNew: boolean): ModelInfo_mark { |
||||
let result = new ModelInfo_mark( |
||||
markData, |
||||
models, |
||||
modelBox, |
||||
belongToBuilding, |
||||
isNew |
||||
); |
||||
// if (belongToBuilding != null) //表示游离态的设备
|
||||
// {
|
||||
// InfoManager.addFacilityInfoToTypeList(result, belongToBuilding.ModelInfo.facilityInfos);
|
||||
// }
|
||||
if (isNew) { |
||||
InfoManager.addModelInfo(result); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
//移除model info
|
||||
static removeModelInfo(modelInfo: ModelInfo) { |
||||
|
||||
Event_ModelInfoChange.dispatch(modelInfo, ModelChangeType.Remove); |
||||
|
||||
} |
||||
|
||||
//创建建筑中的设备
|
||||
static createFacilityInfos( |
||||
modelEditData: ModelEditData, |
||||
buildingInfo: BuildingInfo = null |
||||
) { |
||||
|
||||
let facilities = modelEditData.facilities; |
||||
|
||||
for (let i = 0; i < facilities.length; i++) { |
||||
|
||||
for (let j = 0; j < facilities[i].facilities.length; j++) { |
||||
FacilityWindow.instance.createFacility( |
||||
modelEditData.facilities[i].facilities[j], |
||||
false, |
||||
buildingInfo, |
||||
true, |
||||
false, |
||||
(modelInfo: ModelInfo_facility) => { |
||||
if (ModeManager.currentMode == ModeType.Look) { |
||||
modelInfo.setIconEnable(false);//查看模式下隐藏所有设备ui
|
||||
} |
||||
} |
||||
); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
//将某设备info,加入到相应的列表中
|
||||
static addFacilityInfoToTypeList(facilityInfo: ModelInfo_facility, facilityInfosByType: FacilityInfoByType[]) { |
||||
let facilityType = (facilityInfo.modelData as ModelData_facility).facilityType; |
||||
let facilityInfoByType = InfoManager.getFacilityInfoByType(facilityType, facilityInfosByType); |
||||
|
||||
if (facilityInfoByType == null) { |
||||
facilityInfoByType = new FacilityInfoByType(facilityType); |
||||
facilityInfosByType.push(facilityInfoByType); |
||||
} |
||||
|
||||
|
||||
facilityInfoByType.facilityInfo.push(facilityInfo); |
||||
} |
||||
|
||||
//将某设备info,从相应的列表中移除
|
||||
static removeFacilityInfoToTypeList(facilityInfo: ModelInfo_facility, facilityInfosByType: FacilityInfoByType[]) { |
||||
let facilityType = (facilityInfo.modelData as ModelData_facility).facilityType; |
||||
let facilityInfoByType = InfoManager.getFacilityInfoByType(facilityType, facilityInfosByType); |
||||
|
||||
TsTool.arrayRemove(facilityInfoByType.facilityInfo, facilityInfo); |
||||
} |
||||
|
||||
//根据类型获取
|
||||
static getFacilityInfoByType(facilityType: FacilityType, facilityInfosByType: FacilityInfoByType[]) { |
||||
let result: FacilityInfoByType = null; |
||||
|
||||
for (let i = 0; i < facilityInfosByType.length; i++) { |
||||
if (facilityInfosByType[i].type == facilityType) { |
||||
result = facilityInfosByType[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,79 @@
|
||||
|
||||
|
||||
/** |
||||
* 模式类型 |
||||
*/ |
||||
export enum ModeType { |
||||
|
||||
Look = "Look",//查看模式
|
||||
Edit = "Edit",//编辑模式
|
||||
} |
||||
|
||||
/** |
||||
* 模式管理器 |
||||
*/ |
||||
export class ModeManager { |
||||
|
||||
/** |
||||
* 当前模式的类型 |
||||
*/ |
||||
private static s_currentMode: ModeType = ModeType.Edit; |
||||
|
||||
/** |
||||
* 调试模式 |
||||
*/ |
||||
public static isDebug = true; |
||||
|
||||
|
||||
//#region 演示单单位
|
||||
|
||||
//未指定演示单位,正常打开
|
||||
static readonly c_demoKey_null = null; |
||||
|
||||
// 上海国际会议中心 测试
|
||||
static readonly c_demoKey_shanghai = "shanghai"; |
||||
|
||||
//测试
|
||||
static readonly c_demoKey_test = "test"; |
||||
|
||||
/** |
||||
* 演示单位的key
|
||||
*/ |
||||
public static institutionDemoKey = ModeManager.c_demoKey_null; |
||||
|
||||
//#endregion
|
||||
|
||||
/** |
||||
* 获取当前模式的类型 |
||||
*/ |
||||
static get currentMode(): ModeType { |
||||
return ModeManager.s_currentMode; |
||||
} |
||||
|
||||
/** |
||||
* 改变模式类型 |
||||
*/ |
||||
static set currentMode(modeType: ModeType) { |
||||
ModeManager.s_currentMode = modeType; |
||||
ModeManager.log("currentMode" + modeType); |
||||
} |
||||
|
||||
//封装打印
|
||||
static log(data: any, ...optionalParams: any[]) { |
||||
if (ModeManager.isDebug) { |
||||
console.log(data, optionalParams); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 封装的打印堆栈 |
||||
*/ |
||||
static trace(message?: any, ...optionalParams: any[]) { |
||||
if (ModeManager.isDebug) { |
||||
console.trace(message, optionalParams); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
@ -0,0 +1,915 @@
|
||||
import { |
||||
AbstractMesh, |
||||
AnimationGroup, |
||||
ArcRotateCamera, |
||||
BoundingBoxGizmo, |
||||
Color3, |
||||
Color4, |
||||
CubeTexture, |
||||
DirectionalLight, |
||||
Engine, |
||||
EventState, |
||||
HemisphericLight, |
||||
HighlightLayer, |
||||
IParticleSystem, |
||||
Mesh, |
||||
MeshBuilder, |
||||
Observable, |
||||
Observer, |
||||
PBRMaterial, |
||||
PickingInfo, |
||||
PointerEventTypes, |
||||
Quaternion, |
||||
Scene, |
||||
ShadowGenerator, |
||||
Skeleton, |
||||
StandardMaterial, |
||||
Texture, |
||||
TransformNode, |
||||
Vector3, |
||||
} from '@babylonjs/core'; |
||||
import '@babylonjs/core/Debug/debugLayer'; |
||||
import '@babylonjs/inspector'; |
||||
import { GridMaterial } from '@babylonjs/materials'; |
||||
import { ModelData, ModelType } from '../model/data/model-data/model-data'; |
||||
import { ModelInfo } from '../model/info/model/model-info'; |
||||
import { ModelInfo_building } from '../model/info/model/model-info-building'; |
||||
import { MyArcRotateCameraPointersInput } from '../tool/myArcRotateCameraPointersInput'; |
||||
import { BabylonTool } from '../tool/babylon-tool'; |
||||
import { GizmoTool } from '../tool/gizmo-tool'; |
||||
import { TsTool } from '../tool/ts-tool'; |
||||
import { FacilityWindow } from '../view/facility-window/facility-window'; |
||||
import { FacilityInfoInSceneWindow } from '../view/facilityinfoinscene-window/facilityinfoinscene-window'; |
||||
import { InfoManager } from './info-manager'; |
||||
import { ModeManager } from './mode-manager'; |
||||
import { MarkWindow } from '../view/mark-window/mark-window'; |
||||
import { ModelInfo_facility } from '../model/info/model/model-info-facility'; |
||||
import { ModelInfo_mark } from '../model/info/mark/model-info-mark'; |
||||
import { MarkData, MarkType } from '../model/data/mark/mark-data'; |
||||
import { Event_KeyboardInput } from './event-manager/events/event-keyboard-input'; |
||||
import { ModelInfo_mark_area } from '../model/info/mark/other/mark-plan-area-info'; |
||||
import { classToClass, plainToClass } from 'class-transformer'; |
||||
import { MarkData_Area } from '../model/data/mark/other/mark-data-area'; |
||||
import { MarkData_Line } from '../model/data/mark/other/mark-data-line'; |
||||
import { ModelInfo_mark_line } from '../model/info/mark/other/mark-plan-line-info'; |
||||
import { MarkData_multiLine } from '../model/data/mark/other/mark-data-multi-line'; |
||||
import { ModelInfo_mark_multiLine } from '../model/info/mark/other/mark-plan-multi-line-info'; |
||||
import { MarkData_multiArrow_CT, MarkData_multiArrow_JG } from '../model/data/mark/other/mark-data-multi-arrow'; |
||||
import { ModelInfo_mark_multiArrow } from '../model/info/mark/other/mark-plan-multi-arrow'; |
||||
import { ModelInfo_mark_particle } from '../model/info/mark/other/mark-plan-particle-info'; |
||||
|
||||
//场景管理器
|
||||
export class SceneManager { |
||||
//----------------Camera-----------------\\
|
||||
|
||||
public engine: Engine; |
||||
public canvas: HTMLCanvasElement; |
||||
public scene: Scene; |
||||
public defaultCamera: ArcRotateCamera; |
||||
private hemisphericLight: HemisphericLight; |
||||
public shadowGenerator: ShadowGenerator;//阴影
|
||||
public sunLight: DirectionalLight;//太阳光,用于产生阴影
|
||||
public skyBox: Mesh;//天空球
|
||||
public ground3D: Mesh;//无天空盒时的背景地面
|
||||
|
||||
|
||||
static s_openLight: boolean = true;//开启光照效果(关闭是要同时关闭阴影)
|
||||
static s_openShadow: boolean = true;//开启阴影(必须开启阴影)
|
||||
static s_openSkyBox: boolean = true;//使用天空盒
|
||||
static s_environmentCubeTexture: CubeTexture;//环境所用的cubeTexture
|
||||
static s_openEnvironmentReflection: boolean = true;//使用环境反射
|
||||
static s_allModelInfo: ModelInfo[] = []; //所有建筑模型信息
|
||||
static s_facilityInfoInSceneWindow: FacilityInfoInSceneWindow; //场景中设备 界面
|
||||
static s_facilityWindow: FacilityWindow; //可用设备 界面
|
||||
static s_markWindow: MarkWindow;//可用的标绘素材 界面
|
||||
|
||||
//#region 单例
|
||||
private static instance: SceneManager; |
||||
|
||||
public static get Instance() { |
||||
if (SceneManager.instance == null) { |
||||
throw new Error('Method not implemented.'); |
||||
} |
||||
return SceneManager.instance; |
||||
} |
||||
//#endregion
|
||||
|
||||
//#region 初始化
|
||||
//初始化
|
||||
public static init(scene: Scene, canvas: HTMLCanvasElement, engine: Engine): SceneManager { |
||||
if (SceneManager.instance != null) { |
||||
throw new Error("sceneManager can't be reinitialized"); |
||||
} else { |
||||
|
||||
SceneManager.instance = new SceneManager(); |
||||
SceneManager.instance.engine; |
||||
SceneManager.instance.scene = scene; |
||||
SceneManager.instance.canvas = canvas; |
||||
|
||||
} |
||||
return SceneManager.instance; |
||||
} |
||||
//#endregion
|
||||
|
||||
//#region 摄像机
|
||||
|
||||
/** |
||||
* 摄像机模式-是正交状态 |
||||
*/ |
||||
public cameraMode_Is2D = false; |
||||
|
||||
//初始化自由旋转相机
|
||||
public initArcRotateCamera() { |
||||
let camera = new ArcRotateCamera( |
||||
'Camera', //名称
|
||||
0, //alpha: 定义相机沿垂直轴的旋转
|
||||
1.2, //beta: 定义相机沿水平轴的旋转
|
||||
10, //摄像机与目标位置的距离
|
||||
Vector3.Zero(), //目标位置
|
||||
this.scene //定义摄像机所属的场景
|
||||
); |
||||
camera.maxZ = 6000; //摄像机拍摄的最远距离
|
||||
camera.upperBetaLimit = 1.5; //beta方向上的旋转限制(防止看到模型底面)
|
||||
camera.lowerRadiusLimit = 3; //相机距离拍摄目标的最小距离(防止穿插)
|
||||
camera.setTarget(Vector3.Zero()); //设置拍摄目标
|
||||
camera.attachControl(this.canvas, true); //把相机连接到画布
|
||||
this.defaultCamera = camera; |
||||
|
||||
camera.inputs.removeByType("ArcRotateCameraPointersInput"); |
||||
camera.inputs.removeByType("ArcRotateCameraKeyboardMoveInput"); //为了配合快捷键,屏蔽了
|
||||
|
||||
camera.inputs.add(new MyArcRotateCameraPointersInput()); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 改变摄像机模式(正交还是透视) |
||||
* @param is2D true表示正交 |
||||
*/ |
||||
public changeCameraMode(is2D: boolean) { |
||||
this.cameraMode_Is2D = is2D; |
||||
BabylonTool.changeCameraMode(this.defaultCamera, is2D); |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
//#region 光照与背景
|
||||
|
||||
|
||||
|
||||
//默认的半球光
|
||||
public initLight() { |
||||
this.hemisphericLight = new HemisphericLight( |
||||
'light1', |
||||
new Vector3(0, 1, 0), |
||||
this.scene |
||||
); |
||||
|
||||
this.updateLightSetting(); |
||||
|
||||
this.updateShadow(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 更新光照设置 |
||||
*/ |
||||
updateLightSetting() { |
||||
if (SceneManager.s_openLight) { |
||||
|
||||
|
||||
if (this.sunLight == null) { |
||||
this.sunLight = new DirectionalLight("sun", new Vector3(0.49, -0.79, 0.38), this.scene); |
||||
} |
||||
else { |
||||
this.sunLight.setEnabled(true); |
||||
} |
||||
|
||||
if (SceneManager.s_openEnvironmentReflection) { |
||||
this.hemisphericLight.intensity = 0.1;//有环境反射时,本身会比较亮(跟当前使用的环境贴图有关)
|
||||
this.sunLight.intensity = 3; |
||||
} |
||||
else { |
||||
this.hemisphericLight.intensity = 0.25; |
||||
this.sunLight.intensity = 3; |
||||
} |
||||
|
||||
|
||||
} |
||||
else { |
||||
if (this.sunLight == null) { |
||||
this.sunLight.setEnabled(false); |
||||
} |
||||
|
||||
this.hemisphericLight.intensity = 10; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 初始化阴影 |
||||
*/ |
||||
public updateShadow() { |
||||
if (SceneManager.s_openShadow) { |
||||
if (this.shadowGenerator == null) { |
||||
this.shadowGenerator = new ShadowGenerator(2048, this.sunLight); |
||||
} |
||||
|
||||
this.shadowGenerator.usePercentageCloserFiltering = true; |
||||
this.shadowGenerator.filteringQuality = ShadowGenerator.QUALITY_MEDIUM; |
||||
// this.shadowGenerator.blurKernel = 32;
|
||||
if (this.sunLight != null) { |
||||
this.sunLight.autoCalcShadowZBounds = true; //投影矩阵距离自适应
|
||||
} |
||||
} |
||||
else { |
||||
if (this.shadowGenerator != null) { |
||||
this.shadowGenerator.usePercentageCloserFiltering = false; |
||||
} |
||||
if (this.sunLight != null) { |
||||
this.sunLight.autoCalcShadowZBounds = false; //投影矩阵距离自适应
|
||||
} |
||||
} |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
//#region 高亮层
|
||||
|
||||
/** |
||||
* 高亮层 |
||||
*/ |
||||
highLightLayer: HighlightLayer; |
||||
|
||||
/** |
||||
* 添加到高亮层 |
||||
* @param mesh
|
||||
* @param color
|
||||
*/ |
||||
addToHighLight(mesh: Mesh, color: Color3) { |
||||
if (this.highLightLayer == null) { |
||||
this.highLightLayer = new HighlightLayer("highLight", this.scene); |
||||
this.highLightLayer.innerGlow = false; |
||||
} |
||||
|
||||
|
||||
let allMesh = mesh.getChildMeshes(); |
||||
this.highLightLayer.addMesh(mesh, color); |
||||
for (let i = 0; i < allMesh.length; i++) { |
||||
let childMesh = allMesh[i]; |
||||
if (childMesh instanceof Mesh) { |
||||
this.highLightLayer.addMesh(childMesh, color); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 移除出高亮层 |
||||
* @param mesh
|
||||
*/ |
||||
removeFromHighLight(mesh: Mesh) { |
||||
if (this.highLightLayer == null) { |
||||
return; |
||||
} |
||||
let allMesh = mesh.getChildMeshes(); |
||||
for (let i = 0; i < allMesh.length; i++) { |
||||
let childMesh = allMesh[i]; |
||||
if (childMesh instanceof Mesh) { |
||||
this.highLightLayer.removeMesh(childMesh); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 清空高亮层 |
||||
*/ |
||||
clearHighLight() { |
||||
this.highLightLayer.removeAllMeshes(); |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
//#region 三维场景的背景
|
||||
|
||||
public updateSceneBG() { |
||||
|
||||
this.scene.clearColor = new Color4(0, 0, 0, 1);//0.51, 0.63, 0.89
|
||||
this.scene.ambientColor = new Color3(1, 1, 1); |
||||
|
||||
if (SceneManager.s_openSkyBox) { |
||||
|
||||
if (this.skyBox == null) { |
||||
this.skyBox = Mesh.CreateBox("skyBox", 4000.0, this.scene); |
||||
let skyboxMaterial = new StandardMaterial("skyBox", this.scene); |
||||
skyboxMaterial.backFaceCulling = false; |
||||
skyboxMaterial.reflectionTexture = new CubeTexture("assets/skybox/default/default", this.scene); |
||||
skyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE; |
||||
skyboxMaterial.diffuseColor = new Color3(0, 0, 0); |
||||
skyboxMaterial.specularColor = new Color3(0, 0, 0); |
||||
skyboxMaterial.disableLighting = true; |
||||
this.skyBox.material = skyboxMaterial; |
||||
this.skyBox.renderingGroupId = -1; |
||||
} |
||||
else { |
||||
this.skyBox.setEnabled(true); |
||||
} |
||||
|
||||
if (this.ground3D != null) { |
||||
this.ground3D.setEnabled(false); |
||||
} |
||||
} |
||||
else { |
||||
if (this.ground3D == null) { |
||||
this.ground3D = MeshBuilder.CreateGround("ground", { width: 10000, height: 10000 }); |
||||
this.ground3D.position.y = -1.5; |
||||
|
||||
let mat_grid = new GridMaterial("mat_ground", SceneManager.Instance.scene); |
||||
|
||||
mat_grid.gridRatio = 10; |
||||
mat_grid.mainColor = new Color3(0, 0, 0); |
||||
mat_grid.lineColor = new Color3(0, 0.4, 1); |
||||
|
||||
this.ground3D.material = mat_grid; |
||||
this.ground3D.renderingGroupId = -1; |
||||
} |
||||
else { |
||||
this.ground3D.setEnabled(true); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
//环境反射
|
||||
if (SceneManager.s_openEnvironmentReflection) { |
||||
this.scene.environmentTexture = new CubeTexture("assets/skybox/city/city.env", this.scene); |
||||
SceneManager.s_environmentCubeTexture = this.scene.environmentTexture as CubeTexture; |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 场景声明周期与事件
|
||||
|
||||
public initSceneEvent() { |
||||
this.scene.onBeforeRenderObservable.add(SceneManager.onBeforeRender); |
||||
|
||||
this.scene.onPointerDown = SceneManager.onPointerDown; |
||||
this.scene.onPointerUp = SceneManager.onPointerUp; |
||||
this.scene.onPointerMove = SceneManager.onPointerMove; |
||||
|
||||
document.onkeydown = SceneManager.onKeyDown; |
||||
} |
||||
|
||||
|
||||
static showDebug = false; |
||||
//按键按下
|
||||
static onKeyDown(this: GlobalEventHandlers, ev: KeyboardEvent) { |
||||
if (ev.altKey && ev.key == 'd' && ModeManager.isDebug) { |
||||
SceneManager.showDebug = !SceneManager.showDebug; |
||||
if (SceneManager.showDebug) { |
||||
SceneManager.Instance.scene.debugLayer.show(); |
||||
} else { |
||||
SceneManager.Instance.scene.debugLayer.hide(); |
||||
} |
||||
} |
||||
Event_KeyboardInput.dispatch(ev); //派发给其他
|
||||
|
||||
} |
||||
|
||||
//场景渲染前
|
||||
static onBeforeRender(eventData: Scene, eventState: EventState) { |
||||
if (SceneManager.s_isPointerDown) { |
||||
SceneManager.s_downTime += SceneManager.Instance.scene.deltaTime; |
||||
} |
||||
} |
||||
|
||||
static s_isPointerDrag: boolean = false; //拖拽中
|
||||
static s_isPointerDown = false; //按下中
|
||||
static s_downTime = 0;//按下的时间
|
||||
|
||||
static readonly c_dragTime = 200;//超过则表示拖拽
|
||||
|
||||
//焦点按下
|
||||
private static onPointerDown( |
||||
evt: PointerEvent, |
||||
pickInfo: PickingInfo, |
||||
type: PointerEventTypes |
||||
) { |
||||
SceneManager.s_isPointerDown = true; |
||||
SceneManager.s_downTime = 0; |
||||
} |
||||
|
||||
//焦点移动
|
||||
private static onPointerMove( |
||||
evt: PointerEvent, |
||||
pickInfo: PickingInfo, |
||||
type: PointerEventTypes |
||||
) { |
||||
if (SceneManager.s_isPointerDown && SceneManager.s_downTime > SceneManager.c_dragTime) { |
||||
SceneManager.s_isPointerDrag = true; |
||||
} |
||||
|
||||
} |
||||
|
||||
//焦点抬起
|
||||
private static onPointerUp(evt: PointerEvent, pickInfo: PickingInfo) { |
||||
SceneManager.s_isPointerDown = false; |
||||
SceneManager.s_isPointerDrag = false; |
||||
SceneManager.s_downTime = 0; |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
//#region 操作模型
|
||||
//创建模型
|
||||
/** |
||||
* 加载模型 |
||||
* @param modelType
|
||||
* @param modelData
|
||||
* @param needBox
|
||||
* @param isNew
|
||||
* @param tag 加载的原因 |
||||
* @param onSuccess
|
||||
* @param onError
|
||||
* @param index 重试次数,超过五次就停止 |
||||
*/ |
||||
static createModel( |
||||
modelType: ModelType, |
||||
modelData: ModelData, |
||||
needBox: boolean, |
||||
isNew: boolean, |
||||
tag: string, |
||||
onSuccess?: ( |
||||
meshes: AbstractMesh[], |
||||
box: AbstractMesh, |
||||
modelInfo: ModelInfo |
||||
) => void, |
||||
onError?: ( |
||||
message: string |
||||
) => void, |
||||
index = 0 |
||||
) { |
||||
// console.log("准备加载");
|
||||
|
||||
let defaultMesh = MeshBuilder.CreateBox(modelData.key, { size: 0.01 }); |
||||
defaultMesh.scaling.y = 0.01; |
||||
defaultMesh.visibility = 0; |
||||
|
||||
let modelInfo: ModelInfo; |
||||
if (modelType == ModelType.Building) { |
||||
modelInfo = InfoManager.newModelInfo_building( |
||||
modelData.key, |
||||
modelData, |
||||
null, |
||||
defaultMesh |
||||
); |
||||
} |
||||
else if (modelType == ModelType.Facility) { |
||||
|
||||
modelInfo = new ModelInfo_facility(modelData.key, modelData, null, defaultMesh, null, isNew); |
||||
modelInfo.showFollowUI(false); |
||||
} |
||||
else if (modelType == ModelType.Mark) { |
||||
switch ((modelData as MarkData).type) { |
||||
case MarkType.JJQ: |
||||
case MarkType.QYSDA: |
||||
case MarkType.QYSDB: |
||||
modelData = plainToClass(MarkData_Area, modelData); |
||||
modelInfo = new ModelInfo_mark_area(modelData as MarkData, null, defaultMesh, null, isNew); |
||||
break; |
||||
case MarkType.JJX: |
||||
modelData = plainToClass(MarkData_Line, modelData); |
||||
modelInfo = new ModelInfo_mark_line(modelData as MarkData, null, defaultMesh, null, isNew); |
||||
break; |
||||
case MarkType.SD: |
||||
modelData = plainToClass(MarkData_multiLine, modelData); |
||||
modelInfo = new ModelInfo_mark_multiLine(modelData as MarkData, null, defaultMesh, null, isNew); |
||||
break; |
||||
case MarkType.JGLX: |
||||
modelData = plainToClass(MarkData_multiArrow_JG, modelData); |
||||
modelInfo = new ModelInfo_mark_multiArrow(modelData as MarkData, null, defaultMesh, null, isNew); |
||||
break; |
||||
case MarkType.CT: |
||||
modelData = plainToClass(MarkData_multiArrow_CT, modelData); |
||||
modelInfo = new ModelInfo_mark_multiArrow(modelData as MarkData, null, defaultMesh, null, isNew); |
||||
break; |
||||
case MarkType.H: |
||||
case MarkType.TPH: |
||||
case MarkType.SNH: |
||||
case MarkType.YWA: |
||||
case MarkType.YWB: |
||||
case MarkType.YWC: |
||||
modelInfo = new ModelInfo_mark_particle(modelData as MarkData, null, defaultMesh, null, isNew); |
||||
break; |
||||
|
||||
default: modelInfo = new ModelInfo_mark(modelData as MarkData, null, defaultMesh, null, isNew); |
||||
break; |
||||
} |
||||
|
||||
modelInfo.showFollowUI(false); |
||||
} |
||||
|
||||
if (modelData.isModel) { |
||||
let importMeshSyncData = SceneManager.getImportMeshSyncData(modelData.resPath, modelData.resName); |
||||
if (importMeshSyncData != null) //已经在加载了
|
||||
{ |
||||
importMeshSyncData.onsuccessObservable.add((eventData: ImportMeshSyncCallBack) => { |
||||
let box = SceneManager.importMeshSuccess(eventData.newMeshes, eventData.particleSystems, eventData.skeletons, eventData.animationGroups, eventData.modelInfo, eventData.needBox, eventData.modelData); |
||||
onSuccess(eventData.newMeshes, box, eventData.modelInfo); |
||||
}) |
||||
} |
||||
else { |
||||
|
||||
importMeshSyncData = SceneManager.startLoadMesh(modelData.resPath, modelData.resName); |
||||
BabylonTool.importMeshSync( |
||||
'', |
||||
modelData.resPath, |
||||
modelData.resName, |
||||
SceneManager.Instance.scene, |
||||
tag, |
||||
function (newMeshes: AbstractMesh[], particleSystems: IParticleSystem[], skeletons: Skeleton[], animationGroups: AnimationGroup[]) { |
||||
let callBack = new ImportMeshSyncCallBack(newMeshes, particleSystems, skeletons, animationGroups, modelInfo, needBox, modelData); |
||||
let allImportMeshSyncDatas = SceneManager.getAllImportMeshSyncData(modelData.resPath, modelData.resName); |
||||
for (let i = 0; i < allImportMeshSyncDatas.length; i++) { |
||||
allImportMeshSyncDatas[i].onsuccessObservable.notifyObservers(callBack); |
||||
} |
||||
SceneManager.endLoadMesh(modelData.resPath, modelData.resName); |
||||
let box = SceneManager.importMeshSuccess(newMeshes, particleSystems, skeletons, animationGroups, modelInfo, needBox, modelData); |
||||
console.log("加载模型完成", modelData.resName); |
||||
onSuccess(newMeshes, box, modelInfo); |
||||
}, null, |
||||
function (scene: Scene, message: string, exception?: any) { |
||||
|
||||
if (index < 5) { |
||||
let l_index = index + 1; |
||||
modelInfo.dispose(); |
||||
importMeshSyncData.isBreak = true;//中断
|
||||
|
||||
SceneManager.createModel(modelType, modelData, needBox, isNew, tag, onSuccess, onError, l_index); |
||||
|
||||
console.log("重新开始加载" + l_index, modelData); |
||||
console.log(exception); |
||||
} |
||||
else { |
||||
modelInfo.dispose(); |
||||
console.log(message); |
||||
console.log(exception); |
||||
// alert("模型加载失败: " + message + "==" + exception);
|
||||
// alert(exception);
|
||||
if (onError) { |
||||
onError(message) |
||||
} |
||||
} |
||||
} |
||||
); |
||||
} |
||||
} |
||||
else { |
||||
onSuccess([], defaultMesh, modelInfo); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 加载完成的回调 |
||||
* @param newMeshes
|
||||
* @param particleSystems
|
||||
* @param skeletons
|
||||
* @param animationGroups
|
||||
*/ |
||||
static importMeshSuccess(newMeshes: AbstractMesh[], particleSystems: IParticleSystem[], skeletons: Skeleton[], animationGroups: AnimationGroup[], modelInfo: ModelInfo, needBox: boolean, modelData: ModelData) { |
||||
SceneManager.addModel(modelInfo); |
||||
let box: AbstractMesh = null; |
||||
if (needBox) { |
||||
box = BoundingBoxGizmo.MakeNotPickableAndWrapInBoundingBox( |
||||
newMeshes[0] as Mesh |
||||
); |
||||
|
||||
box.isPickable = false; |
||||
box.name = modelData.key; |
||||
box.rotationQuaternion = undefined; |
||||
modelInfo.models = newMeshes; |
||||
modelInfo.modelBox = box; |
||||
modelInfo.animationGroups = animationGroups; |
||||
if (animationGroups != null && animationGroups.length > 0) { |
||||
animationGroups[0].stop(); |
||||
} |
||||
|
||||
let canPick = false; |
||||
for (let i = 0; i < newMeshes.length; i++) { |
||||
//if (newMeshes[i].name.match("Floor") || newMeshes[i].name.match("floor") || newMeshes[i].name.match("Terrain")) {
|
||||
newMeshes[i].isPickable = true; |
||||
canPick = true; |
||||
//}
|
||||
|
||||
if (SceneManager.s_openShadow) { |
||||
newMeshes[i].receiveShadows = true; |
||||
|
||||
// let mat = newMeshes[i].material;
|
||||
//if (mat instanceof PBRMaterial && TsTool.stringContain(mat.name, "glass")) {
|
||||
// mat.refractionTexture = SceneManager.s_environmentCubeTexture;//折射
|
||||
// mat.reflectionTexture = SceneManager.s_prefabSkyBoxCubeTexture;//反射
|
||||
// mat.invertRefractionY = true;
|
||||
//}
|
||||
} |
||||
} |
||||
|
||||
if (!SceneManager.s_openLight) { |
||||
BabylonTool.setMatToUnlit(newMeshes, true, "Color"); //无光材质
|
||||
BabylonTool.setMatSheen(newMeshes, true, true); |
||||
} |
||||
|
||||
|
||||
// SceneManager.instance.shadowGenerator.addShadowCaster(newMeshes[0], true);
|
||||
|
||||
//如果是建筑,内部还没找到可接受pick的特定mesh,则整体可接受pick
|
||||
if (modelInfo instanceof ModelInfo_building && !canPick) { |
||||
//box.isPickable = true;
|
||||
let ground = MeshBuilder.CreateBox("ground", { size: 1 }); |
||||
ground.scaling = new Vector3(box.scaling.x, 0.1, box.scaling.z); |
||||
ground.setParent(box); |
||||
ground.rotationQuaternion = Quaternion.Zero(); |
||||
ground.position = new Vector3(0, -0.5, 0); |
||||
ground.visibility = 0.01; |
||||
|
||||
} |
||||
|
||||
// if (modelInfo instanceof ModelInfo_building) {
|
||||
// for (let i = 0; i < newMeshes.length; i++) {
|
||||
// newMeshes[i].receiveShadows = true;
|
||||
// }
|
||||
|
||||
// }
|
||||
} |
||||
return box |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 正在加载的模型数据 |
||||
*/ |
||||
static s_ImportMeshSyncData: ImportMeshSyncData[] = []; |
||||
|
||||
/** |
||||
* 开始加载模型 |
||||
*/ |
||||
static startLoadMesh(path: string, name: string) { |
||||
let importMeshSyncData = new ImportMeshSyncData(path, name); |
||||
|
||||
SceneManager.s_ImportMeshSyncData.push(importMeshSyncData); |
||||
|
||||
return importMeshSyncData |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* 结束加载模型 |
||||
* @param path
|
||||
* @param name
|
||||
*/ |
||||
static endLoadMesh(path: string, name: string) { |
||||
let datas = SceneManager.getAllImportMeshSyncData(path, name); |
||||
for (let i = 0; i < datas.length; i++) { |
||||
TsTool.arrayRemove(SceneManager.s_ImportMeshSyncData, datas[i]); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 查询加载模型的数据(确实在加载的) |
||||
* @param path
|
||||
* @param name
|
||||
*/ |
||||
static getImportMeshSyncData(path: string, name: string) { |
||||
let result: ImportMeshSyncData = null; |
||||
for (let i = 0; i < SceneManager.s_ImportMeshSyncData.length; i++) { |
||||
let data = SceneManager.s_ImportMeshSyncData[i]; |
||||
if (data.path == path && data.name == name && data.isBreak == false) { |
||||
result = data; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 获取所有的加载信息(失败时,会产生多份) |
||||
* @param path
|
||||
* @param name
|
||||
*/ |
||||
static getAllImportMeshSyncData(path: string, name: string) { |
||||
let result: ImportMeshSyncData[] = []; |
||||
for (let i = 0; i < SceneManager.s_ImportMeshSyncData.length; i++) { |
||||
let data = SceneManager.s_ImportMeshSyncData[i]; |
||||
if (data.path == path && data.name == name) { |
||||
result.push(data); |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
//克隆模型
|
||||
static cloneMesh( |
||||
key, |
||||
modelInfo: ModelInfo, |
||||
prefab: Mesh, |
||||
name?: string |
||||
): Mesh { |
||||
let result = BabylonTool.cloneMesh(prefab); |
||||
|
||||
if (SceneManager.s_openShadow) { |
||||
SceneManager.Instance.shadowGenerator.addShadowCaster(result); |
||||
} |
||||
SceneManager.addModel(modelInfo); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
//获取模型
|
||||
static getModel(modelKey: string): ModelInfo { |
||||
let result = null; |
||||
if (SceneManager.s_allModelInfo != null) { |
||||
for (let i = 0; i < SceneManager.s_allModelInfo.length; i++) { |
||||
let l_modelInfo = SceneManager.s_allModelInfo[i]; |
||||
if (l_modelInfo.key == modelKey) { |
||||
return l_modelInfo; |
||||
} |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
//获取模型
|
||||
static getModelById(uniqueId: number): ModelInfo { |
||||
let result = null; |
||||
if (SceneManager.s_allModelInfo != null) { |
||||
for (let i = 0; i < SceneManager.s_allModelInfo.length; i++) { |
||||
let l_modelInfo = SceneManager.s_allModelInfo[i]; |
||||
if (l_modelInfo.modelBox.uniqueId == uniqueId) { |
||||
return l_modelInfo; |
||||
} |
||||
} |
||||
} |
||||
console.log('没找到:' + uniqueId); |
||||
return result; |
||||
} |
||||
|
||||
//删除模型
|
||||
static destroyModel(model: string | ModelInfo) { |
||||
let modelInfo: ModelInfo; |
||||
|
||||
if (model instanceof ModelInfo) { |
||||
modelInfo = model; |
||||
} else { |
||||
modelInfo = SceneManager.getModel(model); |
||||
} |
||||
if (modelInfo == null) { |
||||
return; |
||||
} else { |
||||
TsTool.arrayRemove(SceneManager.s_allModelInfo, modelInfo); |
||||
modelInfo.dispose(); |
||||
} |
||||
|
||||
} |
||||
|
||||
//添加模型
|
||||
private static addModel(modelInfo: ModelInfo) { |
||||
SceneManager.s_allModelInfo.push(modelInfo); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 聚焦当前选中的目标 |
||||
*/ |
||||
public static lookAtCurrentSelect() { |
||||
if (GizmoTool.s_nowPickAim_mesh != null) { |
||||
BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, GizmoTool.s_nowPickAim_mesh, true); |
||||
} |
||||
else { |
||||
ModeManager.log("没有选中的目标"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 模型的Y方向吸附 |
||||
* @param mover 行动者 |
||||
* @param target 吸附的目标物 |
||||
*/ |
||||
public static meshAdsorbY(mover: AbstractMesh, target: AbstractMesh, pickPos: Vector3) { |
||||
|
||||
ModeManager.log("吸附模型" + target); |
||||
|
||||
let targetRoot = SceneManager.getRootTransformNode(target); |
||||
|
||||
if (mover == targetRoot) { |
||||
return; |
||||
} |
||||
let aimPos_y: number = 0; |
||||
|
||||
let direction = 0.5; |
||||
if (mover.absolutePosition.y < pickPos.y) { |
||||
direction = -0.5; |
||||
} |
||||
|
||||
aimPos_y += mover.scaling.y * direction; |
||||
|
||||
let newPos = new Vector3(mover.absolutePosition.x, pickPos.y + aimPos_y, mover.absolutePosition.z) |
||||
|
||||
mover.setAbsolutePosition(newPos); |
||||
} |
||||
|
||||
|
||||
//获取根节点
|
||||
public static getRootTransformNode(mesh: AbstractMesh): TransformNode { |
||||
let result: TransformNode = mesh; |
||||
let parent: any = mesh; |
||||
while (true) { |
||||
if (parent.id == "ground" || parent.id.match("Floor")) { |
||||
result = parent; |
||||
return result; |
||||
} |
||||
|
||||
parent = parent.parent; |
||||
if (parent == null) { |
||||
return mesh; |
||||
} |
||||
else if (parent.id == "box") { |
||||
result = parent; |
||||
return result; |
||||
} |
||||
else { |
||||
result = parent; |
||||
} |
||||
} |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 正在异步导入模型的数据 |
||||
*/ |
||||
class ImportMeshSyncData { |
||||
path: string; |
||||
name: string; |
||||
isBreak: boolean; //中断了
|
||||
|
||||
onsuccessObservable: Observable<ImportMeshSyncCallBack>; |
||||
|
||||
constructor(path: string, |
||||
name: string) { |
||||
this.isBreak = false; |
||||
this.path = path; |
||||
this.name = name; |
||||
this.onsuccessObservable = new Observable(); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 异步导入模型的回调 |
||||
*/ |
||||
class ImportMeshSyncCallBack { |
||||
|
||||
newMeshes: AbstractMesh[]; |
||||
particleSystems: IParticleSystem[]; |
||||
skeletons: Skeleton[]; |
||||
animationGroups: AnimationGroup[]; |
||||
modelInfo: ModelInfo; |
||||
needBox: boolean; |
||||
modelData: ModelData; |
||||
|
||||
constructor(newMeshes: AbstractMesh[], |
||||
particleSystems: IParticleSystem[], |
||||
skeletons: Skeleton[], |
||||
animationGroups: AnimationGroup[], |
||||
modelInfo: ModelInfo, |
||||
needBox: boolean, |
||||
modelData: ModelData) { |
||||
this.newMeshes = newMeshes; |
||||
this.particleSystems = particleSystems; |
||||
this.skeletons = skeletons; |
||||
this.animationGroups = animationGroups; |
||||
this.modelInfo = modelInfo; |
||||
this.needBox = needBox; |
||||
this.modelData = modelData; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,242 @@
|
||||
import { HttpErrorResponse } from "@angular/common/http"; |
||||
import { classToPlain } from "class-transformer"; |
||||
import { BuildingBasicInfosService } from "src/app/service/babylon/building-basic-infos.service"; |
||||
import { ObjectsService } from "src/app/service/babylon/objects.service"; |
||||
import { InsitutionDataSimple } from "../model/data/institution/institution-data-simple"; |
||||
import { AllMarkPlanData } from "../model/data/mark/mark-plan-data"; |
||||
import { ModeManager } from "./mode-manager"; |
||||
|
||||
//服务器通信
|
||||
export class ServeManager { |
||||
|
||||
static ngAssetsPath = "assets/";//资源根目录
|
||||
|
||||
static instance: ServeManager = null; |
||||
|
||||
postFilePath: string;//上传文件的相对路径
|
||||
|
||||
static Init(buildingBISrv: BuildingBasicInfosService, objectsSrv: ObjectsService) { |
||||
ServeManager.instance = new ServeManager(buildingBISrv, objectsSrv); |
||||
} |
||||
|
||||
constructor( |
||||
private buildingBISrv: BuildingBasicInfosService, |
||||
private objectsSrv: ObjectsService |
||||
) { |
||||
//this.fileInput = document.getElementById("file");
|
||||
|
||||
} |
||||
|
||||
//从服务器获取单位信息
|
||||
getInstitutionData(key: string = 'test', onSuccess?: (key: string, |
||||
data: string |
||||
) => void, onError?: (key: string, error: any) => void) { |
||||
this.buildingBISrv.getBuildingBasicInfos(key) |
||||
.subscribe(data => { |
||||
|
||||
if (onSuccess) { |
||||
onSuccess(key, data); |
||||
} |
||||
}, error => { |
||||
console.error("From serve" + key + "===" + error); |
||||
if (onError) { |
||||
onError(key, error); |
||||
} |
||||
}) |
||||
} |
||||
|
||||
//保存单位信息
|
||||
saveInstitutionData(institutionData: any, key: string = 'test', onSuccess?: (key: string, |
||||
result: string |
||||
) => void, onError?: (key: string, error: string) => void) { |
||||
let data = classToPlain(institutionData); |
||||
|
||||
console.log(data); |
||||
this.buildingBISrv.postBuildingBasicInfos(key, data) |
||||
.subscribe(data => { |
||||
ModeManager.log("保存单位成功:" + key); |
||||
if (onSuccess) { |
||||
onSuccess(key, data); |
||||
} |
||||
if (key != "InsList") { |
||||
//ThreeDimensionalHomeComponent.instance.openSnackBar("保存单位成功");
|
||||
// alert("保存单位成功");
|
||||
} |
||||
|
||||
|
||||
//暂时没有失败的回调 onError
|
||||
}) |
||||
} |
||||
|
||||
//保存单位列表
|
||||
saveInstitutionListData(institutionList: InsitutionDataSimple[], onSucess?: () => void) { |
||||
// console.log("======保存单位");
|
||||
|
||||
ServeManager.instance.saveInstitutionData(institutionList, "InsList", () => { |
||||
//alert("保存单位列表成功");
|
||||
if (onSucess) { |
||||
onSucess(); |
||||
} |
||||
}) |
||||
} |
||||
|
||||
//#region 态势标会
|
||||
|
||||
/** |
||||
* 获取态势标会信息 |
||||
* @param institutionID
|
||||
* @param onSuccess
|
||||
* @param onError
|
||||
*/ |
||||
getMarkData(institutionID: string, |
||||
onSuccess?: (institutionID: string, data: string) => void, |
||||
onError?: (institutionID: string, error: any) => void) { |
||||
|
||||
this.buildingBISrv.getMarkData(institutionID) |
||||
.subscribe(data => { |
||||
ModeManager.log(data); |
||||
if (onSuccess) { |
||||
onSuccess(institutionID, data); |
||||
} |
||||
}, (error) => { |
||||
if (error instanceof HttpErrorResponse) { |
||||
if (error.status === 404) { |
||||
ModeManager.log("没有标绘数据,新建:" + error.error); |
||||
onSuccess(institutionID, null); //data 为null ,表示新建
|
||||
} |
||||
else { |
||||
if (onError) { |
||||
onError(institutionID, error); |
||||
} |
||||
} |
||||
} |
||||
if (onError) { |
||||
onError(institutionID, error); |
||||
} |
||||
}) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 保存态势标会信息 |
||||
*/ |
||||
saveMarkData(allMarkPlanData: AllMarkPlanData, |
||||
onSuccess?: (key: string, result: string) => void, |
||||
onError?: (key: string, error: string) => void) { |
||||
|
||||
if (allMarkPlanData == null) { |
||||
console.error("标绘信息为空,无法保存"); |
||||
} |
||||
else { |
||||
let data = classToPlain(allMarkPlanData); |
||||
this.buildingBISrv.postMarkData(allMarkPlanData.institutionID, data) |
||||
.subscribe(data => { |
||||
ModeManager.log("保存标绘信息成功:" + allMarkPlanData.institutionID); |
||||
if (onSuccess) { |
||||
onSuccess(allMarkPlanData.institutionID, data); |
||||
} |
||||
// ThreeDimensionalHomeComponent.instance.openSnackBar("保存标绘信息成功");
|
||||
// alert("保存标绘信息成功");
|
||||
|
||||
//暂时没有失败的回调 onError
|
||||
}) |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//#region 文件上传
|
||||
//队列性,批量上传
|
||||
uploadFile(index: number, files: File[], resPath_out, onOneSuccess: (name: string, path: string, file: File) => void, onEnd: () => void) { |
||||
if (index < files.length) { |
||||
ServeManager.instance.openFileSelect(files[index], resPath_out, (name: string, path: string, file: File) => { |
||||
onOneSuccess(name, path, file); |
||||
this.uploadFile(index + 1, files, resPath_out, onOneSuccess, onEnd); |
||||
|
||||
}); |
||||
} |
||||
else { |
||||
onEnd(); |
||||
} |
||||
} |
||||
|
||||
|
||||
//设置文件路径并上传
|
||||
openFileSelect(file: File, extensionPath: string, onSuccess?: (name: string, path: string, file: File) => void) { |
||||
this.postFilePath = extensionPath; |
||||
|
||||
this.onPostFileSuccess = onSuccess; |
||||
|
||||
let fileSize = file.size || null //上传文件的总大小
|
||||
let shardSize = 5 * 1024 * 1024 //5MB 超过5MB要分块上传
|
||||
if (fileSize >= shardSize) // 超过5MB要分块上传
|
||||
{ |
||||
this.postFileByMul(file); |
||||
} |
||||
else //普通上传
|
||||
{ |
||||
this.postFile(file); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
//上传成功
|
||||
onPostFileSuccess?: (name: string, path: string, file: File) => void; |
||||
|
||||
//上传文件
|
||||
async postFile(file: File) { |
||||
await new Promise((resolve, reject) => { |
||||
|
||||
ServeManager.instance.objectsSrv.postFile(ServeManager.ngAssetsPath + this.postFilePath, file).subscribe(data => { |
||||
let dataObj = data as any; |
||||
let fileName = dataObj.fileName; |
||||
let filePath: string = dataObj.objectName; |
||||
filePath = filePath.replace(fileName, ""); |
||||
filePath = ObjectsService.baseUrl + filePath; |
||||
ServeManager.instance.onGetPostFileResult(fileName, filePath, file); |
||||
resolve('success') |
||||
}); |
||||
}) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 上传文件的结果 |
||||
* @param data
|
||||
* @param file
|
||||
*/ |
||||
onGetPostFileResult(fileName: string, filePath: string, file: File) { |
||||
|
||||
|
||||
if (ServeManager.instance.onPostFileSuccess) { |
||||
ServeManager.instance.onPostFileSuccess(fileName, filePath, file); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 分块上传 |
||||
* @param file
|
||||
*/ |
||||
postFileByMul(file: File) { |
||||
ServeManager.instance.objectsSrv.postFile_MultipartUpload(ServeManager.ngAssetsPath + this.postFilePath, file).then((value) => { |
||||
let dataObj = value as any; |
||||
ServeManager.instance.onGetPostFileResult(dataObj.fileName, dataObj.filePath, file); |
||||
}); |
||||
|
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,164 @@
|
||||
|
||||
import { Observable, Observer } from "@babylonjs/core"; |
||||
import { Game } from "../../game"; |
||||
import { BuildingType, BuildingData } from "../../model/data/institution/building/building-data"; |
||||
import { FacilityPosType, ModelData_facility } from "../../model/data/model-data/model-data-facility"; |
||||
import { ModelEditData } from "../../model/data/model-data/model-edit-data"; |
||||
import { BuildingInfo } from "../../model/info/building/building-info"; |
||||
import { GizmoTool } from "../../tool/gizmo-tool"; |
||||
import { BuildingUIItem } from "../../view/building-window/building-ui-item"; |
||||
import { BuildingWindow } from "../../view/building-window/building-window"; |
||||
import { FacilityWindow } from "../../view/facility-window/facility-window"; |
||||
import { FacilityInfoInSceneWindow } from "../../view/facilityinfoinscene-window/facilityinfoinscene-window"; |
||||
import { MarkWindow } from "../../view/mark-window/mark-window"; |
||||
import { ToolbarWindow } from "../../view/toolbar-window/toobar-window"; |
||||
|
||||
import { DataManager, ModelChangeType } from "../data-manager"; |
||||
import { EventManager } from "../event-manager/event-manager"; |
||||
import { Event_ChangeFacility } from "../event-manager/events/event-change-facility"; |
||||
import { InfoManager } from "../info-manager"; |
||||
import { ModeManager, ModeType } from "../mode-manager"; |
||||
import { SceneManager } from "../scene-manager"; |
||||
import { UIManager } from "../ui-manager"; |
||||
import { StatusBase, StatusManager } from "./status-manager"; |
||||
|
||||
//建筑物外观模式
|
||||
export class BuildingStatus extends StatusBase { |
||||
buildingWindow: BuildingWindow; |
||||
currentBuildingInfo: BuildingInfo; //当前的建筑
|
||||
onChangeFacilityObserver: Observer<Event_ChangeFacility>; |
||||
|
||||
static changeStatusFromUI: boolean = false;//因为ui而切换
|
||||
static startEnterObservable: Observable<BuildingUIItem> = new Observable<BuildingUIItem>();//开始切入
|
||||
static enterSuccessObservable: Observable<BuildingUIItem> = new Observable<BuildingUIItem>();//进入成功的事件
|
||||
|
||||
|
||||
//#region
|
||||
/** |
||||
* 在数据层创建建筑 |
||||
* @param key 唯一key,来自服务器分配 |
||||
* @param name 名称,由玩家自定义 |
||||
* @param buildingType 建筑类型 |
||||
*/ |
||||
createOneBuildingInData(key: string, name: string, buildingType: BuildingType): BuildingData { |
||||
return DataManager.createBuilding(key, name, buildingType); |
||||
} |
||||
//#endregion
|
||||
|
||||
//#region 生命周期
|
||||
//初始化
|
||||
onCreate() { |
||||
super.onCreate(); |
||||
// this.enterSuccessObservable = new Observable<BuildingUIItem>();
|
||||
GizmoTool.init(SceneManager.Instance.scene, UIManager.Instance.uiRoot, SceneManager.Instance.defaultCamera); |
||||
InfoManager.init(); |
||||
//UIManager.open<InputHintWindow>(InputHintWindow);
|
||||
UIManager.open<ToolbarWindow>(ToolbarWindow); |
||||
} |
||||
//进入状态
|
||||
onEnter() { |
||||
super.onEnter(); |
||||
Game.instance.engine.resize(); |
||||
|
||||
//首次进入
|
||||
if (this.buildingWindow == null) { |
||||
SceneManager.s_facilityWindow = UIManager.open<FacilityWindow>(FacilityWindow); |
||||
if (ModeManager.currentMode == ModeType.Look) { |
||||
//此处应改为由前端调用, 退出编辑状态时应调用hide
|
||||
// SceneManager.s_markWindow = MarkWindow.openWindow();
|
||||
} |
||||
|
||||
this.buildingWindow = UIManager.open<BuildingWindow>(BuildingWindow); |
||||
|
||||
SceneManager.s_facilityInfoInSceneWindow = UIManager.open<FacilityInfoInSceneWindow>(FacilityInfoInSceneWindow); |
||||
|
||||
} |
||||
else { //从室内返回
|
||||
UIManager.show<BuildingWindow>(this.buildingWindow); |
||||
if (this.buildingWindow.currentBuidngItem != null) { |
||||
this.buildingWindow.currentBuidngItem.select(); |
||||
BuildingStatus.startEnterObservable.notifyObservers(this.buildingWindow.currentBuidngItem); |
||||
BuildingStatus.enterSuccessObservable.notifyObservers(this.buildingWindow.currentBuidngItem) |
||||
if (MarkWindow.s_cameraData == null) { |
||||
this.buildingWindow.currentBuidngItem.lookAt(); |
||||
} |
||||
else { |
||||
|
||||
MarkWindow.s_cameraData.setDataToCamera(SceneManager.Instance.defaultCamera); |
||||
MarkWindow.s_cameraData = null; |
||||
} |
||||
|
||||
FacilityInfoInSceneWindow.instance.createAllFacilities(this.buildingWindow.currentBuidngItem.buildingInfo.ModelInfo.facilityInfos); |
||||
if (ModeManager.currentMode == ModeType.Look) { |
||||
FacilityInfoInSceneWindow.instance.showFacilityByType(null, false); |
||||
} |
||||
} |
||||
} |
||||
|
||||
SceneManager.s_facilityWindow.updateAllFacilities(FacilityPosType.Outdoor); |
||||
|
||||
let instance = this; |
||||
this.onChangeFacilityObserver = EventManager.addListener<Event_ChangeFacility>(Event_ChangeFacility, ((eventInfo) => { |
||||
instance.onChangeFacility(eventInfo); |
||||
})); |
||||
|
||||
SceneManager.Instance.sunLight.intensity = 3; |
||||
} |
||||
//退出状态
|
||||
onExit() { |
||||
UIManager.hide<BuildingWindow>(this.buildingWindow); |
||||
// console.log("==退出buildingStatus==");
|
||||
EventManager.removeListener(Event_ChangeFacility, this.onChangeFacilityObserver); |
||||
super.onExit(); |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
//改变当前选中的建筑
|
||||
changeCurrentBuilding(buildingInfo: BuildingInfo) { |
||||
|
||||
if (buildingInfo == this.currentBuildingInfo) { |
||||
return; |
||||
} |
||||
|
||||
// console.log("改变当前建筑" + buildingInfo.buildingData.normalData.key);
|
||||
//FacilityInfoInSceneWindow.instance.clearFacilityInfoUIItemes();
|
||||
if (this.currentBuildingInfo != null) { |
||||
// this.buildingWindow.clearFacilityInfos(this.currentBuildingInfo);
|
||||
//隐藏
|
||||
this.buildingWindow.showFacilityInfosIcon(this.currentBuildingInfo, false); |
||||
} |
||||
|
||||
this.currentBuildingInfo = buildingInfo; |
||||
|
||||
|
||||
FacilityInfoInSceneWindow.instance.createAllFacilities(buildingInfo.ModelInfo.facilityInfos); |
||||
if (this.currentBuildingInfo.ModelInfo.facilityInfos != null && ModeManager.currentMode == ModeType.Edit) { |
||||
//判断已经有了就不创建了
|
||||
// InfoManager.createFacilityInfos(buildingInfo.buildingData.outdoorData, buildingInfo);
|
||||
//显示
|
||||
this.buildingWindow.showFacilityInfosIcon(this.currentBuildingInfo, true); |
||||
} |
||||
|
||||
} |
||||
|
||||
//模型变化
|
||||
onChangeFacility(eventInfo: Event_ChangeFacility) { |
||||
if (eventInfo.modeleData instanceof ModelData_facility) { |
||||
let modelEditData: ModelEditData; |
||||
if (StatusManager.s_currentStatus instanceof BuildingStatus) { |
||||
modelEditData = this.currentBuildingInfo.buildingData.outdoorData; |
||||
} |
||||
|
||||
if (eventInfo.modelChangeType == ModelChangeType.Add) { |
||||
modelEditData.addFacility(eventInfo.modeleData); |
||||
// console.log("添加设备数据" + eventInfo.modeleData.key);
|
||||
} |
||||
else if (eventInfo.modelChangeType == ModelChangeType.Remove) { |
||||
modelEditData.removeFacility(eventInfo.modeleData); |
||||
|
||||
// console.log("移除设备数据" + eventInfo.modeleData.key);
|
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,127 @@
|
||||
import { Observable, Observer } from "@babylonjs/core"; |
||||
import { BuildingData_Normal } from "../../model/data/institution/building/building-data"; |
||||
import { ModelData } from "../../model/data/model-data/model-data"; |
||||
import { FacilityPosType, ModelData_facility } from "../../model/data/model-data/model-data-facility"; |
||||
import { ModelEditData } from "../../model/data/model-data/model-edit-data"; |
||||
import { BuildingInfo_Normal } from "../../model/info/building/building-info-normal"; |
||||
import { GizmoTool } from "../../tool/gizmo-tool"; |
||||
import { IndoorFloorUIItem } from "../../view/indoor-window/indoor-floorui-item"; |
||||
import { IndoorWindow } from "../../view/indoor-window/indoor-window"; |
||||
|
||||
import { ModelChangeType } from "../data-manager"; |
||||
import { EventManager } from "../event-manager/event-manager"; |
||||
import { Event_ChangeFacility } from "../event-manager/events/event-change-facility"; |
||||
import { SceneManager } from "../scene-manager"; |
||||
import { UIManager } from "../ui-manager"; |
||||
import { StatusBase, StatusManager } from "./status-manager"; |
||||
|
||||
//室内模式
|
||||
export class IndoorStatus extends StatusBase { |
||||
buildingInfo: BuildingInfo_Normal; |
||||
indoorWindow: IndoorWindow; |
||||
|
||||
//indoorInfos:BuildingInfo[];//室内信息(运行时)
|
||||
indoorData: BuildingData_Normal; //室内信息(纯数据)
|
||||
|
||||
onChangeFacilityObserver: Observer<Event_ChangeFacility>; |
||||
|
||||
static changeStatusFromUI: boolean = false;//因为ui而切换
|
||||
static startEnterObservable: Observable<IndoorFloorUIItem> = new Observable<IndoorFloorUIItem>();//开始切入
|
||||
static enterSuccessObservable: Observable<IndoorFloorUIItem> = new Observable<IndoorFloorUIItem>();//进入成功的事件
|
||||
|
||||
//初始化
|
||||
onCreate() { |
||||
super.onCreate(); |
||||
// this.enterSuccessObservable = new Observable<IndoorFloorUIItem>();
|
||||
} |
||||
//进入状态
|
||||
onEnter() { |
||||
super.onEnter(); |
||||
if (this.indoorWindow == null) { |
||||
this.indoorWindow = UIManager.open<IndoorWindow>(IndoorWindow); |
||||
} else { |
||||
UIManager.show<IndoorWindow>(this.indoorWindow); |
||||
} |
||||
|
||||
let instance = this; |
||||
this.onChangeFacilityObserver = EventManager.addListener<Event_ChangeFacility>(Event_ChangeFacility, (eventInfo) => { |
||||
instance.onChangeFacility(eventInfo); |
||||
}) |
||||
|
||||
GizmoTool.onPickMeshInfoObservable.notifyObservers(null);//取消之前的选中
|
||||
|
||||
SceneManager.s_facilityInfoInSceneWindow.clearFacilityInfoUIItemes();//先清空
|
||||
SceneManager.s_facilityWindow.updateAllFacilities(FacilityPosType.Indoor); |
||||
SceneManager.Instance.sunLight.intensity = 1; |
||||
} |
||||
//退出状态
|
||||
onExit() { |
||||
EventManager.removeListener(Event_ChangeFacility, this.onChangeFacilityObserver); |
||||
UIManager.hide<IndoorWindow>(this.indoorWindow); |
||||
this.clearIndoorInfo(); |
||||
super.onExit(); |
||||
} |
||||
|
||||
init(buildingInfo: BuildingInfo_Normal, key: string) { |
||||
this.buildingInfo = buildingInfo; |
||||
this.indoorData = buildingInfo.buildingData as BuildingData_Normal; |
||||
|
||||
this.indoorWindow.initAllFloor(this.indoorData.indoorsData, key); |
||||
} |
||||
|
||||
//清空室内运行时信息
|
||||
clearIndoorInfo() { |
||||
console.log('清空室内'); |
||||
this.indoorWindow.clearAllFloorUIItem(); |
||||
|
||||
if (this.indoorWindow.currentFloorUIItem != null && |
||||
this.indoorWindow.currentFloorUIItem.buildingInfo != null) { |
||||
GizmoTool.leaveTheGizmoAim(this.indoorWindow.currentFloorUIItem.buildingInfo.ModelInfo); |
||||
} |
||||
|
||||
this.indoorWindow.currentFloorUIItem = null; |
||||
} |
||||
|
||||
//模型Data数据变化
|
||||
onChangeFacility(eventInfo: Event_ChangeFacility) { |
||||
if (eventInfo.modeleData instanceof ModelData_facility) { |
||||
let modelEditData: ModelEditData; |
||||
|
||||
modelEditData = (StatusManager.s_currentStatus as IndoorStatus) |
||||
.indoorWindow.currentFloorUIItem.modelEditData; |
||||
|
||||
if (eventInfo.modelChangeType == ModelChangeType.Add) { |
||||
modelEditData.addFacility(eventInfo.modeleData); |
||||
} else if (eventInfo.modelChangeType == ModelChangeType.Remove) { |
||||
modelEditData.removeFacility(eventInfo.modeleData); |
||||
} |
||||
} |
||||
} |
||||
|
||||
//创建新的室内数据
|
||||
newIndoorData(key: string, name: string, isRefugeFloor: boolean): ModelEditData { |
||||
let newIndoorData = new ModelEditData(); |
||||
|
||||
newIndoorData.modelData = new ModelData(); |
||||
newIndoorData.modelData.key = key; |
||||
newIndoorData.modelData.name = name; |
||||
newIndoorData.isRefugeFloor = isRefugeFloor; |
||||
return newIndoorData; |
||||
} |
||||
|
||||
//将新的室内添加到当前建筑中
|
||||
addNewIndoorToBuilding(newIndoorData: ModelEditData) { |
||||
let buildingData = this.buildingInfo.buildingData as BuildingData_Normal; |
||||
if (buildingData.indoorsData == null) { |
||||
buildingData.indoorsData = []; |
||||
} |
||||
newIndoorData.index = buildingData.getNextIndoorIndex(); |
||||
//设置index为最大+1
|
||||
buildingData.indoorsData.push(newIndoorData); |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,224 @@
|
||||
import { HttpErrorResponse } from "@angular/common/http"; |
||||
import { plainToClass } from "class-transformer"; |
||||
import { InstitutionData, NormalData } from "../../model/data/institution/institution-data"; |
||||
import { InsitutionDataSimple } from "../../model/data/institution/institution-data-simple"; |
||||
import { BabylonTool } from "../../tool/babylon-tool"; |
||||
import { InstitutionCreateWindow } from "../../view/institution/institution-create-window"; |
||||
import { InstitutionSelectWindow } from "../../view/institution/institution-select-window"; |
||||
import { TopbarWindow } from "../../view/topbar-window/topbar-window"; |
||||
|
||||
import { DataManager } from "../data-manager"; |
||||
import { SceneManager } from "../scene-manager"; |
||||
import { ServeManager } from "../serve-manager"; |
||||
import { UIManager } from "../ui-manager"; |
||||
import { MainStatus } from "./main-status"; |
||||
import { StatusBase, StatusManager } from "./status-manager"; |
||||
|
||||
export class LoginSatus extends StatusBase { |
||||
|
||||
institutionSelectWindow: InstitutionSelectWindow; |
||||
|
||||
institutionCreateWindow: InstitutionCreateWindow; |
||||
|
||||
institutionList: InsitutionDataSimple[];//单位简易信息列表
|
||||
|
||||
|
||||
//#region 前端对接
|
||||
|
||||
/** |
||||
* 新建单位 |
||||
* @param insData 新的单位信息 |
||||
*/ |
||||
createInsitution(key: string, name: string, onSuccess?: (insDataSimple: InsitutionDataSimple) => void) { |
||||
|
||||
if (key == null) { |
||||
console.error("创建单位key为null"); |
||||
return; |
||||
} |
||||
let insData = new InstitutionData(); |
||||
insData.normalData = new NormalData(key, name); |
||||
|
||||
this.saveNewIns(this, insData, key, onSuccess); |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 外部方法
|
||||
|
||||
|
||||
/** |
||||
* 获取单位简易信息列表 |
||||
* @param onSuccess 获取成功的回调 |
||||
*/ |
||||
getInstitutionListFromServe(onSuccess?: (result: InsitutionDataSimple[], data?: any) => void, onFail?: (error: string) => void) { |
||||
let debugList: any | InsitutionDataSimple[] = []; |
||||
// let testIns1 = new InsitutionDataSimple();
|
||||
// testIns1.key = "test";
|
||||
// testIns1.name = "测试单位1";
|
||||
// debugList.push(testIns1);
|
||||
ServeManager.instance.getInstitutionData("InsList", (key, data) => { |
||||
debugList = plainToClass(InsitutionDataSimple, data); |
||||
this.institutionList = debugList; |
||||
if (onSuccess) { |
||||
onSuccess(debugList, data); |
||||
} |
||||
}, (key: string, error: any) => { |
||||
console.error("获取单位列表失败"); |
||||
console.log(error); |
||||
if (error instanceof HttpErrorResponse && error.status === 404) { |
||||
//数据库没有数据,新建
|
||||
this.institutionList = []; |
||||
if (onSuccess) { |
||||
onSuccess(this.institutionList, this.institutionList); |
||||
} |
||||
console.log("新建数据列表"); |
||||
} |
||||
else { |
||||
if (onFail) { |
||||
onFail(error); |
||||
} |
||||
} |
||||
|
||||
return; |
||||
}) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 选择单位完成,初始化数据(向服务器请求完整数据) |
||||
* @param simpleData 选择的单位 |
||||
*/ |
||||
onSelectInsSuccess(simpleData: InsitutionDataSimple) { |
||||
let status: LoginSatus = StatusManager.getStatus<LoginSatus>(LoginSatus); |
||||
if (status.institutionSelectWindow != null) { |
||||
UIManager.close(status.institutionSelectWindow); |
||||
status.institutionSelectWindow = null; |
||||
} |
||||
|
||||
DataManager.init(simpleData, (resultkey) => { |
||||
StatusManager.enterStatus<MainStatus>(MainStatus); |
||||
}); |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 生命周期
|
||||
//初始化
|
||||
onCreate() { |
||||
super.onCreate(); |
||||
|
||||
} |
||||
//进入状态
|
||||
onEnter() { |
||||
super.onEnter(); |
||||
|
||||
console.log("进入 logins"); |
||||
|
||||
BabylonTool.importMeshSync("", "assets/mesh/outdoor/ZhuTi/ZhuTi.gltf", undefined, undefined, undefined, (meshes) => { |
||||
console.log("加载完成", meshes); |
||||
}); |
||||
|
||||
//UIManager.open<TopbarWindow>(TopbarWindow);
|
||||
// this.openSelectWindow();//可以开启选择、新建单位
|
||||
|
||||
|
||||
} |
||||
//退出状态
|
||||
onExit() { |
||||
|
||||
super.onEnter(); |
||||
|
||||
} |
||||
|
||||
//开启选择界面
|
||||
openSelectWindow() { |
||||
console.log("=======开启选择界面"); |
||||
this.institutionSelectWindow = UIManager.open<InstitutionSelectWindow>(InstitutionSelectWindow); |
||||
console.log(this.institutionSelectWindow); |
||||
let status = this; |
||||
this.institutionSelectWindow.getInsList(status.onSelectInsSuccess); |
||||
} |
||||
|
||||
//关闭选择界面
|
||||
closeSelectWindow() { |
||||
if (this.institutionSelectWindow != null) { |
||||
UIManager.close(this.institutionSelectWindow); |
||||
this.institutionSelectWindow = null; |
||||
} |
||||
} |
||||
|
||||
|
||||
//新建完成
|
||||
onCreateInsSuccess(insData: InsitutionDataSimple) { |
||||
|
||||
this.closeCreateWindow(); |
||||
|
||||
let isOverWrite = false; |
||||
for (let i = 0; i < this.institutionList.length; i++) { |
||||
if (this.institutionList[i].key == insData.key) { |
||||
this.institutionList[i].name = insData.name; |
||||
isOverWrite = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!isOverWrite) { |
||||
this.institutionList.push(insData); |
||||
} |
||||
|
||||
let status = this; |
||||
|
||||
ServeManager.instance.saveInstitutionListData(this.institutionList, () => { |
||||
//进入新单位
|
||||
status.onSelectInsSuccess(insData); |
||||
}); |
||||
|
||||
} |
||||
//#endregion
|
||||
|
||||
//#region babylonGUI 新建单位
|
||||
//开启新建界面
|
||||
onNewIns() { |
||||
this.closeSelectWindow(); |
||||
|
||||
this.institutionCreateWindow = UIManager.open<InstitutionCreateWindow>(InstitutionCreateWindow); |
||||
let status = this; |
||||
this.institutionCreateWindow.startCreate(); |
||||
|
||||
} |
||||
|
||||
//关闭创建界面
|
||||
closeCreateWindow() { |
||||
if (this.institutionCreateWindow != null) { |
||||
UIManager.close(this.institutionCreateWindow); |
||||
} |
||||
this.institutionCreateWindow = null; |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
//保存新单位信息至服务器
|
||||
saveNewIns(status: LoginSatus, insData: InstitutionData, key: string, onSuccess?: (insDataSimple: InsitutionDataSimple) => void) { |
||||
ServeManager.instance.saveInstitutionData(insData, key, (key, result) => { |
||||
console.log("在服务器新建单位" + key); |
||||
let insDataSimple = new InsitutionDataSimple(); |
||||
insDataSimple.key = key; |
||||
insDataSimple.name = insData.normalData.name; |
||||
status.onCreateInsSuccess(insDataSimple); |
||||
if (onSuccess != null) { |
||||
onSuccess(insDataSimple); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
} |
@ -0,0 +1,28 @@
|
||||
|
||||
import { DataManager } from "../data-manager"; |
||||
import { BuildingStatus } from "./building-status"; |
||||
import { StatusBase, StatusManager } from "./status-manager"; |
||||
|
||||
//主状态
|
||||
export class MainStatus extends StatusBase { |
||||
//初始化
|
||||
onCreate() { |
||||
super.onCreate(); |
||||
} |
||||
//进入状态
|
||||
onEnter() { |
||||
super.onEnter(); |
||||
|
||||
|
||||
if (DataManager.institutionData == null) { |
||||
//新建单位信息、开启上传建筑模型的界面
|
||||
} else { |
||||
//已有信息,进入建筑物模式
|
||||
StatusManager.enterStatus<BuildingStatus>(BuildingStatus); |
||||
} |
||||
} |
||||
//退出状态
|
||||
onExit() { |
||||
super.onExit(); |
||||
} |
||||
} |
@ -0,0 +1,74 @@
|
||||
//状态管理
|
||||
export class StatusManager { |
||||
//所有已经实例化的status
|
||||
static s_allStatus: StatusBase[] = []; |
||||
//当前状态
|
||||
static s_currentStatus: StatusBase; |
||||
|
||||
//获取已经有的目标类型status
|
||||
static getStatus<T extends StatusBase>(c: { new(): T; }): T { |
||||
|
||||
if (StatusManager.s_allStatus == null) { |
||||
return null; |
||||
} |
||||
for (let i = 0; i < StatusManager.s_allStatus.length; i++) { |
||||
|
||||
if ((StatusManager.s_allStatus[i]) instanceof c) { |
||||
let result = <T>StatusManager.s_allStatus[i]; |
||||
return result; |
||||
|
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
//创建status
|
||||
static createStatus<T extends StatusBase>(c: { new(): T }): T { |
||||
let newStatus = StatusManager.getStatus<T>(c); |
||||
if (newStatus == null) { |
||||
newStatus = new c(); |
||||
newStatus.onCreate(); |
||||
StatusManager.s_allStatus.push(newStatus); |
||||
} |
||||
|
||||
return newStatus; |
||||
} |
||||
|
||||
//进入某状态
|
||||
static enterStatus<T extends StatusBase>(c: { new(): T }): T { |
||||
if (StatusManager.s_currentStatus != null) { |
||||
// console.log("退出status");
|
||||
// console.log(StatusManager.s_currentStatus);
|
||||
StatusManager.s_currentStatus.onExit(); |
||||
} |
||||
let newStatus = <T>StatusManager.getStatus<T>(c); |
||||
if (newStatus == null) { |
||||
newStatus = new c(); |
||||
newStatus.onCreate(); |
||||
StatusManager.s_allStatus.push(newStatus); |
||||
} |
||||
// console.log("进入status");
|
||||
// console.log(newStatus);
|
||||
|
||||
StatusManager.s_currentStatus = newStatus; |
||||
newStatus.onEnter(); |
||||
return newStatus; |
||||
} |
||||
} |
||||
|
||||
|
||||
//状态基类
|
||||
export class StatusBase { |
||||
//初始化
|
||||
onCreate() { |
||||
|
||||
} |
||||
//进入状态
|
||||
onEnter() { |
||||
|
||||
} |
||||
//退出状态
|
||||
onExit() { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,43 @@
|
||||
import { AdvancedDynamicTexture } from "@babylonjs/gui"; |
||||
import { UIBase } from "../view/window-base/ui-base"; |
||||
|
||||
export class UIManager { |
||||
public static _instance: UIManager; |
||||
static get Instance(): UIManager { |
||||
if (UIManager._instance == null) { |
||||
UIManager._instance = new UIManager(); |
||||
} |
||||
return UIManager._instance; |
||||
} |
||||
|
||||
public uiRoot: AdvancedDynamicTexture; |
||||
|
||||
|
||||
public init() { |
||||
this.uiRoot = AdvancedDynamicTexture.CreateFullscreenUI("UIRoot", undefined);//UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene
|
||||
|
||||
} |
||||
|
||||
static open<T extends UIBase>(c: { new(): T }): T { |
||||
let ui: T = new c(); |
||||
ui.onInit(); |
||||
ui.onOpen(); |
||||
return ui; |
||||
} |
||||
|
||||
static close<T extends UIBase>(ui: T) { |
||||
|
||||
ui.onClose(); |
||||
ui.root.dispose(); |
||||
} |
||||
|
||||
static hide<T extends UIBase>(ui: T) { |
||||
ui.onHide(); |
||||
} |
||||
|
||||
static show<T extends UIBase>(ui: T) { |
||||
ui.onShow(); |
||||
} |
||||
} |
||||
|
||||
|
@ -0,0 +1,58 @@
|
||||
import { Database, Engine, RenderingManager, Scene } from "@babylonjs/core"; |
||||
import { AdvancedDynamicTexture } from "@babylonjs/gui"; |
||||
|
||||
import { SceneManager } from "./controller/scene-manager"; |
||||
import { LoginSatus } from "./controller/status/login-status"; |
||||
import { StatusManager } from "./controller/status/status-manager"; |
||||
import { UIManager } from "./controller/ui-manager"; |
||||
|
||||
|
||||
export class Game { |
||||
public canvas: HTMLCanvasElement; |
||||
public engine: Engine; |
||||
public scene: Scene; |
||||
public uiRoot: AdvancedDynamicTexture; |
||||
|
||||
static instance: Game; |
||||
|
||||
//初始化引擎和画布
|
||||
public init(canvas: HTMLCanvasElement) { |
||||
Game.instance = this; |
||||
this.canvas = canvas; |
||||
this.engine = new Engine(canvas, null, { stencil: true }); |
||||
Database.IDBStorageEnabled = true;//开启本地缓存
|
||||
this.scene = new Scene(this.engine); |
||||
this.scene.useRightHandedSystem = true;//使用右手坐标系
|
||||
RenderingManager.MIN_RENDERINGGROUPS = -1;//最小渲染序列
|
||||
|
||||
this.createScene(); |
||||
let scene = this.scene; |
||||
// canvas.translate = true; //用于设置背景透明
|
||||
// scene.autoClear = true;
|
||||
UIManager.Instance.init(); |
||||
|
||||
StatusManager.enterStatus<LoginSatus>(LoginSatus); |
||||
|
||||
//最后,将场景渲染出来 (重要,不可缺少)
|
||||
this.engine.runRenderLoop(function () { |
||||
scene.render(); |
||||
}) |
||||
|
||||
// 监听浏览器改变大小的事件,通过调用engine.resize()来自适应窗口大小
|
||||
window.addEventListener("resize", function () { |
||||
Game.instance.engine.resize(); |
||||
}); |
||||
|
||||
} |
||||
|
||||
//创建初始场景
|
||||
private createScene() { |
||||
let sceneManager = SceneManager.init(this.scene, this.canvas, this.engine); |
||||
sceneManager.initArcRotateCamera(); |
||||
sceneManager.initLight(); |
||||
sceneManager.updateSceneBG(); |
||||
sceneManager.initSceneEvent(); |
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,37 @@
|
||||
import { ArcRotateCamera, Vector3 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
|
||||
/** |
||||
* 自由旋转相机的数据 |
||||
*/ |
||||
export class ArcRotateCameraData { |
||||
|
||||
@Type(() => Vector3) |
||||
target: Vector3; |
||||
radius: number; |
||||
alpha: number; |
||||
beta: number; |
||||
|
||||
/** |
||||
* 将数据设置到相机上 |
||||
* @param camera
|
||||
*/ |
||||
setDataToCamera(camera: ArcRotateCamera) { |
||||
camera._scene.stopAnimation(camera); |
||||
camera.target = this.target; |
||||
camera.radius = this.radius; |
||||
camera.alpha = this.alpha; |
||||
camera.beta = this.beta; |
||||
} |
||||
|
||||
/** |
||||
* 将摄像机的数据记录下来 |
||||
* @param camera
|
||||
*/ |
||||
getDataFromCamera(camera: ArcRotateCamera) { |
||||
this.target = camera.target; |
||||
this.radius = camera.radius; |
||||
this.alpha = camera.alpha; |
||||
this.beta = camera.beta; |
||||
} |
||||
} |
@ -0,0 +1,70 @@
|
||||
import { Type } from "class-transformer"; |
||||
import { ModelEditData } from "../../model-data/model-edit-data"; |
||||
|
||||
import { NormalData } from "../institution-data"; |
||||
|
||||
//基础建筑信息
|
||||
export class BuildingData { |
||||
// belongToInstitution: InstitutionData
|
||||
@Type(() => NormalData) |
||||
normalData: NormalData; //常规信息
|
||||
buildingIDFromPlatform: string;//关联自预案管理平台中的建筑id
|
||||
describe: string; //描述
|
||||
buildingType: BuildingType; //建筑类型
|
||||
@Type(() => ModelEditData) |
||||
outdoorData: ModelEditData; //外观建筑编辑信息
|
||||
|
||||
constructor() { |
||||
// this.belongToInstitution = belongToInstitution;
|
||||
this.normalData = new NormalData(); |
||||
this.outdoorData = new ModelEditData(); |
||||
} |
||||
} |
||||
|
||||
//普通大楼信息
|
||||
export class BuildingData_Normal extends BuildingData { |
||||
@Type(() => ModelEditData) |
||||
indoorsData: ModelEditData[];//室内编辑信息
|
||||
constructor() { |
||||
super(); |
||||
this.buildingType = BuildingType.Normal; |
||||
} |
||||
|
||||
/** |
||||
* 获取下一个室内层的index序号 |
||||
*/ |
||||
getNextIndoorIndex() { |
||||
let result = -1; |
||||
for (let i = 0; i < this.indoorsData.length; i++) { |
||||
if (this.indoorsData[i].index > result) { |
||||
result = this.indoorsData[i].index; |
||||
} |
||||
} |
||||
result++; |
||||
return result; |
||||
} |
||||
} |
||||
|
||||
|
||||
//环境信息
|
||||
export class BuildingData_Environment extends BuildingData { |
||||
constructor() { |
||||
super(); |
||||
this.buildingType = BuildingType.Environment; |
||||
} |
||||
} |
||||
|
||||
//化工厂信息
|
||||
export class BuildingData_ChemicalPlant extends BuildingData { |
||||
constructor() { |
||||
super(); |
||||
this.buildingType = BuildingType.ChemicalPlant; |
||||
} |
||||
} |
||||
|
||||
//建筑类型
|
||||
export enum BuildingType { |
||||
Normal = "normal", //普通大楼
|
||||
Environment = "environment", //环境
|
||||
ChemicalPlant = "chemicalPlant", //化工厂
|
||||
} |
@ -0,0 +1,79 @@
|
||||
import { Type } from 'class-transformer'; |
||||
import { ConfigManager } from 'src/app/babylon/controller/config-manager'; |
||||
import { DataManager } from 'src/app/babylon/controller/data-manager'; |
||||
|
||||
|
||||
import { FacilityPosType, FacilityType, ModelData_facility } from '../../model-data/model-data-facility'; |
||||
import { TransformData } from '../../transform-data'; |
||||
|
||||
//所有设备数据
|
||||
export class AllFacilityData { |
||||
@Type(() => ModelData_facility) |
||||
indoor: ModelData_facility[] = []; //室内
|
||||
@Type(() => ModelData_facility) |
||||
outdoor: ModelData_facility[] = []; //室外
|
||||
|
||||
/**捏造所有消防设施的源数据 */ |
||||
static CreateAllFacilityData(): AllFacilityData { |
||||
let result = new AllFacilityData(); |
||||
|
||||
AllFacilityData.newFacilityData(FacilityType.AQCK, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.DSXHS, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.DXXHS, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.SZDSXHS, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.SZDXXHS, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.DSSBJHQ, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.DXSBJHQ, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.QBSBJHQ, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.DGNSBJHQ, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.GD, FacilityPosType.Outdoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.PL, FacilityPosType.Outdoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.JTQ, FacilityPosType.Outdoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.JJQ, FacilityPosType.Outdoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.TPBZ, FacilityPosType.Outdoor, result, true); |
||||
|
||||
AllFacilityData.newFacilityData(FacilityType.XKS, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.BF, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.SX, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.LSXFB, FacilityPosType.Indoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.WSXFB, FacilityPosType.Indoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.CYXFB, FacilityPosType.Indoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.FHFQ, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.SNXHS, FacilityPosType.Indoor, result); |
||||
AllFacilityData.newFacilityData(FacilityType.FHM, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.FHJL, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.SSLT, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.XFDT, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.PTDT, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.HT, FacilityPosType.Indoor, result, false); |
||||
AllFacilityData.newFacilityData(FacilityType.WXY, FacilityPosType.Public, result); |
||||
AllFacilityData.newFacilityData(FacilityType.ZDQY, FacilityPosType.Public, result); |
||||
AllFacilityData.newFacilityData(FacilityType.DWBZ, FacilityPosType.Public, result); |
||||
return result; |
||||
|
||||
} |
||||
|
||||
//新建设备信息
|
||||
static newFacilityData(type: FacilityType, posType: FacilityPosType, allFacilityData: AllFacilityData, isModel: boolean = true): ModelData_facility { |
||||
let name = ConfigManager.getFacilityTypeName(type); |
||||
let result = new ModelData_facility(type.toString(), type, name, DataManager.getResName_facility(type) + ".gltf", new TransformData(), posType, isModel); |
||||
switch (posType) { |
||||
case FacilityPosType.Outdoor: |
||||
allFacilityData.outdoor.push(result); |
||||
break; |
||||
case FacilityPosType.Indoor: |
||||
allFacilityData.indoor.push(result); |
||||
break; |
||||
case FacilityPosType.Public: |
||||
allFacilityData.outdoor.push(result); |
||||
allFacilityData.indoor.push(result); |
||||
break; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 图片类 基础类 |
||||
*/ |
||||
export class PropertyData_Base_IMG extends PropertyData_Base { |
||||
|
||||
img: string;//图片
|
||||
is360: boolean;//全景图片
|
||||
pos: string;//位置
|
||||
info: string;//详情
|
||||
|
||||
constructor(key: string, img: string, pos: string, info: string, type: FacilityType) { |
||||
super(key, type); |
||||
this.img = img; |
||||
this.pos = pos; |
||||
this.info = info; |
||||
this.is360 = false; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_Base_IMG(key, this.img, this.pos, this.info, this.facilityType); |
||||
result.is360 = this.is360; |
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,27 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 楼梯基础类 |
||||
*/ |
||||
export class PropertyData_Base_LT extends PropertyData_Base { |
||||
|
||||
number: string = "";//编号
|
||||
channel: string = "";//通往层数
|
||||
|
||||
constructor(key: string, number: string, channel: string, type: FacilityType) { |
||||
super(key, type); |
||||
this.number = number; |
||||
this.channel = channel; |
||||
|
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_Base_LT(key, this.number, this.channel, this.facilityType); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,31 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 水泵接合器 基础类 |
||||
*/ |
||||
export class PropertyData_Base_SBJHQ extends PropertyData_Base { |
||||
|
||||
number: string;//编号
|
||||
type: string;//类型(特殊字段,关系UI分类展示)
|
||||
range: string;//供给范围
|
||||
img: string;//图片
|
||||
is360: boolean;//是否是全景图片
|
||||
|
||||
constructor(key: string, number: string, type: string, range: string, img: string, facilityType: FacilityType) { |
||||
super(key, facilityType); |
||||
this.number = number; |
||||
this.type = type; |
||||
this.range = range; |
||||
this.img = img; |
||||
this.is360 = false; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_Base_SBJHQ(key, this.number, this.type, this.range, this.img, this.facilityType); |
||||
result.is360 = this.is360; |
||||
return result; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,34 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 消防泵基础类 |
||||
*/ |
||||
export class PropertyData_Base_XFB extends PropertyData_Base { |
||||
|
||||
type: string;//类型
|
||||
number: string;//型号
|
||||
power: string;//功率
|
||||
lift: string;//扬程
|
||||
flow: string;//流量
|
||||
pressure: string;//压力
|
||||
|
||||
constructor(key: string, type: string, number: string, power: string, lift: string, flow: string, pressure: string, facilityType: FacilityType) { |
||||
super(key, facilityType); |
||||
this.type = type; |
||||
this.power = power; |
||||
this.number = number; |
||||
this.lift = lift; |
||||
this.flow = flow; |
||||
this.pressure = pressure; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_Base_XFB(key, this.type, this.number, this.power, this.lift, this.flow, this.pressure, this.facilityType); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,32 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 消火栓基础类 |
||||
*/ |
||||
export class PropertyData_Base_XHS extends PropertyData_Base { |
||||
|
||||
img: string;//图片
|
||||
is360: boolean;//全景图片
|
||||
number: string;//编号
|
||||
caliber: string;//管径
|
||||
screw: string;//牙口
|
||||
|
||||
constructor(key: string, img: string, is360: boolean, number: string, caliber: string, screw: string, type: FacilityType) { |
||||
super(key, type); |
||||
this.img = img; |
||||
this.is360 = is360; |
||||
this.number = number; |
||||
this.caliber = caliber; |
||||
this.screw = screw; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_Base_XHS(key, this.img, this.is360, this.number, this.caliber, this.screw, this.facilityType); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,27 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 点位标注 |
||||
*/ |
||||
export class PropertyData_DWBZ extends PropertyData_Base { |
||||
|
||||
|
||||
pos: string = "";//位置
|
||||
info: string = "";//详情
|
||||
constructor(key: string, pos: string, info: string) { |
||||
super(key, FacilityType.DWBZ); |
||||
this.pos = pos; |
||||
this.info = info; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_DWBZ(key, this.pos, this.info); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,31 @@
|
||||
import { Color3, Color4 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 防火分区 |
||||
*/ |
||||
export class PropertyData_FHFQ extends PropertyData_Base { |
||||
|
||||
|
||||
name: string = "";//名称
|
||||
area: string = "";//面积
|
||||
@Type(() => Color3) |
||||
color: Color3 = Color3.Red();//颜色
|
||||
constructor(key: string, name: string, area: string, color: Color3 = Color3.Red()) { |
||||
super(key, FacilityType.FHFQ); |
||||
this.name = name; |
||||
this.area = area; |
||||
this.color = color; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_FHFQ(key, this.name, this.area, this.color); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,26 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base_LT } from "../base/property-data-base-lt"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 疏散楼梯 |
||||
*/ |
||||
export class PropertyData_SSLT extends PropertyData_Base_LT { |
||||
|
||||
width: string = "";//宽度
|
||||
|
||||
constructor(key: string, number: string, channel: string, width: string) { |
||||
super(key, number, channel, FacilityType.SSLT); |
||||
this.width = width; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_SSLT(key, this.number, this.channel, this.width); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,24 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base_LT } from "../base/property-data-base-lt"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 消防电梯 |
||||
*/ |
||||
export class PropertyData_XFDT extends PropertyData_Base_LT { |
||||
|
||||
weight: string = "";//载重
|
||||
|
||||
constructor(key: string, number: string, channel: string, weight: string) { |
||||
super(key, number, channel, FacilityType.XFDT); |
||||
this.weight = weight; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_XFDT(key, this.number, this.channel, this.weight); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,42 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 重点区域 |
||||
*/ |
||||
export class PropertyData_ZDQY extends PropertyData_Base { |
||||
|
||||
name: string = "";//名称
|
||||
pos: string = "";//所在位置
|
||||
construction: string = "";//建筑结构
|
||||
character: string = "";//使用性质
|
||||
danger: string = "";//主要危险性
|
||||
imgs: string[] = [];//图片
|
||||
|
||||
constructor(key: string, name: string, pos: string, construction: string, character: string, danger: string, imgs: string[]) { |
||||
super(key, FacilityType.ZDQY); |
||||
this.name = name; |
||||
this.pos = pos; |
||||
this.construction = construction; |
||||
this.character = character; |
||||
this.danger = danger; |
||||
this.imgs = imgs; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
|
||||
let newImgs: string[] = []; |
||||
|
||||
for (let i = 0; i < this.imgs.length; i++) { |
||||
newImgs.push(this.imgs[i]); |
||||
} |
||||
|
||||
let result = new PropertyData_ZDQY(key, this.name, this.pos, this.construction, this.character, this.danger, newImgs); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,31 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 安全出口 |
||||
*/ |
||||
export class PropertyData_AQCK extends PropertyData_Base { |
||||
|
||||
img: string = ""; |
||||
is360: boolean;//全景图片
|
||||
name: string = "安全出口"; |
||||
width: string = ""; |
||||
constructor(key: string, img: string, is360: boolean, name: string, width: string) { |
||||
super(key, FacilityType.AQCK); |
||||
this.img = img; |
||||
this.is360 = is360; |
||||
this.name = name; |
||||
this.width = width; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_AQCK(key, this.img, this.is360, "安全出口", "1"); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,26 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 高度 |
||||
*/ |
||||
export class PropertyData_GD extends PropertyData_Base { |
||||
|
||||
|
||||
info: string = ""; |
||||
constructor(key: string, info: string) { |
||||
super(key, FacilityType.GD); |
||||
this.info = info; |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_GD(key, this.info); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,36 @@
|
||||
|
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 毗邻 |
||||
*/ |
||||
export class tableData { |
||||
public tableRow: string[] |
||||
} |
||||
export class tableRow { |
||||
public street: string = "" |
||||
public adjoinBuilding: string = "" |
||||
public range: string = "" |
||||
} |
||||
export class PropertyData_PL extends PropertyData_Base { |
||||
|
||||
direction: number = 0; //毗邻所属方向 0,1,2,3 --- 东南西北
|
||||
info: string = ""; |
||||
tableData: tableData[] = []; |
||||
constructor(key: string, direction: number, info: string, tableData: tableData[]) { |
||||
super(key, FacilityType.PL); |
||||
this.direction = direction; |
||||
this.info = info; |
||||
this.tableData = tableData |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_PL(key, this.direction, this.info, this.tableData); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,37 @@
|
||||
import { Color3 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
import { FacilityType } from "../../../../model-data/model-data-facility"; |
||||
|
||||
import { PropertyData_Base_IMG } from "../base/property-data-base-img"; |
||||
import { PropertyData_Base } from "../property-data-base"; |
||||
|
||||
/** |
||||
* 集结区和禁停区 |
||||
*/ |
||||
export class PropertyData_Q extends PropertyData_Base_IMG { |
||||
|
||||
@Type(() => Color3) |
||||
color: Color3;//区域颜色
|
||||
constructor(key: string, img: string, pos: string, info: string, color: Color3, type: FacilityType) { |
||||
super(key, img, pos, info, type); |
||||
this.color = color; |
||||
if (color == null) { |
||||
switch (type) { |
||||
case FacilityType.JTQ: |
||||
this.color = Color3.Yellow(); |
||||
break; |
||||
case FacilityType.JJQ: |
||||
this.color = Color3.Green(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
clone(key: string) { |
||||
let result = new PropertyData_Q(key, this.img, this.pos, this.info, this.color, this.facilityType); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,38 @@
|
||||
|
||||
import { classToClass } from "class-transformer"; |
||||
import { FacilityType } from "../../../model-data/model-data-facility"; |
||||
|
||||
//基本属性
|
||||
export abstract class PropertyData_Base { |
||||
|
||||
static readonly c_defaultText = "----"; //文字默认值
|
||||
|
||||
/** |
||||
* 唯一身份key |
||||
*/ |
||||
key: string; |
||||
/** |
||||
* 设备具体类型 |
||||
*/ |
||||
facilityType: FacilityType; |
||||
|
||||
/** |
||||
* 自定义名称 |
||||
*/ |
||||
name: string; |
||||
|
||||
|
||||
constructor(key: string, facilityType: FacilityType) { |
||||
this.key = key; |
||||
this.facilityType = facilityType; |
||||
} |
||||
|
||||
clone(key: string): PropertyData_Base { |
||||
let result = classToClass(this); |
||||
result.key = key; |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,14 @@
|
||||
import { PropertyData_Base } from "./property-data-base"; |
||||
|
||||
//暂时用于哪些还没有具体实现的属性
|
||||
export class PropertyData_public extends PropertyData_Base { |
||||
|
||||
|
||||
clone(key: string) { |
||||
|
||||
let result = new PropertyData_public(key, this.facilityType); |
||||
return result; |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,5 @@
|
||||
//简易单位基本信息,用于显示于列表中
|
||||
export class InsitutionDataSimple { |
||||
key: string;//唯一身份key
|
||||
name: string;//自定义的名称
|
||||
} |
@ -0,0 +1,87 @@
|
||||
import { Vector3 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
import { BuildingData_ChemicalPlant, BuildingData_Environment, BuildingData_Normal, BuildingType } from "./building/building-data"; |
||||
|
||||
//单位信息
|
||||
export class InstitutionData { |
||||
|
||||
@Type(() => NormalData) |
||||
normalData: NormalData = null;//常规信息
|
||||
|
||||
@Type(() => BuildingData_Normal) |
||||
normalBuildingDatas: BuildingData_Normal[] = [];//普通建筑列表
|
||||
|
||||
@Type(() => BuildingData_Environment) |
||||
environmentDatas: BuildingData_Environment[] = [];//环境信息
|
||||
|
||||
@Type(() => BuildingData_ChemicalPlant) |
||||
chemicalPlantData: BuildingData_ChemicalPlant[] = [];//化工厂信息
|
||||
|
||||
@Type(() => Vector3) |
||||
pos: Vector3 = new Vector3(0, 0, 0); |
||||
|
||||
|
||||
//获取一个最新的key(根据前一个同类建筑key,加一)
|
||||
public getNewKey(buildingType: BuildingType): string { |
||||
let result = ""; |
||||
|
||||
let lastNormalData: NormalData = null; |
||||
let length = 0; |
||||
switch (buildingType) { |
||||
case BuildingType.Normal: |
||||
if (this.normalBuildingDatas != null && this.normalBuildingDatas.length > 0) { |
||||
length = this.normalBuildingDatas.length; |
||||
lastNormalData = this.normalBuildingDatas[length - 1].normalData; |
||||
} |
||||
break; |
||||
case BuildingType.Environment: |
||||
if (this.environmentDatas != null && this.environmentDatas.length > 0) { |
||||
length = this.environmentDatas.length; |
||||
lastNormalData = this.environmentDatas[length - 1].normalData; |
||||
} |
||||
break; |
||||
case BuildingType.ChemicalPlant: |
||||
if (this.chemicalPlantData != null && this.chemicalPlantData.length > 0) { |
||||
length = this.chemicalPlantData.length; |
||||
lastNormalData = this.chemicalPlantData[length - 1].normalData; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
let lastKey = 0; |
||||
if (lastNormalData != null) { |
||||
lastKey = Number.parseInt(lastNormalData.key); |
||||
lastKey++; |
||||
} |
||||
|
||||
result += lastKey; |
||||
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//常规、必有的信息
|
||||
export class NormalData { |
||||
|
||||
key: string;//唯一key
|
||||
|
||||
name: string;//给用户编辑、查看用的名称
|
||||
constructor(key: string = "", name: string = "") { |
||||
|
||||
this.key = key; |
||||
this.name = name; |
||||
} |
||||
clone(): NormalData { |
||||
let result = new NormalData(this.key, this.name); |
||||
return result; |
||||
|
||||
} |
||||
|
||||
getName() { |
||||
//console.log("getName==" + this.name);
|
||||
return this.name; |
||||
} |
||||
} |
@ -0,0 +1,227 @@
|
||||
import { Type } from "class-transformer"; |
||||
|
||||
import { MarkData_Area } from "./other/mark-data-area"; |
||||
import { MarkData, MarkType, MarkKindType, MarkTagPos, MarkTask } from "./mark-data"; |
||||
import { MarkData_Line } from "./other/mark-data-line"; |
||||
import { MarkData_multiLine } from "./other/mark-data-multi-line"; |
||||
import { MarkData_multiArrow_CT, MarkData_multiArrow_JG } from "./other/mark-data-multi-arrow"; |
||||
import { ConfigManager } from "src/app/babylon/controller/config-manager"; |
||||
|
||||
|
||||
export class AllMarkData { |
||||
/** |
||||
* 灾情 |
||||
*/ |
||||
@Type(() => MarkData) |
||||
marks_Disaster: MarkData[] = []; |
||||
|
||||
/** |
||||
* 消防力量 |
||||
*/ |
||||
@Type(() => MarkData) |
||||
marks_FireFighting: MarkData[] = []; |
||||
|
||||
/** |
||||
* 联动力量 |
||||
*/ |
||||
@Type(() => MarkData) |
||||
marks_Linkage: MarkData[] = []; |
||||
|
||||
/** |
||||
* 内部力量 |
||||
*/ |
||||
@Type(() => MarkData) |
||||
marks_Inside: MarkData[] = []; |
||||
|
||||
/** |
||||
* 标绘工具 |
||||
*/ |
||||
@Type(() => MarkData) |
||||
marks_Tool: MarkData[] = []; |
||||
|
||||
static CreateAllMarkData(): AllMarkData { |
||||
let result = new AllMarkData(); |
||||
|
||||
//灾情
|
||||
let tagPos: MarkTagPos = MarkTagPos.Disaster; |
||||
AllMarkData.newMarkData(MarkType.SYA, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.SYB, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.SYC, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.SYD, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZQR, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.WXP, MarkKindType.Goods, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZWD, MarkKindType.Goods, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.PCD, MarkKindType.Goods, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.H, MarkKindType.Effect, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.TPH, MarkKindType.Effect, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.SNH, MarkKindType.Effect, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.YWA, MarkKindType.Effect, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.YWB, MarkKindType.Effect, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.YWC, MarkKindType.Effect, tagPos, result, undefined, false); |
||||
|
||||
//消防力量
|
||||
tagPos = MarkTagPos.FireFighting; |
||||
AllMarkData.newMarkData(MarkType.MHF, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JYF, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.GRF, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.FHF, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.BHF, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.YWXFY, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.AQS, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.MTC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.XLC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.SGC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.PMC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.GPC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.DGPTC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.YTC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.QXJYC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.QCC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZMC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.PCC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.PYC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZHC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.GCGSC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.KQHXCQC, MarkKindType.Car, tagPos, result); |
||||
|
||||
//联动力量
|
||||
tagPos = MarkTagPos.Linkage; |
||||
AllMarkData.newMarkData(MarkType.GA, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JJ, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.YS, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.QXRY, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JHC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.DLQXC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.RQQXC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.GSQXC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.HBJCC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JTYSC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.WSFYC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.YJTXC, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JCA, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JCB, MarkKindType.Car, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JCC, MarkKindType.Car, tagPos, result); |
||||
|
||||
//内部力量
|
||||
tagPos = MarkTagPos.Inside; |
||||
AllMarkData.newMarkData(MarkType.DSZ, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JL, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.FZ, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.MS, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZJ, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZG, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZZ, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.QT, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.SJS, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.CXY, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZYA, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.ZYB, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.JG, MarkKindType.Persion, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.BA, MarkKindType.Persion, tagPos, result); |
||||
|
||||
//标绘工具
|
||||
tagPos = MarkTagPos.Tool; |
||||
AllMarkData.newMarkData(MarkType.JJX, MarkKindType.Goods, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.SD, MarkKindType.Goods, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.JGLX, MarkKindType.Virtual, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.CT, MarkKindType.Virtual, tagPos, result, undefined, false); |
||||
AllMarkData.newMarkData(MarkType.ZHB, MarkKindType.Goods, tagPos, result, MarkTask.Unknown); |
||||
AllMarkData.newMarkData(MarkType.LT6, MarkKindType.Goods, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.LT15, MarkKindType.Goods, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.FSQ, MarkKindType.Goods, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.STB, MarkKindType.Goods, tagPos, result); |
||||
AllMarkData.newMarkData(MarkType.SP, MarkKindType.Goods, tagPos, result, MarkTask.WaterMonitor); |
||||
AllMarkData.newMarkData(MarkType.WZ, MarkKindType.Virtual, tagPos, result, MarkTask.Unknown); |
||||
AllMarkData.newMarkData(MarkType.JJQ, MarkKindType.Virtual, tagPos, result, MarkTask.Unknown, false); |
||||
AllMarkData.newMarkData(MarkType.QYSDA, MarkKindType.Virtual, tagPos, result, MarkTask.Unknown, false); |
||||
AllMarkData.newMarkData(MarkType.QYSDB, MarkKindType.Virtual, tagPos, result, MarkTask.Unknown, false); |
||||
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
//新建设备信息
|
||||
/** |
||||
* 创建标绘物素材库数据 |
||||
* @param type
|
||||
* @param kindType
|
||||
* @param tagPos
|
||||
* @param allMarkData
|
||||
* @param taskType
|
||||
* @param isModel
|
||||
*/ |
||||
static newMarkData(type: MarkType, kindType: MarkKindType, tagPos: MarkTagPos, allMarkData: AllMarkData, taskType?: MarkTask, isModel = true): MarkData { |
||||
|
||||
let l_taskType: MarkTask = MarkTask.None; |
||||
let list = []; |
||||
switch (tagPos) { |
||||
case MarkTagPos.Disaster: |
||||
list = allMarkData.marks_Disaster; |
||||
break; |
||||
case MarkTagPos.FireFighting: |
||||
list = allMarkData.marks_FireFighting |
||||
break; |
||||
case MarkTagPos.Linkage: |
||||
list = allMarkData.marks_Linkage; |
||||
break; |
||||
case MarkTagPos.Inside: |
||||
list = allMarkData.marks_Inside; |
||||
break; |
||||
case MarkTagPos.Tool: |
||||
list = allMarkData.marks_Tool; |
||||
break; |
||||
} |
||||
|
||||
//除了灾情以外, 人和车的任务类型
|
||||
if (tagPos != MarkTagPos.Disaster) { |
||||
if (kindType == MarkKindType.Persion) { |
||||
l_taskType = MarkTask.Person; |
||||
} |
||||
else if (kindType == MarkKindType.Car) { |
||||
l_taskType = MarkTask.Car; |
||||
} |
||||
} |
||||
|
||||
//没指定,则使用规则的任务类型
|
||||
if (taskType == null) { |
||||
taskType = l_taskType; |
||||
} |
||||
|
||||
let icon = ConfigManager.getMarkIconUrl(tagPos, type); |
||||
let modelPath = ConfigManager.getMarkModelPath(tagPos, type); |
||||
let modelName = type + ".gltf"; |
||||
|
||||
|
||||
let result = null; |
||||
switch (type) { |
||||
case MarkType.JJQ: |
||||
case MarkType.QYSDA: |
||||
case MarkType.QYSDB: |
||||
result = new MarkData_Area(type.toString(), type, tagPos, kindType, icon, modelPath, modelName, taskType, isModel); |
||||
break; |
||||
case MarkType.JJX: |
||||
result = new MarkData_Line(type.toString(), type, tagPos, kindType, icon, modelPath, modelName, taskType, isModel); |
||||
break; |
||||
case MarkType.SD: |
||||
result = new MarkData_multiLine(type.toString(), type, tagPos, kindType, icon, modelPath, modelName, taskType, isModel); |
||||
break; |
||||
case MarkType.JGLX: |
||||
result = new MarkData_multiArrow_JG(type.toString(), type, tagPos, kindType, icon, modelPath, modelName, taskType, isModel); |
||||
break; |
||||
case MarkType.CT: |
||||
result = new MarkData_multiArrow_CT(type.toString(), type, tagPos, kindType, icon, modelPath, modelName, taskType, isModel); |
||||
break; |
||||
default: |
||||
result = new MarkData(type.toString(), type, tagPos, kindType, icon, modelPath, modelName, taskType, isModel); |
||||
break; |
||||
} |
||||
|
||||
|
||||
list.push(result); |
||||
return result; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,598 @@
|
||||
import { Type } from "class-transformer"; |
||||
import { ConfigManager } from "src/app/babylon/controller/config-manager"; |
||||
|
||||
|
||||
import { ModelData } from "../model-data/model-data"; |
||||
import { TransformData } from "../transform-data"; |
||||
import { MarkProperty } from "./mark-property"; |
||||
|
||||
/** |
||||
* 标绘数据 |
||||
*/ |
||||
export class MarkData extends ModelData { |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* 名称类型,标志其具体是什么 |
||||
*/ |
||||
type: MarkType = MarkType.SYA; |
||||
|
||||
/** |
||||
* 所属标签的tag |
||||
*/ |
||||
tagPos: MarkTagPos = MarkTagPos.Disaster; |
||||
|
||||
/** |
||||
* 标记的类型划分 |
||||
* 包括:人、车、物、虚拟物、特效 |
||||
*/ |
||||
markKindType: MarkKindType = MarkKindType.Persion; |
||||
|
||||
/** |
||||
* 图标地址 |
||||
*/ |
||||
iconURL: string; |
||||
|
||||
/** |
||||
* 所属建筑 |
||||
*/ |
||||
belongtoBuildingId: string; |
||||
|
||||
/** |
||||
* 属性 |
||||
*/ |
||||
@Type(() => MarkProperty) |
||||
property: MarkProperty; |
||||
|
||||
/** |
||||
* 子节点信息(用于保存子节点变换信息,完成举臂等功能) |
||||
*/ |
||||
@Type(() => ChildNodeData) |
||||
childrenNodeData: ChildNodeData[] = []; |
||||
|
||||
/** |
||||
* 水枪特效强度 |
||||
*/ |
||||
waterPower: number = 20; |
||||
|
||||
|
||||
constructor(id: string, type: MarkType, tagPos: MarkTagPos, markKindType: MarkKindType, iconURL: string, resPath: string, resName: string, taskType: MarkTask, isModel: boolean) { |
||||
super(id, ConfigManager.getMarkName(type), resPath, resName, undefined, isModel) |
||||
this.name = ConfigManager.getMarkName(type); |
||||
this.type = type; |
||||
this.tagPos = tagPos; |
||||
this.markKindType = markKindType; |
||||
this.iconURL = iconURL; |
||||
|
||||
let defaultTask: string = undefined; |
||||
if (type == MarkType.WZ) { |
||||
defaultTask = "文字信息"; |
||||
} |
||||
|
||||
this.property = new MarkProperty(taskType, undefined, undefined, defaultTask); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 子节点数据 |
||||
*/ |
||||
export class ChildNodeData { |
||||
/** |
||||
* 子节点名称 |
||||
*/ |
||||
name: string; |
||||
|
||||
/** |
||||
* 变换信息 |
||||
*/ |
||||
@Type(() => TransformData) |
||||
transformData: TransformData = new TransformData(); |
||||
} |
||||
|
||||
/** |
||||
* 所属标签的tag |
||||
*/ |
||||
export enum MarkTagPos { |
||||
/** |
||||
* 灾情 |
||||
*/ |
||||
Disaster = "Disaster", |
||||
|
||||
/** |
||||
* 消防力量 |
||||
*/ |
||||
FireFighting = "FireFighting", |
||||
|
||||
/** |
||||
* 联动力量 |
||||
*/ |
||||
Linkage = "Linkage", |
||||
|
||||
/** |
||||
* 内部力量 |
||||
*/ |
||||
Inside = "Inside", |
||||
|
||||
/** |
||||
* 标绘工具 |
||||
*/ |
||||
Tool = "Tool", |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 标绘的分类类型 |
||||
*/ |
||||
export enum MarkKindType { |
||||
/** |
||||
* 人 |
||||
*/ |
||||
Persion = "Persion", |
||||
|
||||
/** |
||||
* 车 |
||||
*/ |
||||
Car = "Car", |
||||
|
||||
/** |
||||
* 物品 |
||||
*/ |
||||
Goods = "Goods", |
||||
|
||||
/** |
||||
* 虚拟物,如: 箭头、文字标记类 |
||||
*/ |
||||
Virtual = "Virtual", |
||||
|
||||
/** |
||||
* 特效 |
||||
*/ |
||||
Effect = "Effect", |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 标绘的名称类型 |
||||
* 每个标会类型id |
||||
*/ |
||||
export enum MarkType { |
||||
|
||||
//============灾情设定===============
|
||||
/** |
||||
* 伤员A |
||||
*/ |
||||
SYA = "SYA", |
||||
/** |
||||
* 伤员B |
||||
*/ |
||||
SYB = "SYB", |
||||
/** |
||||
* 伤员C |
||||
*/ |
||||
SYC = "SYC", |
||||
/** |
||||
* 伤员D |
||||
*/ |
||||
SYD = "SYD", |
||||
|
||||
/** |
||||
* 知情人 |
||||
*/ |
||||
ZQR = "ZQR", |
||||
|
||||
/** |
||||
* 危险品 |
||||
*/ |
||||
WXP = "WXP", |
||||
|
||||
/** |
||||
* 杂物堆 |
||||
*/ |
||||
ZWD = "ZWD", |
||||
|
||||
/** |
||||
* 破拆点 |
||||
*/ |
||||
PCD = "PCD", |
||||
|
||||
/** |
||||
* 火 |
||||
*/ |
||||
H = "H", |
||||
|
||||
/** |
||||
* 突破火 |
||||
*/ |
||||
TPH = "TPH", |
||||
|
||||
/** |
||||
* 室内火 |
||||
*/ |
||||
SNH = "SNH", |
||||
|
||||
/** |
||||
* 烟雾A |
||||
*/ |
||||
YWA = "YWA", |
||||
|
||||
/** |
||||
* 烟雾B |
||||
*/ |
||||
YWB = "YWB", |
||||
|
||||
/** |
||||
* 烟雾C |
||||
*/ |
||||
YWC = "YWC", |
||||
|
||||
//==================消防力量================
|
||||
|
||||
/** |
||||
* 灭火服 |
||||
*/ |
||||
MHF = "MHF", |
||||
|
||||
/** |
||||
* 救援服 |
||||
*/ |
||||
JYF = "JYF", |
||||
|
||||
/** |
||||
* 隔热服 |
||||
*/ |
||||
GRF = "GRF", |
||||
|
||||
/** |
||||
* 防化服 |
||||
*/ |
||||
FHF = "FHF", |
||||
|
||||
/** |
||||
* 避火服 |
||||
*/ |
||||
BHF = "BHF", |
||||
|
||||
/** |
||||
* 义务消防员 |
||||
*/ |
||||
YWXFY = "YWXFY", |
||||
|
||||
/** |
||||
* 安全哨 |
||||
*/ |
||||
AQS = "AQS", |
||||
|
||||
/** |
||||
* 摩托车 |
||||
*/ |
||||
MTC = "MTC", |
||||
|
||||
/** |
||||
* 巡逻车 |
||||
*/ |
||||
XLC = "XLC", |
||||
|
||||
/** |
||||
* 水罐车 |
||||
*/ |
||||
SGC = "SGC", |
||||
|
||||
/** |
||||
* 泡沫车 |
||||
*/ |
||||
PMC = "PMC", |
||||
|
||||
/** |
||||
* 高喷车 |
||||
*/ |
||||
GPC = "GPC", |
||||
|
||||
/** |
||||
* 登高平台车 |
||||
*/ |
||||
DGPTC = "DGPTC", |
||||
|
||||
/** |
||||
* 云梯车 |
||||
*/ |
||||
YTC = "YTC", |
||||
|
||||
/** |
||||
* 抢险救援车 |
||||
*/ |
||||
QXJYC = "QXJYC", |
||||
|
||||
/** |
||||
* 器材车 |
||||
*/ |
||||
QCC = "QCC", |
||||
|
||||
/** |
||||
* 照明车 |
||||
*/ |
||||
ZMC = "ZMC", |
||||
|
||||
/** |
||||
* 破拆车 |
||||
*/ |
||||
PCC = "PCC", |
||||
|
||||
/** |
||||
* 排烟车 |
||||
*/ |
||||
PYC = "PYC", |
||||
|
||||
/** |
||||
* 指挥车 |
||||
*/ |
||||
ZHC = "ZHC", |
||||
|
||||
/** |
||||
* 高层供水车 |
||||
*/ |
||||
GCGSC = "GCGSC", |
||||
|
||||
/** |
||||
* 空气呼吸充气车 |
||||
*/ |
||||
KQHXCQC = "KQHXCQC", |
||||
|
||||
//================联动力量===================
|
||||
/** |
||||
* 公安 |
||||
*/ |
||||
GA = "GA", |
||||
|
||||
/** |
||||
* 交警 |
||||
*/ |
||||
JJ = "JJ", |
||||
|
||||
/** |
||||
* 医生 |
||||
*/ |
||||
YS = "YS", |
||||
|
||||
/** |
||||
* 抢修人员 |
||||
*/ |
||||
QXRY = "QXRY", |
||||
|
||||
/** |
||||
* 救护车 |
||||
*/ |
||||
JHC = "JHC", |
||||
|
||||
/** |
||||
* 警车 |
||||
*/ |
||||
JC = "JC", |
||||
|
||||
/** |
||||
* 电力抢修车 |
||||
*/ |
||||
DLQXC = "DLQXC", |
||||
|
||||
/** |
||||
* 燃气抢修车 |
||||
*/ |
||||
RQQXC = "RQQXC", |
||||
|
||||
/** |
||||
* 供水抢修车 |
||||
*/ |
||||
GSQXC = "GSQXC", |
||||
|
||||
/** |
||||
* 环保检测车 |
||||
*/ |
||||
HBJCC = "HBJCC", |
||||
|
||||
/** |
||||
* 交通运输车 |
||||
*/ |
||||
JTYSC = "JTYSC", |
||||
|
||||
/** |
||||
* 卫生防疫车 |
||||
*/ |
||||
WSFYC = "WSFYC", |
||||
|
||||
/** |
||||
* 应急通信车 |
||||
*/ |
||||
YJTXC = "YJTXC", |
||||
|
||||
/** |
||||
* 轿车 |
||||
*/ |
||||
JCA = "JCA", |
||||
|
||||
/** |
||||
* 轿车 |
||||
*/ |
||||
JCB = "JCB", |
||||
|
||||
/** |
||||
* 轿车 |
||||
*/ |
||||
JCC = "JCC", |
||||
|
||||
//===============内部力量=================
|
||||
/** |
||||
* 董事长 |
||||
*/ |
||||
DSZ = "DSZ", |
||||
|
||||
/** |
||||
* 经理 |
||||
*/ |
||||
JL = "JL", |
||||
|
||||
/** |
||||
* 副总 |
||||
*/ |
||||
FZ = "FZ", |
||||
|
||||
/** |
||||
* 秘书 |
||||
*/ |
||||
MS = "MS", |
||||
|
||||
/** |
||||
* 总监 |
||||
*/ |
||||
ZJ = "ZJ", |
||||
|
||||
/** |
||||
* 主管 |
||||
*/ |
||||
ZG = "ZG", |
||||
|
||||
/** |
||||
* 组长 |
||||
*/ |
||||
ZZ = "ZZ", |
||||
|
||||
/** |
||||
* 前台 |
||||
*/ |
||||
QT = "QT", |
||||
|
||||
/** |
||||
* 设计师 |
||||
*/ |
||||
SJS = "SJS", |
||||
|
||||
/** |
||||
* 程序员 |
||||
*/ |
||||
CXY = "CXY", |
||||
|
||||
/** |
||||
* 职员 |
||||
*/ |
||||
ZYA = "ZYA", |
||||
|
||||
/** |
||||
* 职员 |
||||
*/ |
||||
ZYB = "ZYB", |
||||
|
||||
/** |
||||
* 技工 |
||||
*/ |
||||
JG = "JG", |
||||
|
||||
/** |
||||
* 保安 |
||||
*/ |
||||
BA = "BA", |
||||
|
||||
//===================标绘工具===================
|
||||
|
||||
/** |
||||
* 警戒线 |
||||
*/ |
||||
JJX = "JJX", |
||||
|
||||
/** |
||||
* 水带
|
||||
*/ |
||||
SD = "SD", |
||||
|
||||
/** |
||||
* 进攻路线 |
||||
*/ |
||||
JGLX = "JGLX", |
||||
|
||||
/** |
||||
* 撤退 |
||||
*/ |
||||
CT = "CT", |
||||
|
||||
/** |
||||
* 指挥部 |
||||
*/ |
||||
ZHB = "ZHB", |
||||
|
||||
/** |
||||
* 6米拉梯 |
||||
*/ |
||||
LT6 = "LT6", |
||||
|
||||
/** |
||||
* 15米拉梯 |
||||
*/ |
||||
LT15 = "LT15", |
||||
|
||||
/** |
||||
* 分水器 |
||||
*/ |
||||
FSQ = "FSQ", |
||||
|
||||
/** |
||||
* 手抬泵 |
||||
*/ |
||||
STB = "STB", |
||||
|
||||
/** |
||||
* 水炮 |
||||
*/ |
||||
SP = "SP", |
||||
|
||||
/** |
||||
* 文字 |
||||
*/ |
||||
WZ = "WZ", |
||||
|
||||
/** |
||||
* 集结区 |
||||
*/ |
||||
JJQ = "JJQ", |
||||
|
||||
/** |
||||
* 区域设定 |
||||
*/ |
||||
QYSDA = "QYSDA", |
||||
|
||||
/** |
||||
* 区域设定 |
||||
*/ |
||||
QYSDB = "QYSDB", |
||||
} |
||||
|
||||
/** |
||||
* 标记的任务类型 |
||||
*/ |
||||
export enum MarkTask { |
||||
/** |
||||
* 无任务(不打开任务界面) |
||||
*/ |
||||
None, |
||||
|
||||
/** |
||||
* 未知(打开界面,但没有任务列表) |
||||
*/ |
||||
Unknown, |
||||
|
||||
/** |
||||
* 人员 |
||||
*/ |
||||
Person, |
||||
|
||||
/** |
||||
* 车辆 |
||||
*/ |
||||
Car, |
||||
|
||||
/** |
||||
* 水炮 |
||||
*/ |
||||
WaterMonitor |
||||
|
||||
} |
||||
|
@ -0,0 +1,492 @@
|
||||
import { Type } from "class-transformer"; |
||||
import { TsTool } from "src/app/babylon/tool/ts-tool"; |
||||
|
||||
|
||||
import { ArcRotateCameraData } from "../camera-data"; |
||||
import { MarkData } from "./mark-data"; |
||||
|
||||
|
||||
/** |
||||
* 当前单位的所有标绘信息 |
||||
*/ |
||||
export class AllMarkPlanData { |
||||
|
||||
/** |
||||
* 单位ID |
||||
*/ |
||||
institutionID: string; |
||||
|
||||
/** |
||||
* 所有方案 |
||||
*/ |
||||
@Type(() => MarkPlanData) |
||||
datas: MarkPlanData[]; |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* 创建新方案 |
||||
* @param name
|
||||
*/ |
||||
createPlanData(name): MarkPlanData { |
||||
let id = this.getNextPlaneId(); |
||||
let data = new MarkPlanData(id, name, []); |
||||
this.datas.push(data); |
||||
return data; |
||||
} |
||||
|
||||
/** |
||||
* 删除方案 |
||||
*/ |
||||
deletePlanData(id: number) { |
||||
let planeData = this.getMarkPlanById(id); |
||||
if (planeData != null) { |
||||
TsTool.arrayRemove(this.datas, planeData); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取下一个方案的id |
||||
*/ |
||||
getNextPlaneId() { |
||||
let index = -1; |
||||
if (this.datas != null && this.datas.length > 0) { |
||||
index = this.datas[this.datas.length - 1].id; |
||||
} |
||||
index++; |
||||
return index; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 根据id查找标绘方案 |
||||
* @param markPlanId
|
||||
*/ |
||||
getMarkPlanById(markPlanId: number) { |
||||
if (this.datas != null) { |
||||
for (let i = 0; i < this.datas.length; i++) { |
||||
if (this.datas[i].id == markPlanId) { |
||||
return this.datas[i]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 方案数据 |
||||
*/ |
||||
export class MarkPlanData { |
||||
|
||||
/** |
||||
* 唯一身份id |
||||
*/ |
||||
id: number; |
||||
/** |
||||
* 显示的名称 |
||||
*/ |
||||
name: string; |
||||
|
||||
/** |
||||
* 用于UI上排序 |
||||
*/ |
||||
index: number = 0; |
||||
|
||||
/** |
||||
* 所有的标绘节点 |
||||
*/ |
||||
@Type(() => MarkNodeData) |
||||
nodes: MarkNodeData[] = []; |
||||
|
||||
constructor(id: number, name: string, nodes: MarkNodeData[] = []) { |
||||
this.id = id; |
||||
this.index = id; |
||||
this.name = name; |
||||
this.nodes = nodes; |
||||
this.index = 0; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取下一个节点的id |
||||
*/ |
||||
getNextNodeId() { |
||||
let index = -1; |
||||
|
||||
if (this.nodes != null && this.nodes.length > 0) { |
||||
index = this.nodes[this.nodes.length - 1].id; |
||||
} |
||||
|
||||
index++; |
||||
return index; |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 创建方案的子节点 |
||||
* @param name
|
||||
*/ |
||||
createMarkNode(name: string) { |
||||
let id = this.getNextNodeId(); |
||||
let result = new MarkNodeData(id, name); |
||||
|
||||
this.nodes.push(result); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 删除方案的节点 |
||||
* @param id
|
||||
*/ |
||||
deleteMarkNode(id: number) { |
||||
let node = this.getNodeById(id); |
||||
if (node != null) { |
||||
TsTool.arrayRemove(this.nodes, node); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 根据id获取节点 |
||||
* @param id
|
||||
*/ |
||||
getNodeById(id: number) { |
||||
if (this.nodes != null) { |
||||
for (let i = 0; i < this.nodes.length; i++) { |
||||
if (this.nodes[i].id == id) { |
||||
return this.nodes[i]; |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 设置节点数据 |
||||
* @param id //要替换的节点id
|
||||
* @param nodeData //新数据
|
||||
*/ |
||||
setNodeData(id: number, nodeData: MarkNodeData) { |
||||
if (this.nodes != null) { |
||||
for (let i = 0; i < this.nodes.length; i++) { |
||||
if (this.nodes[i].id == id) { |
||||
this.nodes[i] = nodeData; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 标绘节点数据 |
||||
*/ |
||||
export class MarkNodeData { |
||||
|
||||
/** |
||||
* 唯一身份id |
||||
*/ |
||||
id: number; |
||||
|
||||
/** |
||||
* 显示的名称 |
||||
*/ |
||||
name: string; |
||||
|
||||
/** |
||||
* 用于UI上排序 |
||||
*/ |
||||
index: number = 0; |
||||
|
||||
/** |
||||
* 相机数据 |
||||
*/ |
||||
@Type(() => ArcRotateCameraData) |
||||
cameraData: ArcRotateCameraData; |
||||
|
||||
/** |
||||
* 所处环境的信息 |
||||
*/ |
||||
@Type(() => EnvironmentData) |
||||
environmentData: EnvironmentData[]; |
||||
|
||||
/** |
||||
* 自然信息 |
||||
*/ |
||||
@Type(() => NatureData) |
||||
natureData: NatureData; |
||||
|
||||
|
||||
constructor(id: number, name: string) { |
||||
this.id = id; |
||||
this.index = id; |
||||
this.name = name; |
||||
this.cameraData = new ArcRotateCameraData(); |
||||
this.environmentData = []; |
||||
this.natureData = new NatureData(); |
||||
this.index = 0; |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取环境信息 |
||||
* @param id
|
||||
*/ |
||||
getEnvironmentData(id: number) { |
||||
let result = null; |
||||
for (let i = 0; i < this.environmentData.length; i++) { |
||||
if (this.environmentData[i].id == id) { |
||||
result = this.environmentData[i]; |
||||
break; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 改变当前环境值 |
||||
* @param id
|
||||
*/ |
||||
changeNowEnvironmentData(id: number) { |
||||
for (let i = 0; i < this.environmentData.length; i++) { |
||||
if (this.environmentData[i].id == id) { |
||||
this.environmentData[i].isNow = true; |
||||
} |
||||
else { |
||||
this.environmentData[i].isNow = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 根据内容获取 |
||||
* @param isOutdoor
|
||||
* @param buildingId
|
||||
* @param floorId
|
||||
*/ |
||||
getEnvironmentDataByValue(isOutdoor: boolean, |
||||
|
||||
/** |
||||
* 建筑Id |
||||
*/ |
||||
buildingId: string, |
||||
|
||||
/** |
||||
* 所处楼层的id(室内的话) |
||||
*/ |
||||
floorId: string) { |
||||
let result: EnvironmentData = null; |
||||
for (let i = 0; i < this.environmentData.length; i++) { |
||||
if (isOutdoor == true && this.environmentData[i].isOutdoor == true) { |
||||
result = this.environmentData[i]; |
||||
break; |
||||
} |
||||
else if (this.environmentData[i].isOutdoor == isOutdoor && this.environmentData[i].buildingId == buildingId && this.environmentData[i].floorId == floorId) { |
||||
result = this.environmentData[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取当前状态的环境数据 |
||||
*/ |
||||
getCurrentEnvironmentData() { |
||||
let result = this.environmentData[0]; |
||||
for (let i = 0; i < this.environmentData.length; i++) { |
||||
if (this.environmentData[i].isNow) { |
||||
result = this.environmentData[i]; |
||||
break; |
||||
} |
||||
} |
||||
result.isNow = true; |
||||
return result; |
||||
} |
||||
|
||||
addEnvironment(buildingId: string, isOutdoor: boolean, floorId: string) { |
||||
let index = -1; |
||||
for (let i = 0; i < this.environmentData.length; i++) { |
||||
if (this.environmentData[i].id > index) { |
||||
index = this.environmentData[i].id; |
||||
} |
||||
} |
||||
index++; |
||||
|
||||
let newEnvironment = new EnvironmentData(index, buildingId, isOutdoor, floorId); |
||||
this.environmentData.push(newEnvironment); |
||||
|
||||
return newEnvironment; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 环境信息 |
||||
*/ |
||||
export class EnvironmentData { |
||||
|
||||
id: number; |
||||
/** |
||||
* 室外、室内 |
||||
*/ |
||||
isOutdoor: boolean; |
||||
|
||||
/** |
||||
* 建筑Id |
||||
*/ |
||||
buildingId: string; |
||||
|
||||
/** |
||||
* 所处楼层的id(室内的话) |
||||
*/ |
||||
floorId: string; |
||||
|
||||
/** |
||||
* 所有标绘物 |
||||
*/ |
||||
@Type(() => MarkData) |
||||
markDatas: MarkData[] = []; |
||||
|
||||
/** |
||||
* 是否是当前节点 |
||||
*/ |
||||
isNow: boolean; |
||||
|
||||
constructor(id: number, buildingId: string, isOutdoor: boolean, floorId: string) { |
||||
this.id = id; |
||||
this.buildingId = buildingId; |
||||
this.isOutdoor = isOutdoor; |
||||
this.floorId = floorId; |
||||
this.markDatas = []; |
||||
} |
||||
|
||||
/** |
||||
* 添加markData |
||||
* @param markData
|
||||
*/ |
||||
addMarkData(markData: MarkData) { |
||||
this.markDatas.push(markData); |
||||
} |
||||
|
||||
/** |
||||
* 移除markData |
||||
* @param markData
|
||||
*/ |
||||
removeMarkData(markData: MarkData) { |
||||
TsTool.arrayRemove(this.markDatas, markData); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 自然信息 |
||||
*/ |
||||
export class NatureData { |
||||
|
||||
/** |
||||
* 天气 |
||||
*/ |
||||
weather: WeatherType; |
||||
/** |
||||
* 温度 |
||||
*/ |
||||
temperature: number; |
||||
|
||||
/** |
||||
* 风向 |
||||
*/ |
||||
windDirection: WindDirectionType; |
||||
|
||||
/** |
||||
* 风力 |
||||
*/ |
||||
windPower: number; |
||||
|
||||
constructor() { |
||||
this.weather = WeatherType.Sun; |
||||
this.temperature = 26; |
||||
this.windDirection = WindDirectionType.East; |
||||
this.windPower = 3; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 天气类型 |
||||
*/ |
||||
export enum WeatherType { |
||||
/** |
||||
* 晴 |
||||
*/ |
||||
Sun = "Sun", |
||||
/** |
||||
* 阴 |
||||
*/ |
||||
Sloudy = "Sloudy", |
||||
/** |
||||
* 雨 |
||||
*/ |
||||
Rain = "Rain", |
||||
/** |
||||
* 雪 |
||||
*/ |
||||
Snow = "Snow" |
||||
} |
||||
|
||||
/** |
||||
* 方向类型 |
||||
*/ |
||||
export enum WindDirectionType { |
||||
/** |
||||
* 东 |
||||
*/ |
||||
East = "East", |
||||
/** |
||||
* 南 |
||||
*/ |
||||
South = "South", |
||||
|
||||
/** |
||||
* 西 |
||||
*/ |
||||
West = "West", |
||||
|
||||
/** |
||||
* 北 |
||||
*/ |
||||
North = "North", |
||||
|
||||
/** |
||||
* 东南 |
||||
*/ |
||||
SouthEast = "SouthEast", |
||||
|
||||
/** |
||||
* 西南 |
||||
*/ |
||||
SouthWest = "SouthWest", |
||||
|
||||
/** |
||||
* 东北 |
||||
*/ |
||||
NorthEast = "NorthEast", |
||||
|
||||
/** |
||||
* 西北 |
||||
*/ |
||||
NorthWest = "NorthWest", |
||||
|
||||
} |
@ -0,0 +1,50 @@
|
||||
import { MarkTask } from "./mark-data"; |
||||
|
||||
/** |
||||
* 标绘物的属性 |
||||
*/ |
||||
export class MarkProperty { |
||||
|
||||
/** |
||||
* 单位 |
||||
*/ |
||||
institution: string; |
||||
|
||||
/** |
||||
* 编号 |
||||
*/ |
||||
index: number; |
||||
|
||||
/** |
||||
* 任务的类型(预制项) |
||||
*/ |
||||
taskType: MarkTask; |
||||
|
||||
/** |
||||
* 任务 |
||||
*/ |
||||
task: string; |
||||
|
||||
/** |
||||
* 备注 |
||||
*/ |
||||
description: string; |
||||
|
||||
constructor(taskType?: MarkTask, institution: string = "辖区中队", index: number = 1, task: string = "待命", description?: string) { |
||||
this.taskType = taskType |
||||
this.institution = institution |
||||
this.index = index |
||||
this.task = task |
||||
this.description = description |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取单位-编号 |
||||
*/ |
||||
getInstitutionNum() { |
||||
return this.institution + "-" + this.index; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,19 @@
|
||||
import { Vector3 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
import { MarkData } from "../mark-data"; |
||||
|
||||
/** |
||||
* 区域类 |
||||
*/ |
||||
export class MarkData_Area extends MarkData { |
||||
/** |
||||
* 点位 |
||||
*/ |
||||
@Type(() => Vector3) |
||||
pointData: Vector3[]; |
||||
|
||||
/** |
||||
* 颜色 |
||||
*/ |
||||
color: string = "#FF666D"; |
||||
} |
@ -0,0 +1,21 @@
|
||||
import { Vector3 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
import { MarkData } from "../mark-data"; |
||||
|
||||
/** |
||||
* 一条线 |
||||
*/ |
||||
export class MarkData_Line extends MarkData { |
||||
/** |
||||
* 点位 |
||||
*/ |
||||
@Type(() => Vector3) |
||||
pointData: Vector3[] = []; |
||||
|
||||
/** |
||||
* 颜色 |
||||
*/ |
||||
color: string = "#FFD306"; |
||||
|
||||
|
||||
} |
@ -0,0 +1,41 @@
|
||||
import { Vector3 } from "@babylonjs/core/Maths"; |
||||
import { Type } from "class-transformer"; |
||||
import { MarkData } from "../mark-data"; |
||||
|
||||
/** |
||||
* 多个线条 |
||||
*/ |
||||
export class MarkData_multiArrow extends MarkData { |
||||
|
||||
/** |
||||
* 点位 |
||||
*/ |
||||
@Type(() => Vector3) |
||||
pointData: Vector3[]; |
||||
|
||||
/** |
||||
* 颜色 |
||||
*/ |
||||
color: string; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 进攻路线
|
||||
*/ |
||||
export class MarkData_multiArrow_JG extends MarkData_multiArrow { |
||||
/** |
||||
* 颜色 |
||||
*/ |
||||
color: string = "#d71345"; |
||||
} |
||||
|
||||
/** |
||||
* 撤退路线 |
||||
*/ |
||||
export class MarkData_multiArrow_CT extends MarkData_multiArrow { |
||||
/** |
||||
* 颜色 |
||||
*/ |
||||
color: string = "#A9FF00"; |
||||
} |
@ -0,0 +1,31 @@
|
||||
import { Vector3 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
import { MarkData } from "../mark-data"; |
||||
|
||||
/** |
||||
* 多个线条 |
||||
*/ |
||||
export class MarkData_multiLine extends MarkData { |
||||
|
||||
/** |
||||
* 点位 |
||||
*/ |
||||
@Type(() => Vector3) |
||||
pointData: Vector3[]; |
||||
|
||||
/** |
||||
* 颜色 |
||||
*/ |
||||
color: string = "#FF5151"; |
||||
|
||||
/** |
||||
* 管线半径 |
||||
*/ |
||||
radius: number = 0.1; |
||||
|
||||
/** |
||||
* y偏移 |
||||
*/ |
||||
yPos: number = 0; |
||||
|
||||
} |
@ -0,0 +1,18 @@
|
||||
import { TransformData } from "../transform-data"; |
||||
import { BuildingPosType, ModelData } from "./model-data"; |
||||
|
||||
//建筑类 模型数据
|
||||
export class ModelData_building extends ModelData { |
||||
modelType: BuildingPosType;//模型类别
|
||||
baseInfoKey: string;//单位基本信息的key
|
||||
|
||||
|
||||
constructor(key: string, name: string, modelType: BuildingPosType, resName: string, transformData: TransformData, l_resPath: string) { |
||||
super(key, name, null, resName, transformData); |
||||
this.modelType = modelType; |
||||
|
||||
this.resPath = l_resPath; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,280 @@
|
||||
import { ModelData } from "./model-data"; |
||||
import { TransformData } from "../transform-data"; |
||||
import { PropertyData_Base } from "../institution/facility/property-data/property-data-base"; |
||||
|
||||
import { classToClass, Type } from "class-transformer"; |
||||
import { Vector3 } from "@babylonjs/core"; |
||||
import { DataManager } from "src/app/babylon/controller/data-manager"; |
||||
|
||||
|
||||
//设备数据
|
||||
export class ModelData_facility extends ModelData { |
||||
posType: FacilityPosType = FacilityPosType.Outdoor;//位置类型
|
||||
|
||||
facilityType: FacilityType = FacilityType.AQCK;//具体设备类别
|
||||
@Type(() => PropertyData_Base) |
||||
propertyData: PropertyData_Base = null;//属性信息
|
||||
@Type(() => Vector3) |
||||
areaPoints: Vector3[] = [];//区域位点
|
||||
|
||||
|
||||
constructor(key: string, type: FacilityType, name: string, resName: string, transformData: TransformData, posType: FacilityPosType, isModel: boolean = true) { |
||||
|
||||
super(key, name, null, resName, transformData, isModel); |
||||
|
||||
this.facilityType = type; |
||||
this.posType = posType; |
||||
if (type != undefined) { |
||||
|
||||
let showType = ModelData_facility.getShowType(type); |
||||
switch (showType) { |
||||
case FacilityShowType.ModelAndTag: |
||||
this.resName = resName; |
||||
this.resPath = DataManager.getResPath_facility(this.posType, type); |
||||
break; |
||||
case FacilityShowType.AreaAndTag: |
||||
this.areaPoints = this.newAreapPoints(); |
||||
break; |
||||
} |
||||
// this.resPath = ConfigManager.c_resPath_facilitiesRoot + this.posType.toString() + "/" + type.toLowerCase() + "/";
|
||||
this.propertyData = DataManager.createPropertyData(key, type); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 获取表现类型 |
||||
*/ |
||||
getShowtype() { |
||||
let showType = ModelData_facility.getShowType(this.facilityType); |
||||
return showType |
||||
} |
||||
|
||||
clone(key: string): ModelData_facility { |
||||
let result = new ModelData_facility(key, this.facilityType, this.name, this.resName, this.transformData.clone(), this.posType); |
||||
result.propertyData = this.propertyData.clone(key); |
||||
result.areaPoints = classToClass(this.areaPoints); |
||||
return result; |
||||
} |
||||
|
||||
//新建区域位点
|
||||
newAreapPoints(): Vector3[] { |
||||
let size = 10; |
||||
let x = 0.75 * size; |
||||
let z = 0.5 * size; |
||||
let result: Vector3[] = []; |
||||
result.push(new Vector3(0, 0, 1 * size)); |
||||
result.push(new Vector3(x, 0, z)); |
||||
result.push(new Vector3(x, 0, -z)); |
||||
result.push(new Vector3(0, 0, -1 * size)); |
||||
result.push(new Vector3(-x, 0, -z)); |
||||
result.push(new Vector3(-x, 0, z)); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 查询展示方式 |
||||
* @param facilityType 设备具体类型 |
||||
*/ |
||||
static getShowType(facilityType: FacilityType): FacilityShowType { |
||||
let result = FacilityShowType.ModelAndTag; |
||||
switch (facilityType) { |
||||
case FacilityType.AQCK: |
||||
case FacilityType.DSXHS: |
||||
case FacilityType.DXXHS: |
||||
case FacilityType.SZDXXHS: |
||||
case FacilityType.SZDSXHS: |
||||
case FacilityType.DSSBJHQ: |
||||
case FacilityType.DXSBJHQ: |
||||
case FacilityType.QBSBJHQ: |
||||
case FacilityType.DGNSBJHQ: |
||||
|
||||
case FacilityType.PL: |
||||
case FacilityType.TPBZ: |
||||
|
||||
case FacilityType.XKS: |
||||
case FacilityType.BF: |
||||
case FacilityType.SX: |
||||
case FacilityType.LSXFB: |
||||
case FacilityType.WSXFB: |
||||
case FacilityType.CYXFB: |
||||
case FacilityType.SNXHS: |
||||
case FacilityType.FHM: |
||||
case FacilityType.HT: |
||||
case FacilityType.PTDT: |
||||
case FacilityType.XFDT: |
||||
case FacilityType.SSLT: |
||||
case FacilityType.FHJL: result = FacilityShowType.ModelAndTag; break;//展示模型和标签
|
||||
|
||||
case FacilityType.JTQ: |
||||
case FacilityType.JJQ: |
||||
case FacilityType.FHFQ: result = FacilityShowType.AreaAndTag; break;//展示可编辑多边形
|
||||
case FacilityType.GD: result = FacilityShowType.GdAndTag; break;//展示高度和标签
|
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
//设备位置类型(室内还是室外)
|
||||
export enum FacilityPosType { |
||||
Indoor = "indoor", //室内
|
||||
Outdoor = "outdoor", //室外
|
||||
Public = "public",//共有
|
||||
} |
||||
|
||||
//设备展示类型
|
||||
export enum FacilityShowType { |
||||
Tag,//标签
|
||||
ModelAndTag,//模型和标签
|
||||
AreaAndTag,//区域和标签
|
||||
GdAndTag,//高度和标签
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 设备具体类型 |
||||
*/ |
||||
export enum FacilityType { |
||||
//室外
|
||||
/** |
||||
* 安全出口 |
||||
*/ |
||||
AQCK = "AQCK", |
||||
/** |
||||
* 地上消火栓 |
||||
*/ |
||||
DSXHS = "DSXHS", |
||||
/** |
||||
* 地下消火栓 |
||||
*/ |
||||
DXXHS = "DXXHS", |
||||
/** |
||||
* 市政地上消火栓 |
||||
*/ |
||||
SZDSXHS = "SZDSXHS", |
||||
/** |
||||
* 市政地下消火栓 |
||||
*/ |
||||
SZDXXHS = "SZDXXHS", |
||||
/** |
||||
* 地上水泵接合器 |
||||
*/ |
||||
DSSBJHQ = "DSSBJHQ", |
||||
/** |
||||
* 地下水泵接合器 |
||||
*/ |
||||
DXSBJHQ = "DXSBJHQ", |
||||
/** |
||||
* 墙壁水泵接合器 |
||||
*/ |
||||
QBSBJHQ = "QBSBJHQ", |
||||
/** |
||||
* 多功能水泵接合器 |
||||
*/ |
||||
DGNSBJHQ = "DGNSBJHQ", |
||||
|
||||
/** |
||||
* 高度 |
||||
*/ |
||||
GD = "GD", |
||||
/** |
||||
* 毗邻 |
||||
*/ |
||||
PL = "PL", |
||||
/** |
||||
* 禁停区 |
||||
*/ |
||||
JTQ = "JTQ", |
||||
/** |
||||
* 集结区 |
||||
*/ |
||||
JJQ = "JJQ", |
||||
/** |
||||
* 图片标注 |
||||
*/ |
||||
TPBZ = "TPBZ",//
|
||||
|
||||
//室内
|
||||
/** |
||||
* 消控室 |
||||
*/ |
||||
XKS = "XKS", |
||||
/** |
||||
* 泵房 |
||||
*/ |
||||
BF = "BF", |
||||
/** |
||||
* 水箱 |
||||
*/ |
||||
SX = "SX", |
||||
/** |
||||
* 立式消防泵 |
||||
*/ |
||||
LSXFB = "LSXFB", |
||||
/** |
||||
* 卧式消防泵 |
||||
*/ |
||||
WSXFB = "WSXFB", |
||||
/** |
||||
* 柴油消防泵 |
||||
*/ |
||||
CYXFB = "CYXFB", |
||||
/** |
||||
* 室内消火栓 |
||||
*/ |
||||
SNXHS = "SNXHS", |
||||
/** |
||||
* 防火门 |
||||
*/ |
||||
FHM = "FHM", |
||||
/** |
||||
* 防火卷帘 |
||||
*/ |
||||
FHJL = "FHJL", |
||||
|
||||
/** |
||||
* 疏散楼梯 |
||||
*/ |
||||
SSLT = "SSLT", |
||||
/** |
||||
* 消防电梯 |
||||
*/ |
||||
XFDT = "XFDT", |
||||
/** |
||||
* 普通电梯 |
||||
*/ |
||||
PTDT = "PTDT", |
||||
/** |
||||
* 货梯 |
||||
*/ |
||||
HT = "HT", |
||||
/** |
||||
* 避难层 |
||||
*/ |
||||
BNC = "BNC", |
||||
/** |
||||
* 危险源 |
||||
*/ |
||||
WXY = "WXY", |
||||
/** |
||||
* 重点区域 |
||||
*/ |
||||
ZDQY = "ZDQY", |
||||
/** |
||||
* 点位标注 |
||||
*/ |
||||
DWBZ = "DWBZ", |
||||
|
||||
/** |
||||
* 防火分区 |
||||
*/ |
||||
FHFQ = "FHFQ", |
||||
} |
@ -0,0 +1,71 @@
|
||||
import { TransformData } from '../transform-data'; |
||||
import { Type } from 'class-transformer'; |
||||
|
||||
//模型 数据
|
||||
export class ModelData { |
||||
|
||||
key: string; //身份唯一标识
|
||||
name: string; //用户定义的名称
|
||||
resName: string; //资源名称
|
||||
resPath: string; //资源路径(局部) 可使用 DataManager.getResPath进行构造
|
||||
@Type(() => TransformData) |
||||
transformData: TransformData; //变换信息
|
||||
version: number = 1;//版本号
|
||||
isModel: boolean;//是否是现成的模型要加载
|
||||
|
||||
constructor( |
||||
key?: string, |
||||
name?: string, |
||||
resPath?: string, |
||||
resName?: string, |
||||
transformData?: TransformData, |
||||
isModel: boolean = true |
||||
) { |
||||
this.key = key; |
||||
this.name = name; |
||||
this.resPath = resPath; |
||||
this.resName = resName; |
||||
this.isModel = isModel; |
||||
if (transformData == null) { |
||||
this.transformData = new TransformData(); |
||||
} |
||||
else { |
||||
this.transformData = transformData; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
//建筑模型位置类别
|
||||
export enum BuildingPosType { |
||||
Default = 'default', |
||||
OutDoor = 'outdoor', //建筑外观
|
||||
Environment = 'environment', //环境
|
||||
Indoor = 'indoor', //室内
|
||||
} |
||||
|
||||
//模型类别
|
||||
export enum ModelType { |
||||
Building, //建筑
|
||||
Facility, //设施
|
||||
Mark,//态势标绘
|
||||
} |
||||
|
||||
//数据记录的类型
|
||||
export enum DataRecordType { |
||||
Number,//数字
|
||||
String,//字符串
|
||||
Texture,//字符串
|
||||
} |
||||
|
||||
//数据记录
|
||||
export class DataRecord { |
||||
|
||||
dataRecordType: DataRecordType;//记录的类型
|
||||
|
||||
value: string;//值
|
||||
|
||||
} |
||||
|
@ -0,0 +1,79 @@
|
||||
import { Type } from "class-transformer"; |
||||
import { TsTool } from "src/app/babylon/tool/ts-tool"; |
||||
|
||||
|
||||
import { ModelData } from "./model-data"; |
||||
import { FacilityType, ModelData_facility } from "./model-data-facility"; |
||||
|
||||
//模型编辑信息(外观、环境、室内分层)
|
||||
export class ModelEditData { |
||||
index: number = 0; //楼层、顺序用于ui上排序
|
||||
isRefugeFloor: boolean = false;//避难层
|
||||
@Type(() => ModelData) |
||||
modelData: ModelData; //模型信息
|
||||
@Type(() => FacilityDatasByType) |
||||
facilities: FacilityDatasByType[] = []; //含有哪些设备
|
||||
|
||||
constructor() { |
||||
// this.belongToBuilding = belongToBuilding;
|
||||
this.modelData = new ModelData(); |
||||
this.index = 0; |
||||
} |
||||
//添加设备
|
||||
addFacility(modelData_facility: ModelData_facility) { |
||||
|
||||
let facility = this.getFacilitiesByType(modelData_facility.facilityType); |
||||
|
||||
if (facility == null) { |
||||
let newDataByType = new FacilityDatasByType(modelData_facility.facilityType); |
||||
this.facilities.push(newDataByType); |
||||
facility = newDataByType.facilities; |
||||
} |
||||
|
||||
facility.push(modelData_facility); |
||||
} |
||||
//移除设备
|
||||
removeFacility(modelData_facility: ModelData_facility) { |
||||
let facility = this.getFacilitiesByType(modelData_facility.facilityType); |
||||
if (facility == null) { |
||||
console.error(this.modelData.key + "移除设备出错" + modelData_facility.key); |
||||
} |
||||
else { |
||||
TsTool.arrayRemove(facility, modelData_facility); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 根据设备类型获取设备数据 |
||||
* @param facilityType 设备类型 |
||||
*/ |
||||
getFacilitiesByType(facilityType: FacilityType) { |
||||
let result: ModelData_facility[] = null; |
||||
for (let i = 0; i < this.facilities.length; i++) { |
||||
if (this.facilities[i].facilityType == facilityType) { |
||||
result = this.facilities[i].facilities; |
||||
return result; |
||||
} |
||||
} |
||||
return result; |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 根据类型储存的设备数据 |
||||
*/ |
||||
export class FacilityDatasByType { |
||||
|
||||
facilityType: FacilityType; |
||||
|
||||
@Type(() => ModelData_facility) |
||||
facilities: ModelData_facility[] = []; //含有哪些设备
|
||||
|
||||
constructor(type: FacilityType) { |
||||
this.facilityType = type; |
||||
this.facilities = []; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,42 @@
|
||||
import { Quaternion, Vector3 } from "@babylonjs/core"; |
||||
import { Type } from "class-transformer"; |
||||
import "reflect-metadata"; |
||||
|
||||
//变换信息
|
||||
export class TransformData { |
||||
|
||||
@Type(() => Vector3) |
||||
position: Vector3 = new Vector3(0, 0, 0); |
||||
|
||||
@Type(() => Vector3) |
||||
rotation: Vector3 = new Vector3(0, 0, 0); |
||||
|
||||
@Type(() => Quaternion) |
||||
rotationQuaternion: Quaternion = new Quaternion(); |
||||
|
||||
@Type(() => Vector3) |
||||
scaling: Vector3 = new Vector3(0, 0, 0); //在babylon中,相对父节点的当前缩放
|
||||
|
||||
@Type(() => Vector3) |
||||
originalScaling: Vector3 = new Vector3(0, 0, 0); //原始缩放
|
||||
|
||||
clone(): TransformData { |
||||
let result = new TransformData(); |
||||
|
||||
result.position = this.position.clone(); |
||||
result.rotation = this.rotation.clone(); |
||||
if ( |
||||
result.rotationQuaternion != null && |
||||
result.rotationQuaternion != undefined |
||||
) { |
||||
result.rotationQuaternion = this.rotationQuaternion.clone(); |
||||
} |
||||
|
||||
result.scaling = this.scaling.clone(); |
||||
result.originalScaling = this.originalScaling.clone(); |
||||
|
||||
return result; |
||||
} |
||||
} |
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { BuildingInfo } from "./building-info"; |
||||
|
||||
/** |
||||
* 化工厂类建筑 |
||||
*/ |
||||
export class BuildingInfo_ChemicalPlant extends BuildingInfo { |
||||
|
||||
} |
@ -0,0 +1,55 @@
|
||||
import { TransformNode } from '@babylonjs/core'; |
||||
import { BuildingStatus } from 'src/app/babylon/controller/status/building-status'; |
||||
import { IndoorStatus } from 'src/app/babylon/controller/status/indoor-status'; |
||||
import { StatusManager } from 'src/app/babylon/controller/status/status-manager'; |
||||
import { TsTool } from 'src/app/babylon/tool/ts-tool'; |
||||
|
||||
|
||||
import { BuildingInfo } from './building-info'; |
||||
|
||||
//环境数据
|
||||
export class BuildingInfo_Environment extends BuildingInfo { |
||||
|
||||
|
||||
readonly c_FuGaiCeng = "FuGaiCeng";//覆盖层关键字
|
||||
go_FuGaiCeng: TransformNode; |
||||
|
||||
/** |
||||
* 更新覆盖层。 室外模式显示覆盖层,室内模式隐藏 |
||||
*/ |
||||
updateFuGaiCeng() { |
||||
if (this.go_FuGaiCeng == null) { |
||||
return; |
||||
} |
||||
let currentStatus = StatusManager.s_currentStatus; |
||||
if (currentStatus instanceof IndoorStatus) { |
||||
this.go_FuGaiCeng.setEnabled(true); |
||||
} |
||||
else if (currentStatus instanceof BuildingStatus) { |
||||
this.go_FuGaiCeng.setEnabled(false); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 设置modelInfo时 |
||||
*/ |
||||
onSetModel() { |
||||
super.onSetModel(); |
||||
|
||||
if (this.ModelInfo != null && this.ModelInfo.modelBox != null) { |
||||
console.log("查找覆盖层", this.ModelInfo.modelBox); |
||||
let allChildren = this.ModelInfo.modelBox.getChildTransformNodes(false); |
||||
if (allChildren != null) { |
||||
for (let i = 0; i < allChildren.length; i++) { |
||||
if (TsTool.stringContain(allChildren[i].name, this.c_FuGaiCeng)) { |
||||
this.go_FuGaiCeng = allChildren[i]; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,11 @@
|
||||
import { BuildingData_Normal } from "../../data/institution/building/building-data"; |
||||
import { ModelInfo_building } from "../model/model-info-building"; |
||||
import { BuildingInfo } from "./building-info"; |
||||
|
||||
//普通大楼
|
||||
export class BuildingInfo_Normal extends BuildingInfo { |
||||
constructor(buildingData: BuildingData_Normal, modelInfo: ModelInfo_building) { |
||||
super(buildingData, modelInfo) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,118 @@
|
||||
import { Vector3 } from "@babylonjs/core"; |
||||
import { InfoManager } from "src/app/babylon/controller/info-manager"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { BuildingStatus } from "src/app/babylon/controller/status/building-status"; |
||||
import { StatusManager } from "src/app/babylon/controller/status/status-manager"; |
||||
import { GizmoTool } from "src/app/babylon/tool/gizmo-tool"; |
||||
|
||||
import { BuildingData } from "../../data/institution/building/building-data"; |
||||
import { TransformData } from "../../data/transform-data"; |
||||
import { ModelInfo_building } from "../model/model-info-building"; |
||||
|
||||
//基本建筑信息
|
||||
export class BuildingInfo { |
||||
/** |
||||
* 所属建筑的数据 |
||||
*/ |
||||
buildingData: BuildingData; |
||||
/** |
||||
* 本模型的数据(室外建筑或室内某层) |
||||
*/ |
||||
private modelInfo: ModelInfo_building; |
||||
isDisposed = false;//已经释放了
|
||||
isEnable = true;//显示状态
|
||||
constructor(buildingData: BuildingData, modelInfo: ModelInfo_building) { |
||||
this.buildingData = buildingData; |
||||
this.ModelInfo = modelInfo; |
||||
this.isDisposed = false; |
||||
} |
||||
|
||||
/** |
||||
* 本模型的数据(室外建筑或室内某层) |
||||
*/ |
||||
get ModelInfo() { |
||||
return this.modelInfo; |
||||
} |
||||
|
||||
set ModelInfo(value: ModelInfo_building) { |
||||
this.modelInfo = value; |
||||
if (this.isDisposed) { |
||||
this.dispose(); |
||||
return; |
||||
} |
||||
if (value != null) { |
||||
let modelInfo = this.modelInfo; |
||||
if (modelInfo.modelData.transformData == null) { |
||||
modelInfo.modelData.transformData = new TransformData(); |
||||
} |
||||
|
||||
if ( |
||||
modelInfo.modelData.transformData.originalScaling.equals(Vector3.Zero()) |
||||
) { |
||||
//表示是新建
|
||||
modelInfo.modelData.transformData.position = modelInfo.modelBox.position; |
||||
modelInfo.modelData.transformData.rotation = modelInfo.modelBox.rotation; |
||||
modelInfo.modelData.transformData.rotationQuaternion = |
||||
modelInfo.modelBox.rotationQuaternion; |
||||
modelInfo.modelData.transformData.originalScaling = modelInfo.modelBox.absoluteScaling.clone(); |
||||
modelInfo.modelData.transformData.scaling = modelInfo.modelBox.absoluteScaling.clone(); |
||||
} //已有数据,进行还原
|
||||
else { |
||||
modelInfo.modelBox.position = modelInfo.modelData.transformData.position; |
||||
modelInfo.modelBox.rotation = modelInfo.modelData.transformData.rotation; |
||||
modelInfo.modelBox.rotationQuaternion = |
||||
modelInfo.modelData.transformData.rotationQuaternion; |
||||
} |
||||
this.ModelInfo.buildingType = this.buildingData.buildingType; |
||||
this.ModelInfo.setEnable(this.isEnable); |
||||
this.onSetModel(); |
||||
//this.initFacility();
|
||||
|
||||
|
||||
} |
||||
|
||||
// if (!this.isEnable) {
|
||||
|
||||
// }
|
||||
// else {
|
||||
// }
|
||||
} |
||||
|
||||
/** |
||||
* 初始化设备 |
||||
*/ |
||||
initFacility() { |
||||
if (StatusManager.s_currentStatus instanceof BuildingStatus) { |
||||
InfoManager.createFacilityInfos(this.buildingData.outdoorData, this); |
||||
this.ModelInfo.showFacilityUI(false); |
||||
} |
||||
} |
||||
|
||||
setEnable(enable: boolean) { |
||||
this.isEnable = enable; |
||||
if (this.ModelInfo != null) { |
||||
this.ModelInfo.setEnable(enable); |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 设置模型了 |
||||
*/ |
||||
onSetModel() { |
||||
|
||||
} |
||||
|
||||
//释放
|
||||
dispose() { |
||||
this.isDisposed = true; |
||||
StatusManager.getStatus(BuildingStatus).buildingWindow.clearFacilityInfos(this); |
||||
if (this.modelInfo != null) { |
||||
if (GizmoTool.s_nowPickAim == this.modelInfo) { |
||||
GizmoTool.onPickMeshInfoObservable.notifyObservers(null); |
||||
} |
||||
SceneManager.destroyModel(this.modelInfo); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,73 @@
|
||||
|
||||
import { MarkType } from "../../data/mark/mark-data"; |
||||
import { ModelInfo_mark } from "./model-info-mark"; |
||||
|
||||
/** |
||||
* 所有标记素材的预制体信息 |
||||
*/ |
||||
export class AllMarkInfo { |
||||
/** |
||||
* 灾情 |
||||
*/ |
||||
marks_Disaster: Map<MarkType, ModelInfo_mark> = new Map(); |
||||
|
||||
/** |
||||
* 消防力量 |
||||
*/ |
||||
|
||||
marks_FireFighting: Map<MarkType, ModelInfo_mark> = new Map(); |
||||
|
||||
/** |
||||
* 联动力量 |
||||
*/ |
||||
|
||||
marks_Linkage: Map<MarkType, ModelInfo_mark> = new Map(); |
||||
|
||||
/** |
||||
* 内部力量 |
||||
*/ |
||||
|
||||
marks_Inside: Map<MarkType, ModelInfo_mark> = new Map(); |
||||
|
||||
/** |
||||
* 标绘工具 |
||||
*/ |
||||
|
||||
marks_Tool: Map<MarkType, ModelInfo_mark> = new Map(); |
||||
|
||||
|
||||
// /**
|
||||
// * 根据类型,找到预制体info
|
||||
// * @param data
|
||||
// */
|
||||
// getMarkPrefab(data: MarkData): ModelInfo_mark {
|
||||
|
||||
// let map: Map<MarkType, ModelInfo_mark>;
|
||||
// switch (data.tagPos) {
|
||||
// case MarkTagPos.Disaster:
|
||||
// map = this.marks_Disaster;
|
||||
// break;
|
||||
// case MarkTagPos.FireFighting:
|
||||
// map = this.marks_FireFighting;
|
||||
// break;
|
||||
// case MarkTagPos.Inside:
|
||||
// map = this.marks_Inside;
|
||||
// break;
|
||||
// case MarkTagPos.Linkage:
|
||||
// map = this.marks_Linkage;
|
||||
// break;
|
||||
// case MarkTagPos.Tool:
|
||||
// map = this.marks_Tool;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (!map.has(data.type)) {
|
||||
// let markInfoPrefab = new ModelInfo_mark(data, true);
|
||||
// map.set(data.type, markInfoPrefab);
|
||||
// }
|
||||
|
||||
// return map.get(data.type);
|
||||
// }
|
||||
|
||||
|
||||
} |
@ -0,0 +1,130 @@
|
||||
|
||||
import { TsTool } from "src/app/babylon/tool/ts-tool"; |
||||
import { MarkTagPos, MarkType } from "../../data/mark/mark-data"; |
||||
import { MarkNodeData, MarkPlanData } from "../../data/mark/mark-plan-data"; |
||||
import { ModelInfo_mark } from "./model-info-mark"; |
||||
|
||||
/** |
||||
* 标绘方案数据(一级节点的集合) |
||||
*/ |
||||
export class MarkNodeInfo { |
||||
|
||||
/** |
||||
* 所属的方案数据 |
||||
*/ |
||||
belongToPlanData: MarkPlanData; |
||||
/** |
||||
* 源数据 |
||||
*/ |
||||
nodeData: MarkNodeData; |
||||
|
||||
/** |
||||
* 运行时的标绘数据 |
||||
*/ |
||||
markInfos: Map<MarkTagPos, ModelInfo_mark[]> = new Map(); |
||||
|
||||
currentMarkDataIndex = -1; |
||||
|
||||
|
||||
constructor(belongToPlanData: MarkPlanData, nodeData: MarkNodeData) { |
||||
this.belongToPlanData = belongToPlanData; |
||||
this.nodeData = nodeData; |
||||
} |
||||
|
||||
/** |
||||
* 获取标绘物 |
||||
* @param tagPos
|
||||
* @param type
|
||||
* @param id
|
||||
*/ |
||||
getMarkInfo(tagPos: MarkTagPos, type: MarkType, id: string) { |
||||
let result: ModelInfo_mark = null; |
||||
if (this.markInfos.has(tagPos)) { |
||||
let array = this.markInfos.get(tagPos); |
||||
for (let i = 0; i < array.length; i++) { |
||||
if (array[i].markData.key == id) { |
||||
result = array[i]; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 新增标绘物 |
||||
* @param markInfo
|
||||
* @param addToData //新增时,需要添加进数据层
|
||||
*/ |
||||
addMarkInfo(markInfo: ModelInfo_mark, addToData: boolean) { |
||||
if (!this.markInfos.has(markInfo.markData.tagPos)) { |
||||
this.markInfos.set(markInfo.markData.tagPos, []); |
||||
} |
||||
this.markInfos.get(markInfo.markData.tagPos).push(markInfo); |
||||
|
||||
if (addToData) { |
||||
this.nodeData.getCurrentEnvironmentData().addMarkData(markInfo.markData);//修改数据层
|
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 删除标绘物 |
||||
* @param markInfo
|
||||
*/ |
||||
removeMarkInfo(markInfo: ModelInfo_mark) { |
||||
if (this.markInfos.has(markInfo.markData.tagPos)) { |
||||
TsTool.arrayRemove(this.markInfos.get(markInfo.markData.tagPos), markInfo); |
||||
} |
||||
this.nodeData.getCurrentEnvironmentData().removeMarkData(markInfo.markData); |
||||
markInfo.dispose(); |
||||
} |
||||
|
||||
/** |
||||
* 获取下一个标绘物的id |
||||
*/ |
||||
getNextMarkDataId() { |
||||
//console.log(this.currentMarkDataIndex, 1);
|
||||
let environmentData = this.nodeData.getCurrentEnvironmentData(); |
||||
if (this.currentMarkDataIndex < 0) { |
||||
if (this.nodeData != null && environmentData.markDatas.length > 0) { |
||||
this.currentMarkDataIndex = Number(environmentData.markDatas[environmentData.markDatas.length - 1].key); |
||||
//console.log(this.currentMarkDataIndex, this.nodeData.markDatas[this.nodeData.markDatas.length - 1].key);
|
||||
} |
||||
} |
||||
this.currentMarkDataIndex++; |
||||
//console.log(this.currentMarkDataIndex, "=====");
|
||||
return this.currentMarkDataIndex; |
||||
} |
||||
|
||||
/** |
||||
* 清空标绘物(表现层和逻辑层) |
||||
*/ |
||||
clearAllMarkDataAndInfo() { |
||||
let currentEnvironmentData = this.nodeData.getCurrentEnvironmentData(); |
||||
currentEnvironmentData.markDatas.length = 0; |
||||
this.nodeData.environmentData.length = 0; |
||||
this.nodeData.environmentData.push(currentEnvironmentData); |
||||
this.disposeInfo(); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 只释放表现层 |
||||
*/ |
||||
disposeInfo() { |
||||
this.markInfos.forEach((value: ModelInfo_mark[], key: MarkTagPos, map: Map<MarkTagPos, ModelInfo_mark[]>) => { |
||||
if (value != null) { |
||||
for (let i = 0; i < value.length; i++) { |
||||
value[i].dispose(); |
||||
} |
||||
} |
||||
}); |
||||
this.markInfos.clear(); |
||||
this.currentMarkDataIndex = -1; |
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,535 @@
|
||||
import { AbstractMesh, Color3, EventState, Mesh, MeshBuilder, ParticleSystem, PointerDragBehavior, Vector3 } from "@babylonjs/core"; |
||||
import { Button } from "@babylonjs/gui/2D/controls/button"; |
||||
import { Control } from "@babylonjs/gui/2D/controls/control"; |
||||
import { Ellipse } from "@babylonjs/gui/2D/controls/ellipse"; |
||||
import { Rectangle } from "@babylonjs/gui/2D/controls/rectangle"; |
||||
import { TextBlock, TextWrapping } from "@babylonjs/gui/2D/controls/textBlock"; |
||||
import { Vector2WithInfo } from "@babylonjs/gui/2D/math2D"; |
||||
import { classToClass } from "class-transformer"; |
||||
import { ConfigManager } from "src/app/babylon/controller/config-manager"; |
||||
import { MarkInfoChangeType, Event_MarkInfoChange } from "src/app/babylon/controller/event-manager/events/event-mark-info-change"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { UIManager } from "src/app/babylon/controller/ui-manager"; |
||||
import { BabylonTool } from "src/app/babylon/tool/babylon-tool"; |
||||
import { BabylonUIStyleTool } from "src/app/babylon/tool/babylon-ui-style-tool"; |
||||
import { ParticleSystemTool } from "src/app/babylon/tool/particle-system-tool"; |
||||
import { TsTool } from "src/app/babylon/tool/ts-tool"; |
||||
import { MarkWindow } from "src/app/babylon/view/mark-window/mark-window"; |
||||
|
||||
import { ChildNodeData, MarkData, MarkTask, MarkType } from "../../data/mark/mark-data"; |
||||
import { BuildingInfo } from "../building/building-info"; |
||||
import { ModelInfo } from "../model/model-info"; |
||||
|
||||
/** |
||||
* 标绘的运行时数据 |
||||
*/ |
||||
export class ModelInfo_mark extends ModelInfo { |
||||
/** |
||||
* 标绘的源数据 |
||||
*/ |
||||
markData: MarkData; |
||||
|
||||
/** |
||||
* 所属建筑 |
||||
*/ |
||||
belongToBuilding: BuildingInfo; |
||||
/** |
||||
* 选中状态 |
||||
*/ |
||||
isSelect: boolean = false; |
||||
ui_select: Ellipse; |
||||
|
||||
|
||||
/** |
||||
* 头部跟随mesh |
||||
*/ |
||||
headMesh: Mesh; |
||||
|
||||
uiFollowHead: Rectangle;//头部跟随节点
|
||||
uiFollowHeadBg: Rectangle;//头部跟随节点的背景
|
||||
uiNumber: TextBlock;//标号
|
||||
uiTask: TextBlock;//任务
|
||||
|
||||
|
||||
|
||||
readonly c_highLightColor = Color3.Green(); |
||||
readonly c_uiDefaultWidth = 100;//默认UI宽度
|
||||
|
||||
/** |
||||
* 水枪强度——最小 |
||||
*/ |
||||
static readonly c_waterPower_min: number = 5; |
||||
/** |
||||
* 水枪强度——最大 |
||||
*/ |
||||
static readonly c_waterPower_max: number = 30; |
||||
|
||||
|
||||
constructor(markData: MarkData, |
||||
models: AbstractMesh[], |
||||
modelBox: AbstractMesh, |
||||
belongToBuilding: BuildingInfo, |
||||
isNew: boolean) { |
||||
super(markData.key, markData, models, modelBox, isNew); |
||||
|
||||
this.belongToBuilding = belongToBuilding; |
||||
|
||||
} |
||||
|
||||
// 根据名字找到子对象数据
|
||||
public getChildrenDataByName(name: string): ChildNodeData { |
||||
const data = this.markData.childrenNodeData.filter(item => item.name === name); |
||||
if (data.length > 0) { |
||||
return data[0] |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
onCreate(isNew: boolean) { |
||||
this.markData = this.modelData as MarkData; |
||||
} |
||||
|
||||
|
||||
onCreateFollowUI() { |
||||
super.onCreateFollowUI(); |
||||
// console.log("创建跟随UI");
|
||||
let instance = this; |
||||
let modelData = this.modelData as MarkData; |
||||
let posType = modelData.tagPos; |
||||
// let iconPath = ConfigManager.getMarkIconUrl(posType, modelData.type);
|
||||
BabylonUIStyleTool.setStyle_size(this.uiFollowRoot, ConfigManager.c_size_facilityIconSize + "px", ConfigManager.c_size_facilityIconSize + "px"); |
||||
this.uiFollowRoot.thickness = 0; |
||||
|
||||
|
||||
this.ui_select = new Ellipse("select"); |
||||
|
||||
|
||||
this.uiFollowRoot.addControl(this.ui_select); |
||||
this.ui_select.background = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.ui_select.thickness = 0; |
||||
this.ui_select.width = 0.95; |
||||
this.ui_select.height = 0.95; |
||||
this.ui_select.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.ui_select.shadowBlur = 3; |
||||
this.ui_select.isVisible = false; |
||||
|
||||
// this.uiIconBtn = Button.CreateImageButton("iconPath", "", iconPath);
|
||||
// this.uiIconBtn.thickness = 0;
|
||||
// this.uiIconBtn.image.width = 0.9;
|
||||
// this.uiIconBtn.image.height = 0.9;
|
||||
// this.uiIconBtn.image.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
|
||||
// this.uiIconBtn.image.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
|
||||
// this.uiFollowRoot.addControl(this.uiIconBtn);
|
||||
|
||||
|
||||
// this.uiIconBtn.onPointerClickObservable.add(() => {
|
||||
// instance.onStopLongPress(null, null);
|
||||
// });
|
||||
|
||||
this.uiFollowRoot.zIndex = BabylonUIStyleTool.c_zIndex_facilityIcon; |
||||
|
||||
this.markData = this.modelData as MarkData; |
||||
if (this.markData.property != null && this.markData.property.taskType != MarkTask.None) { |
||||
|
||||
this.headMesh = MeshBuilder.CreateBox("headMesh", { size: 0.001 }); |
||||
this.headMesh.position = this.modelBox.absolutePosition.add(new Vector3(0, this.modelBox.scaling.y * 0.5, 0)).add(new Vector3(0, 0.5, 0)); |
||||
this.headMesh.setParent(this.modelBox); |
||||
|
||||
|
||||
this.uiFollowHead = Button.CreateSimpleButton('followHead_' + this.key, ""); |
||||
UIManager.Instance.uiRoot.addControl(this.uiFollowHead); |
||||
this.uiFollowHead.width = this.c_uiDefaultWidth + "px"; |
||||
this.uiFollowHead.height = "50px"; |
||||
this.uiFollowHead.thickness = 0; |
||||
this.uiFollowHead.linkWithMesh(this.headMesh); |
||||
this.uiFollowHead.onPointerClickObservable.add(() => { |
||||
MarkWindow.instance.selectMarkDataFrom3d(instance, true); |
||||
instance.lookAt(); |
||||
}); |
||||
|
||||
this.uiFollowHeadBg = new Rectangle('bg'); |
||||
this.uiFollowHead.addControl(this.uiFollowHeadBg); |
||||
this.uiFollowHeadBg.width = 1; |
||||
this.uiFollowHeadBg.alpha = 0.7; |
||||
this.uiFollowHeadBg.color = BabylonUIStyleTool.c_color_3d_blueLight; |
||||
this.uiFollowHeadBg.background = BabylonUIStyleTool.c_color_3d_blueBg; |
||||
|
||||
|
||||
this.uiNumber = new TextBlock(this.modelData.key + "-num", this.markData.property.getInstitutionNum()); |
||||
this.uiFollowHead.addControl(this.uiNumber); |
||||
this.uiNumber.width = 1; |
||||
this.uiNumber.height = 0.5; |
||||
this.uiNumber.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
this.uiNumber.color = "white"; |
||||
this.uiNumber.shadowBlur = 2; |
||||
this.uiNumber.textWrapping = TextWrapping.Clip; |
||||
this.uiNumber.resizeToFit = true; |
||||
|
||||
this.uiTask = new TextBlock(this.modelData.key + "-task", this.markData.property.task); |
||||
this.uiFollowHead.addControl(this.uiTask); |
||||
this.uiTask.width = 1; |
||||
this.uiTask.height = 0.5; |
||||
this.uiTask.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM |
||||
this.uiTask.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.uiTask.shadowBlur = 1; |
||||
this.uiTask.textWrapping = TextWrapping.Clip; |
||||
this.uiTask.resizeToFit = true; |
||||
|
||||
this.updateProperty(); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
//终止长按
|
||||
onStopLongPress(eventData: Vector2WithInfo, eventState: EventState) { |
||||
// this.onClickMeshIconBtn(eventData,eventState);
|
||||
MarkWindow.instance.selectMarkDataFrom3d(this, true); |
||||
} |
||||
|
||||
/** |
||||
* 选中 |
||||
* @param select
|
||||
*/ |
||||
onSelect(select: boolean) { |
||||
this.isSelect = select; |
||||
// this.lookAt();
|
||||
if (select) { |
||||
SceneManager.Instance.addToHighLight(this.modelBox as Mesh, this.c_highLightColor); |
||||
if (this.pointerDragBehavior == null) { |
||||
this.pointerDragBehavior = new PointerDragBehavior({ dragPlaneNormal: Vector3.Up() }); //平面内移动
|
||||
this.modelBox.addBehavior(this.pointerDragBehavior); |
||||
this.pointerDragBehavior.onDragEndObservable.add((event) => { |
||||
// instance.modelData.transformData.position = instance.modelBox.position;
|
||||
}) |
||||
} |
||||
else { |
||||
//this.pointerDragBehavior.enabled = true;
|
||||
} |
||||
|
||||
// SceneManager.Instance.defaultCamera.target = this.modelBox.absolutePosition.clone()
|
||||
// SceneManager.Instance.defaultCamera.setTarget(this.modelBox.absolutePosition.clone());
|
||||
|
||||
} |
||||
else { |
||||
SceneManager.Instance.removeFromHighLight(this.modelBox as Mesh) |
||||
if (this.pointerDragBehavior != null) { |
||||
//this.pointerDragBehavior.enabled = false; //停止拖拽
|
||||
} |
||||
} |
||||
|
||||
let eventType: MarkInfoChangeType = select ? MarkInfoChangeType.Select : MarkInfoChangeType.UnSelect; |
||||
Event_MarkInfoChange.dispatch(eventType, this); |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 聚焦 |
||||
*/ |
||||
lookAt() { |
||||
BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, this.modelBox, true, null); |
||||
} |
||||
|
||||
/** |
||||
* 更新属性显示 |
||||
*/ |
||||
updateProperty() { |
||||
if (this.markData.property.taskType != MarkTask.None) { |
||||
this.uiNumber.text = this.markData.property.getInstitutionNum(); |
||||
this.uiTask.text = this.markData.property.task; |
||||
|
||||
let instance = this; |
||||
setTimeout(() => { |
||||
if (instance.uiNumber == null) { |
||||
return; |
||||
} |
||||
let numWidth = instance.uiNumber.widthInPixels; |
||||
let taskWidth = instance.uiTask.widthInPixels; |
||||
let maxWidth = Math.max(numWidth, taskWidth, this.c_uiDefaultWidth); |
||||
instance.uiFollowHead.widthInPixels = maxWidth; |
||||
// instance.uiFollowHeadBg.widthInPixels = maxWidth;
|
||||
}, (50)); |
||||
|
||||
if (this.taskNeedWaterParticle()) { |
||||
this.sprinklingWater(true); |
||||
} |
||||
else { |
||||
this.sprinklingWater(false); |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* 释放属性相关ui |
||||
*/ |
||||
disposeProperty() { |
||||
|
||||
if (this.uiNumber != null) { |
||||
this.uiNumber.dispose(); |
||||
this.uiNumber = null; |
||||
} |
||||
if (this.uiTask != null) { |
||||
this.uiTask.dispose(); |
||||
this.uiTask = null; |
||||
} |
||||
|
||||
if (this.uiFollowHead != null) { |
||||
this.uiFollowHead.dispose(); |
||||
this.uiFollowHead = null; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 克隆 |
||||
*/ |
||||
clone(markData?: MarkData, isNew: boolean = true): ModelInfo_mark { |
||||
|
||||
let l_markData: MarkData = null; |
||||
if (markData == null) { |
||||
l_markData = classToClass(this.modelData) as MarkData; |
||||
} |
||||
else { |
||||
l_markData = markData; |
||||
} |
||||
|
||||
let childMeshes = null; |
||||
let modelBox = null; |
||||
|
||||
|
||||
modelBox = BabylonTool.cloneMesh(this.modelBox as Mesh, null, (childMesh: AbstractMesh[]) => { |
||||
childMeshes = childMesh; |
||||
}); |
||||
modelBox.name = markData.key; |
||||
|
||||
let info = new ModelInfo_mark(l_markData, childMeshes, modelBox, null, isNew); |
||||
|
||||
this.cloneAnimTo(info); |
||||
|
||||
|
||||
|
||||
return info; |
||||
} |
||||
|
||||
/** |
||||
* 显隐跟随UI |
||||
* @param show
|
||||
*/ |
||||
showFollowUI(show: boolean) { |
||||
super.showFollowUI(show); |
||||
if (this.uiFollowHead != null) { |
||||
this.uiFollowHead.isVisible = show; |
||||
} |
||||
} |
||||
|
||||
dispose() { |
||||
SceneManager.Instance.removeFromHighLight(this.modelBox as Mesh); |
||||
this.disposeProperty(); |
||||
super.dispose(); |
||||
} |
||||
|
||||
//#region 喷水
|
||||
|
||||
|
||||
/** |
||||
* 播放喷水特效的任务,包含此特殊字则播放 |
||||
*/ |
||||
static readonly c_taskPenShui: string[] = ["喷水", "冷却", "灭火", "控火"]; |
||||
|
||||
|
||||
/** |
||||
* 喷水特效 |
||||
*/ |
||||
particle_water: ParticleSystem; |
||||
|
||||
/** |
||||
* 喷头(消防员喷水枪) |
||||
*/ |
||||
node_pt: Mesh; |
||||
/** |
||||
* 喷嘴,用于放特效的根节点 |
||||
*/ |
||||
node_pz: Mesh; |
||||
|
||||
/** |
||||
* 正在喷水 |
||||
*/ |
||||
isSprinkling: boolean; |
||||
|
||||
|
||||
/** |
||||
* 是否可以喷水 |
||||
*/ |
||||
canSprinkling() { |
||||
let result = false; |
||||
switch (this.markData.type) { |
||||
case MarkType.MHF: |
||||
case MarkType.JYF: |
||||
case MarkType.GRF: |
||||
case MarkType.FHF: |
||||
case MarkType.BHF: |
||||
result = true; |
||||
//五种消防员
|
||||
if (this.node_pt == null && this.models != null) { |
||||
this.node_pt = this.getChildrenByName("PT") as Mesh; |
||||
// for (let i = 0; i < this.models.length; i++) {
|
||||
// if (this.models[i].name == "PT") {
|
||||
// this.node_pt = this.models[i] as Mesh;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
} |
||||
break; |
||||
case MarkType.SGC: |
||||
case MarkType.PMC: |
||||
case MarkType.GPC: |
||||
case MarkType.GCGSC: |
||||
case MarkType.YTC: |
||||
//五种消防车
|
||||
result = true; |
||||
break; |
||||
case MarkType.SP: |
||||
result = true; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
|
||||
if (result == true && this.node_pz == null && this.models != null) { |
||||
this.node_pz = this.getChildrenByName("PZ") as Mesh; |
||||
// let transformNodes = this.modelBox.getChildTransformNodes();
|
||||
// for (let i = 0; i < transformNodes.length; i++) {
|
||||
// if (transformNodes[i].name == "PZ") {
|
||||
|
||||
// this.node_pz = new Mesh("PZ_1", undefined, transformNodes[i]);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
} |
||||
if (this.node_pz == null) { |
||||
result = false; |
||||
} |
||||
else { |
||||
this.node_pz.scaling = Vector3.One(); |
||||
this.node_pz.isVisible = false; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 当前任务是否需要喷水特效 |
||||
*/ |
||||
taskNeedWaterParticle() { |
||||
let result: boolean = false; |
||||
for (let i = 0; i < ModelInfo_mark.c_taskPenShui.length; i++) { |
||||
//包含某些特殊字
|
||||
if (TsTool.stringContain(this.markData.property.task, ModelInfo_mark.c_taskPenShui[i])) { |
||||
result = true; |
||||
break; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 喷水 |
||||
* @param show
|
||||
*/ |
||||
sprinklingWater(show: boolean) { |
||||
let canSprinkling = this.canSprinkling();//是否可以喷水
|
||||
let instance = this; |
||||
if (!canSprinkling) { |
||||
return; |
||||
} |
||||
switch (this.markData.type) { |
||||
case MarkType.MHF: |
||||
case MarkType.JYF: |
||||
case MarkType.GRF: |
||||
case MarkType.FHF: |
||||
case MarkType.BHF: |
||||
//消防员,显隐喷枪
|
||||
if (this.node_pt != null) { |
||||
this.node_pt.setEnabled(show); |
||||
} |
||||
break; |
||||
} |
||||
if (this.particle_water != null) { |
||||
this.playWater(show); |
||||
} |
||||
else { |
||||
//编写特效克隆方案
|
||||
//加载特效,然后播放
|
||||
ParticleSystemTool.instance.importParticle(this.markData.type + "_water", MarkWindow.c_water_particlePath, (ps) => { |
||||
instance.particle_water = ps; |
||||
instance.particle_water.emitter = instance.node_pz; |
||||
instance.playWater(show); |
||||
|
||||
}) |
||||
|
||||
} |
||||
|
||||
} |
||||
/** |
||||
* 播放喷水 |
||||
* @param show
|
||||
*/ |
||||
playWater(show: boolean) { |
||||
if (this.particle_water == null) { |
||||
return; |
||||
} |
||||
this.isSprinkling = show; |
||||
if (show) { |
||||
this.changeWaterPower(this.markData.waterPower); |
||||
this.particle_water.start(); |
||||
|
||||
} |
||||
else { |
||||
this.particle_water.stop(); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 改变喷水强度,返回改变后的 |
||||
* @param 最小值:c_waterPower_min |
||||
* @param 最大值:c_waterPower_max |
||||
* @param value
|
||||
*/ |
||||
changeWaterPower(value: number): number { |
||||
|
||||
if (!this.isSprinkling) //不在喷水
|
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
let power = Math.min(value, ModelInfo_mark.c_waterPower_max); |
||||
power = Math.max(power, ModelInfo_mark.c_waterPower_min); |
||||
|
||||
|
||||
if (this.particle_water != null) { |
||||
this.particle_water.minEmitPower = power * 0.3; |
||||
this.particle_water.maxEmitPower = power; |
||||
} |
||||
|
||||
this.markData.waterPower = power; |
||||
return power; |
||||
|
||||
} |
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
} |
@ -0,0 +1,271 @@
|
||||
import { AbstractMesh, Color3, Material, Mesh, MeshBuilder, PointerDragBehavior, PolygonMeshBuilder, Vector2, Vector3 } from "@babylonjs/core"; |
||||
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; |
||||
import { classToClass, plainToClass } from "class-transformer"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { BabylonTool } from "src/app/babylon/tool/babylon-tool"; |
||||
import { MarkWindow } from "src/app/babylon/view/mark-window/mark-window"; |
||||
|
||||
|
||||
import { MarkData, MarkType } from "../../../data/mark/mark-data"; |
||||
import { MarkData_Area } from "../../../data/mark/other/mark-data-area"; |
||||
import { ModelInfo_mark } from "../model-info-mark"; |
||||
|
||||
/** |
||||
* 区域类的标绘物 |
||||
*/ |
||||
export class ModelInfo_mark_area extends ModelInfo_mark { |
||||
|
||||
areaSize = 5;//区域尺寸
|
||||
|
||||
material: StandardMaterial;//mesh材质
|
||||
pointMat: StandardMaterial; //顶点材质
|
||||
|
||||
areaPoint: AreaPoint[]; |
||||
|
||||
areaMesh: Mesh; |
||||
|
||||
areaDragEvent: PointerDragBehavior;//区域mesh 拖拽行为
|
||||
|
||||
onCreate(isNew: boolean) { |
||||
super.onCreate(isNew); |
||||
|
||||
this.modelBox.position.y = this.modelBox.position.y + 1; |
||||
|
||||
let data = this.markData as MarkData_Area; |
||||
|
||||
this.pointMat = new StandardMaterial("mat_areaPoint", SceneManager.Instance.scene); |
||||
this.pointMat.emissiveColor = Color3.FromHexString("#A9FF00"); |
||||
this.pointMat.disableLighting = true; |
||||
this.pointMat.alpha = 0.87; |
||||
|
||||
|
||||
let instance = this; |
||||
this.areaDragEvent = new PointerDragBehavior({ dragPlaneNormal: Vector3.Up() }); //平面内移动
|
||||
this.areaDragEvent.moveAttached = false; |
||||
this.areaDragEvent.onDragStartObservable.add((eventData) => { |
||||
//instance.modelBox.translate(eventData.dragPlaneNormal, eventData.dragDistance);
|
||||
MarkWindow.instance.selectMarkDataFrom3d(instance, true); |
||||
}) |
||||
|
||||
this.initMeshPoint(isNew); |
||||
this.material = new StandardMaterial("mat_area", SceneManager.Instance.scene); |
||||
this.material.emissiveColor = Color3.FromHexString((this.markData as MarkData_Area).color); |
||||
this.material.disableLighting = true; |
||||
this.material.alpha = 0.87; |
||||
this.refreshMesh(); |
||||
} |
||||
|
||||
getVector2Point(): Vector2[] { |
||||
let data = this.markData as MarkData_Area; |
||||
let point: Vector2[] = []; |
||||
for (let i = 0; i < data.pointData.length; i++) { |
||||
let pos = new Vector2(data.pointData[i].x, data.pointData[i].z); |
||||
point.push(pos); |
||||
} |
||||
return point; |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* 更新mesh |
||||
*/ |
||||
refreshMesh() { |
||||
if (this.areaMesh != null) { |
||||
this.areaMesh.removeBehavior(this.areaDragEvent); |
||||
this.areaMesh.dispose(); |
||||
SceneManager.Instance.removeFromHighLight(this.areaMesh); |
||||
} |
||||
|
||||
let poly_tri = new PolygonMeshBuilder("polytri", this.getVector2Point(), SceneManager.Instance.scene); |
||||
this.areaMesh = poly_tri.build(true, 0); |
||||
this.areaMesh.setParent(this.modelBox); |
||||
this.areaMesh.position = new Vector3(0, 1, 0); |
||||
this.areaMesh.material = this.material; |
||||
this.areaMesh.addBehavior(this.areaDragEvent); |
||||
|
||||
if (this.isSelect) { |
||||
// console.log("选中状态下更新");
|
||||
SceneManager.Instance.addToHighLight(this.areaMesh, this.c_highLightColor); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 更新顶点 |
||||
* @param index
|
||||
*/ |
||||
initMeshPoint(isNew: boolean) { |
||||
let data = this.markData as MarkData_Area; |
||||
|
||||
if (isNew) { |
||||
switch (data.type) { |
||||
case MarkType.JJQ: data.pointData = this.getDefaultPoint_4(); |
||||
break; |
||||
case MarkType.QYSDA: data.pointData = this.getDefaultPoint_6(); |
||||
break; |
||||
case MarkType.QYSDB: data.pointData = this.getDefaultPoint_8(); |
||||
} |
||||
|
||||
} |
||||
else { |
||||
data.pointData = plainToClass(Vector3, data.pointData); |
||||
} |
||||
|
||||
this.areaPoint = []; |
||||
for (let i = 0; i < data.pointData.length; i++) { |
||||
let newPoint = new AreaPoint(data.pointData[i], this.pointMat, this); |
||||
this.areaPoint.push(newPoint); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 显示顶点 |
||||
* @param show
|
||||
*/ |
||||
showMeshPoint(show: boolean) { |
||||
|
||||
} |
||||
|
||||
//清空顶点
|
||||
clearMeshPoint() { |
||||
for (let i = 0; i < this.areaPoint.length; i++) { |
||||
this.areaPoint[i].dispose(); |
||||
} |
||||
this.areaPoint = []; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取默认位置,4点 |
||||
* @param center
|
||||
*/ |
||||
getDefaultPoint_4() { |
||||
let l_xy = this.areaSize; |
||||
let result = [new Vector3(l_xy, 0, l_xy), new Vector3(l_xy, 0, -l_xy), new Vector3(-l_xy, 0, -l_xy), new Vector3(-l_xy, 0, l_xy)]; |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 获取默认位置,6边型 |
||||
* @param center
|
||||
*/ |
||||
getDefaultPoint_6() { |
||||
let sin60 = Math.sin(Math.PI / 3) * this.areaSize; |
||||
let sin30 = 0.5 * this.areaSize; |
||||
let l_size = this.areaSize; |
||||
let result = [new Vector3(0, 0, l_size), new Vector3(sin60, 0, sin30), new Vector3(sin60, 0, -sin30), new Vector3(0, 0, -l_size), new Vector3(-sin60, 0, -sin30), new Vector3(-sin60, 0, sin30)]; |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 获取默认位置,8边形 |
||||
* @param center
|
||||
*/ |
||||
getDefaultPoint_8() { |
||||
let sin45 = Math.sin(Math.PI * 0.25) * this.areaSize; |
||||
let l_size = this.areaSize; |
||||
let result = [new Vector3(0, 0, l_size), new Vector3(sin45, 0, sin45), new Vector3(l_size, 0, 0), new Vector3(sin45, 0, -sin45), |
||||
new Vector3(0, 0, -l_size), new Vector3(-sin45, 0, -sin45), new Vector3(-l_size, 0, 0), new Vector3(-sin45, 0, sin45)]; |
||||
return result; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 克隆 |
||||
*/ |
||||
clone(markData?: MarkData, isNew: boolean = true): ModelInfo_mark_area { |
||||
|
||||
let l_markData: MarkData = null; |
||||
if (markData == null) { |
||||
l_markData = classToClass(this.modelData) as MarkData; |
||||
} |
||||
else { |
||||
l_markData = markData; |
||||
} |
||||
|
||||
let childMeshes = null; |
||||
let modelBox = null; |
||||
|
||||
|
||||
modelBox = BabylonTool.cloneMesh(this.modelBox as Mesh, null, (childMesh: AbstractMesh[]) => { |
||||
childMeshes = childMesh; |
||||
}); |
||||
|
||||
|
||||
|
||||
let info = new ModelInfo_mark_area(l_markData, childMeshes, modelBox, null, isNew); |
||||
|
||||
this.cloneAnimTo(info); |
||||
|
||||
|
||||
|
||||
return info; |
||||
} |
||||
|
||||
dispose() { |
||||
this.areaMesh.dispose(); |
||||
this.material.dispose(); |
||||
this.pointMat.dispose(); |
||||
this.clearMeshPoint(); |
||||
|
||||
super.dispose(); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 区域顶点 |
||||
*/ |
||||
export class AreaPoint { |
||||
|
||||
parent: ModelInfo_mark_area; |
||||
|
||||
mesh: Mesh; |
||||
|
||||
pos: Vector3; |
||||
|
||||
pointerDragBehavior: PointerDragBehavior;//拖拽事件
|
||||
|
||||
constructor(pos: Vector3, material: Material, parent: ModelInfo_mark_area) { |
||||
this.pos = pos; |
||||
this.parent = parent; |
||||
|
||||
this.mesh = MeshBuilder.CreateSphere("AreaPoint", { segments: 4, diameter: 3 }); |
||||
this.mesh.material = material; |
||||
this.mesh.setParent(parent.modelBox); |
||||
this.mesh.position = pos; |
||||
this.initDragEvent(); |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
initDragEvent() { |
||||
let instance = this; |
||||
this.pointerDragBehavior = new PointerDragBehavior({ dragPlaneNormal: Vector3.Up() }); //平面内移动
|
||||
this.mesh.addBehavior(this.pointerDragBehavior); |
||||
this.pointerDragBehavior.onDragStartObservable.add(() => { |
||||
instance.parent.setDragEventEnable(false); |
||||
}) |
||||
this.pointerDragBehavior.onDragObservable.add(() => { |
||||
instance.parent.refreshMesh(); |
||||
setTimeout(() => { |
||||
instance.parent.refreshMesh(); |
||||
}, 100); |
||||
}); |
||||
this.pointerDragBehavior.onDragEndObservable.add(() => { |
||||
instance.parent.setDragEventEnable(true); |
||||
instance.parent.refreshMesh(); |
||||
}) |
||||
} |
||||
|
||||
|
||||
dispose() { |
||||
this.mesh.removeBehavior(this.pointerDragBehavior); |
||||
this.pointerDragBehavior = null; |
||||
this.mesh.dispose(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,183 @@
|
||||
import { Color3, EventState, Mesh, MeshBuilder, Observer, PointerEventTypes, PointerInfo, Scene, StandardMaterial, Vector3 } from "@babylonjs/core"; |
||||
import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh"; |
||||
import { classToClass, plainToClass } from "class-transformer"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { BabylonTool } from "src/app/babylon/tool/babylon-tool"; |
||||
import { MarkWindow } from "src/app/babylon/view/mark-window/mark-window"; |
||||
|
||||
import { MarkData } from "../../../data/mark/mark-data"; |
||||
import { MarkData_Line } from "../../../data/mark/other/mark-data-line"; |
||||
|
||||
|
||||
import { ModelInfo_mark } from "../model-info-mark"; |
||||
|
||||
/** |
||||
* 单线条 |
||||
*/ |
||||
export class ModelInfo_mark_line extends ModelInfo_mark { |
||||
lineData: MarkData_Line; |
||||
|
||||
onPointObserver: Observer<PointerInfo>; |
||||
|
||||
lineMesh: Mesh; |
||||
|
||||
mat: StandardMaterial; |
||||
|
||||
|
||||
onCreate(isNew: boolean) { |
||||
let instance = this; |
||||
instance.lineData = this.markData as MarkData_Line; |
||||
|
||||
|
||||
this.mat = new StandardMaterial("mat_areaPoint", SceneManager.Instance.scene); |
||||
this.mat.emissiveColor = Color3.FromHexString(this.lineData.color); |
||||
this.mat.disableLighting = true; |
||||
|
||||
if (isNew) { |
||||
instance.lineData.pointData = []; |
||||
instance.lineData.pointData.push(Vector3.Zero()); |
||||
|
||||
setTimeout(() => { |
||||
instance.onPointObserver = SceneManager.Instance.scene.onPointerObservable.add((eventData: PointerInfo, eventState: EventState) => { |
||||
instance.onPointerObservable(eventData, eventState); |
||||
} |
||||
|
||||
); |
||||
}, 300); |
||||
} |
||||
else { |
||||
instance.lineData.pointData = plainToClass(Vector3, instance.lineData.pointData); |
||||
} |
||||
instance.updateRender(); |
||||
} |
||||
|
||||
/** |
||||
* 更新显示 |
||||
*/ |
||||
updateRender() { |
||||
if (this.lineData.pointData != null && this.lineData.pointData.length > 1) { |
||||
this.lineMesh = MeshBuilder.CreateTube("tube", { path: this.lineData.pointData, radius: 0.5, sideOrientation: Mesh.DOUBLESIDE, updatable: true }, SceneManager.Instance.scene); |
||||
this.lineMesh.setParent(this.modelBox); |
||||
this.lineMesh.position = Vector3.Zero(); |
||||
this.lineMesh.material = this.mat; |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 添加节点 |
||||
* @param point
|
||||
*/ |
||||
addPoint(point: Vector3) { |
||||
|
||||
this.lineData.pointData.push(point.subtract(this.modelBox.absolutePosition)); |
||||
|
||||
//更新表现
|
||||
|
||||
if (this.lineData.pointData.length == 2) { |
||||
this.removeEvent(); |
||||
this.updateRender(); |
||||
|
||||
MarkWindow.instance.selectMarkDataFrom3d(this, true); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 移除事件 |
||||
*/ |
||||
removeEvent() { |
||||
if (this.onPointObserver != null) { |
||||
SceneManager.Instance.scene.onPointerObservable.remove(this.onPointObserver); |
||||
this.onPointObserver = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 取消创建 |
||||
*/ |
||||
cancelCreate() { |
||||
if (this.lineData.pointData.length < 2) { |
||||
MarkWindow.instance.deleteMarkInfo(this); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
onPointerObservable(eventData: PointerInfo, eventState: EventState) { |
||||
let instance = this; |
||||
if (MarkWindow.instance.markLineIsBreak < 0) { |
||||
instance.cancelCreate(); |
||||
return; |
||||
} |
||||
|
||||
switch (eventData.type) { |
||||
case PointerEventTypes.POINTERUP: |
||||
if (eventData.event.button == 0) { //左键正常
|
||||
if (eventData.pickInfo.hit && !SceneManager.s_isPointerDrag) { |
||||
console.log("点击添加节点"); |
||||
instance.addPoint(eventData.pickInfo.pickedPoint); |
||||
} |
||||
} |
||||
else { //右键取消
|
||||
console.log("按键", eventData.event.button); |
||||
instance.cancelCreate(); |
||||
} |
||||
break; |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
onSelect(select: boolean) { |
||||
super.onSelect(select); |
||||
|
||||
if (select = false) { |
||||
this.cancelCreate(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 克隆 |
||||
*/ |
||||
clone(markData?: MarkData, isNew: boolean = true): ModelInfo_mark { |
||||
|
||||
let l_markData: MarkData = null; |
||||
if (markData == null) { |
||||
l_markData = classToClass(this.modelData) as MarkData; |
||||
} |
||||
else { |
||||
l_markData = markData; |
||||
} |
||||
|
||||
let childMeshes = null; |
||||
let modelBox = null; |
||||
|
||||
modelBox = BabylonTool.cloneMesh(this.modelBox as Mesh, null, (childMesh: AbstractMesh[]) => { |
||||
childMeshes = childMesh; |
||||
}); |
||||
|
||||
|
||||
let info = new ModelInfo_mark_line(l_markData, childMeshes, modelBox, null, isNew); |
||||
|
||||
this.cloneAnimTo(info); |
||||
|
||||
|
||||
|
||||
return info; |
||||
} |
||||
|
||||
|
||||
dispose() { |
||||
if (this.mat != null) { |
||||
this.mat.dispose(); |
||||
} |
||||
|
||||
this.removeEvent(); |
||||
super.dispose(); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,323 @@
|
||||
import { Color3, MeshBuilder, Quaternion, Space, Vector3 } from "@babylonjs/core"; |
||||
import { PointerEventTypes, PointerInfo } from "@babylonjs/core/Events/pointerEvents"; |
||||
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; |
||||
import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh"; |
||||
import { Mesh } from "@babylonjs/core/Meshes/mesh"; |
||||
import { EventState, Observer } from "@babylonjs/core/Misc/observable"; |
||||
import { classToClass, plainToClass } from "class-transformer"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { BabylonTool } from "src/app/babylon/tool/babylon-tool"; |
||||
import { MarkWindow } from "src/app/babylon/view/mark-window/mark-window"; |
||||
|
||||
|
||||
import { MarkData, MarkType } from "../../../data/mark/mark-data"; |
||||
import { MarkData_multiArrow } from "../../../data/mark/other/mark-data-multi-arrow"; |
||||
import { ModelInfo_mark } from "../model-info-mark"; |
||||
|
||||
/** |
||||
* 多点的箭头 |
||||
*/ |
||||
export class ModelInfo_mark_multiArrow extends ModelInfo_mark { |
||||
|
||||
|
||||
arrowData: MarkData_multiArrow; |
||||
|
||||
onPointObserver: Observer<PointerInfo>; |
||||
|
||||
arrowInfo: ArrowInfo[] = []; |
||||
|
||||
mat: StandardMaterial; |
||||
|
||||
|
||||
onCreate(isNew: boolean) { |
||||
let instance = this; |
||||
instance.arrowData = this.markData as MarkData_multiArrow; |
||||
|
||||
|
||||
this.mat = new StandardMaterial("mat_multiArrow", SceneManager.Instance.scene); |
||||
if (this.arrowData.color == null) { |
||||
this.mat.emissiveColor = Color3.Green(); |
||||
} |
||||
else { |
||||
this.mat.emissiveColor = Color3.FromHexString(this.arrowData.color); |
||||
} |
||||
|
||||
this.mat.disableLighting = true; |
||||
|
||||
if (isNew) { |
||||
instance.arrowData.pointData = []; |
||||
instance.addPoint(this.modelBox.absolutePosition.clone()); |
||||
|
||||
setTimeout(() => { |
||||
instance.onPointObserver = SceneManager.Instance.scene.onPointerObservable.add((eventData: PointerInfo, eventState: EventState) => { |
||||
instance.onPointerObservable(eventData, eventState); |
||||
} |
||||
|
||||
); |
||||
}, 300); |
||||
} |
||||
else { |
||||
instance.arrowData.pointData = plainToClass(Vector3, instance.arrowData.pointData); |
||||
instance.updateRender(); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 更新显示 |
||||
*/ |
||||
updateRender() { |
||||
if (this.arrowData.pointData != null && this.arrowData.pointData.length > 1) { |
||||
// this.lineMesh = MeshBuilder.CreateTube("tube", { path: this.lineData.pointData, radius: this.lineData.radius, sideOrientation: Mesh.DOUBLESIDE, updatable: true }, SceneManager.Instance.scene);
|
||||
// this.lineMesh.setParent(this.modelBox);
|
||||
// this.lineMesh.position = Vector3.Zero();
|
||||
// this.lineMesh.material = this.mat;
|
||||
for (let i = 1; i < this.arrowData.pointData.length; i++) { |
||||
// let newBox = MeshBuilder.CreateBox("box", { size: 1 });
|
||||
// newBox.setParent(this.modelBox);
|
||||
// newBox.position = this.arrowData.pointData[i];
|
||||
let lastPoint = this.arrowData.pointData[i - 1]; |
||||
let point = this.arrowData.pointData[i]; |
||||
let newArrow = new ArrowInfo(lastPoint, point, this.mat, this.modelBox as Mesh); |
||||
this.arrowInfo.push(newArrow); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 添加节点 |
||||
* @param point
|
||||
*/ |
||||
addPoint(point: Vector3) { |
||||
|
||||
let localPos = point.subtract(this.modelBox.absolutePosition); |
||||
|
||||
localPos.y = localPos.y / this.modelBox.scaling.y; |
||||
console.log(point, localPos, this.modelBox.absolutePosition); |
||||
|
||||
let startBox = MeshBuilder.CreateBox("start", { size: 1 }); |
||||
startBox.setParent(this.modelBox); |
||||
|
||||
startBox.position = localPos; |
||||
|
||||
|
||||
|
||||
this.arrowData.pointData.push(localPos); |
||||
|
||||
//更新表现
|
||||
|
||||
if (this.arrowData.pointData.length > 1) { |
||||
|
||||
// this.updateRender();
|
||||
let lastPoint = this.arrowData.pointData[this.arrowData.pointData.length - 2]; |
||||
let newArrow = new ArrowInfo(lastPoint, localPos, this.mat, this.modelBox as Mesh); |
||||
this.arrowInfo.push(newArrow); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 移除事件 |
||||
*/ |
||||
removeEvent() { |
||||
if (this.onPointObserver != null) { |
||||
SceneManager.Instance.scene.onPointerObservable.remove(this.onPointObserver); |
||||
this.onPointObserver = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 取消创建 |
||||
*/ |
||||
cancelCreate() { |
||||
if (this.arrowData.pointData.length < 2) { |
||||
MarkWindow.instance.deleteMarkInfo(this); |
||||
} |
||||
|
||||
if (this.arrowData.type == MarkType.JGLX) { |
||||
MarkWindow.instance.mulArrowIsBreak_JG = -1; |
||||
} |
||||
else if (this.arrowData.type == MarkType.CT) { |
||||
MarkWindow.instance.mulArrowIsBreak_CT = -1; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
onPointerObservable(eventData: PointerInfo, eventState: EventState) { |
||||
let instance = this; |
||||
if (this.arrowData.type == MarkType.JGLX && MarkWindow.instance.mulArrowIsBreak_JG < 0) { |
||||
instance.cancelCreate(); |
||||
instance.removeEvent(); |
||||
return; |
||||
} |
||||
else if (this.arrowData.type == MarkType.CT && MarkWindow.instance.mulArrowIsBreak_CT < 0) { |
||||
instance.cancelCreate(); |
||||
instance.removeEvent(); |
||||
return; |
||||
} |
||||
|
||||
switch (eventData.type) { |
||||
case PointerEventTypes.POINTERUP: |
||||
if (eventData.event.button == 0) { //左键正常
|
||||
if (eventData.pickInfo.hit && !SceneManager.s_isPointerDrag) { |
||||
instance.addPoint(eventData.pickInfo.pickedPoint); |
||||
} |
||||
} |
||||
else if (eventData.event.button == 2) { //右键取消
|
||||
instance.cancelCreate(); |
||||
instance.removeEvent(); |
||||
} |
||||
break; |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
onSelect(select: boolean) { |
||||
super.onSelect(select); |
||||
|
||||
if (select = false) { |
||||
this.cancelCreate(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 克隆 |
||||
*/ |
||||
clone(markData?: MarkData, isNew: boolean = true): ModelInfo_mark { |
||||
|
||||
let l_markData: MarkData = null; |
||||
if (markData == null) { |
||||
l_markData = classToClass(this.modelData) as MarkData; |
||||
} |
||||
else { |
||||
l_markData = markData; |
||||
} |
||||
|
||||
let childMeshes = null; |
||||
let modelBox = null; |
||||
|
||||
modelBox = BabylonTool.cloneMesh(this.modelBox as Mesh, null, (childMesh: AbstractMesh[]) => { |
||||
childMeshes = childMesh; |
||||
}); |
||||
|
||||
|
||||
let info = new ModelInfo_mark_multiArrow(l_markData, childMeshes, modelBox, null, isNew); |
||||
|
||||
this.cloneAnimTo(info); |
||||
|
||||
|
||||
|
||||
return info; |
||||
} |
||||
|
||||
|
||||
dispose() { |
||||
if (this.mat != null) { |
||||
this.mat.dispose(); |
||||
} |
||||
|
||||
this.removeEvent(); |
||||
super.dispose(); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 箭头信息 |
||||
* 仅用作创建mesh,所以没有释放(mesh会跟随父节点释放) |
||||
*/ |
||||
class ArrowInfo { |
||||
|
||||
static s_step = 3;//箭头间隔(从头到下一个的头)
|
||||
|
||||
lastArrowInfo: ArrowInfo;//上一个箭头
|
||||
parent: Mesh; |
||||
mesh: Mesh[] = []; |
||||
|
||||
point: Vector3[]; |
||||
|
||||
start: Vector3; |
||||
|
||||
end: Vector3; |
||||
forward: Vector3; |
||||
|
||||
endlocalY: number; //局部的Y做坐标,末尾
|
||||
mat: StandardMaterial; |
||||
|
||||
constructor(start: Vector3, end: Vector3, mat: StandardMaterial, parent: Mesh) { |
||||
this.start = start; |
||||
this.end = end; |
||||
this.forward = end.subtract(start).normalize(); |
||||
this.mat = mat; |
||||
this.parent = parent; |
||||
this.createMesh(); |
||||
} |
||||
|
||||
createMesh() { |
||||
//let distance = Vector3.Distance(this.start, this.end);
|
||||
//console.log(distance);
|
||||
|
||||
|
||||
let distance = Vector3.Distance(new Vector3(this.start.x, 0, this.start.z), new Vector3(this.end.x, 0, this.end.z)); |
||||
|
||||
let yStep = (this.start.y - this.end.y) / (distance / ArrowInfo.s_step); |
||||
|
||||
let index = 0; |
||||
|
||||
|
||||
while (distance > ArrowInfo.s_step) { |
||||
|
||||
let offset = index * ArrowInfo.s_step; |
||||
let forwardDistance = this.forward.multiplyByFloats(1, 0, 1).normalize().multiplyByFloats(offset, offset, offset); |
||||
let meshStart: Vector3 = this.start.add(forwardDistance); |
||||
|
||||
let posArray = []; |
||||
posArray.push(new Vector3(0, 0, 2)); |
||||
posArray.push(new Vector3(-1, 0, 1)); |
||||
posArray.push(new Vector3(-0.5, 0, 1)); |
||||
posArray.push(new Vector3(-0.5, 0, 0)); |
||||
posArray.push(new Vector3(0.5, 0, 0)); |
||||
posArray.push(new Vector3(0.5, 0, 1)); |
||||
posArray.push(new Vector3(1, 0, 1)); |
||||
|
||||
let l_mesh = MeshBuilder.ExtrudePolygon("arrow", { shape: posArray, depth: 1, updatable: false }, SceneManager.Instance.scene); |
||||
l_mesh.material = this.mat; |
||||
|
||||
|
||||
|
||||
l_mesh.setParent(this.parent); |
||||
this.endlocalY = (0.5) / this.parent.scaling.y - index * yStep;//0.5 - index * yStep
|
||||
//l_mesh.position = new Vector3(0, (0.5 - index * yStep) / this.parent.scaling.y, 0).add(meshStart);
|
||||
l_mesh.position = new Vector3(0, this.endlocalY, 0).add(meshStart); |
||||
// l_mesh.setParent(null)
|
||||
|
||||
// setTimeout(() => {
|
||||
l_mesh.lookAt(this.end.add(this.parent.absolutePosition), undefined, undefined, undefined, Space.WORLD); |
||||
l_mesh.rotation.x = 0; |
||||
l_mesh.rotation.z = 0; |
||||
|
||||
// }, (50));
|
||||
|
||||
// l_mesh.rotation.x = 0;
|
||||
// l_mesh.rotation.z = 0;
|
||||
// l_mesh.setParent(this.parent);
|
||||
|
||||
//l_mesh.rotationQuaternion = Quaternion.FromEulerVector(Vector3.Zero());
|
||||
|
||||
// let angle = Vector3.GetAngleBetweenVectors(l_mesh.forward, this.forward, Vector3.Up());
|
||||
// l_mesh.rotation.y = 180 / Math.PI * angle;
|
||||
|
||||
|
||||
this.mesh.push(l_mesh); |
||||
|
||||
distance -= ArrowInfo.s_step; |
||||
index++; |
||||
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,185 @@
|
||||
import { Color3, MeshBuilder, Vector3 } from "@babylonjs/core"; |
||||
import { PointerEventTypes, PointerInfo } from "@babylonjs/core/Events/pointerEvents"; |
||||
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; |
||||
import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh"; |
||||
import { Mesh } from "@babylonjs/core/Meshes/mesh"; |
||||
import { EventState, Observer } from "@babylonjs/core/Misc/observable"; |
||||
import { classToClass, plainToClass } from "class-transformer"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { BabylonTool } from "src/app/babylon/tool/babylon-tool"; |
||||
import { MarkWindow } from "src/app/babylon/view/mark-window/mark-window"; |
||||
|
||||
|
||||
import { MarkData } from "../../../data/mark/mark-data"; |
||||
import { MarkData_multiLine } from "../../../data/mark/other/mark-data-multi-line"; |
||||
import { ModelInfo_mark } from "../model-info-mark"; |
||||
|
||||
/** |
||||
* 多点的线段 |
||||
*/ |
||||
export class ModelInfo_mark_multiLine extends ModelInfo_mark { |
||||
|
||||
|
||||
lineData: MarkData_multiLine; |
||||
|
||||
onPointObserver: Observer<PointerInfo>; |
||||
|
||||
lineMesh: Mesh; |
||||
|
||||
mat: StandardMaterial; |
||||
|
||||
|
||||
onCreate(isNew: boolean) { |
||||
let instance = this; |
||||
instance.lineData = this.markData as MarkData_multiLine; |
||||
|
||||
|
||||
this.mat = new StandardMaterial("mat_multiLine", SceneManager.Instance.scene); |
||||
this.mat.emissiveColor = Color3.FromHexString(this.lineData.color); |
||||
this.mat.disableLighting = true; |
||||
|
||||
if (isNew) { |
||||
instance.lineData.pointData = []; |
||||
instance.addPoint(this.modelBox.absolutePosition.clone()); |
||||
|
||||
setTimeout(() => { |
||||
instance.onPointObserver = SceneManager.Instance.scene.onPointerObservable.add((eventData: PointerInfo, eventState: EventState) => { |
||||
instance.onPointerObservable(eventData, eventState); |
||||
} |
||||
|
||||
); |
||||
}, 300); |
||||
} |
||||
else { |
||||
instance.lineData.pointData = plainToClass(Vector3, instance.lineData.pointData); |
||||
} |
||||
instance.updateRender(); |
||||
} |
||||
|
||||
/** |
||||
* 更新显示 |
||||
*/ |
||||
updateRender() { |
||||
if (this.lineData.pointData != null && this.lineData.pointData.length > 1) { |
||||
this.lineMesh = MeshBuilder.CreateTube("tube", { path: this.lineData.pointData, radius: this.lineData.radius, sideOrientation: Mesh.DOUBLESIDE, updatable: true }, SceneManager.Instance.scene); |
||||
this.lineMesh.setParent(this.modelBox); |
||||
this.lineMesh.position = Vector3.Zero(); |
||||
this.lineMesh.material = this.mat; |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 添加节点 |
||||
* @param point
|
||||
*/ |
||||
addPoint(point: Vector3) { |
||||
point.y = point.y + this.lineData.yPos; |
||||
this.lineData.pointData.push(point.subtract(this.modelBox.absolutePosition)); |
||||
//更新表现
|
||||
|
||||
if (this.lineData.pointData.length > 1) { |
||||
|
||||
this.updateRender(); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 移除事件 |
||||
*/ |
||||
removeEvent() { |
||||
if (this.onPointObserver != null) { |
||||
SceneManager.Instance.scene.onPointerObservable.remove(this.onPointObserver); |
||||
this.onPointObserver = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 取消创建 |
||||
*/ |
||||
cancelCreate() { |
||||
if (this.lineData.pointData.length < 2) { |
||||
MarkWindow.instance.deleteMarkInfo(this); |
||||
} |
||||
MarkWindow.instance.mulLineIsBreak_SD = -1; |
||||
|
||||
} |
||||
|
||||
|
||||
onPointerObservable(eventData: PointerInfo, eventState: EventState) { |
||||
let instance = this; |
||||
if (MarkWindow.instance.mulLineIsBreak_SD < 0) { |
||||
instance.cancelCreate(); |
||||
instance.removeEvent(); |
||||
return; |
||||
} |
||||
|
||||
switch (eventData.type) { |
||||
case PointerEventTypes.POINTERUP: |
||||
if (eventData.event.button == 0) { //左键正常
|
||||
if (eventData.pickInfo.hit && !SceneManager.s_isPointerDrag) { |
||||
instance.addPoint(eventData.pickInfo.pickedPoint); |
||||
} |
||||
} |
||||
else if (eventData.event.button == 2) { //右键取消
|
||||
instance.cancelCreate(); |
||||
instance.removeEvent(); |
||||
} |
||||
break; |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
onSelect(select: boolean) { |
||||
super.onSelect(select); |
||||
|
||||
if (select = false) { |
||||
this.cancelCreate(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 克隆 |
||||
*/ |
||||
clone(markData?: MarkData, isNew: boolean = true): ModelInfo_mark { |
||||
|
||||
let l_markData: MarkData = null; |
||||
if (markData == null) { |
||||
l_markData = classToClass(this.modelData) as MarkData; |
||||
} |
||||
else { |
||||
l_markData = markData; |
||||
} |
||||
|
||||
let childMeshes = null; |
||||
let modelBox = null; |
||||
|
||||
modelBox = BabylonTool.cloneMesh(this.modelBox as Mesh, null, (childMesh: AbstractMesh[]) => { |
||||
childMeshes = childMesh; |
||||
}); |
||||
|
||||
|
||||
let info = new ModelInfo_mark_multiLine(l_markData, childMeshes, modelBox, null, isNew); |
||||
|
||||
this.cloneAnimTo(info); |
||||
|
||||
|
||||
|
||||
return info; |
||||
} |
||||
|
||||
|
||||
dispose() { |
||||
if (this.mat != null) { |
||||
this.mat.dispose(); |
||||
} |
||||
|
||||
this.removeEvent(); |
||||
super.dispose(); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,149 @@
|
||||
import { Mesh, ParticleSystem, ParticleSystemSet, Vector3 } from "@babylonjs/core"; |
||||
import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh"; |
||||
import { classToClass } from "class-transformer"; |
||||
import { BabylonTool } from "src/app/babylon/tool/babylon-tool"; |
||||
import { ParticleSystemTool } from "src/app/babylon/tool/particle-system-tool"; |
||||
|
||||
import { MarkType, MarkData } from "../../../data/mark/mark-data"; |
||||
|
||||
import { ModelInfo_mark } from "../model-info-mark"; |
||||
|
||||
export class ModelInfo_mark_particle extends ModelInfo_mark { |
||||
|
||||
/** |
||||
* 粒子特效集合 |
||||
*/ |
||||
particleSet: ParticleSystemSet; |
||||
|
||||
/** |
||||
* 是否播放 |
||||
*/ |
||||
isPlaying: boolean = true; |
||||
|
||||
|
||||
onCreate(isNew: boolean) { |
||||
super.onCreate(isNew); |
||||
let instance = this; |
||||
|
||||
this.particleSet = new ParticleSystemSet(); |
||||
|
||||
let particleJsonPath: string[] = []; |
||||
|
||||
let posOffset = Vector3.Zero(); |
||||
|
||||
switch (this.markData.type) { |
||||
case MarkType.H: |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_h_1.json"); |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_h_2.json"); |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_h_3.json"); |
||||
particleJsonPath.push("assets/particlesystem/smoke/smoke_a.json"); |
||||
instance.modelBox.scaling = new Vector3(300, 300, 300); |
||||
posOffset.y = 2.9 / instance.modelBox.scaling.y; |
||||
break; |
||||
case MarkType.TPH: |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_tph_1.json"); |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_tph_2.json"); |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_tph_3.json"); |
||||
particleJsonPath.push("assets/particlesystem/smoke/smoke_b.json"); |
||||
instance.modelBox.scaling = new Vector3(300, 300, 300); |
||||
posOffset.y = 2.9 / instance.modelBox.scaling.y; |
||||
break; |
||||
case MarkType.SNH: |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_snh_1.json"); |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_snh_2.json"); |
||||
particleJsonPath.push("assets/particlesystem/fire/fire_snh_3.json"); |
||||
particleJsonPath.push("assets/particlesystem/smoke/smoke_snh.json"); |
||||
instance.modelBox.scaling = new Vector3(300, 100, 300); |
||||
posOffset.y = 1 / instance.modelBox.scaling.y; |
||||
break; |
||||
case MarkType.YWA: |
||||
particleJsonPath.push("assets/particlesystem/smoke/smoke_a.json"); |
||||
instance.modelBox.scaling = new Vector3(500, 100, 500); |
||||
break; |
||||
case MarkType.YWB: |
||||
particleJsonPath.push("assets/particlesystem/smoke/smoke_b.json"); |
||||
instance.modelBox.scaling = new Vector3(300, 600, 300); |
||||
break; |
||||
case MarkType.YWC: |
||||
particleJsonPath.push("assets/particlesystem/smoke/smoke_c.json"); |
||||
instance.modelBox.scaling = new Vector3(100, 100, 100); |
||||
break; |
||||
} |
||||
|
||||
let root: AbstractMesh = new AbstractMesh("psRoot"); |
||||
root.setParent(instance.modelBox); |
||||
root.position = Vector3.Zero().add(posOffset); |
||||
root.rotationQuaternion = undefined; |
||||
root.rotation = Vector3.Zero(); |
||||
|
||||
|
||||
for (let i = 0; i < particleJsonPath.length; i++) { |
||||
ParticleSystemTool.instance.importParticle(instance.markData.type.toString(), particleJsonPath[i], (ps: ParticleSystem) => { |
||||
// instance.modelBox.scaling = new Vector3(100, 300, 100);
|
||||
ps.emitter = root; |
||||
instance.particleSet.systems.push(ps); |
||||
if (instance.isPlaying) { |
||||
instance.particleSet.start(); |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
|
||||
play() { |
||||
this.isPlaying = true; |
||||
if (this.particleSet == null) { |
||||
return; |
||||
} |
||||
this.particleSet.start(); |
||||
} |
||||
|
||||
stop() { |
||||
this.isPlaying = true; |
||||
if (this.particleSet == null) { |
||||
return; |
||||
} |
||||
for (let i = 0; i < this.particleSet.systems.length; i++) { |
||||
this.particleSet.systems[i].stop(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 克隆 |
||||
*/ |
||||
clone(markData?: MarkData, isNew: boolean = true): ModelInfo_mark { |
||||
|
||||
let l_markData: MarkData = null; |
||||
if (markData == null) { |
||||
l_markData = classToClass(this.modelData) as MarkData; |
||||
} |
||||
else { |
||||
l_markData = markData; |
||||
} |
||||
|
||||
let childMeshes = null; |
||||
let modelBox = null; |
||||
|
||||
modelBox = BabylonTool.cloneMesh(this.modelBox as Mesh, null, (childMesh: AbstractMesh[]) => { |
||||
childMeshes = childMesh; |
||||
}); |
||||
|
||||
|
||||
let info = new ModelInfo_mark_particle(l_markData, childMeshes, modelBox, null, isNew); |
||||
|
||||
this.cloneAnimTo(info); |
||||
|
||||
|
||||
|
||||
return info; |
||||
} |
||||
|
||||
|
||||
dispose() { |
||||
if (this.particleSet != null) { |
||||
this.particleSet.dispose(); |
||||
} |
||||
super.dispose(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,369 @@
|
||||
//#region 区域
|
||||
|
||||
import { AbstractMesh, Color3, Mesh, MeshBuilder, Observer, PolygonMeshBuilder, Quaternion, Scene, StandardMaterial, Vector2, Vector3 } from "@babylonjs/core"; |
||||
import { Button, Vector2WithInfo } from "@babylonjs/gui"; |
||||
|
||||
import { ModelInfo_facility } from "../model-info-facility"; |
||||
import * as earcut from "earcut"; |
||||
|
||||
import { FacilityType, ModelData_facility } from "../../../data/model-data/model-data-facility"; |
||||
import { ModeManager, ModeType } from "src/app/babylon/controller/mode-manager"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { UIManager } from "src/app/babylon/controller/ui-manager"; |
||||
import { BabylonUIStyleTool } from "src/app/babylon/tool/babylon-ui-style-tool"; |
||||
import { GizmoTool } from "src/app/babylon/tool/gizmo-tool"; |
||||
import { PosPointTool } from "src/app/babylon/tool/pos-point-tool"; |
||||
|
||||
(window as any).earcut = earcut; |
||||
|
||||
|
||||
// import {earcut} from "earcut";
|
||||
|
||||
/** |
||||
* 区域信息 |
||||
*/ |
||||
export class AreaInfo { |
||||
pointData: Vector3[];//点位
|
||||
mesh: Mesh; |
||||
material: StandardMaterial; |
||||
belongToFacility: ModelInfo_facility; |
||||
|
||||
pointMesh: PolygonMeshPoint[] = []; |
||||
root: Mesh; |
||||
isShow: boolean; |
||||
|
||||
onBeforeRenderObserver: Observer<Scene>; |
||||
onGizmoAimMeshObserver: Observer<AbstractMesh>; |
||||
|
||||
/** |
||||
* 根据类别分辨区域颜色 |
||||
* @param facilityType
|
||||
*/ |
||||
static getAreaColor(facilityType: FacilityType): Color3 { |
||||
let result = Color3.Red(); |
||||
switch (facilityType) { |
||||
case FacilityType.FHFQ: |
||||
result = Color3.Red(); |
||||
break; |
||||
case FacilityType.JTQ: |
||||
result = Color3.Yellow(); |
||||
break; |
||||
case FacilityType.JJQ: |
||||
result = Color3.Green(); |
||||
break; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
constructor(pointData: Vector3[], facilityInfo: ModelInfo_facility) { |
||||
this.belongToFacility = facilityInfo; |
||||
this.pointData = pointData; |
||||
|
||||
this.root = MeshBuilder.CreateBox("areaRoot_" + this.belongToFacility.key, { size: 1 }); |
||||
this.root.isVisible = false; |
||||
|
||||
this.root.setParent(this.belongToFacility.modelBox); |
||||
this.root.position = Vector3.Zero(); |
||||
this.root.rotationQuaternion = new Quaternion(); |
||||
|
||||
this.updateMeshPoint(); |
||||
|
||||
|
||||
let poly_tri = new PolygonMeshBuilder("polytri", this.getVector2Point(), SceneManager.Instance.scene); |
||||
this.mesh = poly_tri.build(true, 0); |
||||
this.mesh.setParent(this.root); |
||||
this.mesh.position = Vector3.Zero(); |
||||
this.mesh.isPickable = false; |
||||
|
||||
|
||||
this.material = new StandardMaterial("mat_area", SceneManager.Instance.scene); |
||||
this.material.emissiveColor = this.getAreaColor(); |
||||
this.material.disableLighting = true; |
||||
this.material.alpha = 0.5; |
||||
this.mesh.material = this.material; |
||||
|
||||
|
||||
let instance = this; |
||||
this.onBeforeRenderObserver = SceneManager.Instance.scene.onBeforeRenderObservable.add(() => { |
||||
instance.onUpdate(); |
||||
}); |
||||
|
||||
this.onGizmoAimMeshObserver = GizmoTool.onGizmoAimMeshObservable.add((mesh) => { |
||||
instance.onChangeGizmo(mesh); |
||||
}) |
||||
|
||||
|
||||
//延时更新一下
|
||||
setTimeout( |
||||
function () { |
||||
instance.refreshMesh(); |
||||
}, |
||||
100); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 获取颜色属性 |
||||
*/ |
||||
getAreaColor() { |
||||
let modelData = this.belongToFacility.modelData as ModelData_facility; |
||||
let propertyData = modelData.propertyData as any; |
||||
if (propertyData.color == undefined) { |
||||
propertyData.color = AreaInfo.getAreaColor(modelData.facilityType); |
||||
} |
||||
else if (!(propertyData.color instanceof Color3)) { |
||||
propertyData.color = new Color3(propertyData.color.r, propertyData.color.g, propertyData.color.b); |
||||
} |
||||
return propertyData.color as Color3; |
||||
} |
||||
|
||||
getVector2Point(): Vector2[] { |
||||
let point: Vector2[] = []; |
||||
for (let i = 0; i < this.pointData.length; i++) { |
||||
point.push(new Vector2(this.pointData[i].x, this.pointData[i].z)); |
||||
} |
||||
return point; |
||||
} |
||||
|
||||
setEnable(enable: boolean) { |
||||
if (this.root != null) { |
||||
this.root.setEnabled(enable); |
||||
} |
||||
} |
||||
|
||||
dispose() { |
||||
SceneManager.Instance.scene.onBeforeRenderObservable.remove(this.onBeforeRenderObserver); |
||||
this.onBeforeRenderObserver = null; |
||||
GizmoTool.onGizmoAimMeshObservable.remove(this.onGizmoAimMeshObserver); |
||||
this.onGizmoAimMeshObserver = null; |
||||
this.clearMeshPoint(); |
||||
this.material.dispose(); |
||||
this.mesh.dispose(); |
||||
} |
||||
|
||||
onChangeGizmo(mesh: AbstractMesh) { |
||||
if (mesh != null) { |
||||
this.isShow = mesh == this.belongToFacility.modelBox || this.isPosPointMesh(mesh); |
||||
this.isShow = this.isShow && ModeManager.currentMode == ModeType.Edit; |
||||
this.showPoint(this.isShow); |
||||
} |
||||
else { |
||||
this.showPoint(false); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//是否是位点mesh
|
||||
isPosPointMesh(mesh: AbstractMesh): boolean { |
||||
if (mesh == null) { |
||||
return false; |
||||
} |
||||
for (let i = 0; i < this.pointMesh.length; i++) { |
||||
if (mesh == this.pointMesh[i].mesh) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
showPoint(show: boolean) { |
||||
for (let i = 0; i < this.pointMesh.length; i++) { |
||||
this.pointMesh[i].showUI(show); |
||||
} |
||||
} |
||||
|
||||
onUpdate() { |
||||
|
||||
if (!this.isShow) { |
||||
return; |
||||
} |
||||
for (let i = 0; i < this.pointData.length; i++) { |
||||
this.pointData[i].y = 0; |
||||
} |
||||
this.refreshMesh(); |
||||
|
||||
|
||||
} |
||||
|
||||
refreshMesh() { |
||||
if (this.mesh != null) { |
||||
this.mesh.dispose(); |
||||
let poly_tri = new PolygonMeshBuilder("polytri", this.getVector2Point(), SceneManager.Instance.scene); |
||||
this.mesh = poly_tri.build(true, 0); |
||||
this.mesh.setParent(this.root); |
||||
this.mesh.position = Vector3.Zero(); |
||||
this.mesh.isPickable = false; |
||||
this.mesh.material = this.material; |
||||
} |
||||
} |
||||
|
||||
//更新顶点
|
||||
updateMeshPoint(index = -1) { |
||||
this.clearMeshPoint(); |
||||
let select = null; |
||||
for (let i = 0; i < this.pointData.length; i++) { |
||||
let l_meshPoint = new PolygonMeshPoint(PosPointTool.c_key + "_" + i, i, 0.2, this.root, this.pointData[i], this); |
||||
|
||||
this.pointMesh.push(l_meshPoint); |
||||
if (i == index) { |
||||
select = l_meshPoint; |
||||
|
||||
} |
||||
} |
||||
if (select != null) { |
||||
select.changeAim(); |
||||
} |
||||
} |
||||
|
||||
//清空顶点
|
||||
clearMeshPoint() { |
||||
for (let i = 0; i < this.pointMesh.length; i++) { |
||||
this.pointMesh[i].dispose(); |
||||
} |
||||
this.pointMesh = []; |
||||
} |
||||
|
||||
//加点
|
||||
addPoint(index: number) { |
||||
let newIndex = index; |
||||
|
||||
let pos = Vector3.Zero(); |
||||
let num = this.pointData.length; |
||||
if (newIndex < 1) { |
||||
pos = (this.pointData[0].add(this.pointData[num - 1])).multiplyByFloats(0.5, 0.5, 0.5); |
||||
this.pointData.push(pos); |
||||
this.updateMeshPoint(num); |
||||
} |
||||
else { |
||||
pos = (this.pointData[index].add(this.pointData[index - 1])).multiplyByFloats(0.5, 0.5, 0.5); |
||||
this.pointData.splice(index, 0, pos); |
||||
this.updateMeshPoint(index); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
//减点
|
||||
reducePoint(index: number) { |
||||
|
||||
let num = this.pointData.length; |
||||
if (num < 4) { |
||||
//ThreeDimensionalHomeComponent.instance.openSnackBar("不能少于3个顶点");
|
||||
// alert("不能少于3个顶点");
|
||||
return; |
||||
} |
||||
this.pointData.splice(index, 1); |
||||
let newSelectIndex = index; |
||||
if (newSelectIndex <= 0) { |
||||
newSelectIndex = 1; |
||||
} |
||||
this.updateMeshPoint(newSelectIndex); |
||||
} |
||||
|
||||
} |
||||
|
||||
//可编辑多边形的mesh
|
||||
export class PolygonMeshPoint { |
||||
|
||||
area: AreaInfo |
||||
mesh: Mesh; |
||||
pos: Vector3; |
||||
|
||||
index: number; |
||||
|
||||
uiRoot: Button; |
||||
|
||||
onGizmoAimMeshObservor: Observer<AbstractMesh>; |
||||
onPointerClickObservor: Observer<Vector2WithInfo>; |
||||
|
||||
constructor(name: string, index: number, size: number, parent: Mesh, pos: Vector3, area: AreaInfo) { |
||||
|
||||
|
||||
this.index = index; |
||||
this.area = area; |
||||
|
||||
this.initEditUI(name, size, parent, pos); |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
//初始化编辑UI
|
||||
initEditUI(name: string, size: number, parent: Mesh, pos: Vector3) { |
||||
if (ModeManager.currentMode == ModeType.Edit) { |
||||
this.mesh = MeshBuilder.CreateBox(name, { size: size }); |
||||
this.mesh.setParent(parent); |
||||
this.mesh.position = pos; |
||||
this.mesh.isVisible = false; |
||||
|
||||
let instance = this; |
||||
this.uiRoot = Button.CreateSimpleButton("ui_" + name, this.index.toString()); |
||||
UIManager.Instance.uiRoot.addControl(this.uiRoot); |
||||
this.uiRoot.linkWithMesh(this.mesh); |
||||
BabylonUIStyleTool.setStyle_size(this.uiRoot, "20px", "20px"); |
||||
this.uiRoot.background = BabylonUIStyleTool.c_color_blue; |
||||
this.uiRoot.color = BabylonUIStyleTool.c_color_white; |
||||
this.uiRoot.onPointerClickObservable.add(() => { |
||||
instance.changeAim(); |
||||
}); |
||||
|
||||
this.showUI(false); |
||||
} |
||||
|
||||
} |
||||
|
||||
//改变序号
|
||||
changeIndex(newIndex: number) { |
||||
this.index = newIndex; |
||||
} |
||||
|
||||
//改变选中的目标
|
||||
changeAim() { |
||||
let instance = this; |
||||
GizmoTool.changeGizmoAim(instance.mesh); |
||||
PosPointTool.attachMesh(instance.mesh as Mesh, instance.pos, |
||||
() => { |
||||
instance.addPoint(); |
||||
}, |
||||
() => { |
||||
instance.reducePoint(); |
||||
} |
||||
); |
||||
} |
||||
|
||||
dispose() { |
||||
|
||||
if (this.uiRoot != null) { |
||||
GizmoTool.onGizmoAimMeshObservable.remove(this.onGizmoAimMeshObservor); |
||||
this.uiRoot.onPointerClickObservable.clear(); |
||||
this.mesh.dispose(); |
||||
this.uiRoot.dispose(); |
||||
} |
||||
|
||||
} |
||||
|
||||
//显示或隐藏UI
|
||||
showUI(show: boolean) { |
||||
if (this.uiRoot != null) { |
||||
this.uiRoot.isVisible = show; |
||||
} |
||||
|
||||
} |
||||
|
||||
//加点
|
||||
addPoint() { |
||||
this.area.addPoint(this.index); |
||||
} |
||||
|
||||
//减点
|
||||
reducePoint() { |
||||
this.area.reducePoint(this.index); |
||||
|
||||
} |
||||
|
||||
} |
||||
//#endregion
|
@ -0,0 +1,267 @@
|
||||
//#region 高度
|
||||
|
||||
import { AbstractMesh, MeshBuilder, Color3, Vector3, Mesh, Observer, Scene, Vector2 } from "@babylonjs/core"; |
||||
import { Control, Button } from "@babylonjs/gui"; |
||||
import { GridMaterial } from "@babylonjs/materials"; |
||||
import { ModeManager, ModeType } from "src/app/babylon/controller/mode-manager"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { UIManager } from "src/app/babylon/controller/ui-manager"; |
||||
import { BabylonUIStyleTool, UI_LineInfo } from "src/app/babylon/tool/babylon-ui-style-tool"; |
||||
import { GizmoTool, TransformUIType } from "src/app/babylon/tool/gizmo-tool"; |
||||
|
||||
import { PropertyData_GD } from "../../../data/institution/facility/property-data/outdoor/property-data-gd"; |
||||
import { ModelData_facility } from "../../../data/model-data/model-data-facility"; |
||||
|
||||
import { ModelInfo_facility } from "../model-info-facility"; |
||||
|
||||
/** |
||||
* 高度信息 |
||||
*/ |
||||
export class GdInfo { |
||||
|
||||
pointData_start: Vector3;//起位
|
||||
pointData_end: Vector3;//终点
|
||||
|
||||
material: GridMaterial; |
||||
belongToFacility: ModelInfo_facility; |
||||
|
||||
myPath: Vector3[] = []; |
||||
myTube: Mesh; |
||||
gdMeshPoints: GdMeshPoint[] = []; |
||||
|
||||
isShow: boolean; |
||||
onGizmoAimMeshObserver: Observer<AbstractMesh>; |
||||
updateObserver: Observer<Scene>; |
||||
|
||||
constructor(startPoint: Vector3, endPoint: Vector3, belongToFacility: ModelInfo_facility) { |
||||
let instance = this; |
||||
this.belongToFacility = belongToFacility; |
||||
this.pointData_start = startPoint; |
||||
|
||||
let point_start = new GdMeshPoint(this, this.pointData_start, false); |
||||
this.gdMeshPoints.push(point_start); |
||||
|
||||
this.pointData_end = endPoint; |
||||
let point_end = new GdMeshPoint(this, this.pointData_end, true); |
||||
this.gdMeshPoints.push(point_end); |
||||
|
||||
this.myPath.push(point_start.pos); |
||||
this.myPath.push(point_end.pos); |
||||
this.updateObserver = SceneManager.Instance.scene.onBeforeRenderObservable.add(() => { |
||||
instance.update(); |
||||
}); |
||||
this.onGizmoAimMeshObserver = GizmoTool.onGizmoAimMeshObservable.add((mesh) => { |
||||
instance.onChangeGizmo(mesh); |
||||
}) |
||||
|
||||
this.createMesh(); |
||||
|
||||
|
||||
} |
||||
|
||||
createMesh() { |
||||
this.myTube = MeshBuilder.CreateTube("tube", { path: this.myPath, radius: 2, sideOrientation: Mesh.DOUBLESIDE, updatable: true }, SceneManager.Instance.scene); |
||||
this.myTube.parent = this.belongToFacility.modelBox; |
||||
this.myTube.position = Vector3.Zero(); |
||||
this.material = new GridMaterial("mat_myTube", SceneManager.Instance.scene); |
||||
this.material.mainColor = Color3.FromHexString(BabylonUIStyleTool.c_color_3d_blue); // new Color3(0, 0.5, 1)
|
||||
this.material.lineColor = new Color3(0, 0, 0); |
||||
this.myTube.material = this.material; |
||||
} |
||||
|
||||
update() { |
||||
this.gdMeshPoints[1].mesh.position.x = 0; |
||||
this.gdMeshPoints[1].mesh.position.z = 0; |
||||
this.myPath[1] = this.gdMeshPoints[1].mesh.position; |
||||
this.myTube = MeshBuilder.CreateTube("tube", { path: this.myPath, radius: 2, sideOrientation: Mesh.DOUBLESIDE, updatable: true, instance: this.myTube }, SceneManager.Instance.scene); |
||||
let facilityData = this.belongToFacility.modelData as ModelData_facility; |
||||
let property = facilityData.propertyData as PropertyData_GD; |
||||
this.gdMeshPoints[1].updateInfo(property.info); |
||||
} |
||||
|
||||
|
||||
|
||||
//释放
|
||||
dispose() { |
||||
SceneManager.Instance.scene.onBeforeRenderObservable.remove(this.updateObserver); |
||||
GizmoTool.onGizmoAimMeshObservable.remove(this.onGizmoAimMeshObserver); |
||||
this.updateObserver = null; |
||||
|
||||
for (let i = 0; i < this.gdMeshPoints.length; i++) { |
||||
this.gdMeshPoints[i].dispose(); |
||||
} |
||||
|
||||
this.material.dispose(); |
||||
this.myTube.dispose(); |
||||
} |
||||
|
||||
onChangeGizmo(mesh: AbstractMesh) { |
||||
// if (mesh != null) {
|
||||
// this.isShow = mesh == this.belongToFacility.modelBox || this.isPosPointMesh(mesh);
|
||||
// this.setEnable(this.isShow);
|
||||
// }
|
||||
// else {
|
||||
// this.setEnable(false);
|
||||
// }
|
||||
|
||||
} |
||||
|
||||
//是否是位点mesh
|
||||
isPosPointMesh(mesh: AbstractMesh): boolean { |
||||
|
||||
if (mesh == null) { |
||||
return false; |
||||
} |
||||
|
||||
for (let i = 0; i < this.gdMeshPoints.length; i++) { |
||||
if (mesh == this.gdMeshPoints[i].mesh) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
|
||||
setEnable(show: boolean) { |
||||
for (let i = 0; i < this.gdMeshPoints.length; i++) { |
||||
this.gdMeshPoints[i].setEnable(show); |
||||
} |
||||
} |
||||
|
||||
|
||||
setUIEnable(show: boolean) { |
||||
for (let i = 0; i < this.gdMeshPoints.length; i++) { |
||||
this.gdMeshPoints[i].showEditUI(show); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* 高度mesh |
||||
*/ |
||||
export class GdMeshPoint { |
||||
|
||||
pos: Vector3; |
||||
canSet: boolean; |
||||
gdInfo: GdInfo; |
||||
uiRoot: Button; |
||||
|
||||
lineInfo: UI_LineInfo; |
||||
|
||||
mesh: Mesh; |
||||
constructor(gdInfo: GdInfo, pos: Vector3, canSet: boolean) { |
||||
this.pos = pos; |
||||
this.canSet = canSet; |
||||
if (canSet) { |
||||
this.gdInfo = gdInfo; |
||||
this.mesh = MeshBuilder.CreateBox(gdInfo.belongToFacility.modelBox.name + "_point", { size: 1 }); |
||||
this.mesh.setParent(gdInfo.belongToFacility.modelBox); |
||||
this.mesh.position = pos; |
||||
this.mesh.isVisible = false; |
||||
|
||||
|
||||
this.initEditUI(); |
||||
|
||||
this.lineInfo = BabylonUIStyleTool.createLineInfo(gdInfo.belongToFacility.modelBox.name, this.mesh); |
||||
|
||||
this.showEditUI(false); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//初始化 编辑UI
|
||||
initEditUI() { |
||||
if (ModeManager.currentMode == ModeType.Edit) { |
||||
let instance = this; |
||||
this.uiRoot = Button.CreateImageButton("ui_editPoint_" + this.gdInfo.belongToFacility.modelBox.name, "", "assets/images/ui/edit.png"); |
||||
UIManager.Instance.uiRoot.addControl(this.uiRoot); |
||||
this.uiRoot.linkWithMesh(this.mesh); |
||||
this.uiRoot.linkOffsetYInPixels = 20; |
||||
this.uiRoot.linkOffsetXInPixels = -40; |
||||
BabylonUIStyleTool.setStyle_size(this.uiRoot, "20px", "20px"); |
||||
this.uiRoot.image.width = 0.8; |
||||
this.uiRoot.image.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER; |
||||
this.uiRoot.image.verticalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER; |
||||
// this.uiRoot.thickness = 0;
|
||||
this.uiRoot.background = BabylonUIStyleTool.c_color_3d_blueBg; |
||||
this.uiRoot.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
// this.uiRoot.alpha = 0.7;
|
||||
this.uiRoot.onPointerClickObservable.add(() => { |
||||
instance.changeAim(); |
||||
}); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//显示或隐藏 编辑UI
|
||||
showEditUI(show: boolean) { |
||||
if (this.uiRoot != null) { |
||||
this.uiRoot.isVisible = show && this.canSet; |
||||
} |
||||
|
||||
} |
||||
|
||||
//显示、隐藏标识UI
|
||||
setEnable(show: boolean) { |
||||
if (this.lineInfo != null) { |
||||
this.lineInfo.setEnable(show); |
||||
} |
||||
this.showEditUI(show && ModeManager.currentMode == ModeType.Edit); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
//改变选中的目标
|
||||
changeAim() { |
||||
let instance = this; |
||||
GizmoTool.onTransformUITypeChange(TransformUIType.Position);//强行变为position
|
||||
GizmoTool.changeGizmoAim(instance.mesh, false, true, false); |
||||
// PosPointTool.attachMesh(instance.mesh as Mesh, instance.pos,
|
||||
// () => {
|
||||
// instance.addPoint();
|
||||
// },
|
||||
// () => {
|
||||
// instance.reducePoint();
|
||||
// }
|
||||
// );
|
||||
//如果需要增加节点,在此拓展
|
||||
} |
||||
|
||||
dispose() { |
||||
|
||||
|
||||
if (this.canSet) { |
||||
if (this.uiRoot != null) { |
||||
this.uiRoot.dispose(); |
||||
} |
||||
|
||||
GizmoTool.leaveTheGizmoAimMesh(this.mesh); |
||||
this.mesh.dispose(); |
||||
this.lineInfo.dispose(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 更新显示内容 |
||||
* @param text
|
||||
*/ |
||||
updateInfo(text: string) { |
||||
if (this.lineInfo.info != null) { |
||||
this.lineInfo.info.text = "高度:" + text; |
||||
this.lineInfo.info.resizeToFit = true; |
||||
this.lineInfo.infoBg.height = (this.lineInfo.info.heightInPixels + 5) + "px"; |
||||
} |
||||
} |
||||
} |
||||
|
||||
//#endregion
|
@ -0,0 +1,232 @@
|
||||
import { Observer, Scene, TransformNode } from "@babylonjs/core"; |
||||
import { Button, Rectangle } from "@babylonjs/gui"; |
||||
import { ModelChangeType } from "src/app/babylon/controller/data-manager"; |
||||
import { Event_ModelInfoChange } from "src/app/babylon/controller/event-manager/events/event-modelinfo-change"; |
||||
import { InfoManager } from "src/app/babylon/controller/info-manager"; |
||||
import { ModeManager, ModeType } from "src/app/babylon/controller/mode-manager"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { BuildingStatus } from "src/app/babylon/controller/status/building-status"; |
||||
import { IndoorStatus } from "src/app/babylon/controller/status/indoor-status"; |
||||
import { StatusManager } from "src/app/babylon/controller/status/status-manager"; |
||||
import { BabylonUIStyleTool } from "src/app/babylon/tool/babylon-ui-style-tool"; |
||||
import { GizmoTool } from "src/app/babylon/tool/gizmo-tool"; |
||||
import { TsTool } from "src/app/babylon/tool/ts-tool"; |
||||
|
||||
|
||||
import { BuildingType } from "../../data/institution/building/building-data"; |
||||
import { ModelInfo_mark } from "../mark/model-info-mark"; |
||||
import { ModelInfo } from "./model-info"; |
||||
import { FacilityInfoByType, ModelInfo_facility } from "./model-info-facility"; |
||||
|
||||
//建筑类模型信息
|
||||
export class ModelInfo_building extends ModelInfo { |
||||
facilityRoot: TransformNode; |
||||
facilityInfos: FacilityInfoByType[] = []; |
||||
buildingType: BuildingType = BuildingType.Normal; |
||||
|
||||
neiRoot: TransformNode; //facilityRoot参照的节点
|
||||
updateObserver: Observer<Scene>; |
||||
|
||||
onSetModelBox() { |
||||
super.onSetModelBox(); |
||||
this.initFacilityRoot(); |
||||
} |
||||
|
||||
initFacilityRoot() { |
||||
|
||||
let allTransformNode = this.modelBox.getChildTransformNodes(); |
||||
this.neiRoot = null; |
||||
for (let i = 0; i < allTransformNode.length; i++) { |
||||
if (TsTool.stringContain(allTransformNode[i].name, "nei")) { |
||||
this.neiRoot = allTransformNode[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (this.neiRoot == null) { |
||||
this.neiRoot = this.modelBox; |
||||
|
||||
} |
||||
|
||||
if (this.facilityRoot != null) { |
||||
this.facilityRoot.dispose(); |
||||
} |
||||
|
||||
this.facilityRoot = new TransformNode(this.modelData.key + '_facilityRoot'); |
||||
|
||||
let instance = this; |
||||
if (this.updateObserver != null) { |
||||
SceneManager.Instance.scene.onAfterRenderObservable.remove(this.updateObserver); |
||||
} |
||||
this.updateObserver = SceneManager.Instance.scene.onAfterRenderObservable.add(function () { |
||||
instance.onBeforeRender(); |
||||
}); |
||||
} |
||||
|
||||
onClickMeshIconBtn() { |
||||
if (StatusManager.s_currentStatus instanceof BuildingStatus) { |
||||
StatusManager.s_currentStatus.buildingWindow.changeCurrentBuildingInfo(this); |
||||
} |
||||
else if (StatusManager.s_currentStatus instanceof IndoorStatus) { |
||||
GizmoTool.onPickMeshInfoObservable.notifyObservers(this); |
||||
// StatusManager.s_currentStatus.indoorWindow.lookAtCenter(this);
|
||||
} |
||||
} |
||||
|
||||
onCreateFollowUI() { |
||||
super.onCreateFollowUI(); |
||||
|
||||
this.uiFollowRoot.width = '104px'; |
||||
this.uiFollowRoot.height = '26px'; |
||||
this.uiFollowRoot.thickness = 0; |
||||
|
||||
|
||||
let border = new Rectangle("border"); |
||||
this.uiFollowRoot.addControl(border); |
||||
border.thickness = 0; |
||||
border.background = BabylonUIStyleTool.c_color_blue;//"#0CB7F7";
|
||||
border.alpha = 0.7; |
||||
|
||||
|
||||
this.uiIconBtn = Button.CreateSimpleButton( |
||||
'Btn_' + this.key, |
||||
"加载中..." |
||||
); |
||||
border.addControl(this.uiIconBtn); |
||||
this.uiIconBtn.width = '100px'; |
||||
this.uiIconBtn.height = '22px'; |
||||
this.uiIconBtn.background = "#415094"; |
||||
this.uiIconBtn.color = "white"; |
||||
this.uiIconBtn.thickness = 0; |
||||
this.uiIconBtn.textBlock.fontSize = 12; |
||||
this.uiIconBtn.shadowBlur = 1; |
||||
this.uiFollowRoot.zIndex = BabylonUIStyleTool.c_zIndex_buildingIcon; |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 显示此模型的跟随UI |
||||
* @param show
|
||||
*/ |
||||
showFollowUI(show: boolean) { |
||||
if (ModeManager.currentMode == ModeType.Look && this.buildingType == BuildingType.Environment) { |
||||
super.showFollowUI(false); |
||||
} |
||||
else { |
||||
super.showFollowUI(show); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 显示设备的跟随UI |
||||
* @param show
|
||||
*/ |
||||
showFacilityUI(show: boolean) { |
||||
|
||||
if (this.facilityInfos != null) { |
||||
for (let i = 0; i < this.facilityInfos.length; i++) { |
||||
let facilityByType = this.facilityInfos[i].facilityInfo; |
||||
if (facilityByType != null) { |
||||
for (let i = 0; i < facilityByType.length; i++) { |
||||
facilityByType[i].setIconEnable(show) |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//更新跟随UI的名称
|
||||
updateName(name: string) { |
||||
this.uiIconBtn.textBlock.text = name; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
dispose() { |
||||
this.disposeAllFacility(); |
||||
super.dispose(); |
||||
} |
||||
|
||||
//释放所有设备
|
||||
disposeAllFacility() { |
||||
ModeManager.log('释放室内设备' + this.facilityInfos.length); |
||||
for (let i = 0; i < this.facilityInfos.length; i++) { |
||||
|
||||
for (let j = 0; j < this.facilityInfos[i].facilityInfo.length; j++) { |
||||
this.removeFacilityInfo(this.facilityInfos[i].facilityInfo[j], false); |
||||
} |
||||
|
||||
} |
||||
this.facilityInfos = []; |
||||
this.facilityRoot.dispose(); |
||||
} |
||||
|
||||
onBeforeRender() { |
||||
// console.log(this.modelBox.absolutePosition);
|
||||
|
||||
this.facilityRoot.position = this.neiRoot.absolutePosition.clone(); |
||||
this.facilityRoot.rotation = this.neiRoot.rotation.clone(); |
||||
//if (this.modelBox.rotationQuaternion != null) {
|
||||
this.facilityRoot.rotationQuaternion = this.neiRoot.absoluteRotationQuaternion.clone(); |
||||
if (this.neiRoot.parent != null && (this.neiRoot.parent as TransformNode).scaling.y < 0) { |
||||
this.facilityRoot.scaling.y = -1; |
||||
} |
||||
|
||||
//}
|
||||
} |
||||
|
||||
//设置设备的父节点
|
||||
setFacilityParent(modelInfo_facility: ModelInfo_facility) { |
||||
modelInfo_facility.modelBox.setParent(this.facilityRoot); |
||||
} |
||||
|
||||
//设置标绘物的父节点
|
||||
steMarkParent(modelInfo_mark: ModelInfo_mark) { |
||||
modelInfo_mark.modelBox.setParent(this.facilityRoot); |
||||
} |
||||
|
||||
//移除设备记录
|
||||
removeFacilityInfo(modelInfo_facility: ModelInfo_facility, remove: boolean) { |
||||
if (remove) { |
||||
|
||||
InfoManager.removeFacilityInfoToTypeList(modelInfo_facility, this.facilityInfos); |
||||
} |
||||
Event_ModelInfoChange.dispatch(modelInfo_facility, ModelChangeType.Remove); |
||||
SceneManager.destroyModel(modelInfo_facility); |
||||
} |
||||
|
||||
/** |
||||
* 设置显示状态 |
||||
* @param enable true 为显示 |
||||
*/ |
||||
setEnable(enable: boolean) { |
||||
super.setEnable(enable); |
||||
this.setFacilityEnable(enable); |
||||
} |
||||
|
||||
/** |
||||
* 设置设备的显隐状态 |
||||
* @param enable
|
||||
*/ |
||||
setFacilityEnable(enable: boolean) { |
||||
if (this.facilityRoot != null) { |
||||
this.facilityRoot.setEnabled(enable); |
||||
} |
||||
|
||||
|
||||
if (this.facilityInfos != null) { |
||||
for (let j = 0; j < this.facilityInfos.length; j++) { |
||||
for (let k = 0; k < this.facilityInfos[j].facilityInfo.length; k++) { |
||||
this.facilityInfos[j].facilityInfo[k].setEnable(enable); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,196 @@
|
||||
import { AbstractMesh, EventState } from "@babylonjs/core"; |
||||
import { Button, Control, Ellipse, Rectangle, Vector2WithInfo } from "@babylonjs/gui"; |
||||
import { ConfigManager } from "src/app/babylon/controller/config-manager"; |
||||
import { SceneManager } from "src/app/babylon/controller/scene-manager"; |
||||
import { BabylonUIStyleTool } from "src/app/babylon/tool/babylon-ui-style-tool"; |
||||
import { FacilityWindow } from "src/app/babylon/view/facility-window/facility-window"; |
||||
import { FacilityInfoInSceneWindow } from "src/app/babylon/view/facilityinfoinscene-window/facilityinfoinscene-window"; |
||||
import { PropertyBaseWindow } from "src/app/babylon/view/property-window/property-base-window"; |
||||
import { ModelData } from "../../data/model-data/model-data"; |
||||
import { FacilityShowType, FacilityType, ModelData_facility } from "../../data/model-data/model-data-facility"; |
||||
import { BuildingInfo } from "../building/building-info"; |
||||
import { AreaInfo } from "./facilityinfo-tool/facility-area"; |
||||
import { GdInfo } from "./facilityinfo-tool/facility-gd"; |
||||
import { ModelInfo } from "./model-info"; |
||||
|
||||
//设施数据
|
||||
export class ModelInfo_facility extends ModelInfo { |
||||
belongToBuilding: BuildingInfo;//属于哪个建筑
|
||||
pickDown: boolean;//按下
|
||||
facilityShowType: FacilityShowType;//设备展示状态
|
||||
ui_select: Ellipse | Rectangle; |
||||
areaInfo: AreaInfo;//区域信息
|
||||
gdInfo: GdInfo;//高度信息
|
||||
isNew: boolean;//是否是新建
|
||||
|
||||
|
||||
constructor( |
||||
key: string, |
||||
modelData: ModelData, |
||||
models: AbstractMesh[], |
||||
modelBox: AbstractMesh, |
||||
belongToBuilding: BuildingInfo, |
||||
isNew: boolean |
||||
) { |
||||
super(key, modelData, models, modelBox); |
||||
this.facilityShowType = ModelData_facility.getShowType((modelData as ModelData_facility).facilityType); |
||||
this.belongToBuilding = belongToBuilding; |
||||
this.isNew = isNew; |
||||
} |
||||
|
||||
onCreateFollowUI() { |
||||
super.onCreateFollowUI(); |
||||
let instance = this; |
||||
let modelData = this.modelData as ModelData_facility; |
||||
let posType = ConfigManager.getPosType(modelData.facilityType); |
||||
let iconPath = ConfigManager.getFacilityIconUrl(modelData.facilityType, posType); |
||||
BabylonUIStyleTool.setStyle_size(this.uiFollowRoot, ConfigManager.c_size_facilityIconSize + "px", ConfigManager.c_size_facilityIconSize + "px"); |
||||
this.uiFollowRoot.thickness = 0; |
||||
|
||||
if (modelData.facilityType == FacilityType.AQCK) { |
||||
this.ui_select = new Rectangle("select"); |
||||
} |
||||
else { |
||||
this.ui_select = new Ellipse("select"); |
||||
} |
||||
|
||||
this.uiFollowRoot.addControl(this.ui_select); |
||||
this.ui_select.background = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.ui_select.thickness = 0; |
||||
this.ui_select.width = 0.95; |
||||
this.ui_select.height = 0.95; |
||||
this.ui_select.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.ui_select.shadowBlur = 3; |
||||
this.ui_select.isVisible = false; |
||||
|
||||
this.uiIconBtn = Button.CreateImageButton("iconPath", "", iconPath); |
||||
this.uiIconBtn.thickness = 0; |
||||
this.uiIconBtn.image.width = 0.9; |
||||
this.uiIconBtn.image.height = 0.9; |
||||
this.uiIconBtn.image.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER; |
||||
this.uiIconBtn.image.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER; |
||||
this.uiFollowRoot.addControl(this.uiIconBtn); |
||||
|
||||
//BabylonUIStyleTool.addLongPressButtonBehave(this.uiIconBtn, SceneManager.Instance.scene, () => {
|
||||
// instance.askDelete(instance);
|
||||
// }, () => {
|
||||
// // instance.onClickMeshIconBtn(null, null);
|
||||
// instance.onStopLongPress(null, null);
|
||||
// })
|
||||
|
||||
this.uiIconBtn.onPointerClickObservable.add(() => { |
||||
instance.onStopLongPress(null, null); |
||||
}); |
||||
|
||||
//双击,拉近镜头
|
||||
BabylonUIStyleTool.addDoubleClickButtonBehave(this.uiIconBtn, SceneManager.Instance.scene, () => { |
||||
let item = FacilityInfoInSceneWindow.instance.getFacilityItem(instance); |
||||
if (item != null) { |
||||
item.lookAt(); |
||||
} |
||||
|
||||
}); |
||||
|
||||
this.uiFollowRoot.zIndex = BabylonUIStyleTool.c_zIndex_facilityIcon; |
||||
} |
||||
|
||||
|
||||
//询问删除
|
||||
askDelete(modelInfo: ModelInfo_facility, ask = true) { |
||||
if (ask) { |
||||
// ThreeDimensionalHomeComponent.instance.deleteProperty(() => {
|
||||
// FacilityWindow.instance.disposeFacility(modelInfo);
|
||||
// }, modelInfo.key);
|
||||
} |
||||
else { //直接删除
|
||||
FacilityWindow.instance.disposeFacility(modelInfo); |
||||
} |
||||
|
||||
} |
||||
|
||||
//终止长按
|
||||
onStopLongPress(eventData: Vector2WithInfo, eventState: EventState) { |
||||
// this.onClickMeshIconBtn(eventData,eventState);
|
||||
FacilityInfoInSceneWindow.instance.selectFacilityInfo(this); |
||||
|
||||
} |
||||
|
||||
//展示属性
|
||||
showProperty() { |
||||
PropertyBaseWindow.ShowWindow(this); |
||||
} |
||||
|
||||
onSetModelBox() { |
||||
super.onSetModelBox(); |
||||
} |
||||
|
||||
|
||||
setEnable(enable: boolean) { |
||||
super.setEnable(enable); |
||||
if (this.areaInfo != null) { |
||||
this.areaInfo.setEnable(enable); |
||||
} |
||||
|
||||
if (this.gdInfo != null) { |
||||
this.gdInfo.setEnable(enable); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 设置选中圈的显示状态 |
||||
* @param enable
|
||||
*/ |
||||
setSelectEnable(enable: boolean) { |
||||
this.ui_select.isVisible = enable; |
||||
} |
||||
|
||||
/** |
||||
* 设置整个Icon的显示状态 |
||||
* @param enable
|
||||
*/ |
||||
setIconEnable(enable: boolean) { |
||||
this.showFollowUI(enable); |
||||
if (this.gdInfo != null) { |
||||
this.gdInfo.setUIEnable(enable); |
||||
} |
||||
|
||||
if (!enable)//还原选中状态
|
||||
{ |
||||
this.setSelectEnable(false); |
||||
} |
||||
} |
||||
|
||||
dispose() { |
||||
if (this.areaInfo != null) { |
||||
this.areaInfo.dispose(); |
||||
|
||||
} |
||||
if (this.gdInfo != null) { |
||||
this.gdInfo.dispose(); |
||||
} |
||||
super.dispose(); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//根据类型划分的设备信息
|
||||
export class FacilityInfoByType { |
||||
type: FacilityType; |
||||
facilityInfo: ModelInfo_facility[]; |
||||
|
||||
constructor(type: FacilityType) { |
||||
this.type = type; |
||||
this.facilityInfo = []; |
||||
|
||||
} |
||||
|
||||
dispose() { |
||||
for (let i = 0; i < this.facilityInfo.length; i++) { |
||||
this.facilityInfo[i].dispose(); |
||||
} |
||||
this.facilityInfo = []; |
||||
} |
||||
} |
@ -0,0 +1,265 @@
|
||||
import { |
||||
AbstractMesh, |
||||
AnimationGroup, |
||||
EventState, |
||||
GizmoManager, |
||||
Mesh, |
||||
PointerDragBehavior, |
||||
TransformNode, |
||||
Node, |
||||
Vector3, |
||||
} from '@babylonjs/core'; |
||||
import { Button, Rectangle, Vector2WithInfo } from '@babylonjs/gui'; |
||||
import { classToClass } from 'class-transformer'; |
||||
import { UIManager } from 'src/app/babylon/controller/ui-manager'; |
||||
import { BabylonTool } from 'src/app/babylon/tool/babylon-tool'; |
||||
import { GizmoTool } from 'src/app/babylon/tool/gizmo-tool'; |
||||
|
||||
|
||||
import { ModelData } from '../../data/model-data/model-data'; |
||||
|
||||
|
||||
//基础模型信息
|
||||
export class ModelInfo { |
||||
key: string; |
||||
/** |
||||
* 所有子节点 |
||||
*/ |
||||
models: AbstractMesh[]; |
||||
/** |
||||
* 包装盒、根节点 ,请使用modelBox 属性进行访问 |
||||
*/ |
||||
_modelBox: AbstractMesh; |
||||
/** |
||||
* 模型的动画 |
||||
*/ |
||||
animationGroups: AnimationGroup[]; |
||||
modelData: ModelData; |
||||
|
||||
uiFollowRoot: Rectangle; |
||||
uiIconBtn: Button; |
||||
uiDeleteBtn: Button; |
||||
|
||||
|
||||
|
||||
|
||||
modelEnableChangeObserver; //模型enable状态变化监听
|
||||
isDisposed: boolean = false;//已经被释放了
|
||||
isEnable: boolean = true;//显示状态
|
||||
|
||||
pointerDragBehavior: PointerDragBehavior;//mesh 拖拽行为
|
||||
|
||||
//请不要直接new ,而是使用 InfoManager.new
|
||||
constructor( |
||||
key: string, |
||||
modelData: ModelData, |
||||
models: AbstractMesh[], |
||||
modelBox: AbstractMesh, |
||||
isNew: boolean = true |
||||
) { |
||||
this.key = key; |
||||
this.models = models; |
||||
this.modelData = modelData; |
||||
this.modelBox = modelBox; |
||||
this.isDisposed = false; |
||||
|
||||
if (this.modelBox != null) { |
||||
this.modelBox.name = this.modelData.key; |
||||
} |
||||
} |
||||
|
||||
// 根据名字找到子对象
|
||||
public getChildrenByName(name: string): AbstractMesh { |
||||
const children = this.models.filter(item => item.name === name); |
||||
if (children.length > 0) { |
||||
return children[0] |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 模型根节点盒子 |
||||
*/ |
||||
get modelBox(): AbstractMesh { |
||||
return this._modelBox; |
||||
} |
||||
|
||||
/** |
||||
* 模型根节点盒子 |
||||
*/ |
||||
set modelBox(value: AbstractMesh) { |
||||
if (this._modelBox != value && this._modelBox != null) { |
||||
this._modelBox.dispose(); |
||||
} |
||||
|
||||
|
||||
if (this.isDisposed) { |
||||
this.dispose(); |
||||
return; |
||||
} |
||||
|
||||
|
||||
this._modelBox = value; |
||||
|
||||
if (value != null && this.uiFollowRoot == null) { |
||||
this.onCreateFollowUI(); |
||||
|
||||
let instance = this; |
||||
if (this.uiIconBtn != null) { |
||||
this.uiIconBtn.onPointerClickObservable.add(function (eventData, eventState) { |
||||
instance.onClickMeshIconBtn(eventData, eventState); |
||||
}); |
||||
} |
||||
|
||||
} |
||||
|
||||
this.onSetModelBox(); |
||||
|
||||
if (!this.isEnable) { |
||||
this.setEnable(this.isEnable); |
||||
} |
||||
} |
||||
|
||||
//创建跟随UI
|
||||
onCreateFollowUI() { |
||||
|
||||
this.uiFollowRoot = new Rectangle('follow_' + this.key); |
||||
UIManager.Instance.uiRoot.addControl(this.uiFollowRoot); |
||||
|
||||
} |
||||
|
||||
//展示或隐藏跟随UI
|
||||
showFollowUI(show: boolean) { |
||||
if (this.uiFollowRoot != null) { |
||||
this.uiFollowRoot.isVisible = show; |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 克隆 |
||||
*/ |
||||
clone(modelData?: ModelData, isNew: boolean = true): ModelInfo { |
||||
|
||||
let l_modelData; |
||||
if (modelData == null) { |
||||
l_modelData = classToClass(this.modelData); |
||||
} |
||||
else { |
||||
l_modelData = modelData; |
||||
} |
||||
|
||||
let childMeshes; |
||||
let modelBox = null; |
||||
|
||||
modelBox = BabylonTool.cloneMesh(this.modelBox as Mesh, null, (childMesh: AbstractMesh[]) => { |
||||
childMeshes = childMesh; |
||||
}); |
||||
|
||||
|
||||
|
||||
let info = new ModelInfo(this.key, l_modelData, childMeshes, modelBox, isNew); |
||||
return info; |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* 从本mesh上克隆动画给新模型 |
||||
* @param newInfo
|
||||
*/ |
||||
cloneAnimTo(newInfo: ModelInfo) { |
||||
if (this.animationGroups != null) { |
||||
|
||||
newInfo.animationGroups = []; |
||||
for (let i = 0; i < this.animationGroups.length; i++) { |
||||
let prfabAnim = this.animationGroups[i]; |
||||
let newAnimGroup = prfabAnim.clone(prfabAnim.name, (oldTarget) => { |
||||
let newTarget = null; |
||||
|
||||
let allChildren = newInfo.modelBox.getChildren((node) => { |
||||
if (oldTarget.name == node.name) { |
||||
newTarget = node; |
||||
// console.log("找到节点了", node);
|
||||
return false; |
||||
} |
||||
else { |
||||
return true; |
||||
} |
||||
}, false); |
||||
|
||||
// console.log("复制动画给新节点", newTarget);
|
||||
return newTarget; |
||||
}); |
||||
|
||||
newInfo.animationGroups.push(newAnimGroup); |
||||
// console.log("测试播放动画", newAnimGroup);
|
||||
// newAnimGroup.play();//完善正式逻辑时,注释掉此行
|
||||
} |
||||
} |
||||
} |
||||
|
||||
dispose() { |
||||
this.isDisposed = true; |
||||
this.uiFollowRoot.dispose(); |
||||
// console.log("释放model" + this.key);
|
||||
if (this.modelBox != null) { |
||||
this.modelBox.dispose(); |
||||
} else { |
||||
this.models[0].dispose(); |
||||
} |
||||
|
||||
} |
||||
|
||||
//设置模型盒子时
|
||||
onSetModelBox() { |
||||
|
||||
if ( |
||||
(this.modelData.transformData.scaling as Vector3).equals(Vector3.Zero()) |
||||
) { |
||||
this.modelData.transformData.originalScaling = this.modelBox.absoluteScaling.clone(); |
||||
this.modelData.transformData.scaling = this.modelData.transformData.originalScaling.clone(); |
||||
} |
||||
|
||||
|
||||
if (this.uiFollowRoot != null) { |
||||
this.uiFollowRoot.linkWithMesh(this.modelBox); |
||||
this.uiFollowRoot.linkOffsetY = '-50px'; |
||||
} |
||||
|
||||
} |
||||
|
||||
//改变显示状态
|
||||
setEnable(enable: boolean) { |
||||
this.isEnable = enable; |
||||
if (this.modelBox != null) { |
||||
this.modelBox.setEnabled(enable); |
||||
GizmoTool.leaveTheGizmoAim(this); |
||||
} |
||||
this.showFollowUI(enable); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 设置拖拽事件的激活状态 |
||||
* @param enable
|
||||
*/ |
||||
setDragEventEnable(enable: boolean) { |
||||
if (this.pointerDragBehavior != null) { |
||||
this.pointerDragBehavior.enabled = enable; |
||||
} |
||||
} |
||||
|
||||
|
||||
//点击到图标按钮
|
||||
onClickMeshIconBtn(eventData: Vector2WithInfo, eventState: EventState) { |
||||
|
||||
|
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,534 @@
|
||||
import { |
||||
AbstractMesh, |
||||
Animation, |
||||
AnimationGroup, |
||||
ArcRotateCamera, |
||||
Camera, |
||||
EasingFunction, |
||||
IParticleSystem, |
||||
ISceneLoaderPlugin, |
||||
ISceneLoaderPluginAsync, |
||||
ISceneLoaderProgressEvent, |
||||
Mesh, |
||||
MeshBuilder, |
||||
PBRMaterial, |
||||
QuadraticEase, |
||||
Quaternion, |
||||
Scene, |
||||
SceneLoader, |
||||
Skeleton, |
||||
Vector3, |
||||
} from '@babylonjs/core'; |
||||
|
||||
import { |
||||
AdvancedDynamicTexture, |
||||
Button, |
||||
Container, |
||||
Control, |
||||
InputText, |
||||
Rectangle, |
||||
ScrollViewer, |
||||
StackPanel, |
||||
TextBlock, |
||||
} from '@babylonjs/gui'; |
||||
import { ConfigManager } from '../controller/config-manager'; |
||||
import { ModeManager } from '../controller/mode-manager'; |
||||
import { UIManager } from '../controller/ui-manager'; |
||||
import { UIBase } from '../view/window-base/ui-base'; |
||||
import { BabylonUIStyleTool } from './babylon-ui-style-tool'; |
||||
import { LoadTool } from './load-tool'; |
||||
import { TsTool } from './ts-tool'; |
||||
|
||||
export class BabylonTool { |
||||
|
||||
|
||||
static readonly c_radian1 = 180 / Math.PI; //1弧度的度数
|
||||
static readonly c_cloneSuffix = '(Clone)'; //克隆物体的名称后缀
|
||||
|
||||
static readonly alpha_N = Math.PI * 0.5;//面朝北时的alpha值 右手坐标系是pi,左手是-pi
|
||||
|
||||
//获取世界坐标
|
||||
static getWorldPosition(mesh: AbstractMesh): Vector3 { |
||||
let result = mesh.position; |
||||
if (mesh.parent != null) { |
||||
result = mesh.absolutePosition; |
||||
} |
||||
return result.clone(); |
||||
} |
||||
|
||||
//载入模型
|
||||
static importMesh( |
||||
meshNames: any, |
||||
rootUrl: string, |
||||
sceneFilename?: string | File, |
||||
scene?: Scene, |
||||
onSuccess?: ( |
||||
meshes: AbstractMesh[], |
||||
particleSystems: IParticleSystem[], |
||||
skeletons: Skeleton[], |
||||
animationGroups: AnimationGroup[] |
||||
) => void, |
||||
onProgress?: (event: ISceneLoaderProgressEvent) => void, |
||||
onError?: (scene: Scene, message: string, exception?: any) => void, |
||||
pluginExtension?: string |
||||
): ISceneLoaderPlugin | ISceneLoaderPluginAsync { |
||||
|
||||
let path = rootUrl; //"institutions/institution001/building001/outdoor/";
|
||||
if (path == null) { |
||||
return null; |
||||
} |
||||
if (path.indexOf(ConfigManager.c_resPath_assetsRoot) == -1) { |
||||
path = ConfigManager.c_resPath_assetsRoot + rootUrl; |
||||
} |
||||
|
||||
ModeManager.log("加载模型" + path + sceneFilename); |
||||
return SceneLoader.ImportMesh( |
||||
meshNames, |
||||
path, |
||||
sceneFilename, |
||||
scene, |
||||
onSuccess, |
||||
onProgress, |
||||
onError, |
||||
pluginExtension |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* 异步加载模型 |
||||
* @param meshNames
|
||||
* @param rootUrl
|
||||
* @param sceneFilename
|
||||
* @param scene
|
||||
* @param tag 加载原因 |
||||
* @param onSuccess
|
||||
* @param onProgress
|
||||
* @param onError
|
||||
* @param pluginExtension
|
||||
*/ |
||||
static importMeshSync(meshNames: any, |
||||
rootUrl: string, |
||||
sceneFilename?: string | File, |
||||
scene?: Scene, |
||||
tag?: string, |
||||
onSuccess?: ( |
||||
meshes: AbstractMesh[], |
||||
particleSystems: IParticleSystem[], |
||||
skeletons: Skeleton[], |
||||
animationGroups: AnimationGroup[] |
||||
) => void, |
||||
onProgress?: (event: ISceneLoaderProgressEvent) => void, |
||||
onError?: (scene: Scene, message: string, exception?: any) => void, |
||||
pluginExtension?: string) { |
||||
let path = rootUrl; //"institutions/institution001/building001/outdoor/";
|
||||
if (path == null) { |
||||
return null; |
||||
} |
||||
if (path.indexOf(ConfigManager.c_resPath_assetsRoot) == -1) { |
||||
path = ConfigManager.c_resPath_assetsRoot + rootUrl; |
||||
} |
||||
|
||||
console.log("异步加载模型" + path + sceneFilename); |
||||
let modelPath = path + sceneFilename; |
||||
LoadTool.add(modelPath, tag); |
||||
SceneLoader.ImportMeshAsync( |
||||
meshNames, |
||||
path, |
||||
sceneFilename, |
||||
scene, |
||||
onProgress, |
||||
).then(function (result) { |
||||
LoadTool.remove(modelPath); |
||||
onSuccess(result.meshes, result.particleSystems, result.skeletons, result.animationGroups); |
||||
}).catch(function (result) { |
||||
onError(scene, "load error", result); |
||||
|
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 设置材质为无光材质 |
||||
*/ |
||||
static setMatToUnlit(meshes: AbstractMesh[], isUnlit: boolean, mask: string = null) { |
||||
if (meshes == null) { |
||||
return; |
||||
} |
||||
for (let i = 0; i < meshes.length; i++) { |
||||
if (meshes[i].material instanceof PBRMaterial) { |
||||
let mat_pbr = (meshes[i].material as PBRMaterial); |
||||
// mat_pbr.metallicF0Factor = 0;//关掉反光
|
||||
if (mask == null || !TsTool.stringContain(mat_pbr.name, mask)) { |
||||
mat_pbr.unlit = isUnlit; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 设置材质从菲涅尔反射(反光效果) |
||||
* @param meshes
|
||||
* @param enable //是否开启
|
||||
* @param linkToAlbedo //是否反射环境光颜色
|
||||
*/ |
||||
static setMatSheen(meshes: AbstractMesh[], enable: boolean, linkToAlbedo: boolean) { |
||||
for (let i = 0; i < meshes.length; i++) { |
||||
if (meshes[i].material instanceof PBRMaterial) { |
||||
let mat_pbr = (meshes[i].material as PBRMaterial); |
||||
if (TsTool.stringContain(mat_pbr.name, "Color")) { |
||||
mat_pbr.sheen.isEnabled = enable; |
||||
mat_pbr.sheen.linkSheenWithAlbedo = linkToAlbedo; |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
//改变摄像机观察目标
|
||||
static changeCameraTarget(camera: ArcRotateCamera, mesh: AbstractMesh, animMove: boolean = true, size = null) { |
||||
if (mesh == null) { |
||||
return; |
||||
} |
||||
|
||||
|
||||
|
||||
let maxScaleAxis = size; |
||||
if (size == null) { |
||||
maxScaleAxis = mesh.scaling.x; |
||||
} |
||||
|
||||
camera._scene.stopAnimation(camera); |
||||
|
||||
maxScaleAxis = Math.max(maxScaleAxis, mesh.scaling.y); |
||||
maxScaleAxis = Math.max(maxScaleAxis, mesh.scaling.z); |
||||
maxScaleAxis *= 1.5; |
||||
if (BabylonTool.cameraModeIs2D) { |
||||
camera.target = BabylonTool.getWorldPosition(mesh); |
||||
camera.radius = maxScaleAxis + 5; |
||||
camera.alpha = BabylonTool.alpha_N; |
||||
camera.beta = 0; |
||||
} |
||||
else { |
||||
if (animMove) { |
||||
BabylonTool.AnimMoveCameraTarget( |
||||
camera, |
||||
60, |
||||
BabylonTool.getWorldPosition(mesh), |
||||
maxScaleAxis + 5 |
||||
); |
||||
} |
||||
else { |
||||
let alpha = BabylonTool.alpha_N; |
||||
camera.target = BabylonTool.getWorldPosition(mesh).clone(); |
||||
camera.radius = maxScaleAxis + 50; |
||||
camera.alpha = alpha; |
||||
camera.beta = 1; |
||||
BabylonTool.AnimMoveCameraTarget( |
||||
camera, |
||||
60, |
||||
BabylonTool.getWorldPosition(mesh).clone(), |
||||
maxScaleAxis + 5 |
||||
); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* 停止动画 |
||||
* @param camera |
||||
*/ |
||||
static stopAnim(camera: ArcRotateCamera) { |
||||
camera._scene.stopAnimation(camera); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 摄像机状态- 是2d正交状态 |
||||
*/ |
||||
static cameraModeIs2D = false; |
||||
/** |
||||
* 改变摄像机模式 |
||||
* @param camera
|
||||
* @param is2D
|
||||
* @param mesh
|
||||
*/ |
||||
static changeCameraMode(camera: ArcRotateCamera, is2D: boolean) { |
||||
camera.mode = is2D ? Camera.ORTHOGRAPHIC_CAMERA : Camera.PERSPECTIVE_CAMERA; |
||||
BabylonTool.cameraModeIs2D = is2D; |
||||
// BabylonTool.AnimMoveCameraTarget(
|
||||
// camera,
|
||||
// 60,
|
||||
// camera.target,
|
||||
// camera.radius
|
||||
// );
|
||||
|
||||
|
||||
if (camera._scene.useRightHandedSystem) { |
||||
|
||||
} |
||||
camera.alpha = BabylonTool.alpha_N; |
||||
camera.beta = 0; |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
//动画移动摄像机target
|
||||
public static AnimMoveCameraTarget( |
||||
camera: ArcRotateCamera, |
||||
allFrame: number, |
||||
target: Vector3, |
||||
radius: number, |
||||
) { |
||||
//缓动动画
|
||||
let easingFunction = new QuadraticEase(); |
||||
easingFunction.setEasingMode(EasingFunction.EASINGMODE_EASEOUT); |
||||
|
||||
//target
|
||||
let anim_target = new Animation( |
||||
'CameraAnim_target', |
||||
'target', |
||||
60, |
||||
Animation.ANIMATIONTYPE_VECTOR3, |
||||
Animation.ANIMATIONLOOPMODE_CYCLE |
||||
); |
||||
let keys_target = [ |
||||
{ frame: 0, value: camera.target }, |
||||
{ frame: allFrame, value: target }, |
||||
]; |
||||
anim_target.setKeys(keys_target); |
||||
anim_target.setEasingFunction(easingFunction); |
||||
|
||||
//radius
|
||||
let anim_radius = new Animation( |
||||
'CameraAnim_radius', |
||||
'radius', |
||||
60, |
||||
Animation.ANIMATIONTYPE_FLOAT, |
||||
Animation.ANIMATIONLOOPMODE_CYCLE |
||||
); |
||||
let keys_radius = [ |
||||
{ frame: 0, value: camera.radius }, |
||||
{ frame: allFrame, value: radius }, |
||||
]; |
||||
anim_radius.setKeys(keys_radius); |
||||
anim_radius.setEasingFunction(easingFunction); |
||||
|
||||
camera.animations = []; |
||||
camera.animations.push(anim_target); |
||||
camera.animations.push(anim_radius); |
||||
|
||||
camera._scene.beginAnimation(camera, 0, allFrame, false); |
||||
// camera.target = target;
|
||||
// SceneManager.scene.beginAnimation(camera, 0, allFrame, false);
|
||||
|
||||
} |
||||
|
||||
//克隆mesh
|
||||
static cloneMesh(prefab: Mesh, name?: string, onSuccess?: (childMesh: AbstractMesh[], root: AbstractMesh) => void): Mesh { |
||||
if (name == null || name == undefined) { |
||||
name = prefab.name + BabylonTool.c_cloneSuffix; |
||||
} |
||||
|
||||
let prefabActive = prefab.isEnabled(false); |
||||
|
||||
if (prefabActive == false) { |
||||
prefab.setEnabled(true); |
||||
} |
||||
|
||||
let result = prefab.clone(name); |
||||
|
||||
let childMesh: AbstractMesh[] = []; |
||||
|
||||
//把名字中,因为复制而产生的无用前缀删掉
|
||||
let allChildren = result.getChildren((node) => { |
||||
let names = node.name.split('.'); |
||||
let newName = names[names.length - 1]; |
||||
node.name = newName; |
||||
if (node instanceof AbstractMesh) { |
||||
childMesh.push(node); |
||||
} |
||||
return true; |
||||
}, false); |
||||
|
||||
if (prefabActive == false) { |
||||
prefab.setEnabled(false); |
||||
} |
||||
|
||||
|
||||
if (onSuccess) { |
||||
onSuccess(childMesh, result); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//输入提示界面
|
||||
export class InputHintWindow extends UIBase { |
||||
|
||||
btn_hide: Button; //隐藏按钮
|
||||
isShow: boolean = true;//是否是显示状态
|
||||
txt_first: TextBlock;//第一行文字
|
||||
|
||||
onInit() { |
||||
super.onInit(); |
||||
|
||||
let window = this; |
||||
|
||||
let advancedTexture = UIManager.Instance.uiRoot; |
||||
let inputInfoBg = new Rectangle('InputHintWindow'); |
||||
inputInfoBg.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT; |
||||
inputInfoBg.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
advancedTexture.addControl(inputInfoBg); |
||||
this.root = inputInfoBg; |
||||
BabylonUIStyleTool.setDefaultStyle_windowRoot(this.root, false); |
||||
BabylonUIStyleTool.setStyle_size(this.root, "160px", "100px"); |
||||
this.root.alpha = 0.8; |
||||
|
||||
|
||||
|
||||
let inputInfoRoot = new StackPanel('inputInfoRoot'); |
||||
inputInfoRoot.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT; |
||||
inputInfoRoot.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
inputInfoRoot.width = '150px'; |
||||
inputInfoRoot.height = '100px'; |
||||
inputInfoRoot.isVertical = true; |
||||
inputInfoBg.addControl(inputInfoRoot); |
||||
|
||||
let infoStyle = advancedTexture.createStyle(); |
||||
infoStyle.fontSize = 15; |
||||
|
||||
let mouseLeft = new TextBlock('mouseLeft', '左键拖动 => 旋转镜头'); |
||||
mouseLeft.color = 'white'; |
||||
mouseLeft.height = '30px'; |
||||
mouseLeft.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
mouseLeft.style = infoStyle; |
||||
inputInfoRoot.addControl(mouseLeft); |
||||
this.txt_first = mouseLeft; |
||||
|
||||
let mouseRight = new TextBlock('mouseRight', '右键拖动 => 平移镜头'); |
||||
mouseRight.color = 'white'; |
||||
mouseRight.height = '30px'; |
||||
mouseRight.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
mouseRight.style = infoStyle; |
||||
inputInfoRoot.addControl(mouseRight); |
||||
|
||||
let mouseCenter = new TextBlock('mouseCenter', '前滑滚轮 => 拉近镜头'); |
||||
mouseCenter.color = 'white'; |
||||
mouseCenter.height = '30px'; |
||||
mouseCenter.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
mouseCenter.style = infoStyle; |
||||
inputInfoRoot.addControl(mouseCenter); |
||||
|
||||
this.btn_hide = Button.CreateSimpleButton("btn_hide", "..."); |
||||
this.root.addControl(this.btn_hide); |
||||
this.btn_hide.textBlock.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT; |
||||
this.btn_hide.textBlock.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
this.btn_hide.textBlock.color = "white"; |
||||
this.btn_hide.thickness = 0; |
||||
this.btn_hide.onPointerClickObservable.add(() => { |
||||
console.log("隐藏"); |
||||
window.setShowStatus(!window.isShow); |
||||
}); |
||||
|
||||
this.setShowStatus(true); |
||||
|
||||
// setTimeout(() => {
|
||||
// if (window.isShow) {
|
||||
// window.setShowStatus(false);
|
||||
// }
|
||||
// }, 4000);
|
||||
|
||||
} |
||||
|
||||
//设置显示状态
|
||||
setShowStatus(newStatus: boolean) { |
||||
this.isShow = newStatus; |
||||
if (newStatus) { |
||||
this.root.width = "160px"; |
||||
this.root.height = "100px"; |
||||
this.root.alpha = 0.8; |
||||
this.txt_first.alpha = 1; |
||||
this.btn_hide.textBlock.isVisible = false; |
||||
} |
||||
else { |
||||
this.root.width = "20px"; |
||||
this.root.height = "20px"; |
||||
this.root.alpha = 0.5; |
||||
this.txt_first.alpha = 0; |
||||
this.btn_hide.textBlock.isVisible = true; |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
//封装的滚动条组件
|
||||
export class MyScrollView { |
||||
name: string; |
||||
scrollView: ScrollViewer; |
||||
container: StackPanel; |
||||
|
||||
constructor(name: string, parent: Rectangle, isVertical: boolean = true) { |
||||
|
||||
this.name = name; |
||||
this.scrollView = new ScrollViewer(name); |
||||
parent.addControl(this.scrollView); |
||||
this.scrollView.paddingTop = "0px"; |
||||
this.scrollView.paddingRight = "0px"; |
||||
this.scrollView.paddingBottom = "0px"; |
||||
this.scrollView.paddingLeft = "0px"; |
||||
|
||||
|
||||
|
||||
this.container = new StackPanel("Container"); |
||||
this.scrollView.addControl(this.container); |
||||
this.container.isVertical = isVertical; |
||||
this.container.paddingTop = "0px"; |
||||
this.container.paddingBottom = "0px"; |
||||
this.container.paddingLeft = "0px"; |
||||
this.container.paddingRight = "0px"; |
||||
|
||||
} |
||||
} |
||||
|
||||
//带背景的输入框
|
||||
export class MyInputText { |
||||
name: string; |
||||
bg: Rectangle; |
||||
inputText: InputText; |
||||
|
||||
constructor(name: string, parent: Container, width: string, height: string) { |
||||
this.name = name; |
||||
this.bg = new Rectangle(name); |
||||
parent.addControl(this.bg); |
||||
this.bg.width = width; |
||||
this.bg.height = height; |
||||
this.inputText = new InputText(name + "_txt"); |
||||
this.bg.addControl(this.inputText); |
||||
this.inputText.width = width; |
||||
this.inputText.height = height; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
@ -0,0 +1,522 @@
|
||||
|
||||
import { AbstractMesh, EventState, Scene, setAndStartTimer, Vector2 } from "@babylonjs/core"; |
||||
import { Button, Container, Control, Ellipse, MultiLine, RadioButton, Rectangle, StackPanel, TextBlock, Vector2WithInfo } from "@babylonjs/gui"; |
||||
import { ConfigManager } from "../controller/config-manager"; |
||||
import { SceneManager } from "../controller/scene-manager"; |
||||
import { UIManager } from "../controller/ui-manager"; |
||||
import { UIBase } from "../view/window-base/ui-base"; |
||||
import { MyInputText } from "./babylon-tool"; |
||||
|
||||
//babylon UI 风格 工具
|
||||
export class BabylonUIStyleTool { |
||||
|
||||
static c_color_blue: string = "#0080FF";//普通蓝色,用于选中、确定等正面风格
|
||||
static c_color_gray: string = "#E8ECF1";//普通灰色,用于取消、后退、输入背景等
|
||||
static c_color_black: string = "black";//黑色
|
||||
static c_color_blueBg: string = "#001121";//深蓝,用于长存界面的背景
|
||||
static c_color_white: string = "white"; |
||||
static c_color_green = "#439C08";//绿色按钮
|
||||
static c_color_greenLight = '#00F424';//亮绿色
|
||||
static c_color_red = "#C14242";//红色按钮,用于删除等危险操作
|
||||
|
||||
static c_color_3d_blueLight: string = "#99ECFC";//亮蓝,字
|
||||
static c_color_3d_blue: string = "#47E0FF";//蓝, 框体
|
||||
static c_color_3d_blueBg: string = "#122F49";//蓝黑,背景
|
||||
|
||||
static c_shadow_blur_button = 2;//按钮的阴影模糊
|
||||
static c_shadow_blur_window = 20; //界面的阴影模糊
|
||||
|
||||
static readonly cornerRadius_window1 = 10;//界面圆角
|
||||
static readonly cornerRadius_button = 6;//按钮圆角
|
||||
|
||||
static c_zIndex_gizmo = 200;//gizmo界面的z
|
||||
static c_zIndex_topBar = 100;//topbar界面的z
|
||||
|
||||
static c_zIndex_buildingIcon = 50;//建筑标志的z
|
||||
static c_zIndex_facilityIcon = 40;//设备标志的z
|
||||
|
||||
|
||||
//#region 组件
|
||||
//创建窗口根节点
|
||||
static createWindoRoot(window: UIBase, name: string, width: string, height: string, isDialog: boolean) { |
||||
|
||||
window.root = new Rectangle(name); |
||||
UIManager.Instance.uiRoot.addControl(window.root); |
||||
window.root.width = width; |
||||
window.root.height = height; |
||||
|
||||
BabylonUIStyleTool.setDefaultStyle_windowRoot(window.root, isDialog); |
||||
|
||||
} |
||||
|
||||
//创建文本输入组件
|
||||
static createInputText(name: string, parent: Container, width: string, height: string, textColor: string = "black", thickness: number = 0, cornerRadius: number = 6, backgroundColor: string = "#EEF1F5", focuseColor: string = "black", focuseBgColor: string = "#EEF1F5"): MyInputText { |
||||
let result = new MyInputText(name, parent, width, height); |
||||
|
||||
result.inputText.color = textColor; |
||||
|
||||
result.inputText.background = backgroundColor; |
||||
result.inputText.thickness = thickness; |
||||
|
||||
result.inputText.focusedColor = focuseColor; |
||||
result.inputText.focusedBackground = focuseBgColor; |
||||
|
||||
result.bg.cornerRadius = cornerRadius; |
||||
result.bg.color = backgroundColor; |
||||
result.bg.thickness = thickness; |
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
//创建文本
|
||||
static createTextBlock(name: string, text: string, width: string, height: string, fontSize: string): TextBlock { |
||||
let textBlock = new TextBlock(name, text); |
||||
BabylonUIStyleTool.setStyle_size(textBlock, width, height); |
||||
textBlock.fontSize = fontSize; |
||||
textBlock.color = "black"; |
||||
return textBlock; |
||||
|
||||
} |
||||
|
||||
//创建统一风格的确定按钮
|
||||
static createBtn_OK(name: string, text: string, width: string, height: string, fontSize: string): Button { |
||||
let result = BabylonUIStyleTool.createBtn(name, text, width, height, fontSize, "white", BabylonUIStyleTool.c_color_blue); |
||||
BabylonUIStyleTool.setStyle_Shadow(result, undefined, 1.5); |
||||
return result; |
||||
} |
||||
|
||||
//创建统一风格的取消按钮
|
||||
static createBtn_Cancel(name: string, text: string, width: string, height: string, fontSize: string): Button { |
||||
let result = BabylonUIStyleTool.createBtn(name, text, width, height, fontSize, "black", BabylonUIStyleTool.c_color_gray); |
||||
return result |
||||
} |
||||
|
||||
//创建统一风格的删除按钮
|
||||
static createBtn_Delete(name: string, text: string, width: string, height: string, fontSize: string,): Button { |
||||
let result = BabylonUIStyleTool.createBtn(name, text, width, height, fontSize, "white", BabylonUIStyleTool.c_color_red); |
||||
return result; |
||||
} |
||||
|
||||
//创建按钮
|
||||
static createBtn(name: string, text: string, width: string, height: string, fontSize: string, textColor: string = "black", bgColor: string = "white", thickness: number = 0, cornerRadius: number = 6): Button { |
||||
let result = Button.CreateSimpleButton(name, text); |
||||
result.background = bgColor; |
||||
result.color = textColor; |
||||
result.width = width; |
||||
result.height = height; |
||||
result.thickness = thickness; |
||||
result.cornerRadius = cornerRadius; |
||||
|
||||
result.textBlock.color = textColor; |
||||
result.fontSize = fontSize; |
||||
return result; |
||||
} |
||||
|
||||
|
||||
//创建选择框
|
||||
static createRadioButton(name: string, parent: Container, group: string, width: string, height: string, color: string, background: string, info?: string, infoWidth?: string, isChecked = false, callback?: (eventData: boolean, eventState: EventState) => void) { |
||||
let root = new StackPanel(name + "Root"); |
||||
root.isVertical = false |
||||
root.width = width; |
||||
root.height = height; |
||||
parent.addControl(root); |
||||
|
||||
|
||||
|
||||
let radioButton = new RadioButton(name); |
||||
root.addControl(radioButton); |
||||
radioButton.group = group; |
||||
BabylonUIStyleTool.setStyle_size(radioButton, height, height); |
||||
radioButton.background = background; |
||||
radioButton.color = color; |
||||
if (callback) { |
||||
radioButton.onIsCheckedChangedObservable.add(callback); |
||||
} |
||||
radioButton.isChecked = isChecked; |
||||
|
||||
|
||||
let header = new TextBlock(name + "_info", info); |
||||
root.addControl(header); |
||||
header.height = height; |
||||
header.width = width; |
||||
header.color = "black"; |
||||
header.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
|
||||
return radioButton; |
||||
} |
||||
|
||||
/** |
||||
* 创建线性指示UI |
||||
* @param key
|
||||
* @param mesh 跟随在此mesh 右侧 |
||||
* @param size 外框的大小, 外框的左侧中点为线段起点 |
||||
* @param infoSize 信息框的大小, 对齐于外框的右上角 |
||||
*/ |
||||
static createLineInfo(key: string, mesh: AbstractMesh, size: Vector2 = new Vector2(160, 60), infoSize: Vector2 = new Vector2(120, 20)): UI_LineInfo { |
||||
|
||||
|
||||
if (size.x < infoSize.x) { |
||||
size.x = infoSize.x; |
||||
} |
||||
if (size.y < infoSize.y) { |
||||
size.y = infoSize.y; |
||||
} |
||||
|
||||
let lineInfo = new UI_LineInfo(key, mesh, size, infoSize); |
||||
|
||||
return lineInfo; |
||||
} |
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 风格样式
|
||||
//统一设置窗口根节点风格
|
||||
static setDefaultStyle_windowRoot(container: Rectangle, isDialog = true, shadow: boolean = true, corner: boolean = true) { |
||||
|
||||
container.thickness = 0; |
||||
//弹框
|
||||
if (isDialog) { |
||||
container.color = BabylonUIStyleTool.c_color_white; |
||||
container.background = BabylonUIStyleTool.c_color_white; |
||||
container.alpha = 1; |
||||
container.zIndex = 100; |
||||
} |
||||
else//长存界面
|
||||
{ |
||||
|
||||
container.color = BabylonUIStyleTool.c_color_blueBg; |
||||
container.background = BabylonUIStyleTool.c_color_blueBg; |
||||
container.alpha = 0.8; |
||||
container.zIndex = 1; |
||||
} |
||||
|
||||
|
||||
//阴影
|
||||
if (shadow) { |
||||
BabylonUIStyleTool.setStyle_Shadow(container, BabylonUIStyleTool.c_color_black, BabylonUIStyleTool.c_shadow_blur_window); |
||||
} |
||||
//圆角
|
||||
if (corner) { |
||||
container.cornerRadius = BabylonUIStyleTool.cornerRadius_window1; |
||||
} |
||||
} |
||||
//设置尺寸
|
||||
static setStyle_size(control: Control, width: string, height: string) { |
||||
control.width = width; |
||||
control.height = height; |
||||
} |
||||
|
||||
//设置文本风格
|
||||
static setStyle_bodyText(text: TextBlock, fontSize: string = "20px", color: string = "#333333", alpha: number = 1) { |
||||
text.fontSize = fontSize; |
||||
text.color = color; |
||||
text.alpha = alpha; |
||||
} |
||||
|
||||
//设置对齐方式
|
||||
//horizontal: Control.HORIZONTAL_ALIGNMENT_CENTER;Control.HORIZONTAL_ALIGNMENT_LEFT;Control.HORIZONTAL_ALIGNMENT_RIGHT;
|
||||
//vertical: Control.VERTICAL_ALIGNMENT_CENTER ; Control.VERTICAL_ALIGNMENT_LEFT;Control.VERTICAL_ALIGNMENT_RIGHT;
|
||||
//
|
||||
static setStyle_Alignment(control: Control, horizontal: number, vertical: number) { |
||||
control.horizontalAlignment = horizontal; |
||||
control.verticalAlignment = vertical; |
||||
} |
||||
|
||||
//设置边距
|
||||
static setStyle_padding(control: Control, paddingTop?: string, paddingRight?: string, paddingBottom?: string, paddingLeft?: string) { |
||||
if (paddingTop != undefined) { |
||||
control.paddingTop = paddingTop; |
||||
} |
||||
|
||||
if (paddingRight != undefined) { |
||||
control.paddingRight = paddingRight; |
||||
} |
||||
if (paddingBottom != undefined) { |
||||
control.paddingBottom = paddingBottom; |
||||
} |
||||
|
||||
if (paddingLeft != undefined) { |
||||
control.paddingLeft = paddingLeft; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
//设置阴影
|
||||
static setStyle_Shadow(container: Control, color: string = BabylonUIStyleTool.c_color_black, blur: number = BabylonUIStyleTool.c_shadow_blur_window) { |
||||
container.shadowColor = color; |
||||
container.shadowBlur = blur; |
||||
|
||||
} |
||||
//#endregion
|
||||
|
||||
|
||||
//#region 功能封装
|
||||
|
||||
|
||||
|
||||
/** |
||||
* 在按钮上增加长按事件 |
||||
* @param button 按钮 |
||||
* @param scene 所在的场景 |
||||
* @param onEnd 正常长按 |
||||
* @param onAbort 长按中端 |
||||
*/ |
||||
static addLongPressButtonBehave(button: Button, scene: Scene, onEnd?: () => void, onAbort?: () => void) { |
||||
let pickDown = false; |
||||
|
||||
let size = ConfigManager.c_size_facilityIconSize; |
||||
let vector2WithInfo: Vector2WithInfo; |
||||
|
||||
let ellipse: Ellipse; |
||||
button.onPointerUpObservable.add((info) => { |
||||
if (pickDown) { |
||||
pickDown = false; |
||||
ellipse.dispose(); |
||||
console.log("onPointerUpObservable"); |
||||
vector2WithInfo = info; |
||||
} |
||||
|
||||
}); |
||||
button.onPointerDownObservable.add(() => { |
||||
ellipse = new Ellipse("ellipse"); |
||||
ellipse.width = size + "px"; |
||||
ellipse.height = size + "px"; |
||||
ellipse.color = BabylonUIStyleTool.c_color_blue; |
||||
button.addControl(ellipse); |
||||
console.log("onPointerDownObservable"); |
||||
pickDown = true; |
||||
setAndStartTimer({ |
||||
timeout: ConfigManager.c_time_longPress, |
||||
contextObservable: scene.onBeforeRenderObservable, |
||||
breakCondition: () => { |
||||
return pickDown == false; |
||||
}, |
||||
|
||||
onEnded: (data) => { |
||||
if (onEnd) { |
||||
onEnd(); |
||||
|
||||
setTimeout( |
||||
function () { |
||||
button.onPointerUpObservable.notifyObservers(vector2WithInfo); |
||||
//此处存在问题,因为打开了前端页面,导致焦点小时,babylon无法确定鼠标抬起,则下一次的按下操作失效
|
||||
}, |
||||
250); |
||||
|
||||
|
||||
} |
||||
}, |
||||
|
||||
onAborted: () => { |
||||
if (onAbort) { |
||||
onAbort(); |
||||
} |
||||
}, |
||||
|
||||
onTick: (data) => { |
||||
ellipse.thickness = data.completeRate * 0.5 * size * data.completeRate * data.completeRate; |
||||
} |
||||
}) |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 在按钮上增加双击事件 |
||||
* @param button
|
||||
* @param scene
|
||||
* @param onClick 双击的回调 |
||||
*/ |
||||
static addDoubleClickButtonBehave(button: Button, scene: Scene, onClick: () => void) { |
||||
if (BabylonUIStyleTool.s_doubleClickHelper == null) { |
||||
BabylonUIStyleTool.s_doubleClickHelper = new DoubleClickHelper(scene); |
||||
} |
||||
button.onPointerClickObservable.add( |
||||
(eventData: Vector2WithInfo, eventState: EventState) => { |
||||
let buttonID = button.uniqueId.toString(); |
||||
if (BabylonUIStyleTool.s_doubleClickHelper.isDoubleClick(buttonID)) { |
||||
onClick(); |
||||
} |
||||
else { |
||||
BabylonUIStyleTool.s_doubleClickHelper.setClickEvent(buttonID); |
||||
} |
||||
|
||||
} |
||||
); |
||||
|
||||
} |
||||
|
||||
static s_doubleClickHelper: DoubleClickHelper; |
||||
|
||||
//#endregion
|
||||
} |
||||
|
||||
/** |
||||
* 双击帮助器 |
||||
*/ |
||||
class DoubleClickHelper { |
||||
readonly c_timer: number = 200; //双击的时间间隔
|
||||
scene: Scene; |
||||
|
||||
timer: number; |
||||
buttonID: string; |
||||
|
||||
constructor(scene: Scene) { |
||||
this.scene = scene; |
||||
let instance = this; |
||||
this.scene.onBeforeRenderObservable.add(() => { |
||||
instance.update() |
||||
}); |
||||
} |
||||
|
||||
update() { |
||||
if (this.timer > 0) { |
||||
this.timer -= this.scene.deltaTime; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 判断双击 |
||||
* @param buttonID 按钮id |
||||
*/ |
||||
isDoubleClick(buttonID: string) { |
||||
if (this.buttonID == buttonID && this.timer > 0) { |
||||
return true; |
||||
} |
||||
else { |
||||
return false; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 记录点击 |
||||
* @param buttonID
|
||||
*/ |
||||
setClickEvent(buttonID: string) { |
||||
this.buttonID = buttonID; |
||||
this.timer = this.c_timer; |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//#region 功能类
|
||||
|
||||
export class UI_LineInfo { |
||||
key: string; |
||||
mesh: AbstractMesh; |
||||
|
||||
root: Rectangle; |
||||
root_size: Vector2; |
||||
|
||||
points: Ellipse[] = []; |
||||
lineLength: number; |
||||
|
||||
infoBg: Rectangle; |
||||
info: TextBlock; |
||||
|
||||
line: MultiLine; |
||||
constructor(l_key: string, l_mesh: AbstractMesh, rootSize: Vector2, infoSize: Vector2) { |
||||
this.key = l_key; |
||||
this.mesh = l_mesh; |
||||
|
||||
this.root = new Rectangle("UI_LineRoot_" + this.key); |
||||
UIManager.Instance.uiRoot.addControl(this.root); |
||||
this.root.thickness = 0; |
||||
|
||||
|
||||
this.root_size = rootSize; |
||||
BabylonUIStyleTool.setStyle_size(this.root, rootSize.x + "px", rootSize.y + "px"); |
||||
this.root.linkWithMesh(this.mesh); |
||||
this.root.linkOffsetXInPixels = rootSize.x * 0.5; |
||||
// this.root.linkOffsetYInPixels = -40;
|
||||
|
||||
let point_start = new Ellipse("start"); |
||||
point_start.width = "5px"; |
||||
point_start.height = "5px"; |
||||
this.root.addControl(point_start); |
||||
point_start.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
point_start.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
point_start.background = BabylonUIStyleTool.c_color_3d_blue; |
||||
point_start.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
||||
point_start.shadowBlur = 5; |
||||
this.points.push(point_start); |
||||
|
||||
let point_end = new Ellipse("end"); |
||||
point_end.width = "1px"; |
||||
point_end.height = "1px"; |
||||
this.root.addControl(point_end); |
||||
point_end.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
point_end.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
this.lineLength = 20; |
||||
point_end.left = this.lineLength + "px"; |
||||
point_end.topInPixels = infoSize.y * 0.5; |
||||
this.points.push(point_end); |
||||
|
||||
|
||||
this.infoBg = new Rectangle("infoBg"); |
||||
BabylonUIStyleTool.setStyle_size(this.infoBg, infoSize.x + "px", infoSize.y + "px"); |
||||
this.root.addControl(this.infoBg); |
||||
this.infoBg.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.infoBg.shadowBlur = 5; |
||||
this.infoBg.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.infoBg.background = BabylonUIStyleTool.c_color_3d_blueBg; |
||||
this.infoBg.alpha = 0.7; |
||||
this.infoBg.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT; |
||||
this.infoBg.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
|
||||
this.info = new TextBlock("info", "info") |
||||
this.info.fontSize = 12; |
||||
this.infoBg.addControl(this.info); |
||||
this.info.color = BabylonUIStyleTool.c_color_3d_blueLight; |
||||
|
||||
|
||||
let point_infoBgLeft = new Ellipse("infoBgLeft"); |
||||
this.infoBg.addControl(point_infoBgLeft); |
||||
BabylonUIStyleTool.setStyle_size(point_infoBgLeft, "1px", "1px"); |
||||
point_infoBgLeft.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
point_infoBgLeft.leftInPixels = -1 |
||||
|
||||
this.points.push(point_infoBgLeft); |
||||
|
||||
|
||||
this.line = new MultiLine("ui_line_" + this.key); |
||||
|
||||
for (let i = 0; i < this.points.length; i++) { |
||||
this.line.add(this.points[i]); |
||||
} |
||||
// this.line.add(this.mesh);//起点
|
||||
// this.line.add(pointL);
|
||||
// this.line.add(point);
|
||||
this.line.lineWidth = 1.5; |
||||
this.line.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.line.alpha = 0.7; |
||||
this.line.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.line.shadowBlur = 5; |
||||
UIManager.Instance.uiRoot.addControl(this.line); |
||||
|
||||
|
||||
} |
||||
|
||||
setEnable(show: boolean) { |
||||
this.root.isVisible = show; |
||||
this.line.isVisible = show; |
||||
} |
||||
|
||||
dispose() { |
||||
this.root.dispose(); |
||||
|
||||
this.line.dispose(); |
||||
} |
||||
|
||||
} |
||||
|
||||
//#endregion
|
@ -0,0 +1,9 @@
|
||||
import { AbstractMesh } from "@babylonjs/core"; |
||||
|
||||
export class GameObject { |
||||
|
||||
mesh: AbstractMesh; |
||||
|
||||
components: any[]; //组件
|
||||
|
||||
} |
@ -0,0 +1,615 @@
|
||||
import { AbstractMesh, ArcRotateCamera, BoundingBoxGizmo, Color3, EventState, GizmoManager, Mesh, Observable, PickingInfo, PointerEventTypes, PointerInfo, Quaternion, Scene, UtilityLayerRenderer, Vector3 } from "@babylonjs/core"; |
||||
import { AdvancedDynamicTexture, Button, Container, InputText, Rectangle, StackPanel, TextBlock } from "@babylonjs/gui"; |
||||
import { ModeManager, ModeType } from "../controller/mode-manager"; |
||||
import { SceneManager } from "../controller/scene-manager"; |
||||
import { Game } from "../game"; |
||||
import { ModelInfo } from "../model/info/model/model-info"; |
||||
import { UIBase } from "../view/window-base/ui-base"; |
||||
import { BabylonTool } from "./babylon-tool"; |
||||
import { BabylonUIStyleTool } from "./babylon-ui-style-tool"; |
||||
|
||||
|
||||
//transform 信息的UI
|
||||
export enum TransformUIType { |
||||
Hide, |
||||
Position, |
||||
Rotation, |
||||
Scale, |
||||
} |
||||
|
||||
export class GizmoTool { |
||||
static s_gizmoManager: GizmoManager; |
||||
static s_boundingBoxGizmo: BoundingBoxGizmo; |
||||
static s_needUpdateGizmo: NeedUpdateGizmo; //需要更新的gizmo分量
|
||||
static s_transformUIInfo: TransformUIInfo; |
||||
static s_camera: ArcRotateCamera; |
||||
|
||||
static onPickMeshInfoObservable: Observable<ModelInfo>; //pick事件
|
||||
static onGizmoAimMeshObservable: Observable<AbstractMesh>; |
||||
static s_nowPickAim: ModelInfo;//当前pick的目标
|
||||
static s_nowPickAim_mesh: AbstractMesh;//当前pick的目标
|
||||
|
||||
static s_btn_poisition: Button; |
||||
static s_btn_rotation: Button; |
||||
static s_btn_scaling: Button; |
||||
|
||||
static init(scene: Scene, uiRoot: AdvancedDynamicTexture, camera: ArcRotateCamera) { |
||||
GizmoTool.s_camera = camera; |
||||
GizmoTool.s_boundingBoxGizmo = new BoundingBoxGizmo(); |
||||
GizmoTool.s_boundingBoxGizmo.setColor(new Color3(1, 0.52, 0.07)); |
||||
GizmoTool.s_boundingBoxGizmo.setEnabledRotationAxis(''); |
||||
GizmoTool.s_boundingBoxGizmo.setEnabledScaling(false); |
||||
|
||||
GizmoTool.initTransformUI(uiRoot); |
||||
|
||||
GizmoTool.s_needUpdateGizmo = new NeedUpdateGizmo(); |
||||
GizmoTool.s_gizmoManager = new GizmoManager(scene, undefined); |
||||
GizmoTool.s_gizmoManager.positionGizmoEnabled = true; |
||||
GizmoTool.s_gizmoManager.rotationGizmoEnabled = true; |
||||
GizmoTool.s_gizmoManager.scaleGizmoEnabled = true; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.planarGizmoEnabled = false; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yPlaneGizmo.isEnabled = true; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yPlaneGizmo.scaleRatio = 1; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.updateGizmoRotationToMatchAttachedMesh = false; |
||||
GizmoTool.s_gizmoManager.usePointerToAttachGizmos = false; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.onDragStartObservable.add( |
||||
GizmoTool.onPositionGizmoStart |
||||
); |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.onDragEndObservable.add( |
||||
GizmoTool.onPositionGizmoEnd |
||||
); |
||||
GizmoTool.s_gizmoManager.gizmos.rotationGizmo.onDragStartObservable.add( |
||||
GizmoTool.onRotationGizmoStart |
||||
); |
||||
GizmoTool.s_gizmoManager.gizmos.rotationGizmo.onDragEndObservable.add( |
||||
GizmoTool.onRotationGizmoEnd |
||||
); |
||||
GizmoTool.s_gizmoManager.gizmos.scaleGizmo.onDragStartObservable.add( |
||||
GizmoTool.onScaleGizmoStart |
||||
); |
||||
GizmoTool.s_gizmoManager.gizmos.scaleGizmo.onDragEndObservable.add( |
||||
GizmoTool.onScaleGizmoEnd |
||||
); |
||||
|
||||
scene.onPointerObservable.add(GizmoTool.onPointerObservable); |
||||
|
||||
GizmoTool.onGizmoAimMeshObservable = new Observable(); |
||||
|
||||
|
||||
GizmoTool.onPickMeshInfoObservable = new Observable(); |
||||
GizmoTool.onPickMeshInfoObservable.add(GizmoTool.onChangeGizmoAim); |
||||
|
||||
scene.onBeforeRenderObservable.add(GizmoTool.onBeforeRender); |
||||
GizmoTool.onTransformUITypeChange(TransformUIType.Hide); |
||||
} |
||||
|
||||
static onBeforeRender( |
||||
eventData: Scene, |
||||
eventState: EventState |
||||
) { |
||||
GizmoTool.updateTransformUI(); |
||||
|
||||
let speed = 10 / GizmoTool.s_camera.radius; |
||||
|
||||
speed *= 1000; |
||||
|
||||
GizmoTool.s_camera.panningSensibility = speed;//动态修改平移灵敏度
|
||||
|
||||
|
||||
if (SceneManager.Instance.cameraMode_Is2D) { |
||||
let camera = SceneManager.Instance.defaultCamera; |
||||
camera.beta = 0; |
||||
if (camera.beta > 0.2) { |
||||
SceneManager.Instance.changeCameraMode(false); |
||||
} |
||||
else { |
||||
//GizmoTool.s_camera.size = GizmoTool.s_camera.radius * 0.01;
|
||||
//console.log(GizmoTool.s_camera.orthoTop);
|
||||
let size_width = GizmoTool.s_camera.radius * Game.instance.canvas.width * 0.0008; |
||||
let size_height = GizmoTool.s_camera.radius * Game.instance.canvas.height * 0.0008; |
||||
camera.orthoTop = size_height; |
||||
camera.orthoBottom = - size_height; |
||||
camera.orthoLeft = - size_width; |
||||
camera.orthoRight = size_width; |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
//鼠标事件监听
|
||||
static onPointerObservable( |
||||
eventData: PointerInfo, |
||||
eventState: EventState |
||||
) { |
||||
switch (eventData.type) { |
||||
case PointerEventTypes.POINTERDOWN: |
||||
//console.log("指针按下");
|
||||
|
||||
break; |
||||
case PointerEventTypes.POINTERUP: |
||||
//console.log("指针抬起");
|
||||
GizmoTool.pickRayTest(eventData.pickInfo); |
||||
break; |
||||
case PointerEventTypes.POINTERMOVE: |
||||
//console.log("指针移动");
|
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 替换选中 |
||||
* @param modelInfo 新的modelInfo |
||||
*/ |
||||
static replacePick(modelInfo: ModelInfo) { |
||||
if (GizmoTool.s_nowPickAim != modelInfo) { |
||||
GizmoTool.onChangeGizmoAim(modelInfo); |
||||
} |
||||
} |
||||
|
||||
//射线检测
|
||||
static pickRayTest(pickResult: PickingInfo) { |
||||
if (!SceneManager.s_isPointerDrag) { |
||||
if (pickResult.hit) { |
||||
let meshName = pickResult.pickedMesh.name; |
||||
// GizmoTool.onPickMeshObservable.notifyObservers(pickResult.pickedMesh);
|
||||
//GizmoTool.changeGizmoAim(pickResult.pickedMesh);
|
||||
|
||||
} else { |
||||
//GizmoTool.onPickMeshInfoObservable.notifyObservers(null);
|
||||
} |
||||
} |
||||
|
||||
// console.log("pickRayTest " + pickResult.hit);
|
||||
|
||||
} |
||||
|
||||
//改变gizmo目标mesh
|
||||
static onChangeGizmoAim(modelInfo: ModelInfo) { |
||||
let mesh = null; |
||||
GizmoTool.s_nowPickAim = modelInfo; |
||||
|
||||
if (modelInfo != null) { |
||||
mesh = modelInfo.modelBox; |
||||
} |
||||
|
||||
GizmoTool.changeGizmoAim(mesh); |
||||
|
||||
if (ModeManager.currentMode == ModeType.Edit) { |
||||
GizmoTool.s_boundingBoxGizmo.attachedMesh = mesh; |
||||
} |
||||
|
||||
|
||||
GizmoTool.s_transformUIInfo.Mesh = mesh; |
||||
GizmoTool.s_transformUIInfo.modelInfo = modelInfo; |
||||
GizmoTool.updateTransformUI(mesh != null); |
||||
} |
||||
|
||||
//改变Gizmo目标
|
||||
static changeGizmoAim(mesh: AbstractMesh, x: boolean = true, y = true, z = true) { |
||||
|
||||
|
||||
GizmoTool.s_nowPickAim_mesh = mesh; |
||||
GizmoTool.s_gizmoManager.attachToMesh(mesh); |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.xGizmo.isEnabled = x; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yGizmo.isEnabled = y; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yPlaneGizmo.isEnabled = x && z; |
||||
GizmoTool.s_gizmoManager.gizmos.positionGizmo.zGizmo.isEnabled = z; |
||||
GizmoTool.onGizmoAimMeshObservable.notifyObservers(mesh); |
||||
|
||||
} |
||||
|
||||
//离开当前目标(如果当前在这个)
|
||||
static leaveTheGizmoAim(modelInfo: ModelInfo) { |
||||
if (GizmoTool.s_nowPickAim != null && GizmoTool.s_nowPickAim == modelInfo) { |
||||
GizmoTool.onChangeGizmoAim(null); |
||||
} |
||||
} |
||||
|
||||
//离开当前目标(如果当前在这个)
|
||||
static leaveTheGizmoAimMesh(mesh: AbstractMesh) { |
||||
if (GizmoTool.s_nowPickAim_mesh != null && GizmoTool.s_nowPickAim_mesh == mesh) { |
||||
GizmoTool.onChangeGizmoAim(null); |
||||
} |
||||
} |
||||
|
||||
//初始化
|
||||
static initTransformUI(advTexture: AdvancedDynamicTexture) { |
||||
let transformUIInfo = new TransformUIInfo(); |
||||
GizmoTool.s_transformUIInfo = transformUIInfo; |
||||
|
||||
let width = 200; |
||||
let height = 150; |
||||
|
||||
let ui_transformUIRoot = new Rectangle('GizmoWindow'); |
||||
ui_transformUIRoot.width = width + 'px'; |
||||
ui_transformUIRoot.height = height + 'px'; |
||||
ui_transformUIRoot.background = UIBase.color_gray; |
||||
ui_transformUIRoot.color = '#FFFFFF'; |
||||
ui_transformUIRoot.alpha = 0.8; |
||||
ui_transformUIRoot.horizontalAlignment = |
||||
Container.HORIZONTAL_ALIGNMENT_LEFT; |
||||
ui_transformUIRoot.verticalAlignment = |
||||
Container.VERTICAL_ALIGNMENT_TOP; |
||||
ui_transformUIRoot.thickness = 0; |
||||
ui_transformUIRoot.cornerRadius = BabylonUIStyleTool.cornerRadius_window1; |
||||
ui_transformUIRoot.zIndex = BabylonUIStyleTool.c_zIndex_gizmo; |
||||
advTexture.addControl(ui_transformUIRoot); |
||||
transformUIInfo.root = ui_transformUIRoot; |
||||
|
||||
let stackPanel = new StackPanel('verticalGroup'); |
||||
stackPanel.isVertical = true; |
||||
stackPanel.width = width + 'px'; |
||||
stackPanel.height = height + 'px'; |
||||
ui_transformUIRoot.addControl(stackPanel); |
||||
|
||||
let txt_title = new TextBlock('title', '信息:(x,y,z)'); |
||||
transformUIInfo.titleText = txt_title; |
||||
txt_title.width = width + 'px'; |
||||
txt_title.height = '45px'; |
||||
|
||||
stackPanel.addControl(txt_title); |
||||
|
||||
for (let i = 0; i < 3; i++) { |
||||
let l_InputInfo: UIVector3InputInfo = new UIVector3InputInfo(); |
||||
let postionRoot = new StackPanel('Group' + i); |
||||
stackPanel.addControl(postionRoot); |
||||
postionRoot.width = width + 'px'; |
||||
postionRoot.height = height * 0.23 + 'px'; |
||||
postionRoot.isVertical = false; |
||||
|
||||
let groupName = Button.CreateSimpleButton( |
||||
'groupName', |
||||
'info:' |
||||
); |
||||
groupName.width = width * 0.22 + 'px'; |
||||
groupName.height = height * 0.22 + 'px'; |
||||
groupName.fontSize = 12; |
||||
groupName.background = '#FF8833'; |
||||
groupName.color = 'white'; |
||||
groupName.thickness = 0; |
||||
groupName.paddingBottom = '2px'; |
||||
postionRoot.addControl(groupName); |
||||
|
||||
groupName.onPointerClickObservable.add(() => { |
||||
switch (i) { |
||||
case 0: |
||||
transformUIInfo.OnTypeChangeObservable.notifyObservers( |
||||
TransformUIType.Position |
||||
); |
||||
break; |
||||
case 1: |
||||
transformUIInfo.OnTypeChangeObservable.notifyObservers( |
||||
TransformUIType.Rotation |
||||
); |
||||
break; |
||||
case 2: |
||||
transformUIInfo.OnTypeChangeObservable.notifyObservers( |
||||
TransformUIType.Scale |
||||
); |
||||
break; |
||||
} |
||||
}); |
||||
|
||||
switch (i) { |
||||
case 0: |
||||
transformUIInfo.position = l_InputInfo; |
||||
postionRoot.name = 'transform'; |
||||
groupName.textBlock.text = '位置:'; |
||||
GizmoTool.s_btn_poisition = groupName; |
||||
break; |
||||
case 1: |
||||
transformUIInfo.rotation = l_InputInfo; |
||||
postionRoot.name = 'rotation'; |
||||
groupName.textBlock.text = '旋转:'; |
||||
GizmoTool.s_btn_rotation = groupName; |
||||
break; |
||||
case 2: |
||||
transformUIInfo.scale = l_InputInfo; |
||||
postionRoot.name = 'scale'; |
||||
groupName.textBlock.text = '缩放:'; |
||||
GizmoTool.s_btn_scaling = groupName; |
||||
break; |
||||
} |
||||
|
||||
for (let j = 0; j < 3; j++) { |
||||
let xyz = new InputText('xyz', '12'); |
||||
xyz.width = width * 0.25 + 'px'; |
||||
xyz.height = height * 0.22 + 'px'; |
||||
|
||||
xyz.color = 'white'; |
||||
xyz.alpha = 0.8; |
||||
xyz.margin = '5px'; |
||||
xyz.fontSize = 13; |
||||
xyz.thickness = 0.1; |
||||
xyz.paddingLeft = '0.1px'; |
||||
xyz.paddingBottom = '2px'; |
||||
|
||||
switch (i) { |
||||
case 0: |
||||
xyz.onTextChangedObservable.add(GizmoTool.onGizmoUIInput_Position); |
||||
break; |
||||
case 1: |
||||
xyz.onTextChangedObservable.add(GizmoTool.onGizmoUIInput_Rotation); |
||||
break; |
||||
case 2: |
||||
xyz.onTextChangedObservable.add(GizmoTool.onGizmoUIInput_Scale); |
||||
break; |
||||
} |
||||
|
||||
switch (j) { |
||||
case 0: |
||||
l_InputInfo.x = xyz; |
||||
xyz.name = 'x'; |
||||
xyz.background = '#C20000'; |
||||
break; |
||||
case 1: |
||||
l_InputInfo.y = xyz; |
||||
xyz.name = 'y'; |
||||
xyz.background = '#00820F'; |
||||
break; |
||||
case 2: |
||||
l_InputInfo.z = xyz; |
||||
xyz.name = 'z'; |
||||
xyz.background = '#0047C2'; |
||||
break; |
||||
} |
||||
|
||||
postionRoot.addControl(xyz); |
||||
} |
||||
} |
||||
transformUIInfo.OnTypeChangeObservable.add( |
||||
GizmoTool.onTransformUITypeChange |
||||
); |
||||
} |
||||
|
||||
static onPositionGizmoStart() { |
||||
GizmoTool.s_needUpdateGizmo.position = true; |
||||
} |
||||
|
||||
static onPositionGizmoEnd() { |
||||
GizmoTool.s_needUpdateGizmo.position = false; |
||||
} |
||||
|
||||
static onRotationGizmoStart() { |
||||
GizmoTool.s_needUpdateGizmo.rotation = true; |
||||
} |
||||
static onRotationGizmoEnd() { |
||||
GizmoTool.s_needUpdateGizmo.rotation = false; |
||||
} |
||||
|
||||
static onScaleGizmoStart() { |
||||
GizmoTool.s_needUpdateGizmo.scale = true; |
||||
} |
||||
|
||||
static onScaleGizmoEnd() { |
||||
GizmoTool.s_needUpdateGizmo.scale = false; |
||||
} |
||||
|
||||
static currentGizmoType: TransformUIType = TransformUIType.Position; |
||||
//操作的类型发生变化: 隐藏、position、rotation、scale
|
||||
static onTransformUITypeChange(uiType: TransformUIType) { |
||||
// console.log("改变type" + uiType);
|
||||
let transformUIInfo = GizmoTool.s_transformUIInfo; |
||||
// if (uiType == TransformUIType.Hide) {
|
||||
// transformUIInfo.root.isVisible = false;
|
||||
// } else {
|
||||
// transformUIInfo.root.isVisible = true;
|
||||
// }
|
||||
transformUIInfo.root.isVisible = ModeManager.isDebug;//先隐藏,因为效果图中没有
|
||||
|
||||
let isEditMode = ModeManager.currentMode == ModeType.Edit; |
||||
|
||||
let isPosition = uiType == TransformUIType.Position && isEditMode; |
||||
GizmoTool.s_btn_poisition.background = isPosition |
||||
? UIBase.color_yellow |
||||
: UIBase.color_null; |
||||
GizmoTool.s_gizmoManager.positionGizmoEnabled = isPosition; |
||||
|
||||
let isRotation = uiType == TransformUIType.Rotation && isEditMode; |
||||
GizmoTool.s_btn_rotation.background = isRotation |
||||
? UIBase.color_yellow |
||||
: UIBase.color_null; |
||||
GizmoTool.s_gizmoManager.rotationGizmoEnabled = isRotation; |
||||
|
||||
let isScaling = uiType == TransformUIType.Scale && isEditMode; |
||||
GizmoTool.s_btn_scaling.background = isScaling |
||||
? UIBase.color_yellow |
||||
: UIBase.color_null; |
||||
GizmoTool.s_gizmoManager.scaleGizmoEnabled = isScaling; |
||||
|
||||
if (uiType == TransformUIType.Hide) { //隐藏选中框
|
||||
GizmoTool.s_boundingBoxGizmo.attachedMesh = null; |
||||
} |
||||
|
||||
} |
||||
|
||||
//更新显示
|
||||
static updateTransformUI(updateAll = false) { |
||||
let transformUIInfo = GizmoTool.s_transformUIInfo; |
||||
let updateGizmoInfo = GizmoTool.s_needUpdateGizmo; |
||||
let mesh = transformUIInfo.mesh; |
||||
|
||||
if (transformUIInfo == null || mesh == null) { |
||||
transformUIInfo.titleText.text = ''; |
||||
return; |
||||
} |
||||
|
||||
transformUIInfo.titleText.text = mesh.name; |
||||
|
||||
if (updateGizmoInfo.position || updateAll) { |
||||
transformUIInfo.position.x.text = mesh.position.x.toPrecision(6); |
||||
transformUIInfo.position.y.text = mesh.position.y.toPrecision(6); |
||||
transformUIInfo.position.z.text = mesh.position.z.toPrecision(6); |
||||
} |
||||
|
||||
if (updateGizmoInfo.rotation || updateAll) { |
||||
let augle = mesh.rotationQuaternion.toEulerAngles(); |
||||
|
||||
let radian1 = BabylonTool.c_radian1; //1弧度
|
||||
augle = augle.multiplyByFloats(radian1, radian1, radian1); |
||||
|
||||
transformUIInfo.rotation.x.text = augle.x.toPrecision(6); |
||||
transformUIInfo.rotation.y.text = augle.y.toPrecision(6); |
||||
transformUIInfo.rotation.z.text = augle.z.toPrecision(6); |
||||
} |
||||
|
||||
if (updateGizmoInfo.scale || updateAll) { |
||||
let originalScaling = |
||||
GizmoTool.s_transformUIInfo.modelInfo.modelData.transformData |
||||
.originalScaling; |
||||
transformUIInfo.scale.x.text = ( |
||||
mesh.absoluteScaling.x / originalScaling.x |
||||
).toPrecision(6); |
||||
transformUIInfo.scale.y.text = ( |
||||
mesh.absoluteScaling.y / originalScaling.y |
||||
).toPrecision(6); |
||||
transformUIInfo.scale.z.text = ( |
||||
mesh.absoluteScaling.z / originalScaling.z |
||||
).toPrecision(6); |
||||
} |
||||
} |
||||
|
||||
//输入gizmo 数值 - position
|
||||
static onGizmoUIInput_Position( |
||||
eventData: InputText, |
||||
eventState: EventState |
||||
) { |
||||
let transformUIInfo = GizmoTool.s_transformUIInfo; |
||||
|
||||
switch (eventData.name) { |
||||
case 'x': |
||||
transformUIInfo.Mesh.position.x = Number.parseFloat( |
||||
transformUIInfo.position.x.text |
||||
); |
||||
break; |
||||
case 'y': |
||||
transformUIInfo.Mesh.position.y = Number.parseFloat( |
||||
transformUIInfo.position.y.text |
||||
); |
||||
break; |
||||
case 'z': |
||||
transformUIInfo.Mesh.position.z = Number.parseFloat( |
||||
transformUIInfo.position.z.text |
||||
); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
//输入gizmo 数值 - rotation
|
||||
static onGizmoUIInput_Rotation( |
||||
eventData: InputText, |
||||
eventState: EventState |
||||
) { |
||||
let transformUIInfo = GizmoTool.s_transformUIInfo; |
||||
|
||||
let eugle = new Vector3(); |
||||
eugle.x = |
||||
Number.parseFloat(transformUIInfo.rotation.x.text) / |
||||
BabylonTool.c_radian1; |
||||
eugle.y = |
||||
Number.parseFloat(transformUIInfo.rotation.y.text) / |
||||
BabylonTool.c_radian1; |
||||
eugle.z = |
||||
Number.parseFloat(transformUIInfo.rotation.z.text) / |
||||
BabylonTool.c_radian1; |
||||
|
||||
transformUIInfo.Mesh.rotationQuaternion = Quaternion.FromEulerAngles( |
||||
eugle.x, |
||||
eugle.y, |
||||
eugle.z |
||||
); |
||||
} |
||||
|
||||
//输入gizmo 数值 - scale
|
||||
static onGizmoUIInput_Scale( |
||||
eventData: InputText, |
||||
eventState: EventState |
||||
) { |
||||
let transformUIInfo = GizmoTool.s_transformUIInfo; |
||||
let originalScaling = |
||||
GizmoTool.s_transformUIInfo.modelInfo.modelData.transformData |
||||
.originalScaling; |
||||
|
||||
switch (eventData.name) { |
||||
case 'x': |
||||
transformUIInfo.Mesh.scaling.x = |
||||
Number.parseFloat(transformUIInfo.scale.x.text) * originalScaling.x; |
||||
break; |
||||
case 'y': |
||||
transformUIInfo.Mesh.scaling.y = |
||||
Number.parseFloat(transformUIInfo.scale.y.text) * originalScaling.y; |
||||
break; |
||||
case 'z': |
||||
transformUIInfo.Mesh.scaling.z = |
||||
Number.parseFloat(transformUIInfo.scale.z.text) * originalScaling.z; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
//需要更新gizmo的类型
|
||||
class NeedUpdateGizmo { |
||||
public position = true; |
||||
public rotation = false; |
||||
public scale = false; |
||||
} |
||||
|
||||
|
||||
|
||||
//存储vector3 对应文本输入UI的映射
|
||||
class UIVector3InputInfo { |
||||
public x: InputText; |
||||
public y: InputText; |
||||
public z: InputText; |
||||
} |
||||
|
||||
//存储 transform 相关UI输入类的映射
|
||||
class TransformUIInfo { |
||||
public root: Rectangle; |
||||
public position: UIVector3InputInfo; |
||||
public rotation: UIVector3InputInfo; |
||||
public scale: UIVector3InputInfo; |
||||
public titleText: TextBlock; |
||||
public nowType: TransformUIType = TransformUIType.Hide; |
||||
public mesh: AbstractMesh; |
||||
public modelInfo: ModelInfo; |
||||
public onTypeChangeObservable: Observable<TransformUIType>; |
||||
public onPositionChangeObservable: Observable<Vector3> = new Observable<Vector3>(); |
||||
public onRotationChangeObservable: Observable<Vector3> = new Observable<Vector3>(); |
||||
public onScaleChangeObservable: Observable<Vector3> = new Observable<Vector3>(); |
||||
|
||||
set Mesh(value: AbstractMesh) { |
||||
let lastMesh = this.mesh; |
||||
this.mesh = value; |
||||
if (value == null) { |
||||
this.NowType = TransformUIType.Hide; |
||||
} else { |
||||
//if (lastMesh == null) {
|
||||
this.NowType = GizmoTool.currentGizmoType;// TransformUIType.Position;
|
||||
//}
|
||||
} |
||||
} |
||||
|
||||
get Mesh() { |
||||
return this.mesh; |
||||
} |
||||
|
||||
set NowType(value: TransformUIType) { |
||||
this.nowType = value; |
||||
// console.log("NowType====" + value);
|
||||
this.OnTypeChangeObservable.notifyObservers(this.nowType); |
||||
} |
||||
|
||||
get OnTypeChangeObservable(): Observable<TransformUIType> { |
||||
if (this.onTypeChangeObservable == null) { |
||||
this.onTypeChangeObservable = new Observable<TransformUIType>(); |
||||
} |
||||
return this.onTypeChangeObservable; |
||||
} |
||||
} |
@ -0,0 +1,64 @@
|
||||
|
||||
/** |
||||
* 加载管理器 |
||||
*/ |
||||
export class LoadTool { |
||||
static s_loadingData: Map<any, string> = new Map(); |
||||
static s_loadingNum: number = 0; |
||||
|
||||
static readonly c_tag_preloadMark = "preloadMark";//预加载标绘物模型(不阻断)
|
||||
static readonly c_tag_createMark = "createMark";//创建标绘物(不阻断)
|
||||
static readonly c_tag_facilityPrefab = "facilityPrefab";//设备预制体
|
||||
|
||||
|
||||
/** |
||||
* 新增加载数据 |
||||
* @param data
|
||||
* @param tag
|
||||
*/ |
||||
static add(data: any, tag?: string) { |
||||
switch (tag) { |
||||
case LoadTool.c_tag_preloadMark: |
||||
case LoadTool.c_tag_createMark: return; |
||||
} |
||||
|
||||
let oldNum = LoadTool.s_loadingNum; |
||||
LoadTool.s_loadingData.set(data, tag); |
||||
LoadTool.s_loadingNum = LoadTool.s_loadingData.size; |
||||
if (oldNum == 0 && LoadTool.s_loadingNum == 1) { |
||||
LoadTool.onStart(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 加载完成,移除记录 |
||||
* @param data
|
||||
*/ |
||||
static remove(data: any) { |
||||
let oldNum = LoadTool.s_loadingNum; |
||||
if (LoadTool.s_loadingData.has(data)) { |
||||
LoadTool.s_loadingData.delete(data); |
||||
} |
||||
LoadTool.s_loadingNum = LoadTool.s_loadingData.size; |
||||
if (oldNum > 0 && LoadTool.s_loadingNum == 0) { |
||||
LoadTool.onEnd(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 开始加载 |
||||
*/ |
||||
static onStart() { |
||||
console.log("开始加载"); |
||||
//ThreeDimensionalHomeComponent.instance.maskLayerService.sendMessage(true)
|
||||
} |
||||
|
||||
/** |
||||
* 全部加载结束 |
||||
*/ |
||||
static onEnd() { |
||||
console.log("结束加载"); |
||||
//ThreeDimensionalHomeComponent.instance.maskLayerService.sendMessage(false)
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,476 @@
|
||||
import { EventState, Mesh, MeshBuilder, PickingInfo, PointerEventTypes, PointerInfo, Scene, Vector3 } from "@babylonjs/core"; |
||||
import { Button, Container, Control, Ellipse, MultiLine, Rectangle, TextBlock } from "@babylonjs/gui"; |
||||
import { UIManager } from "../controller/ui-manager"; |
||||
import { BabylonUIStyleTool } from "./babylon-ui-style-tool"; |
||||
|
||||
/** |
||||
* 测量工具 |
||||
*/ |
||||
export class MeasureTool { |
||||
|
||||
|
||||
static instance: MeasureTool; |
||||
|
||||
/** |
||||
* 当前编辑的测量 |
||||
*/ |
||||
currentMeasureInfo: MeasureInfo; |
||||
|
||||
/** |
||||
* 当前所处的测量状态 |
||||
*/ |
||||
currentMeasureType: MeasureType = MeasureType.None; |
||||
|
||||
scene: Scene; |
||||
|
||||
constructor(scene: Scene) { |
||||
this.scene = scene; |
||||
MeasureTool.instance = this; |
||||
scene.onPointerObservable.add( |
||||
MeasureTool.instance.onPointerObservable |
||||
); |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 新建测量 |
||||
* @param start
|
||||
* @param type
|
||||
*/ |
||||
createMeasureInfo(start: Vector3) { |
||||
let type: MeasureType = this.currentMeasureType; |
||||
if (type != MeasureType.None) { |
||||
this.currentMeasureInfo = new MeasureInfo(start, type); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 中断测量 |
||||
*/ |
||||
breakMeasure() { |
||||
this.currentMeasureInfo = null; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 改变测量类型 |
||||
* @param type MeasureType.None,表示结束测量 |
||||
*/ |
||||
changeMeasureType(type: MeasureType) { |
||||
|
||||
|
||||
this.currentMeasureType = type; |
||||
switch (type) { |
||||
case MeasureType.None: |
||||
this.breakMeasure(); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
//鼠标交互监听
|
||||
onPointerObservable(eventData: PointerInfo, eventState: EventState) { |
||||
let instance = MeasureTool.instance; |
||||
if (instance.currentMeasureType == MeasureType.None) { |
||||
return; //非测量状态
|
||||
} |
||||
|
||||
switch (eventData.type) { |
||||
case PointerEventTypes.POINTERPICK: |
||||
if (eventData.event.button == 0 && eventData.pickInfo.hit) { |
||||
if (!instance.isPickTooFar(eventData.pickInfo)) { |
||||
if (instance.currentMeasureInfo == null) { |
||||
instance.createMeasureInfo(eventData.pickInfo.pickedPoint); |
||||
} |
||||
else { |
||||
instance.addMeasurePoint(eventData.pickInfo); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
else if (eventData.event.button == 2) //右键,中断
|
||||
{ |
||||
instance.breakMeasure(); |
||||
|
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 添加测量点 |
||||
*/ |
||||
addMeasurePoint(pickInfo: PickingInfo) { |
||||
console.log("测量", pickInfo); |
||||
if (this.currentMeasureInfo != null) { |
||||
this.currentMeasureInfo.addPoint(pickInfo.pickedPoint); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 点击太远了(点在天空盒上) |
||||
* @param point
|
||||
*/ |
||||
isPickTooFar(point: PickingInfo) { |
||||
|
||||
if (point.pickedMesh != null && point.pickedMesh.name == "skyBox") { |
||||
return true; |
||||
} |
||||
else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 测量状态 |
||||
*/ |
||||
export enum MeasureType { |
||||
/** |
||||
* 未测量 |
||||
*/ |
||||
None, |
||||
|
||||
/** |
||||
* 直线距离 |
||||
*/ |
||||
Distance, |
||||
|
||||
/** |
||||
* 高度 |
||||
*/ |
||||
Height, |
||||
|
||||
/** |
||||
* 面积 |
||||
*/ |
||||
Area, |
||||
} |
||||
|
||||
/** |
||||
* 测量信息 |
||||
*/ |
||||
export class MeasureInfo { |
||||
/** |
||||
* 所有点 |
||||
*/ |
||||
points: MeasurePoint[]; |
||||
|
||||
type: MeasureType; |
||||
|
||||
/** |
||||
* ui根节点 |
||||
*/ |
||||
uiRoot: Container; |
||||
|
||||
|
||||
/** |
||||
* 圆形起点 |
||||
*/ |
||||
ell_start: Ellipse; |
||||
|
||||
/** |
||||
* 释放按钮 |
||||
*/ |
||||
btn_dispose: Button; |
||||
|
||||
/** |
||||
* 是信息 |
||||
*/ |
||||
txt_info: TextBlock; |
||||
|
||||
/** |
||||
* 信息背景 |
||||
*/ |
||||
txtbg: Rectangle; |
||||
|
||||
mulLine: MultiLine; |
||||
|
||||
constructor(start: Vector3, type: MeasureType) { |
||||
this.points = []; |
||||
this.type = type; |
||||
|
||||
this.mulLine = new MultiLine("mulLine" + type); |
||||
this.mulLine.lineWidth = 1.5; |
||||
this.mulLine.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.mulLine.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.mulLine.shadowBlur = 5; |
||||
UIManager.Instance.uiRoot.addControl(this.mulLine); |
||||
this.addPoint(start); |
||||
|
||||
this.updateUI(); |
||||
} |
||||
|
||||
/** |
||||
* 新增节点 |
||||
*/ |
||||
addPoint(pos: Vector3) { |
||||
if (this.points.length > 0) { |
||||
for (let i = 0; i < this.points.length; i++) { |
||||
this.points[i].changeEnd(false); |
||||
} |
||||
if (this.type == MeasureType.Height) { |
||||
pos.x = this.points[0].pos.x; |
||||
pos.z = this.points[0].pos.z; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
let point = new MeasurePoint(pos, true, this); |
||||
this.points.push(point); |
||||
|
||||
if (this.points.length > 3 && this.type == MeasureType.Area) { |
||||
let lastPoint = this.mulLine.getAt(this.points.length - 1); |
||||
this.mulLine.remove(lastPoint); |
||||
this.mulLine.add(point.mesh); |
||||
this.mulLine.add(this.points[0].mesh); |
||||
} |
||||
else { |
||||
this.mulLine.add(point.mesh); |
||||
} |
||||
|
||||
|
||||
|
||||
if (this.points.length > 1 && this.type == MeasureType.Height) { //高度只能放两个点
|
||||
MeasureTool.instance.breakMeasure(); |
||||
} |
||||
|
||||
if (this.points.length == 3 && this.type == MeasureType.Area) { |
||||
this.mulLine.add(this.points[0].mesh); |
||||
} |
||||
|
||||
//更新显示
|
||||
this.updateUI(); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 更新UI |
||||
*/ |
||||
updateUI() { |
||||
if (this.uiRoot == null) { |
||||
this.ell_start = new Ellipse("MeasureStart") |
||||
UIManager.Instance.uiRoot.addControl(this.ell_start); |
||||
BabylonUIStyleTool.setStyle_size(this.ell_start, "10px", "10px"); |
||||
this.ell_start.thickness = 2; |
||||
this.ell_start.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.ell_start.background = BabylonUIStyleTool.c_color_3d_blueBg; |
||||
this.ell_start.linkWithMesh(this.points[0].mesh); |
||||
|
||||
this.uiRoot = new Container("Measure"); |
||||
this.uiRoot.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
UIManager.Instance.uiRoot.addControl(this.uiRoot); |
||||
BabylonUIStyleTool.setStyle_size(this.uiRoot, "100px", "40px"); |
||||
|
||||
this.btn_dispose = Button.CreateSimpleButton("dispose", "x"); |
||||
this.uiRoot.addControl(this.btn_dispose); |
||||
this.btn_dispose.leftInPixels = 10; |
||||
BabylonUIStyleTool.setStyle_size(this.btn_dispose, "15px", "15px"); |
||||
this.btn_dispose.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
this.btn_dispose.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
let instance = this; |
||||
this.btn_dispose.onPointerClickObservable.add(() => { |
||||
instance.dispose(); |
||||
}); |
||||
this.btn_dispose.background = BabylonUIStyleTool.c_color_3d_blueBg; |
||||
this.btn_dispose.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
|
||||
this.txtbg = new Rectangle("txtBG"); |
||||
this.uiRoot.addControl(this.txtbg); |
||||
BabylonUIStyleTool.setStyle_size(this.txtbg, "70px", "25px"); |
||||
this.txtbg.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
this.txtbg.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM; |
||||
this.txtbg.background = BabylonUIStyleTool.c_color_3d_blueBg; |
||||
this.txtbg.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
|
||||
|
||||
this.txt_info = new TextBlock("txt"); |
||||
this.uiRoot.addControl(this.txt_info); |
||||
BabylonUIStyleTool.setStyle_size(this.txt_info, "70px", "25px"); |
||||
this.txt_info.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
this.txt_info.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM; |
||||
this.txt_info.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
this.txt_info.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
this.txt_info.resizeToFit = true; |
||||
|
||||
let ell_end = new Ellipse("end") |
||||
this.uiRoot.addControl(ell_end); |
||||
BabylonUIStyleTool.setStyle_size(ell_end, "10px", "10px"); |
||||
ell_end.thickness = 2; |
||||
ell_end.color = BabylonUIStyleTool.c_color_3d_blue; |
||||
ell_end.background = BabylonUIStyleTool.c_color_3d_blueBg; |
||||
ell_end.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||
ell_end.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||
|
||||
} |
||||
|
||||
|
||||
let info: string = ""; |
||||
switch (this.type) { |
||||
case MeasureType.Distance: |
||||
info = " 长度:" + this.getPointsDistance(this.points).toFixed(1) + "米"; |
||||
break; |
||||
case MeasureType.Height: |
||||
info = " 高度:" + this.getPointsHeight(this.points).toFixed(1) + "米"; |
||||
break; |
||||
case MeasureType.Area: |
||||
info = " 面积:" + this.getPointsArea(this.points).toFixed(1) + "平方米"; |
||||
break; |
||||
} |
||||
|
||||
this.txt_info.text = info; |
||||
|
||||
let instance = this; |
||||
setTimeout(() => { |
||||
|
||||
instance.txtbg.widthInPixels = instance.txt_info.widthInPixels + 3; |
||||
instance.uiRoot.widthInPixels = instance.txt_info.widthInPixels + 3; |
||||
|
||||
let lastPoint = instance.points[instance.points.length - 1]; |
||||
instance.uiRoot.linkWithMesh(lastPoint.mesh); |
||||
instance.uiRoot.linkOffsetYInPixels = 20 - 5; |
||||
instance.uiRoot.linkOffsetXInPixels = instance.uiRoot.widthInPixels * 0.5 - 5; |
||||
|
||||
}, (30)); |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取多个点的长度 |
||||
* @param points
|
||||
*/ |
||||
getPointsDistance(points: MeasurePoint[]) { |
||||
let result = 0; |
||||
|
||||
if (points != null && points.length > 1) { |
||||
for (let i = 1; i < points.length; i++) { |
||||
result += Vector3.Distance(points[i - 1].pos, points[i].pos); |
||||
} |
||||
} |
||||
|
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 获取高度 |
||||
* @param points
|
||||
*/ |
||||
getPointsHeight(points: MeasurePoint[]) { |
||||
let result = 0; |
||||
|
||||
if (points != null && points.length > 1) { |
||||
result = points[points.length - 1].pos.y - points[0].pos.y; |
||||
result = Math.abs(result); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 获取面积(在地面的投影面积, xz平面内) |
||||
* @param points
|
||||
*/ |
||||
getPointsArea(points: MeasurePoint[]) { |
||||
let result = 0; |
||||
|
||||
if (points != null && points.length > 2) { |
||||
|
||||
for (let i = 0; i < points.length - 1; i++) { |
||||
result += (points[i].pos.x * points[i + 1].pos.z - points[i + 1].pos.x * points[i].pos.z); |
||||
} |
||||
|
||||
let num = points.length - 1; |
||||
|
||||
result = 0.5 * (result + points[num].pos.x * points[0].pos.z - points[0].pos.x * points[num].pos.z); |
||||
result = Math.abs(result); |
||||
} |
||||
|
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 释放 |
||||
*/ |
||||
dispose() { |
||||
this.ell_start.dispose(); |
||||
|
||||
this.uiRoot.dispose(); |
||||
this.uiRoot = null; |
||||
this.btn_dispose = null; |
||||
this.txt_info = null; |
||||
this.mulLine.dispose(); |
||||
this.mulLine = null; |
||||
|
||||
for (let i = 0; i < this.points.length; i++) { |
||||
this.points[i].dispose(); |
||||
} |
||||
this.points = []; |
||||
|
||||
MeasureTool.instance.breakMeasure(); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 测量点 |
||||
*/ |
||||
export class MeasurePoint { |
||||
|
||||
/** |
||||
* 终点 |
||||
*/ |
||||
isEnd: boolean; |
||||
|
||||
pos: Vector3; |
||||
|
||||
/** |
||||
* 所属测量信息
|
||||
*/ |
||||
belongTo: MeasureInfo; |
||||
|
||||
/** |
||||
* 模型网格 |
||||
*/ |
||||
mesh: Mesh; |
||||
|
||||
|
||||
|
||||
constructor(pos: Vector3, isEnd: boolean, belongTo: MeasureInfo) { |
||||
this.pos = pos; |
||||
this.isEnd = isEnd; |
||||
this.belongTo = belongTo; |
||||
|
||||
this.mesh = MeshBuilder.CreateSphere(belongTo.type.toString(), { segments: 1, diameter: 0.01 }, MeasureTool.instance.scene); |
||||
this.mesh.position = pos; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 更新终点的显示 |
||||
* @param isEnd
|
||||
*/ |
||||
changeEnd(isEnd: boolean) { |
||||
this.isEnd = isEnd; |
||||
//更新终点显示
|
||||
|
||||
} |
||||
|
||||
dispose() { |
||||
if (this.mesh != null) { |
||||
this.mesh.dispose(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,322 @@
|
||||
//mesh对象池
|
||||
//为避免重复加载、销毁mesh对象
|
||||
|
||||
import { AbstractMesh, MeshBuilder, Observable, TransformNode, Vector3 } from "@babylonjs/core"; |
||||
import { SceneManager } from "../controller/scene-manager"; |
||||
import { ModelData, ModelType } from "../model/data/model-data/model-data"; |
||||
import { ModelInfo } from "../model/info/model/model-info"; |
||||
import { TsTool } from "./ts-tool"; |
||||
|
||||
export class MeshPool { |
||||
|
||||
//#region 单例
|
||||
private static instance: MeshPool; |
||||
|
||||
static get Instance() { |
||||
if (MeshPool.instance == null) { |
||||
MeshPool.instance = new MeshPool(); |
||||
} |
||||
|
||||
return MeshPool.instance; |
||||
} |
||||
//#endregion
|
||||
|
||||
|
||||
root: TransformNode; |
||||
|
||||
prefabPool: Map<string, MeshPoolInfo[]> = new Map();//预制体池
|
||||
idlePool: Map<string, MeshPoolInfo[]> = new Map();//空闲池
|
||||
workingPool: Map<string, MeshPoolInfo[]> = new Map();//工作池
|
||||
|
||||
constructor() { |
||||
this.root = new TransformNode("MeshPoolRoot", SceneManager.Instance.scene); |
||||
|
||||
this.root.setEnabled(false);//隐藏起来
|
||||
} |
||||
|
||||
//#region 外部方法
|
||||
|
||||
/** |
||||
* 从对象池导入模型(经过包装盒包装) |
||||
*/ |
||||
static importMesh(modeltype: ModelType, modelData: ModelData, isNew: boolean = true, fromClone: boolean = true, tag?: string, onSuccess?: (meshBox: AbstractMesh, meshes: AbstractMesh[], result: MeshPoolInfo) => void, onlyPrefab = false,): MeshPoolInfo { |
||||
let result = MeshPool.Instance.getMesh(modelData.resPath, modelData.resName, fromClone); |
||||
|
||||
if (result == null) { |
||||
//console.log("对象池中没有,要加载:" + path + name);
|
||||
|
||||
let prefab = MeshPool.Instance.getMeshPrefab(modelData.resPath, modelData.resName); |
||||
result = new MeshPoolInfo(modelData.resPath, modelData.resName, fromClone); |
||||
if (prefab == null) { |
||||
prefab = new MeshPoolInfo(modelData.resPath, modelData.resName, false); |
||||
prefab.onSuccessObserver = new Observable<MeshPoolInfo>(); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.prefabPool, prefab); |
||||
|
||||
SceneManager.createModel(modeltype, modelData, true, isNew, tag, (meshes: AbstractMesh[], box: AbstractMesh, modelInfo: ModelInfo) => { |
||||
prefab.meshes = meshes; |
||||
prefab.meshBox = box; |
||||
prefab.modelInfo = modelInfo; |
||||
prefab.setActive(false); |
||||
modelInfo.showFollowUI(false); |
||||
prefab.success(); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.prefabPool, prefab); |
||||
if (!onlyPrefab) { |
||||
if (fromClone) { |
||||
result.cloneMeshFrom(prefab, modelData, isNew); |
||||
result.setActive(true); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.workingPool, result); |
||||
result.success(); |
||||
if (onSuccess) { |
||||
onSuccess(result.meshBox, result.meshes, result); |
||||
} |
||||
} |
||||
else { |
||||
SceneManager.createModel(modeltype, modelData, true, isNew, tag, (meshes: AbstractMesh[], box: AbstractMesh, modelInfo: ModelInfo) => { |
||||
result.meshBox = box; |
||||
result.meshes = meshes; |
||||
result.modelInfo = modelInfo; |
||||
result.setActive(true); |
||||
modelInfo.showFollowUI(false); |
||||
result.success(); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.workingPool, result); |
||||
if (onSuccess) { |
||||
onSuccess(result.meshBox, result.meshes, result); |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
}) |
||||
return result; |
||||
|
||||
} |
||||
else { |
||||
if (fromClone) { |
||||
if (prefab.meshBox == null) { |
||||
// console.log("找到了预制体,但是还没加载完")
|
||||
prefab.onSuccessObserver.add((eventData: MeshPoolInfo) => { |
||||
// console.log("加载回调");
|
||||
result.cloneMeshFrom(prefab, modelData, isNew); |
||||
result.setActive(true); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.workingPool, result); |
||||
result.success(); |
||||
if (onSuccess) { |
||||
onSuccess(result.meshBox, result.meshes, result); |
||||
} |
||||
}) |
||||
return result; |
||||
} |
||||
else { |
||||
result.cloneMeshFrom(prefab, modelData, isNew); |
||||
result.setActive(true); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.workingPool, result); |
||||
result.success(); |
||||
if (onSuccess) { |
||||
onSuccess(result.meshBox, result.meshes, result); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
||||
else { |
||||
SceneManager.createModel(modeltype, modelData, true, isNew, tag, (meshes: AbstractMesh[], box: AbstractMesh, modelInfo: ModelInfo) => { |
||||
result.meshBox = box; |
||||
result.meshes = meshes; |
||||
result.modelInfo = modelInfo; |
||||
result.setActive(true); |
||||
modelInfo.showFollowUI(false); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.workingPool, result); |
||||
result.success(); |
||||
if (onSuccess) { |
||||
onSuccess(result.meshBox, result.meshes, result); |
||||
} |
||||
}) |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
// console.log("从对象池取出" + result.key);
|
||||
MeshPool.Instance.removePool(MeshPool.Instance.idlePool, result); |
||||
MeshPool.instance.addPool(MeshPool.Instance.workingPool, result); |
||||
result.setActive(true); |
||||
result.success(); |
||||
if (onSuccess && result.meshBox != null) { |
||||
onSuccess(result.meshBox, result.meshes, result); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 放回到对象池(从工作池放入空闲池) |
||||
* @param meshPoolInfo
|
||||
*/ |
||||
static disposeMesh(meshPoolInfo: MeshPoolInfo) { |
||||
MeshPool.Instance.removePool(MeshPool.Instance.workingPool, meshPoolInfo); |
||||
MeshPool.Instance.addPool(MeshPool.Instance.idlePool, meshPoolInfo); |
||||
meshPoolInfo.setActive(false); |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
//#region 内部方法
|
||||
|
||||
getMesh(path: string, name: string, fromClone: boolean = true): MeshPoolInfo { |
||||
let result: MeshPoolInfo = null; |
||||
let resKey = path + name; |
||||
|
||||
let poolList = MeshPool.Instance.idlePool.get(resKey); |
||||
|
||||
if (poolList != null && poolList.length > 0) { |
||||
for (let i = 0; i < poolList.length; i++) { |
||||
if (poolList[i].fromClone == fromClone) { |
||||
result = poolList[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
} |
||||
else { |
||||
//console.log("对象池取出失败" + name);
|
||||
} |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
//放入某池
|
||||
addPool(pool: Map<string, MeshPoolInfo[]>, value: MeshPoolInfo) { |
||||
let poolInfo = pool.get(value.key); |
||||
if (poolInfo == null) { |
||||
poolInfo = []; |
||||
pool.set(value.key, poolInfo); |
||||
} |
||||
poolInfo.push(value); |
||||
} |
||||
|
||||
//移除池
|
||||
removePool(pool: Map<string, MeshPoolInfo[]>, value: MeshPoolInfo) { |
||||
let poolInfo = pool.get(value.key); |
||||
if (poolInfo == null) { |
||||
console.error("removePool no key" + value.key); |
||||
return; |
||||
} |
||||
TsTool.arrayRemove(poolInfo, value); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 从预制体池中取出 |
||||
*/ |
||||
getMeshPrefab(path: string, name: string): MeshPoolInfo { |
||||
let result: MeshPoolInfo = null; |
||||
let resKey = path + name; |
||||
|
||||
let poolList = MeshPool.Instance.prefabPool.get(resKey); |
||||
if (poolList != null && poolList.length > 0) { |
||||
result = poolList[0]; |
||||
} |
||||
else { |
||||
|
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 对象池元数据 |
||||
*/ |
||||
export class MeshPoolInfo { |
||||
key: string; |
||||
resPath: string;//资源路径,
|
||||
resName: string; |
||||
meshBox: AbstractMesh;//对象
|
||||
fromClone: boolean;//来自克隆
|
||||
|
||||
meshes: AbstractMesh[];//所有mesh节点
|
||||
active: boolean; |
||||
modelInfo: ModelInfo; |
||||
|
||||
onSuccessObserver: Observable<MeshPoolInfo>; |
||||
|
||||
constructor(resPath: string, resName: string, fromClone: boolean = true, mesh?: AbstractMesh, meshes?: AbstractMesh[], modelInfo?: ModelInfo) { |
||||
this.key = resPath + resName; |
||||
this.resPath = resPath; |
||||
this.resName = resName; |
||||
this.fromClone = fromClone; |
||||
this.meshBox = mesh; |
||||
this.meshes = meshes; |
||||
this.modelInfo = modelInfo; |
||||
|
||||
} |
||||
|
||||
setActive(active: boolean) { |
||||
if (this.meshBox != null) { |
||||
|
||||
if (active) { |
||||
this.meshBox.setParent(null); |
||||
let allNode = this.meshBox.getChildTransformNodes(); |
||||
for (let i = 0; i < allNode.length; i++) { |
||||
allNode[i].setEnabled(true); |
||||
} |
||||
this.meshBox.setEnabled(true); |
||||
} |
||||
else { |
||||
|
||||
this.meshBox.setParent(MeshPool.Instance.root); |
||||
this.meshBox.position = Vector3.Zero(); |
||||
// this.meshBox.setEnabled(false);
|
||||
|
||||
// console.log("放入对象池" + this.meshBox.name);
|
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 导入完成 |
||||
*/ |
||||
success() { |
||||
if (this.onSuccessObserver != null) { |
||||
// console.log("导入完成", this.onSuccessObserver.observers);
|
||||
this.onSuccessObserver.notifyObservers(this); |
||||
this.onSuccessObserver.clear(); |
||||
} |
||||
|
||||
} |
||||
|
||||
clone() { |
||||
let modelInfo = this.modelInfo.clone(); |
||||
let newMesh = new MeshPoolInfo(this.resPath, this.resName, true, modelInfo.modelBox, modelInfo.models, modelInfo); |
||||
return newMesh; |
||||
} |
||||
|
||||
/** |
||||
* 从预制体克隆mesh |
||||
* @param prefab
|
||||
*/ |
||||
cloneMeshFrom(prefab: MeshPoolInfo, modelData?: ModelData, isNew: boolean = true) { |
||||
let modelInfo = prefab.modelInfo.clone(modelData, isNew); |
||||
this.meshBox = modelInfo.modelBox; |
||||
this.modelInfo = modelInfo; |
||||
// let box = MeshBuilder.CreateBox("box", { size: 1 }); //用于测试阴影
|
||||
// box.setParent(modelInfo.modelBox);
|
||||
// box.position = new Vector3(0, 2, 0);
|
||||
if (SceneManager.s_openShadow) { |
||||
SceneManager.Instance.shadowGenerator.addShadowCaster(modelInfo.modelBox, true); |
||||
// console.log("添加到阴影", modelInfo.modelBox.name);
|
||||
} |
||||
|
||||
} |
||||
|
||||
dispose() { |
||||
this.modelInfo.dispose(); |
||||
} |
||||
} |
||||
|
||||
|
@ -0,0 +1,262 @@
|
||||
import { ArcRotateCamera, CameraInputTypes, Nullable, PointerTouch, serialize } from "@babylonjs/core"; |
||||
import { BaseCameraPointersInput } from "@babylonjs/core/Cameras/Inputs/BaseCameraPointersInput"; |
||||
|
||||
|
||||
//修改为左键平移,右键旋转
|
||||
|
||||
export class MyArcRotateCameraPointersInput extends BaseCameraPointersInput { |
||||
/** |
||||
* Defines the camera the input is attached to. |
||||
*/ |
||||
public camera: ArcRotateCamera; |
||||
|
||||
/** |
||||
* Gets the class name of the current input. |
||||
* @returns the class name |
||||
*/ |
||||
public getClassName(): string { |
||||
return "MyArcRotateCameraPointersInput"; |
||||
} |
||||
|
||||
/** |
||||
* Defines the buttons associated with the input to handle camera move. |
||||
*/ |
||||
@serialize() |
||||
public buttons = [0, 1, 2]; |
||||
|
||||
/** |
||||
* Defines the pointer angular sensibility along the X axis or how fast is |
||||
* the camera rotating. |
||||
*/ |
||||
@serialize() |
||||
public angularSensibilityX = 1000.0; |
||||
|
||||
/** |
||||
* Defines the pointer angular sensibility along the Y axis or how fast is |
||||
* the camera rotating. |
||||
*/ |
||||
@serialize() |
||||
public angularSensibilityY = 1000.0; |
||||
|
||||
/** |
||||
* Defines the pointer pinch precision or how fast is the camera zooming. |
||||
*/ |
||||
@serialize() |
||||
public pinchPrecision = 12.0; |
||||
|
||||
/** |
||||
* pinchDeltaPercentage will be used instead of pinchPrecision if different |
||||
* from 0. |
||||
* It defines the percentage of current camera.radius to use as delta when |
||||
* pinch zoom is used. |
||||
*/ |
||||
@serialize() |
||||
public pinchDeltaPercentage = 0; |
||||
|
||||
/** |
||||
* When useNaturalPinchZoom is true, multi touch zoom will zoom in such |
||||
* that any object in the plane at the camera's target point will scale |
||||
* perfectly with finger motion. |
||||
* Overrides pinchDeltaPercentage and pinchPrecision. |
||||
*/ |
||||
@serialize() |
||||
public useNaturalPinchZoom: boolean = false; |
||||
|
||||
/** |
||||
* Defines whether zoom (2 fingers pinch) is enabled through multitouch |
||||
*/ |
||||
@serialize() |
||||
public pinchZoom: boolean = true; |
||||
|
||||
/** |
||||
* Defines the pointer panning sensibility or how fast is the camera moving. |
||||
*/ |
||||
@serialize() |
||||
public panningSensibility: number = 1000.0; |
||||
|
||||
/** |
||||
* Defines whether panning (2 fingers swipe) is enabled through multitouch. |
||||
*/ |
||||
@serialize() |
||||
public multiTouchPanning: boolean = true; |
||||
|
||||
/** |
||||
* Defines whether panning is enabled for both pan (2 fingers swipe) and |
||||
* zoom (pinch) through multitouch. |
||||
*/ |
||||
@serialize() |
||||
public multiTouchPanAndZoom: boolean = true; |
||||
|
||||
/** |
||||
* Revers pinch action direction. |
||||
*/ |
||||
public pinchInwards = true; |
||||
|
||||
private _isPanClick: boolean = false; |
||||
private _twoFingerActivityCount: number = 0; |
||||
private _isPinching: boolean = false; |
||||
|
||||
/** |
||||
* Move camera from multi touch panning positions. |
||||
*/ |
||||
private _computeMultiTouchPanning( |
||||
previousMultiTouchPanPosition: Nullable<PointerTouch>, |
||||
multiTouchPanPosition: Nullable<PointerTouch> |
||||
): void { |
||||
if (this.panningSensibility !== 0 && previousMultiTouchPanPosition |
||||
&& multiTouchPanPosition) { |
||||
var moveDeltaX = multiTouchPanPosition.x - previousMultiTouchPanPosition.x; |
||||
var moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y; |
||||
// this.camera.inertialPanningX += -moveDeltaX / this.panningSensibility;
|
||||
// this.camera.inertialPanningY += moveDeltaY / this.panningSensibility;
|
||||
// this.moveCamera(-moveDeltaX, moveDeltaY);
|
||||
this.rotateCamera(moveDeltaX, moveDeltaX); |
||||
} |
||||
|
||||
} |
||||
|
||||
moveCamera(x, y) { |
||||
this.camera.inertialPanningX += x / this.panningSensibility; |
||||
this.camera.inertialPanningY += y / this.panningSensibility; |
||||
} |
||||
|
||||
/** |
||||
* Move camera from pinch zoom distances. |
||||
*/ |
||||
private _computePinchZoom( |
||||
previousPinchSquaredDistance: number, |
||||
pinchSquaredDistance: number |
||||
): void { |
||||
if (this.useNaturalPinchZoom) { |
||||
this.camera.radius = this.camera.radius * |
||||
Math.sqrt(previousPinchSquaredDistance) / Math.sqrt(pinchSquaredDistance); |
||||
} else if (this.pinchDeltaPercentage) { |
||||
this.camera.inertialRadiusOffset += |
||||
(pinchSquaredDistance - previousPinchSquaredDistance) * 0.001 * |
||||
this.camera.radius * this.pinchDeltaPercentage; |
||||
} |
||||
else { |
||||
this.camera.inertialRadiusOffset += |
||||
(pinchSquaredDistance - previousPinchSquaredDistance) / |
||||
(this.pinchPrecision * (this.pinchInwards ? 1 : -1) * |
||||
(this.angularSensibilityX + this.angularSensibilityY) / 2); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Called on pointer POINTERMOVE event if only a single touch is active. |
||||
*/ |
||||
protected onTouch(point: Nullable<PointerTouch>, |
||||
offsetX: number, |
||||
offsetY: number): void { |
||||
if (this.panningSensibility !== 0 && |
||||
((this._ctrlKey && this.camera._useCtrlForPanning) || this._isPanClick)) { |
||||
// this.camera.inertialPanningX += -offsetX / this.panningSensibility;
|
||||
// this.camera.inertialPanningY += offsetY / this.panningSensibility;
|
||||
|
||||
this.rotateCamera(offsetX, offsetY); |
||||
} else { |
||||
this.moveCamera(-offsetX, offsetY); |
||||
// this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
|
||||
// this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY;
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
rotateCamera(offsetX, offsetY) { |
||||
this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX; |
||||
this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY; |
||||
} |
||||
|
||||
/** |
||||
* Called on pointer POINTERDOUBLETAP event. |
||||
*/ |
||||
protected onDoubleTap(type: string) { |
||||
if (this.camera.useInputToRestoreState) { |
||||
this.camera.restoreState(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Called on pointer POINTERMOVE event if multiple touches are active. |
||||
*/ |
||||
protected onMultiTouch(pointA: Nullable<PointerTouch>, |
||||
pointB: Nullable<PointerTouch>, |
||||
previousPinchSquaredDistance: number, |
||||
pinchSquaredDistance: number, |
||||
previousMultiTouchPanPosition: Nullable<PointerTouch>, |
||||
multiTouchPanPosition: Nullable<PointerTouch>): void { |
||||
if (previousPinchSquaredDistance === 0 && previousMultiTouchPanPosition === null) { |
||||
// First time this method is called for new pinch.
|
||||
// Next time this is called there will be a
|
||||
// previousPinchSquaredDistance and pinchSquaredDistance to compare.
|
||||
return; |
||||
} |
||||
if (pinchSquaredDistance === 0 && multiTouchPanPosition === null) { |
||||
// Last time this method is called at the end of a pinch.
|
||||
return; |
||||
} |
||||
// Zoom and panning enabled together
|
||||
if (this.multiTouchPanAndZoom) { |
||||
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance); |
||||
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition); |
||||
|
||||
// Zoom and panning enabled but only one at a time
|
||||
} else if (this.multiTouchPanning && this.pinchZoom) { |
||||
this._twoFingerActivityCount++; |
||||
|
||||
if (this._isPinching || (this._twoFingerActivityCount < 20 |
||||
&& Math.abs(Math.sqrt(pinchSquaredDistance) - Math.sqrt(previousPinchSquaredDistance)) > |
||||
this.camera.pinchToPanMaxDistance)) { |
||||
|
||||
// Since pinch has not been active long, assume we intend to zoom.
|
||||
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance); |
||||
|
||||
// Since we are pinching, remain pinching on next iteration.
|
||||
this._isPinching = true; |
||||
} else { |
||||
// Pause between pinch starting and moving implies not a zoom event. Pan instead.
|
||||
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition); |
||||
} |
||||
|
||||
// Panning enabled, zoom disabled
|
||||
} else if (this.multiTouchPanning) { |
||||
this._computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition); |
||||
|
||||
// Zoom enabled, panning disabled
|
||||
} else if (this.pinchZoom) { |
||||
this._computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Called each time a new POINTERDOWN event occurs. Ie, for each button |
||||
* press. |
||||
*/ |
||||
protected onButtonDown(evt: PointerEvent): void { |
||||
this._isPanClick = evt.button === this.camera._panningMouseButton; |
||||
} |
||||
|
||||
/** |
||||
* Called each time a new POINTERUP event occurs. Ie, for each button |
||||
* release. |
||||
*/ |
||||
protected onButtonUp(evt: PointerEvent): void { |
||||
this._twoFingerActivityCount = 0; |
||||
this._isPinching = false; |
||||
} |
||||
|
||||
/** |
||||
* Called when window becomes inactive. |
||||
*/ |
||||
protected onLostFocus(): void { |
||||
|
||||
// console.trace("失去焦点")
|
||||
this._isPanClick = false; |
||||
this._twoFingerActivityCount = 0; |
||||
this._isPinching = false; |
||||
} |
||||
} |
||||
(<any>CameraInputTypes)["MyArcRotateCameraPointersInput"] = |
||||
MyArcRotateCameraPointersInput; |
@ -0,0 +1,113 @@
|
||||
import { ParticleHelper, ParticleSystem, ParticleSystemSet, Scene, Vector3 } from "@babylonjs/core"; |
||||
|
||||
|
||||
/** |
||||
* 粒子特效工具 |
||||
*/ |
||||
export class ParticleSystemTool { |
||||
|
||||
/** |
||||
* 保存的预制 |
||||
*/ |
||||
psPool: Map<string, ParticleSystem>; |
||||
|
||||
scene: Scene; |
||||
|
||||
constructor(scene: Scene) { |
||||
this.scene = scene; |
||||
this.psPool = new Map(); |
||||
} |
||||
|
||||
static instance: ParticleSystemTool; |
||||
|
||||
static Init(scene: Scene) { |
||||
ParticleSystemTool.instance = new ParticleSystemTool(scene); |
||||
|
||||
|
||||
} |
||||
|
||||
static dispose() { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 加载预制 |
||||
* @param name
|
||||
* @param path
|
||||
* @param onSuccess
|
||||
*/ |
||||
loadPrefab(name: string, path: string, clone: boolean = true, onSuccess?: (ps: ParticleSystem) => void) { |
||||
let instance = this; |
||||
ParticleHelper.ParseFromFileAsync(null, path, this.scene, false).then((value: ParticleSystem) => { |
||||
value.stop(); |
||||
instance.psPool.set(path, value); |
||||
if (clone) { |
||||
let result = instance.cloneParticle(value, name); |
||||
if (onSuccess) { |
||||
onSuccess(result) |
||||
} |
||||
} |
||||
else { |
||||
if (onSuccess) { |
||||
onSuccess(value) |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 异步导入粒子特效 |
||||
* @param path
|
||||
* @param onSuccess
|
||||
*/ |
||||
importParticle(name: string, path: string, onSuccess: (ps: ParticleSystem) => void) { |
||||
let instance = this; |
||||
if (instance.psPool.has(path)) { |
||||
let set = instance.psPool.get(path); |
||||
let result = instance.cloneParticle(set, name); |
||||
onSuccess(result); |
||||
} |
||||
else { |
||||
|
||||
instance.loadPrefab(null, path, true, (value: ParticleSystem) => { |
||||
onSuccess(value); |
||||
}) |
||||
|
||||
// ParticleHelper.ParseFromFileAsync(null, path, this.scene, false).then((value: ParticleSystem) => {
|
||||
// instance.psPool.set(path, value);
|
||||
// let result = instance.cloneParticle(value, name);
|
||||
// onSuccess(result)
|
||||
// });
|
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 克隆粒子系统 |
||||
* @param setPrefab
|
||||
* @param name
|
||||
*/ |
||||
cloneParticleSet(setPrefab: ParticleSystemSet, name: string) { |
||||
let result = new ParticleSystemSet(); |
||||
for (let i = 0; i < setPrefab.systems.length; i++) { |
||||
result.systems.push(this.cloneParticle(setPrefab.systems[i] as ParticleSystem, name)); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 粒子 |
||||
* @param particle
|
||||
* @param name
|
||||
*/ |
||||
cloneParticle(particle: ParticleSystem, name: string) { |
||||
// let root = new AbstractMesh("root_" + name, this.scene);
|
||||
let root = Vector3.Zero(); |
||||
let result = particle.clone(particle.name, root); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,112 @@
|
||||
import { ArcRotateCamera, Color3, Color4, Database, Engine, EngineStore, PhotoDome, Scene, Vector3 } from "@babylonjs/core"; |
||||
import { TextBlock } from "@babylonjs/gui"; |
||||
import { AdvancedDynamicTexture } from "@babylonjs/gui/2D/advancedDynamicTexture"; |
||||
|
||||
/** |
||||
* 360全景图工具 |
||||
*/ |
||||
export class Photo360Tool { |
||||
|
||||
static instance: Photo360Tool; |
||||
|
||||
canvas: HTMLCanvasElement; |
||||
engine: Engine; |
||||
scene: Scene; |
||||
|
||||
photo: PhotoDome; |
||||
loadingTxt: TextBlock; |
||||
|
||||
|
||||
/** |
||||
* 开启全景图,创建 |
||||
* @param canvas
|
||||
* @param photoURL
|
||||
*/ |
||||
static open(canvas: HTMLCanvasElement, photoURL: string) { |
||||
if (Photo360Tool.instance == null) { |
||||
Photo360Tool.instance = new Photo360Tool(); |
||||
let instance = Photo360Tool.instance; |
||||
instance.canvas = canvas; |
||||
instance.engine = new Engine(canvas, null, { stencil: true }); |
||||
instance.scene = new Scene(instance.engine, { virtual: true }); // virtual确保默认场景为主场景,而不是新创建的这个
|
||||
instance.scene.useRightHandedSystem = true;//使用右手坐标系
|
||||
instance.scene.clearColor = new Color4(0, 0, 0, 1); |
||||
//instance.initUI();
|
||||
//最后,将场景渲染出来 (重要,不可缺少)
|
||||
instance.engine.runRenderLoop(function () { |
||||
if (instance.scene != null) { |
||||
instance.scene.render(); |
||||
} |
||||
}) |
||||
|
||||
// 监听浏览器改变大小的事件,通过调用engine.resize()来自适应窗口大小
|
||||
window.addEventListener("resize", function () { |
||||
if (instance != null && instance.engine != null) { |
||||
instance.engine.resize(); |
||||
} |
||||
}); |
||||
|
||||
let camera = new ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 5, Vector3.Zero(), Photo360Tool.instance.scene); |
||||
camera.attachControl(canvas, true); |
||||
camera.inputs.attached.mousewheel.detachControl(); |
||||
} |
||||
else { |
||||
console.error("重复开启全景图"); |
||||
} |
||||
|
||||
//确保默认场景为主场景,而不是新创建的这个. 替换为virtual: true 设置。
|
||||
// EngineStore._LastCreatedScene = SceneManager.Instance.scene;
|
||||
|
||||
Photo360Tool.instance.changePhoto(photoURL); |
||||
} |
||||
|
||||
static close() { |
||||
if (Photo360Tool.instance != null) { |
||||
Photo360Tool.instance.disposePhoto(); |
||||
Photo360Tool.instance = null; |
||||
} |
||||
} |
||||
|
||||
|
||||
initUI() { |
||||
let rootUI = AdvancedDynamicTexture.CreateFullscreenUI("UIRoot", undefined, this.scene);//UtilityLayerRenderer.DefaultUtilityLayer.utilityLayerScene
|
||||
|
||||
this.loadingTxt = new TextBlock("loading", "加载中..."); |
||||
rootUI.addControl(this.loadingTxt); |
||||
this.loadingTxt.fontSize = "30px"; |
||||
this.loadingTxt.color = "white"; |
||||
this.loadingTxt.width = "200px"; |
||||
this.loadingTxt.height = "100px"; |
||||
|
||||
// this.scene.debugLayer.show();
|
||||
} |
||||
|
||||
changePhoto(photoURL: string) { |
||||
if (this.photo != null) { |
||||
this.photo.dispose(); |
||||
} |
||||
Photo360Tool.instance.photo = new PhotoDome( |
||||
"testdome", |
||||
photoURL, |
||||
{ |
||||
resolution: 32, |
||||
size: 1000 |
||||
}, |
||||
Photo360Tool.instance.scene |
||||
); |
||||
|
||||
|
||||
} |
||||
|
||||
disposePhoto() { |
||||
if (this.photo != null) { |
||||
this.photo.dispose(); |
||||
} |
||||
|
||||
this.scene.dispose(); |
||||
this.scene = null; |
||||
this.engine.dispose(); |
||||
this.engine = null; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,112 @@
|
||||
import { Mesh, Vector3 } from "@babylonjs/core"; |
||||
import { Button, Rectangle, StackPanel } from "@babylonjs/gui"; |
||||
import { SceneManager } from "../controller/scene-manager"; |
||||
import { UIManager } from "../controller/ui-manager"; |
||||
import { BabylonUIStyleTool } from "./babylon-ui-style-tool"; |
||||
import { GizmoTool } from "./gizmo-tool"; |
||||
|
||||
export class PosPointTool { |
||||
|
||||
static readonly c_key = "PosPoint"; |
||||
static instance: PosPointTool; |
||||
|
||||
mesh: Mesh; |
||||
pos: Vector3; |
||||
|
||||
uiRoot: Rectangle; |
||||
|
||||
//#region UI
|
||||
initUI() { |
||||
let instance = this; |
||||
this.uiRoot = new Rectangle("PosPointTooUI"); |
||||
UIManager.Instance.uiRoot.addControl(this.uiRoot); |
||||
|
||||
BabylonUIStyleTool.setStyle_size(this.uiRoot, "40px", "20px"); |
||||
|
||||
let stack = new StackPanel("stack"); |
||||
this.uiRoot.addControl(stack); |
||||
stack.isVertical = false; |
||||
|
||||
let btn_add = Button.CreateSimpleButton("add", "+"); |
||||
stack.addControl(btn_add); |
||||
btn_add.background = BabylonUIStyleTool.c_color_blue; |
||||
btn_add.color = "white"; |
||||
btn_add.thickness = 0; |
||||
btn_add.onPointerClickObservable.add(() => { |
||||
instance.btn_add(); |
||||
}); |
||||
BabylonUIStyleTool.setStyle_size(btn_add, "20px", "20px"); |
||||
|
||||
let btn_reduce = Button.CreateSimpleButton("reduce", "-"); |
||||
stack.addControl(btn_reduce); |
||||
btn_reduce.background = BabylonUIStyleTool.c_color_red; |
||||
btn_reduce.color = "white"; |
||||
btn_reduce.thickness = 0; |
||||
btn_reduce.onPointerClickObservable.add(() => { |
||||
instance.btn_reduce(); |
||||
}); |
||||
BabylonUIStyleTool.setStyle_size(btn_reduce, "20px", "20px"); |
||||
|
||||
} |
||||
|
||||
showUI(show: boolean) { |
||||
this.uiRoot.isVisible = show; |
||||
this.uiRoot.linkWithMesh(this.mesh); |
||||
this.uiRoot.linkOffsetY = "-50px"; |
||||
} |
||||
//#endregion
|
||||
|
||||
static get Instance() { |
||||
if (PosPointTool.instance == null) { |
||||
PosPointTool.instance = new PosPointTool(); |
||||
PosPointTool.instance.initUI(); |
||||
SceneManager.Instance.scene.onBeforeRenderObservable.add(PosPointTool.onUpdate); |
||||
GizmoTool.onGizmoAimMeshObservable.add((mesh) => { |
||||
if (mesh == null || !mesh.name.match(PosPointTool.c_key)) { |
||||
PosPointTool.attachMesh(null); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
return PosPointTool.instance; |
||||
|
||||
} |
||||
|
||||
onAdd: () => void; |
||||
onReduce: () => void; |
||||
|
||||
static attachMesh(mesh: Mesh, pos?: Vector3, onAdd?: () => void, onReduce?: () => void) { |
||||
|
||||
|
||||
|
||||
PosPointTool.Instance.mesh = mesh; |
||||
PosPointTool.Instance.pos = pos; |
||||
PosPointTool.Instance.showUI(mesh != null); |
||||
|
||||
PosPointTool.Instance.onAdd = onAdd; |
||||
PosPointTool.Instance.onReduce = onReduce; |
||||
} |
||||
|
||||
|
||||
static onUpdate() { |
||||
if (PosPointTool.Instance.mesh != null) { |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
//添加
|
||||
btn_add() { |
||||
if (this.onAdd) { |
||||
this.onAdd(); |
||||
} |
||||
} |
||||
|
||||
//减少
|
||||
btn_reduce() { |
||||
if (this.onReduce) { |
||||
this.onReduce(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,26 @@
|
||||
export class TsTool { |
||||
//在数组中移除目标(不留空位)
|
||||
static arrayRemove(array: any[], remove: any): boolean { |
||||
let index = array.indexOf(remove, 0); |
||||
if (index > -1) { |
||||
array.splice(index, 1); |
||||
return true; |
||||
} |
||||
else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
//判断字符串source中是否包含某字符串aim
|
||||
static stringContain(source: string, aim: string): boolean { |
||||
let result = source.indexOf(aim) != -1; |
||||
return result; |
||||
} |
||||
|
||||
//打印调用堆栈
|
||||
static trace() { |
||||
console.trace(); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,351 @@
|
||||
// import { Checkbox, Control, InputText, RadioButton, Rectangle, StackPanel, TextBlock } from "@babylonjs/gui";
|
||||
// import { DataManager, ModelChangeType } from "src/babylon/controller/data-manager";
|
||||
// import { Event_ModelInfoChange } from "src/babylon/controller/event-manager/events/event-modelinfo-change";
|
||||
// import { ServeManager } from "src/babylon/controller/serve-manager";
|
||||
// import { UIManager } from "src/babylon/controller/ui-manager";
|
||||
// import { BuildingData, BuildingType } from "src/babylon/model/data/institution/building/building-data";
|
||||
// import { BuildingPosType, ModelData } from "src/babylon/model/data/model-data/model-data";
|
||||
// import { ModelEditData } from "src/babylon/model/data/model-data/model-edit-data";
|
||||
// import { BuildingInfo } from "src/babylon/model/info/building/building-info";
|
||||
// import { ModelInfo_facility } from "src/babylon/model/info/model/model-info-facility";
|
||||
// import { BabylonUIStyleTool } from "src/babylon/tool/babylon-ui-style-tool";
|
||||
// import { TsTool } from "src/babylon/tool/ts-tool";
|
||||
// import { UIBase } from "../window-base/ui-base";
|
||||
// import { BuildingUIItem } from "./building-ui-item";
|
||||
// import { BuildingWindow } from "./building-window";
|
||||
|
||||
// //创建建筑物界面
|
||||
// export class BuildingCreateWindow extends UIBase {
|
||||
|
||||
// buildingWindow: BuildingWindow;
|
||||
// buildingData: BuildingData;
|
||||
|
||||
// buildingUIItem: BuildingUIItem;
|
||||
// isChangeType: boolean;//是修改模式
|
||||
|
||||
// needUpdateModel: boolean;//需要更新模型
|
||||
|
||||
// newName: string;
|
||||
|
||||
|
||||
// onInit() {
|
||||
// super.onInit();
|
||||
|
||||
// }
|
||||
|
||||
// onOpen() {
|
||||
// super.onOpen();
|
||||
// }
|
||||
|
||||
// onClose() {
|
||||
// super.onClose();
|
||||
// }
|
||||
|
||||
// initUI() {
|
||||
// let window = this;
|
||||
// let isChangeType = this.isChangeType;
|
||||
|
||||
// let outDoorData: ModelEditData = null;
|
||||
// if (isChangeType) {
|
||||
// this.buildingData = this.buildingUIItem.buildingInfo.buildingData;
|
||||
// outDoorData = this.buildingUIItem.buildingInfo.buildingData.outdoorData;
|
||||
// if (outDoorData == null) {
|
||||
// this.buildingUIItem.buildingInfo.buildingData.outdoorData = new ModelEditData();
|
||||
// outDoorData = this.buildingUIItem.buildingInfo.buildingData.outdoorData;
|
||||
// outDoorData.modelData = new ModelData("model0", "空模型", null, null, null);
|
||||
// }
|
||||
|
||||
// }
|
||||
// else {
|
||||
// this.buildingData = DataManager.createBulding("请输入", "key", BuildingType.Normal);
|
||||
// outDoorData = this.buildingData.outdoorData;
|
||||
// }
|
||||
|
||||
|
||||
// this.root = new Rectangle("BuildingCreateWindow")
|
||||
// UIManager.Instance.uiRoot.addControl(this.root);
|
||||
|
||||
// BabylonUIStyleTool.setDefaultStyle_windowRoot(this.root, true);
|
||||
// BabylonUIStyleTool.setStyle_size(this.root, "300px", "482px");
|
||||
|
||||
// let stackPanel = new StackPanel("Root");
|
||||
// BabylonUIStyleTool.setStyle_size(stackPanel, "250px", "440px");
|
||||
// this.root.addControl(stackPanel);
|
||||
// stackPanel.isVertical = true;
|
||||
|
||||
// let titleValue = isChangeType ? "修改建筑" : "新建建筑";
|
||||
|
||||
// let title = new TextBlock("title", titleValue);
|
||||
// BabylonUIStyleTool.setStyle_size(title, "220px", "36px");
|
||||
// stackPanel.addControl(title);
|
||||
// title.color = "black";
|
||||
|
||||
// let name = new TextBlock("name", "名称");
|
||||
// BabylonUIStyleTool.setStyle_size(name, "220px", "16px");
|
||||
// name.fontSize = "16px";
|
||||
// name.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// stackPanel.addControl(name);
|
||||
// name.color = "black";
|
||||
|
||||
// let space = new Rectangle("space");
|
||||
// BabylonUIStyleTool.setStyle_size(space, "220px", "2px");
|
||||
// stackPanel.addControl(space);
|
||||
|
||||
// let nameInput = BabylonUIStyleTool.createInputText("nameInput", stackPanel, "220px", "20px", "black", 0, undefined, BabylonUIStyleTool.c_color_gray, "black", BabylonUIStyleTool.c_color_gray);
|
||||
// nameInput.inputText.onTextChangedObservable.add(() => {
|
||||
// this.newName = nameInput.inputText.text;
|
||||
// })
|
||||
|
||||
// let key = new TextBlock("key", "key");
|
||||
// BabylonUIStyleTool.setStyle_size(key, "220px", "16px");
|
||||
// key.fontSize = "16px";
|
||||
// key.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// stackPanel.addControl(key);
|
||||
// key.color = "black";
|
||||
|
||||
// let keyInput = BabylonUIStyleTool.createInputText("keyInput", stackPanel, "220px", "20px", "black", 0, undefined, BabylonUIStyleTool.c_color_gray, "black", BabylonUIStyleTool.c_color_gray);
|
||||
// keyInput.inputText.text = window.isChangeType ? window.buildingData.normalData.key : "defalult";
|
||||
// keyInput.inputText.onTextChangedObservable.add(() => {
|
||||
// this.buildingData.normalData.key = keyInput.inputText.text;
|
||||
// })
|
||||
|
||||
|
||||
|
||||
// let space2 = new Rectangle("space2");
|
||||
// BabylonUIStyleTool.setStyle_size(space2, "220px", "20px");
|
||||
// stackPanel.addControl(space2);
|
||||
|
||||
// if (!isChangeType) {
|
||||
// let type = new TextBlock("type", "建筑类型");
|
||||
// BabylonUIStyleTool.setStyle_size(type, "220px", "36px");
|
||||
// type.color = "black";
|
||||
// type.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// stackPanel.addControl(type);
|
||||
|
||||
// let group = "buildingType";
|
||||
// let normalBuilding = BabylonUIStyleTool.createRadioButton("normalBuilding", stackPanel, group, "200px", "20px", BabylonUIStyleTool.c_color_blue, BabylonUIStyleTool.c_color_gray, "普通建筑", "150px", true, (select) => {
|
||||
// if (select) {
|
||||
// window.onSelectType(BuildingType.Normal);
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
// let space3 = new Rectangle("space3");
|
||||
// BabylonUIStyleTool.setStyle_size(space3, "220px", "10px");
|
||||
// stackPanel.addControl(space3);
|
||||
|
||||
// let environment = BabylonUIStyleTool.createRadioButton("environment", stackPanel, group, "200px", "20px", BabylonUIStyleTool.c_color_blue, BabylonUIStyleTool.c_color_gray, "环境", "150px", false, (select) => {
|
||||
// if (select) {
|
||||
// window.onSelectType(BuildingType.Environment);
|
||||
// }
|
||||
|
||||
// });
|
||||
// }
|
||||
|
||||
// nameInput.inputText.text = window.buildingData.normalData.name;
|
||||
// let buildingTitle = new TextBlock("buildingTitle", "模型:");
|
||||
// buildingTitle.color = "black";
|
||||
// BabylonUIStyleTool.setStyle_size(buildingTitle, "220px", "20px");
|
||||
// buildingTitle.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// stackPanel.addControl(buildingTitle);
|
||||
|
||||
// let nowBuilding_name = new TextBlock("nowBuildingName", "模型名");
|
||||
// nowBuilding_name.fontSize = "16px";
|
||||
// nowBuilding_name.color = "black";
|
||||
// nowBuilding_name.alpha = 0.8;
|
||||
// BabylonUIStyleTool.setStyle_size(nowBuilding_name, "220px", "20px");
|
||||
// nowBuilding_name.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// stackPanel.addControl(nowBuilding_name);
|
||||
|
||||
// let input_buildingName = BabylonUIStyleTool.createInputText("input_buildingName", stackPanel, "220px", "18px");
|
||||
// input_buildingName.inputText.fontSize = "16px";
|
||||
// input_buildingName.bg.paddingLeft = "20px";
|
||||
// input_buildingName.inputText.text = "-空";
|
||||
// if (isChangeType && outDoorData.modelData != null && outDoorData.modelData.name != null) {
|
||||
// input_buildingName.inputText.text = outDoorData.modelData.name;
|
||||
// }
|
||||
// input_buildingName.inputText.onTextChangedObservable.add(() => {
|
||||
// outDoorData.modelData.name = input_buildingName.inputText.text;
|
||||
// });
|
||||
|
||||
|
||||
// let nowBuilding_key = new TextBlock("nowBuildingKey", "文件名");
|
||||
// BabylonUIStyleTool.setStyle_size(nowBuilding_key, "220px", "20px");
|
||||
// nowBuilding_key.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// nowBuilding_key.color = "black";
|
||||
// nowBuilding_key.fontSize = "16px";
|
||||
// stackPanel.addControl(nowBuilding_key);
|
||||
|
||||
// let txt_buildingKey = BabylonUIStyleTool.createInputText("txt_buildingKey", stackPanel, "220px", "20px", undefined, 0, undefined, undefined, undefined, undefined);
|
||||
|
||||
// txt_buildingKey.bg.paddingLeft = "20px";
|
||||
// txt_buildingKey.inputText.fontSize = "16px";
|
||||
// if (isChangeType && outDoorData.modelData.key != null) {
|
||||
// txt_buildingKey.inputText.text = outDoorData.modelData.key;
|
||||
// }
|
||||
// txt_buildingKey.inputText.onTextChangedObservable.add(() => {
|
||||
// window.buildingData.outdoorData.modelData.key = txt_buildingKey.inputText.text;
|
||||
// })
|
||||
|
||||
// let btn_changeModel = BabylonUIStyleTool.createBtn_OK("btn_createModel", "修改模型", "200px", "30px", "18px");
|
||||
// btn_changeModel.onPointerClickObservable.add(() => {
|
||||
// window.onChangeModel();
|
||||
// })
|
||||
// stackPanel.addControl(btn_changeModel);
|
||||
|
||||
|
||||
|
||||
|
||||
// let space5 = new Rectangle("space5");
|
||||
// BabylonUIStyleTool.setStyle_size(space5, "220px", "40px");
|
||||
// stackPanel.addControl(space5);
|
||||
|
||||
// let btns = new StackPanel("btns");
|
||||
// BabylonUIStyleTool.setStyle_size(btns, "220px", "40px");
|
||||
// btns.isVertical = false;
|
||||
// stackPanel.addControl(btns);
|
||||
|
||||
// let btn_OK = BabylonUIStyleTool.createBtn_OK("OK", "确定", "100px", "36px", "18px");
|
||||
// btns.addControl(btn_OK);
|
||||
// btn_OK.onPointerClickObservable.add(() => {
|
||||
// window.onOK();
|
||||
// })
|
||||
|
||||
// let space4 = new Rectangle("space4");
|
||||
// BabylonUIStyleTool.setStyle_size(space4, "20px", "36px");
|
||||
// btns.addControl(space4);
|
||||
|
||||
// let btn_cancle = BabylonUIStyleTool.createBtn_Cancel("cancel", "取消", "100px", "36px", "18px");
|
||||
// btns.addControl(btn_cancle);
|
||||
// btn_cancle.onPointerClickObservable.add(() => {
|
||||
// window.onCancel();
|
||||
// });
|
||||
|
||||
// if (this.isChangeType) {
|
||||
// let btn_delete = BabylonUIStyleTool.createBtn_Delete("delete", "删", "30px", "30px", "18px");
|
||||
// this.root.addControl(btn_delete);
|
||||
// btn_delete.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// btn_delete.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
|
||||
// btn_delete.onPointerClickObservable.add(() => {
|
||||
// window.onBtn_delete();
|
||||
// })
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// //初始化新建
|
||||
// init(buildingWindow: BuildingWindow) {
|
||||
// this.buildingWindow = buildingWindow;
|
||||
// this.isChangeType = false;
|
||||
// this.initUI();
|
||||
// }
|
||||
|
||||
// //初始化修改
|
||||
// initChange(buildingWindow: BuildingWindow, buildingUIItem: BuildingUIItem) {
|
||||
// this.buildingUIItem = buildingUIItem;
|
||||
// this.buildingWindow = buildingWindow;
|
||||
// this.isChangeType = true;
|
||||
// this.initUI();
|
||||
// }
|
||||
|
||||
// //选择建筑类型
|
||||
// onSelectType(buildingType: BuildingType) {
|
||||
|
||||
// this.buildingData.buildingType = buildingType;
|
||||
// // this.key = DataManager.institutionData.getNewKey(buildingType);
|
||||
// console.log("选择建筑类型" + buildingType + "key =" + this.buildingData.normalData.key);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// //修改模型
|
||||
// onChangeModel() {
|
||||
// console.log("修改模型");
|
||||
|
||||
// let normalData = this.buildingData.normalData;
|
||||
// let resPath_out = DataManager.getResPath_building(
|
||||
// DataManager.institutionData.normalData.key.toLowerCase(),
|
||||
// normalData.key.toLocaleLowerCase(),
|
||||
// BuildingPosType.OutDoor,
|
||||
// this.buildingData.outdoorData.modelData.key
|
||||
// );
|
||||
// console.log("新资源路径" + resPath_out);
|
||||
// let instance = this;
|
||||
// ServeManager.instance.openFileSelect(resPath_out, (name: string, path: string) => {
|
||||
// if (TsTool.stringContain(name, ".gltf")) {
|
||||
// this.buildingData.outdoorData.modelData.resName = name;
|
||||
// this.buildingData.outdoorData.modelData.resPath = path;
|
||||
// }
|
||||
// instance.needUpdateModel = true;
|
||||
|
||||
// });
|
||||
// }
|
||||
|
||||
// //确定
|
||||
// onOK() {
|
||||
|
||||
// if (this.buildingData.normalData.name == null) {
|
||||
// alert("请输入名称");
|
||||
// }
|
||||
|
||||
// else {
|
||||
// console.log("修改模式" + this.isChangeType);
|
||||
// if (this.isChangeType) {
|
||||
// // let normalData = this.buildingUIItem.buildingInfo.buildingData.normalData;
|
||||
// // normalData.name = this.buildingData.normalData.name;
|
||||
// this.buildingUIItem.changeName(this.newName);
|
||||
// // this.buildingUIItem.updateUI();
|
||||
// Event_ModelInfoChange.dispatch(this.buildingUIItem.buildingInfo.ModelInfo, ModelChangeType.Update);
|
||||
// this.closeWindow();
|
||||
// }
|
||||
// else {
|
||||
// if (this.buildingData.buildingType == null) {
|
||||
// alert("请选择建筑类型")
|
||||
// }
|
||||
// else {
|
||||
// let result = this.buildingData;
|
||||
// this.buildingData.normalData.name = this.newName;
|
||||
|
||||
// if (result != null) {
|
||||
// this.closeWindow();
|
||||
// console.log("=======addOneBuilding");
|
||||
// console.log(result);
|
||||
// this.buildingWindow.addOneBuilding(result, -1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// //取消
|
||||
// onCancel() {
|
||||
// this.closeWindow();
|
||||
|
||||
// }
|
||||
|
||||
// //删除
|
||||
// onBtn_delete() {
|
||||
|
||||
// this.buildingWindow.deleteBuilding(this.buildingUIItem);
|
||||
// this.closeWindow();
|
||||
// }
|
||||
|
||||
// //关闭界面
|
||||
// closeWindow() {
|
||||
|
||||
// if (this.isChangeType) {
|
||||
// this.buildingUIItem.closeChangeWindow();
|
||||
|
||||
// console.log("需要修改模型" + this.needUpdateModel);
|
||||
// if (this.needUpdateModel) {
|
||||
// this.buildingUIItem.buildingWindow.updateBuildingModel(this.buildingUIItem.buildingInfo, true);
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// this.buildingWindow.closeCreateWindow();
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
@ -0,0 +1,212 @@
|
||||
|
||||
|
||||
import { SceneManager } from "../../controller/scene-manager"; |
||||
import { IndoorStatus } from "../../controller/status/indoor-status"; |
||||
import { StatusManager } from "../../controller/status/status-manager"; |
||||
import { BuildingType, BuildingData_Normal } from "../../model/data/institution/building/building-data"; |
||||
import { ModelEditData } from "../../model/data/model-data/model-edit-data"; |
||||
import { BuildingInfo } from "../../model/info/building/building-info"; |
||||
import { ModelInfo_building } from "../../model/info/model/model-info-building"; |
||||
import { BabylonTool } from "../../tool/babylon-tool"; |
||||
import { GizmoTool } from "../../tool/gizmo-tool"; |
||||
import { MarkWindow } from "../mark-window/mark-window"; |
||||
// import { BuildingCreateWindow } from "./building-create-window";
|
||||
import { BuildingWindow } from "./building-window"; |
||||
|
||||
//建筑UI Item
|
||||
export class BuildingUIItem { |
||||
buildingInfo: BuildingInfo; |
||||
buildingWindow: BuildingWindow; |
||||
|
||||
|
||||
constructor(buildingInfo: BuildingInfo, buildingWindow: BuildingWindow) { |
||||
|
||||
this.buildingWindow = buildingWindow; |
||||
this.buildingInfo = buildingInfo; |
||||
|
||||
} |
||||
|
||||
dispose() { |
||||
|
||||
this.buildingInfo.dispose(); |
||||
} |
||||
|
||||
//#region 前端对接
|
||||
|
||||
/** |
||||
* 获取建筑ID |
||||
*/ |
||||
getBuildingID(): string { |
||||
return this.buildingInfo.buildingData.normalData.key; |
||||
} |
||||
|
||||
/** |
||||
* 获取建筑显示的名称 |
||||
*/ |
||||
getBuildingName(): string { |
||||
return this.buildingInfo.buildingData.normalData.name; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 修改建筑名称 |
||||
*/ |
||||
setBuildingName(newName: string) { |
||||
this.changeName(newName); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取建筑类型 |
||||
*/ |
||||
getBuildingType(): BuildingType { |
||||
return this.buildingInfo.buildingData.buildingType; |
||||
} |
||||
|
||||
/** |
||||
* 获取室内数据 (null ,表示没有室内) |
||||
*/ |
||||
getAllIndoorData(): ModelEditData[] { |
||||
if (this.buildingInfo.buildingData instanceof BuildingData_Normal) { |
||||
let buildingData: BuildingData_Normal = this.buildingInfo.buildingData as BuildingData_Normal; |
||||
|
||||
let result = buildingData.indoorsData; |
||||
return result; |
||||
} |
||||
else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 进入室内 |
||||
* 来自ui的切换(不是因为切换沙盘节点而导致的切层) |
||||
*/ |
||||
enterIndoor(key: string = null, fromUI: boolean = true) { |
||||
GizmoTool.onPickMeshInfoObservable.notifyObservers(null); |
||||
IndoorStatus.changeStatusFromUI = fromUI; |
||||
|
||||
if (fromUI && MarkWindow.instance != null && MarkWindow.instance.isShow && MarkWindow.instance.currentMarkNodeInfo != null) { |
||||
if (key == null) { |
||||
let indoorsData = (this.buildingInfo.buildingData as BuildingData_Normal).indoorsData; |
||||
if (indoorsData != null && indoorsData.length > 0) { |
||||
key = indoorsData[0].modelData.key; |
||||
} |
||||
else { |
||||
//ThreeDimensionalHomeComponent.instance.openSnackBar("暂无室内信息");
|
||||
// alert("暂无室内信息");
|
||||
return; |
||||
} |
||||
|
||||
} |
||||
|
||||
MarkWindow.instance.changeBuilding(false, this.buildingInfo.buildingData.normalData.key, key); |
||||
} |
||||
else { |
||||
console.log("进入室内"); |
||||
let indoorStatus = StatusManager.enterStatus<IndoorStatus>(IndoorStatus); |
||||
indoorStatus.init(this.buildingInfo, key); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 修改模型 |
||||
* @param buildingData
|
||||
*/ |
||||
changeModel(file: File[]) { |
||||
|
||||
this.buildingWindow.changeModel(file, this.buildingInfo.buildingData); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 关联预案管理平台的建筑id |
||||
* @param id
|
||||
*/ |
||||
linkingBuildingID(id: string) { |
||||
this.buildingInfo.buildingData.buildingIDFromPlatform = id; |
||||
} |
||||
|
||||
/** |
||||
* 读取关联的预案管理平台的建筑id |
||||
*/ |
||||
getlinkedBuildingID(): string { |
||||
return this.buildingInfo.buildingData.buildingIDFromPlatform; |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 外部公有
|
||||
|
||||
/** |
||||
* 选中 |
||||
*/ |
||||
select() { |
||||
this.buildingWindow.onChangeCurrentBuildingItem(this); |
||||
} |
||||
|
||||
/** |
||||
* 当选中时的表现 |
||||
* @param select true表示选中 |
||||
*/ |
||||
onSelect(select: boolean, animMove = true) { |
||||
if (select) { |
||||
if (this.buildingInfo.ModelInfo != null && this.buildingInfo.ModelInfo.modelBox != null) { |
||||
GizmoTool.onPickMeshInfoObservable.notifyObservers(this.buildingInfo.ModelInfo); |
||||
//BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, this.buildingInfo.ModelInfo.modelBox, animMove);
|
||||
} |
||||
} |
||||
else { |
||||
if (this.buildingInfo != null) { |
||||
GizmoTool.leaveTheGizmoAim(this.buildingInfo.ModelInfo); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 相机注释、聚焦 |
||||
*/ |
||||
lookAt(anim: boolean = true) { |
||||
if (this.canLookAt()) { |
||||
BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, this.buildingInfo.ModelInfo.modelBox, anim); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 是否可以聚焦 |
||||
*/ |
||||
canLookAt(): boolean { |
||||
let result = this.buildingInfo != null && this.buildingInfo.ModelInfo != null && this.buildingInfo.ModelInfo.modelBox != null; |
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 设置模型的显示状态 |
||||
*/ |
||||
setModelEnable(show: boolean) { |
||||
if (this.buildingInfo != null) { |
||||
this.buildingInfo.setEnable(show); |
||||
} |
||||
} |
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region 内部私有
|
||||
|
||||
//修改建筑名称
|
||||
private changeName(name: string) { |
||||
this.buildingInfo.buildingData.normalData.name = name; |
||||
if (this.buildingInfo.ModelInfo != null) { |
||||
(this.buildingInfo.ModelInfo as ModelInfo_building).updateName(name); |
||||
} |
||||
} |
||||
|
||||
//#endregion
|
||||
} |
@ -0,0 +1,499 @@
|
||||
|
||||
import { DataManager } from "../../controller/data-manager"; |
||||
import { InfoManager } from "../../controller/info-manager"; |
||||
import { SceneManager } from "../../controller/scene-manager"; |
||||
import { ServeManager } from "../../controller/serve-manager"; |
||||
import { BuildingStatus } from "../../controller/status/building-status"; |
||||
import { StatusManager } from "../../controller/status/status-manager"; |
||||
import { BuildingData_Normal, BuildingData_Environment, BuildingData_ChemicalPlant, BuildingType, BuildingData } from "../../model/data/institution/building/building-data"; |
||||
import { BuildingPosType, ModelType } from "../../model/data/model-data/model-data"; |
||||
import { FacilityType } from "../../model/data/model-data/model-data-facility"; |
||||
import { ModelEditData } from "../../model/data/model-data/model-edit-data"; |
||||
import { BuildingInfo } from "../../model/info/building/building-info"; |
||||
import { BuildingInfo_ChemicalPlant } from "../../model/info/building/building-info-chemicalplant"; |
||||
import { BuildingInfo_Environment } from "../../model/info/building/building-info-environment"; |
||||
import { BuildingInfo_Normal } from "../../model/info/building/building-info-normal"; |
||||
import { ModelInfo_building } from "../../model/info/model/model-info-building"; |
||||
import { TsTool } from "../../tool/ts-tool"; |
||||
import { UIBase } from "../window-base/ui-base"; |
||||
import { BuildingUIItem } from "./building-ui-item"; |
||||
|
||||
//建筑界面
|
||||
export class BuildingWindow extends UIBase { |
||||
buldingStatus: BuildingStatus; |
||||
|
||||
buildingUIItems: BuildingUIItem[] = [];//所有建筑UI
|
||||
|
||||
currentBuidngItem: BuildingUIItem; //当前正在操作的建筑
|
||||
|
||||
// three: ThreeDimensionalHomeComponent;//前端组件
|
||||
|
||||
|
||||
|
||||
|
||||
//#region 与前端对接部分
|
||||
|
||||
/** |
||||
* UI上添加一个建筑item |
||||
* @param buildingData 建筑data数据 |
||||
* @param index 序号 |
||||
* @param onSuccess 成功的回调 |
||||
*/ |
||||
createOneBuildingItem(buildingData: BuildingData_Normal | BuildingData_Environment | BuildingData_ChemicalPlant, index: number, onSuccess?: (buildingUIItem: BuildingUIItem, index: number) => void) { |
||||
let buildingInfo: BuildingInfo_Normal | BuildingInfo_Environment | BuildingInfo_ChemicalPlant; |
||||
switch (buildingData.buildingType) { |
||||
case BuildingType.Normal: |
||||
buildingInfo = new BuildingInfo_Normal(buildingData as BuildingData_Normal, null); |
||||
break; |
||||
case BuildingType.Environment: |
||||
buildingInfo = new BuildingInfo_Environment(buildingData, null); |
||||
break; |
||||
case BuildingType.ChemicalPlant: |
||||
buildingInfo = new BuildingInfo_ChemicalPlant(buildingData, null); |
||||
break; |
||||
} |
||||
// console.log("初始化建筑info");
|
||||
// console.log(buildingInfo.buildingData);
|
||||
let uiItem = this.addBuildingItem(buildingInfo); |
||||
|
||||
if (buildingData.outdoorData != null && buildingData.outdoorData.modelData != null && buildingData.outdoorData.modelData.resName != null) { |
||||
this.updateBuildingModel(buildingInfo, false, () => { |
||||
buildingInfo.initFacility(); |
||||
BuildingStatus.enterSuccessObservable.notifyObservers(uiItem); |
||||
if (onSuccess) { |
||||
onSuccess(uiItem, index); |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
//删除建筑
|
||||
deleteBuilding(buidlingUIItem: BuildingUIItem) { |
||||
// console.log("删除建筑" + buidlingUIItem.buildingInfo.buildingData.normalData.key);
|
||||
DataManager.deleteOneBuildingData(buidlingUIItem.buildingInfo.buildingData.buildingType, buidlingUIItem.buildingInfo.buildingData.normalData.key); |
||||
for (let i = 0; i < this.buildingUIItems.length; i++) { |
||||
if (this.buildingUIItems[i] == buidlingUIItem) { |
||||
buidlingUIItem.dispose(); |
||||
TsTool.arrayRemove(this.buildingUIItems, buidlingUIItem); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 改变模型 |
||||
* @param file
|
||||
*/ |
||||
changeModel(file: File[], buildingData: BuildingData) { |
||||
if (file == null || file.length == 0) { |
||||
return; |
||||
} |
||||
console.log("修改模型"); |
||||
|
||||
buildingData.outdoorData.modelData.key = buildingData.normalData.key; |
||||
buildingData.outdoorData.modelData.name = buildingData.normalData.key; |
||||
|
||||
let normalData = buildingData.normalData; |
||||
let resPath_out = DataManager.getResPath_building( |
||||
DataManager.institutionData.normalData.key.toLowerCase(), |
||||
normalData.key.toLocaleLowerCase(), |
||||
BuildingPosType.OutDoor, |
||||
buildingData.normalData.key |
||||
); |
||||
// console.log("新资源路径" + resPath_out);
|
||||
let buildingWindow = this; |
||||
|
||||
let manifestFile: File = null; |
||||
if (buildingData.outdoorData.modelData.resName != null) { |
||||
|
||||
manifestFile = DataManager.createManifestFile(buildingData.outdoorData.modelData); |
||||
file.push(manifestFile); //临时关闭缓存文件
|
||||
} |
||||
|
||||
|
||||
ServeManager.instance.uploadFile(0, file, resPath_out, (name: string, path: string, currentfile) => { |
||||
if (TsTool.stringContain(name, ".gltf")) { |
||||
if (TsTool.stringContain(name, ".gltf.manifest")) { |
||||
//缓存文件,提取版本号
|
||||
DataManager.readFile_manifest(currentfile, (version: number) => { |
||||
buildingData.outdoorData.modelData.version = version; |
||||
// console.log("设置version" + version);
|
||||
}); |
||||
} |
||||
else { |
||||
buildingData.outdoorData.modelData.resName = name; |
||||
buildingData.outdoorData.modelData.resPath = path; |
||||
if (manifestFile == null) { |
||||
manifestFile = DataManager.createManifestFile(buildingData.outdoorData.modelData); |
||||
file.push(manifestFile); |
||||
}//临时关闭缓存文件
|
||||
} |
||||
|
||||
} |
||||
} |
||||
, () => { |
||||
let buildingInfo = buildingWindow.getBuildingInfo(buildingData.normalData.key); |
||||
buildingWindow.updateBuildingModel(buildingInfo, true); |
||||
// buildingWindow.three = ThreeDimensionalHomeComponent.instance;
|
||||
// buildingWindow.three.maskLayerService.sendMessage(false) //关闭遮罩层
|
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 获取目标建筑中,室内的某类设备数目 |
||||
*/ |
||||
getNormalBuildingIndoorFacilitys(buildingUIItem: BuildingUIItem, facilityType: FacilityType) { |
||||
let result = 0; |
||||
|
||||
if (buildingUIItem.buildingInfo.buildingData.buildingType != BuildingType.Normal) { |
||||
//不是普通建筑,没有室内
|
||||
} |
||||
else { |
||||
let indoorData: ModelEditData[] = (buildingUIItem.buildingInfo.buildingData as BuildingData_Normal).indoorsData; |
||||
if (indoorData != null) { |
||||
for (let i = 0; i < indoorData.length; i++) { |
||||
let facilitiesByType = indoorData[i].getFacilitiesByType(facilityType); |
||||
if (facilitiesByType != null) { |
||||
result += facilitiesByType.length; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 进入第一个具有本设备的室内楼层 |
||||
*/ |
||||
changeToFirstIndoorByFacility(buildingUIItem: BuildingUIItem, facilityType: FacilityType) { |
||||
|
||||
let result = false;//是否成功找到并进入某室内层
|
||||
let num = 0; |
||||
|
||||
if (buildingUIItem.buildingInfo.buildingData.buildingType != BuildingType.Normal) { |
||||
//不是普通建筑,没有室内
|
||||
|
||||
} |
||||
else { |
||||
let indoorData: ModelEditData[] = (buildingUIItem.buildingInfo.buildingData as BuildingData_Normal).indoorsData; |
||||
for (let i = 0; i < indoorData.length; i++) { |
||||
let facilitiesByType = indoorData[i].getFacilitiesByType(facilityType); |
||||
if (facilitiesByType != null) { |
||||
num += facilitiesByType.length; |
||||
} |
||||
|
||||
|
||||
if (num > 0) { |
||||
result = true; |
||||
buildingUIItem.enterIndoor(indoorData[i].modelData.key, true); |
||||
break; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 生命周期
|
||||
onInit() { |
||||
super.onInit(); |
||||
|
||||
this.buldingStatus = StatusManager.getStatus<BuildingStatus>(BuildingStatus); |
||||
|
||||
|
||||
this.initBuildings();//创建每一个建筑buildingItem
|
||||
|
||||
|
||||
|
||||
// this.three = ThreeDimensionalHomeComponent.instance;
|
||||
// this.three.getAllBuilding(this);
|
||||
|
||||
} |
||||
|
||||
onShow() { |
||||
this.showModel(true); |
||||
|
||||
super.onShow(); |
||||
} |
||||
onHide() { |
||||
this.showModel(false); |
||||
super.onHide(); |
||||
} |
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 外部公有
|
||||
|
||||
/** |
||||
* 清空建筑上的设备实例 |
||||
* @param buildingInfo
|
||||
*/ |
||||
clearFacilityInfos(buildingInfo: BuildingInfo) { |
||||
|
||||
if (buildingInfo.ModelInfo != null) { |
||||
for (let i = 0; i < buildingInfo.ModelInfo.facilityInfos.length; i++) { |
||||
buildingInfo.ModelInfo.facilityInfos[i].dispose(); |
||||
} |
||||
buildingInfo.ModelInfo.facilityInfos = []; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 显示或隐藏建筑上的设备icon |
||||
* @param buildingInfo
|
||||
* @param show
|
||||
*/ |
||||
showFacilityInfosIcon(buildingInfo: BuildingInfo, show: boolean) { |
||||
if (buildingInfo.ModelInfo != null) { |
||||
buildingInfo.ModelInfo.showFacilityUI(show); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 根据buildingInfo找到item,然后模拟选中 |
||||
* @param buildingInfo 建筑信息 |
||||
*/ |
||||
changeCurrentBuildingInfo(modelInfo: ModelInfo_building) { |
||||
|
||||
let item: BuildingUIItem = null; |
||||
for (let i = 0; i < this.buildingUIItems.length; i++) { |
||||
if (this.buildingUIItems[i].buildingInfo.ModelInfo == modelInfo) { |
||||
item = this.buildingUIItems[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
//this.onChangeCurrentBuildingItem(item);
|
||||
|
||||
// this.three.selectLeftBuilding(item);
|
||||
} |
||||
|
||||
/** |
||||
* 改变当前操作建筑目标 |
||||
* @param buidlingUIItem 新选中的目标 |
||||
*/ |
||||
onChangeCurrentBuildingItem(buidlingUIItem: BuildingUIItem, animMove = true) { |
||||
if (this.currentBuidngItem != null && this.currentBuidngItem != buidlingUIItem) { |
||||
this.currentBuidngItem.onSelect(false); |
||||
} |
||||
|
||||
this.currentBuidngItem = buidlingUIItem; |
||||
this.currentBuidngItem.onSelect(true, animMove); |
||||
|
||||
this.buldingStatus.changeCurrentBuilding(buidlingUIItem.buildingInfo); |
||||
} |
||||
|
||||
/** |
||||
* 查询buildingKey |
||||
* @param key
|
||||
*/ |
||||
public getBuildingInfo(key: string): BuildingInfo { |
||||
for (let i = 0; i < this.buildingUIItems.length; i++) { |
||||
if (this.buildingUIItems[i].buildingInfo.buildingData.normalData.key == key) { |
||||
return this.buildingUIItems[i].buildingInfo; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 查询UIItem |
||||
* @param key
|
||||
*/ |
||||
public getBuildingUIItem(key: string) { |
||||
for (let i = 0; i < this.buildingUIItems.length; i++) { |
||||
if (this.buildingUIItems[i].buildingInfo.buildingData.normalData.key == key) { |
||||
return this.buildingUIItems[i]; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 更新建筑模型 |
||||
* @param buildingInfo
|
||||
* @param updateFacility
|
||||
* @param onSuccess
|
||||
*/ |
||||
public updateBuildingModel(buildingInfo: BuildingInfo, updateFacility: boolean, onSuccess?: () => void) { |
||||
if (buildingInfo == null) { |
||||
return; |
||||
} |
||||
if (buildingInfo.ModelInfo != null) { |
||||
buildingInfo.ModelInfo.dispose(); |
||||
} |
||||
|
||||
|
||||
SceneManager.createModel(ModelType.Building, buildingInfo.buildingData.outdoorData.modelData, true, true, "Building", (newMesh, box, modelInfo) => { |
||||
buildingInfo.ModelInfo = modelInfo as ModelInfo_building; |
||||
buildingInfo.ModelInfo.updateName(buildingInfo.buildingData.normalData.name); |
||||
if (updateFacility) { |
||||
InfoManager.createFacilityInfos(buildingInfo.buildingData.outdoorData, buildingInfo); |
||||
} |
||||
if (buildingInfo instanceof BuildingInfo_Environment) { |
||||
buildingInfo.updateFuGaiCeng(); |
||||
} |
||||
|
||||
if (onSuccess) { |
||||
onSuccess(); |
||||
} |
||||
}); |
||||
} |
||||
//#endregion
|
||||
|
||||
|
||||
//#region 内部私有
|
||||
|
||||
|
||||
//填充建筑列表
|
||||
private initBuildings() { |
||||
|
||||
|
||||
//因为babylon内对indexDB的封装使用有问题,在用户第一次使用时触发了创建数据库操作,导致我们同时调用多个加载方法时报错
|
||||
//解决策略是:如果发现有多个模型要加载,则先加载第一个模型,保证indexDB数据库正常建立, 第一个加载完成后,在加载剩余模型
|
||||
|
||||
BuildingStatus.startEnterObservable.notifyObservers(null); |
||||
|
||||
let instance = this; |
||||
let firstItem; //第一个要加载的模型
|
||||
let firstType: BuildingType; |
||||
|
||||
let allModelNumber = 0; |
||||
|
||||
|
||||
let buildingDatas_Environment = DataManager.getBuildingDataListByType(BuildingType.Environment); |
||||
if (buildingDatas_Environment != null) { |
||||
allModelNumber += buildingDatas_Environment.length; |
||||
if (buildingDatas_Environment.length > 0) { |
||||
firstItem = buildingDatas_Environment[0]; |
||||
firstType = BuildingType.Environment; |
||||
} |
||||
} |
||||
|
||||
let buildingDatas_mormal = DataManager.getBuildingDataListByType(BuildingType.Normal); |
||||
if (buildingDatas_mormal != null) { |
||||
allModelNumber += buildingDatas_mormal.length; |
||||
if (buildingDatas_mormal.length > 0) { |
||||
firstItem = buildingDatas_mormal[0]; |
||||
firstType = BuildingType.Normal; |
||||
} |
||||
} |
||||
|
||||
if (allModelNumber > 1) { |
||||
|
||||
if (firstType == BuildingType.Environment) { |
||||
instance.createOneBuildingItem(firstItem, 0, (uiItem, index) => { |
||||
instance.onChangeCurrentBuildingItem(uiItem, false); |
||||
uiItem.lookAt(false); |
||||
if (buildingDatas_Environment.length > 1) { |
||||
instance.addBuildings(BuildingType.Environment, 1); |
||||
} |
||||
|
||||
instance.addBuildings(BuildingType.Normal, 0); |
||||
|
||||
}); |
||||
|
||||
} |
||||
else { |
||||
instance.createOneBuildingItem(firstItem, 0, (uiItem, index) => { |
||||
instance.onChangeCurrentBuildingItem(uiItem, false); |
||||
uiItem.lookAt(false); |
||||
if (buildingDatas_mormal.length > 1) { |
||||
instance.addBuildings(BuildingType.Normal, 1); |
||||
} |
||||
instance.addBuildings(BuildingType.Environment, 0); |
||||
|
||||
|
||||
}); |
||||
} |
||||
|
||||
} |
||||
else { |
||||
|
||||
instance.addBuildings(BuildingType.Normal, 0, (uiItem, index) => { |
||||
if (index == 0 && uiItem.buildingInfo.isEnable) { |
||||
instance.onChangeCurrentBuildingItem(uiItem, false); |
||||
uiItem.lookAt(false); |
||||
// console.log("默认选中" + uiItem.buildingInfo.buildingData.normalData.key);
|
||||
} |
||||
}); |
||||
|
||||
instance.addBuildings(BuildingType.Environment, 0); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
//初始化建筑显示(根据类别)
|
||||
private addBuildings(buildingType: BuildingType, startIndex: number, onSuccess?: (buildingUIItem: BuildingUIItem, index: number) => void) { |
||||
let index = startIndex; |
||||
|
||||
let buildingDatas = DataManager.getBuildingDataListByType(buildingType); |
||||
// console.log(buildingDatas);
|
||||
while (buildingDatas != null && index < buildingDatas.length) { |
||||
let l_index = index; |
||||
let buildingData = buildingDatas[l_index]; |
||||
this.createOneBuildingItem(buildingData, l_index, onSuccess); |
||||
|
||||
index++; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
//添加一个item到界面中
|
||||
private addBuildingItem(buildingInfo: BuildingInfo): BuildingUIItem { |
||||
let buildingItem = new BuildingUIItem(buildingInfo, this); |
||||
this.buildingUIItems.push(buildingItem); |
||||
|
||||
return buildingItem; |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* 隐藏或展示模型 |
||||
* @param show true-表示展示 |
||||
*/ |
||||
private showModel(show: boolean) { |
||||
for (let i = 0; i < this.buildingUIItems.length; i++) { |
||||
|
||||
//周围环境,不隐藏(也就不用再显示)
|
||||
if (this.buildingUIItems[i].buildingInfo.ModelInfo.buildingType == BuildingType.Environment) { |
||||
(this.buildingUIItems[i].buildingInfo as BuildingInfo_Environment).updateFuGaiCeng(); |
||||
if (show) { //切换到室外时,根据选中状态恢复设备UI
|
||||
if (this.currentBuidngItem == this.buildingUIItems[i]) { |
||||
this.buildingUIItems[i].buildingInfo.ModelInfo.showFacilityUI(show); |
||||
} |
||||
else { |
||||
this.buildingUIItems[i].buildingInfo.ModelInfo.showFacilityUI(false); |
||||
} |
||||
this.buildingUIItems[i].buildingInfo.ModelInfo.showFollowUI(true);//环境的名称UI 不显示
|
||||
} |
||||
else { //切换到室内时,显示环境的设备UI
|
||||
this.buildingUIItems[i].buildingInfo.ModelInfo.showFacilityUI(false);//(感觉太乱,暂时取消)
|
||||
this.buildingUIItems[i].buildingInfo.ModelInfo.showFollowUI(false);//环境的名称UI 不显示
|
||||
} |
||||
} |
||||
else { // 建筑,正常显隐
|
||||
this.buildingUIItems[i].setModelEnable(show); |
||||
} |
||||
// if (this.buildingUIItems[i].buildingInfo != null) {
|
||||
// this.buildingUIItems[i].buildingInfo.setEnable(show);
|
||||
// }
|
||||
} |
||||
} |
||||
//#endregion
|
||||
|
||||
|
||||
} |
@ -0,0 +1,131 @@
|
||||
// import { Button, Control, Rectangle, TextBlock } from "@babylonjs/gui";
|
||||
// import { ThreeDimensionalHomeComponent } from "src/app/gis/three-dimensional-home/three-dimensional-home.component";
|
||||
// import { UIManager } from "src/babylon/controller/ui-manager";
|
||||
// import { BabylonUIStyleTool } from "src/babylon/tool/babylon-ui-style-tool";
|
||||
// import { UIBase } from "../window-base/ui-base";
|
||||
|
||||
// //对话框
|
||||
// export class DialogWindow extends UIBase {
|
||||
// title: string;//标题
|
||||
// content: string;//内容描述
|
||||
|
||||
// okText: string;//确定按钮上的文字
|
||||
// okCallBack?: () => void; //确定按钮的回调
|
||||
// cancelText: string;//取消按钮上的文字
|
||||
// cancelCallBack?: () => void;//取消按钮的回调
|
||||
|
||||
// static OpenDialog(title: string, content: string, okText: string, okCallBack?: () => void, cancelText?: string, cancelCallBack?: () => void) {
|
||||
// let result: DialogWindow = UIManager.open<DialogWindow>(DialogWindow);
|
||||
|
||||
// result.initInfo(title, content, okText, okCallBack, cancelText, cancelCallBack);
|
||||
// result.initUI();
|
||||
|
||||
// return result;
|
||||
|
||||
// }
|
||||
|
||||
// onInit() {
|
||||
// super.onInit();
|
||||
|
||||
// }
|
||||
|
||||
// onOpen() {
|
||||
// super.onOpen();
|
||||
// }
|
||||
|
||||
// onClose() {
|
||||
// super.onClose();
|
||||
|
||||
// }
|
||||
|
||||
// //初始化信息
|
||||
// initInfo(title: string, content: string, okText: string, okCallBack?: () => void, cancelText?: string, cancelCallBack?: () => void) {
|
||||
// this.title = title;
|
||||
// this.content = content;
|
||||
// this.okText = okText;
|
||||
// this.okCallBack = okCallBack;
|
||||
// this.cancelText = cancelText;
|
||||
// this.cancelCallBack = cancelCallBack;
|
||||
// }
|
||||
|
||||
// //初始化界面
|
||||
// initUI() {
|
||||
// this.root = new Rectangle("DialogWindow");
|
||||
// this.root.zIndex = 900;
|
||||
// UIManager.Instance.uiRoot.addControl(this.root);
|
||||
// this.root.width = "200px";
|
||||
// this.root.height = "150px";
|
||||
// this.root.background = UIBase.color_gray;
|
||||
// this.root.thickness = 0;
|
||||
// this.root.cornerRadius = BabylonUIStyleTool.cornerRadius_window1;
|
||||
|
||||
// let ui_title = new TextBlock("title");
|
||||
// this.root.addControl(ui_title);
|
||||
// ui_title.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
|
||||
// ui_title.height = "30px";
|
||||
// ui_title.text = this.title;
|
||||
// ui_title.fontSize = 22;
|
||||
// ui_title.color = "white";
|
||||
|
||||
// let ui_content = new TextBlock("content");
|
||||
// this.root.addControl(ui_content);
|
||||
// ui_content.width = "180px";
|
||||
// ui_content.height = "100px";
|
||||
// ui_content.text = this.content;
|
||||
// ui_content.color = "white";
|
||||
// ui_content.textWrapping = true;
|
||||
|
||||
// let btn_ok = Button.CreateSimpleButton("btn_ok", this.okText);
|
||||
// this.root.addControl(btn_ok);
|
||||
// btn_ok.width = "90px";
|
||||
// btn_ok.height = "30px";
|
||||
// btn_ok.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// btn_ok.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
|
||||
// btn_ok.paddingLeft = "20px";
|
||||
// btn_ok.background = BabylonUIStyleTool.c_color_green;
|
||||
// btn_ok.textBlock.color = "white";
|
||||
// btn_ok.thickness = 0;
|
||||
// btn_ok.cornerRadius = BabylonUIStyleTool.cornerRadius_window1;
|
||||
// btn_ok.onPointerClickObservable.add(() => {
|
||||
// this.onOK(this.okCallBack);
|
||||
// });
|
||||
|
||||
// let btn_Cancel = Button.CreateSimpleButton("btn_cancel", this.cancelText);
|
||||
// this.root.addControl(btn_Cancel);
|
||||
// btn_Cancel.width = "90px";
|
||||
// btn_Cancel.height = "30px";
|
||||
// btn_Cancel.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
|
||||
// btn_Cancel.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
|
||||
// btn_Cancel.paddingRight = "20px";
|
||||
// btn_Cancel.background = UIBase.color_red;
|
||||
// btn_Cancel.color = "white";
|
||||
// btn_Cancel.thickness = 0;
|
||||
// btn_Cancel.cornerRadius = BabylonUIStyleTool.cornerRadius_window1;
|
||||
// btn_Cancel.onPointerClickObservable.add(() => {
|
||||
// this.onConcel(this.cancelCallBack);
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
// //确定按钮回调
|
||||
// onOK(okCallBack?: () => void) {
|
||||
// if (okCallBack != null) {
|
||||
// okCallBack();
|
||||
// }
|
||||
|
||||
// this.onClickBtn();
|
||||
// }
|
||||
// //取消按钮回调
|
||||
// onConcel(cancelCallBack?: () => void) {
|
||||
// if (cancelCallBack != null) {
|
||||
// cancelCallBack();
|
||||
// }
|
||||
// this.onClickBtn();
|
||||
// }
|
||||
|
||||
// //按钮统一行为
|
||||
// onClickBtn() {
|
||||
// UIManager.close<DialogWindow>(this);
|
||||
// }
|
||||
|
||||
// }
|
@ -0,0 +1,90 @@
|
||||
import { AbstractMesh } from "@babylonjs/core"; |
||||
import { Button, Rectangle } from "@babylonjs/gui"; |
||||
import { ConfigManager } from "../../controller/config-manager"; |
||||
import { ModeManager, ModeType } from "../../controller/mode-manager"; |
||||
import { SceneManager } from "../../controller/scene-manager"; |
||||
import { ModelType } from "../../model/data/model-data/model-data"; |
||||
import { ModelData_facility, FacilityShowType } from "../../model/data/model-data/model-data-facility"; |
||||
import { BabylonTool } from "../../tool/babylon-tool"; |
||||
import { LoadTool } from "../../tool/load-tool"; |
||||
import { MeshPoolInfo, MeshPool } from "../../tool/mesh-pool"; |
||||
|
||||
import { FacilityInfoInSceneWindow } from "../facilityinfoinscene-window/facilityinfoinscene-window"; |
||||
import { FacilityWindow } from "./facility-window"; |
||||
|
||||
//设施UI item
|
||||
export class FacilityUIItem { |
||||
facilityData: ModelData_facility; |
||||
meshPrefab: AbstractMesh; |
||||
meshPoolInfo: MeshPoolInfo; |
||||
constructor(facilityData: ModelData_facility, root: Rectangle, button: Button) { |
||||
this.facilityData = facilityData; |
||||
let instance = this; |
||||
if (facilityData.getShowtype() == FacilityShowType.ModelAndTag) { |
||||
instance.meshPoolInfo = MeshPool.importMesh(ModelType.Facility, facilityData, true, true, LoadTool.c_tag_facilityPrefab, (mesh, meshes, result: MeshPoolInfo) => { |
||||
instance.meshPrefab = mesh; |
||||
mesh.name = "pfb_" + this.facilityData.key; |
||||
mesh.setEnabled(false); |
||||
result.modelInfo.showFollowUI(false); |
||||
if (!SceneManager.s_openLight) { |
||||
BabylonTool.setMatToUnlit(meshes, true); |
||||
} |
||||
}) |
||||
} |
||||
|
||||
} |
||||
|
||||
//#region 前端对接
|
||||
|
||||
//获取图片URL
|
||||
getIconURL() { |
||||
return ConfigManager.getFacilityIconUrl(this.facilityData.facilityType, this.facilityData.posType) |
||||
} |
||||
|
||||
//获取图片key
|
||||
getIconID() { |
||||
return this.facilityData.key |
||||
} |
||||
|
||||
//获取设备中文名
|
||||
getIconName() { |
||||
|
||||
return this.facilityData.name |
||||
} |
||||
|
||||
//取消选择 当前设备
|
||||
unSelect() { |
||||
FacilityWindow.instance.clearCurrentFacility(); |
||||
} |
||||
|
||||
/** |
||||
* 选中当前设备 |
||||
*/ |
||||
select() { |
||||
FacilityWindow.instance.onClickFacilityBtn(this); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//选中时的表现
|
||||
onSelect(select: boolean) { |
||||
if (ModeManager.currentMode == ModeType.Look) //只在查看模式下生效
|
||||
{ |
||||
FacilityInfoInSceneWindow.instance.showFacilityByType(this.facilityData.facilityType, select); |
||||
} |
||||
} |
||||
|
||||
dispose() { |
||||
if (this.meshPoolInfo != null) { |
||||
//MeshPool.disposeMesh(this.meshPoolInfo);
|
||||
this.meshPoolInfo.dispose(); |
||||
this.meshPoolInfo = null; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,521 @@
|
||||
import { |
||||
EventState, |
||||
Mesh, |
||||
MeshBuilder, |
||||
PointerEventTypes, |
||||
PointerInfo, |
||||
Vector3, |
||||
} from '@babylonjs/core'; |
||||
import { |
||||
Control, |
||||
Image, |
||||
Rectangle, |
||||
} from '@babylonjs/gui'; |
||||
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 } from '../../model/data/model-data/model-data-facility'; |
||||
import { BuildingInfo } from '../../model/info/building/building-info'; |
||||
import { AreaInfo } from '../../model/info/model/facilityinfo-tool/facility-area'; |
||||
import { GdInfo } from '../../model/info/model/facilityinfo-tool/facility-gd'; |
||||
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 { 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: ThreeDimensionalHomeComponent;//前端组件
|
||||
|
||||
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.Indoor) { |
||||
facilities = DataManager.allFacilityData.indoor; |
||||
} else { |
||||
// console.log("=====updateAllFacilities=====");
|
||||
// console.log(DataManager.allFacilityData);
|
||||
facilities = DataManager.allFacilityData.outdoor; |
||||
} |
||||
|
||||
|
||||
let instance = this; |
||||
//为了避免多个模型同时加载、导致indexDB创建冲突,所以先加载一个,保证indexDB创建完成
|
||||
BabylonTool.importMeshSync(null, "assets/facilities/outdoor/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); |
||||
} |
||||
|
||||
|
||||
// ThreeDimensionalHomeComponent.instance.getAllIcons(instance)
|
||||
|
||||
}) |
||||
// instance.three = ThreeDimensionalHomeComponent.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.createNewFacility(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<Mesh> { |
||||
let thisWindow = this; //为了方便调用其方法
|
||||
let myPromise = new Promise<Mesh>(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; |
||||
} |
||||
|
||||
|
||||
|
||||
//创建新的设施(用世界坐标)
|
||||
createNewFacility(worldPosition: Vector3) { |
||||
let facilityData = FacilityWindow.s_currentFacilityItem.facilityData.clone( |
||||
this.createIndex.toString() |
||||
); |
||||
|
||||
facilityData.transformData.position = worldPosition.clone(); |
||||
|
||||
let currentBuidngItem = StatusManager.getStatus<BuildingStatus>(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, (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, (modelInfo) => { |
||||
//GizmoTool.onPickMeshInfoObservable.notifyObservers(modelInfo);
|
||||
|
||||
modelInfo.onStopLongPress(null, null); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
//移除设备(等待UI调用)
|
||||
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, |
||||
onSuccess?: (modelInfo: ModelInfo_facility) => void |
||||
): ModelInfo_facility { |
||||
|
||||
if (buildingInfo == null) { |
||||
buildingInfo = this.getCurrentBuildingInfo(); |
||||
} |
||||
|
||||
|
||||
let defaultMesh = MeshBuilder.CreateBox(facilityData.key, { size: 1 }); |
||||
defaultMesh.isVisible = false; |
||||
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) { |
||||
|
||||
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); |
||||
} |
||||
|
||||
} |
||||
else if (facilityInfo.facilityShowType == FacilityShowType.GdAndTag) { |
||||
if (facilityData.areaPoints.length == 0) { |
||||
facilityData.areaPoints = []; |
||||
facilityData.areaPoints.push(new Vector3(0, 0, 0)); |
||||
facilityData.areaPoints.push(new Vector3(0, 10, 0)); |
||||
} |
||||
facilityInfo.gdInfo = new GdInfo(facilityData.areaPoints[0], facilityData.areaPoints[1], 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: Mesh, 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>(BuildingStatus) |
||||
.buildingWindow.currentBuidngItem.buildingInfo; |
||||
} else if (StatusManager.s_currentStatus instanceof IndoorStatus) { |
||||
buildingInfo = StatusManager.getStatus<IndoorStatus>(IndoorStatus) |
||||
.indoorWindow.currentFloorUIItem.buildingInfo; |
||||
} |
||||
|
||||
return buildingInfo; |
||||
} |
||||
} |
@ -0,0 +1,202 @@
|
||||
|
||||
import { SceneManager } from "../../controller/scene-manager"; |
||||
import { PropertyData_Base_IMG } from "../../model/data/institution/facility/property-data/base/property-data-base-img"; |
||||
import { PropertyData_Base_SBJHQ } from "../../model/data/institution/facility/property-data/base/property-data-base-sbjhq"; |
||||
import { PropertyData_Base_XFB } from "../../model/data/institution/facility/property-data/base/property-data-base-xfb"; |
||||
import { PropertyData_Base_XHS } from "../../model/data/institution/facility/property-data/base/property-data-base-xhs"; |
||||
import { PropertyData_DWBZ } from "../../model/data/institution/facility/property-data/indoor/property-data-dwbz"; |
||||
import { PropertyData_FHFQ } from "../../model/data/institution/facility/property-data/indoor/property-data-fhfq"; |
||||
import { PropertyData_SSLT } from "../../model/data/institution/facility/property-data/indoor/property-data-sslt"; |
||||
import { PropertyData_XFDT } from "../../model/data/institution/facility/property-data/indoor/property-data-xfdt"; |
||||
import { PropertyData_ZDQY } from "../../model/data/institution/facility/property-data/indoor/property-data-zdqy"; |
||||
import { PropertyData_AQCK } from "../../model/data/institution/facility/property-data/outdoor/property-data-aqck"; |
||||
import { PropertyData_GD } from "../../model/data/institution/facility/property-data/outdoor/property-data-gd"; |
||||
import { PropertyData_PL } from "../../model/data/institution/facility/property-data/outdoor/property-data-pl"; |
||||
import { PropertyData_Q } from "../../model/data/institution/facility/property-data/outdoor/property-data-q"; |
||||
import { PropertyData_Base } from "../../model/data/institution/facility/property-data/property-data-base"; |
||||
import { FacilityType, ModelData_facility } from "../../model/data/model-data/model-data-facility"; |
||||
import { ModelInfo_facility } from "../../model/info/model/model-info-facility"; |
||||
import { BabylonTool } from "../../tool/babylon-tool"; |
||||
import { GizmoTool } from "../../tool/gizmo-tool"; |
||||
import { TsTool } from "../../tool/ts-tool"; |
||||
import { FacilityInfoInSceneWindow } from "./facilityinfoinscene-window"; |
||||
|
||||
//单个场景中的设备 UI item
|
||||
export class FacilityInfoUIItem { |
||||
modelInfo: ModelInfo_facility; |
||||
facilityInfoInSceneWindow: FacilityInfoInSceneWindow; |
||||
isSelect: boolean = false; |
||||
isChecked: boolean = false; //是否 选中
|
||||
// facilityBtn: Button;
|
||||
|
||||
constructor(modelInfo: ModelInfo_facility, facilityInfoInSceneWindow: FacilityInfoInSceneWindow) { |
||||
this.modelInfo = modelInfo; |
||||
this.facilityInfoInSceneWindow = facilityInfoInSceneWindow; |
||||
this.initUI(); |
||||
} |
||||
|
||||
|
||||
|
||||
//#region 前端对接
|
||||
|
||||
l_name = null; |
||||
/** |
||||
* 获取设备名 |
||||
*/ |
||||
getName(): string { |
||||
return this.modelInfo.modelData.name; |
||||
} |
||||
|
||||
/** |
||||
* 设备类型 |
||||
*/ |
||||
getType(): FacilityType { |
||||
return (this.modelInfo.modelData as ModelData_facility).facilityType; |
||||
} |
||||
/** |
||||
* 设备ID |
||||
*/ |
||||
getID(): string { |
||||
return this.modelInfo.key; |
||||
} |
||||
/** |
||||
* 获取 设备属性 |
||||
*/ |
||||
getPropertyData() { |
||||
let facilityData |
||||
// = (this.modelInfo.modelData as ModelData_facility).propertyData as any;
|
||||
if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.AQCK) { |
||||
//安全出口
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_AQCK; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.DSXHS || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.DXXHS || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.SZDSXHS || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.SZDXXHS) { |
||||
//消火栓
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_Base_XHS; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.DSSBJHQ || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.DXSBJHQ || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.QBSBJHQ || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.DGNSBJHQ) { |
||||
//水泵接合器
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_Base_SBJHQ; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.GD) { |
||||
//高度
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_GD; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.PL) { |
||||
//毗邻
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_PL; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.TPBZ || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.XKS || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.BF || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.SX) { |
||||
//图片标注,消控室,泵房,水箱
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_Base_IMG; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.JJQ || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.JTQ) { |
||||
//集结区,禁停区
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_Q; |
||||
} |
||||
else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.LSXFB || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.WSXFB || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.CYXFB) { |
||||
//消防泵
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_Base_XFB; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.FHFQ) { |
||||
//防火分区
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_FHFQ; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.FHM) { |
||||
//防火门
|
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.FHJL) { |
||||
//防火卷帘
|
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.SSLT) { |
||||
//疏散楼梯
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_SSLT; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.XFDT) { |
||||
//消防电梯
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_XFDT; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.PTDT) { |
||||
//普通电梯
|
||||
facilityData = null |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.ZDQY) { |
||||
//重点区域
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_ZDQY; |
||||
} else if ((this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.WXY || (this.modelInfo.modelData as ModelData_facility).facilityType == FacilityType.DWBZ) { |
||||
//危险源,点位标注
|
||||
facilityData = (this.modelInfo.modelData as ModelData_facility).propertyData as PropertyData_DWBZ; |
||||
} else { |
||||
//未匹配到的
|
||||
facilityData = null |
||||
} |
||||
return facilityData |
||||
} |
||||
|
||||
/** |
||||
* 粘贴属性 |
||||
* @param propertyData
|
||||
*/ |
||||
pasteProperty(propertyData: PropertyData_Base) { |
||||
let facilityData = this.modelInfo.modelData as ModelData_facility; |
||||
let key = facilityData.propertyData.key; |
||||
facilityData.propertyData = propertyData.clone(key); |
||||
|
||||
console.log("粘贴属性"); |
||||
} |
||||
|
||||
/** |
||||
* 询问删除 |
||||
* @param ask true表示询问,false表示不询问
|
||||
*/ |
||||
askDelete(ask: boolean = true) { |
||||
this.modelInfo.askDelete(this.modelInfo, ask); |
||||
} |
||||
//#endregion
|
||||
|
||||
initUI() { |
||||
|
||||
} |
||||
|
||||
dispose() { |
||||
|
||||
TsTool.arrayRemove(this.facilityInfoInSceneWindow.facilityInfoUIItemes, this); |
||||
} |
||||
|
||||
onSelect(select: boolean) { |
||||
this.isSelect = select; |
||||
this.modelInfo.setSelectEnable(select); |
||||
if (select) { |
||||
// console.log("选中设备==" + this.modelInfo.key);
|
||||
GizmoTool.onPickMeshInfoObservable.notifyObservers(this.modelInfo); |
||||
this.facilityInfoInSceneWindow.selectFacilityItemToThree([this], true); |
||||
this.modelInfo.setIconEnable(select); |
||||
} |
||||
else { |
||||
this.facilityInfoInSceneWindow.selectFacilityItemToThree([this], false); |
||||
if (!this.facilityInfoInSceneWindow.getFacilityUIShowType(this.getType())) { |
||||
this.modelInfo.setIconEnable(select); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 相机聚焦 |
||||
*/ |
||||
lookAt() { |
||||
|
||||
if (!this.canLookAt()) { |
||||
return; |
||||
} |
||||
|
||||
let size = null; |
||||
if (this.modelInfo.gdInfo != null) { |
||||
size = this.modelInfo.gdInfo.myPath[1].y * 3; |
||||
} |
||||
|
||||
if (this.modelInfo.areaInfo != null) { |
||||
//计算多边形size
|
||||
} |
||||
BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, this.modelInfo.modelBox, true, size); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 是否可以聚焦 |
||||
*/ |
||||
canLookAt(): boolean { |
||||
let result = this.modelInfo != null && this.modelInfo.modelBox != null; |
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,603 @@
|
||||
import { EventManager } from "@angular/platform-browser"; |
||||
import { AbstractMesh, Ray, RayHelper, Vector3 } from "@babylonjs/core"; |
||||
import { classToClass } from "class-transformer"; |
||||
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 { 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 { 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 { UIBase } from "../window-base/ui-base"; |
||||
import { FacilityInfoUIItem } from "./facilityinfo-ui-item"; |
||||
|
||||
//所有放在场景中的设备 信息界面
|
||||
export class FacilityInfoInSceneWindow extends UIBase { |
||||
static instance: FacilityInfoInSceneWindow; |
||||
// three: ThreeDimensionalHomeComponent;//前端组件
|
||||
// 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 = ThreeDimensionalHomeComponent.instance;
|
||||
// if (this.isMultiselect) { // 多选
|
||||
// if (isChecked) { //选中
|
||||
// facilityInfoUIItem.forEach(element => {
|
||||
// element.isChecked = isChecked
|
||||
// let isFind = this.three.beforeOnefacilityInfoList.find(item => { return item === element.getID() })
|
||||
// isFind == undefined || isFind == null ? this.three.beforeOnefacilityInfoList.push(element.getID()) : null
|
||||
// })
|
||||
// } else { //取消选中
|
||||
// this.three.isShowRightNature = false
|
||||
// facilityInfoUIItem.forEach(element => {
|
||||
// element.isChecked = isChecked
|
||||
// let index = this.three.beforeOnefacilityInfoList.findIndex(value => value === element.getID())
|
||||
// index != undefined && index != null ? this.three.beforeOnefacilityInfoList.splice(index, 1) : null
|
||||
// })
|
||||
// }
|
||||
// } 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); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 根据类型获取数目 |
||||
* @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 false; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 删除某一类设备 |
||||
* @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(); |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
onClose() { |
||||
super.onClose(); |
||||
//EventManager.removeCallback(Event_ModelInfoChange, this.onModelInfoChange);
|
||||
|
||||
GizmoTool.onPickMeshInfoObservable.removeCallback(this.onClickModel); |
||||
} |
||||
|
||||
//#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 退格
|
||||
{ |
||||
//改由前端完成快捷键删除
|
||||
// if (this.currentFacility != null) {
|
||||
// for (let i = 0; i < this.currentFacility.length; i++) {
|
||||
// this.currentFacility[i].askDelete(false);
|
||||
// }
|
||||
// this.currentFacility = [];
|
||||
// this.three.getAllCensusList(this.facilityInfoUIItemes || []);
|
||||
// }
|
||||
} |
||||
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
|
||||
|
||||
//创建所有设备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>(BuildingStatus).buildingWindow; |
||||
return (buildingWindow != null && buildingWindow.currentBuidngItem != null && buildingWindow.currentBuidngItem.buildingInfo == belongToBuilding) |
||||
} |
||||
else if (StatusManager.s_currentStatus instanceof IndoorStatus) { |
||||
let indoorKey = StatusManager.getStatus<IndoorStatus>(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[]; |
||||
} |
@ -0,0 +1,234 @@
|
||||
// import { Control, Rectangle, StackPanel, TextBlock } from "@babylonjs/gui";
|
||||
// import { DataManager } from "src/babylon/controller/data-manager";
|
||||
// import { ServeManager } from "src/babylon/controller/serve-manager";
|
||||
// import { IndoorStatus } from "src/babylon/controller/status/indoor-status";
|
||||
// import { StatusManager } from "src/babylon/controller/status/status-manager";
|
||||
// import { UIManager } from "src/babylon/controller/ui-manager";
|
||||
// import { BuildingData_Normal } from "src/babylon/model/data/institution/building/building-data";
|
||||
// import { BuildingPosType, ModelData } from "src/babylon/model/data/model-data/model-data";
|
||||
// import { ModelEditData } from "src/babylon/model/data/model-data/model-edit-data";
|
||||
// import { BabylonUIStyleTool } from "src/babylon/tool/babylon-ui-style-tool";
|
||||
// import { TsTool } from "src/babylon/tool/ts-tool";
|
||||
// import { UIBase } from "../window-base/ui-base";
|
||||
// import { IndoorFloorUIItem } from "./indoor-floorui-item";
|
||||
|
||||
// export class IndoorCreateWindow extends UIBase {
|
||||
// buildingData: BuildingData_Normal
|
||||
// newFloorData: ModelEditData;//新的楼层信息,新建时填充
|
||||
// indoorFloorUIItem: IndoorFloorUIItem;//已有的楼层item,修改时填充
|
||||
// isCreate: boolean = true;//是新建楼层
|
||||
|
||||
// indoorStatus: IndoorStatus;
|
||||
// isChangeModel = false;//修改了模型,则要重新加载模型
|
||||
|
||||
// //初始化为新建
|
||||
// initCreate() {
|
||||
// this.newFloorData = this.indoorStatus.newIndoorData("key", "name");
|
||||
|
||||
// this.initUI();
|
||||
// }
|
||||
|
||||
// //初始化为修改
|
||||
// initChange(indoorFloorUIItem: IndoorFloorUIItem) {
|
||||
// this.indoorFloorUIItem = indoorFloorUIItem;
|
||||
// this.newFloorData = indoorFloorUIItem.modelEditData;
|
||||
// this.initUI();
|
||||
// }
|
||||
|
||||
// //#region 声明周期
|
||||
// onInit() {
|
||||
// super.onInit();
|
||||
// this.indoorStatus = StatusManager.getStatus<IndoorStatus>(IndoorStatus);
|
||||
|
||||
// }
|
||||
|
||||
// onOpen() {
|
||||
// super.onOpen();
|
||||
|
||||
// BabylonUIStyleTool.createWindoRoot(this, "IndoorCreateWindow", "300px", "296px", true);
|
||||
// }
|
||||
|
||||
// onClose() {
|
||||
// super.onClose();
|
||||
// }
|
||||
// //#endregion
|
||||
|
||||
|
||||
// initUI() {
|
||||
|
||||
// let window = this;
|
||||
|
||||
// let baseWidth = "220px";
|
||||
// let baseHeight = "20px";
|
||||
|
||||
// let indoorStatus = StatusManager.getStatus<IndoorStatus>(IndoorStatus);
|
||||
// this.buildingData = indoorStatus.buildingInfo.buildingData as BuildingData_Normal;
|
||||
|
||||
// let stack = new StackPanel("stack");
|
||||
// stack.isVertical = true;
|
||||
// BabylonUIStyleTool.setStyle_size(stack, baseWidth, "280px");
|
||||
// this.root.addControl(stack);
|
||||
|
||||
|
||||
// this.isCreate = this.indoorFloorUIItem == null;
|
||||
|
||||
// let titleText = this.isCreate ? "新建" : "编辑";
|
||||
// let title = BabylonUIStyleTool.createTextBlock("title", titleText, baseWidth, baseHeight, "20px");
|
||||
// stack.addControl(title);
|
||||
|
||||
// let space = new Rectangle("space");
|
||||
// BabylonUIStyleTool.setStyle_size(space, baseWidth, baseHeight);
|
||||
// stack.addControl(space);
|
||||
|
||||
// let floorKey = BabylonUIStyleTool.createTextBlock("floorKey", "唯一key", baseWidth, baseHeight, "18px");
|
||||
// stack.addControl(floorKey);
|
||||
// floorKey.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
|
||||
// let floorKeyInput = BabylonUIStyleTool.createInputText("floorKeyInput", stack, baseWidth, baseHeight);
|
||||
// if (!this.isCreate && this.newFloorData.modelData.key != null) {
|
||||
// floorKeyInput.inputText.text = this.newFloorData.modelData.key;
|
||||
// }
|
||||
// floorKeyInput.inputText.onTextChangedObservable.add(() => {
|
||||
// window.newFloorData.modelData.key = floorKeyInput.inputText.text;
|
||||
// });
|
||||
|
||||
// let floorName = BabylonUIStyleTool.createTextBlock("floorName", "楼层名称", baseWidth, baseHeight, "18px");
|
||||
// stack.addControl(floorName);
|
||||
// floorName.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
|
||||
// let floorNameInput = BabylonUIStyleTool.createInputText("floorNameInput", stack, baseWidth, baseHeight);
|
||||
// if (this.isCreate) {
|
||||
|
||||
// }
|
||||
// else {
|
||||
// floorNameInput.inputText.text = this.newFloorData.modelData.name;
|
||||
// }
|
||||
// floorNameInput.inputText.onTextChangedObservable.add(() => {
|
||||
// window.newFloorData.modelData.name = floorNameInput.inputText.text;
|
||||
// })
|
||||
|
||||
// let space4 = new Rectangle("space4");
|
||||
// BabylonUIStyleTool.setStyle_size(space4, baseWidth, "20px");
|
||||
// stack.addControl(space4);
|
||||
|
||||
// let btn_changeModel = BabylonUIStyleTool.createBtn_OK("btn_changeModel", "上传模型", baseWidth, "30px", "18px");
|
||||
// stack.addControl(btn_changeModel);
|
||||
|
||||
// btn_changeModel.onPointerClickObservable.add(() => {
|
||||
// window.changeModel();
|
||||
// })
|
||||
|
||||
|
||||
// let space2 = new Rectangle("space2");
|
||||
// BabylonUIStyleTool.setStyle_size(space2, baseWidth, "30px");
|
||||
// stack.addControl(space2);
|
||||
|
||||
// let btns = new StackPanel("btns");
|
||||
// BabylonUIStyleTool.setStyle_size(btns, baseWidth, "36px");
|
||||
// stack.addControl(btns);
|
||||
// btns.isVertical = false;
|
||||
|
||||
// let btn_OK = BabylonUIStyleTool.createBtn_OK("OK", "确定", "100px", "36px", "18px");
|
||||
// btns.addControl(btn_OK);
|
||||
// btn_OK.onPointerClickObservable.add(() => {
|
||||
// window.onBtn_Ok();
|
||||
// })
|
||||
|
||||
// let space3 = new Rectangle("space3");
|
||||
// BabylonUIStyleTool.setStyle_size(space3, "20px", "36px");
|
||||
// btns.addControl(space3);
|
||||
|
||||
// let btn_cancel = BabylonUIStyleTool.createBtn_Cancel("cancel", "取消", "100px", "36px", "18px");
|
||||
// btns.addControl(btn_cancel);
|
||||
// btn_cancel.onPointerClickObservable.add(() => {
|
||||
// window.onBtn_Cancel();
|
||||
// });
|
||||
|
||||
// if (!this.isCreate) {
|
||||
// let btn_delete = BabylonUIStyleTool.createBtn_Delete("delete", "删", "30px", "30px", "20px");
|
||||
// this.root.addControl(btn_delete);
|
||||
// btn_delete.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||
// btn_delete.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
|
||||
// btn_delete.onPointerClickObservable.add(() => {
|
||||
// console.log("===btn_delete===");
|
||||
// window.onBtn_Delete();
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// //修改模型
|
||||
// changeModel() {
|
||||
// let institutionKey = DataManager.institutionData.normalData.key;
|
||||
// let indoorData = this.newFloorData;
|
||||
// let buildingKey = StatusManager.getStatus<IndoorStatus>(IndoorStatus).buildingInfo.buildingData.normalData.key;
|
||||
// let path = DataManager.getResPath_building(institutionKey, buildingKey, BuildingPosType.Indoor, this.newFloorData.modelData.key);
|
||||
// console.log("模型路径" + path);
|
||||
|
||||
// let instance = this;
|
||||
// ServeManager.instance.openFileSelect(path, (name: string, path: string) => {
|
||||
// instance.isChangeModel = true;
|
||||
// if (TsTool.stringContain(name, ".gltf")) {
|
||||
// indoorData.modelData.resName = name;
|
||||
// indoorData.modelData.resPath = path;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// onBtn_Ok() {
|
||||
// if (this.isCreate) {
|
||||
// if (this.buildingData.indoorsData == null) {
|
||||
// this.buildingData.indoorsData = [];
|
||||
// }
|
||||
// this.indoorStatus.addNewIndoorToBuilding(this.newFloorData);
|
||||
// // this.buildingData.indoorsData.push(this.newFloorData);
|
||||
|
||||
// let indoorStatus = StatusManager.getStatus<IndoorStatus>(IndoorStatus);
|
||||
// indoorStatus.indoorWindow.createOneFloorUIItem(this.newFloorData);
|
||||
// }
|
||||
// else {
|
||||
// console.log(this.indoorFloorUIItem.modelEditData.modelData);
|
||||
// //更新场景
|
||||
// if (this.isChangeModel) {
|
||||
// this.indoorFloorUIItem.updateBuilding();
|
||||
// }
|
||||
// else {
|
||||
// this.indoorFloorUIItem.updateUI();
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// this.closeWindow();
|
||||
// }
|
||||
|
||||
// //点击取消按钮
|
||||
// onBtn_Cancel() {
|
||||
// this.closeWindow();
|
||||
// }
|
||||
|
||||
// //点击删除按钮
|
||||
// onBtn_Delete() {
|
||||
// console.log("onBtn_Delete");
|
||||
// let indoorStatus = StatusManager.getStatus<IndoorStatus>(IndoorStatus);
|
||||
// indoorStatus.indoorWindow.deleteFloor(this.indoorFloorUIItem);
|
||||
// this.closeWindow();
|
||||
// }
|
||||
|
||||
// //关闭界面
|
||||
// closeWindow() {
|
||||
// if (this.isCreate) {
|
||||
// let indoorStatus = StatusManager.getStatus<IndoorStatus>(IndoorStatus);
|
||||
|
||||
// indoorStatus.indoorWindow.closeCreateIndoorWindow();
|
||||
// }
|
||||
// else {
|
||||
// this.isChangeModel = false;
|
||||
// this.indoorFloorUIItem.closeChangeWindow();
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// }
|
@ -0,0 +1,278 @@
|
||||
import { AbstractMesh, Mesh } from "@babylonjs/core"; |
||||
import { Button, Container, Rectangle } from "@babylonjs/gui"; |
||||
import ObjectID from "bson-objectid"; |
||||
import { classToClass } from "class-transformer"; |
||||
import { DataManager } from "../../controller/data-manager"; |
||||
import { InfoManager } from "../../controller/info-manager"; |
||||
import { SceneManager } from "../../controller/scene-manager"; |
||||
import { IndoorStatus } from "../../controller/status/indoor-status"; |
||||
import { ModelType } from "../../model/data/model-data/model-data"; |
||||
import { ModelEditData } from "../../model/data/model-data/model-edit-data"; |
||||
import { BuildingInfo } from "../../model/info/building/building-info"; |
||||
import { ModelInfo } from "../../model/info/model/model-info"; |
||||
import { ModelInfo_building } from "../../model/info/model/model-info-building"; |
||||
import { BabylonTool } from "../../tool/babylon-tool"; |
||||
import { GizmoTool } from "../../tool/gizmo-tool"; |
||||
import { MeshPoolInfo } from "../../tool/mesh-pool"; |
||||
|
||||
import { MarkWindow } from "../mark-window/mark-window"; |
||||
// import { IndoorCreateWindow } from "./indoor-create-window";
|
||||
import { IndoorWindow } from "./indoor-window"; |
||||
|
||||
//室内楼层UI
|
||||
export class IndoorFloorUIItem { |
||||
modelEditData: ModelEditData; |
||||
buildingInfo: BuildingInfo; |
||||
root: Rectangle; |
||||
content: Container; |
||||
indoorWindow: IndoorWindow; |
||||
btn: Button; |
||||
|
||||
|
||||
constructor(modelEditData: ModelEditData, indoorWindow: IndoorWindow) { |
||||
this.modelEditData = modelEditData; |
||||
this.indoorWindow = indoorWindow; |
||||
|
||||
} |
||||
|
||||
//#region 前端对接
|
||||
|
||||
/** |
||||
* 获取室内层key |
||||
*/ |
||||
getIndoorKey() { |
||||
return this.modelEditData.modelData.key; |
||||
} |
||||
|
||||
/** |
||||
* 获取室内层名称 |
||||
*/ |
||||
getIndoorName() { |
||||
return this.modelEditData.modelData.name; |
||||
} |
||||
|
||||
/** |
||||
* 楼层序列 |
||||
*/ |
||||
getIndoorIndex() { |
||||
return this.modelEditData.index; |
||||
} |
||||
|
||||
/** |
||||
* 修改室内名称 |
||||
* @param newName
|
||||
*/ |
||||
setIndoorName(newName: string) { |
||||
this.modelEditData.modelData.name = newName; |
||||
if (this.buildingInfo != null && this.buildingInfo.ModelInfo != null) { |
||||
(this.buildingInfo.ModelInfo as ModelInfo_building).updateName(newName); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 设置避难层 |
||||
*/ |
||||
setRefugeFloor(isRefugeFloor: boolean) { |
||||
this.modelEditData.isRefugeFloor = isRefugeFloor; |
||||
} |
||||
|
||||
/** |
||||
* 修改模型 |
||||
* @param file
|
||||
*/ |
||||
changeModel(file: File[]) { |
||||
console.log("修改模型", file); |
||||
this.indoorWindow.changeModel(file, this.modelEditData); |
||||
} |
||||
|
||||
/** |
||||
* 复制楼层数据 |
||||
*/ |
||||
copyFloor() { |
||||
let result = classToClass(this.modelEditData); |
||||
result.modelData.key = ObjectID.generate(); |
||||
result.modelData.name = result.modelData.name + "(1)"; |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region 内部方法
|
||||
//更新建筑
|
||||
updateBuilding() { |
||||
let instance = this; |
||||
|
||||
if (this.modelEditData != null && this.modelEditData.modelData != null && this.modelEditData.modelData.resPath != null) { |
||||
|
||||
if (instance.buildingInfo == null) { |
||||
instance.buildingInfo = new BuildingInfo(DataManager.institutionData.normalBuildingDatas[0], null); |
||||
} |
||||
instance.buildingInfo.isDisposed = false; |
||||
if (instance.buildingInfo.ModelInfo != null) { //更新、释放掉之前的模型、ui
|
||||
instance.buildingInfo.ModelInfo.dispose(); |
||||
} |
||||
|
||||
let resKey = this.modelEditData.modelData.resName + this.modelEditData.modelData.name; |
||||
let meshFromPool = IndoorFloorUIItem.getFromPool(resKey); |
||||
console.log(meshFromPool); |
||||
if (meshFromPool == null) { |
||||
//创建所有室内模型
|
||||
SceneManager.createModel(ModelType.Building, this.modelEditData.modelData, true, true, undefined, (newMesh, box, modelInfo) => { |
||||
// instance.buildingInfo.ModelInfo = modelInfo as ModelInfo_building;
|
||||
// box.position.y = box.scaling.y * 0.5 + 1;
|
||||
// IndoorFloorUIItem.addToPool(this.modelEditData.modelData.resPath +this.modelEditData.modelData.name,box);
|
||||
// // console.log("创建建筑成功=" + this.modelEditData.modelData.name + "isdispos" + instance.buildingInfo.ModelInfo.isDisposed);
|
||||
// if (!instance.buildingInfo.ModelInfo.isDisposed) {
|
||||
// instance.buildingInfo.ModelInfo.updateName(instance.modelEditData.modelData.name);
|
||||
// let facilitysInFloor = instance.buildingInfo.ModelInfo.facilityInfos;
|
||||
// SceneManager.s_facilityInfoInSceneWindow.createAllFacilities(facilitysInFloor);
|
||||
// InfoManager.createFacilityInfos(instance.modelEditData, instance.buildingInfo);
|
||||
// //BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, box, false);
|
||||
// IndoorStatus.enterSuccessObservable.notifyObservers(instance);
|
||||
// instance.lookAt(false);
|
||||
|
||||
// }
|
||||
instance.onLoadMesh(instance, modelInfo, box); |
||||
IndoorFloorUIItem.addToPool(resKey, box); |
||||
}); |
||||
} |
||||
else { |
||||
let modelInfo = InfoManager.newModelInfo_building( |
||||
instance.modelEditData.modelData.key, |
||||
instance.modelEditData.modelData, |
||||
null, |
||||
meshFromPool |
||||
); |
||||
|
||||
instance.onLoadMesh(instance, modelInfo, meshFromPool); |
||||
} |
||||
|
||||
|
||||
} |
||||
else { |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 加载完成的回调 |
||||
* @param instance
|
||||
* @param modelInfo
|
||||
* @param modelBox
|
||||
*/ |
||||
onLoadMesh(instance: IndoorFloorUIItem, modelInfo: ModelInfo, modelBox: AbstractMesh) { |
||||
instance.buildingInfo.ModelInfo = modelInfo as ModelInfo_building; |
||||
modelBox.position.y = modelBox.scaling.y * 0.5 + 1; |
||||
// console.log("创建建筑成功=" + this.modelEditData.modelData.name + "isdispos" + instance.buildingInfo.ModelInfo.isDisposed);
|
||||
if (!instance.buildingInfo.ModelInfo.isDisposed) { |
||||
instance.buildingInfo.ModelInfo.updateName(instance.modelEditData.modelData.name); |
||||
let facilitysInFloor = instance.buildingInfo.ModelInfo.facilityInfos; |
||||
SceneManager.s_facilityInfoInSceneWindow.createAllFacilities(facilitysInFloor); |
||||
InfoManager.createFacilityInfos(instance.modelEditData, instance.buildingInfo); |
||||
//BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, box, false);
|
||||
IndoorStatus.enterSuccessObservable.notifyObservers(instance); |
||||
instance.lookAt(true); |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
dispose() { |
||||
|
||||
if (this.buildingInfo != null) { |
||||
GizmoTool.leaveTheGizmoAim(this.buildingInfo.ModelInfo); |
||||
} |
||||
if (this.buildingInfo != null) { |
||||
this.buildingInfo.dispose(); |
||||
} |
||||
} |
||||
|
||||
//点击选中
|
||||
onClick() { |
||||
this.indoorWindow.selectFloor(this); |
||||
} |
||||
|
||||
|
||||
//是否选中的表现更新
|
||||
onSelect(select: boolean) { |
||||
if (select) { |
||||
|
||||
this.updateBuilding(); |
||||
} |
||||
else { |
||||
if (this.buildingInfo != null) { |
||||
GizmoTool.leaveTheGizmoAim(this.buildingInfo.ModelInfo); |
||||
this.buildingInfo.dispose(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 摄像机聚焦 |
||||
*/ |
||||
lookAt(anim: boolean = true) { |
||||
if (MarkWindow.s_cameraData != null) { |
||||
// setTimeout(() => {
|
||||
SceneManager.Instance.defaultCamera.animations |
||||
MarkWindow.s_cameraData.setDataToCamera(SceneManager.Instance.defaultCamera); |
||||
MarkWindow.s_cameraData = null; |
||||
// }, (500));
|
||||
|
||||
} else if (this.buildingInfo != null && this.buildingInfo.ModelInfo != null && this.buildingInfo.ModelInfo.modelBox != null) { |
||||
BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, this.buildingInfo.ModelInfo.modelBox, anim); |
||||
} |
||||
} |
||||
//#endregion
|
||||
|
||||
|
||||
//#region 室内模型池
|
||||
|
||||
/** |
||||
* 缓存室内楼层的备份 |
||||
*/ |
||||
static pool: Map<string, MeshPoolInfo> = new Map(); |
||||
|
||||
/** |
||||
* 将备份放入池中 |
||||
* @param meshKey
|
||||
* @param mesh
|
||||
*/ |
||||
static addToPool(meshKey: string, mesh: AbstractMesh) { |
||||
|
||||
if (IndoorFloorUIItem.pool.has(meshKey)) { |
||||
return; |
||||
} |
||||
else { |
||||
let prefabMesh = BabylonTool.cloneMesh(mesh as Mesh, mesh.name); |
||||
let poolInfo: MeshPoolInfo = new MeshPoolInfo(meshKey, meshKey, false, prefabMesh); |
||||
poolInfo.meshBox.setEnabled(false); |
||||
IndoorFloorUIItem.pool.set(meshKey, poolInfo); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 从池中获取 |
||||
* @param modelPath
|
||||
*/ |
||||
static getFromPool(modelPath: string) { |
||||
if (IndoorFloorUIItem.pool.has(modelPath)) { |
||||
let result = IndoorFloorUIItem.pool.get(modelPath); |
||||
let modelBox = BabylonTool.cloneMesh(result.meshBox as Mesh, result.meshBox.name + "111"); |
||||
modelBox.setEnabled(true); |
||||
return modelBox; |
||||
} |
||||
else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
} |
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue