@snaptrude/plugin-core 0.0.0-dev-20260708130115 → 0.0.0-dev-20260827135706
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +152 -1
- package/api-manifest.json +3620 -276
- package/dist/api/analysis/daylight.d.ts +603 -0
- package/dist/api/analysis/daylight.d.ts.map +1 -0
- package/dist/api/analysis/heatmaps.d.ts +658 -0
- package/dist/api/analysis/heatmaps.d.ts.map +1 -0
- package/dist/api/analysis/illuminance.d.ts +145 -0
- package/dist/api/analysis/illuminance.d.ts.map +1 -0
- package/dist/api/analysis/index.d.ts +59 -0
- package/dist/api/analysis/index.d.ts.map +1 -0
- package/dist/api/analysis/shadows.d.ts +165 -0
- package/dist/api/analysis/shadows.d.ts.map +1 -0
- package/dist/api/analysis/solar.d.ts +249 -0
- package/dist/api/analysis/solar.d.ts.map +1 -0
- package/dist/api/analysis/sunlightHours.d.ts +208 -0
- package/dist/api/analysis/sunlightHours.d.ts.map +1 -0
- package/dist/api/analysis/sunpath.d.ts +80 -0
- package/dist/api/analysis/sunpath.d.ts.map +1 -0
- package/dist/api/analysis/weather.d.ts +193 -0
- package/dist/api/analysis/weather.d.ts.map +1 -0
- package/dist/api/core/camera/index.d.ts +261 -0
- package/dist/api/core/camera/index.d.ts.map +1 -0
- package/dist/api/core/comment/index.d.ts +105 -2
- package/dist/api/core/comment/index.d.ts.map +1 -1
- package/dist/api/core/geom/create/index.d.ts +840 -14
- package/dist/api/core/geom/create/index.d.ts.map +1 -1
- package/dist/api/core/geom/delete/index.d.ts +8 -2
- package/dist/api/core/geom/delete/index.d.ts.map +1 -1
- package/dist/api/core/geom/query/arc.d.ts +5 -5
- package/dist/api/core/geom/query/brep.d.ts +130 -18
- package/dist/api/core/geom/query/brep.d.ts.map +1 -1
- package/dist/api/core/geom/query/circle.d.ts +18 -18
- package/dist/api/core/geom/query/contour.d.ts +20 -20
- package/dist/api/core/geom/query/curve.d.ts +49 -49
- package/dist/api/core/geom/query/edge.d.ts +5 -5
- package/dist/api/core/geom/query/face.d.ts +16 -16
- package/dist/api/core/geom/query/halfedge.d.ts +8 -8
- package/dist/api/core/geom/query/profile.d.ts +19 -19
- package/dist/api/core/geom/query/vertex.d.ts +8 -8
- package/dist/api/core/geom/update/contour.d.ts +14 -14
- package/dist/api/core/geom/update/curve.d.ts +7 -7
- package/dist/api/core/geom/update/profile.d.ts +16 -16
- package/dist/api/core/handles/index.d.ts +210 -0
- package/dist/api/core/handles/index.d.ts.map +1 -0
- package/dist/api/core/index.d.ts +34 -0
- package/dist/api/core/index.d.ts.map +1 -1
- package/dist/api/core/io/export/index.d.ts +134 -0
- package/dist/api/core/io/export/index.d.ts.map +1 -0
- package/dist/api/core/io/import/index.d.ts +453 -0
- package/dist/api/core/io/import/index.d.ts.map +1 -0
- package/dist/api/core/io/index.d.ts +40 -0
- package/dist/api/core/io/index.d.ts.map +1 -0
- package/dist/api/core/io/job/index.d.ts +139 -0
- package/dist/api/core/io/job/index.d.ts.map +1 -0
- package/dist/api/core/io/query/index.d.ts +74 -0
- package/dist/api/core/io/query/index.d.ts.map +1 -0
- package/dist/api/core/io/terrain/index.d.ts +341 -0
- package/dist/api/core/io/terrain/index.d.ts.map +1 -0
- package/dist/api/core/io/underlay/index.d.ts +805 -0
- package/dist/api/core/io/underlay/index.d.ts.map +1 -0
- package/dist/api/core/layers.d.ts +7 -7
- package/dist/api/core/mode/index.d.ts +99 -0
- package/dist/api/core/mode/index.d.ts.map +1 -0
- package/dist/api/core/project/index.d.ts +68 -1
- package/dist/api/core/project/index.d.ts.map +1 -1
- package/dist/api/core/proposals/index.d.ts +531 -0
- package/dist/api/core/proposals/index.d.ts.map +1 -0
- package/dist/api/core/storeys/index.d.ts +265 -0
- package/dist/api/core/storeys/index.d.ts.map +1 -0
- package/dist/api/core/tags.d.ts +24 -0
- package/dist/api/core/tags.d.ts.map +1 -1
- package/dist/api/core/user.d.ts +44 -0
- package/dist/api/core/user.d.ts.map +1 -0
- package/dist/api/core/zoom/index.d.ts +4 -0
- package/dist/api/core/zoom/index.d.ts.map +1 -1
- package/dist/api/design/boolean/index.d.ts +4 -4
- package/dist/api/design/create/index.d.ts +568 -45
- package/dist/api/design/create/index.d.ts.map +1 -1
- package/dist/api/design/delete/index.d.ts +3 -0
- package/dist/api/design/delete/index.d.ts.map +1 -1
- package/dist/api/design/doors/index.d.ts +195 -0
- package/dist/api/design/doors/index.d.ts.map +1 -1
- package/dist/api/design/edit/index.d.ts +1 -1
- package/dist/api/design/erase/index.d.ts +2 -2
- package/dist/api/design/family.d.ts +349 -0
- package/dist/api/design/family.d.ts.map +1 -0
- package/dist/api/design/furniture/index.d.ts +181 -8
- package/dist/api/design/furniture/index.d.ts.map +1 -1
- package/dist/api/design/index.d.ts +98 -0
- package/dist/api/design/index.d.ts.map +1 -1
- package/dist/api/design/lock.d.ts +26 -0
- package/dist/api/design/lock.d.ts.map +1 -1
- package/dist/api/design/materials/index.d.ts +270 -16
- package/dist/api/design/materials/index.d.ts.map +1 -1
- package/dist/api/design/query/geometry/index.d.ts +112 -0
- package/dist/api/design/query/geometry/index.d.ts.map +1 -1
- package/dist/api/design/query/index.d.ts +282 -11
- package/dist/api/design/query/index.d.ts.map +1 -1
- package/dist/api/design/query/referenceLines.d.ts +45 -0
- package/dist/api/design/query/referenceLines.d.ts.map +1 -0
- package/dist/api/design/query/spaces.d.ts +181 -8
- package/dist/api/design/query/spaces.d.ts.map +1 -1
- package/dist/api/design/selection/index.d.ts +144 -0
- package/dist/api/design/selection/index.d.ts.map +1 -1
- package/dist/api/design/transform/index.d.ts +172 -10
- package/dist/api/design/transform/index.d.ts.map +1 -1
- package/dist/api/design/types/index.d.ts +181 -0
- package/dist/api/design/types/index.d.ts.map +1 -0
- package/dist/api/design/update/index.d.ts +553 -2
- package/dist/api/design/update/index.d.ts.map +1 -1
- package/dist/api/design/visibility.d.ts +126 -0
- package/dist/api/design/visibility.d.ts.map +1 -0
- package/dist/api/design/windows/index.d.ts +113 -2
- package/dist/api/design/windows/index.d.ts.map +1 -1
- package/dist/api/entity/buildableEnvelope.d.ts +4 -0
- package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
- package/dist/api/entity/referenceLine.d.ts +10 -2
- package/dist/api/entity/referenceLine.d.ts.map +1 -1
- package/dist/api/entity/space.d.ts +21 -21
- package/dist/api/entity/story.d.ts +242 -15
- package/dist/api/entity/story.d.ts.map +1 -1
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/presentation/aiInspiration.d.ts +25 -25
- package/dist/api/presentation/annotate.d.ts +467 -0
- package/dist/api/presentation/annotate.d.ts.map +1 -0
- package/dist/api/presentation/diagrams.d.ts +111 -8
- package/dist/api/presentation/diagrams.d.ts.map +1 -1
- package/dist/api/presentation/export.d.ts +108 -0
- package/dist/api/presentation/export.d.ts.map +1 -0
- package/dist/api/presentation/import.d.ts +55 -4
- package/dist/api/presentation/import.d.ts.map +1 -1
- package/dist/api/presentation/index.d.ts +58 -1
- package/dist/api/presentation/index.d.ts.map +1 -1
- package/dist/api/presentation/placedViews.d.ts +1139 -0
- package/dist/api/presentation/placedViews.d.ts.map +1 -0
- package/dist/api/presentation/shapes.d.ts +481 -0
- package/dist/api/presentation/shapes.d.ts.map +1 -0
- package/dist/api/presentation/sheets.d.ts +452 -13
- package/dist/api/presentation/sheets.d.ts.map +1 -1
- package/dist/api/presentation/slideshow.d.ts +125 -0
- package/dist/api/presentation/slideshow.d.ts.map +1 -0
- package/dist/api/presentation/tables.d.ts +81 -0
- package/dist/api/presentation/tables.d.ts.map +1 -0
- package/dist/api/presentation/views.d.ts +367 -7
- package/dist/api/presentation/views.d.ts.map +1 -1
- package/dist/api/program/areas.d.ts +102 -12
- package/dist/api/program/areas.d.ts.map +1 -1
- package/dist/api/program/cores.d.ts +3 -99
- package/dist/api/program/cores.d.ts.map +1 -1
- package/dist/api/program/index.d.ts +7 -15
- package/dist/api/program/index.d.ts.map +1 -1
- package/dist/api/program/layout.d.ts +346 -11
- package/dist/api/program/layout.d.ts.map +1 -1
- package/dist/api/program/site.d.ts +469 -13
- package/dist/api/program/site.d.ts.map +1 -1
- package/dist/api/program/spreadsheet.d.ts +365 -41
- package/dist/api/program/spreadsheet.d.ts.map +1 -1
- package/dist/api/workspace/index.d.ts +505 -0
- package/dist/api/workspace/index.d.ts.map +1 -0
- package/dist/errors/codes.d.ts +34 -0
- package/dist/errors/codes.d.ts.map +1 -0
- package/dist/errors/envelope.d.ts +56 -0
- package/dist/errors/envelope.d.ts.map +1 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/plugin-error.d.ts +69 -0
- package/dist/errors/plugin-error.d.ts.map +1 -0
- package/dist/handles.d.ts +97 -25
- package/dist/handles.d.ts.map +1 -1
- package/dist/host-utils.d.ts +4 -0
- package/dist/host-utils.d.ts.map +1 -1
- package/dist/index.cjs +4582 -1422
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4171 -1411
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/scripts/generate-manifest.mjs +45 -0
- package/scripts/generate-manifest.test.mjs +103 -4
- package/src/api/analysis/daylight.ts +470 -0
- package/src/api/analysis/heatmaps.ts +683 -0
- package/src/api/analysis/illuminance.ts +155 -0
- package/src/api/analysis/index.ts +61 -0
- package/src/api/analysis/shadows.ts +183 -0
- package/src/api/analysis/solar.ts +237 -0
- package/src/api/analysis/sunlightHours.ts +211 -0
- package/src/api/analysis/sunpath.ts +83 -0
- package/src/api/analysis/weather.ts +179 -0
- package/src/api/core/camera/index.ts +268 -0
- package/src/api/core/comment/index.ts +120 -2
- package/src/api/core/geom/create/index.ts +912 -1
- package/src/api/core/geom/delete/index.ts +6 -0
- package/src/api/core/geom/query/brep.ts +119 -0
- package/src/api/core/handles/index.ts +233 -0
- package/src/api/core/index.ts +34 -0
- package/src/api/core/io/export/index.ts +126 -0
- package/src/api/core/io/import/index.ts +496 -0
- package/src/api/core/io/index.ts +42 -0
- package/src/api/core/io/job/index.ts +140 -0
- package/src/api/core/io/query/index.ts +71 -0
- package/src/api/core/io/terrain/index.ts +360 -0
- package/src/api/core/io/underlay/index.ts +705 -0
- package/src/api/core/mode/index.ts +96 -0
- package/src/api/core/project/index.ts +62 -1
- package/src/api/core/proposals/index.ts +569 -0
- package/src/api/core/storeys/index.ts +294 -0
- package/src/api/core/tags.ts +27 -0
- package/src/api/core/user.ts +46 -0
- package/src/api/core/zoom/index.ts +4 -0
- package/src/api/design/create/index.ts +670 -30
- package/src/api/design/delete/index.ts +3 -0
- package/src/api/design/doors/index.ts +208 -0
- package/src/api/design/erase/index.ts +1 -1
- package/src/api/design/family.ts +388 -0
- package/src/api/design/furniture/index.ts +197 -8
- package/src/api/design/index.ts +102 -0
- package/src/api/design/lock.ts +27 -0
- package/src/api/design/materials/index.ts +334 -27
- package/src/api/design/query/geometry/index.ts +125 -3
- package/src/api/design/query/index.ts +217 -7
- package/src/api/design/query/referenceLines.ts +52 -0
- package/src/api/design/query/spaces.ts +143 -0
- package/src/api/design/selection/index.ts +129 -0
- package/src/api/design/transform/index.ts +170 -9
- package/src/api/design/types/index.ts +156 -0
- package/src/api/design/update/index.ts +631 -3
- package/src/api/design/visibility.ts +143 -0
- package/src/api/design/windows/index.ts +128 -2
- package/src/api/entity/buildableEnvelope.ts +4 -0
- package/src/api/entity/referenceLine.ts +8 -0
- package/src/api/entity/story.ts +259 -15
- package/src/api/index.ts +10 -0
- package/src/api/presentation/annotate.ts +385 -0
- package/src/api/presentation/diagrams.ts +118 -8
- package/src/api/presentation/export.ts +108 -0
- package/src/api/presentation/import.ts +51 -4
- package/src/api/presentation/index.ts +66 -1
- package/src/api/presentation/placedViews.ts +1120 -0
- package/src/api/presentation/shapes.ts +274 -0
- package/src/api/presentation/sheets.ts +400 -13
- package/src/api/presentation/slideshow.ts +134 -0
- package/src/api/presentation/tables.ts +84 -0
- package/src/api/presentation/views.ts +376 -8
- package/src/api/program/areas.ts +88 -15
- package/src/api/program/cores.ts +3 -91
- package/src/api/program/index.ts +7 -15
- package/src/api/program/layout.ts +365 -11
- package/src/api/program/site.ts +435 -13
- package/src/api/program/spreadsheet.ts +376 -35
- package/src/api/workspace/index.ts +563 -0
- package/src/errors/codes.ts +136 -0
- package/src/errors/envelope.ts +75 -0
- package/src/errors/index.ts +21 -0
- package/src/errors/plugin-error.ts +134 -0
- package/src/handles.ts +123 -13
- package/src/host-utils.ts +4 -0
- package/src/index.ts +1 -0
- package/test/errors.test.mjs +184 -0
- package/tsconfig.json +7 -2
|
@@ -0,0 +1,705 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import { PluginApiReturn } from "../../../../types"
|
|
3
|
+
import {
|
|
4
|
+
UnderlayHandle,
|
|
5
|
+
BBoxComponents,
|
|
6
|
+
Vec3Components,
|
|
7
|
+
} from "../../../../handles"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Underlays — inspect and edit the placed reference planes imported into the
|
|
11
|
+
* scene (`core.io.import.image` / `pdf` / `dwg` / `cadJson`).
|
|
12
|
+
*
|
|
13
|
+
* An underlay is an image, PDF, or CAD sketch dropped on a storey to trace over.
|
|
14
|
+
* This namespace lists them, calibrates their scale, sets opacity, and removes
|
|
15
|
+
* them. Every underlay is an {@linkcode UnderlayHandle}.
|
|
16
|
+
*
|
|
17
|
+
* ## Set-scale
|
|
18
|
+
* {@link PluginCoreIoUnderlayApi.setScale} takes **either** a numeric factor **or**
|
|
19
|
+
* a `{ planSize }` — the real-world length of the plan's longest side. A numeric
|
|
20
|
+
* factor is **absolute**: it is the total scale relative to the underlay's
|
|
21
|
+
* import-time size, the same number {@link PluginCoreIoUnderlayApi.getScale}
|
|
22
|
+
* returns as `scaleFactor` (so `setScale(u, 2)` is idempotent, and
|
|
23
|
+
* `setScale(u, (await getScale(u)).scaleFactor)` is a no-op). Use `planSize` to
|
|
24
|
+
* calibrate programmatically ("this plan is 50 m across") without clicking
|
|
25
|
+
* points on the canvas. Scale is supported for **image and PDF** underlays;
|
|
26
|
+
* **CAD scaling is not supported** (`getScale` returns `null`, `setScale`/`resetScale`
|
|
27
|
+
* throw). Image scale is tracked on the plan (and is **not undoable**); PDF scale is
|
|
28
|
+
* baked into the mesh (X/Z) and **is undoable**.
|
|
29
|
+
*
|
|
30
|
+
* Accessed via `snaptrude.core.io.underlay`.
|
|
31
|
+
*/
|
|
32
|
+
export abstract class PluginCoreIoUnderlayApi {
|
|
33
|
+
constructor() {}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* List the underlays in the scene, optionally limited to one storey.
|
|
37
|
+
*
|
|
38
|
+
* @param storey - When given, only underlays on this storey number.
|
|
39
|
+
* @returns an array of {@linkcode UnderlayHandle} (empty, never `null`).
|
|
40
|
+
*
|
|
41
|
+
* @examplePrompt List all the reference underlays in the model
|
|
42
|
+
* @examplePrompt What underlays are on the ground floor?
|
|
43
|
+
* @examplePrompt Show every imported floor plan and PDF
|
|
44
|
+
* @examplePrompt How many trace-over images are on storey 2?
|
|
45
|
+
*
|
|
46
|
+
* # Example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const underlays = await snaptrude.core.io.underlay.list(1)
|
|
49
|
+
* console.log(`${underlays.length} underlays on storey 1`)
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
public abstract list(storey?: number): PluginApiReturn<UnderlayHandle[]>
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Read an underlay's world-space bounding box (image, PDF, or CAD). `null` if
|
|
56
|
+
* the underlay no longer resolves or has no measurable mesh. Useful for fitting
|
|
57
|
+
* drawn geometry to a reference, or computing a plan size before scaling.
|
|
58
|
+
*
|
|
59
|
+
* @param underlay - The underlay to measure.
|
|
60
|
+
*
|
|
61
|
+
* @examplePrompt How big is this floor plan in the scene?
|
|
62
|
+
* @examplePrompt Get the bounding box of the underlay
|
|
63
|
+
* @examplePrompt What's the extent of the imported PDF?
|
|
64
|
+
* @examplePrompt Measure the CAD sketch's size
|
|
65
|
+
*
|
|
66
|
+
* # Example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const bb = await snaptrude.core.io.underlay.getBounds(plan)
|
|
69
|
+
* if (bb) console.log(`width ${bb.max.x - bb.min.x}`)
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
public abstract getBounds(
|
|
73
|
+
underlay: UnderlayHandle,
|
|
74
|
+
): PluginApiReturn<BBoxComponents | null>
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* List the distinct original AutoCAD layer names retained by a placed CAD
|
|
78
|
+
* underlay. Returns `[]` for non-CAD underlays, legacy imports created before
|
|
79
|
+
* source-layer retention, missing underlays, or CAD drawings without layer tags.
|
|
80
|
+
*
|
|
81
|
+
* @param underlay - The placed CAD underlay to inspect.
|
|
82
|
+
* @returns the retained AutoCAD layer names in first-appearance order.
|
|
83
|
+
*
|
|
84
|
+
* @examplePrompt List the original AutoCAD layers in this imported drawing
|
|
85
|
+
* @examplePrompt Which CAD layers are available in this underlay?
|
|
86
|
+
*
|
|
87
|
+
* # Example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const layers = await snaptrude.core.io.underlay.listCadLayers(cad)
|
|
90
|
+
* console.log(layers)
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
public abstract listCadLayers(
|
|
94
|
+
underlay: UnderlayHandle,
|
|
95
|
+
): PluginApiReturn<string[]>
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Read one original AutoCAD layer's retained line and arc geometry in
|
|
99
|
+
* **Snaptrude world space** and Snaptrude internal units. Results are paged so
|
|
100
|
+
* large drawings can be inspected without returning the whole DWG at once.
|
|
101
|
+
*
|
|
102
|
+
* The world-space coordinates include the CAD underlay's current position,
|
|
103
|
+
* rotation, scale, and storey elevation. `null` means the underlay no longer
|
|
104
|
+
* resolves. An unknown layer returns a page with `total: 0`.
|
|
105
|
+
*
|
|
106
|
+
* @param underlay - The placed CAD underlay to inspect.
|
|
107
|
+
* @param layer - Exact, case-sensitive original AutoCAD layer name.
|
|
108
|
+
* @param options - Optional zero-based offset and page limit (default 500,
|
|
109
|
+
* maximum 1000).
|
|
110
|
+
* @returns a page of retained CAD curves, or `null` if the underlay is gone.
|
|
111
|
+
* @throws if the handle resolves to an image/PDF rather than a CAD underlay.
|
|
112
|
+
*
|
|
113
|
+
* @examplePrompt Read the wall geometry from the A-WALL layer in this CAD underlay
|
|
114
|
+
* @examplePrompt Get the next 500 curves from the structural CAD layer
|
|
115
|
+
*
|
|
116
|
+
* # Example
|
|
117
|
+
* ```ts
|
|
118
|
+
* const page = await snaptrude.core.io.underlay.getCadLayerGeometry(
|
|
119
|
+
* cad,
|
|
120
|
+
* "A-WALL",
|
|
121
|
+
* { offset: 0, limit: 500 },
|
|
122
|
+
* )
|
|
123
|
+
* if (page) console.log(`${page.curves.length} of ${page.total} curves`)
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
public abstract getCadLayerGeometry(
|
|
127
|
+
underlay: UnderlayHandle,
|
|
128
|
+
layer: string,
|
|
129
|
+
options?: PluginCadLayerGeometryOptions,
|
|
130
|
+
): PluginApiReturn<PluginCadLayerGeometryPage | null>
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Read an underlay's scale. Works for **image and PDF** underlays. Returns
|
|
134
|
+
* `null` for CAD (scaling not supported) or if the handle no longer resolves.
|
|
135
|
+
*
|
|
136
|
+
* - `scaleFactor` — the **cumulative user scale** relative to the underlay's
|
|
137
|
+
* import-time size (`1` = as imported). This is the same number
|
|
138
|
+
* {@link PluginCoreIoUnderlayApi.setScale} accepts.
|
|
139
|
+
* - `initialScaleFactor` — the engine's import-time fit factor (how the raw
|
|
140
|
+
* image was sized to the canvas on import); informational only. For PDF it
|
|
141
|
+
* is always `1`.
|
|
142
|
+
*
|
|
143
|
+
* @param underlay - The underlay to read.
|
|
144
|
+
*
|
|
145
|
+
* @examplePrompt What scale is this floor plan set to?
|
|
146
|
+
* @examplePrompt Get the current and original scale of the underlay
|
|
147
|
+
* @examplePrompt How much has this image been scaled since import?
|
|
148
|
+
* @examplePrompt Read the scale factor of the reference plan
|
|
149
|
+
*
|
|
150
|
+
* # Example
|
|
151
|
+
* ```ts
|
|
152
|
+
* const s = await snaptrude.core.io.underlay.getScale(plan)
|
|
153
|
+
* if (s) console.log(`scale ${s.scaleFactor} (was ${s.initialScaleFactor})`)
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
public abstract getScale(
|
|
157
|
+
underlay: UnderlayHandle,
|
|
158
|
+
): PluginApiReturn<{ scaleFactor: number; initialScaleFactor: number } | null>
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Set an underlay's scale — the **calibration** step after import. Works for
|
|
162
|
+
* **image and PDF** underlays (CAD scaling is not supported — throws).
|
|
163
|
+
*
|
|
164
|
+
* Pass the `scale` argument as **either**:
|
|
165
|
+
* - a **number** — the **absolute** scale factor relative to the underlay's
|
|
166
|
+
* import-time size (e.g. `2` makes it twice its imported size, `0.5` half —
|
|
167
|
+
* no matter what the current scale is). It is the same number
|
|
168
|
+
* {@link PluginCoreIoUnderlayApi.getScale} returns as `scaleFactor`, so the
|
|
169
|
+
* call is idempotent: repeating `setScale(u, 2)` leaves the underlay at 2×.
|
|
170
|
+
* **Or**
|
|
171
|
+
* - a **`{ planSize }`** object — the real-world **length of the plan's longest
|
|
172
|
+
* side**, in the project's length unit. The factor is computed precisely so the
|
|
173
|
+
* underlay's longest side becomes exactly `planSize`. This is the way to
|
|
174
|
+
* calibrate programmatically without clicking points on the canvas: if you
|
|
175
|
+
* know the plan is 50 m across, pass `{ planSize: 50 }`.
|
|
176
|
+
*
|
|
177
|
+
* Image scale is not undoable; PDF scale is undoable.
|
|
178
|
+
*
|
|
179
|
+
* @param underlay - The underlay to scale (image or PDF).
|
|
180
|
+
* @param scale - An absolute numeric factor, **or** `{ planSize }` (the real
|
|
181
|
+
* length of the underlay's longest side, in project units).
|
|
182
|
+
* @returns the applied `{ scaleFactor }` (the new absolute factor).
|
|
183
|
+
* @throws if writes are disabled, the underlay is CAD / can't be resolved, the plan
|
|
184
|
+
* has zero size, or the engine fails.
|
|
185
|
+
*
|
|
186
|
+
* @examplePrompt Scale this floor plan so it's 50 meters across
|
|
187
|
+
* @examplePrompt Set the plan size to 30m — it's imported too small
|
|
188
|
+
* @examplePrompt Make the reference image twice its imported size
|
|
189
|
+
* @examplePrompt Calibrate the PDF: the site is 120 meters long
|
|
190
|
+
*
|
|
191
|
+
* # Example
|
|
192
|
+
* ```ts
|
|
193
|
+
* // Absolute factor — set the underlay to 2× its imported size:
|
|
194
|
+
* await snaptrude.core.io.underlay.setScale(plan, 2)
|
|
195
|
+
*
|
|
196
|
+
* // Fit to a real-world size — make the plan's longest side 50 project-units:
|
|
197
|
+
* await snaptrude.core.io.underlay.setScale(plan, { planSize: 50 })
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
public abstract setScale(
|
|
201
|
+
underlay: UnderlayHandle,
|
|
202
|
+
scale: number | { planSize: number },
|
|
203
|
+
): PluginApiReturn<{ scaleFactor: number }>
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Reset an underlay's scale back to its import-time size (image or PDF; CAD
|
|
207
|
+
* scaling is not supported — throws). Equivalent to `setScale(underlay, 1)`.
|
|
208
|
+
*
|
|
209
|
+
* @param underlay - The underlay to reset (image or PDF).
|
|
210
|
+
* @returns the restored `{ scaleFactor }` (`1`).
|
|
211
|
+
* @throws if writes are disabled, the underlay is CAD / can't be resolved, or the engine fails.
|
|
212
|
+
*
|
|
213
|
+
* @examplePrompt Reset this floor plan's scale to how it was imported
|
|
214
|
+
* @examplePrompt Undo the scaling on the underlay
|
|
215
|
+
* @examplePrompt Put the reference image back to its original size
|
|
216
|
+
* @examplePrompt Restore the plan's default scale
|
|
217
|
+
*
|
|
218
|
+
* # Example
|
|
219
|
+
* ```ts
|
|
220
|
+
* await snaptrude.core.io.underlay.resetScale(plan)
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
public abstract resetScale(
|
|
224
|
+
underlay: UnderlayHandle,
|
|
225
|
+
): PluginApiReturn<{ scaleFactor: number }>
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Read an underlay's opacity (`0`..`1`), or `null` if it has no material.
|
|
229
|
+
*
|
|
230
|
+
* @param underlay - The underlay to read.
|
|
231
|
+
*
|
|
232
|
+
* @examplePrompt How transparent is this underlay?
|
|
233
|
+
* @examplePrompt Get the opacity of the floor plan
|
|
234
|
+
* @examplePrompt What's the fade level on the reference image?
|
|
235
|
+
* @examplePrompt Read the underlay's opacity
|
|
236
|
+
*
|
|
237
|
+
* # Example
|
|
238
|
+
* ```ts
|
|
239
|
+
* const o = await snaptrude.core.io.underlay.getOpacity(plan)
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
public abstract getOpacity(
|
|
243
|
+
underlay: UnderlayHandle,
|
|
244
|
+
): PluginApiReturn<number | null>
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Set an underlay's opacity (`0` = transparent .. `1` = opaque). Undoable.
|
|
248
|
+
* The engine keeps underlays faintly visible: values below `0.01` clamp to
|
|
249
|
+
* `0.01`, so `setOpacity(u, 0)` reads back as `0.01`, not `0`.
|
|
250
|
+
*
|
|
251
|
+
* @param underlay - The underlay to change.
|
|
252
|
+
* @param opacity - Target opacity, `0`..`1` (engine floor `0.01`).
|
|
253
|
+
* @throws if writes are disabled, the underlay can't be resolved, or the
|
|
254
|
+
* underlay is **locked** (unlock it in the app first).
|
|
255
|
+
*
|
|
256
|
+
* @examplePrompt Fade this floor plan to 30% so I can see through it
|
|
257
|
+
* @examplePrompt Make the underlay half transparent
|
|
258
|
+
* @examplePrompt Set the reference image opacity to 0.2
|
|
259
|
+
* @examplePrompt Dim the trace-over plan
|
|
260
|
+
*
|
|
261
|
+
* # Example
|
|
262
|
+
* ```ts
|
|
263
|
+
* await snaptrude.core.io.underlay.setOpacity(plan, 0.3)
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
public abstract setOpacity(
|
|
267
|
+
underlay: UnderlayHandle,
|
|
268
|
+
opacity: number,
|
|
269
|
+
): PluginApiReturn<void>
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Delete an underlay from the scene (and its backend record). Applies to image,
|
|
273
|
+
* PDF, and CAD underlays.
|
|
274
|
+
*
|
|
275
|
+
* @param underlay - The underlay to delete.
|
|
276
|
+
* @throws if writes are disabled or the underlay can't be resolved.
|
|
277
|
+
*
|
|
278
|
+
* @examplePrompt Delete this floor plan underlay
|
|
279
|
+
* @examplePrompt Remove the imported PDF from the scene
|
|
280
|
+
* @examplePrompt Get rid of the CAD sketch I traced over
|
|
281
|
+
* @examplePrompt Clear the reference image off storey 1
|
|
282
|
+
*
|
|
283
|
+
* # Example
|
|
284
|
+
* ```ts
|
|
285
|
+
* const [first] = await snaptrude.core.io.underlay.list(1)
|
|
286
|
+
* if (first) await snaptrude.core.io.underlay.delete(first)
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
public abstract delete(underlay: UnderlayHandle): PluginApiReturn<void>
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Extract **continuous wall centrelines** from one retained AutoCAD layer's
|
|
293
|
+
* double-line wall faces — the deterministic tracing primitive behind
|
|
294
|
+
* CAD-to-BIM wall conversion. Instead of paging raw curves and re-deriving
|
|
295
|
+
* the geometry in worker code, this reads the whole layer and runs the vetted
|
|
296
|
+
* pipeline: cull fragments, dedupe, merge collinear runs into *faces*, pair
|
|
297
|
+
* parallel faces a wall-thickness apart into centrelines (midline = axis,
|
|
298
|
+
* separation = thickness), bridge collinear gaps up to
|
|
299
|
+
* `bridgeOpenings.maxWidth` into ONE continuous centreline while recording
|
|
300
|
+
* each bridged span as an opening, then snap near-touching endpoints at
|
|
301
|
+
* junctions.
|
|
302
|
+
*
|
|
303
|
+
* CAD drafters interrupt wall faces at every door/window, so raw wall layers
|
|
304
|
+
* always have gaps; Snaptrude doors/windows must host into a continuous wall.
|
|
305
|
+
* The returned centrelines are ready for `design.create.walls`, and each
|
|
306
|
+
* centreline's `openings` records where the CAD had a gap — feed those to the
|
|
307
|
+
* door/window placement step. `unpaired` faces (no parallel partner at wall
|
|
308
|
+
* thickness) are evidence, not noise: a run of unpaired perimeter faces
|
|
309
|
+
* usually means that stretch of facade is glazed, not solid.
|
|
310
|
+
*
|
|
311
|
+
* All lengths are in **Snaptrude internal units** (convert from project units
|
|
312
|
+
* with `core.units.convert`). Coordinates are world-space plan (x, z).
|
|
313
|
+
*
|
|
314
|
+
* Thin parallel pairs (glass lines, mullion faces) are the same algorithm at
|
|
315
|
+
* a smaller separation: pass e.g. `thicknessRange: [0.01, 0.25]` with
|
|
316
|
+
* `bridgeOpenings: null` to detect glazing runs on a glazing layer.
|
|
317
|
+
*
|
|
318
|
+
* @param underlay - The placed CAD underlay to read.
|
|
319
|
+
* @param layer - Exact, case-sensitive original AutoCAD layer name.
|
|
320
|
+
* @param options - Tolerances; see {@linkcode PluginCadCenterlineOptions}.
|
|
321
|
+
* @returns centrelines + unpaired faces + stats, or `null` if the underlay is gone.
|
|
322
|
+
* @throws if the handle resolves to an image/PDF rather than a CAD underlay.
|
|
323
|
+
*
|
|
324
|
+
* @examplePrompt Trace the walls from the a-wall CAD layer
|
|
325
|
+
* @examplePrompt Convert the AutoCAD wall linework into Snaptrude walls
|
|
326
|
+
* @examplePrompt Extract wall centrelines with thickness from the imported DWG
|
|
327
|
+
* @examplePrompt Find the glazing runs on the a-glazing layer
|
|
328
|
+
*
|
|
329
|
+
* # Example
|
|
330
|
+
* ```ts
|
|
331
|
+
* const [cad] = await snaptrude.core.io.underlay.list()
|
|
332
|
+
* const r = await snaptrude.core.io.underlay.extractCenterlines(cad, "a-wall")
|
|
333
|
+
* if (r) {
|
|
334
|
+
* const items = r.centerlines.map((c) => ({
|
|
335
|
+
* profile: [c.start, c.end],
|
|
336
|
+
* thickness: c.thickness,
|
|
337
|
+
* }))
|
|
338
|
+
* console.log(`${items.length} walls, ${r.unpaired.length} unpaired faces`)
|
|
339
|
+
* }
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
public abstract extractCenterlines(
|
|
343
|
+
underlay: UnderlayHandle,
|
|
344
|
+
layer: string,
|
|
345
|
+
options?: PluginCadCenterlineOptions,
|
|
346
|
+
): PluginApiReturn<PluginCadCenterlinesResult | null>
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Classify one retained AutoCAD layer's **arcs as door swings** — the
|
|
350
|
+
* deterministic tracing primitive behind CAD-to-BIM door placement. A door
|
|
351
|
+
* swing is drawn as a ~90° arc whose radius IS the leaf width and whose
|
|
352
|
+
* centre IS the hinge point. This filters the layer's arcs by plausible
|
|
353
|
+
* radius and sweep (rejecting inch-scale fillets, full-circle symbols and
|
|
354
|
+
* long shallow curves), reads each survivor as a door candidate (hinge, leaf
|
|
355
|
+
* width, swing direction, hosting wall direction), merges mirrored pairs
|
|
356
|
+
* sharing a chord line into double doors, and returns a radius histogram —
|
|
357
|
+
* real drawings use a handful of standard door sizes, so the histogram's
|
|
358
|
+
* clusters are the drawing's door widths (sanity-check them against the
|
|
359
|
+
* catalog; distrust arcs in no cluster).
|
|
360
|
+
*
|
|
361
|
+
* All lengths are in **Snaptrude internal units**. `rejected` lists filtered
|
|
362
|
+
* arcs with reasons so nothing is silently dropped.
|
|
363
|
+
*
|
|
364
|
+
* @param underlay - The placed CAD underlay to read.
|
|
365
|
+
* @param layer - Exact, case-sensitive original AutoCAD layer name.
|
|
366
|
+
* @param options - Gates and binning; see {@linkcode PluginCadArcClassifyOptions}.
|
|
367
|
+
* @returns door candidates + rejected arcs + histogram, or `null` if the underlay is gone.
|
|
368
|
+
* @throws if the handle resolves to an image/PDF rather than a CAD underlay.
|
|
369
|
+
*
|
|
370
|
+
* @examplePrompt Find the doors on the a-door CAD layer
|
|
371
|
+
* @examplePrompt Classify the door swing arcs in the imported drawing
|
|
372
|
+
* @examplePrompt What door sizes does this DWG use?
|
|
373
|
+
* @examplePrompt Read hinge points and leaf widths from the CAD door layer
|
|
374
|
+
*
|
|
375
|
+
* # Example
|
|
376
|
+
* ```ts
|
|
377
|
+
* const [cad] = await snaptrude.core.io.underlay.list()
|
|
378
|
+
* const r = await snaptrude.core.io.underlay.classifyArcs(cad, "a-door")
|
|
379
|
+
* if (r) {
|
|
380
|
+
* console.log(`${r.doors.length} doors; sizes:`,
|
|
381
|
+
* r.radiusHistogram.filter((b) => b.count > 1))
|
|
382
|
+
* }
|
|
383
|
+
* ```
|
|
384
|
+
*/
|
|
385
|
+
public abstract classifyArcs(
|
|
386
|
+
underlay: UnderlayHandle,
|
|
387
|
+
layer: string,
|
|
388
|
+
options?: PluginCadArcClassifyOptions,
|
|
389
|
+
): PluginApiReturn<PluginCadArcClassifyResult | null>
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Arguments for {@link PluginCoreIoUnderlayApi.list}.
|
|
394
|
+
*
|
|
395
|
+
* | Property | Type | Description |
|
|
396
|
+
* |---|---|---|
|
|
397
|
+
* | `storey` | `number`? | Only underlays on this storey (default: all) |
|
|
398
|
+
*/
|
|
399
|
+
export const PluginUnderlayListArgs = z.object({
|
|
400
|
+
storey: z.number().int().optional(),
|
|
401
|
+
})
|
|
402
|
+
export type PluginUnderlayListArgs = z.infer<typeof PluginUnderlayListArgs>
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Fit-to-size calibration: the real-world **length of the plan's longest side**, in
|
|
406
|
+
* the project's length unit. Passed to {@link PluginCoreIoUnderlayApi.setScale}; the
|
|
407
|
+
* factor is computed as `planSize / currentLongestSide`.
|
|
408
|
+
*
|
|
409
|
+
* | Property | Type | Description |
|
|
410
|
+
* |---|---|---|
|
|
411
|
+
* | `planSize` | `number` | Real-world length of the underlay's longest side (project units) |
|
|
412
|
+
*/
|
|
413
|
+
export const PluginUnderlayPlanSize = z.object({
|
|
414
|
+
planSize: z.number().positive(),
|
|
415
|
+
})
|
|
416
|
+
export type PluginUnderlayPlanSize = z.infer<typeof PluginUnderlayPlanSize>
|
|
417
|
+
|
|
418
|
+
/** The `scale` argument of {@link PluginCoreIoUnderlayApi.setScale}: a direct factor or a `{ planSize }`. */
|
|
419
|
+
export const PluginUnderlaySetScaleValue = z.union([
|
|
420
|
+
z.number().positive(),
|
|
421
|
+
PluginUnderlayPlanSize,
|
|
422
|
+
])
|
|
423
|
+
export type PluginUnderlaySetScaleValue = z.infer<
|
|
424
|
+
typeof PluginUnderlaySetScaleValue
|
|
425
|
+
>
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Arguments for {@link PluginCoreIoUnderlayApi.setScale}.
|
|
429
|
+
*
|
|
430
|
+
* | Property | Type | Description |
|
|
431
|
+
* |---|---|---|
|
|
432
|
+
* | `underlay` | {@link UnderlayHandle} | The image/PDF underlay to scale |
|
|
433
|
+
* | `scale` | `number \| {@link PluginUnderlayPlanSize}` | Direct factor, or `{ planSize }` |
|
|
434
|
+
*/
|
|
435
|
+
export const PluginUnderlaySetScaleArgs = z.object({
|
|
436
|
+
underlay: UnderlayHandle,
|
|
437
|
+
scale: PluginUnderlaySetScaleValue,
|
|
438
|
+
})
|
|
439
|
+
export type PluginUnderlaySetScaleArgs = z.infer<
|
|
440
|
+
typeof PluginUnderlaySetScaleArgs
|
|
441
|
+
>
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Arguments for {@link PluginCoreIoUnderlayApi.setOpacity}.
|
|
445
|
+
*
|
|
446
|
+
* | Property | Type | Description |
|
|
447
|
+
* |---|---|---|
|
|
448
|
+
* | `underlay` | {@link UnderlayHandle} | The underlay to change |
|
|
449
|
+
* | `opacity` | `number` | Target opacity, `0`..`1` |
|
|
450
|
+
*/
|
|
451
|
+
export const PluginUnderlaySetOpacityArgs = z.object({
|
|
452
|
+
underlay: UnderlayHandle,
|
|
453
|
+
opacity: z.number().min(0).max(1),
|
|
454
|
+
})
|
|
455
|
+
export type PluginUnderlaySetOpacityArgs = z.infer<
|
|
456
|
+
typeof PluginUnderlaySetOpacityArgs
|
|
457
|
+
>
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Arguments for the single-underlay methods
|
|
461
|
+
* ({@link PluginCoreIoUnderlayApi.getScale} / `resetScale` / `getOpacity` / `delete`).
|
|
462
|
+
*
|
|
463
|
+
* | Property | Type | Description |
|
|
464
|
+
* |---|---|---|
|
|
465
|
+
* | `underlay` | {@link UnderlayHandle} | The target underlay |
|
|
466
|
+
*/
|
|
467
|
+
export const PluginUnderlayRefArgs = z.object({
|
|
468
|
+
underlay: UnderlayHandle,
|
|
469
|
+
})
|
|
470
|
+
export type PluginUnderlayRefArgs = z.infer<typeof PluginUnderlayRefArgs>
|
|
471
|
+
|
|
472
|
+
/** A retained AutoCAD line represented as a world-space read record. */
|
|
473
|
+
export const PluginCadLineGeometry = z.object({
|
|
474
|
+
type: z.literal("line"),
|
|
475
|
+
start: Vec3Components,
|
|
476
|
+
end: Vec3Components,
|
|
477
|
+
})
|
|
478
|
+
export type PluginCadLineGeometry = z.infer<typeof PluginCadLineGeometry>
|
|
479
|
+
|
|
480
|
+
/** A retained AutoCAD arc represented as a world-space read record. */
|
|
481
|
+
export const PluginCadArcGeometry = z.object({
|
|
482
|
+
type: z.literal("arc"),
|
|
483
|
+
centre: Vec3Components,
|
|
484
|
+
axis: Vec3Components,
|
|
485
|
+
start: Vec3Components,
|
|
486
|
+
end: Vec3Components,
|
|
487
|
+
})
|
|
488
|
+
export type PluginCadArcGeometry = z.infer<typeof PluginCadArcGeometry>
|
|
489
|
+
|
|
490
|
+
/** Line or arc geometry returned by `getCadLayerGeometry`. */
|
|
491
|
+
export const PluginCadGeometry = z.discriminatedUnion("type", [
|
|
492
|
+
PluginCadLineGeometry,
|
|
493
|
+
PluginCadArcGeometry,
|
|
494
|
+
])
|
|
495
|
+
export type PluginCadGeometry = z.infer<typeof PluginCadGeometry>
|
|
496
|
+
|
|
497
|
+
/** Pagination options for `getCadLayerGeometry`. */
|
|
498
|
+
export const PluginCadLayerGeometryOptions = z.object({
|
|
499
|
+
offset: z.number().int().nonnegative().default(0),
|
|
500
|
+
limit: z.number().int().positive().max(1000).default(500),
|
|
501
|
+
})
|
|
502
|
+
export type PluginCadLayerGeometryOptions = z.input<
|
|
503
|
+
typeof PluginCadLayerGeometryOptions
|
|
504
|
+
>
|
|
505
|
+
|
|
506
|
+
/** Arguments for {@link PluginCoreIoUnderlayApi.getCadLayerGeometry}. */
|
|
507
|
+
export const PluginCadLayerGeometryArgs = z.object({
|
|
508
|
+
underlay: UnderlayHandle,
|
|
509
|
+
layer: z.string(),
|
|
510
|
+
options: PluginCadLayerGeometryOptions.default({ offset: 0, limit: 500 }),
|
|
511
|
+
})
|
|
512
|
+
export type PluginCadLayerGeometryArgs = z.infer<
|
|
513
|
+
typeof PluginCadLayerGeometryArgs
|
|
514
|
+
>
|
|
515
|
+
|
|
516
|
+
/** A page of one original AutoCAD layer's geometry in Snaptrude world space. */
|
|
517
|
+
export const PluginCadLayerGeometryPage = z.object({
|
|
518
|
+
layer: z.string(),
|
|
519
|
+
coordinateSpace: z.literal("snaptrude-world"),
|
|
520
|
+
units: z.literal("snaptrude-internal"),
|
|
521
|
+
total: z.number().int().nonnegative(),
|
|
522
|
+
offset: z.number().int().nonnegative(),
|
|
523
|
+
curves: z.array(PluginCadGeometry),
|
|
524
|
+
})
|
|
525
|
+
export type PluginCadLayerGeometryPage = z.infer<
|
|
526
|
+
typeof PluginCadLayerGeometryPage
|
|
527
|
+
>
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
/** A point in the world-space plan (x, z) projection, Snaptrude internal units. */
|
|
531
|
+
export const PluginPlanPoint = z.object({ x: z.number(), z: z.number() })
|
|
532
|
+
export type PluginPlanPoint = z.infer<typeof PluginPlanPoint>
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Options for {@link PluginCoreIoUnderlayApi.extractCenterlines}. All lengths in
|
|
536
|
+
* Snaptrude internal units.
|
|
537
|
+
*
|
|
538
|
+
* | Property | Type | Description |
|
|
539
|
+
* |---|---|---|
|
|
540
|
+
* | `thicknessRange` | `[number, number]`? | Plausible wall thickness `[min, max]` (default `[0.3, 1.6]` ≈ 3–16 in) |
|
|
541
|
+
* | `mergeGap` | `number`? | Noise tolerance joining collinear segments that are really one face (default `0.05`) |
|
|
542
|
+
* | `minLength` | `number`? | Cull fragments shorter than this (default `0.1`) |
|
|
543
|
+
* | `parallelTolDeg` | `number`? | Max angle in degrees between faces still considered parallel (default `2`) |
|
|
544
|
+
* | `minOverlap` | `number`? | Fraction of the shorter face that must overlap its pair (default `0.6`) |
|
|
545
|
+
* | `bridgeOpenings` | `{ maxWidth }` \| `null`? | Close collinear centreline gaps up to `maxWidth`, recording each as an opening (default `{ maxWidth: 9.6 }` ≈ 8 ft); `null` disables bridging |
|
|
546
|
+
*/
|
|
547
|
+
export const PluginCadCenterlineOptions = z.object({
|
|
548
|
+
thicknessRange: z
|
|
549
|
+
.tuple([z.number().positive(), z.number().positive()])
|
|
550
|
+
.default([0.3, 1.6]),
|
|
551
|
+
mergeGap: z.number().nonnegative().default(0.05),
|
|
552
|
+
minLength: z.number().nonnegative().default(0.1),
|
|
553
|
+
parallelTolDeg: z.number().positive().max(15).default(2),
|
|
554
|
+
minOverlap: z.number().min(0).max(1).default(0.6),
|
|
555
|
+
bridgeOpenings: z
|
|
556
|
+
.object({ maxWidth: z.number().positive() })
|
|
557
|
+
.nullable()
|
|
558
|
+
.default({ maxWidth: 9.6 }),
|
|
559
|
+
})
|
|
560
|
+
export type PluginCadCenterlineOptions = z.input<
|
|
561
|
+
typeof PluginCadCenterlineOptions
|
|
562
|
+
>
|
|
563
|
+
|
|
564
|
+
/** Arguments for {@link PluginCoreIoUnderlayApi.extractCenterlines}. */
|
|
565
|
+
export const PluginCadCenterlinesArgs = z.object({
|
|
566
|
+
underlay: UnderlayHandle,
|
|
567
|
+
layer: z.string(),
|
|
568
|
+
options: PluginCadCenterlineOptions.default({
|
|
569
|
+
thicknessRange: [0.3, 1.6],
|
|
570
|
+
mergeGap: 0.05,
|
|
571
|
+
minLength: 0.1,
|
|
572
|
+
parallelTolDeg: 2,
|
|
573
|
+
minOverlap: 0.6,
|
|
574
|
+
bridgeOpenings: { maxWidth: 9.6 },
|
|
575
|
+
}),
|
|
576
|
+
})
|
|
577
|
+
export type PluginCadCenterlinesArgs = z.infer<typeof PluginCadCenterlinesArgs>
|
|
578
|
+
|
|
579
|
+
/** A span bridged over a CAD gap in a continuous centreline — a door/window opening candidate. */
|
|
580
|
+
export const PluginCadOpening = z.object({
|
|
581
|
+
start: PluginPlanPoint,
|
|
582
|
+
end: PluginPlanPoint,
|
|
583
|
+
width: z.number(),
|
|
584
|
+
})
|
|
585
|
+
export type PluginCadOpening = z.infer<typeof PluginCadOpening>
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* One continuous wall centreline extracted from CAD wall faces. `thickness` is
|
|
589
|
+
* the measured face separation; `openings` are the CAD gaps bridged into this
|
|
590
|
+
* centreline (feed the door/window step).
|
|
591
|
+
*/
|
|
592
|
+
export const PluginCadCenterline = z.object({
|
|
593
|
+
start: PluginPlanPoint,
|
|
594
|
+
end: PluginPlanPoint,
|
|
595
|
+
thickness: z.number(),
|
|
596
|
+
length: z.number(),
|
|
597
|
+
sourceFaceCount: z.number().int().nonnegative(),
|
|
598
|
+
openings: z.array(PluginCadOpening),
|
|
599
|
+
})
|
|
600
|
+
export type PluginCadCenterline = z.infer<typeof PluginCadCenterline>
|
|
601
|
+
|
|
602
|
+
/** A merged face with no parallel partner at wall thickness — evidence (often glazing), not noise. */
|
|
603
|
+
export const PluginCadUnpairedFace = z.object({
|
|
604
|
+
start: PluginPlanPoint,
|
|
605
|
+
end: PluginPlanPoint,
|
|
606
|
+
length: z.number(),
|
|
607
|
+
})
|
|
608
|
+
export type PluginCadUnpairedFace = z.infer<typeof PluginCadUnpairedFace>
|
|
609
|
+
|
|
610
|
+
/** Result of {@link PluginCoreIoUnderlayApi.extractCenterlines}. */
|
|
611
|
+
export const PluginCadCenterlinesResult = z.object({
|
|
612
|
+
layer: z.string(),
|
|
613
|
+
coordinateSpace: z.literal("snaptrude-world"),
|
|
614
|
+
units: z.literal("snaptrude-internal"),
|
|
615
|
+
centerlines: z.array(PluginCadCenterline),
|
|
616
|
+
unpaired: z.array(PluginCadUnpairedFace),
|
|
617
|
+
stats: z.object({
|
|
618
|
+
curvesRead: z.number().int().nonnegative(),
|
|
619
|
+
arcsSkipped: z.number().int().nonnegative(),
|
|
620
|
+
fragmentsCulled: z.number().int().nonnegative(),
|
|
621
|
+
duplicates: z.number().int().nonnegative(),
|
|
622
|
+
faces: z.number().int().nonnegative(),
|
|
623
|
+
}),
|
|
624
|
+
})
|
|
625
|
+
export type PluginCadCenterlinesResult = z.infer<
|
|
626
|
+
typeof PluginCadCenterlinesResult
|
|
627
|
+
>
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Options for {@link PluginCoreIoUnderlayApi.classifyArcs}. Lengths in Snaptrude
|
|
631
|
+
* internal units, sweeps in degrees.
|
|
632
|
+
*
|
|
633
|
+
* | Property | Type | Description |
|
|
634
|
+
* |---|---|---|
|
|
635
|
+
* | `radiusRange` | `[number, number]`? | Plausible door-leaf widths (default `[3, 5.4]` ≈ 2.5–4.5 ft) |
|
|
636
|
+
* | `sweepRangeDeg` | `[number, number]`? | Accepted arc sweep in degrees (default `[60, 120]`; a swing is ~90°) |
|
|
637
|
+
* | `clusterTol` | `number`? | Radius bin size for the histogram (default `0.1`) |
|
|
638
|
+
*/
|
|
639
|
+
export const PluginCadArcClassifyOptions = z.object({
|
|
640
|
+
radiusRange: z
|
|
641
|
+
.tuple([z.number().positive(), z.number().positive()])
|
|
642
|
+
.default([3, 5.4]),
|
|
643
|
+
sweepRangeDeg: z
|
|
644
|
+
.tuple([z.number().positive(), z.number().positive()])
|
|
645
|
+
.default([60, 120]),
|
|
646
|
+
clusterTol: z.number().positive().default(0.1),
|
|
647
|
+
})
|
|
648
|
+
export type PluginCadArcClassifyOptions = z.input<
|
|
649
|
+
typeof PluginCadArcClassifyOptions
|
|
650
|
+
>
|
|
651
|
+
|
|
652
|
+
/** Arguments for {@link PluginCoreIoUnderlayApi.classifyArcs}. */
|
|
653
|
+
export const PluginCadArcClassifyArgs = z.object({
|
|
654
|
+
underlay: UnderlayHandle,
|
|
655
|
+
layer: z.string(),
|
|
656
|
+
options: PluginCadArcClassifyOptions.default({
|
|
657
|
+
radiusRange: [3, 5.4],
|
|
658
|
+
sweepRangeDeg: [60, 120],
|
|
659
|
+
clusterTol: 0.1,
|
|
660
|
+
}),
|
|
661
|
+
})
|
|
662
|
+
export type PluginCadArcClassifyArgs = z.infer<typeof PluginCadArcClassifyArgs>
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* One door candidate read from a CAD swing arc. `hinge` is the arc centre,
|
|
666
|
+
* `leafWidth` the arc radius, `swingDir` the unit direction from hinge toward
|
|
667
|
+
* the open leaf, `wallDir` the unit direction of the hosting wall (hinge →
|
|
668
|
+
* closed-leaf chord end). `openingWidth` equals `leafWidth` for singles and
|
|
669
|
+
* `2 × leafWidth` for doubles.
|
|
670
|
+
*/
|
|
671
|
+
export const PluginCadDoorCandidate = z.object({
|
|
672
|
+
hinge: PluginPlanPoint,
|
|
673
|
+
leafWidth: z.number(),
|
|
674
|
+
swingDir: PluginPlanPoint,
|
|
675
|
+
wallDir: PluginPlanPoint,
|
|
676
|
+
openingWidth: z.number(),
|
|
677
|
+
double: z.boolean(),
|
|
678
|
+
})
|
|
679
|
+
export type PluginCadDoorCandidate = z.infer<typeof PluginCadDoorCandidate>
|
|
680
|
+
|
|
681
|
+
/** Result of {@link PluginCoreIoUnderlayApi.classifyArcs}. */
|
|
682
|
+
export const PluginCadArcClassifyResult = z.object({
|
|
683
|
+
layer: z.string(),
|
|
684
|
+
coordinateSpace: z.literal("snaptrude-world"),
|
|
685
|
+
units: z.literal("snaptrude-internal"),
|
|
686
|
+
doors: z.array(PluginCadDoorCandidate),
|
|
687
|
+
rejected: z.array(
|
|
688
|
+
z.object({
|
|
689
|
+
centre: PluginPlanPoint,
|
|
690
|
+
radius: z.number(),
|
|
691
|
+
sweepDeg: z.number(),
|
|
692
|
+
reason: z.string(),
|
|
693
|
+
}),
|
|
694
|
+
),
|
|
695
|
+
radiusHistogram: z.array(
|
|
696
|
+
z.object({ radius: z.number(), count: z.number().int().positive() }),
|
|
697
|
+
),
|
|
698
|
+
stats: z.object({
|
|
699
|
+
curvesRead: z.number().int().nonnegative(),
|
|
700
|
+
arcsConsidered: z.number().int().nonnegative(),
|
|
701
|
+
}),
|
|
702
|
+
})
|
|
703
|
+
export type PluginCadArcClassifyResult = z.infer<
|
|
704
|
+
typeof PluginCadArcClassifyResult
|
|
705
|
+
>
|