Files
grotti/web/static/sweep-viewer.js
T

122 lines
4.1 KiB
JavaScript

/* Draufsicht: Schiebe-Bahn auf dem Kobra-3-Bett. */
(function (global) {
const BED_X = 250;
const BED_Y = 235;
function SweepViewer(canvas) {
this.canvas = canvas;
this.renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true });
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
this.scene = new THREE.Scene();
this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 100);
this.camera.position.set(0, 0, 10);
this.camera.lookAt(0, 0, 0);
this.root = new THREE.Group();
this.scene.add(this.root);
this._bed = null;
this._paths = null;
this._front = null;
this._resize();
}
SweepViewer.prototype._resize = function () {
const width = this.canvas.clientWidth || 280;
const height = this.canvas.clientHeight || 220;
this.renderer.setSize(width, height, false);
const aspect = width / height;
const worldW = BED_X * 1.12;
const worldH = BED_Y * 1.12;
let halfW = worldW / 2;
let halfH = worldH / 2;
if (halfW / halfH < aspect) halfW = halfH * aspect;
else halfH = halfW / aspect;
this.camera.left = -halfW;
this.camera.right = halfW;
this.camera.top = halfH;
this.camera.bottom = -halfH;
this.camera.updateProjectionMatrix();
this.renderer.render(this.scene, this.camera);
};
SweepViewer.prototype._clearGroup = function (name) {
const old = this[name];
if (!old) return;
this.root.remove(old);
old.traverse(function (obj) {
if (obj.geometry) obj.geometry.dispose();
if (obj.material) {
if (Array.isArray(obj.material)) obj.material.forEach((m) => m.dispose());
else obj.material.dispose();
}
});
this[name] = null;
};
SweepViewer.prototype.setSweep = function (step) {
const params = step || {};
const xFrom = Number(params.x_from);
const xTo = Number(params.x_to);
const xStep = Math.abs(Number(params.x_step) || 20);
const yFrom = Number(params.y_from);
const yTo = Number(params.y_to);
this._clearGroup("_bed");
this._clearGroup("_paths");
this._clearGroup("_front");
const bed = new THREE.Group();
const plate = new THREE.Mesh(
new THREE.PlaneGeometry(BED_X, BED_Y),
new THREE.MeshBasicMaterial({ color: 0x1a1a22, transparent: true, opacity: 0.95 })
);
bed.add(plate);
const edge = new THREE.LineSegments(
new THREE.EdgesGeometry(new THREE.PlaneGeometry(BED_X, BED_Y)),
new THREE.LineBasicMaterial({ color: 0x555566 })
);
bed.add(edge);
bed.position.set(BED_X / 2, BED_Y / 2, 0);
this.root.add(bed);
this._bed = bed;
const front = new THREE.Line(
new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(0, 0, 0.02),
new THREE.Vector3(BED_X, 0, 0.02),
]),
new THREE.LineBasicMaterial({ color: 0xf97316 })
);
this.root.add(front);
this._front = front;
const paths = new THREE.Group();
if (Number.isFinite(xFrom) && Number.isFinite(xTo) && Number.isFinite(yFrom) && Number.isFinite(yTo) && xStep > 0) {
const dir = xTo >= xFrom ? 1 : -1;
const points = [];
for (let x = xFrom, i = 0; dir > 0 ? x <= xTo + 0.01 : x >= xTo - 0.01; x += dir * xStep, i += 1) {
const yA = i % 2 === 0 ? yFrom : yTo;
const yB = i % 2 === 0 ? yTo : yFrom;
points.push(new THREE.Vector3(x, yA, 0.05), new THREE.Vector3(x, yB, 0.05));
if (dir > 0 ? x + dir * xStep <= xTo + 0.01 : x + dir * xStep >= xTo - 0.01) {
points.push(new THREE.Vector3(x, yB, 0.05), new THREE.Vector3(x + dir * xStep, yB, 0.05));
}
}
if (points.length >= 2) {
const geo = new THREE.BufferGeometry().setFromPoints(points);
paths.add(new THREE.LineSegments(geo, new THREE.LineBasicMaterial({ color: 0x3dce7c })));
}
}
this.root.add(paths);
this._paths = paths;
this._resize();
};
SweepViewer.prototype.dispose = function () {
this._clearGroup("_bed");
this._clearGroup("_paths");
this._clearGroup("_front");
this.renderer.dispose();
};
global.SweepViewer = SweepViewer;
})(window);