112 changed files with 24688 additions and 899 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,30 @@ |
|||||||
|
|
||||||
|
import { ModelData } from "src/babylon/model/data/model-data/model-data"; |
||||||
|
import { BuildingInfo } from "src/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,23 @@ |
|||||||
|
import { AllMarkPlanData } from "src/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,43 @@ |
|||||||
|
import { ModelInfo_mark } from "src/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,32 @@ |
|||||||
|
import { ModelInfo } from "src/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,219 @@ |
|||||||
|
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 { 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"); |
||||||
|
|
||||||
|
//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,78 @@ |
|||||||
|
import { Type } from 'class-transformer'; |
||||||
|
import { ConfigManager } from 'src/assets/babylon/controller/config-manager'; |
||||||
|
import { DataManager } from 'src/assets/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,226 @@ |
|||||||
|
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/assets/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,597 @@ |
|||||||
|
import { Type } from "class-transformer"; |
||||||
|
import { ConfigManager } from "src/assets/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,491 @@ |
|||||||
|
import { Type } from "class-transformer"; |
||||||
|
import { TsTool } from "src/assets/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,279 @@ |
|||||||
|
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/assets/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,78 @@ |
|||||||
|
import { Type } from "class-transformer"; |
||||||
|
import { TsTool } from "src/assets/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,54 @@ |
|||||||
|
import { TransformNode } from '@babylonjs/core'; |
||||||
|
import { BuildingStatus } from 'src/assets/babylon/controller/status/building-status'; |
||||||
|
import { IndoorStatus } from 'src/assets/babylon/controller/status/indoor-status'; |
||||||
|
import { StatusManager } from 'src/assets/babylon/controller/status/status-manager'; |
||||||
|
import { TsTool } from 'src/assets/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/assets/babylon/controller/info-manager"; |
||||||
|
import { SceneManager } from "src/assets/babylon/controller/scene-manager"; |
||||||
|
import { BuildingStatus } from "src/assets/babylon/controller/status/building-status"; |
||||||
|
import { StatusManager } from "src/assets/babylon/controller/status/status-manager"; |
||||||
|
import { GizmoTool } from "src/assets/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/assets/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,534 @@ |
|||||||
|
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/assets/babylon/controller/config-manager"; |
||||||
|
import { MarkInfoChangeType, Event_MarkInfoChange } from "src/assets/babylon/controller/event-manager/events/event-mark-info-change"; |
||||||
|
import { SceneManager } from "src/assets/babylon/controller/scene-manager"; |
||||||
|
import { UIManager } from "src/assets/babylon/controller/ui-manager"; |
||||||
|
import { BabylonTool } from "src/assets/babylon/tool/babylon-tool"; |
||||||
|
import { BabylonUIStyleTool } from "src/assets/babylon/tool/babylon-ui-style-tool"; |
||||||
|
import { ParticleSystemTool } from "src/assets/babylon/tool/particle-system-tool"; |
||||||
|
import { TsTool } from "src/assets/babylon/tool/ts-tool"; |
||||||
|
import { MarkWindow } from "src/assets/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,270 @@ |
|||||||
|
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/assets/babylon/controller/scene-manager"; |
||||||
|
import { BabylonTool } from "src/assets/babylon/tool/babylon-tool"; |
||||||
|
import { MarkWindow } from "src/assets/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,182 @@ |
|||||||
|
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/assets/babylon/controller/scene-manager"; |
||||||
|
import { BabylonTool } from "src/assets/babylon/tool/babylon-tool"; |
||||||
|
import { MarkWindow } from "src/assets/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,322 @@ |
|||||||
|
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/assets/babylon/controller/scene-manager"; |
||||||
|
import { BabylonTool } from "src/assets/babylon/tool/babylon-tool"; |
||||||
|
import { MarkWindow } from "src/assets/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,184 @@ |
|||||||
|
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/assets/babylon/controller/scene-manager"; |
||||||
|
import { BabylonTool } from "src/assets/babylon/tool/babylon-tool"; |
||||||
|
import { MarkWindow } from "src/assets/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,148 @@ |
|||||||
|
import { Mesh, ParticleSystem, ParticleSystemSet, Vector3 } from "@babylonjs/core"; |
||||||
|
import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh"; |
||||||
|
import { classToClass } from "class-transformer"; |
||||||
|
import { BabylonTool } from "src/assets/babylon/tool/babylon-tool"; |
||||||
|
import { ParticleSystemTool } from "src/assets/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,368 @@ |
|||||||
|
//#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 { ModeManager, ModeType } from "src/assets/babylon/controller/mode-manager"; |
||||||
|
import { SceneManager } from "src/assets/babylon/controller/scene-manager"; |
||||||
|
import { UIManager } from "src/assets/babylon/controller/ui-manager"; |
||||||
|
import { BabylonUIStyleTool } from "src/assets/babylon/tool/babylon-ui-style-tool"; |
||||||
|
import { GizmoTool } from "src/assets/babylon/tool/gizmo-tool"; |
||||||
|
import { PosPointTool } from "src/assets/babylon/tool/pos-point-tool"; |
||||||
|
import { FacilityType, ModelData_facility } from "../../../data/model-data/model-data-facility"; |
||||||
|
|
||||||
|
(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,266 @@ |
|||||||
|
//#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/assets/babylon/controller/mode-manager"; |
||||||
|
import { SceneManager } from "src/assets/babylon/controller/scene-manager"; |
||||||
|
import { UIManager } from "src/assets/babylon/controller/ui-manager"; |
||||||
|
import { BabylonUIStyleTool, UI_LineInfo } from "src/assets/babylon/tool/babylon-ui-style-tool"; |
||||||
|
import { GizmoTool, TransformUIType } from "src/assets/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,231 @@ |
|||||||
|
import { Observer, Scene, TransformNode } from "@babylonjs/core"; |
||||||
|
import { Button, Rectangle } from "@babylonjs/gui"; |
||||||
|
import { ModelChangeType } from "src/assets/babylon/controller/data-manager"; |
||||||
|
import { Event_ModelInfoChange } from "src/assets/babylon/controller/event-manager/events/event-modelinfo-change"; |
||||||
|
import { InfoManager } from "src/assets/babylon/controller/info-manager"; |
||||||
|
import { ModeManager, ModeType } from "src/assets/babylon/controller/mode-manager"; |
||||||
|
import { SceneManager } from "src/assets/babylon/controller/scene-manager"; |
||||||
|
import { BuildingStatus } from "src/assets/babylon/controller/status/building-status"; |
||||||
|
import { IndoorStatus } from "src/assets/babylon/controller/status/indoor-status"; |
||||||
|
import { StatusManager } from "src/assets/babylon/controller/status/status-manager"; |
||||||
|
import { BabylonUIStyleTool } from "src/assets/babylon/tool/babylon-ui-style-tool"; |
||||||
|
import { GizmoTool } from "src/assets/babylon/tool/gizmo-tool"; |
||||||
|
import { TsTool } from "src/assets/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/assets/babylon/controller/config-manager"; |
||||||
|
import { SceneManager } from "src/assets/babylon/controller/scene-manager"; |
||||||
|
import { BabylonUIStyleTool } from "src/assets/babylon/tool/babylon-ui-style-tool"; |
||||||
|
import { FacilityWindow } from "src/assets/babylon/view/facility-window/facility-window"; |
||||||
|
import { FacilityInfoInSceneWindow } from "src/assets/babylon/view/facilityinfoinscene-window/facilityinfoinscene-window"; |
||||||
|
import { PropertyBaseWindow } from "src/assets/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,264 @@ |
|||||||
|
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/assets/babylon/controller/ui-manager'; |
||||||
|
import { BabylonTool } from 'src/assets/babylon/tool/babylon-tool'; |
||||||
|
import { GizmoTool } from 'src/assets/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,65 @@ |
|||||||
|
import { ThreeDimensionalHomeComponent } from "src/app/gis/three-dimensional-home/three-dimensional-home.component"; |
||||||
|
|
||||||
|
/** |
||||||
|
* 加载管理器 |
||||||
|
*/ |
||||||
|
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
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,281 @@ |
|||||||
|
|
||||||
|
import { DataManager } from "../../controller/data-manager"; |
||||||
|
import { SceneManager } from "../../controller/scene-manager"; |
||||||
|
import { ServeManager } from "../../controller/serve-manager"; |
||||||
|
import { BuildingStatus } from "../../controller/status/building-status"; |
||||||
|
import { IndoorStatus } from "../../controller/status/indoor-status"; |
||||||
|
import { StatusManager } from "../../controller/status/status-manager"; |
||||||
|
import { BuildingPosType } from "../../model/data/model-data/model-data"; |
||||||
|
import { ModelEditData } from "../../model/data/model-data/model-edit-data"; |
||||||
|
import { TsTool } from "../../tool/ts-tool"; |
||||||
|
import { MarkWindow } from "../mark-window/mark-window"; |
||||||
|
import { UIBase } from "../window-base/ui-base"; |
||||||
|
import { IndoorFloorUIItem } from "./indoor-floorui-item"; |
||||||
|
|
||||||
|
|
||||||
|
//室内界面
|
||||||
|
export class IndoorWindow extends UIBase { |
||||||
|
|
||||||
|
allFloorDatas: ModelEditData[]; |
||||||
|
allFloorUIItems: IndoorFloorUIItem[] = []; |
||||||
|
|
||||||
|
currentFloorUIItem: IndoorFloorUIItem; |
||||||
|
|
||||||
|
refugeFloorNum: number;//避难层数目
|
||||||
|
|
||||||
|
indoorStatus: IndoorStatus; |
||||||
|
|
||||||
|
//#region 生命周期
|
||||||
|
onInit() { |
||||||
|
super.onInit(); |
||||||
|
this.indoorStatus = StatusManager.getStatus<IndoorStatus>(IndoorStatus); |
||||||
|
} |
||||||
|
|
||||||
|
onOpen() { |
||||||
|
super.onOpen(); |
||||||
|
} |
||||||
|
|
||||||
|
onClose() { |
||||||
|
super.onClose(); |
||||||
|
} |
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 前端对接
|
||||||
|
|
||||||
|
/** |
||||||
|
* 获取当前室内的避难层数目 |
||||||
|
*/ |
||||||
|
getRefugeFloorNum() { |
||||||
|
return this.refugeFloorNum; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 返回室外 |
||||||
|
* 来自UI |
||||||
|
*/ |
||||||
|
onBtnToOutDoor(fromUI: boolean = true) { |
||||||
|
BuildingStatus.changeStatusFromUI = fromUI; |
||||||
|
if (fromUI && MarkWindow.instance != null && MarkWindow.instance.isShow && MarkWindow.instance.currentMarkNodeInfo != null) { |
||||||
|
MarkWindow.instance.changeBuilding(true); |
||||||
|
} |
||||||
|
else { |
||||||
|
StatusManager.enterStatus<BuildingStatus>(BuildingStatus); |
||||||
|
console.log("退出到室外"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
/** |
||||||
|
* 修改模型 |
||||||
|
* @param file
|
||||||
|
* @param modelEditData
|
||||||
|
*/ |
||||||
|
changeModel(file: File[], modelEditData: ModelEditData) { |
||||||
|
|
||||||
|
if (file == null || file.length == 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
let institutionKey = DataManager.institutionData.normalData.key; |
||||||
|
let indoorData = modelEditData; |
||||||
|
let buildingKey = StatusManager.getStatus<IndoorStatus>(IndoorStatus).buildingInfo.buildingData.normalData.key; |
||||||
|
let path = DataManager.getResPath_building(institutionKey, buildingKey, BuildingPosType.Indoor, indoorData.modelData.key); |
||||||
|
// console.log("模型路径" + path);
|
||||||
|
let instance = this; |
||||||
|
|
||||||
|
let manifestFile: File = null; |
||||||
|
if (indoorData.modelData.resName != null) { |
||||||
|
|
||||||
|
manifestFile = DataManager.createManifestFile(indoorData.modelData); |
||||||
|
file.push(manifestFile);//临时关闭缓存文件
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
ServeManager.instance.uploadFile(0, file, path, (name: string, path: string, currentfile: File) => { |
||||||
|
|
||||||
|
|
||||||
|
if (TsTool.stringContain(name, ".gltf")) { |
||||||
|
if (TsTool.stringContain(name, ".gltf.manifest")) { |
||||||
|
//缓存文件,提取版本号
|
||||||
|
DataManager.readFile_manifest(currentfile, (version: number) => { |
||||||
|
indoorData.modelData.version = version; |
||||||
|
// console.log("设置version" + version);
|
||||||
|
}); |
||||||
|
} |
||||||
|
else { |
||||||
|
indoorData.modelData.resName = name; |
||||||
|
indoorData.modelData.resPath = path; |
||||||
|
|
||||||
|
// console.log("上传室内:" + path + name);
|
||||||
|
|
||||||
|
if (manifestFile == null) { |
||||||
|
manifestFile = DataManager.createManifestFile(indoorData.modelData); |
||||||
|
file.push(manifestFile);//临时关闭缓存文件
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
, () => { |
||||||
|
//ThreeDimensionalHomeComponent.instance.maskLayerService.sendMessage(false)
|
||||||
|
if (instance.currentFloorUIItem != null && modelEditData.modelData.key == instance.currentFloorUIItem.modelEditData.modelData.key) { |
||||||
|
instance.currentFloorUIItem.updateBuilding(); |
||||||
|
} |
||||||
|
else { |
||||||
|
let newItem = this.getFloorByKey(modelEditData.modelData.key); |
||||||
|
//ThreeDimensionalHomeComponent.instance.selectLeftBuilding(newItem);
|
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//初始化所有楼层
|
||||||
|
initAllFloor(allFloorData: ModelEditData[], key: string) { |
||||||
|
this.allFloorDatas = allFloorData; |
||||||
|
this.updateFloorUIItem(key); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//更新item
|
||||||
|
updateFloorUIItem(key: string) { |
||||||
|
this.clearAllFloorUIItem(); |
||||||
|
let defaultItem: IndoorFloorUIItem = null; |
||||||
|
if (this.allFloorDatas != null) { |
||||||
|
for (let i = 0; i < this.allFloorDatas.length; i++) { |
||||||
|
let item = this.createOneFloorUIItem(this.allFloorDatas[i]); |
||||||
|
if (this.allFloorDatas[i].modelData.key == key) { |
||||||
|
defaultItem = item; |
||||||
|
} |
||||||
|
|
||||||
|
if (this.allFloorDatas[i].isRefugeFloor) { |
||||||
|
this.refugeFloorNum++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
if (defaultItem == null) { |
||||||
|
if (this.allFloorUIItems.length > 0) { |
||||||
|
this.selectFloor(this.getFirstIndexFloor(this.allFloorUIItems), false); |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
this.selectFloor(defaultItem, false); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取最小序列的楼层 |
||||||
|
* @param items
|
||||||
|
*/ |
||||||
|
getFirstIndexFloor(items: IndoorFloorUIItem[]) { |
||||||
|
let index = 0; |
||||||
|
for (let i = 0; i < items.length; i++) { |
||||||
|
if (items[i].getIndoorIndex() < items[index].getIndoorIndex()) { |
||||||
|
index = i; |
||||||
|
} |
||||||
|
} |
||||||
|
return items[index]; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//创建单个楼层UIitem
|
||||||
|
createOneFloorUIItem(modelEditData: ModelEditData): IndoorFloorUIItem { |
||||||
|
let result = new IndoorFloorUIItem(modelEditData, this); |
||||||
|
this.allFloorUIItems.push(result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
//删除室内层
|
||||||
|
deleteFloor(indoorFloorUIItem: IndoorFloorUIItem) { |
||||||
|
// console.log("试图删除");
|
||||||
|
|
||||||
|
for (let i = 0; i < this.allFloorDatas.length; i++) { |
||||||
|
if (this.allFloorDatas[i] == indoorFloorUIItem.modelEditData) { |
||||||
|
TsTool.arrayRemove(this.allFloorDatas, indoorFloorUIItem.modelEditData); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (let i = 0; i < this.allFloorUIItems.length; i++) { |
||||||
|
if (this.allFloorUIItems[i] == indoorFloorUIItem) { |
||||||
|
this.allFloorUIItems[i].dispose(); |
||||||
|
TsTool.arrayRemove(this.allFloorUIItems, indoorFloorUIItem); |
||||||
|
// console.log("成功删除");
|
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//清空楼层item
|
||||||
|
clearAllFloorUIItem() { |
||||||
|
// console.log("清空楼层item"+this.allFloorUIItems.length);
|
||||||
|
for (let i = 0; i < this.allFloorUIItems.length; i++) { |
||||||
|
this.allFloorUIItems[i].dispose(); |
||||||
|
} |
||||||
|
this.allFloorUIItems = []; |
||||||
|
this.refugeFloorNum = 0; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//选中某层
|
||||||
|
selectFloor(floorUIItem: IndoorFloorUIItem, fromUI: boolean = true) { |
||||||
|
|
||||||
|
|
||||||
|
if (fromUI && MarkWindow.instance != null && MarkWindow.instance.isShow) { |
||||||
|
MarkWindow.instance.changeBuilding(false, this.indoorStatus.buildingInfo.buildingData.normalData.key, floorUIItem.modelEditData.modelData.key); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (this.currentFloorUIItem == floorUIItem) { |
||||||
|
// if (floorUIItem.buildingInfo != null) {
|
||||||
|
// BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, floorUIItem.buildingInfo.ModelInfo.modelBox);
|
||||||
|
// }
|
||||||
|
return; |
||||||
|
} |
||||||
|
else if (this.currentFloorUIItem != null) { |
||||||
|
this.currentFloorUIItem.onSelect(false); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
this.currentFloorUIItem = floorUIItem; |
||||||
|
SceneManager.s_facilityInfoInSceneWindow.clearFacilityInfoUIItemes();//先清空
|
||||||
|
this.currentFloorUIItem.onSelect(true); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 根据key找item |
||||||
|
* @param key
|
||||||
|
*/ |
||||||
|
getFloorByKey(key: string): IndoorFloorUIItem { |
||||||
|
let result = null; |
||||||
|
if (this.allFloorUIItems != null) { |
||||||
|
for (let i = 0; i < this.allFloorUIItems.length; i++) { |
||||||
|
if (this.allFloorUIItems[i].modelEditData.modelData.key == key) { |
||||||
|
result = this.allFloorUIItems[i]; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 摄像机注视中心
|
||||||
|
// */
|
||||||
|
// lookAtCenter(buildingInfo: ModelInfo_building) {
|
||||||
|
// if (buildingInfo != null && buildingInfo.modelBox != null) {
|
||||||
|
// BabylonTool.changeCameraTarget(SceneManager.Instance.defaultCamera, buildingInfo.modelBox);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
} |
@ -0,0 +1,190 @@ |
|||||||
|
import { Button, Control, Rectangle, StackPanel, TextBlock } from "@babylonjs/gui"; |
||||||
|
import { LoginSatus } from "../../controller/status/login-status"; |
||||||
|
import { StatusManager } from "../../controller/status/status-manager"; |
||||||
|
import { UIManager } from "../../controller/ui-manager"; |
||||||
|
import { InstitutionData, NormalData } from "../../model/data/institution/institution-data"; |
||||||
|
import { InsitutionDataSimple } from "../../model/data/institution/institution-data-simple"; |
||||||
|
import { MyInputText } from "../../tool/babylon-tool"; |
||||||
|
import { BabylonUIStyleTool } from "../../tool/babylon-ui-style-tool"; |
||||||
|
|
||||||
|
import { UIBase } from "../window-base/ui-base"; |
||||||
|
|
||||||
|
//创建单位界面
|
||||||
|
//由于还没有可存放多个单位信息的位置,先预留,暂时没实现
|
||||||
|
export class InstitutionCreateWindow extends UIBase { |
||||||
|
|
||||||
|
insDataSimple: InsitutionDataSimple;//新单位简易信息
|
||||||
|
insData: InstitutionData; //新单位的详细信息
|
||||||
|
|
||||||
|
//#region 声明周期
|
||||||
|
onInit() { |
||||||
|
super.onInit(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
onOpen() { |
||||||
|
super.onOpen(); |
||||||
|
this.initUI(); |
||||||
|
} |
||||||
|
|
||||||
|
onClose() { |
||||||
|
super.onClose(); |
||||||
|
} |
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 创建新单位
|
||||||
|
|
||||||
|
//开始创建
|
||||||
|
startCreate() { |
||||||
|
this.insDataSimple = new InsitutionDataSimple(); |
||||||
|
this.insDataSimple.key = "test3";//因不可重复,应该从服务器获得
|
||||||
|
this.txt_keyValue.inputText.text = this.insDataSimple.key;//假装请求成功
|
||||||
|
this.txt_keyValue.inputText.onTextChangedObservable.add(() => { |
||||||
|
this.insDataSimple.key = this.txt_keyValue.inputText.text; |
||||||
|
console.log("设置key" + this.insDataSimple.key); |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
//确定
|
||||||
|
onbtnOK() { |
||||||
|
this.insDataSimple.name = this.inputTxt_insName.inputText.text;//从输入框获取
|
||||||
|
// console.log("onbtnOK==key" + this.insDataSimple.key);
|
||||||
|
// console.log("onbtnOK==name" + this.insDataSimple.name);
|
||||||
|
if (this.insDataSimple.name == null) { |
||||||
|
console.log("请输入单位名称"); |
||||||
|
} |
||||||
|
else { |
||||||
|
|
||||||
|
this.insData = new InstitutionData(); |
||||||
|
this.insData.normalData = new NormalData(this.insDataSimple.key, this.insDataSimple.name); |
||||||
|
|
||||||
|
console.log(this.insData.normalData); |
||||||
|
this.saveNewIns(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//保存新单位信息至服务器
|
||||||
|
saveNewIns() { |
||||||
|
let window = this; |
||||||
|
let loginStatus = StatusManager.getStatus<LoginSatus>(LoginSatus); |
||||||
|
loginStatus.saveNewIns(loginStatus, window.insData, window.insDataSimple.key, (insDataSimple) => { |
||||||
|
loginStatus.closeCreateWindow(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region UI界面
|
||||||
|
|
||||||
|
inputTxt_insName: MyInputText;//名称输入框
|
||||||
|
txt_keyValue: MyInputText;//唯一Key
|
||||||
|
btn_OK: Button;//确定创建
|
||||||
|
btn_Cancle: Button;//取消
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
initUI() { |
||||||
|
let window = this; |
||||||
|
|
||||||
|
this.root = new Rectangle("InstitutionCreateWindow"); |
||||||
|
this.root.width = "300px"; |
||||||
|
this.root.height = "382px"; |
||||||
|
BabylonUIStyleTool.setDefaultStyle_windowRoot(this.root); |
||||||
|
|
||||||
|
UIManager.Instance.uiRoot.addControl(this.root); |
||||||
|
|
||||||
|
let title = new TextBlock("title", "新建单位"); |
||||||
|
BabylonUIStyleTool.setStyle_size(title, "80px", "20px"); |
||||||
|
BabylonUIStyleTool.setStyle_bodyText(title); |
||||||
|
this.root.addControl(title); |
||||||
|
BabylonUIStyleTool.setStyle_Alignment(title, Control.HORIZONTAL_ALIGNMENT_CENTER, Control.VERTICAL_ALIGNMENT_TOP); |
||||||
|
BabylonUIStyleTool.setStyle_padding(title, "40px", undefined, undefined, undefined); |
||||||
|
|
||||||
|
let nameRoot = new StackPanel("nameRoor"); |
||||||
|
BabylonUIStyleTool.setStyle_size(nameRoot, "200px", "300px"); |
||||||
|
this.root.addControl(nameRoot); |
||||||
|
BabylonUIStyleTool.setStyle_Alignment(nameRoot, Control.HORIZONTAL_ALIGNMENT_CENTER, Control.VERTICAL_ALIGNMENT_TOP); |
||||||
|
BabylonUIStyleTool.setStyle_padding(nameRoot, "80px", undefined, undefined, undefined); |
||||||
|
|
||||||
|
let nameTxt = new TextBlock("nameTxt", "单位名称"); |
||||||
|
BabylonUIStyleTool.setStyle_size(nameTxt, "200px", "20px"); |
||||||
|
nameTxt.textVerticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||||
|
BabylonUIStyleTool.setStyle_bodyText(nameTxt, "16px", UIBase.color_black); |
||||||
|
nameTxt.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||||
|
nameRoot.addControl(nameTxt); |
||||||
|
|
||||||
|
|
||||||
|
this.inputTxt_insName = BabylonUIStyleTool.createInputText("input_name", nameRoot, "200px", "30px"); |
||||||
|
|
||||||
|
let padding = new Control(); |
||||||
|
BabylonUIStyleTool.setStyle_size(padding, "200px", "20px"); |
||||||
|
nameRoot.addControl(padding); |
||||||
|
|
||||||
|
let keyTxt = new TextBlock("keyTxt", "唯一key,仅供测试可见"); |
||||||
|
BabylonUIStyleTool.setStyle_size(keyTxt, "200px", "20px"); |
||||||
|
keyTxt.textVerticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
||||||
|
BabylonUIStyleTool.setStyle_bodyText(keyTxt, "16px", UIBase.color_black); |
||||||
|
keyTxt.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
||||||
|
nameRoot.addControl(keyTxt); |
||||||
|
keyTxt.alpha = 0.5; |
||||||
|
|
||||||
|
this.txt_keyValue = BabylonUIStyleTool.createInputText("keyValueTxt", nameRoot, "200px", "20px", "black", undefined, undefined, BabylonUIStyleTool.c_color_gray, "black", BabylonUIStyleTool.c_color_gray); |
||||||
|
// BabylonUIStyleTool.setStyle_size(this.txt_keyValue, "200px", "20px");
|
||||||
|
// this.txt_keyValue.textVerticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
|
||||||
|
// BabylonUIStyleTool.setStyle_bodyText(this.txt_keyValue, "14px", UIBase.color_black);
|
||||||
|
// this.txt_keyValue.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
|
||||||
|
// nameRoot.addControl(this.txt_keyValue);
|
||||||
|
// this.txt_keyValue.alpha = 0.7;
|
||||||
|
this.txt_keyValue.inputText.onTextChangedObservable.add(() => { |
||||||
|
window.insDataSimple.key = window.txt_keyValue.inputText.text; |
||||||
|
}); |
||||||
|
|
||||||
|
let btnRoot = new StackPanel("btnRoot"); |
||||||
|
btnRoot.isVertical = false; |
||||||
|
this.root.addControl(btnRoot); |
||||||
|
BabylonUIStyleTool.setStyle_size(btnRoot, "240px", "70px"); |
||||||
|
BabylonUIStyleTool.setStyle_Alignment(btnRoot, Control.HORIZONTAL_ALIGNMENT_CENTER, Control.VERTICAL_ALIGNMENT_BOTTOM); |
||||||
|
BabylonUIStyleTool.setStyle_padding(btnRoot, undefined, undefined, "30px"); |
||||||
|
|
||||||
|
|
||||||
|
let padding_btn = new Control("padding_btn"); |
||||||
|
BabylonUIStyleTool.setStyle_size(padding_btn, "10px", "36px"); |
||||||
|
btnRoot.addControl(padding_btn); |
||||||
|
|
||||||
|
this.btn_OK = BabylonUIStyleTool.createBtn_OK("OK", "确定", "100px", "36px", "18px"); |
||||||
|
btnRoot.addControl(this.btn_OK); |
||||||
|
|
||||||
|
this.btn_OK.onPointerClickObservable.add(() => { |
||||||
|
window.onbtnOK(); |
||||||
|
}) |
||||||
|
|
||||||
|
let padding_btn1 = new Control("padding_btn1"); |
||||||
|
BabylonUIStyleTool.setStyle_size(padding_btn1, "20px", "36px"); |
||||||
|
btnRoot.addControl(padding_btn1); |
||||||
|
|
||||||
|
this.btn_Cancle = BabylonUIStyleTool.createBtn_Cancel("Cancel", "取消", "100px", "36px", "18px"); |
||||||
|
btnRoot.addControl(this.btn_Cancle); |
||||||
|
this.btn_Cancle.onPointerClickObservable.add(() => { |
||||||
|
window.onBtnClose(); |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
onBtnClose() { |
||||||
|
let loginStatus = StatusManager.getStatus<LoginSatus>(LoginSatus); |
||||||
|
loginStatus.closeCreateWindow(); |
||||||
|
loginStatus.openSelectWindow(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
import { Button, Rectangle, StackPanel } from "@babylonjs/gui"; |
||||||
|
import { InsitutionDataSimple } from "../../model/data/institution/institution-data-simple"; |
||||||
|
import { BabylonUIStyleTool } from "../../tool/babylon-ui-style-tool"; |
||||||
|
|
||||||
|
import { UIBase } from "../window-base/ui-base"; |
||||||
|
import { InstitutionSelectWindow } from "./institution-select-window"; |
||||||
|
|
||||||
|
export class InstitutionItem { |
||||||
|
root: Rectangle; |
||||||
|
window: InstitutionSelectWindow;//单位选择界面
|
||||||
|
insData: InsitutionDataSimple;//单位简易信息
|
||||||
|
|
||||||
|
btn_select: Button; |
||||||
|
constructor(window: InstitutionSelectWindow, parent: StackPanel, insitutionDataSimple: InsitutionDataSimple) { |
||||||
|
this.window = window; |
||||||
|
this.insData = insitutionDataSimple; |
||||||
|
|
||||||
|
if (this.insData == null) { |
||||||
|
this.insData = new InsitutionDataSimple(); |
||||||
|
this.insData.name = "+新建单位"; |
||||||
|
this.insData.key = undefined; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
this.root = new Rectangle("InstitutionItem"); |
||||||
|
BabylonUIStyleTool.setStyle_size(this.root, parent.width + "px", "40px"); |
||||||
|
this.root.color = UIBase.color_blue; |
||||||
|
parent.addControl(this.root); |
||||||
|
|
||||||
|
let name = "null"; |
||||||
|
if (this.insData.name != null) { |
||||||
|
name = this.insData.name; |
||||||
|
} |
||||||
|
this.btn_select = Button.CreateSimpleButton("select", name); |
||||||
|
let item = this; |
||||||
|
this.btn_select.onPointerClickObservable.add(() => { |
||||||
|
item.onSelect(); |
||||||
|
}); |
||||||
|
this.root.addControl(this.btn_select); |
||||||
|
|
||||||
|
// let text = this.btn_select.textBlock;
|
||||||
|
// text.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//选择单位
|
||||||
|
onSelect() { |
||||||
|
console.log("选择单位" + this.insData.name); |
||||||
|
|
||||||
|
this.window.onSelectIns(this); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//新建单位
|
||||||
|
onNewSelect() { |
||||||
|
console.log("新建单位"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue