sophia_controller/ros_robot_visualiser/JointVisualiser.js

73 lines
2.8 KiB
JavaScript

import * as THREE from 'three';
export function createRotationSector(axis, lower, upper, encoderRange, radius = 0.1, segments = 32) {
const motorMargin = 0.4;
const motorLower = -encoderRange/2 * (Math.PI / 180);// -Math.PI/2;//lower - motorMargin;
const motorUpper = encoderRange/2 * (Math.PI / 180);//Math.PI/2;//upper + motorMargin;
const redMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, transparent: true, opacity: 0.2, side: THREE.DoubleSide, depthTest: false, depthWrite: false });
const whiteMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.6, side: THREE.DoubleSide, depthTest: false, depthWrite: false });
function createArc(start, end, material) {
const shape = new THREE.Shape();
shape.moveTo(0, 0);
for (let i = 0; i <= segments; i++) {
const angle = start + (end - start) * (i / segments);
shape.lineTo(Math.cos(angle) * radius, Math.sin(angle) * radius);
}
shape.lineTo(0, 0);
return new THREE.Mesh(new THREE.ShapeGeometry(shape), material);
}
const redLeft = createArc(motorLower, lower, redMaterial);
const whiteArc = createArc(lower, upper, whiteMaterial);
const redRight = createArc(upper, motorUpper, redMaterial);
const up = new THREE.Vector3(0, 0, 1);
const quaternion = new THREE.Quaternion().setFromUnitVectors(up, axis.clone().normalize());
const basis = new THREE.Matrix4().makeRotationFromQuaternion(quaternion);
redLeft.applyMatrix4(basis);
whiteArc.applyMatrix4(basis);
redRight.applyMatrix4(basis);
const group = new THREE.Group();
group.add(redLeft, whiteArc, redRight);
return group;
}
export function createAngleIndicator(axis, angle, radius = 0.1) {
const dir = new THREE.Vector3(Math.cos(angle), Math.sin(angle), 0).multiplyScalar(radius);
const geometry = new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(0, 0, 0), dir]);
const material = new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, depthWrite: false });
const line = new THREE.Line(geometry, material);
const up = new THREE.Vector3(0, 0, 1);
const quaternion = new THREE.Quaternion().setFromUnitVectors(up, axis.clone().normalize());
line.applyQuaternion(quaternion);
return line;
}
export function createJointLabel(name, angle) {
const canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 64;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = '20px monospace';
ctx.fillStyle = '#ffffff';
ctx.fillText(`${name}: ${(angle * 180 / Math.PI).toFixed(1)}°`, 10, 40);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, transparent: true });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.5, 0.125, 1); // adjust size
return sprite;
}