@reekon-tools/boldr-cad 0.1.0 → 1.0.0
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/README.md +81 -9
- package/dist/app/edit.d.ts +12 -1
- package/dist/app/edit.js +96 -11
- package/dist/app/edit.js.map +1 -1
- package/dist/app/state.d.ts +31 -4
- package/dist/app/state.js +31 -2
- package/dist/app/state.js.map +1 -1
- package/dist/data/memory.d.ts +5 -0
- package/dist/data/memory.js +2 -2
- package/dist/data/memory.js.map +1 -1
- package/dist/data/provider.d.ts +19 -7
- package/dist/data/sync.d.ts +7 -2
- package/dist/data/sync.js +115 -64
- package/dist/data/sync.js.map +1 -1
- package/dist/editor/actions.d.ts +1 -2
- package/dist/editor/actions.js +391 -113
- package/dist/editor/actions.js.map +1 -1
- package/dist/editor/confirm.d.ts +23 -0
- package/dist/editor/confirm.js +35 -0
- package/dist/editor/confirm.js.map +1 -0
- package/dist/editor/elevation.d.ts +191 -90
- package/dist/editor/elevation.js +812 -616
- package/dist/editor/elevation.js.map +1 -1
- package/dist/editor/face.d.ts +73 -0
- package/dist/editor/face.js +269 -0
- package/dist/editor/face.js.map +1 -0
- package/dist/editor/files.d.ts +6 -0
- package/dist/editor/files.js +50 -4
- package/dist/editor/files.js.map +1 -1
- package/dist/editor/gestures.d.ts +18 -3
- package/dist/editor/gestures.js +145 -30
- package/dist/editor/gestures.js.map +1 -1
- package/dist/editor/keypad.d.ts +19 -4
- package/dist/editor/keypad.js +39 -9
- package/dist/editor/keypad.js.map +1 -1
- package/dist/editor/keys.js +36 -4
- package/dist/editor/keys.js.map +1 -1
- package/dist/editor/laser.d.ts +20 -4
- package/dist/editor/laser.js +104 -21
- package/dist/editor/laser.js.map +1 -1
- package/dist/editor/linkActions.d.ts +49 -0
- package/dist/editor/linkActions.js +210 -0
- package/dist/editor/linkActions.js.map +1 -0
- package/dist/editor/linkFollow.d.ts +2 -0
- package/dist/editor/linkFollow.js +53 -0
- package/dist/editor/linkFollow.js.map +1 -0
- package/dist/editor/linkWrite.d.ts +13 -0
- package/dist/editor/linkWrite.js +84 -0
- package/dist/editor/linkWrite.js.map +1 -0
- package/dist/editor/links.d.ts +84 -0
- package/dist/editor/links.js +130 -0
- package/dist/editor/links.js.map +1 -0
- package/dist/editor/markup.d.ts +29 -3
- package/dist/editor/markup.js +95 -10
- package/dist/editor/markup.js.map +1 -1
- package/dist/editor/mode.d.ts +40 -2
- package/dist/editor/mode.js +71 -4
- package/dist/editor/mode.js.map +1 -1
- package/dist/editor/ports.d.ts +36 -6
- package/dist/editor/ports.js +10 -1
- package/dist/editor/ports.js.map +1 -1
- package/dist/editor/project.d.ts +38 -6
- package/dist/editor/project.js +167 -27
- package/dist/editor/project.js.map +1 -1
- package/dist/editor/selection.d.ts +10 -0
- package/dist/editor/selection.js +62 -8
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/status.js +3 -0
- package/dist/editor/status.js.map +1 -1
- package/dist/editor/tooltips.d.ts +5 -0
- package/dist/editor/tooltips.js +48 -0
- package/dist/editor/tooltips.js.map +1 -0
- package/dist/editor/view3d.d.ts +17 -0
- package/dist/editor/view3d.js +135 -0
- package/dist/editor/view3d.js.map +1 -0
- package/dist/editor/view3dState.d.ts +39 -0
- package/dist/editor/view3dState.js +44 -0
- package/dist/editor/view3dState.js.map +1 -0
- package/dist/export/dxf.js +1 -1
- package/dist/export/dxf.js.map +1 -1
- package/dist/export/pdf.js +17 -12
- package/dist/export/pdf.js.map +1 -1
- package/dist/export/plan.d.ts +23 -6
- package/dist/export/plan.js +127 -44
- package/dist/export/plan.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model/constraints.js +15 -4
- package/dist/model/constraints.js.map +1 -1
- package/dist/model/demo.js +3 -3
- package/dist/model/demo.js.map +1 -1
- package/dist/model/elevation.d.ts +6 -9
- package/dist/model/elevation.js +5 -13
- package/dist/model/elevation.js.map +1 -1
- package/dist/model/faces.d.ts +58 -0
- package/dist/model/faces.js +197 -0
- package/dist/model/faces.js.map +1 -0
- package/dist/model/facesolve.d.ts +72 -0
- package/dist/model/facesolve.js +369 -0
- package/dist/model/facesolve.js.map +1 -0
- package/dist/model/history.d.ts +3 -2
- package/dist/model/history.js +17 -11
- package/dist/model/history.js.map +1 -1
- package/dist/model/images.d.ts +18 -0
- package/dist/model/images.js +26 -0
- package/dist/model/images.js.map +1 -0
- package/dist/model/links.d.ts +46 -0
- package/dist/model/links.js +73 -0
- package/dist/model/links.js.map +1 -0
- package/dist/model/markup.d.ts +46 -0
- package/dist/model/markup.js +71 -0
- package/dist/model/markup.js.map +1 -0
- package/dist/model/measurement.d.ts +11 -0
- package/dist/model/measurement.js +24 -0
- package/dist/model/measurement.js.map +1 -0
- package/dist/model/openings.d.ts +4 -0
- package/dist/model/openings.js +4 -0
- package/dist/model/openings.js.map +1 -1
- package/dist/model/planGeom.d.ts +72 -2
- package/dist/model/planGeom.js +184 -10
- package/dist/model/planGeom.js.map +1 -1
- package/dist/model/project.js +3 -2
- package/dist/model/project.js.map +1 -1
- package/dist/model/projectfile.js +2 -1
- package/dist/model/projectfile.js.map +1 -1
- package/dist/model/rooms.js +2 -2
- package/dist/model/rooms.js.map +1 -1
- package/dist/model/settings.d.ts +6 -0
- package/dist/model/settings.js +2 -2
- package/dist/model/settings.js.map +1 -1
- package/dist/model/sketch.d.ts +14 -0
- package/dist/model/sketch.js +143 -24
- package/dist/model/sketch.js.map +1 -1
- package/dist/model/smooth.d.ts +6 -0
- package/dist/model/smooth.js +52 -0
- package/dist/model/smooth.js.map +1 -0
- package/dist/model/store.d.ts +12 -0
- package/dist/model/store.js +35 -3
- package/dist/model/store.js.map +1 -1
- package/dist/model/types.d.ts +173 -8
- package/dist/model/wallfaces.d.ts +32 -0
- package/dist/model/wallfaces.js +133 -20
- package/dist/model/wallfaces.js.map +1 -1
- package/dist/model/wallshape.d.ts +15 -0
- package/dist/model/wallshape.js +89 -0
- package/dist/model/wallshape.js.map +1 -0
- package/dist/react/BottomBar.d.ts +9 -5
- package/dist/react/BottomBar.js +213 -24
- package/dist/react/BottomBar.js.map +1 -1
- package/dist/react/Buttons.d.ts +13 -2
- package/dist/react/Buttons.js +37 -5
- package/dist/react/Buttons.js.map +1 -1
- package/dist/react/CadEditor.d.ts +46 -3
- package/dist/react/CadEditor.js +77 -20
- package/dist/react/CadEditor.js.map +1 -1
- package/dist/react/ConfirmSheet.d.ts +4 -0
- package/dist/react/ConfirmSheet.js +31 -0
- package/dist/react/ConfirmSheet.js.map +1 -0
- package/dist/react/ConflictSheet.d.ts +2 -1
- package/dist/react/ConflictSheet.js +16 -8
- package/dist/react/ConflictSheet.js.map +1 -1
- package/dist/react/Drawer.d.ts +8 -2
- package/dist/react/Drawer.js +167 -38
- package/dist/react/Drawer.js.map +1 -1
- package/dist/react/Duck.d.ts +13 -0
- package/dist/react/Duck.js +45 -0
- package/dist/react/Duck.js.map +1 -0
- package/dist/react/Empty3D.d.ts +2 -0
- package/dist/react/Empty3D.js +39 -0
- package/dist/react/Empty3D.js.map +1 -0
- package/dist/react/FitScroll.d.ts +6 -0
- package/dist/react/FitScroll.js +14 -0
- package/dist/react/FitScroll.js.map +1 -0
- package/dist/react/Icon.native.d.ts +6 -0
- package/dist/react/Icon.native.js +4 -0
- package/dist/react/Icon.native.js.map +1 -1
- package/dist/react/Icon.web.d.ts +6 -0
- package/dist/react/Icon.web.js +4 -0
- package/dist/react/Icon.web.js.map +1 -1
- package/dist/react/KeypadSheet.d.ts +9 -2
- package/dist/react/KeypadSheet.js +174 -42
- package/dist/react/KeypadSheet.js.map +1 -1
- package/dist/react/LaserTray.js +8 -5
- package/dist/react/LaserTray.js.map +1 -1
- package/dist/react/MarkupPanel.d.ts +8 -0
- package/dist/react/MarkupPanel.js +67 -0
- package/dist/react/MarkupPanel.js.map +1 -0
- package/dist/react/PageThumb.native.d.ts +7 -2
- package/dist/react/PageThumb.native.js +19 -7
- package/dist/react/PageThumb.native.js.map +1 -1
- package/dist/react/PageThumb.web.d.ts +3 -2
- package/dist/react/PageThumb.web.js +4 -4
- package/dist/react/PageThumb.web.js.map +1 -1
- package/dist/react/PlanCanvas.native.d.ts +1 -1
- package/dist/react/PlanCanvas.native.js +134 -36
- package/dist/react/PlanCanvas.native.js.map +1 -1
- package/dist/react/PlanCanvas.web.js +16 -5
- package/dist/react/PlanCanvas.web.js.map +1 -1
- package/dist/react/Popovers.d.ts +12 -6
- package/dist/react/Popovers.js +53 -26
- package/dist/react/Popovers.js.map +1 -1
- package/dist/react/Rail.d.ts +24 -0
- package/dist/react/Rail.js +324 -34
- package/dist/react/Rail.js.map +1 -1
- package/dist/react/ShapeMenu.d.ts +7 -0
- package/dist/react/ShapeMenu.js +58 -0
- package/dist/react/ShapeMenu.js.map +1 -0
- package/dist/react/Sheet.d.ts +14 -4
- package/dist/react/Sheet.js +54 -9
- package/dist/react/Sheet.js.map +1 -1
- package/dist/react/Slider.d.ts +18 -0
- package/dist/react/Slider.js +27 -0
- package/dist/react/Slider.js.map +1 -0
- package/dist/react/Toast.js +14 -6
- package/dist/react/Toast.js.map +1 -1
- package/dist/react/ToolTip.d.ts +7 -0
- package/dist/react/ToolTip.js +43 -0
- package/dist/react/ToolTip.js.map +1 -0
- package/dist/react/TopBar.d.ts +6 -3
- package/dist/react/TopBar.js +48 -17
- package/dist/react/TopBar.js.map +1 -1
- package/dist/react/Tween.d.ts +7 -0
- package/dist/react/Tween.js +26 -0
- package/dist/react/Tween.js.map +1 -0
- package/dist/react/Tween.native.d.ts +6 -0
- package/dist/react/Tween.native.js +43 -0
- package/dist/react/Tween.native.js.map +1 -0
- package/dist/react/View3D.native.d.ts +4 -0
- package/dist/react/View3D.native.js +103 -0
- package/dist/react/View3D.native.js.map +1 -0
- package/dist/react/View3D.web.d.ts +4 -0
- package/dist/react/View3D.web.js +151 -0
- package/dist/react/View3D.web.js.map +1 -0
- package/dist/react/View3DHost.d.ts +143 -0
- package/dist/react/View3DHost.js +377 -0
- package/dist/react/View3DHost.js.map +1 -0
- package/dist/react/corners.d.ts +7 -0
- package/dist/react/corners.js +51 -0
- package/dist/react/corners.js.map +1 -0
- package/dist/react/easing.d.ts +15 -0
- package/dist/react/easing.js +10 -0
- package/dist/react/easing.js.map +1 -0
- package/dist/react/host.d.ts +7 -2
- package/dist/react/host.js +8 -3
- package/dist/react/host.js.map +1 -1
- package/dist/react/hostKeypad.d.ts +56 -0
- package/dist/react/hostKeypad.js +5 -0
- package/dist/react/hostKeypad.js.map +1 -0
- package/dist/react/motion.d.ts +77 -0
- package/dist/react/motion.js +173 -0
- package/dist/react/motion.js.map +1 -0
- package/dist/react/ports.js +90 -8
- package/dist/react/ports.js.map +1 -1
- package/dist/react/saving.d.ts +15 -0
- package/dist/react/saving.js +76 -0
- package/dist/react/saving.js.map +1 -0
- package/dist/react/store.d.ts +38 -1
- package/dist/react/store.js +31 -1
- package/dist/react/store.js.map +1 -1
- package/dist/react/theme.d.ts +10 -0
- package/dist/react/theme.js +8 -0
- package/dist/react/theme.js.map +1 -1
- package/dist/react/topRow.d.ts +22 -0
- package/dist/react/topRow.js +61 -0
- package/dist/react/topRow.js.map +1 -0
- package/dist/react/touch.d.ts +6 -0
- package/dist/react/touch.js +9 -0
- package/dist/react/touch.js.map +1 -0
- package/dist/render/ctx.d.ts +8 -0
- package/dist/render/draw.d.ts +33 -1
- package/dist/render/draw.js +593 -215
- package/dist/render/draw.js.map +1 -1
- package/dist/render/elevation.d.ts +65 -43
- package/dist/render/elevation.js +414 -140
- package/dist/render/elevation.js.map +1 -1
- package/dist/render/figmaIcons.d.ts +12 -0
- package/dist/render/figmaIcons.js +21 -0
- package/dist/render/figmaIcons.js.map +1 -0
- package/dist/render/hit.d.ts +22 -2
- package/dist/render/hit.js +168 -25
- package/dist/render/hit.js.map +1 -1
- package/dist/render/icons.js +69 -10
- package/dist/render/icons.js.map +1 -1
- package/dist/render/linkTile.d.ts +15 -0
- package/dist/render/linkTile.js +369 -0
- package/dist/render/linkTile.js.map +1 -0
- package/dist/render/markup.d.ts +11 -0
- package/dist/render/markup.js +112 -0
- package/dist/render/markup.js.map +1 -0
- package/dist/render/navigate.d.ts +88 -0
- package/dist/render/navigate.js +100 -0
- package/dist/render/navigate.js.map +1 -0
- package/dist/render/snap.d.ts +20 -1
- package/dist/render/snap.js +118 -25
- package/dist/render/snap.js.map +1 -1
- package/dist/render/squircle.d.ts +8 -0
- package/dist/render/squircle.js +71 -0
- package/dist/render/squircle.js.map +1 -0
- package/dist/render/view.d.ts +115 -2
- package/dist/render/view.js +244 -19
- package/dist/render/view.js.map +1 -1
- package/dist/skia/SkiaDrawCtx.d.ts +30 -2
- package/dist/skia/SkiaDrawCtx.js +198 -43
- package/dist/skia/SkiaDrawCtx.js.map +1 -1
- package/dist/skia/host.d.ts +18 -2
- package/dist/skia/host.js +46 -1
- package/dist/skia/host.js.map +1 -1
- package/dist/solver/equations.js +37 -2
- package/dist/solver/equations.js.map +1 -1
- package/dist/solver/gauss-newton.d.ts +17 -0
- package/dist/solver/gauss-newton.js +144 -36
- package/dist/solver/gauss-newton.js.map +1 -1
- package/dist/solver/linalg.d.ts +45 -2
- package/dist/solver/linalg.js +164 -10
- package/dist/solver/linalg.js.map +1 -1
- package/dist/solver/types.d.ts +5 -0
- package/dist/tools/annotate.d.ts +57 -1
- package/dist/tools/annotate.js +64 -43
- package/dist/tools/annotate.js.map +1 -1
- package/dist/tools/chamfer.d.ts +12 -0
- package/dist/tools/chamfer.js +114 -0
- package/dist/tools/chamfer.js.map +1 -0
- package/dist/tools/corner.d.ts +38 -0
- package/dist/tools/corner.js +99 -0
- package/dist/tools/corner.js.map +1 -0
- package/dist/tools/dim.d.ts +86 -9
- package/dist/tools/dim.js +581 -96
- package/dist/tools/dim.js.map +1 -1
- package/dist/tools/elevation.js +1 -1
- package/dist/tools/elevation.js.map +1 -1
- package/dist/tools/fillet.d.ts +9 -0
- package/dist/tools/fillet.js +86 -0
- package/dist/tools/fillet.js.map +1 -0
- package/dist/tools/freehand.d.ts +3 -2
- package/dist/tools/freehand.js +19 -12
- package/dist/tools/freehand.js.map +1 -1
- package/dist/tools/index.js +14 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/line.d.ts +8 -3
- package/dist/tools/line.js +66 -30
- package/dist/tools/line.js.map +1 -1
- package/dist/tools/modify.d.ts +13 -0
- package/dist/tools/modify.js +105 -25
- package/dist/tools/modify.js.map +1 -1
- package/dist/tools/openings.js +22 -15
- package/dist/tools/openings.js.map +1 -1
- package/dist/tools/registry.d.ts +8 -0
- package/dist/tools/registry.js +42 -2
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/select.d.ts +77 -3
- package/dist/tools/select.js +560 -74
- package/dist/tools/select.js.map +1 -1
- package/dist/tools/shapes.d.ts +14 -0
- package/dist/tools/shapes.js +154 -75
- package/dist/tools/shapes.js.map +1 -1
- package/dist/units/format.d.ts +10 -2
- package/dist/units/format.js +18 -3
- package/dist/units/format.js.map +1 -1
- package/dist/view3d/build.d.ts +35 -0
- package/dist/view3d/build.js +630 -0
- package/dist/view3d/build.js.map +1 -0
- package/dist/view3d/camera.d.ts +60 -0
- package/dist/view3d/camera.js +84 -0
- package/dist/view3d/camera.js.map +1 -0
- package/dist/view3d/fatLines.d.ts +11 -0
- package/dist/view3d/fatLines.js +83 -0
- package/dist/view3d/fatLines.js.map +1 -0
- package/dist/view3d/lines.d.ts +17 -0
- package/dist/view3d/lines.js +271 -0
- package/dist/view3d/lines.js.map +1 -0
- package/dist/view3d/mesh.d.ts +51 -0
- package/dist/view3d/mesh.js +101 -0
- package/dist/view3d/mesh.js.map +1 -0
- package/dist/view3d/poly.d.ts +16 -0
- package/dist/view3d/poly.js +109 -0
- package/dist/view3d/poly.js.map +1 -0
- package/dist/view3d/viewer.d.ts +86 -0
- package/dist/view3d/viewer.js +350 -0
- package/dist/view3d/viewer.js.map +1 -0
- package/package.json +15 -2
- package/src/app/edit.ts +83 -12
- package/src/app/main.ts +11 -5
- package/src/app/state.ts +38 -5
- package/src/data/memory.ts +2 -2
- package/src/data/provider.ts +15 -7
- package/src/data/sync.ts +87 -50
- package/src/editor/actions.ts +292 -83
- package/src/editor/confirm.ts +58 -0
- package/src/editor/elevation.ts +698 -478
- package/src/editor/face.ts +227 -0
- package/src/editor/files.ts +40 -4
- package/src/editor/gestures.ts +147 -31
- package/src/editor/keypad.ts +43 -11
- package/src/editor/keys.ts +25 -5
- package/src/editor/laser.ts +98 -20
- package/src/editor/linkActions.ts +194 -0
- package/src/editor/linkFollow.ts +43 -0
- package/src/editor/linkWrite.ts +77 -0
- package/src/editor/links.ts +181 -0
- package/src/editor/markup.ts +92 -8
- package/src/editor/mode.ts +83 -7
- package/src/editor/ports.ts +37 -6
- package/src/editor/project.ts +155 -26
- package/src/editor/selection.ts +54 -8
- package/src/editor/status.ts +2 -0
- package/src/editor/tooltips.ts +47 -0
- package/src/editor/view3d.ts +119 -0
- package/src/editor/view3dState.ts +61 -0
- package/src/export/dxf.ts +1 -1
- package/src/export/pdf.ts +15 -7
- package/src/export/plan.ts +119 -35
- package/src/index.ts +5 -0
- package/src/input/keyboard.ts +2 -4
- package/src/model/constraints.ts +13 -4
- package/src/model/demo.ts +3 -3
- package/src/model/elevation.ts +6 -16
- package/src/model/faces.ts +153 -0
- package/src/model/facesolve.ts +322 -0
- package/src/model/history.ts +19 -11
- package/src/model/images.ts +35 -0
- package/src/model/links.ts +77 -0
- package/src/model/markup.ts +80 -0
- package/src/model/measurement.ts +26 -0
- package/src/model/openings.ts +6 -0
- package/src/model/planGeom.ts +174 -8
- package/src/model/project.ts +3 -2
- package/src/model/projectfile.ts +2 -1
- package/src/model/rooms.ts +1 -1
- package/src/model/settings.ts +8 -2
- package/src/model/sketch.ts +101 -14
- package/src/model/smooth.ts +51 -0
- package/src/model/store.ts +35 -4
- package/src/model/types.ts +170 -8
- package/src/model/wallfaces.ts +126 -17
- package/src/model/wallshape.ts +97 -0
- package/src/react/BottomBar.tsx +263 -46
- package/src/react/Buttons.tsx +50 -9
- package/src/react/CadEditor.tsx +133 -30
- package/src/react/ConfirmSheet.tsx +38 -0
- package/src/react/ConflictSheet.tsx +19 -12
- package/src/react/Drawer.tsx +213 -110
- package/src/react/Duck.tsx +50 -0
- package/src/react/Empty3D.tsx +32 -0
- package/src/react/FitScroll.tsx +19 -0
- package/src/react/Icon.native.tsx +5 -0
- package/src/react/Icon.web.tsx +5 -0
- package/src/react/KeypadSheet.tsx +253 -60
- package/src/react/LaserTray.tsx +12 -8
- package/src/react/MarkupPanel.tsx +150 -0
- package/src/react/PageThumb.native.tsx +18 -7
- package/src/react/PageThumb.web.tsx +4 -4
- package/src/react/PlanCanvas.native.tsx +151 -34
- package/src/react/PlanCanvas.web.tsx +15 -5
- package/src/react/Popovers.tsx +116 -51
- package/src/react/Rail.tsx +360 -27
- package/src/react/ShapeMenu.tsx +66 -0
- package/src/react/Sheet.tsx +56 -11
- package/src/react/Slider.tsx +48 -0
- package/src/react/Toast.tsx +16 -9
- package/src/react/ToolTip.tsx +49 -0
- package/src/react/TopBar.tsx +97 -39
- package/src/react/Tween.native.tsx +36 -0
- package/src/react/Tween.tsx +24 -0
- package/src/react/View3D.native.tsx +131 -0
- package/src/react/View3D.web.tsx +131 -0
- package/src/react/View3DHost.ts +367 -0
- package/src/react/corners.ts +52 -0
- package/src/react/easing.ts +14 -0
- package/src/react/host.ts +8 -3
- package/src/react/hostKeypad.ts +66 -0
- package/src/react/motion.tsx +239 -0
- package/src/react/ports.ts +78 -9
- package/src/react/saving.ts +80 -0
- package/src/react/store.ts +35 -3
- package/src/react/theme.ts +8 -0
- package/src/react/topRow.ts +71 -0
- package/src/react/touch.ts +10 -0
- package/src/render/ctx.ts +8 -0
- package/src/render/draw.ts +437 -175
- package/src/render/elevation.ts +349 -143
- package/src/render/figmaIcons.ts +22 -0
- package/src/render/hit.ts +140 -21
- package/src/render/icons.ts +69 -10
- package/src/render/linkTile.ts +297 -0
- package/src/render/markup.ts +91 -0
- package/src/render/navigate.ts +114 -0
- package/src/render/snap.ts +105 -22
- package/src/render/squircle.ts +73 -0
- package/src/render/view.ts +255 -19
- package/src/skia/SkiaDrawCtx.ts +163 -41
- package/src/skia/host.ts +46 -1
- package/src/solver/equations.ts +37 -2
- package/src/solver/gauss-newton.ts +125 -28
- package/src/solver/linalg.ts +141 -5
- package/src/solver/types.ts +5 -0
- package/src/styles.css +91 -42
- package/src/tools/annotate.ts +58 -29
- package/src/tools/chamfer.ts +103 -0
- package/src/tools/corner.ts +99 -0
- package/src/tools/dim.ts +524 -92
- package/src/tools/elevation.ts +1 -1
- package/src/tools/fillet.ts +82 -0
- package/src/tools/freehand.ts +20 -16
- package/src/tools/index.ts +17 -4
- package/src/tools/line.ts +59 -23
- package/src/tools/modify.ts +86 -24
- package/src/tools/openings.ts +8 -13
- package/src/tools/registry.ts +27 -2
- package/src/tools/select.ts +424 -75
- package/src/tools/shapes.ts +119 -58
- package/src/ui/ctx.ts +2 -1
- package/src/ui/domPorts.ts +23 -4
- package/src/ui/drawer.ts +6 -26
- package/src/ui/elevation.ts +10 -101
- package/src/ui/keypad.ts +8 -14
- package/src/ui/laser.ts +2 -2
- package/src/ui/menu.ts +63 -17
- package/src/ui/noteinput.ts +3 -3
- package/src/ui/opacity.ts +108 -0
- package/src/ui/palette.ts +67 -12
- package/src/ui/rail.ts +21 -7
- package/src/ui/topbar.ts +4 -14
- package/src/units/format.ts +18 -3
- package/src/view3d/build.ts +607 -0
- package/src/view3d/camera.ts +113 -0
- package/src/view3d/fatLines.ts +83 -0
- package/src/view3d/lines.ts +258 -0
- package/src/view3d/mesh.ts +111 -0
- package/src/view3d/poly.ts +104 -0
- package/src/view3d/viewer.ts +348 -0
- package/dist/react/ElevCanvas.native.d.ts +0 -3
- package/dist/react/ElevCanvas.native.js +0 -58
- package/dist/react/ElevCanvas.native.js.map +0 -1
- package/dist/react/ElevCanvas.web.d.ts +0 -4
- package/dist/react/ElevCanvas.web.js +0 -44
- package/dist/react/ElevCanvas.web.js.map +0 -1
- package/dist/react/ElevationSheet.d.ts +0 -2
- package/dist/react/ElevationSheet.js +0 -38
- package/dist/react/ElevationSheet.js.map +0 -1
- package/dist/render/elevationView.d.ts +0 -3
- package/dist/render/elevationView.js +0 -100
- package/dist/render/elevationView.js.map +0 -1
- package/src/react/ElevCanvas.native.tsx +0 -68
- package/src/react/ElevCanvas.web.tsx +0 -42
- package/src/react/ElevationSheet.tsx +0 -88
- package/src/render/elevationView.ts +0 -73
package/src/model/types.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface Pt extends XY {
|
|
|
7
7
|
fixed?: boolean;
|
|
8
8
|
origin?: boolean;
|
|
9
9
|
datum?: boolean;
|
|
10
|
+
/** on a wall face: a point the plan sets (a corner of the wall, of a door or window) — fixed, kept in step with the plan */
|
|
11
|
+
anchor?: boolean;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export type LineKind = 'line' | 'wall';
|
|
@@ -14,6 +16,10 @@ export interface Line {
|
|
|
14
16
|
a: string; b: string; kind: LineKind; constr: boolean; thick: number;
|
|
15
17
|
/** wall height, inches; unset = the default wall height in Settings */
|
|
16
18
|
height?: number;
|
|
19
|
+
/** on a wall face: an edge the plan sets (the floor, the ceiling, the wall's ends, a door's or window's sides) */
|
|
20
|
+
anchor?: boolean;
|
|
21
|
+
/** on a wall face: an edge of this cabinet */
|
|
22
|
+
cab?: string;
|
|
17
23
|
}
|
|
18
24
|
/** Curves can be walls too (kind 'wall', with a thickness), like straight lines. */
|
|
19
25
|
export interface Circle { c: string; r: number; constr?: boolean; kind?: LineKind; thick?: number }
|
|
@@ -36,6 +42,17 @@ export interface Constraint {
|
|
|
36
42
|
line?: string | null;
|
|
37
43
|
/** dist: aligned, horizontal or vertical */
|
|
38
44
|
kind?: 'al' | 'h' | 'v';
|
|
45
|
+
/**
|
|
46
|
+
* dist, a wall's length: measured along this face of it — +1 the face to the left of its line's A → B, −1 the right
|
|
47
|
+
* — corner to corner, as a tape measure along it reads. diam, a curved wall's: across its outer face (+1) or its
|
|
48
|
+
* inner face (−1). Unset, its centreline.
|
|
49
|
+
*/
|
|
50
|
+
face?: 1 | -1;
|
|
51
|
+
/**
|
|
52
|
+
* pldist between two walls (`l`, and `l2`, the wall `p` is on): which face of each it's measured from — +1 the face
|
|
53
|
+
* toward the other, −1 the far one, 0 the centreline; unset, both centrelines.
|
|
54
|
+
*/
|
|
55
|
+
faces?: [number, number];
|
|
39
56
|
value?: number;
|
|
40
57
|
/** false = reference dimension (shown in parentheses, never drives geometry) */
|
|
41
58
|
driving?: boolean;
|
|
@@ -43,10 +60,32 @@ export interface Constraint {
|
|
|
43
60
|
off?: number;
|
|
44
61
|
/** diameters: direction of the diameter line, radians (default 60°) */
|
|
45
62
|
ang?: number;
|
|
63
|
+
/** diameters: shown, entered and measured as a radius (a fillet's) — `value` is still the diameter */
|
|
64
|
+
rad?: boolean;
|
|
46
65
|
sign?: number;
|
|
47
66
|
layer?: 'print';
|
|
48
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* the drawing's own BOLDR measurement this driving dimension's value is kept in — made automatically by drawings
|
|
69
|
+
* from before Save to group, and still kept in step for them; no new ones are made
|
|
70
|
+
*/
|
|
49
71
|
measurementId?: string;
|
|
72
|
+
/**
|
|
73
|
+
* a job measurement this driving dimension shows (picked to drive a line, or saved to the group): the job's, never the
|
|
74
|
+
* drawing's — its value comes from the job, and a new one is written back only once the person says so. Never set
|
|
75
|
+
* together with measurementId.
|
|
76
|
+
*/
|
|
77
|
+
measurementRef?: LinkTarget;
|
|
78
|
+
/**
|
|
79
|
+
* the host's own record of the laser reading that set this dimension's value (opaque, kept as JSON), handed back when
|
|
80
|
+
* it's saved to the group so the measurement is recorded as the tool's; dropped when the value changes any other way
|
|
81
|
+
*/
|
|
82
|
+
capture?: unknown;
|
|
83
|
+
/** a default nobody measured (a new cabinet's size): it drives the drawing but isn't kept as a measurement until it's entered */
|
|
84
|
+
auto?: boolean;
|
|
85
|
+
/** on a wall face: drawn by the wall view (a cabinet's shape and size, the dimensions along the floor and beside things), not as a plan dimension or badge */
|
|
86
|
+
elev?: boolean;
|
|
87
|
+
/** on a wall face: kept by the plan (a door's or window's shape there, and where the plan locks it), never edited */
|
|
88
|
+
anchor?: boolean;
|
|
50
89
|
}
|
|
51
90
|
|
|
52
91
|
/** A room: its corner points, and (for loops with curves) the line or arc id after each corner. */
|
|
@@ -81,6 +120,11 @@ export interface Opening {
|
|
|
81
120
|
/** centre, inches along the line from its start point */
|
|
82
121
|
at: number;
|
|
83
122
|
w: number;
|
|
123
|
+
/**
|
|
124
|
+
* the width was entered (typed or lasered); until then it's the standard size, shown grey. Unset on drawings from
|
|
125
|
+
* before this was kept: a width other than the standard one was entered.
|
|
126
|
+
*/
|
|
127
|
+
wSet?: boolean;
|
|
84
128
|
type: 'door' | 'window';
|
|
85
129
|
flip: boolean;
|
|
86
130
|
dims?: OpeningDim[];
|
|
@@ -94,7 +138,63 @@ export interface Opening {
|
|
|
94
138
|
sillLocked?: boolean;
|
|
95
139
|
}
|
|
96
140
|
|
|
97
|
-
|
|
141
|
+
/**
|
|
142
|
+
* line … ellipse: markup shapes drawn by a drag, kept as two corners like a cloud (a line: its two ends, like an arrow).
|
|
143
|
+
* link: a tile for one of the job's files (see LinkTarget), at x, y, with an optional leader. (A measurement comes into a
|
|
144
|
+
* drawing only as the dimension it drives; a measurement tile from before that rule still draws, its value live.)
|
|
145
|
+
*/
|
|
146
|
+
export type NoteType = 'pen' | 'arrow' | 'cloud' | 'text' | 'line' | 'rect' | 'triangle' | 'ellipse' | 'link';
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* One of the job's files or measurements, as a drawing points at it. The host finds it by its group and id within the
|
|
150
|
+
* job it's open in — never by `path` — so a copied or moved job's drawings still find theirs.
|
|
151
|
+
*/
|
|
152
|
+
export interface LinkTarget {
|
|
153
|
+
kind: 'file' | 'measurement';
|
|
154
|
+
id: string;
|
|
155
|
+
/** the group it's in (any group of the job) */
|
|
156
|
+
groupId: string;
|
|
157
|
+
/** a form group's column (the host finds the measurement in it) */
|
|
158
|
+
columnId?: string;
|
|
159
|
+
/** the host's own reference, handed back as it was */
|
|
160
|
+
path?: string;
|
|
161
|
+
/**
|
|
162
|
+
* What it was when it was linked: shown until the host says what it is now, offline, in exports, and once it's been
|
|
163
|
+
* removed. Never refreshed by itself (a drawing opened would count as edited).
|
|
164
|
+
*/
|
|
165
|
+
name?: string;
|
|
166
|
+
groupName?: string;
|
|
167
|
+
/** the host's tag for the kind of file (its icon) */
|
|
168
|
+
fileType?: string;
|
|
169
|
+
/** a measurement's kind: 'length', 'angle', or the host's own */
|
|
170
|
+
mkind?: string;
|
|
171
|
+
/** a measurement's value: µm for a length, degrees for an angle */
|
|
172
|
+
value?: number;
|
|
173
|
+
/** that value as the host writes it */
|
|
174
|
+
text?: string;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* What a link is now, as the host says (LinkTarget has what it was when it was linked). A file's kind, for its icon:
|
|
179
|
+
* 'photo', 'pdf', 'document', 'note', 'calculator', 'label', 'drawing' or anything else (a plain page).
|
|
180
|
+
*/
|
|
181
|
+
export interface LinkInfo {
|
|
182
|
+
/** false once the host has looked and it's gone — never while it's still loading */
|
|
183
|
+
exists: boolean;
|
|
184
|
+
name?: string;
|
|
185
|
+
groupName?: string;
|
|
186
|
+
fileType?: string;
|
|
187
|
+
/** a small picture of it: a URL or a data URL */
|
|
188
|
+
thumbUrl?: string;
|
|
189
|
+
mkind?: string;
|
|
190
|
+
/** µm for a length, degrees for an angle */
|
|
191
|
+
value?: number;
|
|
192
|
+
/** the value as the host writes it */
|
|
193
|
+
text?: string;
|
|
194
|
+
/** whether it can be opened from the drawing, and its measurement changed from it (unset: yes) */
|
|
195
|
+
canOpen?: boolean;
|
|
196
|
+
canEdit?: boolean;
|
|
197
|
+
}
|
|
98
198
|
export interface Note {
|
|
99
199
|
id: string;
|
|
100
200
|
type: NoteType;
|
|
@@ -103,14 +203,66 @@ export interface Note {
|
|
|
103
203
|
y?: number;
|
|
104
204
|
text?: string;
|
|
105
205
|
color: string;
|
|
206
|
+
/**
|
|
207
|
+
* text: how tall its letters are on the drawing, in inches (unset: 5") — fixed to the drawing, so it zooms with it as
|
|
208
|
+
* the lines do; the box, padding and corners grow with it. Set by the note's corner handles or the markup panel.
|
|
209
|
+
* link: the tile's side on the drawing, inches (set as it's placed: a tile's size on the screen at that zoom).
|
|
210
|
+
*/
|
|
211
|
+
ts?: number;
|
|
212
|
+
/** text, from before `ts`: a size in screen pixels (14 px read as 5", as the PDF has always printed it) */
|
|
213
|
+
size?: number;
|
|
214
|
+
/** stroke width in screen pixels (unset: 3, a cloud 2.5); not for text */
|
|
215
|
+
width?: number;
|
|
216
|
+
/** dashed or dotted (unset: solid); a note's box takes it too */
|
|
217
|
+
style?: 'dash' | 'dot';
|
|
218
|
+
/** pen strokes and arrows: how each end finishes (unset: round, an arrow's end an arrowhead) */
|
|
219
|
+
startCap?: NoteCap;
|
|
220
|
+
cap?: NoteCap;
|
|
221
|
+
/** link: what it's a tile for (x, y is the tile's centre, `ts` its side on the drawing, inches) */
|
|
222
|
+
link?: LinkTarget;
|
|
223
|
+
/**
|
|
224
|
+
* link: where its leader points, plan inches — the leader runs from the tile's edge to here, so `cap` is the end at
|
|
225
|
+
* what it points to. Unset: no leader. Its look is the note's color, width, style and caps.
|
|
226
|
+
*/
|
|
227
|
+
leader?: [number, number];
|
|
106
228
|
}
|
|
229
|
+
export type NoteCap = 'butt' | 'round' | 'arrow';
|
|
107
230
|
|
|
108
231
|
/**
|
|
109
|
-
* A line drawn on a wall elevation (layout marks, guides). a / b are [s, z]: s inches along the
|
|
110
|
-
* start point A
|
|
232
|
+
* A line drawn on a wall elevation by earlier versions (layout marks, guides). a / b are [s, z]: s inches along the
|
|
233
|
+
* wall from its start point A, z inches up from the floor. Read only to move it into the wall's face (WallFace).
|
|
111
234
|
*/
|
|
112
235
|
export interface ElevLine { id: string; a: [number, number]; b: [number, number]; guide?: boolean }
|
|
113
236
|
|
|
237
|
+
/**
|
|
238
|
+
* A cabinet on a wall face: a rectangle of four face points — bottom-left, bottom-right, top-right and top-left as
|
|
239
|
+
* seen — kept square by constraints. w, h: its width and height constraints.
|
|
240
|
+
*/
|
|
241
|
+
export interface Cabinet {
|
|
242
|
+
bl: string; br: string; tr: string; tl: string;
|
|
243
|
+
w?: string; h?: string;
|
|
244
|
+
/** inches from the wall face out into the room */
|
|
245
|
+
depth: number;
|
|
246
|
+
/** the depth was entered (not the standard one) */
|
|
247
|
+
depthSet?: boolean;
|
|
248
|
+
label?: string;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* What's drawn on one face of a wall (one side of it, as its elevation shows it): a sketch of its own, edited and
|
|
253
|
+
* solved like the plan. x runs across the wall as seen from that side, y up from the floor. The plan's corners,
|
|
254
|
+
* floor, ceiling and doors and windows are in it as anchors (fixed points and edges, ids starting "@"), kept in step
|
|
255
|
+
* with the plan, so what's drawn can be snapped, constrained and dimensioned to them.
|
|
256
|
+
*/
|
|
257
|
+
export interface WallFace extends Sketch {
|
|
258
|
+
cabs: Record<string, Cabinet>;
|
|
259
|
+
/**
|
|
260
|
+
* Where the face's corners were when what's drawn on it was last placed: across as seen, and each in the plan. When
|
|
261
|
+
* one end of the wall moves, what's drawn keeps its place from the end that moved less (it stays where it is).
|
|
262
|
+
*/
|
|
263
|
+
wall?: { u: [number, number]; ends: [[number, number], [number, number]] };
|
|
264
|
+
}
|
|
265
|
+
|
|
114
266
|
export interface Sketch {
|
|
115
267
|
points: Record<string, Pt>;
|
|
116
268
|
lines: Record<string, Line>;
|
|
@@ -121,12 +273,16 @@ export interface Sketch {
|
|
|
121
273
|
openings: Record<string, Opening>;
|
|
122
274
|
notes: Note[];
|
|
123
275
|
seq: { room: number };
|
|
124
|
-
/**
|
|
276
|
+
/** what's drawn on wall elevations, per wall face: key "<wall line id>|<side>" (side 1: left of A → B, -1: right) */
|
|
277
|
+
faces?: Record<string, WallFace>;
|
|
278
|
+
/** earlier versions' lines on wall elevations (same keys): moved into `faces` when the drawing loads */
|
|
125
279
|
elev?: Record<string, ElevLine[]>;
|
|
126
280
|
}
|
|
127
281
|
|
|
128
282
|
/** Photo or plan traced under the drawing. (x, y) is its top-left corner in world inches. */
|
|
129
283
|
export interface Underlay {
|
|
284
|
+
/** which of the page's images (unique on its page) */
|
|
285
|
+
id: string;
|
|
130
286
|
src: string;
|
|
131
287
|
x: number;
|
|
132
288
|
y: number;
|
|
@@ -134,11 +290,14 @@ export interface Underlay {
|
|
|
134
290
|
/** height in inches; when missing, it follows the image's own aspect ratio */
|
|
135
291
|
h?: number;
|
|
136
292
|
opacity?: number;
|
|
137
|
-
/**
|
|
293
|
+
/** turned about its middle, degrees clockwise as it's seen (unset: upright) — x, y, w, h are the box before it's turned */
|
|
294
|
+
rot?: number;
|
|
295
|
+
/** locked images can't be moved, resized or turned (they still show, and can be unlocked) */
|
|
138
296
|
locked?: boolean;
|
|
139
297
|
}
|
|
140
298
|
export interface View { cx: number; cy: number; s: number }
|
|
141
|
-
|
|
299
|
+
/** underlays: the page's photos and plans, drawn in order (the last on top) */
|
|
300
|
+
export interface Page { id: string; name: string; sk: Sketch; underlays: Underlay[]; view: View | null; _fit?: boolean }
|
|
142
301
|
export interface Project { name: string; pages: Page[] }
|
|
143
302
|
|
|
144
303
|
/** Result of degree-of-freedom analysis. */
|
|
@@ -154,5 +313,8 @@ export interface Analysis {
|
|
|
154
313
|
}
|
|
155
314
|
|
|
156
315
|
/** 'odim': a door/window position dimension, id "<opening id>|<part>" (part 'a' / 'b' = distance to a wall end, 'd:<id>' = a placed one). */
|
|
157
|
-
|
|
316
|
+
/** On a wall face, also 'cab' (a cabinet) and 'elev' (one of the wall view's dimension chips; id: what it measures, as JSON). */
|
|
317
|
+
/** 'oanchor': one end of a door or window in the plan, id "<opening>|s0" or "<opening>|s1" */
|
|
318
|
+
/** 'wface': one edge (face) of a wall, id '<line id>|1' (the face to the left of its A → B) or '<line id>|-1' (the right) */
|
|
319
|
+
export type SelType = 'point' | 'line' | 'circle' | 'arc' | 'cons' | 'dim' | 'room' | 'opening' | 'odim' | 'oanchor' | 'note' | 'underlay' | 'cab' | 'elev' | 'wface';
|
|
158
320
|
export interface SelItem { type: SelType; id: string }
|
package/src/model/wallfaces.ts
CHANGED
|
@@ -16,16 +16,81 @@ export interface WallFace {
|
|
|
16
16
|
strips: [number, number][];
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
/**
|
|
20
|
+
* A wall meeting one end of another (not a guide), and its thickness: a straight one, by the point it runs out to
|
|
21
|
+
* (`far`); a curved one, by its centre and which way it leaves the corner (`ccw`: counter-clockwise, from its start).
|
|
22
|
+
*/
|
|
23
|
+
export interface FaceEnd { thick: number; far?: string; arc?: { c: string; ccw: boolean } }
|
|
24
|
+
/** The walls meeting each end of a wall. */
|
|
25
|
+
export interface FaceEnds { a: FaceEnd[]; b: FaceEnd[] }
|
|
26
|
+
|
|
27
|
+
/** How close (inches) counts as the same place, for a wall's end on another wall. */
|
|
28
|
+
const ON = 1e-3;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The walls meeting each end of a wall: those it shares the point with, and those its end sits on partway along (a T —
|
|
32
|
+
* a wall run up to the middle of another). One partway along runs out both ways from the end, as if it were split
|
|
33
|
+
* there, so the faces either side of the end stop at its near face. (A curved wall's end on its centreline, as snapping
|
|
34
|
+
* puts it: its radius is taken from there.)
|
|
35
|
+
*/
|
|
36
|
+
export function faceEnds(sk: Sketch, lid: string): FaceEnds {
|
|
37
|
+
const l = sk.lines[lid], out: FaceEnds = { a: [], b: [] };
|
|
38
|
+
for (const end of ['a', 'b'] as const) {
|
|
39
|
+
const pid = l[end], P = sk.points[pid], list = out[end];
|
|
40
|
+
for (const id in sk.lines) {
|
|
41
|
+
const n = sk.lines[id];
|
|
42
|
+
if (id === lid || n.kind !== 'wall' || n.constr) continue;
|
|
43
|
+
if (n.a === pid || n.b === pid) list.push({ far: n.a === pid ? n.b : n.a, thick: n.thick });
|
|
44
|
+
else if (P && alongWall(sk, n, P)) list.push({ far: n.a, thick: n.thick }, { far: n.b, thick: n.thick });
|
|
45
|
+
}
|
|
46
|
+
// (an arc runs counter-clockwise from its start, a, to its end, b; one drawn as a wall without a thickness is 4½")
|
|
47
|
+
for (const id in sk.arcs) {
|
|
48
|
+
const n = sk.arcs[id], t = n.thick || 4.5;
|
|
49
|
+
if (n.kind !== 'wall' || n.constr) continue;
|
|
50
|
+
if (n.a === pid || n.b === pid) { list.push({ arc: { c: n.c, ccw: n.a === pid }, thick: t }); continue; }
|
|
51
|
+
const C = sk.points[n.c], S = sk.points[n.a];
|
|
52
|
+
if (P && C && S && alongCurve(sk, n.c, hyp(S.x - C.x, S.y - C.y), t, P, n)) list.push({ arc: { c: n.c, ccw: true }, thick: t }, { arc: { c: n.c, ccw: false }, thick: t });
|
|
53
|
+
}
|
|
54
|
+
for (const id in sk.circles) {
|
|
55
|
+
const n = sk.circles[id], t = n.thick || 4.5;
|
|
56
|
+
if (n.kind !== 'wall' || n.constr) continue;
|
|
57
|
+
if (P && alongCurve(sk, n.c, n.r, t, P)) list.push({ arc: { c: n.c, ccw: true }, thick: t }, { arc: { c: n.c, ccw: false }, thick: t });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Whether point P is on straight wall `n` partway along it (within its thickness, short of its ends). */
|
|
64
|
+
function alongWall(sk: Sketch, n: { a: string; b: string; thick: number }, P: XY): boolean {
|
|
65
|
+
const A = sk.points[n.a], B = sk.points[n.b];
|
|
66
|
+
if (!A || !B) return false;
|
|
67
|
+
const L = hyp(B.x - A.x, B.y - A.y);
|
|
68
|
+
if (L < ON) return false;
|
|
69
|
+
const s = ((P.x - A.x) * (B.x - A.x) + (P.y - A.y) * (B.y - A.y)) / L, off = Math.abs((B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)) / L;
|
|
70
|
+
return s > ON && s < L - ON && off <= n.thick / 2 + ON;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Whether point P is on a curved wall (centre `c`, radius `r`, `t` thick) partway along it — for an arc, short of its ends. */
|
|
74
|
+
function alongCurve(sk: Sketch, c: string, r: number, t: number, P: XY, arc?: { a: string; b: string }): boolean {
|
|
75
|
+
const C = sk.points[c];
|
|
76
|
+
if (!C || r < ON || Math.abs(hyp(P.x - C.x, P.y - C.y) - r) > t / 2 + ON) return false;
|
|
77
|
+
if (!arc) return true;
|
|
78
|
+
const A = sk.points[arc.a], B = sk.points[arc.b];
|
|
79
|
+
if (!A || !B) return false;
|
|
80
|
+
const turn = (v: number) => ((v % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);
|
|
81
|
+
const t0 = Math.atan2(A.y - C.y, A.x - C.x), sweep = turn(Math.atan2(B.y - C.y, B.x - C.x) - t0), at = turn(Math.atan2(P.y - C.y, P.x - C.x) - t0);
|
|
82
|
+
return at * r > ON && at < sweep && (sweep - at) * r > ON;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* One face of a straight wall from A to B, `t` thick: `side` +1 the face to the left of A → B, −1 the right. The
|
|
87
|
+
* walls at its ends (`ends`) and every point are looked up by `pt` — the sketch's own, or a solve's trial positions
|
|
88
|
+
* (a face dimension is solved through this). Null if A and B are one point.
|
|
89
|
+
*/
|
|
90
|
+
export function faceSpan(pt: (id: string) => XY, A: XY, B: XY, t: number, side: 1 | -1, ends: FaceEnds): WallFace | null {
|
|
25
91
|
const L = hyp(B.x - A.x, B.y - A.y);
|
|
26
92
|
if (L < 1e-6) return null;
|
|
27
93
|
const ux = (B.x - A.x) / L, uy = (B.y - A.y) / L, nx = -uy * side, ny = ux * side;
|
|
28
|
-
const t = l.kind === 'wall' ? l.thick : 0;
|
|
29
94
|
const F = { x: A.x + nx * (t / 2), y: A.y + ny * (t / 2) };
|
|
30
95
|
|
|
31
96
|
/** Where the face line (F + û s) crosses each face of a neighbouring wall leaving `P` in direction d. */
|
|
@@ -39,18 +104,47 @@ export function wallFace(sk: Sketch, lid: string, side: 1 | -1): WallFace | null
|
|
|
39
104
|
const s1 = at(tn / 2), s2 = at(-tn / 2);
|
|
40
105
|
return [Math.min(s1, s2), Math.max(s1, s2)];
|
|
41
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* Where the face line crosses each face of a curved wall leaving `P` in direction d (its tangent there) around centre
|
|
109
|
+
* `C`: the circles half its thickness either side of it, each where it crosses nearest the corner (`sP`, s at P). A
|
|
110
|
+
* face the line misses is taken along the tangent, as a straight wall's would be.
|
|
111
|
+
*/
|
|
112
|
+
const arcCrossings = (P: XY, C: XY, d: [number, number], tn: number, sP: number, ccw: boolean): [number, number] | null => {
|
|
113
|
+
const den = ux * d[1] - uy * d[0];
|
|
114
|
+
if (Math.abs(den) < 0.05) return null; // (it carries on in line with the face, as a fillet does: no corner)
|
|
115
|
+
const R = hyp(P.x - C.x, P.y - C.y), fx = F.x - C.x, fy = F.y - C.y, b = ux * fx + uy * fy;
|
|
116
|
+
/** Along the tangent: where the face line crosses the line k to its left (a straight wall's face). */
|
|
117
|
+
const along = (k: number) => { const Q = { x: P.x - d[1] * k, y: P.y + d[0] * k }; return ((Q.x - F.x) * d[1] - (Q.y - F.y) * d[0]) / den; };
|
|
118
|
+
/** Where the face line crosses the circle of radius rho (k: the same face along the tangent, if it misses it). */
|
|
119
|
+
const at = (rho: number, k: number) => {
|
|
120
|
+
const disc = b * b - (fx * fx + fy * fy - rho * rho);
|
|
121
|
+
if (rho <= 0 || disc < 0) return along(k);
|
|
122
|
+
const r1 = -b - Math.sqrt(disc), r2 = -b + Math.sqrt(disc);
|
|
123
|
+
return Math.abs(r1 - sP) <= Math.abs(r2 - sP) ? r1 : r2;
|
|
124
|
+
};
|
|
125
|
+
// (left of the tangent is toward the centre for an arc leaving counter-clockwise: its inner face)
|
|
126
|
+
const s1 = at(R + tn / 2, ccw ? -tn / 2 : tn / 2), s2 = at(R - tn / 2, ccw ? tn / 2 : -tn / 2);
|
|
127
|
+
return [Math.min(s1, s2), Math.max(s1, s2)];
|
|
128
|
+
};
|
|
42
129
|
const strips: [number, number][] = [];
|
|
43
130
|
/** One end of the face: s of the corner, collecting the neighbouring walls cut on this side. */
|
|
44
|
-
const end = (
|
|
131
|
+
const end = (P: XY, walls: FaceEnds['a'], atStart: boolean): number => {
|
|
45
132
|
let toward: number | null = null, away: number | null = null;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
133
|
+
for (const n of walls) {
|
|
134
|
+
let d: [number, number], c: [number, number] | null;
|
|
135
|
+
if (n.arc) {
|
|
136
|
+
// a curved wall: it leaves the corner along its tangent there
|
|
137
|
+
const C = pt(n.arc.c), R = hyp(P.x - C.x, P.y - C.y);
|
|
138
|
+
if (R < 1e-6) continue;
|
|
139
|
+
const k = n.arc.ccw ? 1 : -1;
|
|
140
|
+
d = [(-(P.y - C.y) / R) * k, ((P.x - C.x) / R) * k];
|
|
141
|
+
c = arcCrossings(P, C, d, n.thick, atStart ? 0 : L, n.arc.ccw);
|
|
142
|
+
} else {
|
|
143
|
+
const Q = pt(n.far!), Ln = hyp(Q.x - P.x, Q.y - P.y);
|
|
144
|
+
if (Ln < 1e-6) continue;
|
|
145
|
+
d = [(Q.x - P.x) / Ln, (Q.y - P.y) / Ln];
|
|
146
|
+
c = crossings(P, d, n.thick);
|
|
147
|
+
}
|
|
54
148
|
if (!c) continue;
|
|
55
149
|
if (d[0] * nx + d[1] * ny > 0) {
|
|
56
150
|
// the neighbour runs out on this side: the face stops at the neighbour's face (an inside corner)
|
|
@@ -65,7 +159,22 @@ export function wallFace(sk: Sketch, lid: string, side: 1 | -1): WallFace | null
|
|
|
65
159
|
}
|
|
66
160
|
return toward ?? away ?? (atStart ? 0 : L);
|
|
67
161
|
};
|
|
68
|
-
return { s0: end(
|
|
162
|
+
return { s0: end(A, ends.a, true), s1: end(B, ends.b, false), strips };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** One face of straight wall `lid`: `side` +1 is the face to the left of A → B, −1 the right. Null if it isn't a usable line. */
|
|
166
|
+
export function wallFace(sk: Sketch, lid: string, side: 1 | -1): WallFace | null {
|
|
167
|
+
const l = sk.lines[lid];
|
|
168
|
+
if (!l) return null;
|
|
169
|
+
const A = sk.points[l.a], B = sk.points[l.b];
|
|
170
|
+
if (!A || !B) return null;
|
|
171
|
+
return faceSpan(id => sk.points[id], A, B, l.kind === 'wall' ? l.thick : 0, side, faceEnds(sk, lid));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** How long one face of a wall is, corner to corner (what a tape measure along it reads); its centreline if it's not a wall. */
|
|
175
|
+
export function faceLength(sk: Sketch, lid: string, side: 1 | -1): number {
|
|
176
|
+
const f = wallFace(sk, lid, side);
|
|
177
|
+
return f ? f.s1 - f.s0 : 0;
|
|
69
178
|
}
|
|
70
179
|
|
|
71
180
|
/** A face corner as a point: on the face (half the wall's thickness off the centerline) at the corner. */
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { hyp } from './geom';
|
|
2
|
+
import type { Sketch, XY } from './types';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
The outline of each straight wall, with its ends cut to fit where walls meet: two walls meet in a mitre (the cut
|
|
6
|
+
runs from the inside corner to the outside corner), three or more share the point where they meet (each wall's
|
|
7
|
+
end runs to it), a free end is square. Where walls meet at a sharp angle the mitre would run far out, so the outside
|
|
8
|
+
corner is cut off flat instead (a bevel, its own piece). Where a curved wall joins, the straight wall runs on half
|
|
9
|
+
its thickness past the joint, as before, so the two overlap.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** A piece of wall to fill: a straight wall (`id`), or a bevel at a sharp joint (`of`: a wall it belongs to). */
|
|
13
|
+
export interface WallPiece { id: string | null; of: string; pts: XY[] }
|
|
14
|
+
|
|
15
|
+
const left = (u: XY): XY => ({ x: -u.y, y: u.x });
|
|
16
|
+
const right = (u: XY): XY => ({ x: u.y, y: -u.x });
|
|
17
|
+
const at = (p: XY, n: XY, k: number): XY => ({ x: p.x + n.x * k, y: p.y + n.y * k });
|
|
18
|
+
|
|
19
|
+
/** Where two lines (a point and a direction each) cross; for parallel ones, the middle of the two points if they're the same line, else null. */
|
|
20
|
+
function cross(p1: XY, d1: XY, p2: XY, d2: XY): XY | null {
|
|
21
|
+
const c = d1.x * d2.y - d1.y * d2.x;
|
|
22
|
+
if (Math.abs(c) < 1e-9) {
|
|
23
|
+
const off = Math.abs((p2.x - p1.x) * d1.y - (p2.y - p1.y) * d1.x);
|
|
24
|
+
return off < 1e-6 ? { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 } : null;
|
|
25
|
+
}
|
|
26
|
+
const l = ((p2.x - p1.x) * d2.y - (p2.y - p1.y) * d2.x) / c;
|
|
27
|
+
return { x: p1.x + d1.x * l, y: p1.y + d1.y * l };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface End { id: string; u: XY; t: number }
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The pieces to fill for the sketch's straight walls (`show`: which to include, e.g. not hidden construction walls).
|
|
34
|
+
* Each wall's outline runs: its start's right corner, its end's right corner, (its end point, at a joint), its end's
|
|
35
|
+
* left corner, its start's left corner, (its start point, at a joint) — right and left as seen going from start to end.
|
|
36
|
+
*/
|
|
37
|
+
export function wallPieces(sk: Sketch, show: (w: { constr?: boolean }) => boolean = () => true): WallPiece[] {
|
|
38
|
+
const walls = Object.entries(sk.lines).filter(([, l]) => l.kind === 'wall' && show(l));
|
|
39
|
+
// what meets at each point: straight walls (their direction away from it) and whether a curved wall does
|
|
40
|
+
/** at each point a curved wall ends: the centres of those curves */
|
|
41
|
+
const ends = new Map<string, End[]>(), curved = new Map<string, XY[]>();
|
|
42
|
+
for (const [id, l] of walls) {
|
|
43
|
+
const A = sk.points[l.a], B = sk.points[l.b], L = hyp(B.x - A.x, B.y - A.y);
|
|
44
|
+
if (L < 1e-9) continue;
|
|
45
|
+
const u = { x: (B.x - A.x) / L, y: (B.y - A.y) / L };
|
|
46
|
+
(ends.get(l.a) ?? ends.set(l.a, []).get(l.a)!).push({ id, u, t: l.thick });
|
|
47
|
+
(ends.get(l.b) ?? ends.set(l.b, []).get(l.b)!).push({ id, u: { x: -u.x, y: -u.y }, t: l.thick });
|
|
48
|
+
}
|
|
49
|
+
for (const a of Object.values(sk.arcs)) {
|
|
50
|
+
if (a.kind !== 'wall' || !show(a)) continue;
|
|
51
|
+
for (const p of [a.a, a.b]) (curved.get(p) ?? curved.set(p, []).get(p)!).push(sk.points[a.c]);
|
|
52
|
+
}
|
|
53
|
+
/** whether a straight wall leaving P along u runs on into a curve there (tangent to it: a fillet) */
|
|
54
|
+
const tangent = (pid: string, u: XY) => {
|
|
55
|
+
const P = sk.points[pid];
|
|
56
|
+
return (curved.get(pid) ?? []).every(o => Math.abs(u.x * (P.x - o.x) + u.y * (P.y - o.y)) < 0.02 * (hyp(P.x - o.x, P.y - o.y) || 1));
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** each wall end's two corners: [left, right] as seen going away from the point; joint: whether the point itself is part of its outline */
|
|
60
|
+
const corners = new Map<string, { l: XY; r: XY; joint: boolean }>();
|
|
61
|
+
const bevels: WallPiece[] = [];
|
|
62
|
+
for (const [pid, list] of ends) {
|
|
63
|
+
const P = sk.points[pid];
|
|
64
|
+
if (list.length === 1 || curved.has(pid)) {
|
|
65
|
+
// a free end is square, and so is one running on into a curve (a fillet: the curve's end is square to it too);
|
|
66
|
+
// next to a curve at an angle, run on half the thickness so the two overlap
|
|
67
|
+
for (const e of list) {
|
|
68
|
+
const Q = curved.has(pid) && !tangent(pid, e.u) ? at(P, e.u, -e.t / 2) : P;
|
|
69
|
+
corners.set(e.id + '|' + pid, { l: at(Q, left(e.u), e.t / 2), r: at(Q, right(e.u), e.t / 2), joint: false });
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// walls around the point, counter-clockwise; between each and the next, the corner where their sides cross
|
|
74
|
+
const sorted = [...list].sort((p, q) => Math.atan2(p.u.y, p.u.x) - Math.atan2(q.u.y, q.u.x));
|
|
75
|
+
const ccw = new Map<number, XY>(), cw = new Map<number, XY>();
|
|
76
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
77
|
+
const a = sorted[i], b = sorted[(i + 1) % sorted.length];
|
|
78
|
+
const ea = at(P, left(a.u), a.t / 2), eb = at(P, right(b.u), b.t / 2);
|
|
79
|
+
const c = cross(ea, a.u, eb, b.u), limit = 2 * Math.max(a.t, b.t);
|
|
80
|
+
if (c && hyp(c.x - P.x, c.y - P.y) <= limit) { ccw.set(i, c); cw.set((i + 1) % sorted.length, c); continue; }
|
|
81
|
+
// too sharp (or parallel sides that don't meet): each side stops square, and a bevel closes the corner
|
|
82
|
+
ccw.set(i, ea); cw.set((i + 1) % sorted.length, eb);
|
|
83
|
+
if (hyp(ea.x - eb.x, ea.y - eb.y) > 1e-6) bevels.push({ id: null, of: a.id, pts: [P, ea, eb] });
|
|
84
|
+
}
|
|
85
|
+
sorted.forEach((e, i) => corners.set(e.id + '|' + pid, { l: ccw.get(i)!, r: cw.get(i)!, joint: true }));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const out: WallPiece[] = [];
|
|
89
|
+
for (const [id, l] of walls) {
|
|
90
|
+
const a = corners.get(id + '|' + l.a), b = corners.get(id + '|' + l.b);
|
|
91
|
+
if (!a || !b) continue;
|
|
92
|
+
// at the start, away from it is along the wall; at the end, back along it — so its left is the wall's right
|
|
93
|
+
const pts = [a.r, b.l, ...(b.joint ? [sk.points[l.b]] : []), b.r, a.l, ...(a.joint ? [sk.points[l.a]] : [])];
|
|
94
|
+
out.push({ id, of: id, pts: pts.map(p => ({ x: p.x, y: p.y })) });
|
|
95
|
+
}
|
|
96
|
+
return [...out, ...bevels];
|
|
97
|
+
}
|