@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/skia/SkiaDrawCtx.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
Skia as SkiaApi, SkCanvas, SkColor, SkFont, SkImage, SkPaint, SkPathBuilder, SkTypeface,
|
|
2
|
+
Skia as SkiaApi, SkCanvas, SkColor, SkFont, SkImage, SkPaint, SkPath, SkPathBuilder, SkTypeface,
|
|
3
3
|
} from '@shopify/react-native-skia/lib/typescript/src/skia/types';
|
|
4
4
|
import type { DrawCtx } from '../render/ctx';
|
|
5
5
|
|
|
@@ -72,38 +72,77 @@ export function parseFont(font: string): { weight: number; size: number } {
|
|
|
72
72
|
return { weight: w, size: Number(m[2]) };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
interface FontPair { main: SkFont; fb: SkFont | null }
|
|
75
|
+
interface FontPair { main: SkFont; fb: SkFont | null; metrics: { ascent: number; descent: number; size: number } }
|
|
76
|
+
interface Run { text: string; font: SkFont; width: number }
|
|
76
77
|
|
|
78
|
+
/** Caches stay small: a drawing has a few dozen styles and labels; past this they start again. */
|
|
79
|
+
const CACHE_MAX = 2000;
|
|
80
|
+
const remember = <K, V>(m: Map<K, V>, k: K, v: V): V => { if (m.size >= CACHE_MAX) m.clear(); m.set(k, v); return v; };
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
Every call into Skia crosses from JavaScript to native code on a device, and every object it makes has to be
|
|
84
|
+
collected again — at 120 frames a second that is what makes drawing lag. So one context is kept for frame after
|
|
85
|
+
frame (begin() points it at the next frame's canvas): paints are made once per distinct style and reused, fonts,
|
|
86
|
+
colours, font metrics and text runs (with their widths) are cached, and one path builder is reset rather than remade.
|
|
87
|
+
Cached paints are never changed after they're made.
|
|
88
|
+
*/
|
|
77
89
|
export class SkiaDrawCtx implements DrawCtx {
|
|
78
90
|
private st: Style = initialStyle();
|
|
79
91
|
private stack: Style[] = [];
|
|
80
92
|
private path: SkPathBuilder;
|
|
81
93
|
private hasPoint = false;
|
|
94
|
+
/** by CSS font string */
|
|
82
95
|
private fonts = new Map<string, FontPair>();
|
|
83
96
|
private colors = new Map<string, SkColor>();
|
|
97
|
+
private paints = new Map<string, SkPaint>();
|
|
98
|
+
/** by CSS font string, then text */
|
|
99
|
+
private textRuns = new Map<string, Map<string, Run[]>>();
|
|
100
|
+
/** the paints for the current style, until a style change (most draws in a row share one: no key to work out) */
|
|
101
|
+
private fillPaint: SkPaint | null = null;
|
|
102
|
+
private strokePaint: SkPaint | null = null;
|
|
103
|
+
/** the current path as Skia draws it, made once while it doesn't change (a fill and a stroke of it share it) */
|
|
104
|
+
private built: SkPath | null = null;
|
|
105
|
+
/** shapes by key, each made once at the origin (see shape), and the current path when it's one moved into place */
|
|
106
|
+
private shapes = new Map<string, SkPath>();
|
|
107
|
+
private placed: { path: SkPath; x: number; y: number; draw: (c: DrawCtx, x: number, y: number) => void } | null = null;
|
|
84
108
|
|
|
85
109
|
constructor(
|
|
86
110
|
private readonly Skia: SkiaApi,
|
|
87
|
-
private
|
|
111
|
+
private canvas: SkCanvas,
|
|
88
112
|
private readonly typefaces: SkiaFonts,
|
|
89
113
|
private readonly imageOf: SkiaImageSource = img => (img && typeof (img as SkImage).width === 'function' ? (img as SkImage) : null),
|
|
90
114
|
) {
|
|
91
115
|
this.path = Skia.PathBuilder.Make();
|
|
92
116
|
}
|
|
93
117
|
|
|
118
|
+
/** Draw the next frame on `canvas`, keeping the caches: the drawing state starts fresh, as on a new canvas. */
|
|
119
|
+
begin(canvas: SkCanvas): this {
|
|
120
|
+
this.canvas = canvas;
|
|
121
|
+
this.st = initialStyle();
|
|
122
|
+
this.stack = [];
|
|
123
|
+
this.path.reset();
|
|
124
|
+
this.hasPoint = false;
|
|
125
|
+
this.fillPaint = this.strokePaint = null;
|
|
126
|
+
this.built = null; this.placed = null;
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** The typefaces this context draws text with (a new set needs a new context). */
|
|
131
|
+
get typefaceSet(): SkiaFonts { return this.typefaces; }
|
|
132
|
+
|
|
94
133
|
// ---- style state (scoped by save/restore, as in the browser canvas) ----
|
|
95
134
|
get fillStyle(): unknown { return this.st.fillStyle; }
|
|
96
|
-
set fillStyle(v: unknown) { this.st.fillStyle =
|
|
135
|
+
set fillStyle(v: unknown) { const c = String(v); if (c !== this.st.fillStyle) { this.st.fillStyle = c; this.fillPaint = null; } }
|
|
97
136
|
get strokeStyle(): unknown { return this.st.strokeStyle; }
|
|
98
|
-
set strokeStyle(v: unknown) { this.st.strokeStyle =
|
|
137
|
+
set strokeStyle(v: unknown) { const c = String(v); if (c !== this.st.strokeStyle) { this.st.strokeStyle = c; this.strokePaint = null; } }
|
|
99
138
|
get lineWidth() { return this.st.lineWidth; }
|
|
100
|
-
set lineWidth(v: number) { if (v > 0 && Number.isFinite(v)) this.st.lineWidth = v; }
|
|
139
|
+
set lineWidth(v: number) { if (v > 0 && Number.isFinite(v) && v !== this.st.lineWidth) { this.st.lineWidth = v; this.strokePaint = null; } }
|
|
101
140
|
get lineCap() { return this.st.lineCap; }
|
|
102
|
-
set lineCap(v: DrawCtx['lineCap']) { this.st.lineCap = v; }
|
|
141
|
+
set lineCap(v: DrawCtx['lineCap']) { if (v !== this.st.lineCap) { this.st.lineCap = v; this.strokePaint = null; } }
|
|
103
142
|
get lineJoin() { return this.st.lineJoin; }
|
|
104
|
-
set lineJoin(v: DrawCtx['lineJoin']) { this.st.lineJoin = v; }
|
|
143
|
+
set lineJoin(v: DrawCtx['lineJoin']) { if (v !== this.st.lineJoin) { this.st.lineJoin = v; this.strokePaint = null; } }
|
|
105
144
|
get globalAlpha() { return this.st.globalAlpha; }
|
|
106
|
-
set globalAlpha(v: number) { if (v >= 0 && v <= 1) this.st.globalAlpha = v; }
|
|
145
|
+
set globalAlpha(v: number) { if (v >= 0 && v <= 1 && v !== this.st.globalAlpha) { this.st.globalAlpha = v; this.fillPaint = this.strokePaint = null; } }
|
|
107
146
|
get font() { return this.st.font; }
|
|
108
147
|
set font(v: string) { this.st.font = v; }
|
|
109
148
|
get textAlign() { return this.st.textAlign; }
|
|
@@ -123,26 +162,44 @@ export class SkiaDrawCtx implements DrawCtx {
|
|
|
123
162
|
const s = this.stack.pop();
|
|
124
163
|
if (!s) return;
|
|
125
164
|
this.st = s;
|
|
165
|
+
this.fillPaint = this.strokePaint = null;
|
|
126
166
|
this.canvas.restore();
|
|
127
167
|
}
|
|
128
168
|
translate(x: number, y: number): void { this.canvas.translate(x, y); }
|
|
129
169
|
rotate(angle: number): void { this.canvas.rotate(deg(angle), 0, 0); }
|
|
170
|
+
scale(x: number, y: number): void { this.canvas.scale(x, y); }
|
|
130
171
|
setLineDash(segments: number[]): void {
|
|
131
172
|
if (segments.some(v => !(v >= 0) || !Number.isFinite(v))) return;
|
|
132
173
|
// as the browser: an odd list repeats to make it even
|
|
133
174
|
this.st.dash = segments.length % 2 ? [...segments, ...segments] : segments.slice();
|
|
175
|
+
this.strokePaint = null;
|
|
134
176
|
}
|
|
135
177
|
|
|
136
178
|
// ---- paths ----
|
|
137
|
-
beginPath(): void { this.path
|
|
138
|
-
|
|
179
|
+
beginPath(): void { this.path.reset(); this.hasPoint = false; this.built = null; this.placed = null; }
|
|
180
|
+
/** About to add to the path: it changes (made again when drawn), and a shape moved into place becomes path commands. */
|
|
181
|
+
private changing(): void {
|
|
182
|
+
this.built = null;
|
|
183
|
+
const pl = this.placed;
|
|
184
|
+
if (pl) { this.placed = null; pl.draw(this, pl.x, pl.y); this.built = null; }
|
|
185
|
+
}
|
|
186
|
+
moveTo(x: number, y: number): void { this.changing(); this.path.moveTo(x, y); this.hasPoint = true; }
|
|
139
187
|
lineTo(x: number, y: number): void {
|
|
188
|
+
this.changing();
|
|
140
189
|
if (!this.hasPoint) this.path.moveTo(x, y); else this.path.lineTo(x, y);
|
|
141
190
|
this.hasPoint = true;
|
|
142
191
|
}
|
|
143
|
-
closePath(): void { this.path.close(); }
|
|
192
|
+
closePath(): void { this.changing(); this.path.close(); }
|
|
193
|
+
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void {
|
|
194
|
+
this.changing();
|
|
195
|
+
// (as the browser: with no current point, the first control point is where it starts)
|
|
196
|
+
if (!this.hasPoint) this.path.moveTo(cp1x, cp1y);
|
|
197
|
+
this.path.cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
|
198
|
+
this.hasPoint = true;
|
|
199
|
+
}
|
|
144
200
|
arc(x: number, y: number, r: number, startAngle: number, endAngle: number, counterclockwise = false): void {
|
|
145
201
|
if (!(r >= 0)) return;
|
|
202
|
+
this.changing();
|
|
146
203
|
const oval = this.Skia.XYWHRect(x - r, y - r, 2 * r, 2 * r);
|
|
147
204
|
const sweep = arcSweep(startAngle, endAngle, counterclockwise);
|
|
148
205
|
// the browser draws a line from the current point to the arc's start; Skia's arcToOval does the same
|
|
@@ -155,16 +212,19 @@ export class SkiaDrawCtx implements DrawCtx {
|
|
|
155
212
|
this.hasPoint = true;
|
|
156
213
|
}
|
|
157
214
|
arcTo(x1: number, y1: number, x2: number, y2: number, r: number): void {
|
|
215
|
+
this.changing();
|
|
158
216
|
if (!this.hasPoint) this.path.moveTo(x1, y1);
|
|
159
217
|
this.path.arcToTangent(x1, y1, x2, y2, r);
|
|
160
218
|
this.hasPoint = true;
|
|
161
219
|
}
|
|
162
220
|
rect(x: number, y: number, w: number, h: number): void {
|
|
221
|
+
this.changing();
|
|
163
222
|
this.path.addRect(this.Skia.XYWHRect(x, y, w, h));
|
|
164
223
|
this.path.moveTo(x, y);
|
|
165
224
|
this.hasPoint = true;
|
|
166
225
|
}
|
|
167
226
|
roundRect(x: number, y: number, w: number, h: number, r: number): void {
|
|
227
|
+
this.changing();
|
|
168
228
|
if (w < 0) { x += w; w = -w; }
|
|
169
229
|
if (h < 0) { y += h; h = -h; }
|
|
170
230
|
const rr = Math.max(0, Math.min(r, w / 2, h / 2));
|
|
@@ -172,9 +232,39 @@ export class SkiaDrawCtx implements DrawCtx {
|
|
|
172
232
|
this.path.moveTo(x, y);
|
|
173
233
|
this.hasPoint = true;
|
|
174
234
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
235
|
+
/**
|
|
236
|
+
* The path is a shape kept by key, made the first time (on a builder of its own, at the origin): its top left at x, y.
|
|
237
|
+
* Chips and badges — hundreds a frame — each took a few dozen calls into native code to describe; now a few to place.
|
|
238
|
+
*/
|
|
239
|
+
shape(key: string, x: number, y: number, draw: (c: DrawCtx, x: number, y: number) => void): void {
|
|
240
|
+
let p = this.shapes.get(key);
|
|
241
|
+
if (!p) {
|
|
242
|
+
const outer = this.path, had = this.hasPoint;
|
|
243
|
+
this.path = this.Skia.PathBuilder.Make();
|
|
244
|
+
this.hasPoint = false; this.placed = null; this.built = null;
|
|
245
|
+
draw(this, 0, 0);
|
|
246
|
+
p = this.path.build();
|
|
247
|
+
this.path = outer; this.hasPoint = had;
|
|
248
|
+
remember(this.shapes, key, p);
|
|
249
|
+
}
|
|
250
|
+
this.path.reset();
|
|
251
|
+
this.hasPoint = false; this.built = null;
|
|
252
|
+
this.placed = { path: p, x, y, draw };
|
|
253
|
+
}
|
|
254
|
+
fill(): void { this.drawCurrent(this.paint(false)); }
|
|
255
|
+
stroke(): void { this.drawCurrent(this.paint(true)); }
|
|
256
|
+
clip(): void {
|
|
257
|
+
if (this.placed) this.changing();
|
|
258
|
+
this.canvas.clipPath(this.built ??= this.path.build(), INTERSECT, true);
|
|
259
|
+
}
|
|
260
|
+
private drawCurrent(paint: SkPaint): void {
|
|
261
|
+
const pl = this.placed;
|
|
262
|
+
if (!pl) { this.canvas.drawPath(this.built ??= this.path.build(), paint); return; }
|
|
263
|
+
this.canvas.save();
|
|
264
|
+
this.canvas.translate(pl.x, pl.y);
|
|
265
|
+
this.canvas.drawPath(pl.path, paint);
|
|
266
|
+
this.canvas.restore();
|
|
267
|
+
}
|
|
178
268
|
|
|
179
269
|
// ---- shapes, text, images ----
|
|
180
270
|
fillRect(x: number, y: number, w: number, h: number): void { this.canvas.drawRect(this.Skia.XYWHRect(x, y, w, h), this.paint(false)); }
|
|
@@ -182,32 +272,37 @@ export class SkiaDrawCtx implements DrawCtx {
|
|
|
182
272
|
|
|
183
273
|
measureText(text: string): { width: number } {
|
|
184
274
|
const f = this.fontPair();
|
|
185
|
-
return { width: this.runs(text, f).reduce((w, r) => w + r.
|
|
275
|
+
return { width: this.runs(text, f).reduce((w, r) => w + r.width, 0) };
|
|
186
276
|
}
|
|
187
277
|
|
|
188
278
|
fillText(text: string, x: number, y: number): void {
|
|
189
279
|
if (!text) return;
|
|
190
280
|
const f = this.fontPair(), runs = this.runs(text, f), paint = this.paint(false);
|
|
191
|
-
const width = runs.reduce((w, r) => w + r.
|
|
281
|
+
const width = runs.reduce((w, r) => w + r.width, 0);
|
|
192
282
|
const a = this.st.textAlign;
|
|
193
283
|
let tx = a === 'center' ? x - width / 2 : a === 'right' || a === 'end' ? x - width : x;
|
|
194
|
-
const m = f.
|
|
195
|
-
const ty = b === 'middle' ? y + middleShift(m.ascent, m.descent,
|
|
284
|
+
const m = f.metrics, b = this.st.textBaseline;
|
|
285
|
+
const ty = b === 'middle' ? y + middleShift(m.ascent, m.descent, m.size)
|
|
196
286
|
: b === 'top' || b === 'hanging' ? y - m.ascent
|
|
197
287
|
: b === 'bottom' || b === 'ideographic' ? y - m.descent
|
|
198
288
|
: y;
|
|
199
289
|
for (const r of runs) {
|
|
200
290
|
this.canvas.drawText(r.text, tx, ty, paint, r.font);
|
|
201
|
-
tx += r.
|
|
291
|
+
tx += r.width;
|
|
202
292
|
}
|
|
203
293
|
}
|
|
204
294
|
|
|
205
295
|
drawImage(image: unknown, x: number, y: number, w: number, h: number): void {
|
|
206
296
|
const img = this.imageOf(image);
|
|
207
297
|
if (!img) return;
|
|
208
|
-
const
|
|
209
|
-
p.
|
|
210
|
-
p
|
|
298
|
+
const key = 'image|' + this.st.globalAlpha;
|
|
299
|
+
let p = this.paints.get(key);
|
|
300
|
+
if (!p) {
|
|
301
|
+
p = this.Skia.Paint();
|
|
302
|
+
p.setAntiAlias(true);
|
|
303
|
+
p.setAlphaf(this.st.globalAlpha);
|
|
304
|
+
remember(this.paints, key, p);
|
|
305
|
+
}
|
|
211
306
|
this.canvas.drawImageRect(img, this.Skia.XYWHRect(0, 0, img.width(), img.height()), this.Skia.XYWHRect(x, y, w, h), p);
|
|
212
307
|
}
|
|
213
308
|
|
|
@@ -219,10 +314,26 @@ export class SkiaDrawCtx implements DrawCtx {
|
|
|
219
314
|
return c;
|
|
220
315
|
}
|
|
221
316
|
|
|
317
|
+
/** The paint for the current style: made the first time a style is used, the same object every time after. */
|
|
222
318
|
private paint(stroke: boolean): SkPaint {
|
|
223
|
-
const
|
|
319
|
+
const same = stroke ? this.strokePaint : this.fillPaint;
|
|
320
|
+
if (same) return same;
|
|
321
|
+
const p = this.paintFor(stroke);
|
|
322
|
+
if (stroke) this.strokePaint = p; else this.fillPaint = p;
|
|
323
|
+
return p;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private paintFor(stroke: boolean): SkPaint {
|
|
327
|
+
const s = this.st, css = stroke ? s.strokeStyle : s.fillStyle;
|
|
328
|
+
const dashed = stroke && s.dash.length > 0 && s.dash.some(v => v > 0);
|
|
329
|
+
const key = stroke
|
|
330
|
+
? 's|' + css + '|' + s.globalAlpha + '|' + s.lineWidth + '|' + s.lineCap + '|' + s.lineJoin + (dashed ? '|' + s.dash.join(',') : '')
|
|
331
|
+
: 'f|' + css + '|' + s.globalAlpha;
|
|
332
|
+
const hit = this.paints.get(key);
|
|
333
|
+
if (hit) return hit;
|
|
334
|
+
const p = this.Skia.Paint();
|
|
224
335
|
p.setAntiAlias(true);
|
|
225
|
-
const c = this.color(
|
|
336
|
+
const c = this.color(css);
|
|
226
337
|
p.setColor(c);
|
|
227
338
|
p.setAlphaf(c[3] * s.globalAlpha);
|
|
228
339
|
if (stroke) {
|
|
@@ -230,36 +341,47 @@ export class SkiaDrawCtx implements DrawCtx {
|
|
|
230
341
|
p.setStrokeWidth(s.lineWidth);
|
|
231
342
|
p.setStrokeCap(CAP[s.lineCap]);
|
|
232
343
|
p.setStrokeJoin(JOIN[s.lineJoin]);
|
|
233
|
-
if (
|
|
344
|
+
if (dashed) p.setPathEffect(this.Skia.PathEffect.MakeDash(s.dash, 0));
|
|
234
345
|
}
|
|
235
|
-
return p;
|
|
346
|
+
return remember(this.paints, key, p);
|
|
236
347
|
}
|
|
237
348
|
|
|
238
349
|
private fontPair(): FontPair {
|
|
239
|
-
const
|
|
350
|
+
const key = this.st.font;
|
|
240
351
|
let f = this.fonts.get(key);
|
|
241
352
|
if (!f) {
|
|
353
|
+
const { weight, size } = parseFont(key);
|
|
242
354
|
const ws = Object.keys(this.typefaces.weights).map(Number);
|
|
243
355
|
const near = ws.sort((a, b) => Math.abs(a - weight) - Math.abs(b - weight))[0];
|
|
356
|
+
const main = this.Skia.Font(this.typefaces.weights[near]!, size), m = main.getMetrics();
|
|
244
357
|
f = {
|
|
245
|
-
main
|
|
358
|
+
main,
|
|
246
359
|
fb: this.typefaces.fallback ? this.Skia.Font(this.typefaces.fallback, size) : null,
|
|
360
|
+
metrics: { ascent: m.ascent, descent: m.descent, size: main.getSize() },
|
|
247
361
|
};
|
|
248
|
-
this.fonts
|
|
362
|
+
remember(this.fonts, key, f);
|
|
249
363
|
}
|
|
250
364
|
return f;
|
|
251
365
|
}
|
|
252
366
|
|
|
253
|
-
/** Split text into runs the main font can draw and runs that need the fallback. */
|
|
254
|
-
private runs(text: string, f: FontPair):
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (!
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
});
|
|
263
|
-
|
|
367
|
+
/** Split text into runs the main font can draw and runs that need the fallback, with their widths (cached). */
|
|
368
|
+
private runs(text: string, f: FontPair): Run[] {
|
|
369
|
+
const css = this.st.font;
|
|
370
|
+
let byText = this.textRuns.get(css);
|
|
371
|
+
if (!byText) this.textRuns.set(css, (byText = new Map()));
|
|
372
|
+
const hit = byText.get(text);
|
|
373
|
+
if (hit) return hit;
|
|
374
|
+
const out: Run[] = [];
|
|
375
|
+
const ids = f.fb ? f.main.getGlyphIDs(text, Array.from(text).length) : null;
|
|
376
|
+
if (!ids || !ids.includes(0)) out.push({ text, font: f.main, width: 0 });
|
|
377
|
+
else {
|
|
378
|
+
Array.from(text).forEach((ch, i) => {
|
|
379
|
+
const font = ids[i] === 0 ? f.fb! : f.main, last = out[out.length - 1];
|
|
380
|
+
if (last && last.font === font) last.text += ch; else out.push({ text: ch, font, width: 0 });
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
for (const r of out) r.width = r.font.getTextWidth(r.text);
|
|
384
|
+
// (kept: measuring and drawing a label again — every frame — asks native code nothing)
|
|
385
|
+
return remember(byText, text, out);
|
|
264
386
|
}
|
|
265
387
|
}
|
package/src/skia/host.ts
CHANGED
|
@@ -44,7 +44,20 @@ export const skiaImageLoader: ImageLoader = (src, onLoad) => {
|
|
|
44
44
|
const imageOf = (img: unknown): SkImage | null => (img as SkiaImage | null)?.sk ?? null;
|
|
45
45
|
|
|
46
46
|
/** A drawing context on a Skia canvas, with the current typefaces and Skia-loaded pictures. */
|
|
47
|
-
|
|
47
|
+
/** One context for frame after frame (its paints, fonts and text caches are reused); a new one if the typefaces change. */
|
|
48
|
+
let shared: SkiaDrawCtx | null = null;
|
|
49
|
+
export function skiaCtx(canvas: SkCanvas): SkiaDrawCtx {
|
|
50
|
+
const fonts = currentFonts();
|
|
51
|
+
if (!shared || shared.typefaceSet !== fonts) shared = new SkiaDrawCtx(Skia, canvas, fonts, imageOf);
|
|
52
|
+
return shared.begin(canvas);
|
|
53
|
+
}
|
|
54
|
+
/** A second one, for drawing on two canvases at once (recordLayers). */
|
|
55
|
+
let second: SkiaDrawCtx | null = null;
|
|
56
|
+
function skiaCtx2(canvas: SkCanvas): SkiaDrawCtx {
|
|
57
|
+
const fonts = currentFonts();
|
|
58
|
+
if (!second || second.typefaceSet !== fonts) second = new SkiaDrawCtx(Skia, canvas, fonts, imageOf);
|
|
59
|
+
return second.begin(canvas);
|
|
60
|
+
}
|
|
48
61
|
|
|
49
62
|
/** Record w × h of drawing as a picture; also returns what `draw` returned (e.g. the tappable chips). */
|
|
50
63
|
export function recordPicture<T>(w: number, h: number, draw: (ctx: SkiaDrawCtx) => T): { picture: SkPicture; result: T } {
|
|
@@ -54,6 +67,19 @@ export function recordPicture<T>(w: number, h: number, draw: (ctx: SkiaDrawCtx)
|
|
|
54
67
|
return { picture: rec.finishRecordingAsPicture(), result };
|
|
55
68
|
}
|
|
56
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Record a frame as two pictures at once: `moving`, which a host moves and scales with the view (drawn `margin` px
|
|
72
|
+
* past each edge of the w × h screen, so moved a little it shows no edge), and `fixed`, what stays put on the screen.
|
|
73
|
+
* Also returns what `draw` returned.
|
|
74
|
+
*/
|
|
75
|
+
export function recordLayers<T>(w: number, h: number, margin: number, draw: (moving: SkiaDrawCtx, fixed: SkiaDrawCtx) => T): { moving: SkPicture; fixed: SkPicture; result: T } {
|
|
76
|
+
const recM = Skia.PictureRecorder(), recF = Skia.PictureRecorder();
|
|
77
|
+
const m = recM.beginRecording(Skia.XYWHRect(-margin, -margin, w + 2 * margin, h + 2 * margin));
|
|
78
|
+
const f = recF.beginRecording(Skia.XYWHRect(0, 0, w, h));
|
|
79
|
+
const result = draw(skiaCtx(m), skiaCtx2(f));
|
|
80
|
+
return { moving: recM.finishRecordingAsPicture(), fixed: recF.finishRecordingAsPicture(), result };
|
|
81
|
+
}
|
|
82
|
+
|
|
57
83
|
/** Draw w × h into an image and encode it as a PNG data URL (null if no surface could be made). */
|
|
58
84
|
export function renderPng(w: number, h: number, draw: (ctx: SkiaDrawCtx) => void): string | null {
|
|
59
85
|
const surface = Skia.Surface.Make(w, h);
|
|
@@ -62,3 +88,22 @@ export function renderPng(w: number, h: number, draw: (ctx: SkiaDrawCtx) => void
|
|
|
62
88
|
surface.flush();
|
|
63
89
|
return 'data:image/png;base64,' + surface.makeImageSnapshot().encodeToBase64();
|
|
64
90
|
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Measuring text without drawing (picking a note, its handles): a context of its own with the current typefaces, so
|
|
94
|
+
* widths match the drawing's exactly. Its canvas is never drawn on.
|
|
95
|
+
*/
|
|
96
|
+
let measurer: SkiaDrawCtx | null = null;
|
|
97
|
+
function measureCtx(): SkiaDrawCtx {
|
|
98
|
+
const fonts = currentFonts();
|
|
99
|
+
if (!measurer || measurer.typefaceSet !== fonts) {
|
|
100
|
+
const canvas = Skia.PictureRecorder().beginRecording(Skia.XYWHRect(0, 0, 1, 1));
|
|
101
|
+
measurer = new SkiaDrawCtx(Skia, canvas, fonts, imageOf);
|
|
102
|
+
}
|
|
103
|
+
return measurer;
|
|
104
|
+
}
|
|
105
|
+
export const skiaTextMeasure = {
|
|
106
|
+
get font(): string { return measureCtx().font; },
|
|
107
|
+
set font(v: string) { measureCtx().font = v; },
|
|
108
|
+
measureText: (s: string): { width: number } => measureCtx().measureText(s),
|
|
109
|
+
};
|
package/src/solver/equations.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hyp } from '../model/geom';
|
|
2
2
|
import { curveInfo } from '../model/sketch';
|
|
3
|
+
import { faceEnds, faceSpan } from '../model/wallfaces';
|
|
3
4
|
import type { Constraint, Sketch } from '../model/types';
|
|
4
5
|
|
|
5
6
|
export type Vec = Float64Array;
|
|
@@ -51,6 +52,20 @@ export function consEqs(sk: Sketch, c: Constraint, P: PFn, D: DFn, RV: RVFn, RD:
|
|
|
51
52
|
// on the side the centre started on (sign), so it never flips across the line
|
|
52
53
|
const l = L(c.l), r = rad(c.c);
|
|
53
54
|
if (!l || !r) break;
|
|
55
|
+
// an arc that ends on one of the line's ends (a fillet, a smooth join): tangent there is its radius to that end
|
|
56
|
+
// standing square to the line. (The distance form has no slope at that point, so the solver couldn't tell a
|
|
57
|
+
// second such tangent from one that's already true.)
|
|
58
|
+
const ci = curveInfo(sk, c.c);
|
|
59
|
+
const joint = ci && ci.kind === 'arc' ? [ci.o.a, ci.o.b].find(p => p === l.a || p === l.b) : undefined;
|
|
60
|
+
if (ci && joint) {
|
|
61
|
+
const o = ci.o.c;
|
|
62
|
+
out.push([[...D(l.a), ...D(l.b), ...D(o), ...D(joint)], X => {
|
|
63
|
+
const a = P(X, l.a), b = P(X, l.b), m = P(X, o), e = P(X, joint);
|
|
64
|
+
const ux = b[0] - a[0], uy = b[1] - a[1], vx = e[0] - m[0], vy = e[1] - m[1];
|
|
65
|
+
return (ux * vx + uy * vy) / ((hyp(ux, uy) || 1e-12) * (hyp(vx, vy) || 1e-12));
|
|
66
|
+
}]);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
54
69
|
const s = c.sign || 1;
|
|
55
70
|
out.push([[...D(l.a), ...D(l.b), ...D(r.c), ...r.deps], X => {
|
|
56
71
|
const o = P(X, r.c), a = P(X, l.a), b = P(X, l.b), n = hyp(b[0] - a[0], b[1] - a[1]) || 1e-12;
|
|
@@ -109,6 +124,19 @@ export function consEqs(sk: Sketch, c: Constraint, P: PFn, D: DFn, RV: RVFn, RD:
|
|
|
109
124
|
break;
|
|
110
125
|
}
|
|
111
126
|
case 'dist': {
|
|
127
|
+
const fw = c.face && c.line && (!c.kind || c.kind === 'al') ? L(c.line) : undefined;
|
|
128
|
+
if (fw && fw.kind === 'wall') {
|
|
129
|
+
// along one face of a wall, corner to corner: the walls at its ends cut it short (an inside corner) or carry it
|
|
130
|
+
// on (an outside one), so they're part of it too
|
|
131
|
+
const ends = faceEnds(sk, c.line!), side = c.face!;
|
|
132
|
+
const deps = [...D(fw.a), ...D(fw.b), ...[...ends.a, ...ends.b].flatMap(e => D(e.far ?? e.arc!.c))];
|
|
133
|
+
out.push([deps, X => {
|
|
134
|
+
const at = (id: string) => { const q = P(X, id); return { x: q[0], y: q[1] }; };
|
|
135
|
+
const f = faceSpan(at, at(fw.a), at(fw.b), fw.thick, side, ends);
|
|
136
|
+
return (f ? f.s1 - f.s0 : 0) - c.value!;
|
|
137
|
+
}]);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
112
140
|
const deps = [...D(c.a!), ...D(c.b!)], s = c.sign || 1;
|
|
113
141
|
if (c.kind === 'h') out.push([deps, X => (P(X, c.b!)[0] - P(X, c.a!)[0]) * s - c.value!]);
|
|
114
142
|
else if (c.kind === 'v') out.push([deps, X => (P(X, c.b!)[1] - P(X, c.a!)[1]) * s - c.value!]);
|
|
@@ -119,16 +147,23 @@ export function consEqs(sk: Sketch, c: Constraint, P: PFn, D: DFn, RV: RVFn, RD:
|
|
|
119
147
|
const l = L(c.l);
|
|
120
148
|
if (!l) break;
|
|
121
149
|
const s = c.sign || 1;
|
|
150
|
+
// between walls' faces: the centreline distance, less half of each wall's thickness for a face toward the other
|
|
151
|
+
// (more, for a far face) — read when solved, so a wall made thicker keeps the faces where they were measured
|
|
152
|
+
const k = c.faces, w2 = L(c.l2);
|
|
153
|
+
const faceOff = () => (k ? (k[0] * (l.kind === 'wall' ? l.thick : 0) + k[1] * (w2 && w2.kind === 'wall' ? w2.thick : 0)) / 2 : 0);
|
|
122
154
|
out.push([[...D(c.p!), ...D(l.a), ...D(l.b)], X => {
|
|
123
155
|
const p = P(X, c.p!), a = P(X, l.a), b = P(X, l.b), dx = b[0] - a[0], dy = b[1] - a[1], n = hyp(dx, dy) || 1e-12;
|
|
124
|
-
return (s * ((b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]))) / n - c.value!;
|
|
156
|
+
return (s * ((b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]))) / n - faceOff() - c.value!;
|
|
125
157
|
}]);
|
|
126
158
|
break;
|
|
127
159
|
}
|
|
128
160
|
case 'diam': {
|
|
129
161
|
const r = rad(c.c);
|
|
130
162
|
if (!r) break;
|
|
131
|
-
|
|
163
|
+
// across a curved wall's face: the centreline's, plus its thickness for the outer face (less, the inner)
|
|
164
|
+
const w = sk.circles[c.c!] ?? sk.arcs[c.c!];
|
|
165
|
+
const faceOff = () => (c.face && w && w.kind === 'wall' ? c.face * (w.thick || 4.5) : 0);
|
|
166
|
+
out.push([r.deps, X => 2 * r.f(X) + faceOff() - c.value!]);
|
|
132
167
|
break;
|
|
133
168
|
}
|
|
134
169
|
case 'angle': {
|