Claude: Kameras in Vizual

This commit is contained in:
chk
2026-06-02 07:09:26 +02:00
parent cff4dfa176
commit 33a70c60c9
46 changed files with 1827 additions and 8323 deletions

View File

@@ -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;