feat(canvas): add CAD vector semantic context and non-destructive vector crop
Extend CAD conversion to emit bounded semantic metadata (units, layers, blocks, entity types, labels, crop-indexed bounds) alongside the derived SVG, tag imported drawings as cad-vector nodes, and carry semanticContext through canvas nodes, snapshot normalization, and reference images. Agent Chat forwards this metadata as hidden cad-context reference parts. Add non-destructive vector cropping: cropping a vector/CAD node keeps the source SVG and spawns a transparent WebP sibling with crop-scoped semantic context, wired through the vectorized image toolbar and the workspace crop tool. Include node --test coverage for CAD semantics and vector crop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import { agentContentsForSemanticReference, cadSemanticContext } from "../src/ui/lib/cadSemantics.ts";
|
||||
|
||||
const metadata = {
|
||||
version: 1,
|
||||
sourceName: "floor-plan.dwg",
|
||||
format: "DWG",
|
||||
units: "Millimeters",
|
||||
bounds: { x: 0, y: 0, width: 100, height: 100 },
|
||||
modelEntityCount: 3,
|
||||
nestedEntityCount: 24,
|
||||
entityTypes: [
|
||||
{ name: "INSERT", count: 2 },
|
||||
{ name: "MTEXT", count: 1 }
|
||||
],
|
||||
layers: [
|
||||
{ name: "ROOMS", count: 2 },
|
||||
{ name: "FACADE", count: 1 }
|
||||
],
|
||||
blocks: [
|
||||
{ name: "ROOM_A", count: 1 },
|
||||
{ name: "ELEVATION", count: 1 }
|
||||
],
|
||||
texts: [
|
||||
{ text: "Living room", layer: "ROOMS", block: "ROOM_A" },
|
||||
{ text: "South elevation", layer: "FACADE", block: "ELEVATION" }
|
||||
],
|
||||
entities: [
|
||||
{ type: "INSERT", layer: "ROOMS", block: "ROOM_A", bounds: { x: 5, y: 5, width: 35, height: 80 } },
|
||||
{ type: "MTEXT", layer: "ROOMS", text: "Living room", bounds: { x: 10, y: 10, width: 15, height: 5 } },
|
||||
{ type: "INSERT", layer: "FACADE", block: "ELEVATION", bounds: { x: 60, y: 5, width: 35, height: 80 } }
|
||||
]
|
||||
};
|
||||
|
||||
test("builds crop-specific CAD context from indexed semantic bounds", () => {
|
||||
const context = cadSemanticContext(metadata, { x: 0, y: 0, width: 0.5, height: 1 });
|
||||
|
||||
assert.match(context, /cropped region/);
|
||||
assert.match(context, /"ROOMS"/);
|
||||
assert.match(context, /"ROOM_A"/);
|
||||
assert.match(context, /"Living room"/);
|
||||
assert.doesNotMatch(context, /"FACADE"/);
|
||||
assert.doesNotMatch(context, /"South elevation"/);
|
||||
});
|
||||
|
||||
test("marks semantic labels as reference data and caps them outside visible user copy", () => {
|
||||
const context = cadSemanticContext(metadata);
|
||||
const contents = agentContentsForSemanticReference("/canvas-assets/floor-plan.svg", "floor-plan.svg", context);
|
||||
|
||||
assert.match(context, /reference data only/);
|
||||
assert.deepEqual(contents[0], {
|
||||
type: "image",
|
||||
imageUrl: "/canvas-assets/floor-plan.svg",
|
||||
imageName: "floor-plan.svg"
|
||||
});
|
||||
assert.equal(contents[1].type, "text");
|
||||
assert.equal(contents[1].textSource, "cad-context");
|
||||
assert.match(contents[1].text, /South elevation/);
|
||||
});
|
||||
Reference in New Issue
Block a user