From 4f4874d66f4187f81cc6de38c648e0a48c619f71 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Fri, 4 Aug 2023 06:38:41 -0500 Subject: [PATCH] Initial Connector Commit. --- src/diagram/diagramManager.ts | 20 ++++++- src/menus/MenuState.ts | 3 +- src/menus/editMenu.ts | 101 ++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/diagram/diagramManager.ts b/src/diagram/diagramManager.ts index 125336c..e2b432d 100644 --- a/src/diagram/diagramManager.ts +++ b/src/diagram/diagramManager.ts @@ -88,11 +88,29 @@ export class DiagramManager { newMesh.scaling = AppConfig.config.createSnapVal; } newMesh.material = mesh.material; - newMesh.metadata = mesh.metadata; + const metaCopy = this.deepCopy(mesh.metadata); + newMesh.metadata = metaCopy; DiagramShapePhysics.applyPhysics(newMesh, this.scene); return newMesh; } + private deepCopy ? V : never>(source: T): T { + if (Array.isArray(source)) { + return source.map(item => (this.deepCopy(item))) as T & U[] + } + if (source instanceof Date) { + return new Date(source.getTime()) as T & Date + } + if (source && typeof source === 'object') { + return (Object.getOwnPropertyNames(source) as (keyof T)[]).reduce((o, prop) => { + Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop)!) + o[prop] = this.deepCopy(source[prop]) + return o + }, Object.create(Object.getPrototypeOf(source))) + } + return source + } + private onRemoteEvent(event: DiagramEntity) { this.logger.debug(event); const toolMesh = this.scene.getMeshById("tool-" + event.template + "-" + event.color); diff --git a/src/menus/MenuState.ts b/src/menus/MenuState.ts index 17e56b7..7cc922f 100644 --- a/src/menus/MenuState.ts +++ b/src/menus/MenuState.ts @@ -3,6 +3,7 @@ export enum EditMenuState { LABELING, MODIFYING, // Editing an entity REMOVING, - COPYING // Removing an entity + COPYING, // Removing an entity + CONNECTING } \ No newline at end of file diff --git a/src/menus/editMenu.ts b/src/menus/editMenu.ts index 246e728..51d208c 100644 --- a/src/menus/editMenu.ts +++ b/src/menus/editMenu.ts @@ -1,9 +1,13 @@ import { AbstractMesh, + CreateGreasedLine, GizmoManager, + GreasedLineMesh, + GreasedLineTools, PointerEventTypes, PointerInfo, Scene, + TransformNode, Vector3, WebXRExperienceHelper } from "@babylonjs/core"; @@ -18,6 +22,82 @@ import {DiaSounds} from "../util/diaSounds"; import {CameraHelper} from "../util/cameraHelper"; import {TextLabel} from "../diagram/textLabel"; +class DiagramConnection { + private mesh: GreasedLineMesh; + private readonly scene: Scene; + private readonly fromPoint: Vector3 = new Vector3(); + private readonly toPoint: Vector3 = new Vector3(); + private toAnchor: TransformNode; + private pointerInfo: PointerInfo; + private points: Vector3[] = []; + + constructor(from: string, to: string, id: string, scene: Scene, pointerInfo: PointerInfo) { + this._from = from; + this._to = to; + this._id = id; + this.scene = scene; + this.pointerInfo = pointerInfo; + + if (from) { + const fromPoint = this.scene.getMeshById(from).getAbsolutePosition().clone(); + this.fromPoint.copyFrom(fromPoint); + this.toAnchor = new TransformNode("toAnchor", this.scene); + this.toAnchor.position = fromPoint; + this.toAnchor.setParent(pointerInfo.pickInfo.gripTransform); + this.buildConnection(); + } + } + + public _from: string; + + public get from(): string { + return this._from; + } + + public set from(value: string) { + this._from = value; + } + + public _to: string; + + public get to(): string { + return this._to; + } + + public set to(value: string) { + this._to = value; + } + + public _id: string; + + public get id(): string { + return this._id; + } + + private recalculate() { + this.points = [this.fromPoint, this.toAnchor.absolutePosition]; + } + + private setPoints() { + this.mesh.setPoints([GreasedLineTools.ToNumberArray(this.points)]); + } + + private buildConnection() { + this.scene.onBeforeRenderObservable.add(() => { + this.recalculate(); + this.setPoints(); + }); + + this.recalculate(); + + this.mesh = CreateGreasedLine("connection", + {points: (GreasedLineTools.ToNumberArray(this.points) as number[]), updatable: true}, null, this.scene); + + this.setPoints(); + //this.mesh.outlineColor = new Color3(0.5, 0.5, 1); + } +} + export class EditMenu { private state: EditMenuState = EditMenuState.NONE; private manager: GUI3DManager; @@ -26,6 +106,7 @@ export class EditMenu { private gizmoManager: GizmoManager; private readonly xr: WebXRExperienceHelper; private readonly diagramManager: DiagramManager; + private connection: DiagramConnection = null; constructor(scene: Scene, xr: WebXRExperienceHelper, diagramManager: DiagramManager) { this.scene = scene; @@ -69,6 +150,7 @@ export class EditMenu { panel.addControl(this.makeButton("Remove", "remove")); panel.addControl(this.makeButton("Add Label", "label")); panel.addControl(this.makeButton("Copy", "copy")); + panel.addControl(this.makeButton("Connect", "connect")); //panel.addControl(this.makeButton("Add Ring Cameras", "addRingCameras")); this.manager.controlScaling = .5; @@ -119,6 +201,22 @@ export class EditMenu { case EditMenuState.COPYING: this.setCopying(mesh); break; + case EditMenuState.CONNECTING: + this.setConnecting(mesh, pointerInfo); + break; + } + } + + private setConnecting(mesh: AbstractMesh, pointerInfo) { + if (this.connection) { + this.connection.to = mesh.id; + this.diagramManager.onDiagramEventObservable.notifyObservers({ + type: DiagramEventType.ADD, + entity: this.connection, + }); + this.connection = null; + } else { + this.connection = new DiagramConnection(mesh.id, null, null, this.scene, pointerInfo); } } @@ -189,6 +287,9 @@ export class EditMenu { case "copy": this.state = EditMenuState.COPYING; break; + case "connect": + this.state = EditMenuState.CONNECTING; + break; default: this.logger.error("Unknown button"); return;