@pascal-app/core 1.0.4 → 1.0.6
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/dist/agent-operations/__fixtures__/add-object-cases.d.ts +102 -90
- package/dist/agent-operations/__fixtures__/add-object-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/add-object-cases.js +301 -1
- package/dist/agent-operations/__fixtures__/add-stair-cases.d.ts +3 -0
- package/dist/agent-operations/__fixtures__/add-stair-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/add-stair-cases.js +176 -0
- package/dist/agent-operations/__fixtures__/build-room-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/build-room-cases.js +410 -40
- package/dist/agent-operations/__fixtures__/cases.d.ts +18 -3
- package/dist/agent-operations/__fixtures__/cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/cases.js +183 -4
- package/dist/agent-operations/__fixtures__/corner-window-cases.d.ts +3 -0
- package/dist/agent-operations/__fixtures__/corner-window-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/corner-window-cases.js +155 -0
- package/dist/agent-operations/__fixtures__/design-brief-cases.d.ts +14 -0
- package/dist/agent-operations/__fixtures__/design-brief-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/design-brief-cases.js +709 -0
- package/dist/agent-operations/__fixtures__/finish-cases.d.ts +7 -0
- package/dist/agent-operations/__fixtures__/finish-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/finish-cases.js +758 -0
- package/dist/agent-operations/__fixtures__/lot-info-cases.d.ts +3 -0
- package/dist/agent-operations/__fixtures__/lot-info-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/lot-info-cases.js +370 -0
- package/dist/agent-operations/__fixtures__/merge-windows-cases.d.ts +3 -0
- package/dist/agent-operations/__fixtures__/merge-windows-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/merge-windows-cases.js +321 -0
- package/dist/agent-operations/__fixtures__/native-materials.d.ts +2237 -0
- package/dist/agent-operations/__fixtures__/native-materials.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/native-materials.js +82 -0
- package/dist/agent-operations/__fixtures__/node-read-cases.d.ts +4 -0
- package/dist/agent-operations/__fixtures__/node-read-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/node-read-cases.js +639 -0
- package/dist/agent-operations/__fixtures__/notation-cases.d.ts +24 -0
- package/dist/agent-operations/__fixtures__/notation-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/notation-cases.js +356 -0
- package/dist/agent-operations/__fixtures__/place-items-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/place-items-cases.js +80 -2
- package/dist/agent-operations/__fixtures__/roof-bearing-cases.d.ts +19726 -0
- package/dist/agent-operations/__fixtures__/roof-bearing-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/roof-bearing-cases.js +106 -0
- package/dist/agent-operations/__fixtures__/roof-cases.d.ts +9 -0
- package/dist/agent-operations/__fixtures__/roof-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/roof-cases.js +382 -0
- package/dist/agent-operations/__fixtures__/room-cases.d.ts +2 -1
- package/dist/agent-operations/__fixtures__/room-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/room-cases.js +136 -1
- package/dist/agent-operations/__fixtures__/scene-check-cases.d.ts +4 -0
- package/dist/agent-operations/__fixtures__/scene-check-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/scene-check-cases.js +417 -0
- package/dist/agent-operations/__fixtures__/search-assets-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/search-assets-cases.js +15 -3
- package/dist/agent-operations/__fixtures__/site-cases.d.ts +290 -0
- package/dist/agent-operations/__fixtures__/site-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/site-cases.js +780 -0
- package/dist/agent-operations/__fixtures__/structure-cases.d.ts +1 -0
- package/dist/agent-operations/__fixtures__/structure-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/structure-cases.js +630 -3
- package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts +311 -1
- package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/verify-scene-cases.js +59 -11
- package/dist/agent-operations/__fixtures__/view-assets-cases.d.ts +3 -0
- package/dist/agent-operations/__fixtures__/view-assets-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/view-assets-cases.js +155 -0
- package/dist/agent-operations/__fixtures__/view-scene-cases.d.ts +50 -0
- package/dist/agent-operations/__fixtures__/view-scene-cases.d.ts.map +1 -0
- package/dist/agent-operations/__fixtures__/view-scene-cases.js +425 -0
- package/dist/agent-operations/achieved.d.ts +5 -0
- package/dist/agent-operations/achieved.d.ts.map +1 -1
- package/dist/agent-operations/achieved.js +21 -1
- package/dist/agent-operations/add-column.d.ts.map +1 -1
- package/dist/agent-operations/add-column.js +3 -1
- package/dist/agent-operations/add-fence.d.ts +18 -0
- package/dist/agent-operations/add-fence.d.ts.map +1 -0
- package/dist/agent-operations/add-fence.js +48 -0
- package/dist/agent-operations/add-level.d.ts +4 -1
- package/dist/agent-operations/add-level.d.ts.map +1 -1
- package/dist/agent-operations/add-level.js +48 -12
- package/dist/agent-operations/add-object.d.ts +38 -9
- package/dist/agent-operations/add-object.d.ts.map +1 -1
- package/dist/agent-operations/add-object.js +172 -11
- package/dist/agent-operations/add-wall.d.ts +1 -3
- package/dist/agent-operations/add-wall.d.ts.map +1 -1
- package/dist/agent-operations/add-wall.js +35 -9
- package/dist/agent-operations/apply-changes.d.ts +7 -1
- package/dist/agent-operations/apply-changes.d.ts.map +1 -1
- package/dist/agent-operations/apply-changes.js +54 -22
- package/dist/agent-operations/apply-outcome.d.ts +6 -0
- package/dist/agent-operations/apply-outcome.d.ts.map +1 -1
- package/dist/agent-operations/apply-outcome.js +23 -8
- package/dist/agent-operations/asset-views.d.ts +75 -0
- package/dist/agent-operations/asset-views.d.ts.map +1 -0
- package/dist/agent-operations/asset-views.js +234 -0
- package/dist/agent-operations/author-scene.d.ts +157 -0
- package/dist/agent-operations/author-scene.d.ts.map +1 -0
- package/dist/agent-operations/author-scene.js +1076 -0
- package/dist/agent-operations/authored-scene-merge.d.ts +4 -0
- package/dist/agent-operations/authored-scene-merge.d.ts.map +1 -0
- package/dist/agent-operations/authored-scene-merge.js +96 -0
- package/dist/agent-operations/batch.d.ts +22 -0
- package/dist/agent-operations/batch.d.ts.map +1 -0
- package/dist/agent-operations/batch.js +104 -0
- package/dist/agent-operations/ceiling-object-observations.d.ts +31 -0
- package/dist/agent-operations/ceiling-object-observations.d.ts.map +1 -0
- package/dist/agent-operations/ceiling-object-observations.js +111 -0
- package/dist/agent-operations/corner-window.d.ts +19 -0
- package/dist/agent-operations/corner-window.d.ts.map +1 -0
- package/dist/agent-operations/corner-window.js +84 -0
- package/dist/agent-operations/create-roof.d.ts +32 -0
- package/dist/agent-operations/create-roof.d.ts.map +1 -0
- package/dist/agent-operations/create-roof.js +304 -0
- package/dist/agent-operations/create-room.d.ts +2 -0
- package/dist/agent-operations/create-room.d.ts.map +1 -1
- package/dist/agent-operations/create-room.js +73 -5
- package/dist/agent-operations/create-stair.d.ts +6 -28
- package/dist/agent-operations/create-stair.d.ts.map +1 -1
- package/dist/agent-operations/create-stair.js +187 -104
- package/dist/agent-operations/design-brief.d.ts +38 -0
- package/dist/agent-operations/design-brief.d.ts.map +1 -0
- package/dist/agent-operations/design-brief.js +300 -0
- package/dist/agent-operations/designs.d.ts +24 -0
- package/dist/agent-operations/designs.d.ts.map +1 -0
- package/dist/agent-operations/designs.js +48 -0
- package/dist/agent-operations/door-clearance.d.ts +16 -1
- package/dist/agent-operations/door-clearance.d.ts.map +1 -1
- package/dist/agent-operations/door-clearance.js +61 -4
- package/dist/agent-operations/duplicate-level.d.ts.map +1 -1
- package/dist/agent-operations/duplicate-level.js +2 -1
- package/dist/agent-operations/find-by-type.d.ts +14 -7
- package/dist/agent-operations/find-by-type.d.ts.map +1 -1
- package/dist/agent-operations/find-by-type.js +266 -43
- package/dist/agent-operations/furnish-room.d.ts +22 -1
- package/dist/agent-operations/furnish-room.d.ts.map +1 -1
- package/dist/agent-operations/furnish-room.js +66 -19
- package/dist/agent-operations/furniture-kind.d.ts +22 -0
- package/dist/agent-operations/furniture-kind.d.ts.map +1 -0
- package/dist/agent-operations/furniture-kind.js +69 -0
- package/dist/agent-operations/get-node.d.ts +5 -2
- package/dist/agent-operations/get-node.d.ts.map +1 -1
- package/dist/agent-operations/get-node.js +82 -10
- package/dist/agent-operations/hosted-services.d.ts +2 -1
- package/dist/agent-operations/hosted-services.d.ts.map +1 -1
- package/dist/agent-operations/index.d.ts +281 -69
- package/dist/agent-operations/index.d.ts.map +1 -1
- package/dist/agent-operations/index.js +66 -5
- package/dist/agent-operations/item-space.d.ts +22 -0
- package/dist/agent-operations/item-space.d.ts.map +1 -0
- package/dist/agent-operations/item-space.js +69 -0
- package/dist/agent-operations/layout-clearance.d.ts +52 -3
- package/dist/agent-operations/layout-clearance.d.ts.map +1 -1
- package/dist/agent-operations/layout-clearance.js +340 -30
- package/dist/agent-operations/level-height-fill.d.ts +12 -0
- package/dist/agent-operations/level-height-fill.d.ts.map +1 -0
- package/dist/agent-operations/level-height-fill.js +59 -0
- package/dist/agent-operations/level-reads.d.ts +5 -1
- package/dist/agent-operations/level-reads.d.ts.map +1 -1
- package/dist/agent-operations/level-reads.js +10 -3
- package/dist/agent-operations/list-levels.d.ts.map +1 -1
- package/dist/agent-operations/list-levels.js +23 -0
- package/dist/agent-operations/material-preset.d.ts.map +1 -1
- package/dist/agent-operations/material-preset.js +3 -9
- package/dist/agent-operations/material-refs.d.ts +7 -1
- package/dist/agent-operations/material-refs.d.ts.map +1 -1
- package/dist/agent-operations/material-refs.js +10 -5
- package/dist/agent-operations/merge-windows.d.ts +6 -0
- package/dist/agent-operations/merge-windows.d.ts.map +1 -0
- package/dist/agent-operations/merge-windows.js +27 -0
- package/dist/agent-operations/move-roofs.d.ts +9 -0
- package/dist/agent-operations/move-roofs.d.ts.map +1 -0
- package/dist/agent-operations/move-roofs.js +29 -0
- package/dist/agent-operations/paint.d.ts +2 -1
- package/dist/agent-operations/paint.d.ts.map +1 -1
- package/dist/agent-operations/paint.js +163 -53
- package/dist/agent-operations/photo-elevation.d.ts +155 -0
- package/dist/agent-operations/photo-elevation.d.ts.map +1 -0
- package/dist/agent-operations/photo-elevation.js +761 -0
- package/dist/agent-operations/place-in-room.d.ts +29 -0
- package/dist/agent-operations/place-in-room.d.ts.map +1 -0
- package/dist/agent-operations/place-in-room.js +403 -0
- package/dist/agent-operations/place-items.d.ts.map +1 -1
- package/dist/agent-operations/place-items.js +15 -2
- package/dist/agent-operations/plan-geometry.d.ts.map +1 -1
- package/dist/agent-operations/plan-geometry.js +3 -0
- package/dist/agent-operations/point-context.d.ts +139 -0
- package/dist/agent-operations/point-context.d.ts.map +1 -0
- package/dist/agent-operations/point-context.js +1 -0
- package/dist/agent-operations/project-files.d.ts +9 -0
- package/dist/agent-operations/project-files.d.ts.map +1 -0
- package/dist/agent-operations/project-files.js +25 -0
- package/dist/agent-operations/record-made.d.ts +18 -0
- package/dist/agent-operations/record-made.d.ts.map +1 -0
- package/dist/agent-operations/record-made.js +28 -0
- package/dist/agent-operations/roof-footprint.d.ts +24 -0
- package/dist/agent-operations/roof-footprint.d.ts.map +1 -0
- package/dist/agent-operations/roof-footprint.js +242 -0
- package/dist/agent-operations/roof-writes.d.ts +20 -0
- package/dist/agent-operations/roof-writes.d.ts.map +1 -0
- package/dist/agent-operations/roof-writes.js +165 -0
- package/dist/agent-operations/room-findings.d.ts +54 -0
- package/dist/agent-operations/room-findings.d.ts.map +1 -0
- package/dist/agent-operations/room-findings.js +143 -0
- package/dist/agent-operations/room-floor-script.d.ts +23 -0
- package/dist/agent-operations/room-floor-script.d.ts.map +1 -0
- package/dist/agent-operations/room-floor-script.js +54 -0
- package/dist/agent-operations/room-structure.d.ts +2 -2
- package/dist/agent-operations/room-structure.d.ts.map +1 -1
- package/dist/agent-operations/scene-checkpoint.d.ts +94 -0
- package/dist/agent-operations/scene-checkpoint.d.ts.map +1 -0
- package/dist/agent-operations/scene-checkpoint.js +176 -0
- package/dist/agent-operations/scene-queries.d.ts +3750 -3319
- package/dist/agent-operations/scene-queries.d.ts.map +1 -1
- package/dist/agent-operations/scene-queries.js +13 -23
- package/dist/agent-operations/scene-review.d.ts +52 -0
- package/dist/agent-operations/scene-review.d.ts.map +1 -0
- package/dist/agent-operations/scene-review.js +106 -0
- package/dist/agent-operations/scene-view.d.ts +82 -15
- package/dist/agent-operations/scene-view.d.ts.map +1 -1
- package/dist/agent-operations/scene-view.js +408 -51
- package/dist/agent-operations/search-assets.d.ts +2 -2
- package/dist/agent-operations/search-assets.d.ts.map +1 -1
- package/dist/agent-operations/search-assets.js +4 -3
- package/dist/agent-operations/search-materials.d.ts +9 -3
- package/dist/agent-operations/search-materials.d.ts.map +1 -1
- package/dist/agent-operations/search-materials.js +83 -29
- package/dist/agent-operations/set-checkpoint.d.ts +9 -0
- package/dist/agent-operations/set-checkpoint.d.ts.map +1 -0
- package/dist/agent-operations/set-checkpoint.js +31 -0
- package/dist/agent-operations/set-ground-level.d.ts +12 -0
- package/dist/agent-operations/set-ground-level.d.ts.map +1 -0
- package/dist/agent-operations/set-ground-level.js +61 -0
- package/dist/agent-operations/site.d.ts +21 -0
- package/dist/agent-operations/site.d.ts.map +1 -0
- package/dist/agent-operations/site.js +123 -0
- package/dist/agent-operations/types.d.ts +66 -7
- package/dist/agent-operations/types.d.ts.map +1 -1
- package/dist/agent-operations/verify-scene.d.ts +39 -5
- package/dist/agent-operations/verify-scene.d.ts.map +1 -1
- package/dist/agent-operations/verify-scene.js +223 -44
- package/dist/agent-operations/wall-face-script.d.ts +28 -0
- package/dist/agent-operations/wall-face-script.d.ts.map +1 -0
- package/dist/agent-operations/wall-face-script.js +62 -0
- package/dist/agent-operations/wall-object-observations.d.ts +41 -0
- package/dist/agent-operations/wall-object-observations.d.ts.map +1 -0
- package/dist/agent-operations/wall-object-observations.js +249 -0
- package/dist/agent-operations/wall-opening.d.ts +23 -23
- package/dist/agent-operations/wall-opening.d.ts.map +1 -1
- package/dist/agent-operations/wall-skirting.d.ts +24 -0
- package/dist/agent-operations/wall-skirting.d.ts.map +1 -0
- package/dist/agent-operations/wall-skirting.js +85 -0
- package/dist/agent-tools/add-object.d.ts +11 -7
- package/dist/agent-tools/add-object.d.ts.map +1 -1
- package/dist/agent-tools/add-object.js +17 -11
- package/dist/agent-tools/assets.d.ts +8 -0
- package/dist/agent-tools/assets.d.ts.map +1 -1
- package/dist/agent-tools/assets.js +13 -1
- package/dist/agent-tools/author-scene.d.ts +651 -0
- package/dist/agent-tools/author-scene.d.ts.map +1 -0
- package/dist/agent-tools/author-scene.js +252 -0
- package/dist/agent-tools/batch.d.ts +25 -0
- package/dist/agent-tools/batch.d.ts.map +1 -0
- package/dist/agent-tools/batch.js +61 -0
- package/dist/agent-tools/checkpoints.d.ts +13 -0
- package/dist/agent-tools/checkpoints.d.ts.map +1 -0
- package/dist/agent-tools/checkpoints.js +16 -0
- package/dist/agent-tools/clear-scene.d.ts.map +1 -1
- package/dist/agent-tools/collections.d.ts +6 -6
- package/dist/agent-tools/collections.d.ts.map +1 -1
- package/dist/agent-tools/columns.d.ts +18 -18
- package/dist/agent-tools/columns.js +2 -2
- package/dist/agent-tools/corner-window.d.ts +46 -0
- package/dist/agent-tools/corner-window.d.ts.map +1 -0
- package/dist/agent-tools/corner-window.js +47 -0
- package/dist/agent-tools/create-room.d.ts +26 -25
- package/dist/agent-tools/create-room.d.ts.map +1 -1
- package/dist/agent-tools/create-room.js +11 -4
- package/dist/agent-tools/design-brief.d.ts +408 -0
- package/dist/agent-tools/design-brief.d.ts.map +1 -0
- package/dist/agent-tools/design-brief.js +149 -0
- package/dist/agent-tools/designs.d.ts +34 -0
- package/dist/agent-tools/designs.d.ts.map +1 -0
- package/dist/agent-tools/designs.js +50 -0
- package/dist/agent-tools/fences.d.ts +28 -0
- package/dist/agent-tools/fences.d.ts.map +1 -0
- package/dist/agent-tools/fences.js +31 -0
- package/dist/agent-tools/find-by-type.d.ts +8 -1
- package/dist/agent-tools/find-by-type.d.ts.map +1 -1
- package/dist/agent-tools/find-by-type.js +23 -2
- package/dist/agent-tools/furnish-room.d.ts +10 -8
- package/dist/agent-tools/furnish-room.d.ts.map +1 -1
- package/dist/agent-tools/furnish-room.js +3 -1
- package/dist/agent-tools/hosted-services.d.ts +177 -141
- package/dist/agent-tools/hosted-services.d.ts.map +1 -1
- package/dist/agent-tools/hosted-services.js +47 -14
- package/dist/agent-tools/index.d.ts +894 -215
- package/dist/agent-tools/index.d.ts.map +1 -1
- package/dist/agent-tools/index.js +47 -3
- package/dist/agent-tools/levels.d.ts +11 -3
- package/dist/agent-tools/levels.d.ts.map +1 -1
- package/dist/agent-tools/levels.js +16 -5
- package/dist/agent-tools/measurement.d.ts +38 -20
- package/dist/agent-tools/measurement.d.ts.map +1 -1
- package/dist/agent-tools/measurement.js +117 -67
- package/dist/agent-tools/merge-windows.d.ts +10 -0
- package/dist/agent-tools/merge-windows.d.ts.map +1 -0
- package/dist/agent-tools/merge-windows.js +12 -0
- package/dist/agent-tools/nodes.d.ts.map +1 -1
- package/dist/agent-tools/nodes.js +1 -1
- package/dist/agent-tools/notation-inventory.d.ts +16 -0
- package/dist/agent-tools/notation-inventory.d.ts.map +1 -0
- package/dist/agent-tools/notation-inventory.js +105 -0
- package/dist/agent-tools/paint.d.ts +5 -5
- package/dist/agent-tools/paint.d.ts.map +1 -1
- package/dist/agent-tools/paint.js +1 -1
- package/dist/agent-tools/photo-elevation.d.ts +32 -0
- package/dist/agent-tools/photo-elevation.d.ts.map +1 -0
- package/dist/agent-tools/photo-elevation.js +73 -0
- package/dist/agent-tools/place-in-room.d.ts +35 -0
- package/dist/agent-tools/place-in-room.d.ts.map +1 -0
- package/dist/agent-tools/place-in-room.js +61 -0
- package/dist/agent-tools/place-items.d.ts +1 -1
- package/dist/agent-tools/place-items.js +2 -2
- package/dist/agent-tools/project-files.d.ts +189 -0
- package/dist/agent-tools/project-files.d.ts.map +1 -0
- package/dist/agent-tools/project-files.js +99 -0
- package/dist/agent-tools/refusal.d.ts.map +1 -1
- package/dist/agent-tools/retired.d.ts +21 -0
- package/dist/agent-tools/retired.d.ts.map +1 -0
- package/dist/agent-tools/retired.js +29 -0
- package/dist/agent-tools/roofs.d.ts +100 -0
- package/dist/agent-tools/roofs.d.ts.map +1 -0
- package/dist/agent-tools/roofs.js +96 -0
- package/dist/agent-tools/room-structure.d.ts +46 -38
- package/dist/agent-tools/room-structure.d.ts.map +1 -1
- package/dist/agent-tools/room-structure.js +30 -27
- package/dist/agent-tools/search-materials.d.ts +22 -3
- package/dist/agent-tools/search-materials.d.ts.map +1 -1
- package/dist/agent-tools/search-materials.js +13 -14
- package/dist/agent-tools/site.d.ts +27 -0
- package/dist/agent-tools/site.d.ts.map +1 -0
- package/dist/agent-tools/site.js +40 -0
- package/dist/agent-tools/sources.d.ts +12 -0
- package/dist/agent-tools/sources.d.ts.map +1 -0
- package/dist/agent-tools/sources.js +11 -0
- package/dist/agent-tools/stairs.d.ts +48 -28
- package/dist/agent-tools/stairs.d.ts.map +1 -1
- package/dist/agent-tools/stairs.js +65 -22
- package/dist/agent-tools/verify-scene.d.ts.map +1 -1
- package/dist/agent-tools/verify-scene.js +1 -1
- package/dist/agent-tools/view-scene.d.ts +50 -12
- package/dist/agent-tools/view-scene.d.ts.map +1 -1
- package/dist/agent-tools/view-scene.js +74 -31
- package/dist/agent-tools/wall-openings.d.ts +77 -73
- package/dist/agent-tools/wall-openings.d.ts.map +1 -1
- package/dist/agent-tools/wall-openings.js +9 -5
- package/dist/agent-tools/walls.d.ts +4 -4
- package/dist/agent-tools/walls.d.ts.map +1 -1
- package/dist/agent-tools/walls.js +7 -2
- package/dist/building/__fixtures__/wall-opening-cases.d.ts +454 -250
- package/dist/building/__fixtures__/wall-opening-cases.d.ts.map +1 -1
- package/dist/building/__fixtures__/wall-opening-cases.js +62 -2
- package/dist/building/corner-window.d.ts +56 -0
- package/dist/building/corner-window.d.ts.map +1 -0
- package/dist/building/corner-window.js +179 -0
- package/dist/building/ground-level.d.ts +26 -0
- package/dist/building/ground-level.d.ts.map +1 -0
- package/dist/building/ground-level.js +58 -0
- package/dist/building/index.d.ts +5 -0
- package/dist/building/index.d.ts.map +1 -1
- package/dist/building/index.js +5 -0
- package/dist/building/level-duplication.d.ts +7472 -6613
- package/dist/building/level-duplication.d.ts.map +1 -1
- package/dist/building/level-duplication.js +18 -4
- package/dist/building/level-insertion.d.ts +55 -0
- package/dist/building/level-insertion.d.ts.map +1 -0
- package/dist/building/level-insertion.js +35 -0
- package/dist/building/merge-windows.d.ts +58 -0
- package/dist/building/merge-windows.d.ts.map +1 -0
- package/dist/building/merge-windows.js +189 -0
- package/dist/building/opening-style-presets.d.ts +2 -2
- package/dist/building/opening-style-presets.d.ts.map +1 -1
- package/dist/building/photo-elevation.d.ts +125 -0
- package/dist/building/photo-elevation.d.ts.map +1 -0
- package/dist/building/photo-elevation.js +404 -0
- package/dist/building/wall-gaps.d.ts +13 -0
- package/dist/building/wall-gaps.d.ts.map +1 -0
- package/dist/building/wall-gaps.js +158 -0
- package/dist/building/wall-openings.d.ts +154 -119
- package/dist/building/wall-openings.d.ts.map +1 -1
- package/dist/building/wall-openings.js +37 -9
- package/dist/capture/schema.d.ts +22 -22
- package/dist/capture/source.d.ts.map +1 -1
- package/dist/capture/source.js +1 -1
- package/dist/commands/structure/create-zone.d.ts +12 -1
- package/dist/commands/structure/create-zone.d.ts.map +1 -1
- package/dist/commands/structure/create-zone.js +49 -0
- package/dist/commands/structure/divide-zone.d.ts +3 -3
- package/dist/commands/structure/index.d.ts +1 -1
- package/dist/commands/structure/index.d.ts.map +1 -1
- package/dist/commands/structure/index.js +1 -1
- package/dist/commands/structure/set-floor-foundation.d.ts +6 -6
- package/dist/commands/structure/set-zone-intent.d.ts +4 -0
- package/dist/commands/structure/set-zone-intent.d.ts.map +1 -1
- package/dist/commands/structure/set-zone-intent.js +19 -0
- package/dist/commands/structure/shared.d.ts +3642 -3213
- package/dist/commands/structure/shared.d.ts.map +1 -1
- package/dist/commands/structure/zone-wall-merge.d.ts +4149 -3334
- package/dist/commands/structure/zone-wall-merge.d.ts.map +1 -1
- package/dist/contracts/reference-inventory.d.ts.map +1 -1
- package/dist/contracts/reference-inventory.js +106 -26
- package/dist/events/bus.d.ts +22 -3
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/capture-sessions.d.ts +5 -0
- package/dist/events/capture-sessions.d.ts.map +1 -0
- package/dist/events/capture-sessions.js +31 -0
- package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +1 -2
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +4 -6
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +3608 -3179
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/support-host-patch.js +11 -2
- package/dist/hooks/spatial-grid/use-spatial-query.d.ts +3 -3
- package/dist/hooks/spatial-grid/wall-spatial-grid.d.ts.map +1 -1
- package/dist/index.d.ts +37 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -9
- package/dist/lib/__fixtures__/mezzanine.d.ts +11800 -10132
- package/dist/lib/__fixtures__/mezzanine.d.ts.map +1 -1
- package/dist/lib/absorb-wall-separators.d.ts +3642 -3213
- package/dist/lib/absorb-wall-separators.d.ts.map +1 -1
- package/dist/lib/angle-accumulator.d.ts.map +1 -1
- package/dist/lib/artifact-store.d.ts.map +1 -1
- package/dist/lib/below-grade-footprints.d.ts +65 -0
- package/dist/lib/below-grade-footprints.d.ts.map +1 -0
- package/dist/lib/below-grade-footprints.js +181 -0
- package/dist/lib/building-footprint.d.ts +33 -0
- package/dist/lib/building-footprint.d.ts.map +1 -0
- package/dist/lib/building-footprint.js +89 -0
- package/dist/lib/corner-pair.d.ts +1129 -0
- package/dist/lib/corner-pair.d.ts.map +1 -0
- package/dist/lib/corner-pair.js +130 -0
- package/dist/lib/corner-snap.d.ts +54 -0
- package/dist/lib/corner-snap.d.ts.map +1 -0
- package/dist/lib/corner-snap.js +125 -0
- package/dist/lib/critically-damped.d.ts +11 -0
- package/dist/lib/critically-damped.d.ts.map +1 -0
- package/dist/lib/critically-damped.js +14 -0
- package/dist/lib/deepest-drawn.d.ts +18 -0
- package/dist/lib/deepest-drawn.d.ts.map +1 -0
- package/dist/lib/deepest-drawn.js +65 -0
- package/dist/lib/door-operation.d.ts +1 -1
- package/dist/lib/exterior-wall-loops.d.ts +17 -0
- package/dist/lib/exterior-wall-loops.d.ts.map +1 -0
- package/dist/lib/exterior-wall-loops.js +334 -0
- package/dist/lib/finish-script.d.ts +61 -0
- package/dist/lib/finish-script.d.ts.map +1 -0
- package/dist/lib/finish-script.js +86 -0
- package/dist/lib/floor-intent-changes.d.ts.map +1 -1
- package/dist/lib/floor-intent-changes.js +4 -4
- package/dist/lib/floor-plate-paint.d.ts +3 -1
- package/dist/lib/floor-plate-paint.d.ts.map +1 -1
- package/dist/lib/floor-plate-paint.js +24 -4
- package/dist/lib/floor-plates.d.ts +50 -50
- package/dist/lib/floor-script.d.ts +24 -0
- package/dist/lib/floor-script.d.ts.map +1 -0
- package/dist/lib/floor-script.js +51 -0
- package/dist/lib/foundation-construction.d.ts +73 -0
- package/dist/lib/foundation-construction.d.ts.map +1 -0
- package/dist/lib/foundation-construction.js +242 -0
- package/dist/lib/foundation-standard.d.ts +30 -0
- package/dist/lib/foundation-standard.d.ts.map +1 -0
- package/dist/lib/foundation-standard.js +30 -0
- package/dist/lib/foundation-wall.d.ts +36 -0
- package/dist/lib/foundation-wall.d.ts.map +1 -0
- package/dist/lib/foundation-wall.js +66 -0
- package/dist/lib/generic-foundation.d.ts +40 -0
- package/dist/lib/generic-foundation.d.ts.map +1 -0
- package/dist/lib/generic-foundation.js +200 -0
- package/dist/lib/geometry-script-node.d.ts +32 -3
- package/dist/lib/geometry-script-node.d.ts.map +1 -1
- package/dist/lib/geometry-script-node.js +26 -0
- package/dist/lib/grade-standing.d.ts +38 -0
- package/dist/lib/grade-standing.d.ts.map +1 -0
- package/dist/lib/grade-standing.js +137 -0
- package/dist/lib/ground-level.d.ts +20 -0
- package/dist/lib/ground-level.d.ts.map +1 -0
- package/dist/lib/ground-level.js +49 -0
- package/dist/lib/ground-over-part.d.ts +13 -0
- package/dist/lib/ground-over-part.d.ts.map +1 -0
- package/dist/lib/ground-over-part.js +94 -0
- package/dist/lib/ground-seat.d.ts +47 -0
- package/dist/lib/ground-seat.d.ts.map +1 -0
- package/dist/lib/ground-seat.js +61 -0
- package/dist/lib/ground-window.d.ts +39 -0
- package/dist/lib/ground-window.d.ts.map +1 -0
- package/dist/lib/ground-window.js +147 -0
- package/dist/lib/opening-floor-datum.d.ts.map +1 -1
- package/dist/lib/opening-floor-datum.js +2 -3
- package/dist/lib/own-floor-intent.d.ts.map +1 -1
- package/dist/lib/own-floor-intent.js +4 -4
- package/dist/lib/plate-surface.d.ts.map +1 -1
- package/dist/lib/plate-surface.js +3 -1
- package/dist/lib/point-ask.d.ts +9 -0
- package/dist/lib/point-ask.d.ts.map +1 -0
- package/dist/lib/point-ask.js +36 -0
- package/dist/lib/room-drawn-floor.d.ts +1 -1
- package/dist/lib/room-drawn-floor.d.ts.map +1 -1
- package/dist/lib/room-floor-feasibility.d.ts.map +1 -1
- package/dist/lib/room-floor-feasibility.js +3 -3
- package/dist/lib/room-graph.d.ts.map +1 -1
- package/dist/lib/room-graph.js +2 -0
- package/dist/lib/room-name.d.ts +2 -0
- package/dist/lib/room-name.d.ts.map +1 -1
- package/dist/lib/room-name.js +2 -0
- package/dist/lib/room-topology-index.d.ts.map +1 -1
- package/dist/lib/room-topology-index.js +1 -1
- package/dist/lib/room-zone-adoption.d.ts.map +1 -1
- package/dist/lib/script-inputs-key.d.ts +3 -0
- package/dist/lib/script-inputs-key.d.ts.map +1 -0
- package/dist/lib/script-inputs-key.js +13 -0
- package/dist/lib/setback-envelope.d.ts +95 -5
- package/dist/lib/setback-envelope.d.ts.map +1 -1
- package/dist/lib/setback-envelope.js +351 -35
- package/dist/lib/site-flatwork.d.ts +11 -0
- package/dist/lib/site-flatwork.d.ts.map +1 -0
- package/dist/lib/site-flatwork.js +11 -0
- package/dist/lib/site-ground-height.d.ts +13 -0
- package/dist/lib/site-ground-height.d.ts.map +1 -0
- package/dist/lib/site-ground-height.js +16 -0
- package/dist/lib/site-placement.d.ts +362 -0
- package/dist/lib/site-placement.d.ts.map +1 -0
- package/dist/lib/site-placement.js +942 -0
- package/dist/lib/snap-ease.d.ts +20 -0
- package/dist/lib/snap-ease.d.ts.map +1 -0
- package/dist/lib/snap-ease.js +50 -0
- package/dist/lib/structure-kernel.d.ts +1 -1
- package/dist/lib/structure-kernel.d.ts.map +1 -1
- package/dist/lib/structure-kernel.js +2 -0
- package/dist/lib/surface-support-references.d.ts +4 -0
- package/dist/lib/surface-support-references.d.ts.map +1 -0
- package/dist/lib/surface-support-references.js +19 -0
- package/dist/lib/terrain-support-query.d.ts +10 -0
- package/dist/lib/terrain-support-query.d.ts.map +1 -1
- package/dist/lib/terrain-support-query.js +1 -1
- package/dist/lib/wall-face-script.d.ts +66 -0
- package/dist/lib/wall-face-script.d.ts.map +1 -0
- package/dist/lib/wall-face-script.js +235 -0
- package/dist/lib/zone-colors.d.ts +1 -1
- package/dist/lib/zone-colors.d.ts.map +1 -1
- package/dist/lib/zone-quantities.d.ts.map +1 -1
- package/dist/lib/zone-quantities.js +4 -5
- package/dist/material-kinds.d.ts +9 -0
- package/dist/material-kinds.d.ts.map +1 -0
- package/dist/material-kinds.js +30 -0
- package/dist/material-library.d.ts +4 -4
- package/dist/material-library.d.ts.map +1 -1
- package/dist/material-library.js +72 -26
- package/dist/node-slots/index.d.ts +1 -0
- package/dist/node-slots/index.d.ts.map +1 -1
- package/dist/node-slots/index.js +7 -1
- package/dist/node-slots/roof.d.ts +5 -0
- package/dist/node-slots/roof.d.ts.map +1 -0
- package/dist/node-slots/roof.js +12 -0
- package/dist/node-slots/stair.d.ts +2 -0
- package/dist/node-slots/stair.d.ts.map +1 -1
- package/dist/node-slots/stair.js +6 -2
- package/dist/procedural-items/design-placement.d.ts.map +1 -1
- package/dist/procedural-items/design.d.ts +19 -19
- package/dist/procedural-items/fixtures.d.ts +297 -297
- package/dist/procedural-items/fixtures.d.ts.map +1 -1
- package/dist/procedural-items/integration.d.ts +106 -106
- package/dist/procedural-items/joints.d.ts +4 -4
- package/dist/procedural-items/library-colors.d.ts +22 -22
- package/dist/procedural-items/library-colors.d.ts.map +1 -1
- package/dist/procedural-items/motion-controller.d.ts.map +1 -1
- package/dist/procedural-items/node.d.ts +291 -291
- package/dist/procedural-items/query.d.ts +1 -1
- package/dist/procedural-items/query.d.ts.map +1 -1
- package/dist/procedural-items/recipe.d.ts +11 -11
- package/dist/procedural-items/recipe.d.ts.map +1 -1
- package/dist/procedural-items/section.d.ts.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/scene-api.d.ts +1 -0
- package/dist/registry/scene-api.d.ts.map +1 -1
- package/dist/registry/scene-api.js +3 -0
- package/dist/registry/subtree.d.ts.map +1 -1
- package/dist/registry/subtree.js +2 -0
- package/dist/registry/types.d.ts +120 -1
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/schema/assembly.d.ts +41 -41
- package/dist/schema/asset-url.d.ts +1 -1
- package/dist/schema/asset-url.d.ts.map +1 -1
- package/dist/schema/base.d.ts +9 -9
- package/dist/schema/base.d.ts.map +1 -1
- package/dist/schema/camera.d.ts +1 -1
- package/dist/schema/collection-templates.d.ts +20 -20
- package/dist/schema/collection-templates.d.ts.map +1 -1
- package/dist/schema/geometry-metadata.d.ts +7 -7
- package/dist/schema/geometry-metadata.d.ts.map +1 -1
- package/dist/schema/geometry-source.d.ts +26 -16
- package/dist/schema/geometry-source.d.ts.map +1 -1
- package/dist/schema/geometry-source.js +14 -0
- package/dist/schema/index.d.ts +10 -7
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +10 -7
- package/dist/schema/material.d.ts +33 -33
- package/dist/schema/nodes/barrel-roof.d.ts +3 -0
- package/dist/schema/nodes/barrel-roof.d.ts.map +1 -0
- package/dist/schema/nodes/barrel-roof.js +11 -0
- package/dist/schema/nodes/block.d.ts +8 -8
- package/dist/schema/nodes/box-vent.d.ts +13 -13
- package/dist/schema/nodes/building.d.ts +9 -8
- package/dist/schema/nodes/building.d.ts.map +1 -1
- package/dist/schema/nodes/building.js +2 -0
- package/dist/schema/nodes/cabinet.d.ts +130 -129
- package/dist/schema/nodes/cabinet.d.ts.map +1 -1
- package/dist/schema/nodes/cabinet.js +1 -1
- package/dist/schema/nodes/ceiling.d.ts +15 -15
- package/dist/schema/nodes/chimney.d.ts +23 -23
- package/dist/schema/nodes/column.d.ts +207 -199
- package/dist/schema/nodes/column.d.ts.map +1 -1
- package/dist/schema/nodes/column.js +2 -0
- package/dist/schema/nodes/construction-dimension.d.ts +34 -34
- package/dist/schema/nodes/cupola.d.ts +15 -15
- package/dist/schema/nodes/curtain-wall.d.ts +21 -20
- package/dist/schema/nodes/curtain-wall.d.ts.map +1 -1
- package/dist/schema/nodes/curtain-wall.js +23 -0
- package/dist/schema/nodes/door.d.ts +50 -43
- package/dist/schema/nodes/door.d.ts.map +1 -1
- package/dist/schema/nodes/door.js +19 -0
- package/dist/schema/nodes/dormer.d.ts +37 -36
- package/dist/schema/nodes/dormer.d.ts.map +1 -1
- package/dist/schema/nodes/downspout.d.ts +17 -17
- package/dist/schema/nodes/duct-fitting.d.ts +24 -24
- package/dist/schema/nodes/duct-segment.d.ts +14 -14
- package/dist/schema/nodes/duct-terminal.d.ts +12 -12
- package/dist/schema/nodes/elevator.d.ts +15 -15
- package/dist/schema/nodes/eyebrow-vent.d.ts +13 -13
- package/dist/schema/nodes/fence-feature.d.ts +37 -37
- package/dist/schema/nodes/fence-types.d.ts +32 -0
- package/dist/schema/nodes/fence-types.d.ts.map +1 -0
- package/dist/schema/nodes/fence-types.js +22 -0
- package/dist/schema/nodes/fence.d.ts +43 -72
- package/dist/schema/nodes/fence.d.ts.map +1 -1
- package/dist/schema/nodes/fence.js +4 -20
- package/dist/schema/nodes/floor-opening.d.ts +8 -8
- package/dist/schema/nodes/guide.d.ts +8 -8
- package/dist/schema/nodes/gutter.d.ts +14 -14
- package/dist/schema/nodes/gutter.d.ts.map +1 -1
- package/dist/schema/nodes/gutter.js +6 -5
- package/dist/schema/nodes/hvac-equipment.d.ts +13 -13
- package/dist/schema/nodes/imported-mesh.d.ts +8 -8
- package/dist/schema/nodes/item.d.ts +30 -25
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/lean-to-extension.d.ts +36 -36
- package/dist/schema/nodes/level.d.ts +9 -9
- package/dist/schema/nodes/lineset.d.ts +8 -8
- package/dist/schema/nodes/liquid-line.d.ts +8 -8
- package/dist/schema/nodes/measurement.d.ts +8 -8
- package/dist/schema/nodes/opening-types.d.ts +13 -13
- package/dist/schema/nodes/opening-types.d.ts.map +1 -1
- package/dist/schema/nodes/pipe-fitting.d.ts +15 -15
- package/dist/schema/nodes/pipe-segment.d.ts +11 -11
- package/dist/schema/nodes/pipe-trap.d.ts +9 -9
- package/dist/schema/nodes/ridge-vent.d.ts +14 -14
- package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
- package/dist/schema/nodes/ridge-vent.js +3 -1
- package/dist/schema/nodes/roof-glazing-config.d.ts +90 -0
- package/dist/schema/nodes/roof-glazing-config.d.ts.map +1 -0
- package/dist/schema/nodes/roof-glazing-config.js +34 -0
- package/dist/schema/nodes/roof-glazing.d.ts +57 -0
- package/dist/schema/nodes/roof-glazing.d.ts.map +1 -0
- package/dist/schema/nodes/roof-glazing.js +514 -0
- package/dist/schema/nodes/roof-segment-resize.d.ts +4 -0
- package/dist/schema/nodes/roof-segment-resize.d.ts.map +1 -0
- package/dist/schema/nodes/roof-segment-resize.js +21 -0
- package/dist/schema/nodes/roof-segment-shape.d.ts +5 -0
- package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-shape.js +44 -0
- package/dist/schema/nodes/roof-segment-walls.d.ts +1 -1
- package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-walls.js +24 -0
- package/dist/schema/nodes/roof-segment.d.ts +153 -46
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +91 -20
- package/dist/schema/nodes/roof-types.d.ts +14 -0
- package/dist/schema/nodes/roof-types.d.ts.map +1 -0
- package/dist/schema/nodes/roof-types.js +14 -0
- package/dist/schema/nodes/roof.d.ts +49 -49
- package/dist/schema/nodes/scan.d.ts +8 -8
- package/dist/schema/nodes/separator.d.ts +8 -8
- package/dist/schema/nodes/shelf.d.ts +16 -16
- package/dist/schema/nodes/site-facts.d.ts +64 -0
- package/dist/schema/nodes/site-facts.d.ts.map +1 -0
- package/dist/schema/nodes/site-facts.js +73 -0
- package/dist/schema/nodes/site.d.ts +105 -63
- package/dist/schema/nodes/site.d.ts.map +1 -1
- package/dist/schema/nodes/site.js +7 -70
- package/dist/schema/nodes/skylight.d.ts +41 -41
- package/dist/schema/nodes/skylight.d.ts.map +1 -1
- package/dist/schema/nodes/slab.d.ts +21 -21
- package/dist/schema/nodes/solar-panel.d.ts +21 -21
- package/dist/schema/nodes/spawn.d.ts +8 -8
- package/dist/schema/nodes/stair-construction.d.ts +3 -3
- package/dist/schema/nodes/stair-defaults.d.ts +16 -0
- package/dist/schema/nodes/stair-defaults.d.ts.map +1 -0
- package/dist/schema/nodes/stair-defaults.js +15 -0
- package/dist/schema/nodes/stair-segment.d.ts +22 -22
- package/dist/schema/nodes/stair-types.d.ts +29 -0
- package/dist/schema/nodes/stair-types.d.ts.map +1 -0
- package/dist/schema/nodes/stair-types.js +23 -0
- package/dist/schema/nodes/stair.d.ts +51 -75
- package/dist/schema/nodes/stair.d.ts.map +1 -1
- package/dist/schema/nodes/stair.js +6 -20
- package/dist/schema/nodes/structural-grid.d.ts +8 -8
- package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -2
- package/dist/schema/nodes/turbine-vent.d.ts +13 -13
- package/dist/schema/nodes/unit.d.ts +10 -10
- package/dist/schema/nodes/unit.d.ts.map +1 -1
- package/dist/schema/nodes/wall.d.ts +479 -146
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +19 -0
- package/dist/schema/nodes/window.d.ts +55 -39
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/nodes/window.js +10 -0
- package/dist/schema/nodes/zone.d.ts +231 -12
- package/dist/schema/nodes/zone.d.ts.map +1 -1
- package/dist/schema/nodes/zone.js +10 -0
- package/dist/schema/provenance.d.ts +21 -21
- package/dist/schema/scene-material.d.ts +5 -5
- package/dist/schema/site-presentation.d.ts +100 -0
- package/dist/schema/site-presentation.d.ts.map +1 -0
- package/dist/schema/site-presentation.js +83 -0
- package/dist/schema/types.d.ts +1954 -1414
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts.map +1 -1
- package/dist/services/index.d.ts +5 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +5 -1
- package/dist/services/level-height.d.ts.map +1 -1
- package/dist/services/level-height.js +7 -3
- package/dist/services/port-connectivity.d.ts +4 -0
- package/dist/services/port-connectivity.d.ts.map +1 -1
- package/dist/services/port-connectivity.js +35 -0
- package/dist/services/project-file-sink.d.ts +9 -0
- package/dist/services/project-file-sink.d.ts.map +1 -0
- package/dist/services/project-file-sink.js +13 -0
- package/dist/services/roof-bearing.d.ts +62 -0
- package/dist/services/roof-bearing.d.ts.map +1 -0
- package/dist/services/roof-bearing.js +234 -0
- package/dist/services/roof-level.d.ts +121 -0
- package/dist/services/roof-level.d.ts.map +1 -0
- package/dist/services/roof-level.js +280 -0
- package/dist/services/roof-move.d.ts +83 -0
- package/dist/services/roof-move.d.ts.map +1 -0
- package/dist/services/roof-move.js +316 -0
- package/dist/services/stair-surface-snap.d.ts +14 -0
- package/dist/services/stair-surface-snap.d.ts.map +1 -0
- package/dist/services/stair-surface-snap.js +116 -0
- package/dist/services/storey-datum.d.ts +12 -0
- package/dist/services/storey-datum.d.ts.map +1 -0
- package/dist/services/storey-datum.js +18 -0
- package/dist/services/storey.d.ts +51 -5
- package/dist/services/storey.d.ts.map +1 -1
- package/dist/services/storey.js +125 -8
- package/dist/solar-panel-presets.d.ts +2 -2
- package/dist/store/actions/node-actions.d.ts +3613 -3182
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +46 -1
- package/dist/store/derived-node-guard.d.ts.map +1 -1
- package/dist/store/history-control.d.ts +39 -0
- package/dist/store/history-control.d.ts.map +1 -1
- package/dist/store/history-control.js +84 -4
- package/dist/store/scene-annotations.d.ts +7267 -6409
- package/dist/store/scene-annotations.d.ts.map +1 -1
- package/dist/store/scene-preview.d.ts +16 -0
- package/dist/store/scene-preview.d.ts.map +1 -0
- package/dist/store/scene-preview.js +144 -0
- package/dist/store/use-live-node-overrides.d.ts.map +1 -1
- package/dist/store/use-live-terrain.d.ts.map +1 -1
- package/dist/store/use-live-transforms.d.ts.map +1 -1
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +37 -4
- package/dist/systems/elevator/elevator-dispatch.js +1 -1
- package/dist/systems/fence/fence-features.d.ts.map +1 -1
- package/dist/systems/owned-floor-openings.d.ts.map +1 -1
- package/dist/systems/owned-floor-openings.js +24 -3
- package/dist/systems/roof/roof-elevation-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-elevation-system.js +9 -3
- package/dist/systems/roof/roof-elevation.d.ts +5 -0
- package/dist/systems/roof/roof-elevation.d.ts.map +1 -1
- package/dist/systems/roof/roof-elevation.js +91 -62
- package/dist/systems/slab/__fixtures__/floor-step.d.ts +4623 -3516
- package/dist/systems/slab/__fixtures__/floor-step.d.ts.map +1 -1
- package/dist/systems/slab/__fixtures__/raised-room.d.ts +5149 -4076
- package/dist/systems/slab/__fixtures__/raised-room.d.ts.map +1 -1
- package/dist/systems/slab/slab-support.d.ts +6 -3
- package/dist/systems/slab/slab-support.d.ts.map +1 -1
- package/dist/systems/slab/slab-support.js +78 -10
- package/dist/systems/stair/stair-detail-budget.d.ts +2 -2
- package/dist/systems/stair/stair-detail-budget.d.ts.map +1 -1
- package/dist/systems/stair/stair-footprint.d.ts +6 -0
- package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
- package/dist/systems/stair/stair-footprint.js +27 -14
- package/dist/systems/stair/stair-layout.d.ts +2 -2
- package/dist/systems/stair/stair-opening-preview.d.ts +3643 -3214
- package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
- package/dist/systems/stair/stair-presets.d.ts +73 -65
- package/dist/systems/stair/stair-presets.d.ts.map +1 -1
- package/dist/systems/stair/stair-presets.js +16 -9
- package/dist/systems/stair/stair-rail-path.d.ts +1 -1
- package/dist/systems/stair/stair-rise-query.d.ts +16 -0
- package/dist/systems/stair/stair-rise-query.d.ts.map +1 -1
- package/dist/systems/stair/stair-rise-query.js +57 -7
- package/dist/systems/stair/stair-sizing.d.ts +101 -99
- package/dist/systems/stair/stair-sizing.d.ts.map +1 -1
- package/dist/systems/wall/wall-assembly.d.ts +11 -0
- package/dist/systems/wall/wall-assembly.d.ts.map +1 -1
- package/dist/systems/wall/wall-assembly.js +21 -0
- package/dist/systems/wall/wall-curve.d.ts +5 -0
- package/dist/systems/wall/wall-curve.d.ts.map +1 -1
- package/dist/systems/wall/wall-curve.js +13 -0
- package/dist/systems/wall/wall-frame.d.ts.map +1 -1
- package/dist/systems/wall/wall-frame.js +8 -0
- package/dist/systems/wall/wall-room-sides.d.ts +8 -0
- package/dist/systems/wall/wall-room-sides.d.ts.map +1 -1
- package/dist/systems/wall/wall-room-sides.js +60 -7
- package/dist/systems/wall/wall-top.d.ts +7 -4
- package/dist/systems/wall/wall-top.d.ts.map +1 -1
- package/dist/systems/wall/wall-top.js +14 -6
- package/dist/systems/wall/wall-topology.d.ts +4 -0
- package/dist/systems/wall/wall-topology.d.ts.map +1 -1
- package/dist/systems/wall/wall-topology.js +4 -2
- package/dist/systems/wall/wall-trim.d.ts +7 -0
- package/dist/systems/wall/wall-trim.d.ts.map +1 -0
- package/dist/systems/wall/wall-trim.js +10 -0
- package/dist/utils/clone-scene-graph.d.ts.map +1 -1
- package/dist/utils/clone-scene-graph.js +8 -0
- package/dist/utils/ensure-scene-openings.d.ts +7420 -6562
- package/dist/utils/ensure-scene-openings.d.ts.map +1 -1
- package/dist/utils/floor-piece-adoption.d.ts +2 -2
- package/dist/utils/floor-plate-migration.d.ts +3746 -3317
- package/dist/utils/floor-plate-migration.d.ts.map +1 -1
- package/dist/utils/floor-plate-migration.js +2 -2
- package/dist/utils/heal-scene-graph.d.ts +12 -0
- package/dist/utils/heal-scene-graph.d.ts.map +1 -1
- package/dist/utils/heal-scene-graph.js +40 -23
- package/dist/utils/legacy-wall-datums.d.ts.map +1 -1
- package/dist/utils/legacy-wall-datums.js +2 -2
- package/dist/utils/owned-floor-opening-migration.d.ts +3642 -3213
- package/dist/utils/owned-floor-opening-migration.d.ts.map +1 -1
- package/dist/utils/reconcile-structure-on-load.d.ts +3730 -7777
- package/dist/utils/reconcile-structure-on-load.d.ts.map +1 -1
- package/dist/utils/scene-migrations.d.ts +1 -1
- package/dist/utils/scene-migrations.d.ts.map +1 -1
- package/dist/utils/scene-migrations.js +1 -1
- package/dist/utils/semantic-equal.d.ts +3 -0
- package/dist/utils/semantic-equal.d.ts.map +1 -0
- package/dist/utils/semantic-equal.js +26 -0
- package/dist/utils/structure-id.d.ts.map +1 -1
- package/dist/utils/types.d.ts.map +1 -1
- package/dist/utils/wall-face-migration.d.ts +1 -1
- package/dist/utils/wall-face-migration.d.ts.map +1 -1
- package/package.json +36 -10
|
@@ -0,0 +1,942 @@
|
|
|
1
|
+
import { migrateSiteMetadata } from '../schema/nodes/site-facts.js';
|
|
2
|
+
import { footprintOutline, levelFootprintLoops, levelFrame, siteFrame, turnPlanPoint, yawOf, } from './building-footprint.js';
|
|
3
|
+
import { area, containsPoint, difference, distanceToBoundary } from './polygon-boolean.js';
|
|
4
|
+
import { polygonInteriorPoint } from './polygon-label.js';
|
|
5
|
+
import { segmentsIntersect } from './polygon-relations.js';
|
|
6
|
+
import { edgeLength, envelopeFrontEdge, outwardNormal, polygonAreaAbs, rayToPolygon, resolveFrontEdge, setbackEnvelope, } from './setback-envelope.js';
|
|
7
|
+
import { heightAt } from './terrain-field.js';
|
|
8
|
+
import { persistedTerrainFieldOf } from './terrain-source-persisted.js';
|
|
9
|
+
const SIDES = { north: [0, -1], east: [1, 0], south: [0, 1], west: [-1, 0] };
|
|
10
|
+
const OPPOSITE = {
|
|
11
|
+
north: 'south',
|
|
12
|
+
south: 'north',
|
|
13
|
+
east: 'west',
|
|
14
|
+
west: 'east',
|
|
15
|
+
};
|
|
16
|
+
/** What a footprint may lose to a ring's edge and still count as inside it: rounding, not a wall. */
|
|
17
|
+
const FIT_AREA_M2 = 0.01;
|
|
18
|
+
const DEFAULT_SQUARE = 15;
|
|
19
|
+
const DEG = 180 / Math.PI;
|
|
20
|
+
const round = (n, step = 100) => Math.round(n * step) / step || 0;
|
|
21
|
+
const roundPt = (p) => [round(p[0]), round(p[1])];
|
|
22
|
+
function boundsOf(points) {
|
|
23
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
24
|
+
let minZ = Number.POSITIVE_INFINITY;
|
|
25
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
26
|
+
let maxZ = Number.NEGATIVE_INFINITY;
|
|
27
|
+
for (const [x, z] of points) {
|
|
28
|
+
minX = Math.min(minX, x);
|
|
29
|
+
maxX = Math.max(maxX, x);
|
|
30
|
+
minZ = Math.min(minZ, z);
|
|
31
|
+
maxZ = Math.max(maxZ, z);
|
|
32
|
+
}
|
|
33
|
+
return { minX, minZ, maxX, maxZ };
|
|
34
|
+
}
|
|
35
|
+
const boundsCentre = (b) => [(b.minX + b.maxX) / 2, (b.minZ + b.maxZ) / 2];
|
|
36
|
+
function sideOf(dx, dz) {
|
|
37
|
+
if (Math.abs(dx) > Math.abs(dz))
|
|
38
|
+
return dx > 0 ? 'east' : 'west';
|
|
39
|
+
return dz > 0 ? 'south' : 'north';
|
|
40
|
+
}
|
|
41
|
+
function selfIntersects(ring) {
|
|
42
|
+
const n = ring.length;
|
|
43
|
+
for (let i = 0; i < n; i++) {
|
|
44
|
+
for (let j = i + 2; j < n; j++) {
|
|
45
|
+
if (i === 0 && j === n - 1)
|
|
46
|
+
continue;
|
|
47
|
+
const a = ring[i];
|
|
48
|
+
const b = ring[(i + 1) % n];
|
|
49
|
+
const c = ring[j];
|
|
50
|
+
const d = ring[(j + 1) % n];
|
|
51
|
+
if (segmentsIntersect(a, b, c, d))
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
/** A ring's centroid when it lies inside the ring, else its most interior point. */
|
|
58
|
+
function ringCentre(ring) {
|
|
59
|
+
if (ring.length < 3 || polygonAreaAbs(ring) <= 0)
|
|
60
|
+
return null;
|
|
61
|
+
return polygonInteriorPoint({ polygon: ring.map((p) => [p[0], p[1]]) }, true);
|
|
62
|
+
}
|
|
63
|
+
function isPlaceholderSquare(points) {
|
|
64
|
+
if (points.length !== 4)
|
|
65
|
+
return false;
|
|
66
|
+
const corners = new Set(points.map(([x, z]) => `${Math.sign(x)},${Math.sign(z)}`));
|
|
67
|
+
return (corners.size === 4 &&
|
|
68
|
+
points.every(([x, z]) => Math.abs(Math.abs(x) - DEFAULT_SQUARE) < 1e-6 &&
|
|
69
|
+
Math.abs(Math.abs(z) - DEFAULT_SQUARE) < 1e-6));
|
|
70
|
+
}
|
|
71
|
+
/** The site with its legacy metadata lifted onto the real fields (read-side only). */
|
|
72
|
+
function readSiteNode(node) {
|
|
73
|
+
const patch = migrateSiteMetadata(node);
|
|
74
|
+
return Object.keys(patch).length > 0 ? { ...node, ...patch } : node;
|
|
75
|
+
}
|
|
76
|
+
/** The street edge the site records: its front edge, else its first street edge; never a guess. */
|
|
77
|
+
function recordedStreetEdge(site) {
|
|
78
|
+
const n = site.polygon?.points?.length ?? 0;
|
|
79
|
+
const valid = (i) => Number.isInteger(i) && i >= 0 && i < n;
|
|
80
|
+
return valid(site.frontEdge) ? site.frontEdge : site.streetEdges?.find(valid);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The lot's front edge, which the setbacks, the yards and the street are all measured from: the
|
|
84
|
+
* street edge the site records, else the edge facing most nearly north.
|
|
85
|
+
*/
|
|
86
|
+
export function siteFrontEdge(site) {
|
|
87
|
+
return resolveFrontEdge((site.polygon?.points ?? []), recordedStreetEdge(site), site.northRotation ?? 0);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Which way a building's street is, from the house toward it: a unit vector in the site's plan
|
|
91
|
+
* (x east, z south). The street edge its site records (its frontEdge, else its first street edge);
|
|
92
|
+
* with none recorded, the house's own front, its −z turned by its yaw, the way a generated house
|
|
93
|
+
* faces. Every side named as seen from the street reads this one street: a view's street sides,
|
|
94
|
+
* Architect's street order, plan labels and the gables its auto_roof names from the street.
|
|
95
|
+
*/
|
|
96
|
+
export function buildingStreet(nodes, buildingId) {
|
|
97
|
+
const node = buildingId ? nodes[buildingId] : undefined;
|
|
98
|
+
const building = node?.type === 'building' ? node : null;
|
|
99
|
+
const stored = siteOfBuilding(nodes, building);
|
|
100
|
+
const site = stored && readSiteNode(stored);
|
|
101
|
+
const lot = (site?.polygon?.points ?? []);
|
|
102
|
+
const edge = site ? recordedStreetEdge(site) : undefined;
|
|
103
|
+
if (edge !== undefined && lot.length >= 3)
|
|
104
|
+
return outwardNormal(lot, edge);
|
|
105
|
+
return turnPlanPoint(0, -1, yawOf(building?.rotation));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The lot's buildable envelope, in site metres, as the site plan and the 3D site draw it: every
|
|
109
|
+
* lot line pushed in by its setback from the front edge's roles, the corner sight triangles kept
|
|
110
|
+
* clear. Empty when the site records no setbacks, when none of them is more than zero, or when
|
|
111
|
+
* they leave nothing.
|
|
112
|
+
*/
|
|
113
|
+
export function siteSetbackEnvelope(site) {
|
|
114
|
+
const points = (site.polygon?.points ?? []);
|
|
115
|
+
if (!site.setbacks || points.length < 3)
|
|
116
|
+
return [];
|
|
117
|
+
const sightTriangleM = typeof site.sightTriangleFt === 'number' && site.sightTriangleFt > 0
|
|
118
|
+
? site.sightTriangleFt * 0.3048
|
|
119
|
+
: 0;
|
|
120
|
+
return setbackEnvelope(points, site.setbacks, siteFrontEdge(site), {
|
|
121
|
+
streetEdges: (site.streetEdges ?? []).filter((i) => Number.isFinite(i)),
|
|
122
|
+
sightTriangleM,
|
|
123
|
+
}).map((p) => [p[0], p[1]]);
|
|
124
|
+
}
|
|
125
|
+
/** The buildable area in SITE metres; `inset` when its ring is the setback envelope, not the lot. */
|
|
126
|
+
function buildableInSite(site) {
|
|
127
|
+
const lot = (site.polygon?.points ?? []);
|
|
128
|
+
if (!site.setbacks)
|
|
129
|
+
return { state: 'lot', ring: lot, inset: false };
|
|
130
|
+
const envelope = siteSetbackEnvelope(site);
|
|
131
|
+
if (envelope.length >= 3)
|
|
132
|
+
return {
|
|
133
|
+
state: selfIntersects(envelope) ? 'advisory' : 'setbacks',
|
|
134
|
+
ring: envelope,
|
|
135
|
+
inset: true,
|
|
136
|
+
};
|
|
137
|
+
// setbacks of zero exclude nothing (the envelope is empty because there is nothing to draw)
|
|
138
|
+
const excludes = Object.values(site.setbacks).some((m) => typeof m === 'number' && m > 0);
|
|
139
|
+
return excludes
|
|
140
|
+
? { state: 'none', ring: [], inset: false }
|
|
141
|
+
: { state: 'setbacks', ring: lot, inset: false };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Each edge of a ring taken as a front: its length, and how far the ring reaches back from it,
|
|
145
|
+
* square to it (inward by the ring's winding, so an L or a U measures right).
|
|
146
|
+
*/
|
|
147
|
+
export function edgeFronts(ring) {
|
|
148
|
+
return ring.map((p, edge) => {
|
|
149
|
+
const frontage = edgeLength(ring, edge);
|
|
150
|
+
if (frontage < 1e-9)
|
|
151
|
+
return { edge, frontage: 0, depth: 0 };
|
|
152
|
+
const [nx, nz] = outwardNormal(ring, edge);
|
|
153
|
+
let depth = 0;
|
|
154
|
+
for (const v of ring)
|
|
155
|
+
depth = Math.max(depth, -((v[0] - p[0]) * nx + (v[1] - p[1]) * nz));
|
|
156
|
+
return { edge, frontage, depth };
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The fall of a terrain over a lot: its highest point on the lot less its lowest. The ground is
|
|
161
|
+
* a plane on each of the field's triangles (the cells split by the diagonal `heightAt` uses), so the
|
|
162
|
+
* extremes lie at the field's samples on the lot, at the lot's corners, or where a lot line
|
|
163
|
+
* crosses a triangle's edge: a grid line (u or v whole, in samples) or a diagonal (u + v whole).
|
|
164
|
+
* Past the field `heightAt` holds its edge, so only the lines of the field itself count.
|
|
165
|
+
*/
|
|
166
|
+
function terrainFall(field, lot) {
|
|
167
|
+
// a field a single sample wide is its first sample everywhere, as heightAt reads it
|
|
168
|
+
if (field.cols < 2 || field.rows < 2)
|
|
169
|
+
return 0;
|
|
170
|
+
const [ox, oz] = field.origin;
|
|
171
|
+
const s = field.spacing;
|
|
172
|
+
let low = Number.POSITIVE_INFINITY;
|
|
173
|
+
let high = Number.NEGATIVE_INFINITY;
|
|
174
|
+
const take = (height) => {
|
|
175
|
+
low = Math.min(low, height);
|
|
176
|
+
high = Math.max(high, height);
|
|
177
|
+
};
|
|
178
|
+
lot.forEach((a, i) => {
|
|
179
|
+
const b = lot[(i + 1) % lot.length];
|
|
180
|
+
const [ua, va] = [(a[0] - ox) / s, (a[1] - oz) / s];
|
|
181
|
+
const [du, dv] = [(b[0] - a[0]) / s, (b[1] - a[1]) / s];
|
|
182
|
+
take(heightAt(field, a[0], a[1]));
|
|
183
|
+
// where this lot line crosses u = k, v = k and u + v = k, k on the field
|
|
184
|
+
for (const [from, along, lines] of [
|
|
185
|
+
[ua, du, field.cols - 1],
|
|
186
|
+
[va, dv, field.rows - 1],
|
|
187
|
+
[ua + va, du + dv, field.cols + field.rows - 2],
|
|
188
|
+
]) {
|
|
189
|
+
if (Math.abs(along) < 1e-12)
|
|
190
|
+
continue;
|
|
191
|
+
const to = from + along;
|
|
192
|
+
const first = Math.max(0, Math.ceil(Math.min(from, to)));
|
|
193
|
+
const last = Math.min(lines, Math.floor(Math.max(from, to)));
|
|
194
|
+
for (let k = first; k <= last; k++) {
|
|
195
|
+
const t = (k - from) / along;
|
|
196
|
+
if (t > 0 && t < 1)
|
|
197
|
+
take(heightAt(field, a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
// the samples inside, row by row between the lot lines' crossings of that row
|
|
202
|
+
for (let row = 0; row < field.rows; row++) {
|
|
203
|
+
const z = oz + row * s;
|
|
204
|
+
const crossings = [];
|
|
205
|
+
lot.forEach((a, i) => {
|
|
206
|
+
const b = lot[(i + 1) % lot.length];
|
|
207
|
+
if (a[1] <= z !== b[1] <= z)
|
|
208
|
+
crossings.push(a[0] + ((z - a[1]) * (b[0] - a[0])) / (b[1] - a[1]));
|
|
209
|
+
});
|
|
210
|
+
crossings.sort((x0, x1) => x0 - x1);
|
|
211
|
+
for (let k = 0; k + 1 < crossings.length; k += 2) {
|
|
212
|
+
const first = Math.max(0, Math.ceil((crossings[k] - ox) / s));
|
|
213
|
+
const last = Math.min(field.cols - 1, Math.floor((crossings[k + 1] - ox) / s));
|
|
214
|
+
// as heightAt shows it at the sample's place: a spacing finer than the coordinates can
|
|
215
|
+
// hold puts some samples where no point of the lot is
|
|
216
|
+
for (let col = first; col <= last; col++)
|
|
217
|
+
take(heightAt(field, ox + col * s, z));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return high - low;
|
|
221
|
+
}
|
|
222
|
+
const METRES_PER_FOOT = 0.3048;
|
|
223
|
+
/**
|
|
224
|
+
* The ground under the lot: the fall of its terrain across the lot, as the scene holds it (the
|
|
225
|
+
* lot drop-in's read records its own figure over the grid it sampled, which reaches past the
|
|
226
|
+
* lot); with no terrain, what that read found (`metadata.terrainSample`: a lot it found flat
|
|
227
|
+
* gets none), else unread.
|
|
228
|
+
*/
|
|
229
|
+
function groundOf(site, lot) {
|
|
230
|
+
const field = persistedTerrainFieldOf(site);
|
|
231
|
+
const sample = site.metadata
|
|
232
|
+
?.terrainSample;
|
|
233
|
+
if (field)
|
|
234
|
+
return { state: 'sloped', reliefM: terrainFall(field, lot) };
|
|
235
|
+
if (sample?.flat === true)
|
|
236
|
+
return {
|
|
237
|
+
state: 'flat',
|
|
238
|
+
reliefM: typeof sample.reliefFt === 'number' ? sample.reliefFt * METRES_PER_FOOT : 0,
|
|
239
|
+
};
|
|
240
|
+
return { state: 'unread', reliefM: null };
|
|
241
|
+
}
|
|
242
|
+
/* ------------------------------------------------- what stands where */
|
|
243
|
+
function sitesOf(nodes) {
|
|
244
|
+
return Object.values(nodes).filter((node) => node.type === 'site');
|
|
245
|
+
}
|
|
246
|
+
function buildingsOf(nodes) {
|
|
247
|
+
return Object.values(nodes).filter((node) => node.type === 'building');
|
|
248
|
+
}
|
|
249
|
+
function buildingLevels(nodes, building) {
|
|
250
|
+
return (building.children ?? [])
|
|
251
|
+
.map((id) => nodes[id])
|
|
252
|
+
.filter((node) => node?.type === 'level');
|
|
253
|
+
}
|
|
254
|
+
/** The building a level belongs to. */
|
|
255
|
+
function levelBuilding(nodes, levelId) {
|
|
256
|
+
const level = nodes[levelId];
|
|
257
|
+
const parent = level?.parentId ? nodes[level.parentId] : undefined;
|
|
258
|
+
return parent?.type === 'building' ? parent : null;
|
|
259
|
+
}
|
|
260
|
+
function siteOfBuilding(nodes, building) {
|
|
261
|
+
const parent = building?.parentId ? nodes[building.parentId] : undefined;
|
|
262
|
+
if (parent?.type === 'site')
|
|
263
|
+
return parent;
|
|
264
|
+
return sitesOf(nodes)[0] ?? null;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* The building a site read or a placement is about: the one named, else the named level's, else
|
|
268
|
+
* the scene's only building. `ambiguous` when there are several and nothing names one.
|
|
269
|
+
*/
|
|
270
|
+
export function resolveSiteBuilding(nodes, target = {}) {
|
|
271
|
+
if (target.buildingId) {
|
|
272
|
+
const node = nodes[target.buildingId];
|
|
273
|
+
return { building: node?.type === 'building' ? node : null, ambiguous: false };
|
|
274
|
+
}
|
|
275
|
+
if (target.levelId) {
|
|
276
|
+
const building = levelBuilding(nodes, target.levelId);
|
|
277
|
+
if (building)
|
|
278
|
+
return { building, ambiguous: false };
|
|
279
|
+
}
|
|
280
|
+
const buildings = buildingsOf(nodes);
|
|
281
|
+
return {
|
|
282
|
+
building: buildings.length === 1 ? (buildings[0] ?? null) : null,
|
|
283
|
+
ambiguous: buildings.length > 1,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The building's footprint in its level frame: the union of every storey's wall bands, a
|
|
288
|
+
* storey's rooms where it has no walls.
|
|
289
|
+
*/
|
|
290
|
+
export function buildingFootprintRings(nodes, building) {
|
|
291
|
+
const loops = [];
|
|
292
|
+
for (const level of buildingLevels(nodes, building)) {
|
|
293
|
+
const walls = levelFootprintLoops(nodes, level, null);
|
|
294
|
+
if (walls.length > 0) {
|
|
295
|
+
loops.push(...walls);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
for (const id of level.children ?? []) {
|
|
299
|
+
const child = nodes[id];
|
|
300
|
+
if (child?.type === 'zone' && child.polygon.length >= 3)
|
|
301
|
+
loops.push(child.polygon);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (loops.length === 0)
|
|
305
|
+
return [];
|
|
306
|
+
return footprintOutline(loops).map((ring) => ring.map((p) => [p[0], p[1]]));
|
|
307
|
+
}
|
|
308
|
+
/* ------------------------------------------------------- measuring */
|
|
309
|
+
/** The ring edge nearest `p`, or the two edges of the corner nearest it. */
|
|
310
|
+
function nearestEdges(ring, p) {
|
|
311
|
+
const n = ring.length;
|
|
312
|
+
let best = 0;
|
|
313
|
+
let bestD = Number.POSITIVE_INFINITY;
|
|
314
|
+
let bestT = 0;
|
|
315
|
+
for (let i = 0; i < n; i++) {
|
|
316
|
+
const a = ring[i];
|
|
317
|
+
const b = ring[(i + 1) % n];
|
|
318
|
+
const dx = b[0] - a[0];
|
|
319
|
+
const dz = b[1] - a[1];
|
|
320
|
+
const l2 = dx * dx + dz * dz;
|
|
321
|
+
const t = l2 ? Math.max(0, Math.min(1, ((p[0] - a[0]) * dx + (p[1] - a[1]) * dz) / l2)) : 0;
|
|
322
|
+
const d = Math.hypot(p[0] - a[0] - dx * t, p[1] - a[1] - dz * t);
|
|
323
|
+
if (d < bestD - 1e-9) {
|
|
324
|
+
bestD = d;
|
|
325
|
+
best = i;
|
|
326
|
+
bestT = t;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (bestT <= 1e-6)
|
|
330
|
+
return [best, (best - 1 + n) % n];
|
|
331
|
+
if (bestT >= 1 - 1e-6)
|
|
332
|
+
return [best, (best + 1) % n];
|
|
333
|
+
return [best];
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* What of `rings` lies outside `ring`, by area (an edge across a notch counts, not only its
|
|
337
|
+
* corners), how far it reaches past the ring's edge, and toward which sides.
|
|
338
|
+
*/
|
|
339
|
+
function spill(rings, ring) {
|
|
340
|
+
const shapes = rings.map((r) => ({ outer: r.map((p) => [p[0], p[1]]), holes: [] }));
|
|
341
|
+
if (ring.length < 3) {
|
|
342
|
+
const all = area(shapes);
|
|
343
|
+
return { areaM2: all, reachM: Number.POSITIVE_INFINITY, sides: [] };
|
|
344
|
+
}
|
|
345
|
+
const outside = difference(shapes, ring.map((p) => [p[0], p[1]]));
|
|
346
|
+
const areaM2 = area(outside);
|
|
347
|
+
if (areaM2 <= FIT_AREA_M2)
|
|
348
|
+
return { areaM2: 0, reachM: 0, sides: [] };
|
|
349
|
+
const boundary = [{ outer: ring.map((p) => [p[0], p[1]]), holes: [] }];
|
|
350
|
+
let reachM = 0;
|
|
351
|
+
const sides = new Set();
|
|
352
|
+
for (const piece of outside) {
|
|
353
|
+
// a piece's corners can all lie on the line it crosses (a house bridging a notch); its most
|
|
354
|
+
// interior point is at least as far past the line as it is from the piece's own edges
|
|
355
|
+
const pole = polygonInteriorPoint({ polygon: piece.outer, holes: piece.holes });
|
|
356
|
+
for (const p of [...[piece.outer, ...piece.holes].flat(), pole]) {
|
|
357
|
+
const d = distanceToBoundary(boundary, p);
|
|
358
|
+
if (d <= 0.005)
|
|
359
|
+
continue;
|
|
360
|
+
reachM = Math.max(reachM, d);
|
|
361
|
+
// past the edge nearest it, or past both edges of the corner nearest it
|
|
362
|
+
for (const edge of nearestEdges(ring, p)) {
|
|
363
|
+
const [nx, nz] = outwardNormal(ring, edge);
|
|
364
|
+
const a = ring[edge];
|
|
365
|
+
if ((p[0] - a[0]) * nx + (p[1] - a[1]) * nz > 0.005)
|
|
366
|
+
sides.add(sideOf(nx, nz));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return { areaM2, reachM, sides: [...sides] };
|
|
371
|
+
}
|
|
372
|
+
/** Signed metres from each face's midpoint, square to the house, to the lot line. */
|
|
373
|
+
function planYards(rings, lot) {
|
|
374
|
+
const b = boundsOf(rings.flat());
|
|
375
|
+
const [mx, mz] = boundsCentre(b);
|
|
376
|
+
const lotShape = [{ outer: lot.map((p) => [p[0], p[1]]), holes: [] }];
|
|
377
|
+
const from = {
|
|
378
|
+
north: [mx, b.minZ],
|
|
379
|
+
south: [mx, b.maxZ],
|
|
380
|
+
west: [b.minX, mz],
|
|
381
|
+
east: [b.maxX, mz],
|
|
382
|
+
};
|
|
383
|
+
const yards = {};
|
|
384
|
+
for (const side of Object.keys(SIDES)) {
|
|
385
|
+
const [dx, dz] = SIDES[side];
|
|
386
|
+
const origin = from[side];
|
|
387
|
+
if (distanceToBoundary(lotShape, origin) < 1e-6)
|
|
388
|
+
yards[side] = 0;
|
|
389
|
+
else if (containsPoint(lotShape, origin)) {
|
|
390
|
+
yards[side] = rayToPolygon(lot, origin, dx, dz)?.distance ?? null;
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
const back = rayToPolygon(lot, origin, -dx, -dz);
|
|
394
|
+
yards[side] = back ? -back.distance : null;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return yards;
|
|
398
|
+
}
|
|
399
|
+
/** The plan side of each yard, seen from the street: standing in it, facing the house. */
|
|
400
|
+
function streetFaces(front) {
|
|
401
|
+
const [fx, fz] = SIDES[front];
|
|
402
|
+
// facing the house is −front; its right hand, with z pointing south, is (−dz, dx)
|
|
403
|
+
const right = sideOf(fz, -fx);
|
|
404
|
+
return { front, rear: OPPOSITE[front], left: OPPOSITE[right], right };
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* The recorded street edge seen from a building turned `yaw`: the plan side it lies on, and the
|
|
408
|
+
* yaw nearest `yaw` that squares the house to it, in radians.
|
|
409
|
+
*/
|
|
410
|
+
function streetAt(site, yaw) {
|
|
411
|
+
const lot = (site.polygon?.points ?? []);
|
|
412
|
+
const n = lot.length;
|
|
413
|
+
const named = recordedStreetEdge(site);
|
|
414
|
+
if (named === undefined || n < 3)
|
|
415
|
+
return null;
|
|
416
|
+
const [nx, nz] = outwardNormal(lot, named);
|
|
417
|
+
const [lx, lz] = turnPlanPoint(nx, nz, -yaw);
|
|
418
|
+
const p = lot[named];
|
|
419
|
+
const q = lot[(named + 1) % n];
|
|
420
|
+
// the house's local x runs along site angle −yaw; square to the edge when −yaw ≡ α (mod 90°)
|
|
421
|
+
const alpha = Math.atan2(q[1] - p[1], q[0] - p[0]);
|
|
422
|
+
const quarter = Math.PI / 2;
|
|
423
|
+
return {
|
|
424
|
+
side: sideOf(lx, lz),
|
|
425
|
+
edge: named,
|
|
426
|
+
squareYaw: -alpha + Math.round((yaw + alpha) / quarter) * quarter,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
function formatAddress(site) {
|
|
430
|
+
const a = site.address;
|
|
431
|
+
if (!a)
|
|
432
|
+
return null;
|
|
433
|
+
const tail = [a.city, [a.state, a.zip].filter(Boolean).join(' ')].filter(Boolean).join(', ');
|
|
434
|
+
const text = [a.street, tail].filter(Boolean).join(', ');
|
|
435
|
+
return text || null;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* How a footprint (rings in the building's level frame) sits on the site the brief reads: its
|
|
439
|
+
* bounds and centre, how far it is off the buildable centre, its yards, and whether it stays in
|
|
440
|
+
* the buildable area, on the lot, or past the lot line.
|
|
441
|
+
*/
|
|
442
|
+
export function measureFootprint(rings, site) {
|
|
443
|
+
const { lot, buildable, street } = site;
|
|
444
|
+
const bounds = boundsOf(rings.flat());
|
|
445
|
+
const centre = boundsCentre(bounds);
|
|
446
|
+
const aim = buildable.centre ?? ringCentre(lot.ring) ?? centre;
|
|
447
|
+
const past = spill(rings, lot.ring);
|
|
448
|
+
const inYards = buildable.state === 'lot' ? past : spill(rings, buildable.ring);
|
|
449
|
+
const plan = planYards(rings, lot.ring);
|
|
450
|
+
const faces = street ? streetFaces(street.side) : null;
|
|
451
|
+
const yards = faces
|
|
452
|
+
? Object.fromEntries(Object.keys(faces).map((key) => [key, plan[faces[key]]]))
|
|
453
|
+
: plan;
|
|
454
|
+
return {
|
|
455
|
+
rings: rings.map((ring) => ring.map((p) => [p[0], p[1]])),
|
|
456
|
+
bounds,
|
|
457
|
+
centre,
|
|
458
|
+
offCentreM: Math.hypot(centre[0] - aim[0], centre[1] - aim[1]),
|
|
459
|
+
yards,
|
|
460
|
+
fit: past.areaM2 > 0 ? 'outside' : inYards.areaM2 > 0 ? 'lot' : 'buildable',
|
|
461
|
+
overhang: {
|
|
462
|
+
lotM: past.reachM,
|
|
463
|
+
setbacksM: Number.isFinite(inYards.reachM) ? inYards.reachM : 0,
|
|
464
|
+
sides: past.areaM2 > 0 ? past.sides : inYards.sides,
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Where new geometry on a level (rings in its level coordinates) crosses its lot line: null
|
|
470
|
+
* while it stays on the lot, or when the level's building has no site. Only the lot is read, so
|
|
471
|
+
* a program drawing room by room pays for no footprint.
|
|
472
|
+
*/
|
|
473
|
+
export function lotOverhang(nodes, levelId, rings) {
|
|
474
|
+
const building = resolveSiteBuilding(nodes, { levelId }).building;
|
|
475
|
+
const lot = (siteOfBuilding(nodes, building)?.polygon?.points ?? []);
|
|
476
|
+
if (lot.length < 3)
|
|
477
|
+
return null;
|
|
478
|
+
const toLevel = levelFrame(building);
|
|
479
|
+
const past = spill(rings, lot.map((p) => toLevel(p[0], p[1])));
|
|
480
|
+
if (past.areaM2 === 0)
|
|
481
|
+
return null;
|
|
482
|
+
return { fit: 'outside', overhangM: round(past.reachM), sides: past.sides };
|
|
483
|
+
}
|
|
484
|
+
/** The building a brief is read for, and the site it stands on (the scene's first site for none). */
|
|
485
|
+
function forBuilding(nodes, target) {
|
|
486
|
+
const resolved = resolveSiteBuilding(nodes, target);
|
|
487
|
+
let building = resolved.building;
|
|
488
|
+
if (!building && resolved.ambiguous) {
|
|
489
|
+
const site = sitesOf(nodes)[0];
|
|
490
|
+
const first = site?.children?.map((id) => nodes[id]).find((node) => node?.type === 'building');
|
|
491
|
+
building = first ?? buildingsOf(nodes)[0] ?? null;
|
|
492
|
+
}
|
|
493
|
+
return { building, stored: siteOfBuilding(nodes, building) };
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* A site named by its id, and the building read on it: the viewed level's when it stands there,
|
|
497
|
+
* else the first standing on it (none on a vacant lot).
|
|
498
|
+
*/
|
|
499
|
+
function onSite(nodes, siteId, levelId) {
|
|
500
|
+
const site = nodes[siteId];
|
|
501
|
+
if (site?.type !== 'site')
|
|
502
|
+
return { building: null, stored: null };
|
|
503
|
+
const viewed = levelId ? levelBuilding(nodes, levelId) : null;
|
|
504
|
+
return {
|
|
505
|
+
building: viewed?.parentId === site.id
|
|
506
|
+
? viewed
|
|
507
|
+
: (buildingsOf(nodes).find((building) => building.parentId === site.id) ?? null),
|
|
508
|
+
stored: site,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* The site a building stands on, in that building's level coordinates. The building is the one
|
|
513
|
+
* named, else the named level's, else the scene's only one, else the site's first; or the site
|
|
514
|
+
* is named, and the building is the named level's when it stands there, else the first standing
|
|
515
|
+
* on it. In site coordinates when no building stands on it; null when the scene has no site with
|
|
516
|
+
* a lot.
|
|
517
|
+
*/
|
|
518
|
+
export function siteBrief(nodes, target = {}) {
|
|
519
|
+
const { building, stored } = target.siteId
|
|
520
|
+
? onSite(nodes, target.siteId, target.levelId)
|
|
521
|
+
: forBuilding(nodes, target);
|
|
522
|
+
if (!stored)
|
|
523
|
+
return null;
|
|
524
|
+
const site = readSiteNode(stored);
|
|
525
|
+
const siteRing = (site.polygon?.points ?? []).map((p) => [p[0], p[1]]);
|
|
526
|
+
if (siteRing.length < 3)
|
|
527
|
+
return null;
|
|
528
|
+
const yaw = building?.rotation?.[1] ?? 0;
|
|
529
|
+
const toLevel = levelFrame(building);
|
|
530
|
+
const inLevel = (ring) => ring.map((p) => toLevel(p[0], p[1]));
|
|
531
|
+
const ring = inLevel(siteRing);
|
|
532
|
+
const inSite = buildableInSite(site);
|
|
533
|
+
const buildableRing = inLevel(inSite.ring);
|
|
534
|
+
const facing = streetAt(site, yaw);
|
|
535
|
+
const lotFront = facing ? edgeFronts(siteRing)[facing.edge] : undefined;
|
|
536
|
+
const street = facing && lotFront
|
|
537
|
+
? {
|
|
538
|
+
side: facing.side,
|
|
539
|
+
edge: facing.edge,
|
|
540
|
+
squareRotationDeg: round(facing.squareYaw * DEG, 10),
|
|
541
|
+
frontage: lotFront.frontage,
|
|
542
|
+
depth: lotFront.depth,
|
|
543
|
+
}
|
|
544
|
+
: null;
|
|
545
|
+
const buildable = {
|
|
546
|
+
state: inSite.state,
|
|
547
|
+
ring: buildableRing,
|
|
548
|
+
centre: inSite.state === 'none' ? null : ringCentre(buildableRing),
|
|
549
|
+
areaM2: polygonAreaAbs(inSite.ring),
|
|
550
|
+
edges: edgeFronts(inSite.ring),
|
|
551
|
+
frontEdge: inSite.state === 'none'
|
|
552
|
+
? null
|
|
553
|
+
: inSite.inset
|
|
554
|
+
? envelopeFrontEdge(siteRing, siteFrontEdge(site), inSite.ring)
|
|
555
|
+
: siteFrontEdge(site),
|
|
556
|
+
...(site.setbacks ? { setbacks: site.setbacks } : {}),
|
|
557
|
+
...(site.setbacksSource ? { source: site.setbacksSource } : {}),
|
|
558
|
+
};
|
|
559
|
+
const parcel = site.parcel;
|
|
560
|
+
const lotArea = polygonAreaAbs(siteRing);
|
|
561
|
+
const lot = {
|
|
562
|
+
ring,
|
|
563
|
+
siteRing,
|
|
564
|
+
bounds: boundsOf(ring),
|
|
565
|
+
areaM2: lotArea,
|
|
566
|
+
approximate: Boolean(parcel && ((parcel.notes ?? []).some((note) => /approximate/i.test(note)) || !parcel.apn)),
|
|
567
|
+
footprintRangeM2: [lotArea * 0.3, lotArea * 0.45],
|
|
568
|
+
};
|
|
569
|
+
const rings = building ? buildingFootprintRings(nodes, building) : [];
|
|
570
|
+
const footprint = rings.length > 0 ? measureFootprint(rings, { lot, buildable, street }) : null;
|
|
571
|
+
const others = [];
|
|
572
|
+
for (const other of buildingsOf(nodes)) {
|
|
573
|
+
if (other.id === building?.id || siteOfBuilding(nodes, other)?.id !== stored.id)
|
|
574
|
+
continue;
|
|
575
|
+
const toSite = siteFrame(other);
|
|
576
|
+
const ringsOther = buildingFootprintRings(nodes, other);
|
|
577
|
+
if (ringsOther.length === 0)
|
|
578
|
+
continue;
|
|
579
|
+
const points = ringsOther.flat().map((p) => {
|
|
580
|
+
const s = toSite(p[0], p[1]);
|
|
581
|
+
return toLevel(s[0], s[1]);
|
|
582
|
+
});
|
|
583
|
+
others.push({ buildingId: other.id, bounds: boundsOf(points) });
|
|
584
|
+
}
|
|
585
|
+
return {
|
|
586
|
+
siteId: stored.id,
|
|
587
|
+
buildingId: building?.id ?? null,
|
|
588
|
+
pose: {
|
|
589
|
+
position: [...(building?.position ?? [0, 0, 0])],
|
|
590
|
+
rotationDeg: yaw * DEG,
|
|
591
|
+
},
|
|
592
|
+
lot,
|
|
593
|
+
placeholder: !formatAddress(site) && !parcel && !site.setbacks && isPlaceholderSquare(siteRing),
|
|
594
|
+
buildable,
|
|
595
|
+
street,
|
|
596
|
+
ground: groundOf(stored, siteRing),
|
|
597
|
+
northDeg: (((((site.northRotation ?? 0) + yaw) * DEG) % 360) + 360) % 360,
|
|
598
|
+
address: formatAddress(site),
|
|
599
|
+
parcel: parcel
|
|
600
|
+
? {
|
|
601
|
+
...(parcel.apn ? { apn: parcel.apn } : {}),
|
|
602
|
+
...(parcel.lotAreaSqFt ? { lotAreaSqFt: parcel.lotAreaSqFt } : {}),
|
|
603
|
+
...(parcel.source ? { source: parcel.source } : {}),
|
|
604
|
+
...(parcel.notes?.length ? { notes: parcel.notes } : {}),
|
|
605
|
+
}
|
|
606
|
+
: null,
|
|
607
|
+
zone: site.zone ?? null,
|
|
608
|
+
footprint,
|
|
609
|
+
others,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
const refusal = (code, message) => ({
|
|
613
|
+
ok: false,
|
|
614
|
+
code,
|
|
615
|
+
message,
|
|
616
|
+
});
|
|
617
|
+
/**
|
|
618
|
+
* Where a building goes on its site: the building's position (and, when asked, its rotation)
|
|
619
|
+
* that puts its footprint's centre on the buildable centre, or at the yards a site plan or the
|
|
620
|
+
* person gives. The inputs are pose-independent (an outline in the drawing's own coordinates,
|
|
621
|
+
* yards from the lot lines), so a repeated call gives the same pose. The lot is never resized: a
|
|
622
|
+
* footprint too big for it is still centred, and the brief reports it outside.
|
|
623
|
+
*/
|
|
624
|
+
export function placeBuildingPose(nodes, input) {
|
|
625
|
+
if (!sitesOf(nodes).some((site) => (site.polygon?.points?.length ?? 0) >= 3))
|
|
626
|
+
return refusal('no_site', 'The scene has no site with a lot to stand a building on.');
|
|
627
|
+
const resolved = resolveSiteBuilding(nodes, input);
|
|
628
|
+
if (input.buildingId && !resolved.building)
|
|
629
|
+
return refusal('not_a_building', `${input.buildingId} is not a building.`);
|
|
630
|
+
if (resolved.ambiguous)
|
|
631
|
+
return refusal('which_building', 'The site has several buildings: name the one to place (its id from list_levels, parentId).');
|
|
632
|
+
const building = resolved.building;
|
|
633
|
+
if (!building)
|
|
634
|
+
return refusal('no_building', 'The scene has no building to place.');
|
|
635
|
+
const site = readSiteNode(siteOfBuilding(nodes, building));
|
|
636
|
+
const standing = buildingFootprintRings(nodes, building);
|
|
637
|
+
const current = building.rotation?.[1] ?? 0;
|
|
638
|
+
// a standing house keeps its facing; one about to rise faces the street square
|
|
639
|
+
const yaw = input.rotationDeg !== undefined
|
|
640
|
+
? input.rotationDeg / DEG
|
|
641
|
+
: standing.length === 0
|
|
642
|
+
? (streetAt(site, current)?.squareYaw ?? current)
|
|
643
|
+
: current;
|
|
644
|
+
const rings = input.outline && input.outline.length >= 3
|
|
645
|
+
? [input.outline.map((p) => [p[0], p[1]])]
|
|
646
|
+
: standing;
|
|
647
|
+
if (rings.length === 0)
|
|
648
|
+
return refusal('needs_footprint', 'The building has no walls or rooms yet: pass the outline of the plan you are about to draw, in the coordinates you will draw it.');
|
|
649
|
+
const yards = input.yards ?? {};
|
|
650
|
+
const given = Object.keys(yards).filter((key) => Number.isFinite(yards[key]));
|
|
651
|
+
if (given.includes('front') && given.includes('rear'))
|
|
652
|
+
return refusal('yards_conflict', 'Give the front yard or the rear one, not both: the house fills the rest.');
|
|
653
|
+
if (given.includes('left') && given.includes('right'))
|
|
654
|
+
return refusal('yards_conflict', 'Give the left yard or the right one, not both: the house fills the rest.');
|
|
655
|
+
const before = siteBrief(nodes, { buildingId: building.id });
|
|
656
|
+
if (given.length > 0 && !before.street)
|
|
657
|
+
return refusal('no_street', 'The site has no street edge, so front, rear, left and right mean nothing yet: set the site frontEdge first.');
|
|
658
|
+
if (given.length === 0 && before.others.length > 0)
|
|
659
|
+
return refusal('other_building_on_site', `Another building stands on this site (${before.others.map((o) => o.buildingId).join(', ')}): centring could put one on the other, so give yards.`);
|
|
660
|
+
const lotSite = before.lot.siteRing;
|
|
661
|
+
const inSite = buildableInSite(site);
|
|
662
|
+
const aimRing = inSite.state === 'none' ? lotSite : inSite.ring;
|
|
663
|
+
const [cx, cz] = boundsCentre(boundsOf(rings.flat()));
|
|
664
|
+
const poseAt = (target) => {
|
|
665
|
+
const [tx, tz] = turnPlanPoint(cx, cz, yaw);
|
|
666
|
+
return [target[0] - tx, target[1] - tz];
|
|
667
|
+
};
|
|
668
|
+
const siteRings = (at) => {
|
|
669
|
+
const toSite = siteFrame({ position: [at[0], 0, at[1]], rotation: [0, yaw, 0] });
|
|
670
|
+
return rings.map((ring) => ring.map((p) => toSite(p[0], p[1])));
|
|
671
|
+
};
|
|
672
|
+
const fits = (at) => spill(siteRings(at), aimRing).areaM2 === 0;
|
|
673
|
+
const centre = ringCentre(aimRing) ?? boundsCentre(boundsOf(lotSite));
|
|
674
|
+
let at = poseAt(centre);
|
|
675
|
+
if (!fits(at)) {
|
|
676
|
+
const pole = polygonInteriorPoint({ polygon: aimRing.map((p) => [p[0], p[1]]) });
|
|
677
|
+
const atPole = poseAt(pole);
|
|
678
|
+
if (fits(atPole))
|
|
679
|
+
at = atPole;
|
|
680
|
+
}
|
|
681
|
+
if (given.length > 0) {
|
|
682
|
+
// the street's side as the house will face it, not as it faces now
|
|
683
|
+
const faces = streetFaces(streetAt(site, yaw).side);
|
|
684
|
+
const yardsAt = (p) => {
|
|
685
|
+
const toLevel = levelFrame({ position: [p[0], 0, p[1]], rotation: [0, yaw, 0] });
|
|
686
|
+
return planYards(rings, lotSite.map((q) => toLevel(q[0], q[1])));
|
|
687
|
+
};
|
|
688
|
+
const misses = (p) => {
|
|
689
|
+
const now = yardsAt(p);
|
|
690
|
+
return given.map((key) => {
|
|
691
|
+
const yard = now[faces[key]];
|
|
692
|
+
return yard === null ? null : yard - yards[key];
|
|
693
|
+
});
|
|
694
|
+
};
|
|
695
|
+
// Each yard is moved along its own face's normal; on a turned lot moving one moves the other,
|
|
696
|
+
// so both are solved together. Straight lot lines make it exact in one step.
|
|
697
|
+
const along = given.map((key) => turnPlanPoint(...SIDES[faces[key]], yaw));
|
|
698
|
+
const step = 0.5;
|
|
699
|
+
for (let pass = 0; pass < 6; pass++) {
|
|
700
|
+
const miss = misses(at);
|
|
701
|
+
const blind = given.find((_, i) => miss[i] === null);
|
|
702
|
+
if (blind)
|
|
703
|
+
return refusal('yards_infeasible', `The ${blind} face does not look onto a lot line.`);
|
|
704
|
+
const [r0 = 0, r1 = 0] = miss;
|
|
705
|
+
if (Math.abs(r0) < 1e-3 && Math.abs(r1) < 1e-3)
|
|
706
|
+
break;
|
|
707
|
+
// how each miss changes per metre moved along each face's normal (one yard: a 1×1 system)
|
|
708
|
+
const slope = along.map(([dx, dz]) => misses([at[0] + dx * step, at[1] + dz * step]).map((m, i) => (m - miss[i]) / step));
|
|
709
|
+
const [[a = 0, c = 0] = [], [b = 0, d = 1] = []] = slope;
|
|
710
|
+
const det = a * d - b * c;
|
|
711
|
+
if (Math.abs(det) < 1e-6)
|
|
712
|
+
break;
|
|
713
|
+
const moves = [(r1 * b - r0 * d) / det, (r0 * c - r1 * a) / det];
|
|
714
|
+
at = along.reduce((p, [dx, dz], i) => [p[0] + dx * (moves[i] ?? 0), p[1] + dz * (moves[i] ?? 0)], [at[0], at[1]]);
|
|
715
|
+
}
|
|
716
|
+
const placed = yardsAt(at);
|
|
717
|
+
for (const key of given) {
|
|
718
|
+
const yard = placed[faces[key]];
|
|
719
|
+
if (yard === null || Math.abs(yard - yards[key]) > 0.01)
|
|
720
|
+
return refusal('yards_infeasible', `No place on this lot gives a ${yards[key]} m ${key} yard with the other yards asked: give one of them, or turn the house square to the street (rotationDeg).`);
|
|
721
|
+
}
|
|
722
|
+
for (const key of given) {
|
|
723
|
+
const across = placed[OPPOSITE[faces[key]]];
|
|
724
|
+
if (across === null || across < 0)
|
|
725
|
+
return refusal('yards_infeasible', `A ${yards[key]} m ${key} yard pushes the house ${across === null ? 'off' : `${round(-across)} m past`} the lot line opposite: the lot is too shallow for it on that side.`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
const position = [
|
|
729
|
+
round(at[0], 1e4),
|
|
730
|
+
building.position?.[1] ?? 0,
|
|
731
|
+
round(at[1], 1e4),
|
|
732
|
+
];
|
|
733
|
+
const rotation = [
|
|
734
|
+
building.rotation?.[0] ?? 0,
|
|
735
|
+
round(yaw, 1e6),
|
|
736
|
+
building.rotation?.[2] ?? 0,
|
|
737
|
+
];
|
|
738
|
+
const moved = Math.hypot(position[0] - (building.position?.[0] ?? 0), position[2] - (building.position?.[2] ?? 0)) > 1e-3 || Math.abs(rotation[1] - (building.rotation?.[1] ?? 0)) > 1e-5;
|
|
739
|
+
const placedNodes = { ...nodes, [building.id]: { ...building, position, rotation } };
|
|
740
|
+
const brief = siteBrief(placedNodes, { buildingId: building.id });
|
|
741
|
+
return {
|
|
742
|
+
ok: true,
|
|
743
|
+
buildingId: building.id,
|
|
744
|
+
position,
|
|
745
|
+
rotation,
|
|
746
|
+
moved,
|
|
747
|
+
brief,
|
|
748
|
+
footprint: measureFootprint(rings, brief),
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
/** A site brief's numbers rounded to the centimetre (angles to a tenth of a degree), as agents read them. */
|
|
752
|
+
export function roundedSiteBrief(brief) {
|
|
753
|
+
const bounds = (b) => ({
|
|
754
|
+
minX: round(b.minX),
|
|
755
|
+
minZ: round(b.minZ),
|
|
756
|
+
maxX: round(b.maxX),
|
|
757
|
+
maxZ: round(b.maxZ),
|
|
758
|
+
});
|
|
759
|
+
const front = (edge) => ({
|
|
760
|
+
...edge,
|
|
761
|
+
frontage: round(edge.frontage),
|
|
762
|
+
depth: round(edge.depth),
|
|
763
|
+
});
|
|
764
|
+
const { footprint, street, ground } = brief;
|
|
765
|
+
const [fewest, most] = brief.lot.footprintRangeM2;
|
|
766
|
+
return {
|
|
767
|
+
...brief,
|
|
768
|
+
pose: {
|
|
769
|
+
position: brief.pose.position.map((n) => round(n)),
|
|
770
|
+
rotationDeg: round(brief.pose.rotationDeg, 10),
|
|
771
|
+
},
|
|
772
|
+
lot: {
|
|
773
|
+
...brief.lot,
|
|
774
|
+
ring: brief.lot.ring.map(roundPt),
|
|
775
|
+
siteRing: brief.lot.siteRing.map(roundPt),
|
|
776
|
+
bounds: bounds(brief.lot.bounds),
|
|
777
|
+
areaM2: round(brief.lot.areaM2, 10),
|
|
778
|
+
footprintRangeM2: [Math.round(fewest), Math.round(most)],
|
|
779
|
+
},
|
|
780
|
+
buildable: {
|
|
781
|
+
...brief.buildable,
|
|
782
|
+
ring: brief.buildable.ring.map(roundPt),
|
|
783
|
+
centre: brief.buildable.centre ? roundPt(brief.buildable.centre) : null,
|
|
784
|
+
areaM2: round(brief.buildable.areaM2, 10),
|
|
785
|
+
edges: brief.buildable.edges.map(front),
|
|
786
|
+
},
|
|
787
|
+
street: street ? front(street) : null,
|
|
788
|
+
ground: { ...ground, reliefM: ground.reliefM === null ? null : round(ground.reliefM) },
|
|
789
|
+
northDeg: round(brief.northDeg, 10),
|
|
790
|
+
footprint: footprint
|
|
791
|
+
? {
|
|
792
|
+
bounds: bounds(footprint.bounds),
|
|
793
|
+
centre: roundPt(footprint.centre),
|
|
794
|
+
offCentreM: round(footprint.offCentreM),
|
|
795
|
+
yards: Object.fromEntries(Object.entries(footprint.yards).map(([key, m]) => [
|
|
796
|
+
key,
|
|
797
|
+
m === null ? null : round(m ?? 0),
|
|
798
|
+
])),
|
|
799
|
+
fit: footprint.fit,
|
|
800
|
+
overhang: {
|
|
801
|
+
lotM: round(footprint.overhang.lotM),
|
|
802
|
+
setbacksM: round(footprint.overhang.setbacksM),
|
|
803
|
+
sides: footprint.overhang.sides,
|
|
804
|
+
},
|
|
805
|
+
}
|
|
806
|
+
: null,
|
|
807
|
+
others: brief.others.map((other) => ({ ...other, bounds: bounds(other.bounds) })),
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
const num = (n) => {
|
|
811
|
+
const r = Math.round(n * 10) / 10 || 0;
|
|
812
|
+
return Number.isInteger(r) ? String(r) : r.toFixed(1);
|
|
813
|
+
};
|
|
814
|
+
const fmtPt = (p) => `[${num(p[0])}, ${num(p[1])}]`;
|
|
815
|
+
const span = (b) => `x ${num(b.minX)}..${num(b.maxX)}, z ${num(b.minZ)}..${num(b.maxZ)}`;
|
|
816
|
+
const size = (b) => `${num(b.maxX - b.minX)}×${num(b.maxZ - b.minZ)} m`;
|
|
817
|
+
/** `18×32 m` for a rectangular lot, whatever its turn; null for any other shape. */
|
|
818
|
+
function rectangleSize(ring) {
|
|
819
|
+
if (ring.length !== 4)
|
|
820
|
+
return null;
|
|
821
|
+
const side = (i) => {
|
|
822
|
+
const a = ring[i];
|
|
823
|
+
const b = ring[(i + 1) % 4];
|
|
824
|
+
return [b[0] - a[0], b[1] - a[1]];
|
|
825
|
+
};
|
|
826
|
+
for (let i = 0; i < 4; i++) {
|
|
827
|
+
const [ax, az] = side(i);
|
|
828
|
+
const [bx, bz] = side((i + 1) % 4);
|
|
829
|
+
if (Math.abs(ax * bx + az * bz) > 1e-3 * Math.hypot(ax, az) * Math.hypot(bx, bz))
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
return `${num(Math.hypot(...side(0)))}×${num(Math.hypot(...side(1)))} m`;
|
|
833
|
+
}
|
|
834
|
+
function describeSetbacks(setbacks) {
|
|
835
|
+
const parts = [`front ${num(setbacks.front)}`];
|
|
836
|
+
if (setbacks.left !== undefined || setbacks.right !== undefined)
|
|
837
|
+
parts.push(`left ${num(setbacks.left ?? setbacks.side)}`, `right ${num(setbacks.right ?? setbacks.side)}`);
|
|
838
|
+
else
|
|
839
|
+
parts.push(`sides ${num(setbacks.side)}`);
|
|
840
|
+
parts.push(`rear ${num(setbacks.rear)}`);
|
|
841
|
+
if (setbacks.streetSide !== undefined)
|
|
842
|
+
parts.push(`street side ${num(setbacks.streetSide)}`);
|
|
843
|
+
return `${parts.join(', ')} m`;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* The site in a few lines, as the agent reads it before drawing: the lot (in the building's level
|
|
847
|
+
* coordinates), its facts, the buildable area and its centre, the street and north, and where the
|
|
848
|
+
* footprint stands, or where a new one goes.
|
|
849
|
+
*/
|
|
850
|
+
export function describeSiteBrief(brief) {
|
|
851
|
+
const { lot, buildable, street, footprint } = brief;
|
|
852
|
+
const [px, py, pz] = brief.pose.position;
|
|
853
|
+
const posed = Math.hypot(px, pz) > 1e-3 || Math.abs(brief.pose.rotationDeg) > 0.05;
|
|
854
|
+
const lines = [
|
|
855
|
+
`lot, in ${brief.buildingId ? "this building's level" : 'site (no building stands on it yet)'} coordinates: [${lot.ring.map(fmtPt).join(', ')}]${posed
|
|
856
|
+
? ` (stored in site coordinates; building at [${num(px)}, ${num(py)}, ${num(pz)}], ${num(brief.pose.rotationDeg)}°)`
|
|
857
|
+
: ''}`,
|
|
858
|
+
];
|
|
859
|
+
const dims = rectangleSize(lot.ring);
|
|
860
|
+
const [fewest, most] = lot.footprintRangeM2;
|
|
861
|
+
// the placeholder is no real lot: a share of it says nothing of the house
|
|
862
|
+
const facts = [
|
|
863
|
+
`lot ${dims ? `${dims}, ` : ''}${Math.round(lot.areaM2)} m²${brief.placeholder ? '' : ` (a house usually covers 30–45%: ${Math.round(fewest)}–${Math.round(most)} m²)`}`,
|
|
864
|
+
];
|
|
865
|
+
if (brief.placeholder)
|
|
866
|
+
facts.push('the new-project placeholder: no address or parcel, real property lines unknown');
|
|
867
|
+
if (brief.address)
|
|
868
|
+
facts.push(brief.address);
|
|
869
|
+
if (brief.parcel?.apn)
|
|
870
|
+
facts.push(`APN ${brief.parcel.apn}`);
|
|
871
|
+
if (brief.zone)
|
|
872
|
+
facts.push(`zone ${brief.zone}`);
|
|
873
|
+
if (lot.approximate)
|
|
874
|
+
facts.push('approximate rectangle: real property lines not found');
|
|
875
|
+
lines.push(facts.join(' · '));
|
|
876
|
+
const centre = buildable.centre;
|
|
877
|
+
if (buildable.state === 'none')
|
|
878
|
+
lines.push(`buildable: none — the setbacks (${describeSetbacks(buildable.setbacks)}) leave nothing on this lot`);
|
|
879
|
+
else if (buildable.state === 'lot')
|
|
880
|
+
lines.push(`buildable: the whole lot (no setbacks recorded) · centre ${centre ? fmtPt(centre) : 'none'}`);
|
|
881
|
+
else {
|
|
882
|
+
const front = buildable.edges.find((edge) => edge.edge === buildable.frontEdge);
|
|
883
|
+
const along = street
|
|
884
|
+
? 'along the street'
|
|
885
|
+
: 'along its edge facing north (the setbacks take it as the front until the street is set)';
|
|
886
|
+
lines.push(`buildable${buildable.state === 'advisory' ? ' (advisory: the inset of this concave lot crosses itself)' : ''}: setbacks ${describeSetbacks(buildable.setbacks)}${buildable.source ? ` (${buildable.source})` : ''} · ${span(boundsOf(buildable.ring))} · centre ${centre ? fmtPt(centre) : 'none'} · ${Math.round(buildable.areaM2)} m² · ${front
|
|
887
|
+
? `${num(front.frontage)} m ${along}, ${num(front.depth)} m deep (its edge ${front.edge})`
|
|
888
|
+
: `no edge of it faces ${street ? 'the street' : 'north'}, so no frontage to build along`}`);
|
|
889
|
+
}
|
|
890
|
+
const north = Math.abs(((brief.northDeg + 180) % 360) - 180) < 0.5
|
|
891
|
+
? 'plan up'
|
|
892
|
+
: `${num(brief.northDeg)}° clockwise of plan up`;
|
|
893
|
+
const squared = !street || Math.abs(street.squareRotationDeg - brief.pose.rotationDeg) < 0.06;
|
|
894
|
+
const squaring = street ? `place_building rotationDeg ${num(street.squareRotationDeg)}` : '';
|
|
895
|
+
// a house yet to rise is squared by place_building itself: naming a rotation for it reads as
|
|
896
|
+
// one to draw the plan at
|
|
897
|
+
const facing = !footprint
|
|
898
|
+
? 'a new house is stood square to it'
|
|
899
|
+
: squared
|
|
900
|
+
? 'the house square to it'
|
|
901
|
+
: `${squaring} squares the house to it`;
|
|
902
|
+
lines.push(`${street ? `street: ${street.side} (lot edge ${street.edge}, ${num(street.frontage)} m of frontage, ${num(street.depth)} m deep; ${facing})` : 'street: not set'} · north: ${north}`);
|
|
903
|
+
const { ground } = brief;
|
|
904
|
+
lines.push(ground.state === 'sloped'
|
|
905
|
+
? `ground: sloped, ${num(ground.reliefM ?? 0)} m of fall across the lot`
|
|
906
|
+
: ground.state === 'flat'
|
|
907
|
+
? `ground: read flat (${num(ground.reliefM ?? 0)} m of fall over the grid read round the lot)`
|
|
908
|
+
: 'ground: not read, flat until it is');
|
|
909
|
+
if (!footprint) {
|
|
910
|
+
const aim = centre ?? boundsCentre(lot.bounds);
|
|
911
|
+
lines.push(`footprint: none yet — centre it on ${fmtPt(aim)} (a 12×10 m footprint spans ${span({ minX: aim[0] - 6, maxX: aim[0] + 6, minZ: aim[1] - 5, maxZ: aim[1] + 5 })})${squared
|
|
912
|
+
? ''
|
|
913
|
+
: '; place_building with its outline first stands it there square to the street'}`);
|
|
914
|
+
return lines;
|
|
915
|
+
}
|
|
916
|
+
const measured = Object.entries(footprint.yards).filter((entry) => typeof entry[1] === 'number');
|
|
917
|
+
const yards = measured.length
|
|
918
|
+
? ` · yards ${measured.map(([key, m]) => `${key} ${num(m)}`).join(', ')} m`
|
|
919
|
+
: '';
|
|
920
|
+
const room = buildable.ring.length >= 3 ? boundsOf(buildable.ring) : lot.bounds;
|
|
921
|
+
const tooBig = footprint.bounds.maxX - footprint.bounds.minX > room.maxX - room.minX ||
|
|
922
|
+
footprint.bounds.maxZ - footprint.bounds.minZ > room.maxZ - room.minZ;
|
|
923
|
+
const centred = footprint.offCentreM < 0.25;
|
|
924
|
+
const fix = centred
|
|
925
|
+
? tooBig
|
|
926
|
+
? `: it is bigger than the buildable area (${size(room)}) even centred, so say so`
|
|
927
|
+
: squared
|
|
928
|
+
? ': even centred, the shape of the lot leaves it out: give yards or reshape the plan'
|
|
929
|
+
: `: even centred, it stands askew to the lot: ${squaring} squares it to the street`
|
|
930
|
+
: `: place_building centres it${tooBig ? `, but it is bigger than the buildable area (${size(room)}): say so` : ''}`;
|
|
931
|
+
const where = footprint.fit === 'outside'
|
|
932
|
+
? `${num(footprint.overhang.lotM)} m past the lot line (${footprint.overhang.sides.join(', ')})${fix}`
|
|
933
|
+
: footprint.fit === 'lot'
|
|
934
|
+
? buildable.state === 'none'
|
|
935
|
+
? 'on the lot, with nothing buildable inside the setbacks'
|
|
936
|
+
: `on the lot but ${num(footprint.overhang.setbacksM)} m into the required yards (${footprint.overhang.sides.join(', ')})${fix}`
|
|
937
|
+
: centred
|
|
938
|
+
? 'inside the buildable area, on its centre'
|
|
939
|
+
: `inside the buildable area, ${num(footprint.offCentreM)} m off its centre`;
|
|
940
|
+
lines.push(`footprint: ${size(footprint.bounds)} centred ${fmtPt(footprint.centre)}${yards} · ${where}`);
|
|
941
|
+
return lines;
|
|
942
|
+
}
|