Keyboard shortcuts
This commit is contained in:
parent
75587e697b
commit
3be4e0a1c5
28
app.py
28
app.py
|
|
@ -15,17 +15,25 @@ def calibration():
|
|||
|
||||
@app.route("/api/calibration-data")
|
||||
def calibration_data():
|
||||
# Return dummy output
|
||||
return {
|
||||
'led_0040': [-5.55700564, 8.14046472, 10.54967666],
|
||||
'led_0090': [-7.06683588, 3.12804841, 6.68884105],
|
||||
'led_0070': [4.75589064, -4.53847239, 4.59339772],
|
||||
'led_0020': [-2.70015523, -9.65693344, 9.3807489],
|
||||
'led_0050': [3.26747465, 9.09127322, 8.52493055],
|
||||
'led_0010': [4.69548335, -7.92767838, 7.98930158],
|
||||
'led_0030': [-7.78342731, -3.88182141, 8.52941532],
|
||||
'led_0060': [9.8648123, 3.14267492, 10.09358765],
|
||||
'led_0080': [-3.3681401, -7.6538693, 6.36718535],
|
||||
'leds': [
|
||||
{'name': 'led_0010', 'position': [4.7568647, -7.99294013, 7.96453843]},
|
||||
{'name': 'led_0020', 'position': [-2.72752819, -9.82011953, 9.24452802]},
|
||||
{'name': 'led_0030', 'position': [-7.71848326, -3.84971189, 8.54659339]},
|
||||
{'name': 'led_0040', 'position': [-5.50536593, 8.13132868, 10.61159615]},
|
||||
{'name': 'led_0050', 'position': [3.2939535, 9.13207673, 8.55962855]},
|
||||
{'name': 'led_0060', 'position': [9.95077473, 3.18431267, 10.01643023]},
|
||||
{'name': 'led_0070', 'position': [4.80205465, -4.56261438, 4.56638023]},
|
||||
{'name': 'led_0080', 'position': [-3.37632619, -7.72890365, 6.26207315]},
|
||||
{'name': 'led_0090', 'position': [-7.05810901, 3.15661764, 6.64505902]}
|
||||
],
|
||||
'spheres': [
|
||||
[0.30415745, -0.17907307, 16.7683142],
|
||||
[3.98316763, 3.44079019, 17.03800586],
|
||||
[-2.83333147, 4.22778253, 16.95089368],
|
||||
[2.88769696, -4.29023411, 16.96762258],
|
||||
[-2.48223398, -4.19363008, 16.89485543],
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ def print_error(msg: str):
|
|||
|
||||
def calibrate(input_dir: str):
|
||||
# Load all images
|
||||
image_names = os.listdir(input_dir)
|
||||
image_names = sorted(os.listdir(input_dir))
|
||||
images = [np.asarray(Image.open(os.path.join(input_dir, x))) for x in image_names]
|
||||
|
||||
# Camera parameters
|
||||
|
|
@ -91,7 +91,7 @@ def calibrate(input_dir: str):
|
|||
light_positions = utils.lines_intersections(sphere_centers, estimated_lights)
|
||||
|
||||
# Return value as dictionnary
|
||||
return dict(zip(image_names, light_positions))
|
||||
return [{'name': name, 'position': position} for name, position in zip(image_names, light_positions)], sphere_centers
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
|||
|
|
@ -56,20 +56,20 @@ class Pyramid extends THREE.Object3D {
|
|||
|
||||
geometry.setAttribute('position', new THREE.BufferAttribute(buffer, 3));
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.layers.enable(1);
|
||||
this.mesh = mesh;
|
||||
this.add(mesh);
|
||||
}
|
||||
|
||||
// Lines
|
||||
{
|
||||
let material = new THREE.LineBasicMaterial({color: 0xff0000});
|
||||
let material = new THREE.LineBasicMaterial({color: 0x990000});
|
||||
let geometry = new THREE.BufferGeometry();
|
||||
|
||||
let width = 1;
|
||||
let height = 1;
|
||||
let length = 2;
|
||||
|
||||
|
||||
|
||||
let lines = [
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
|
|
@ -97,14 +97,82 @@ class Pyramid extends THREE.Object3D {
|
|||
|
||||
geometry.setAttribute('position', new THREE.BufferAttribute(buffer, 3));
|
||||
const mesh = new THREE.Line(geometry, material);
|
||||
mesh.layers.enable(1);
|
||||
this.lines = mesh;
|
||||
|
||||
this.add(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let renderer, scene, camera, controls, leds, cameraObject, domElement, raycaster, pointer, selectedObject, ledView;
|
||||
class Led extends THREE.Mesh {
|
||||
constructor() {
|
||||
super(
|
||||
new THREE.SphereGeometry(0.7, 32, 16),
|
||||
new THREE.MeshBasicMaterial({ color: 0x555500 }),
|
||||
);
|
||||
|
||||
this.on = false;
|
||||
this.isHovering = false;
|
||||
}
|
||||
|
||||
hover() {
|
||||
if (this.on) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isHovering = true;
|
||||
this.refreshColor();
|
||||
}
|
||||
|
||||
unhover() {
|
||||
if (this.on) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isHovering = false;
|
||||
this.refreshColor();
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.on = !this.on;
|
||||
this.refreshColor();
|
||||
}
|
||||
|
||||
turnOn() {
|
||||
this.on = true;
|
||||
this.refreshColor();
|
||||
}
|
||||
|
||||
|
||||
turnOff() {
|
||||
this.on = false;
|
||||
this.refreshColor();
|
||||
}
|
||||
|
||||
refreshColor() {
|
||||
this.material.color.setHex(this.getColor());
|
||||
}
|
||||
|
||||
getColor() {
|
||||
if (this.on) {
|
||||
return 0xffff00;
|
||||
} else if (this.isHovering) {
|
||||
return 0x888800;
|
||||
} else {
|
||||
return 0x555500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let center, renderer, scene, camera, controls, pointLight, leds, spheres, cameraObject, domElement, raycaster, pointer, selectedObject, ledView, animationStep, beforeAnimationPosition, beforeAnimationTarget;
|
||||
|
||||
async function init(dataPath, domElementArg = document.body) {
|
||||
center = new THREE.Vector3(0, 0, 10);
|
||||
animationStep = NaN;
|
||||
beforeAnimationPosition = new THREE.Vector3();
|
||||
beforeAnimationTarget = new THREE.Vector3();
|
||||
|
||||
let request = await fetch('/api/calibration-data');
|
||||
let data = await request.json();
|
||||
|
||||
|
|
@ -113,38 +181,53 @@ async function init(dataPath, domElementArg = document.body) {
|
|||
let h = domElement === document.body ? window.innerHeight : domElement.offsetHeight;
|
||||
|
||||
raycaster = new THREE.Raycaster();
|
||||
raycaster.layers.set(1);
|
||||
|
||||
camera = new THREE.PerspectiveCamera(45, w / h, 0.001, 1000);
|
||||
camera.position.set(0, 0, -50);
|
||||
camera.position.set(0, 0, -30);
|
||||
|
||||
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);
|
||||
for (let ledInfo of data.leds) {
|
||||
let row = ledInfo.position;
|
||||
let sphere = new Led();
|
||||
sphere.position.x = -row[1];
|
||||
sphere.position.y = -row[0];
|
||||
sphere.position.z = row[2];
|
||||
sphere.name = key
|
||||
sphere.name = ledInfo.name;
|
||||
sphere.layers.enable(1);
|
||||
leds.add(sphere);
|
||||
}
|
||||
|
||||
scene.add(leds);
|
||||
|
||||
let spheres = new THREE.Object3D();
|
||||
|
||||
for (let row of data.spheres) {
|
||||
const geometry = new THREE.SphereGeometry(1, 32, 16);
|
||||
const material = new THREE.MeshPhongMaterial({ color: 0xffffff });
|
||||
let sphere = new THREE.Mesh(geometry, material);
|
||||
sphere.position.x = -row[1];
|
||||
sphere.position.y = -row[0];
|
||||
sphere.position.z = row[2];
|
||||
sphere.layers.enable(1);
|
||||
spheres.add(sphere);
|
||||
}
|
||||
|
||||
scene.add(spheres);
|
||||
|
||||
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);
|
||||
pointLight = new THREE.PointLight(0xffffff, 0);
|
||||
scene.add(pointLight);
|
||||
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.25);
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.15);
|
||||
scene.add(ambientLight);
|
||||
|
||||
renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
|
||||
|
|
@ -155,11 +238,27 @@ async function init(dataPath, domElementArg = document.body) {
|
|||
|
||||
// Add listeners
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.zoomSpeed = 5;
|
||||
controls.target.copy(center);
|
||||
controls.update();
|
||||
|
||||
window.addEventListener('pointermove', onPointerMove);
|
||||
window.addEventListener('pointerup', onPointerUp);
|
||||
window.addEventListener('resize', onWindowResize, false);
|
||||
document.addEventListener('keyup', function(e) {
|
||||
switch (e.code) {
|
||||
case "ArrowDown":
|
||||
case "ArrowRight":
|
||||
nextLed();
|
||||
break;
|
||||
|
||||
case "ArrowUp":
|
||||
case "ArrowLeft":
|
||||
previousLed();
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
onWindowResize();
|
||||
|
||||
domElement.appendChild(renderer.domElement);
|
||||
|
|
@ -168,15 +267,46 @@ async function init(dataPath, domElementArg = document.body) {
|
|||
function animate(time) {
|
||||
controls.update();
|
||||
|
||||
if (!isNaN(animationStep)) {
|
||||
animationStep += 0.025;
|
||||
if (animationStep > 1) {
|
||||
controls.enabled = true;
|
||||
camera.position.set(0, 0, 0);
|
||||
controls.target.copy(center);
|
||||
animationStep = NaN;
|
||||
controls.update();
|
||||
} else {
|
||||
camera.position.set(0, 0, 0);
|
||||
camera.position.addScaledVector(beforeAnimationPosition, 1 - animationStep);
|
||||
controls.target.set(0, 0, 0);
|
||||
controls.target.addScaledVector(beforeAnimationTarget, 1 - animationStep);
|
||||
controls.target.addScaledVector(center, animationStep);
|
||||
controls.update();
|
||||
}
|
||||
}
|
||||
|
||||
if (pointer !== undefined) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(leds.children);
|
||||
const intersects = raycaster.intersectObjects(scene.children);
|
||||
const intersection = intersects.length > 0 ? intersects[0].object : undefined;
|
||||
|
||||
if (intersection && intersection.parent instanceof Pyramid) {
|
||||
cameraObject.mesh.material.opacity = 1;
|
||||
cameraObject.lines.material.color.setHex(0xff0000);
|
||||
} else {
|
||||
cameraObject.mesh.material.opacity = 0.8;
|
||||
cameraObject.lines.material.color.setHex(0x990000);
|
||||
}
|
||||
|
||||
if (intersection && intersection instanceof Led) {
|
||||
intersection.hover();
|
||||
}
|
||||
|
||||
for (let led of leds.children) {
|
||||
if (led === intersection) {
|
||||
led.scale.set(1.5, 1.5, 1.5);
|
||||
led.hover();
|
||||
} else {
|
||||
led.scale.set(1, 1, 1);
|
||||
led.unhover();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -209,16 +339,68 @@ function onPointerMove(event) {
|
|||
|
||||
function onPointerUp(event) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(leds.children);
|
||||
const intersects = raycaster.intersectObjects(scene.children);
|
||||
if (intersects.length > 0) {
|
||||
for (let led of leds.children) {
|
||||
if (led === intersects[0].object) {
|
||||
ledView.src = 'data/small/' + led.name + '.PNG';
|
||||
led.material.color.setHex(0xff0000);
|
||||
selectedObject.innerText = led.name;
|
||||
|
||||
if (intersects[0].object.parent instanceof Pyramid && intersects[0].distance > 1) {
|
||||
triggerAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (intersects[0].object instanceof Led) {
|
||||
selectLed(intersects[0].object);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function triggerAnimation() {
|
||||
beforeAnimationPosition.copy(camera.position);
|
||||
beforeAnimationTarget.copy(controls.target);
|
||||
animationStep = 0;
|
||||
controls.enabled = false;
|
||||
}
|
||||
|
||||
function nextLed() {
|
||||
for (let index = 0; index < leds.children.length; index++) {
|
||||
if (leds.children[index].on) {
|
||||
selectLed(leds.children[(index + 1) % leds.children.length]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
selectLed(leds.children[0]);
|
||||
}
|
||||
|
||||
function previousLed() {
|
||||
for (let index = 0; index < leds.children.length; index++) {
|
||||
if (leds.children[index].on) {
|
||||
selectLed(leds.children[(index - 1 + leds.children.length) % leds.children.length]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
selectLed(leds.children[0]);
|
||||
}
|
||||
|
||||
function selectLed(led) {
|
||||
for (let child of leds.children) {
|
||||
if (led === child) {
|
||||
if (led.on) {
|
||||
led.turnOff();
|
||||
pointLight.intensity = 0;
|
||||
ledView.style.display = "none";
|
||||
selectedObject.innerText = 'aucune';
|
||||
} else {
|
||||
led.material.color.setHex(0xffff00);
|
||||
led.turnOn();
|
||||
pointLight.intensity = 100;
|
||||
pointLight.position.copy(led.position);
|
||||
ledView.src = 'data/small/' + led.name + '.PNG';
|
||||
ledView.style.display = "block";
|
||||
selectedObject.innerText = led.name;
|
||||
}
|
||||
} else {
|
||||
child.turnOff();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<div id="visualiser-container">
|
||||
<div id="visualiser">
|
||||
<div id="info">
|
||||
Objet sélectionné : <span id="selected-object">aucun</span>
|
||||
LED sélectionnée : <span id="selected-object">aucune</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue