feat: add direct edit preview APIs
This commit is contained in:
@@ -4,12 +4,20 @@
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
const { loadOverrides, validateOverrides, writeJsonAtomic } = require('../src/compile/native-road');
|
||||
const {
|
||||
compileRoadModel,
|
||||
compileGeometry,
|
||||
loadOverrides,
|
||||
validateOverrides,
|
||||
writeJsonAtomic,
|
||||
} = require('../src/compile/native-road');
|
||||
const { generate, validateDocument, runtime } = require('../src/native-traffic-signals');
|
||||
const { convertGeoJson } = require('../src/reference/gaode');
|
||||
const { exportNativeRoadPackage } = require('../src/export/native-road-package');
|
||||
const { compileInput } = require('../src/compile/compiler');
|
||||
const { ensureRevisionStore, setActiveAreaConfig } = require('../src/compile/road-revisions');
|
||||
const { GEOMETRY_VERSION, resolveDirectEditConstraints } = require('../src/compile/direct-edit-solver');
|
||||
const { loadEditDocument, validateEditDocument } = require('../src/compile/native-road-edits');
|
||||
|
||||
function startWorkbench({
|
||||
area = null,
|
||||
@@ -69,6 +77,19 @@ function handle(request, response, session) {
|
||||
return area
|
||||
? sendJson(response, 200, state(area, junctionReference, debug))
|
||||
: sendJson(response, 200, { active: false });
|
||||
if (request.method === 'GET' && url.pathname === '/api/edit-state')
|
||||
return Promise.resolve()
|
||||
.then(() => (area ? editState(area) : { active: false }))
|
||||
.then((value) => sendJson(response, 200, value))
|
||||
.catch((error) => sendJson(response, 400, { ok: false, error: error.message }));
|
||||
if (request.method === 'POST' && url.pathname === '/api/edit-preview')
|
||||
return readBody(request)
|
||||
.then((body) => {
|
||||
if (!area) throw new Error('请先导入 OSM 文件。');
|
||||
return editPreview(area, body);
|
||||
})
|
||||
.then((value) => sendJson(response, 200, value))
|
||||
.catch((error) => sendJson(response, 400, { ok: false, error: error.message }));
|
||||
if (request.method === 'GET' && url.pathname === '/api/session')
|
||||
return sendJson(response, 200, { active: Boolean(session.area), areaId: session.area?.id || null });
|
||||
if (request.method === 'POST' && url.pathname === '/api/import')
|
||||
@@ -210,6 +231,83 @@ function state(area, junctionReference = null, debug = false) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function editState(area) {
|
||||
const workspace = path.dirname(area.input);
|
||||
const initialized = ensureRevisionStore(workspace, area.nativeRoad);
|
||||
const directEdits = loadEditDocument(initialized.paths.activeEdits);
|
||||
const model = compileRoadModel(fs.readFileSync(area.input, 'utf8'), loadOverrides(area.outputs.nativeRoadOverrides));
|
||||
const resolution = resolveDirectEditConstraints(model, directEdits, {
|
||||
revisionId: initialized.active.activeRevisionId,
|
||||
compilerGeometryVersion: GEOMETRY_VERSION,
|
||||
});
|
||||
return {
|
||||
active: true,
|
||||
areaId: area.id,
|
||||
activeRevisionId: initialized.active.activeRevisionId,
|
||||
documentVersion: directEdits.documentVersion,
|
||||
document: directEdits,
|
||||
constraintStates: resolution.constraintStates,
|
||||
diagnostics: resolution.diagnostics,
|
||||
handles: resolution.handles,
|
||||
};
|
||||
}
|
||||
|
||||
function editPreview(area, body = {}) {
|
||||
const startedAt = Date.now();
|
||||
const workspace = path.dirname(area.input);
|
||||
const activeEditsFile = path.join(workspace, 'active', 'native-road-edits.json');
|
||||
const activeStateFile = path.join(workspace, 'active', 'state.json');
|
||||
if (!fs.existsSync(activeEditsFile) || !fs.existsSync(activeStateFile))
|
||||
throw new Error('编辑工作区尚未初始化,请先重新导入 OSM 文件。');
|
||||
const activeEdits = loadEditDocument(activeEditsFile);
|
||||
const draft = body.document
|
||||
? validateEditDocument(body.document)
|
||||
: validateEditDocument({
|
||||
...activeEdits,
|
||||
...(Array.isArray(body.constraints) ? { constraints: body.constraints } : {}),
|
||||
...(Array.isArray(body.operations) ? { operations: body.operations } : {}),
|
||||
});
|
||||
const activeState = readJson(activeStateFile);
|
||||
const model = compileRoadModel(fs.readFileSync(area.input, 'utf8'), loadOverrides(area.outputs.nativeRoadOverrides));
|
||||
const previewSeq = Number.isInteger(body.previewSeq) ? body.previewSeq : 0;
|
||||
const resolution = resolveDirectEditConstraints(model, draft, {
|
||||
revisionId: activeState.activeRevisionId,
|
||||
previewSeq,
|
||||
compilerGeometryVersion: GEOMETRY_VERSION,
|
||||
});
|
||||
const compiled = compileGeometry(model, loadOverrides(area.outputs.nativeRoadOverrides), {
|
||||
edgeLines: area.nativeRoad.edgeLines,
|
||||
junctionTemplates: area.nativeRoad.junctionTemplates,
|
||||
directEdit: resolution,
|
||||
});
|
||||
const diagnostics = [...compiled.diagnostics, ...resolution.diagnostics];
|
||||
const degraded = Date.now() - startedAt > 300;
|
||||
return {
|
||||
ok: true,
|
||||
previewSeq,
|
||||
degraded,
|
||||
revisionId: activeState.activeRevisionId,
|
||||
documentVersion: activeEdits.documentVersion,
|
||||
constraintStates: resolution.constraintStates,
|
||||
diagnostics,
|
||||
handles: resolution.handles,
|
||||
layers: {
|
||||
roadSurface: compiled.roadSurface,
|
||||
edgeLines: compiled.edgeLines,
|
||||
sidewalkSurface: compiled.sidewalkSurface,
|
||||
intersectionSurface: compiled.intersectionSurface,
|
||||
laneCenterlines: compiled.laneCenterlines,
|
||||
laneSeparators: compiled.laneSeparators,
|
||||
centerLines: compiled.centerLines,
|
||||
directionArrows: compiled.directionArrows,
|
||||
turnArrows: compiled.turnArrows,
|
||||
crosswalks: compiled.crosswalks,
|
||||
vehicleStopLines: compiled.vehicleStopLines,
|
||||
connectors: compiled.connectors,
|
||||
},
|
||||
};
|
||||
}
|
||||
// The compiler reports candidates as advisory diagnostics. Lift them into their
|
||||
// own payload with a stable index so the map can label them "#1, #2, ..." and
|
||||
// the inspector can offer a ready-to-paste cluster配置.
|
||||
@@ -427,4 +525,4 @@ function sendJson(response, status, value) {
|
||||
response.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-store' });
|
||||
response.end(`${JSON.stringify(value)}\n`);
|
||||
}
|
||||
module.exports = { startWorkbench, readMultipart };
|
||||
module.exports = { startWorkbench, readMultipart, editState, editPreview };
|
||||
|
||||
Reference in New Issue
Block a user