105 lines
3.3 KiB
JavaScript
105 lines
3.3 KiB
JavaScript
(() => {
|
|
function stripComment(line) {
|
|
const pos = line.indexOf("#");
|
|
return pos === -1 ? line : line.slice(0, pos);
|
|
}
|
|
|
|
function trim(s) {
|
|
return String(s || "").trim();
|
|
}
|
|
|
|
function parseOriginArray(value) {
|
|
const start = value.indexOf("[");
|
|
const end = value.indexOf("]");
|
|
if (start === -1 || end === -1 || end <= start) return null;
|
|
const parts = value
|
|
.slice(start + 1, end)
|
|
.split(",")
|
|
.map((p) => Number(trim(p)))
|
|
.filter((n) => !Number.isNaN(n));
|
|
if (parts.length < 2) return null;
|
|
return { origin_x: parts[0], origin_y: parts[1], origin_yaw: parts[2] || 0 };
|
|
}
|
|
|
|
function parseNumber(value) {
|
|
const n = Number(value);
|
|
return Number.isFinite(n) ? n : null;
|
|
}
|
|
|
|
function parseIntField(value) {
|
|
const n = parseInt(value, 10);
|
|
return Number.isFinite(n) ? n : null;
|
|
}
|
|
|
|
/**
|
|
* Parse ROS map_server yaml (resolution, origin, thresholds).
|
|
* @param {string} text
|
|
* @param {{ requireImage?: boolean }} opts
|
|
*/
|
|
function parse(text, opts = {}) {
|
|
const requireImage = !!opts.requireImage;
|
|
const out = {
|
|
image: "",
|
|
resolution: null,
|
|
origin_x: 0,
|
|
origin_y: 0,
|
|
origin_yaw: 0,
|
|
negate: 0,
|
|
occupied_thresh: 0.65,
|
|
free_thresh: 0.196,
|
|
};
|
|
|
|
for (const rawLine of String(text || "").split(/\r?\n/)) {
|
|
const line = trim(stripComment(rawLine));
|
|
if (!line) continue;
|
|
const colon = line.indexOf(":");
|
|
if (colon === -1) continue;
|
|
const key = trim(line.slice(0, colon));
|
|
const value = trim(line.slice(colon + 1));
|
|
if (!value && key !== "image") continue;
|
|
|
|
if (key === "image") out.image = value;
|
|
else if (key === "resolution") out.resolution = parseNumber(value);
|
|
else if (key === "origin") {
|
|
const origin = parseOriginArray(value);
|
|
if (origin) Object.assign(out, origin);
|
|
} else if (key === "negate") {
|
|
const n = parseIntField(value);
|
|
if (n != null) out.negate = n;
|
|
} else if (key === "occupied_thresh") {
|
|
const n = parseNumber(value);
|
|
if (n != null) out.occupied_thresh = n;
|
|
} else if (key === "free_thresh") {
|
|
const n = parseNumber(value);
|
|
if (n != null) out.free_thresh = n;
|
|
}
|
|
}
|
|
|
|
if (requireImage && !out.image) return { error: "yaml missing image field" };
|
|
if (out.resolution == null || out.resolution <= 0) return { error: "yaml missing resolution field" };
|
|
return out;
|
|
}
|
|
|
|
function serialize(meta) {
|
|
const image = meta.image || "map.png";
|
|
const resolution = meta.resolution != null ? meta.resolution : 0.05;
|
|
const ox = meta.origin_x != null ? meta.origin_x : 0;
|
|
const oy = meta.origin_y != null ? meta.origin_y : 0;
|
|
const oyaw = meta.origin_yaw != null ? meta.origin_yaw : 0;
|
|
const negate = meta.negate != null ? meta.negate : 0;
|
|
const occ = meta.occupied_thresh != null ? meta.occupied_thresh : 0.65;
|
|
const free = meta.free_thresh != null ? meta.free_thresh : 0.196;
|
|
return [
|
|
`image: ${image}`,
|
|
`resolution: ${Number(resolution).toFixed(6)}`,
|
|
`origin: [${Number(ox).toFixed(6)}, ${Number(oy).toFixed(6)}, ${Number(oyaw).toFixed(6)}]`,
|
|
`negate: ${negate}`,
|
|
`occupied_thresh: ${Number(occ).toFixed(3)}`,
|
|
`free_thresh: ${Number(free).toFixed(3)}`,
|
|
"",
|
|
].join("\n");
|
|
}
|
|
|
|
window.MapYaml = { parse, serialize };
|
|
})();
|