nenuscanner/ts/Led.ts

263 lines
7.2 KiB
TypeScript

import * as THREE from 'three';
import * as Calibration from './Calibration';
/**
* Helper to render leds as spheres.
*/
export class Led extends THREE.Mesh<THREE.SphereGeometry, THREE.MeshBasicMaterial> {
/** Whether the led is on or off. */
on: boolean;
/** Whether the mouse is hovering the led or not. */
isHovered: boolean;
/** Lines going from the sphere to the led. */
lines: THREE.LineSegments;
/** Point light to produce a nice lighting effect when the light is on. */
light: THREE.PointLight;
/**
* Creates a new led from its information and the spheres.
*/
constructor(ledInfo: Calibration.Led, spheres: Calibration.Vector3[]) {
super(
new THREE.SphereGeometry(0.7, 32, 16),
new THREE.MeshBasicMaterial({ color: 0x555500 }),
);
this.position.set(-ledInfo.position[1], -ledInfo.position[0], ledInfo.position[2]);
this.name = ledInfo.name;
this.layers.enable(1);
this.on = false;
this.isHovered = false;
const material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
let vertices = new Float32Array(3 * 2 * spheres.length);
for (let index = 0; index < ledInfo.directions.length; index++) {
let line = ledInfo.directions[index];
let sphere = spheres[index];
vertices[3 * 2 * index ] = -this.position.x - sphere[1];
vertices[3 * 2 * index + 1] = -this.position.y - sphere[0];
vertices[3 * 2 * index + 2] = -this.position.z + sphere[2];
vertices[3 * 2 * index + 3] = -line[1] * 100;
vertices[3 * 2 * index + 4] = -line[0] * 100;
vertices[3 * 2 * index + 5] = line[2] * 100;
}
let geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
this.lines = new THREE.LineSegments(geometry, material);
this.lines.visible = false;
this.add(this.lines);
this.light = new THREE.PointLight(0xffffff, 1000);
this.light.visible = false;
this.add(this.light);
}
/**
* Changes the style of the model to a nice hovered style.
*/
hover() {
if (this.on) {
return;
}
this.isHovered = true;
this.refreshColor();
}
/**
* Restores original style.
*/
unHover() {
if (this.on) {
return;
}
this.isHovered = false;
this.refreshColor();
}
/**
* Turn on the led if its off, turn it off if its on.
*/
toggle() {
this.on = !this.on;
this.refreshColor();
}
/**
* Changes the style of the model to make it visible that the led is on.
*/
turnOn(showLines: boolean) {
this.on = true;
this.light.visible = true;
for (let child of this.children) {
child.visible = true;
}
this.refreshColor();
this.lines.visible = showLines;
}
/**
* Changes the style of the model to make it visible that the led is off.
*/
turnOff() {
this.on = false;
this.light.visible = false;
for (let child of this.children) {
child.visible = false;
}
this.refreshColor();
this.lines.visible = false;
}
/**
* Refreshes the color according to the led state.
*/
refreshColor() {
this.material.color.setHex(this.getColor());
}
/**
* Shows or hides the lines from the spheres following the light direction.
*/
showLines(showLines: boolean) {
if (this.on) {
this.lines.visible = showLines;
}
}
/**
* Returns the hexadecimal value of the color of the led depending on the state.
*/
getColor() {
if (this.on) {
return 0xffff00;
} else if (this.isHovered) {
return 0x888800;
} else {
return 0x555500;
}
}
}
/**
* Container for all the leds that will help managing which led is on.
* Only one led can be on at a time.
*/
export class Leds extends THREE.Object3D {
/** Index of the led that is currently on, null if all leds are off. */
currentLedIndex: number | null;
/** Whether we need to show the lines of the leds. */
showLines: boolean;
/** A little light to be turned on when all leds are off, to show depth. */
light: THREE.PointLight;
/** Array of all the leds of the setup. */
leds: Array<Led>;
/**
* Create a set of leds from their configuration.
*/
constructor(calibration: Calibration.Calibration, showLines: boolean) {
super();
this.showLines = showLines;
this.currentLedIndex = null;
this.light = new THREE.PointLight(0xffffff, 1000);
this.add(this.light);
this.leds = [];
for (let ledInfo of calibration.leds) {
let led = new Led(ledInfo, calibration.spheres);
this.add(led);
this.leds.push(led);
}
}
/**
* Turns of the current led if any, and turns on the led given in argument.
* If the led given in argument is the one on, it will be turned off.
*/
toggle(led: Led): void {
// If the specified led is the one on.
if (this.currentLedIndex !== null && led === this.leds[this.currentLedIndex]) {
this.currentLedIndex = null;
led.turnOff();
this.light.visible = true;
return;
}
for (let index = 0; index < this.leds.length; index++) {
let child = this.leds[index];
if (led === this.leds[index]) {
child.turnOn(this.showLines);
this.currentLedIndex = index;
} else {
child.turnOff();
}
}
this.light.visible = false;
}
/**
* Changes whether we should show or not show the led lines.
*/
setShowLines(showLines: boolean): void {
this.showLines = showLines;
for (let child of this.leds) {
if (child instanceof Led && child.on) {
child.lines.visible = showLines;
}
}
}
/**
* Turn off the current led and goes to the next one.
*/
next(): Led {
if (this.currentLedIndex === null) {
this.currentLedIndex = 0;
let led = this.leds[0];
led.turnOn(this.showLines);
return led;
}
this.leds[this.currentLedIndex].turnOff();
this.currentLedIndex = (this.currentLedIndex + 1) % this.leds.length;
this.leds[this.currentLedIndex].turnOn(this.showLines);
return <Led> this.leds[this.currentLedIndex];
}
/**
* Turn off the current led and goes to the previous one.
*/
previous(): Led {
if (this.currentLedIndex === null) {
this.currentLedIndex = 0;
this.leds[0].turnOn(this.showLines);
return this.leds[0];
}
this.leds[this.currentLedIndex].turnOff();
this.currentLedIndex = (this.currentLedIndex + this.leds.length - 1) % this.leds.length;
let led = this.leds[this.currentLedIndex];
led.turnOn(this.showLines);
return led;
}
}