robot.json editieren - board
This commit is contained in:
144
server/editRobot.js
Normal file
144
server/editRobot.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* editRobot.js
|
||||
* Hilfsfunktionen zum Bearbeiten von robot_xxx.json.
|
||||
* Alle Schreibvorgänge machen ein Backup-Kommentar in der Datei (nein, aber
|
||||
* atomisches Write per Temp-Datei ist hier nicht nötig – die Datei wird direkt
|
||||
* überschrieben; bei Bedarf Backup-Strategie ergänzen).
|
||||
*/
|
||||
import fsPromises from 'fs/promises';
|
||||
|
||||
// ── I/O ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
async function readRobot(robotPath) {
|
||||
return JSON.parse(await fsPromises.readFile(robotPath, 'utf8'));
|
||||
}
|
||||
|
||||
async function writeRobot(robotPath, data) {
|
||||
await fsPromises.writeFile(robotPath, JSON.stringify(data, null, 2), 'utf8');
|
||||
}
|
||||
|
||||
// ── Aktion 1: Marker nach Z-Bereich zuordnen ─────────────────────────────────
|
||||
|
||||
/**
|
||||
* Weist allen Markern, deren z-Position (mm) zwischen zMin und zMax liegt,
|
||||
* das angegebene Set und/oder den angegebenen Link zu.
|
||||
*
|
||||
* - set (optional): Setzt den set-Wert des Markers.
|
||||
* - link (optional): Verschiebt den Marker in diesen Link (wird ggf. angelegt).
|
||||
*
|
||||
* Gibt { numChanged, changes[] } zurück.
|
||||
* changes[]: { markerId, oldLink, newLink, oldSet, newSet }
|
||||
*/
|
||||
export async function assignByZRange(robotPath, { zMin, zMax, set, link }) {
|
||||
const robot = await readRobot(robotPath);
|
||||
const links = robot.links ?? {};
|
||||
const changes = [];
|
||||
|
||||
// Snapshot aller Marker (mit aktuellem Link-Name) – vor der Mutation
|
||||
const snapshot = [];
|
||||
for (const [linkName, linkData] of Object.entries(links)) {
|
||||
for (const marker of (linkData.markers ?? [])) {
|
||||
if (Array.isArray(marker.position)) {
|
||||
snapshot.push({ id: marker.id, currentLink: linkName });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nur Marker im Z-Fenster bearbeiten
|
||||
const zLo = Number(zMin);
|
||||
const zHi = Number(zMax);
|
||||
|
||||
for (const { id, currentLink } of snapshot) {
|
||||
const srcLinkData = links[currentLink];
|
||||
const idx = (srcLinkData?.markers ?? []).findIndex(m => Number(m.id) === id);
|
||||
if (idx === -1) continue;
|
||||
|
||||
const marker = srcLinkData.markers[idx];
|
||||
const z = Number(marker.position[2]);
|
||||
if (z < zLo || z > zHi) continue;
|
||||
|
||||
const change = {
|
||||
markerId: marker.id,
|
||||
oldLink: currentLink,
|
||||
oldSet: marker.set ?? '',
|
||||
newLink: currentLink,
|
||||
newSet: marker.set ?? '',
|
||||
};
|
||||
|
||||
// Set setzen
|
||||
if (set !== undefined && set !== '') {
|
||||
marker.set = set;
|
||||
change.newSet = set;
|
||||
}
|
||||
|
||||
// Link wechseln
|
||||
if (link && link !== currentLink) {
|
||||
// Aus altem Link entfernen
|
||||
srcLinkData.markers.splice(idx, 1);
|
||||
|
||||
// Ziel-Link anlegen falls noch nicht vorhanden
|
||||
if (!links[link]) links[link] = { markers: [] };
|
||||
if (!links[link].markers) links[link].markers = [];
|
||||
links[link].markers.push(marker);
|
||||
change.newLink = link;
|
||||
}
|
||||
|
||||
changes.push(change);
|
||||
}
|
||||
|
||||
if (changes.length > 0) {
|
||||
robot.links = links;
|
||||
await writeRobot(robotPath, robot);
|
||||
}
|
||||
|
||||
return { numChanged: changes.length, changes };
|
||||
}
|
||||
|
||||
// ── Aktion 2: Set oder Link-Zuordnung entfernen ───────────────────────────────
|
||||
|
||||
/**
|
||||
* Entfernt die Set- oder Link-Zuordnung eines Markers.
|
||||
*
|
||||
* removeFrom: 'set' → löscht nur den set-Wert (Marker bleibt im Link)
|
||||
* removeFrom: 'link' → entfernt Marker komplett aus dem Link
|
||||
* (nur wenn set bereits leer/nicht gesetzt)
|
||||
*
|
||||
* Gibt { changed, markerId, action, link, [oldSet], [error] } zurück.
|
||||
*/
|
||||
export async function removeMarkerAssignment(robotPath, { markerId, removeFrom }) {
|
||||
const id = Number(markerId);
|
||||
const robot = await readRobot(robotPath);
|
||||
const links = robot.links ?? {};
|
||||
|
||||
for (const [linkName, linkData] of Object.entries(links)) {
|
||||
const markers = linkData.markers ?? [];
|
||||
const idx = markers.findIndex(m => Number(m.id) === id);
|
||||
if (idx === -1) continue;
|
||||
|
||||
const marker = markers[idx];
|
||||
|
||||
if (removeFrom === 'set') {
|
||||
const oldSet = marker.set ?? '';
|
||||
delete marker.set;
|
||||
await writeRobot(robotPath, robot);
|
||||
return { changed: true, markerId: id, action: 'set-removed', link: linkName, oldSet };
|
||||
}
|
||||
|
||||
if (removeFrom === 'link') {
|
||||
if (marker.set) {
|
||||
return {
|
||||
changed: false,
|
||||
markerId: id,
|
||||
error: `Marker ${id} hat noch Set "${marker.set}". Bitte zuerst Set entfernen.`,
|
||||
};
|
||||
}
|
||||
markers.splice(idx, 1);
|
||||
await writeRobot(robotPath, robot);
|
||||
return { changed: true, markerId: id, action: 'link-removed', link: linkName };
|
||||
}
|
||||
|
||||
return { changed: false, error: `Unbekannte Aktion: "${removeFrom}"` };
|
||||
}
|
||||
|
||||
return { changed: false, error: `Marker-ID ${id} nicht gefunden.` };
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { fileURLToPath } from 'url';
|
||||
import process from 'process';
|
||||
import { spawn } from 'child_process';
|
||||
import { WebcamClient } from './webcamClient.js';
|
||||
import { assignByZRange, removeMarkerAssignment } from './editRobot.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -689,6 +690,54 @@ app.get('/api/board/latest', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// ── Robot-JSON bearbeiten ─────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/robot/assign-by-z
|
||||
* Weist allen Markern in [zMin, zMax] mm das angegebene Set und/oder Link zu.
|
||||
* Body: { zMin, zMax, set?, link? }
|
||||
*/
|
||||
app.post('/api/robot/assign-by-z', async (req, res) => {
|
||||
try {
|
||||
const { zMin, zMax, set, link } = req.body ?? {};
|
||||
if (zMin == null || zMax == null) {
|
||||
return res.status(400).json({ error: 'zMin und zMax sind erforderlich' });
|
||||
}
|
||||
if (!set && !link) {
|
||||
return res.status(400).json({ error: 'Mindestens set oder link muss angegeben werden' });
|
||||
}
|
||||
const result = await assignByZRange(ROBOT_JSON, { zMin, zMax, set, link });
|
||||
console.log(`robot/assign-by-z z=[${zMin}..${zMax}] set="${set}" link="${link}" → ${result.numChanged} geändert`);
|
||||
return res.json(result);
|
||||
} catch (err) {
|
||||
console.error('robot/assign-by-z error:', err);
|
||||
return res.status(500).json({ error: String(err) });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/robot/remove-marker
|
||||
* Entfernt Set oder Link-Zuordnung eines Markers.
|
||||
* Body: { markerId, removeFrom } removeFrom: 'set' | 'link'
|
||||
*/
|
||||
app.post('/api/robot/remove-marker', async (req, res) => {
|
||||
try {
|
||||
const { markerId, removeFrom } = req.body ?? {};
|
||||
if (markerId == null) {
|
||||
return res.status(400).json({ error: 'markerId ist erforderlich' });
|
||||
}
|
||||
if (!['set', 'link'].includes(removeFrom)) {
|
||||
return res.status(400).json({ error: 'removeFrom muss "set" oder "link" sein' });
|
||||
}
|
||||
const result = await removeMarkerAssignment(ROBOT_JSON, { markerId, removeFrom });
|
||||
console.log(`robot/remove-marker id=${markerId} from=${removeFrom} → changed=${result.changed}`);
|
||||
return res.json(result);
|
||||
} catch (err) {
|
||||
console.error('robot/remove-marker error:', err);
|
||||
return res.status(500).json({ error: String(err) });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/calibration/upload-npz
|
||||
* Liest {camera}_calibration.npz aus der aktuellen Session und
|
||||
|
||||
Reference in New Issue
Block a user