120 lines
3.8 KiB
JavaScript
120 lines
3.8 KiB
JavaScript
import fs from "fs";
|
|
import path from "path";
|
|
import {
|
|
boundsFromPoints,
|
|
extractPolylineVertices,
|
|
first,
|
|
num,
|
|
parseDxfText,
|
|
pointsFromLWPolyline,
|
|
readDxfText,
|
|
} from "./lib/dxf_basic_parser.mjs";
|
|
|
|
function parseArgs(argv) {
|
|
const out = {};
|
|
for (let i = 0; i < argv.length; i += 1) {
|
|
const token = argv[i];
|
|
if (!token.startsWith("--")) continue;
|
|
const key = token.slice(2);
|
|
const value = argv[i + 1];
|
|
if (!value || value.startsWith("--")) continue;
|
|
out[key] = value;
|
|
i += 1;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
function normalizeLayer(layerName) {
|
|
return String(layerName || "0")
|
|
.trim()
|
|
.toUpperCase()
|
|
.replace(/[^A-Z0-9_]/g, "_");
|
|
}
|
|
|
|
function representativePoint(entity, entities, index) {
|
|
if (entity.type === "INSERT") return { point: { x: num(entity, 10), y: num(entity, 20) }, nextIndex: index };
|
|
if (entity.type === "LINE") {
|
|
const x1 = num(entity, 10);
|
|
const y1 = num(entity, 20);
|
|
const x2 = num(entity, 11);
|
|
const y2 = num(entity, 21);
|
|
return { point: { x: (x1 + x2) / 2, y: (y1 + y2) / 2 }, nextIndex: index };
|
|
}
|
|
if (entity.type === "CIRCLE" || entity.type === "ARC") {
|
|
return { point: { x: num(entity, 10), y: num(entity, 20) }, nextIndex: index };
|
|
}
|
|
if (entity.type === "LWPOLYLINE") {
|
|
const points = pointsFromLWPolyline(entity);
|
|
const box = boundsFromPoints(points);
|
|
return { point: box ? { x: box.cx, y: box.cy } : null, nextIndex: index };
|
|
}
|
|
if (entity.type === "POLYLINE") {
|
|
const parsed = extractPolylineVertices(entities, index);
|
|
const box = boundsFromPoints(parsed.points);
|
|
return { point: box ? { x: box.cx, y: box.cy } : null, nextIndex: parsed.nextIndex };
|
|
}
|
|
return { point: null, nextIndex: index };
|
|
}
|
|
|
|
function buildLayerPositionKeys(dxfPath, cellSize) {
|
|
const dxfText = readDxfText(dxfPath);
|
|
const { entities, headerBounds } = parseDxfText(dxfText);
|
|
const minX = Number.isFinite(headerBounds.minX) ? headerBounds.minX : 0;
|
|
const minY = Number.isFinite(headerBounds.minY) ? headerBounds.minY : 0;
|
|
|
|
const items = [];
|
|
const sequenceByLayer = new Map();
|
|
|
|
for (let i = 0; i < entities.length; i += 1) {
|
|
const entity = entities[i];
|
|
const layerRaw = first(entity, 8) ?? "0";
|
|
const layer = normalizeLayer(layerRaw);
|
|
|
|
const extracted = representativePoint(entity, entities, i);
|
|
i = extracted.nextIndex;
|
|
if (!extracted.point) continue;
|
|
|
|
const col = Math.floor((extracted.point.x - minX) / cellSize);
|
|
const row = Math.floor((extracted.point.y - minY) / cellSize);
|
|
const seq = (sequenceByLayer.get(layer) ?? 0) + 1;
|
|
sequenceByLayer.set(layer, seq);
|
|
|
|
const key = `${layer}::R${row}C${col}::${String(seq).padStart(4, "0")}`;
|
|
items.push({
|
|
key,
|
|
layer,
|
|
sourceLayer: layerRaw,
|
|
type: entity.type,
|
|
x: Number(extracted.point.x.toFixed(3)),
|
|
y: Number(extracted.point.y.toFixed(3)),
|
|
grid: { row, col },
|
|
});
|
|
}
|
|
|
|
const byLayer = {};
|
|
for (const item of items) byLayer[item.layer] = (byLayer[item.layer] ?? 0) + 1;
|
|
|
|
return {
|
|
meta: {
|
|
source: path.basename(dxfPath),
|
|
generatedAt: new Date().toISOString(),
|
|
cellSize,
|
|
entityCount: entities.length,
|
|
keyedItemCount: items.length,
|
|
bounds: headerBounds,
|
|
},
|
|
byLayer,
|
|
items,
|
|
};
|
|
}
|
|
|
|
const args = parseArgs(process.argv.slice(2));
|
|
const scriptDir = path.dirname(new URL(import.meta.url).pathname);
|
|
const dxfPath = path.resolve(args.input ?? path.join(scriptDir, "center.dxf"));
|
|
const outputPath = path.resolve(args.output ?? path.join(scriptDir, "layer_position_keys.json"));
|
|
const cellSize = Number(args.cell ?? 2000);
|
|
|
|
const result = buildLayerPositionKeys(dxfPath, Number.isFinite(cellSize) && cellSize > 0 ? cellSize : 2000);
|
|
fs.writeFileSync(outputPath, `${JSON.stringify(result, null, 2)}\n`, "utf8");
|
|
console.log(`saved: ${outputPath}`);
|