import { Color3, MeshBuilder, Quaternion, Space, Vector3 } from "@babylonjs/core"; import { PointerEventTypes, PointerInfo } from "@babylonjs/core/Events/pointerEvents"; import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh"; import { Mesh } from "@babylonjs/core/Meshes/mesh"; import { EventState, Observer } from "@babylonjs/core/Misc/observable"; import { classToClass, plainToClass } from "class-transformer"; import { SceneManager } from "src/app/babylon/controller/scene-manager"; import { BabylonTool } from "src/app/babylon/tool/babylon-tool"; import { MarkWindow } from "src/app/babylon/view/mark-window/mark-window"; import { MarkData, MarkType } from "../../../data/mark/mark-data"; import { MarkData_multiArrow } from "../../../data/mark/other/mark-data-multi-arrow"; import { ModelInfo_mark } from "../model-info-mark"; /** * 多点的箭头 */ export class ModelInfo_mark_multiArrow extends ModelInfo_mark { arrowData: MarkData_multiArrow; onPointObserver: Observer; 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++; } } }