import fs from "fs"; import path from "path"; import { boundsFromPoints, computeEntityListBounds, first, num, parseDxfText, readDxfText, transformPoint, } 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 toFixedNumber(value, fraction = 3) { return Number(Number(value).toFixed(fraction)); } function computeZoneKey(centerX, centerY, bounds, split) { const width = Math.max(1, bounds.maxX - bounds.minX); const height = Math.max(1, bounds.maxY - bounds.minY); const col = Math.min(split - 1, Math.max(0, Math.floor(((centerX - bounds.minX) / width) * split))); const row = Math.min(split - 1, Math.max(0, Math.floor(((centerY - bounds.minY) / height) * split))); return `Z-R${row + 1}C${col + 1}`; } function buildBlockPartitionData(dxfPath, split) { const { blocks, entities, headerBounds } = parseDxfText(readDxfText(dxfPath)); const drawingWidth = Math.max(1, headerBounds.maxX - headerBounds.minX); const drawingHeight = Math.max(1, headerBounds.maxY - headerBounds.minY); const drawingArea = drawingWidth * drawingHeight; const blockDefs = new Map(); for (const block of blocks) { const name = first(block, 2) ?? "*anonymous*"; const basePoint = { x: num(block, 10), y: num(block, 20) }; const localBounds = computeEntityListBounds(block.entities); blockDefs.set(name, { name, basePoint, localBounds, entityCount: block.entities.length, }); } const partitions = []; for (const entity of entities) { if (entity.type !== "INSERT") continue; const blockName = first(entity, 2) ?? ""; const blockLayer = first(entity, 8) ?? "0"; const blockDef = blockDefs.get(blockName); if (!blockDef || !blockDef.localBounds) continue; const insert = { x: num(entity, 10), y: num(entity, 20), rotation: num(entity, 50), xScale: num(entity, 41, 1), yScale: num(entity, 42, 1), }; const b = blockDef.localBounds; const corners = [ { x: b.minX, y: b.minY }, { x: b.maxX, y: b.minY }, { x: b.maxX, y: b.maxY }, { x: b.minX, y: b.maxY }, ].map((point) => transformPoint(point, insert, blockDef.basePoint)); const worldBounds = boundsFromPoints(corners); if (!worldBounds) continue; const area = Math.max(1, worldBounds.width * worldBounds.height); const oversized = area > drawingArea * 0.6 || worldBounds.width > drawingWidth * 0.9 || worldBounds.height > drawingHeight * 0.9; if (oversized) continue; const zoneKey = computeZoneKey(worldBounds.cx, worldBounds.cy, headerBounds, split); partitions.push({ id: `P-${String(partitions.length + 1).padStart(4, "0")}`, zoneKey, blockName, layer: blockLayer, handle: first(entity, 5) ?? "", rotation: toFixedNumber(insert.rotation, 2), scale: { x: toFixedNumber(insert.xScale, 4), y: toFixedNumber(insert.yScale, 4), }, center: { x: toFixedNumber(worldBounds.cx), y: toFixedNumber(worldBounds.cy), }, bounds: { minX: toFixedNumber(worldBounds.minX), minY: toFixedNumber(worldBounds.minY), maxX: toFixedNumber(worldBounds.maxX), maxY: toFixedNumber(worldBounds.maxY), width: toFixedNumber(worldBounds.width), height: toFixedNumber(worldBounds.height), }, blockEntityCount: blockDef.entityCount, }); } partitions.sort((a, b) => { const dy = b.center.y - a.center.y; if (Math.abs(dy) > 0.0001) return dy; return a.center.x - b.center.x; }); const byBlock = {}; const byZone = {}; for (const item of partitions) { byBlock[item.blockName] = (byBlock[item.blockName] ?? 0) + 1; byZone[item.zoneKey] = (byZone[item.zoneKey] ?? 0) + 1; } return { meta: { source: path.basename(dxfPath), generatedAt: new Date().toISOString(), split, partitionCount: partitions.length, blockDefinitionCount: blockDefs.size, headerBounds, }, byBlock, byZone, partitions, }; } function buildHtml(payload) { return ` DXF block partition report
Block partition map
Partition list ${payload.partitions.length} items
ID Zone Block Layer Size
`; } 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 outputJsonPath = path.resolve(args.json ?? path.join(scriptDir, "block_partition_report.json")); const outputHtmlPath = path.resolve(args.html ?? path.join(scriptDir, "block_partition_report.html")); const split = Math.max(2, Number(args.split ?? 4) || 4); const report = buildBlockPartitionData(dxfPath, split); fs.writeFileSync(outputJsonPath, `${JSON.stringify(report, null, 2)}\n`, "utf8"); fs.writeFileSync(outputHtmlPath, buildHtml(report), "utf8"); console.log(`saved: ${outputJsonPath}`); console.log(`saved: ${outputHtmlPath}`);