260710_0
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||
import { RENDER_OPTIONS } from "@config/config_frontend";
|
||||
import type { SurfacePointCloudSampleResponse } from "./B04_wf1_Surface_Api_Fetch";
|
||||
|
||||
export interface SurfacePointCloudViewer {
|
||||
root: HTMLElement;
|
||||
render: (data: SurfacePointCloudSampleResponse | null) => void;
|
||||
dispose: () => void;
|
||||
}
|
||||
|
||||
export function createSurfacePointCloudViewer(): SurfacePointCloudViewer {
|
||||
const root = document.createElement("div");
|
||||
root.className = "b04-surface-viewer";
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.className = "b04-surface-viewer__canvas";
|
||||
root.append(canvas);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
canvas,
|
||||
antialias: RENDER_OPTIONS.antialias,
|
||||
});
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, RENDER_OPTIONS.maxPixelRatio));
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(RENDER_OPTIONS.canvasClearColorLight);
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
RENDER_OPTIONS.cameraFov,
|
||||
1,
|
||||
RENDER_OPTIONS.cameraNear,
|
||||
RENDER_OPTIONS.cameraFar,
|
||||
);
|
||||
const controls = new OrbitControls(camera, canvas);
|
||||
controls.enableDamping = true;
|
||||
|
||||
const grid = new THREE.GridHelper(
|
||||
200,
|
||||
20,
|
||||
RENDER_OPTIONS.gridCenterColor,
|
||||
RENDER_OPTIONS.gridLineColor,
|
||||
);
|
||||
scene.add(grid);
|
||||
|
||||
let pointsObject: THREE.Points | null = null;
|
||||
let animationFrame = 0;
|
||||
|
||||
function resize(): void {
|
||||
const rect = root.getBoundingClientRect();
|
||||
const width = Math.max(1, Math.floor(rect.width));
|
||||
const height = Math.max(1, Math.floor(rect.height));
|
||||
renderer.setSize(width, height, false);
|
||||
camera.aspect = width / height;
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
function animate(): void {
|
||||
resize();
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
animationFrame = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
function clearPoints(): void {
|
||||
if (!pointsObject) return;
|
||||
pointsObject.geometry.dispose();
|
||||
const material = pointsObject.material;
|
||||
if (Array.isArray(material)) material.forEach((item) => item.dispose());
|
||||
else material.dispose();
|
||||
scene.remove(pointsObject);
|
||||
pointsObject = null;
|
||||
}
|
||||
|
||||
function render(data: SurfacePointCloudSampleResponse | null): void {
|
||||
clearPoints();
|
||||
if (!data || data.points.length === 0) return;
|
||||
|
||||
const bounds = data.bounds;
|
||||
const cx = ((bounds.x_min ?? 0) + (bounds.x_max ?? 0)) / 2;
|
||||
const cy = ((bounds.y_min ?? 0) + (bounds.y_max ?? 0)) / 2;
|
||||
const cz = ((bounds.z_min ?? 0) + (bounds.z_max ?? 0)) / 2;
|
||||
const positions = new Float32Array(data.points.length * 3);
|
||||
data.points.forEach((point, index) => {
|
||||
positions[index * 3] = point[0] - cx;
|
||||
positions[index * 3 + 1] = point[2] - cz;
|
||||
positions[index * 3 + 2] = point[1] - cy;
|
||||
});
|
||||
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
|
||||
geometry.computeBoundingSphere();
|
||||
const material = new THREE.PointsMaterial({
|
||||
color: RENDER_OPTIONS.pointColor,
|
||||
size: 1.6,
|
||||
sizeAttenuation: false,
|
||||
});
|
||||
pointsObject = new THREE.Points(geometry, material);
|
||||
scene.add(pointsObject);
|
||||
|
||||
const radius = geometry.boundingSphere?.radius ?? 100;
|
||||
camera.position.set(radius * 0.9, radius * 0.7, radius * 1.4);
|
||||
camera.near = Math.max(RENDER_OPTIONS.cameraNear, radius / 10000);
|
||||
camera.far = Math.max(RENDER_OPTIONS.cameraFar, radius * 8);
|
||||
camera.updateProjectionMatrix();
|
||||
controls.target.set(0, 0, 0);
|
||||
controls.update();
|
||||
}
|
||||
|
||||
animationFrame = requestAnimationFrame(animate);
|
||||
|
||||
return {
|
||||
root,
|
||||
render,
|
||||
dispose: () => {
|
||||
cancelAnimationFrame(animationFrame);
|
||||
clearPoints();
|
||||
controls.dispose();
|
||||
renderer.dispose();
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user