Claude: Kameras in Vizual
This commit is contained in:
@@ -267,6 +267,10 @@
|
||||
<span class="toggle-label">Board plane</span>
|
||||
<label class="toggle"><input type="checkbox" id="tBoard" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Cameras</span>
|
||||
<label class="toggle"><input type="checkbox" id="tCameras" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- stats -->
|
||||
@@ -543,7 +547,8 @@ const gObserved = new THREE.Group();
|
||||
const gObsNormals= new THREE.Group();
|
||||
const gErrors = new THREE.Group();
|
||||
const gBoard = new THREE.Group();
|
||||
scene.add(gSkeleton, gModel, gNormals, gObserved, gObsNormals, gErrors, gBoard);
|
||||
const gCameras = new THREE.Group();
|
||||
scene.add(gSkeleton, gModel, gNormals, gObserved, gObsNormals, gErrors, gBoard, gCameras);
|
||||
|
||||
// ─── toggle wiring ────────────────────────────────────────────
|
||||
const toggles = {
|
||||
@@ -554,6 +559,7 @@ const toggles = {
|
||||
tObsNormals:gObsNormals,
|
||||
tErrors: gErrors,
|
||||
tBoard: gBoard,
|
||||
tCameras: gCameras,
|
||||
};
|
||||
for (const [id, grp] of Object.entries(toggles)) {
|
||||
document.getElementById(id).addEventListener('change', e => {
|
||||
@@ -568,6 +574,7 @@ for (const [id, grp] of Object.entries(toggles)) {
|
||||
let robotData = null;
|
||||
let arucoData = null;
|
||||
let solutionData = null;
|
||||
let cameraData = [];
|
||||
const joints = { x:0, y:0, z:0, a:0, b:0, c:0, e:0 };
|
||||
|
||||
// ─── slider setup ─────────────────────────────────────────────
|
||||
@@ -651,7 +658,13 @@ document.getElementById('fRobot').addEventListener('change', async e => {
|
||||
document.getElementById('fAruco').addEventListener('change', async e => {
|
||||
if (!e.target.files[0]) return;
|
||||
arucoData = await readJSON(e.target.files[0]);
|
||||
setStatus('aruco/markers.json loaded');
|
||||
// Kamera-Posen aus derselben Datei übernehmen (falls vorhanden) → Frusta
|
||||
cameraData = (arucoData.cameras || []).map(c => ({
|
||||
pos_mm: c.position_mm || (c.position_m ? c.position_m.map(v => v * 1000) : null),
|
||||
dir: c.direction,
|
||||
id: c.camera_id
|
||||
})).filter(c => c.pos_mm && c.dir);
|
||||
setStatus('aruco geladen' + (cameraData.length ? ` (+ ${cameraData.length} Kameras)` : ''));
|
||||
rebuild();
|
||||
});
|
||||
|
||||
@@ -759,6 +772,24 @@ function r2vDir(rx, ry, rz) {
|
||||
return new THREE.Vector3(rx, rz, -ry).normalize();
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Camera frustum (halbtransparente Pyramide, Spitze = Linse)
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
function makeCameraFrustum(posThree, dirThree, size, hexColor) {
|
||||
const geo = new THREE.ConeGeometry(size * 0.6, size, 4);
|
||||
geo.translate(0, -size / 2, 0); // Spitze (Linse) an den lokalen Ursprung
|
||||
geo.rotateY(Math.PI / 4); // Pyramidenkanten ausrichten
|
||||
const mat = new THREE.MeshPhongMaterial({
|
||||
color: hexColor, transparent: true, opacity: 0.28,
|
||||
side: THREE.DoubleSide, depthWrite: false
|
||||
});
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.position.copy(posThree);
|
||||
const d = dirThree.clone().normalize();
|
||||
if (d.lengthSq() > 1e-9) m.quaternion.setFromUnitVectors(new THREE.Vector3(0, -1, 0), d);
|
||||
return m;
|
||||
}
|
||||
|
||||
function rebuild() {
|
||||
clearGroup(gSkeleton);
|
||||
clearGroup(gModel);
|
||||
@@ -767,6 +798,12 @@ function rebuild() {
|
||||
clearGroup(gObsNormals);
|
||||
clearGroup(gErrors);
|
||||
clearGroup(gBoard);
|
||||
clearGroup(gCameras);
|
||||
|
||||
// Kamera-Frusta hängen nicht vom Roboterzustand ab
|
||||
for (const cam of cameraData) {
|
||||
gCameras.add(makeCameraFrustum(r2vArr(cam.pos_mm), r2vDir(...cam.dir), 0.05, 0x9b7bff));
|
||||
}
|
||||
|
||||
if (!robotData) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user