/* 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);