中化加油站项目
 
 
 
 
 
 

476 lines
12 KiB

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();
}
}
}