3d-viewer/app/three/SceneView.ts

120 lines
3.2 KiB
TypeScript

import { AxesHelper, Group, Mesh, MeshStandardMaterial, Scene } from "three";
import { buildMeshes } from "./utils/build-meshes";
import { Extent, buildScene } from "./utils/build-scene";
import { getMetadata } from "./utils/utils";
import { MODEL_ID, SERVICE_URL } from "./config";
import { buildClippingplanes } from "./utils/build-clipping-planes";
import { buildCoordinateGrid } from "./utils/build-coordinate-grid";
import { DragControls } from "three/examples/jsm/Addons.js";
export class SceneView {
private _scene: Scene;
private _dragControls: DragControls;
private _model: Group;
constructor(scene: Scene, model: Group, dragControls: DragControls) {
this._scene = scene;
this._dragControls = dragControls;
this._model = model;
}
static async create(container: HTMLElement, modelId: string) {
const { scene, model, dragControls } = await init(container, modelId);
return new SceneView(scene, model, dragControls);
}
get scene() {
return this._scene;
}
get model() {
return this._model;
}
toggleClippingBox() {
const box = this._scene?.getObjectByName("clipping-box");
if (box) {
// Set DragControls
if (box.visible) {
this._dragControls.enabled = false;
} else {
this._dragControls.enabled = true;
}
box.visible = !box.visible;
}
}
toggleLayerVisibility(layerName: string) {
const mesh = this._model.getObjectByName(layerName);
if (mesh) {
mesh.visible = !mesh.visible;
}
}
toggleCoordinateGrid() {
const group = this._scene.getObjectByName("coordinate-grid");
if (group) {
group.visible = !group.visible;
}
}
toggleWireFrame() {
const model = this._model;
model.children.forEach((child) => {
const material = (child as Mesh).material as MeshStandardMaterial;
material.wireframe = !material.wireframe;
});
}
}
async function init(container: HTMLElement, modelId = MODEL_ID) {
const modelData = await getMetadata(SERVICE_URL + modelId);
const mappedFeatures = modelData.mappedfeatures;
const modelarea = modelData.modelarea;
const extent: Extent = {
xmin: modelarea.x.min,
xmax: modelarea.x.max,
ymin: modelarea.y.min,
ymax: modelarea.y.max,
zmin: modelarea.z.min,
zmax: modelarea.z.max,
};
const { renderer, scene, camera, controls } = buildScene(container, extent);
// Build the 3D model
const meshes = await buildMeshes(mappedFeatures);
const model = new Group();
model.add(...meshes);
model.name = "geologic-model";
scene.add(model);
// Build the clipping planes and add them to the scene
const { planes, dragControls } = buildClippingplanes(
renderer,
camera,
controls,
extent,
meshes,
scene
);
// Add clipping planes to the meshes
for (let mesh of meshes) {
mesh.material.clippingPlanes = planes;
}
// Add a coordinate grid to the scene
const { gridHelper, annotations } = buildCoordinateGrid(extent);
const annotationsGroup = new Group();
annotationsGroup.name = "coordinate-grid";
annotationsGroup.add(...annotations, gridHelper);
scene.add(annotationsGroup);
//const axesHelper = new AxesHelper(5);
//scene.add(axesHelper);
return { scene, model, dragControls };
}