CAD/client/src/helpers/volatileGeometryHelper.ts

92 lines
2.6 KiB
TypeScript

import * as THREE from "three";
export type VolatileGeometry = {
mesh: THREE.Mesh,
}
export type VolatileGeometryBaseOptions = {
color: THREE.ColorRepresentation,
}
export type VolatileGeometryPointOptions = VolatileGeometryBaseOptions & {
kind: 'point',
size: number,
}
export type VolatileGeometryCicleOptions = VolatileGeometryBaseOptions & {
kind: 'circle',
radius: number,
thickness: number,
}
export type VolatileGeometryOptions = VolatileGeometryPointOptions | VolatileGeometryCicleOptions;
export class VolatileGeometryHelper {
private scene: THREE.Scene;
private camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
private readonly baseMaterial = new THREE.MeshBasicMaterial({ color: 'red' });
private readonly markers: Record<string, VolatileGeometry> = {};
constructor(scene: THREE.Scene, camera: THREE.PerspectiveCamera | THREE.OrthographicCamera) {
this.scene = scene;
this.camera = camera;
}
private createGeometry(options: VolatileGeometryOptions): THREE.BufferGeometry {
switch (options.kind) {
case 'point':
return new THREE.SphereGeometry(options.size);
case 'circle':
return new THREE.TorusGeometry(options.radius, options.thickness * options.radius);
default:
throw new Error('Unknown volatile geometry type');
}
}
private ensure(id: string, options: VolatileGeometryOptions): VolatileGeometry {
if (!this.markers[id]) {
const material = this.baseMaterial.clone();
material.color.set(options.color);
this.markers[id] = {
mesh: new THREE.Mesh(
this.createGeometry(options),
material,
),
};
this.scene.add(this.markers[id].mesh);
}
return this.markers[id];
}
private disposeGeometry(id: string) {
const point = this.markers[id];
if (point) {
this.scene.remove(point.mesh);
point.mesh.geometry.dispose();
delete (this.markers[id]);
}
}
public dispose() {
for (const id in this.markers)
this.disposeGeometry(id);
}
public set(id: string, position: THREE.Vector3Like, options: VolatileGeometryOptions) {
const point = this.ensure(id, options);
// additional actions
switch (options.kind) {
case 'circle':
point.mesh.lookAt(this.camera.position);
break;
}
point.mesh.position.copy(position);
}
}