dxf: split into layer-key and block-partition workflows

This commit is contained in:
2026-04-13 09:22:03 +09:00
parent be58c7ed3c
commit bd79da2b64
13 changed files with 38154 additions and 0 deletions

119
dxf/layer_position_keys.mjs Normal file
View File

@@ -0,0 +1,119 @@
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}`);