nenuscanner/static/calibration-visualiser.js

211 lines
6.5 KiB
JavaScript

import * as THREE from 'three';
import { OrbitControls } from 'orbit-controls';
class Pyramid extends THREE.Object3D {
constructor() {
super();
let width = 1;
let height = 1;
let length = 2;
let vertices = [
new THREE.Vector3( 0, 0, 0),
new THREE.Vector3( width, height, length),
new THREE.Vector3(-width, height, length),
new THREE.Vector3(-width, -height, length),
new THREE.Vector3( width, -height, length),
]
// Faces
{
let material = new THREE.MeshPhongMaterial({color: 0xffffff});
material.transparent = true;
material.opacity = 0.8;
let geometry = new THREE.BufferGeometry();
let faces = [
// Sides of the pyramid
[0, 2, 1],
[0, 3, 2],
[0, 4, 3],
[0, 1, 4],
// Base of the pyramid
[1, 2, 3],
[1, 3, 4],
]
let buffer = new Float32Array(3 * 3 * faces.length);
for (let faceIndex in faces) {
let face = faces[faceIndex];
buffer[faceIndex * 3 * 3 + 0] = vertices[face[0]].x;
buffer[faceIndex * 3 * 3 + 1] = vertices[face[0]].y;
buffer[faceIndex * 3 * 3 + 2] = vertices[face[0]].z;
buffer[faceIndex * 3 * 3 + 3] = vertices[face[1]].x;
buffer[faceIndex * 3 * 3 + 4] = vertices[face[1]].y;
buffer[faceIndex * 3 * 3 + 5] = vertices[face[1]].z;
buffer[faceIndex * 3 * 3 + 6] = vertices[face[2]].x;
buffer[faceIndex * 3 * 3 + 7] = vertices[face[2]].y;
buffer[faceIndex * 3 * 3 + 8] = vertices[face[2]].z;
}
geometry.setAttribute('position', new THREE.BufferAttribute(buffer, 3));
const mesh = new THREE.Mesh(geometry, material);
this.add(mesh);
}
// Lines
{
let material = new THREE.LineBasicMaterial({color: 0xff0000});
let geometry = new THREE.BufferGeometry();
let width = 1;
let height = 1;
let length = 2;
let lines = [
[0, 1],
[0, 2],
[0, 3],
[0, 4],
[1, 2],
[2, 3],
[3, 4],
[4, 1],
]
let buffer = new Float32Array(2 * 3 * lines.length);
for (let lineIndex in lines) {
let line = lines[lineIndex];
buffer[lineIndex * 2 * 3 + 0] = vertices[line[0]].x;
buffer[lineIndex * 2 * 3 + 1] = vertices[line[0]].y;
buffer[lineIndex * 2 * 3 + 2] = vertices[line[0]].z;
buffer[lineIndex * 2 * 3 + 3] = vertices[line[1]].x;
buffer[lineIndex * 2 * 3 + 4] = vertices[line[1]].y;
buffer[lineIndex * 2 * 3 + 5] = vertices[line[1]].z;
}
geometry.setAttribute('position', new THREE.BufferAttribute(buffer, 3));
const mesh = new THREE.Line(geometry, material);
this.add(mesh);
}
}
}
let renderer, scene, camera, controls, leds, cameraObject, domElement, raycaster, pointer, selectedObject;
async function init(dataPath, domElementArg = document.body) {
let request = await fetch('/api/calibration-data');
let data = await request.json();
domElement = domElementArg;
let w = domElement === document.body ? window.innerWidth : domElement.offsetWidth;
let h = domElement === document.body ? window.innerHeight : domElement.offsetHeight;
raycaster = new THREE.Raycaster();
camera = new THREE.PerspectiveCamera(45, w / h, 0.001, 1000);
camera.position.set(0, 0, -50);
scene = new THREE.Scene();
leds = new THREE.Object3D();
for (let key in data) {
let row = data[key];
const geometry = new THREE.SphereGeometry(1, 32, 16);
const material = new THREE.MeshPhongMaterial({ color: 0xffff00 });
let sphere = new THREE.Mesh(geometry, material);
sphere.position.x = row[0];
sphere.position.y = row[1];
sphere.position.z = row[2];
sphere.name = key
leds.add(sphere);
}
scene.add(leds);
cameraObject = new Pyramid();
scene.add(cameraObject);
const axesHelper = new THREE.AxesHelper(10);
scene.add(axesHelper);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
scene.add(directionalLight);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.25);
scene.add(ambientLight);
renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
renderer.setAnimationLoop(animate);
selectedObject = document.getElementById('selected-object');
// Add listeners
controls = new OrbitControls(camera, renderer.domElement);
controls.update();
window.addEventListener('pointermove', onPointerMove);
window.addEventListener('resize', onWindowResize, false);
onWindowResize();
domElement.appendChild(renderer.domElement);
}
function animate(time) {
controls.update();
if (pointer !== undefined) {
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(leds.children);
if (intersects.length > 0) {
for (let led of leds.children) {
if (led === intersects[0].object) {
led.material.color.setHex(0xff0000);
selectedObject.innerText = led.name;
} else {
led.material.color.setHex(0xffff00);
}
}
}
}
renderer.render(scene, camera);
}
function onWindowResize() {
let w = domElement === document.body ? window.innerWidth : domElement.offsetWidth;
let h = domElement === document.body ? window.innerHeight : domElement.offsetHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
}
function onPointerMove(event) {
// calculate pointer position in normalized device coordinates
// (-1 to +1) for both components
if (pointer === undefined) {
pointer = new THREE.Vector2();
}
let w = domElement === document.body ? window.innerWidth : domElement.offsetWidth;
let h = domElement === document.body ? window.innerHeight : domElement.offsetHeight;
pointer.x = (event.offsetX / w) * 2 - 1;
pointer.y = - (event.offsetY / h) * 2 + 1;
}
export { init };