gps-plus-slam-app-framework 1.3.0 → 1.7.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/dist/absolute-orientation-CAEh840t.d.ts +54 -0
- package/dist/{app-selectors-B8VQoMDY.d.ts → app-selectors-ikTUQZpe.d.ts} +1 -1
- package/dist/ar/bresenham3d.d.ts +1 -1
- package/dist/ar/camera-blit-capture.d.ts +2 -2
- package/dist/ar/camera-blit-capture.js +74 -9
- package/dist/ar/capability-checker.d.ts +1 -1
- package/dist/ar/capture-failure-tracker.d.ts +1 -1
- package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
- package/dist/ar/depth-grid-lookup.d.ts +2 -0
- package/dist/ar/depth-grid-lookup.js +43 -0
- package/dist/ar/depth-sampler.d.ts +2 -2
- package/dist/ar/depth-sampler.js +2 -4
- package/dist/ar/depth-unprojection.d.ts +1 -1
- package/dist/ar/enable-gps-ar.d.ts +1 -1
- package/dist/ar/enable-gps-ar.js +26 -1
- package/dist/ar/frame-loop.d.ts +1 -1
- package/dist/ar/image-capture.d.ts +2 -2
- package/dist/ar/image-capture.js +1 -154
- package/dist/ar/image-quality.d.ts +2 -0
- package/dist/ar/image-quality.js +168 -0
- package/dist/ar/index.d.ts +31 -19
- package/dist/ar/index.js +17 -5
- package/dist/ar/occupancy-grid.d.ts +1 -1
- package/dist/ar/occupancy-grid.js +29 -2
- package/dist/ar/planar-pnp.d.ts +2 -0
- package/dist/ar/planar-pnp.js +425 -0
- package/dist/ar/qr-debug-view.d.ts +2 -0
- package/dist/ar/qr-debug-view.js +89 -0
- package/dist/ar/qr-derived-pose.d.ts +2 -0
- package/dist/ar/qr-derived-pose.js +114 -0
- package/dist/ar/qr-detection-controller.d.ts +2 -0
- package/dist/ar/qr-detection-controller.js +2 -0
- package/dist/ar/qr-frontend.d.ts +2 -0
- package/dist/ar/qr-frontend.js +60 -0
- package/dist/ar/qr-pose.d.ts +2 -0
- package/dist/ar/qr-pose.js +267 -0
- package/dist/ar/qr-size-depth-context.d.ts +3 -0
- package/dist/ar/qr-size-depth-context.js +42 -0
- package/dist/ar/qr-size-measurer.d.ts +2 -0
- package/dist/ar/qr-size-measurer.js +2 -0
- package/dist/ar/replay-scene.d.ts +1 -1
- package/dist/ar/replay-scene.js +1 -1
- package/dist/ar/scene-node-names.d.ts +1 -1
- package/dist/ar/webxr-nue-basis.d.ts +1 -1
- package/dist/ar/webxr-session.d.ts +4 -4
- package/dist/ar/webxr-session.js +2 -2
- package/dist/ar/xr-camera-texture.d.ts +1 -1
- package/dist/ar/xr-error-handler.d.ts +1 -1
- package/dist/ar/xr-frame-loop.d.ts +1 -1
- package/dist/ar-MFpFlV7j.js +382 -0
- package/dist/{ar-world-group-alignment-C9lwwIyI.d.ts → ar-world-group-alignment-69fgnB39.d.ts} +1 -1
- package/dist/{camera-blit-capture-CnxUDbKx.d.ts → camera-blit-capture-NKT9H5-e.d.ts} +57 -4
- package/dist/capture-motion-gate-0Yl2NpQG.d.ts +24 -0
- package/dist/capture-motion-gate-4EscNZCw.js +94 -0
- package/dist/concurrency-By0oOTZt.d.ts +50 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +2 -2
- package/dist/create-slam-app-store-DkCHOpvb.js +149 -0
- package/dist/{create-slam-app-store-BljusOua.d.ts → create-slam-app-store-n_VF63D5.d.ts} +50 -40
- package/dist/depth-grid-lookup-DQ-IYhO3.d.ts +21 -0
- package/dist/{depth-sampler-Bhanfwla.d.ts → depth-sampler-asc8exHt.d.ts} +1 -1
- package/dist/{depth-unprojection-Y6i_mJuT.d.ts → depth-unprojection-DjsbJW9L.d.ts} +1 -1
- package/dist/{enable-gps-ar-BfUJOgpW.d.ts → enable-gps-ar-DkNhFv4Y.d.ts} +4 -4
- package/dist/{frame-conversions-BfsafGWR.d.ts → frame-conversions-DObhj8Wf.d.ts} +1 -1
- package/dist/{fused-path-DJoVu98b.d.ts → fused-path-v6eOmLl3.d.ts} +1 -1
- package/dist/geo/h3-proximity.d.ts +2 -2
- package/dist/geo/h3-proximity.js +61 -2
- package/dist/geo/index.d.ts +2 -2
- package/dist/geo/index.js +2 -2
- package/dist/geodesic-angle-BTldfFgs.js +39 -0
- package/dist/{gps-anchor-dYeCvvp5.d.ts → gps-anchor-BeFO2RYa.d.ts} +1 -1
- package/dist/{gps-ar-pose-sampler-DVb96iOy.d.ts → gps-ar-pose-sampler-DHMZmYAc.d.ts} +1 -1
- package/dist/{gps-event-coordinator-CWIDOk4U.d.ts → gps-event-coordinator-CjWW636x.d.ts} +21 -11
- package/dist/{gps-event-markers-Dc9FT-q1.d.ts → gps-event-markers-Cz9RMA2k.d.ts} +18 -0
- package/dist/{h3-proximity-I1msGPgE.d.ts → h3-proximity-C-j0pw1j.d.ts} +39 -1
- package/dist/image-capture-B2-b6tKK.js +374 -0
- package/dist/{image-capture-qAZ5Fh5X.d.ts → image-capture-CNZDrQXG.d.ts} +103 -3
- package/dist/image-quality-smCBoFj1.d.ts +158 -0
- package/dist/index-BAPokxMb.d.ts +22 -0
- package/dist/{index-BYYUdf9v.d.ts → index-BODDUTvD.d.ts} +1 -1
- package/dist/index-BneSj4_5.d.ts +399 -0
- package/dist/index-_Rhgoqkh.d.ts +2 -0
- package/dist/index.d.ts +80 -67
- package/dist/index.js +24 -12
- package/dist/{leaflet-map-overlay-6CJC-E1l.d.ts → leaflet-map-overlay-CmIyiE8n.d.ts} +1 -1
- package/dist/{map-data-CkloBxIl.d.ts → map-data-B4oEehUh.d.ts} +1 -1
- package/dist/{map-overlay-draw-krOKwDAq.d.ts → map-overlay-draw-ymz1s7fG.d.ts} +1 -1
- package/dist/{null-storage-backend-uKQE8tl7.d.ts → null-storage-backend-B9rtyDfG.d.ts} +2 -2
- package/dist/{occupancy-grid-BRNRaPyT.d.ts → occupancy-grid-DnOc-6PU.d.ts} +12 -2
- package/dist/{opfs-storage-D5zAn_lx.d.ts → opfs-storage-3VZh-qH6.d.ts} +23 -4
- package/dist/{opfs-storage-backend-6aYMUZlJ.d.ts → opfs-storage-backend-JJiUJo-3.d.ts} +3 -3
- package/dist/{persistence-middleware-B9ei4Nhx.d.ts → persistence-middleware-DAPTTwB2.d.ts} +1 -1
- package/dist/planar-pnp-my9bqULS.d.ts +67 -0
- package/dist/qr-debug-view-Brl73HGO.d.ts +29 -0
- package/dist/qr-derived-pose-CmxTP2m4.d.ts +122 -0
- package/dist/qr-detected-slice-VQssZmQJ.d.ts +166 -0
- package/dist/qr-detection-controller-B-tLVd-S.js +119 -0
- package/dist/qr-detection-controller-CDurHv8E.d.ts +48 -0
- package/dist/qr-frontend--fFX25mV.d.ts +58 -0
- package/dist/qr-pose-D2rfu5DA.d.ts +138 -0
- package/dist/qr-pose-aggregation-B7tWJq7j.d.ts +90 -0
- package/dist/qr-pose-aggregation-DBiaLW0O.js +191 -0
- package/dist/qr-size-depth-context-CeAG53fy.d.ts +13 -0
- package/dist/qr-size-measurer-DLb33geH.js +596 -0
- package/dist/qr-size-measurer-DQdAsid1.d.ts +165 -0
- package/dist/recording-options-BPCpMHLK.d.ts +514 -0
- package/dist/{recording-replayer-r0DZ9ALp.d.ts → recording-replayer-DQKpAGyQ.d.ts} +2 -2
- package/dist/recording-slice-DaxHZvNu.d.ts +55 -0
- package/dist/{replay-engine-XpDa0dy1.d.ts → replay-engine-CmKh_4wf.d.ts} +7 -4
- package/dist/{replay-scene-Bw58VL6p.d.ts → replay-scene-DBlDrV_x.d.ts} +3 -3
- package/dist/sensors/absolute-orientation.d.ts +2 -0
- package/dist/sensors/absolute-orientation.js +145 -0
- package/dist/sensors/gps-error-handler.d.ts +1 -1
- package/dist/sensors/gps.d.ts +1 -1
- package/dist/sensors/index.d.ts +5 -4
- package/dist/sensors/index.js +2 -1
- package/dist/sensors/permission-checker.d.ts +1 -1
- package/dist/sensors/permission-checker.js +1 -1
- package/dist/state/app-selectors.d.ts +1 -1
- package/dist/state/combined-root-state.d.ts +1 -1
- package/dist/state/create-slam-app-store.d.ts +1 -1
- package/dist/state/create-slam-app-store.js +1 -74
- package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
- package/dist/state/gps-event-coordinator.d.ts +2 -2
- package/dist/state/gps-event-coordinator.js +27 -17
- package/dist/state/index.d.ts +20 -17
- package/dist/state/index.js +5 -4
- package/dist/state/persistence-middleware.d.ts +1 -1
- package/dist/state/persistence-middleware.js +30 -19
- package/dist/state/qr-detected-slice.d.ts +4 -0
- package/dist/state/qr-detected-slice.js +311 -0
- package/dist/state/recording-options.d.ts +2 -2
- package/dist/state/recording-options.js +273 -7
- package/dist/state/recording-replayer.d.ts +2 -2
- package/dist/state/recording-replayer.js +1 -1
- package/dist/state/recording-slice.d.ts +1 -1
- package/dist/state/recording-slice.js +5 -1
- package/dist/state/replay-engine.d.ts +1 -1
- package/dist/state/replay-engine.js +7 -3
- package/dist/state/store-subscribers.d.ts +2 -2
- package/dist/state/subscribe-to-selector.d.ts +1 -1
- package/dist/state/tracking-quality.d.ts +2 -2
- package/dist/state/tracking-quality.js +40 -128
- package/dist/state/tracking-slice.d.ts +1 -1
- package/dist/{state-BkIfpiyA.js → state-E51QT_-j.js} +2 -1
- package/dist/storage/file-system-utils.d.ts +1 -1
- package/dist/storage/index.d.ts +9 -9
- package/dist/storage/index.js +4 -4
- package/dist/storage/null-storage-backend.d.ts +1 -1
- package/dist/storage/opfs-storage-backend.d.ts +1 -1
- package/dist/storage/opfs-storage-backend.js +3 -3
- package/dist/storage/opfs-storage.d.ts +1 -1
- package/dist/storage/opfs-storage.js +5 -4
- package/dist/storage/storage-backend.d.ts +1 -1
- package/dist/storage/zip-coverage-embed.d.ts +2 -0
- package/dist/storage/zip-coverage-embed.js +88 -0
- package/dist/storage/zip-export.d.ts +2 -2
- package/dist/storage/zip-export.js +37 -59
- package/dist/storage/zip-reader.d.ts +1 -1
- package/dist/{storage-backend-Do6YDpNo.d.ts → storage-backend-BdVLD0dU.d.ts} +1 -1
- package/dist/{store-subscribers-0YWyOLvV.d.ts → store-subscribers-CA6AJH_8.d.ts} +2 -2
- package/dist/{subscribe-to-selector-CZ6k1NFP.d.ts → subscribe-to-selector-B6EUmQ3I.d.ts} +1 -1
- package/dist/test-utils/browser-mocks.d.ts +7 -1
- package/dist/test-utils/browser-mocks.js +6 -0
- package/dist/test-utils/zip-round-trip-helpers.d.ts +9 -1
- package/dist/test-utils/zip-round-trip-helpers.js +5 -1
- package/dist/{tracking-slice-CdK8c-8P.d.ts → tracking-slice-BuAZxXZ5.d.ts} +1 -1
- package/dist/types/ar-types.d.ts +1 -1
- package/dist/types/geo-types.d.ts +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/utils/concurrency.d.ts +2 -2
- package/dist/utils/concurrency.js +66 -2
- package/dist/utils/failure-tracker.d.ts +1 -1
- package/dist/utils/format-file-size.d.ts +1 -1
- package/dist/utils/fused-path.d.ts +1 -1
- package/dist/utils/index.d.ts +8 -7
- package/dist/utils/index.js +2 -1
- package/dist/utils/list-formatter.d.ts +1 -1
- package/dist/utils/logger.d.ts +1 -1
- package/dist/visualization/accuracy-circles.d.ts +1 -1
- package/dist/visualization/alignment-lerper.d.ts +1 -1
- package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
- package/dist/visualization/ar-world-group-alignment.js +1 -1
- package/dist/visualization/camera-follower.d.ts +1 -1
- package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
- package/dist/visualization/frame-conversions.d.ts +1 -1
- package/dist/visualization/frustum-visibility.d.ts +1 -1
- package/dist/visualization/gps-anchor.d.ts +1 -1
- package/dist/visualization/gps-compass-cubes.d.ts +1 -1
- package/dist/visualization/gps-event-markers.d.ts +1 -1
- package/dist/visualization/gps-event-markers.js +40 -5
- package/dist/visualization/hit-test-reticle.d.ts +1 -1
- package/dist/visualization/hit-test-reticle.js +1 -0
- package/dist/visualization/index.d.ts +18 -18
- package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
- package/dist/visualization/leaflet-map-overlay.js +15 -3
- package/dist/visualization/lerp-utils.d.ts +1 -1
- package/dist/visualization/map-data.d.ts +1 -1
- package/dist/visualization/map-overlay-draw.d.ts +1 -1
- package/dist/visualization/map-overlay.d.ts +1 -1
- package/dist/visualization/three-dispose.d.ts +1 -1
- package/dist/visualization/vis-colors.d.ts +1 -1
- package/dist/{webxr-session-TIaD883f.js → webxr-session-DG-eNfny.js} +244 -11
- package/dist/{webxr-session-GjZ2BIpS.d.ts → webxr-session-Do5L6G3B.d.ts} +86 -8
- package/dist/zip-coverage-embed-DCAREVmw.d.ts +41 -0
- package/dist/{zip-export-G14hkSPG.d.ts → zip-export-ol0S_Ofd.d.ts} +27 -23
- package/package.json +2 -2
- package/dist/concurrency-CO1FQvs3.d.ts +0 -24
- package/dist/file-system-CwXTNHmB.d.ts +0 -114
- package/dist/index-CF05QV2m.d.ts +0 -2
- package/dist/recording-options-DJBXuMxV.d.ts +0 -182
- package/dist/recording-slice-89O07ebs.d.ts +0 -36
- package/dist/storage/file-system.d.ts +0 -2
- package/dist/storage/file-system.js +0 -289
- /package/dist/{accuracy-circles-BpwWAs8G.d.ts → accuracy-circles-BtqOP_v1.d.ts} +0 -0
- /package/dist/{alignment-lerper-Dm9G7JJO.d.ts → alignment-lerper-Bil6vbVw.d.ts} +0 -0
- /package/dist/{ar-types-Dan1MVTi.d.ts → ar-types-BFX2r1wk.d.ts} +0 -0
- /package/dist/{bresenham3d-CFfd7n6B.d.ts → bresenham3d-CU1Gv2W4.d.ts} +0 -0
- /package/dist/{camera-follower-C2mwEn7c.d.ts → camera-follower-CqJJ7zRj.d.ts} +0 -0
- /package/dist/{capability-checker-CQXJHxXg.d.ts → capability-checker-DUQLg6gq.d.ts} +0 -0
- /package/dist/{capture-failure-tracker-CUeU3L_M.d.ts → capture-failure-tracker-gsm8q7yi.d.ts} +0 -0
- /package/dist/{chromium-camera-access-workaround-Jqbn0apH.d.ts → chromium-camera-access-workaround-D4K2uwwQ.d.ts} +0 -0
- /package/dist/{css3d-renderer-manager-ptu_t3B3.d.ts → css3d-renderer-manager-B3kGNtcn.d.ts} +0 -0
- /package/dist/{failure-tracker-Cn8Fo9D4.d.ts → failure-tracker-BO7M7jF_.d.ts} +0 -0
- /package/dist/{file-system-utils-CXIoL-DM.d.ts → file-system-utils-DOajnMm-.d.ts} +0 -0
- /package/dist/{format-file-size-CLCZz3lC.d.ts → format-file-size-Dc98ulzB.d.ts} +0 -0
- /package/dist/{frame-loop-CMewS8cY.d.ts → frame-loop-CpVjQ1dH.d.ts} +0 -0
- /package/dist/{frustum-visibility-CmI96ESS.d.ts → frustum-visibility-CeoCZchO.d.ts} +0 -0
- /package/dist/{geo-types-SaPnIEUM.d.ts → geo-types-3Ip1NzVR.d.ts} +0 -0
- /package/dist/{gps-VuezJWK3.d.ts → gps-BBO3hKfT.d.ts} +0 -0
- /package/dist/{gps-compass-cubes-BM1uGiYV.d.ts → gps-compass-cubes-DSN87L8p.d.ts} +0 -0
- /package/dist/{gps-error-handler-CJl_2MVm.d.ts → gps-error-handler-BbPsfw-_.d.ts} +0 -0
- /package/dist/{hit-test-reticle-BEzEybxZ.d.ts → hit-test-reticle-DV-2TpB9.d.ts} +0 -0
- /package/dist/{lerp-utils-BpV-0Dtk.d.ts → lerp-utils-BLmHhkVe.d.ts} +0 -0
- /package/dist/{list-formatter-RRcBe8Vg.d.ts → list-formatter-KNMS0ay2.d.ts} +0 -0
- /package/dist/{logger-BEHXsnnq.d.ts → logger-CLnPrHiD.d.ts} +0 -0
- /package/dist/{map-overlay-bcogY5fK.d.ts → map-overlay-Dh2B97MP.d.ts} +0 -0
- /package/dist/{permission-checker-GpAiSCwd.d.ts → permission-checker-CDuI8BwC.d.ts} +0 -0
- /package/dist/{scene-node-names-Bu0S66H1.d.ts → scene-node-names-BiShOQDB.d.ts} +0 -0
- /package/dist/{session-disposers-M-oashRH.js → session-disposers-zv9OGXPB.js} +0 -0
- /package/dist/{three-dispose-D950t71B.d.ts → three-dispose-Bt1k7WKh.d.ts} +0 -0
- /package/dist/{vis-colors-D6omC64K.d.ts → vis-colors-Obw2pLqT.d.ts} +0 -0
- /package/dist/{webxr-nue-basis-CqKQmZzT.d.ts → webxr-nue-basis-3nfjDJJp.d.ts} +0 -0
- /package/dist/{xr-camera-texture-DBwCaKTd.d.ts → xr-camera-texture-Cva1q3Qj.d.ts} +0 -0
- /package/dist/{xr-error-handler-C0AQRmxs.d.ts → xr-error-handler-CtvHpjfm.d.ts} +0 -0
- /package/dist/{xr-frame-loop-BtYytZJg.d.ts → xr-frame-loop-DIYtRcUa.d.ts} +0 -0
- /package/dist/{zip-reader-DSEXt7K6.d.ts → zip-reader-D9iPQwdQ.d.ts} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as geodesicAngleRad } from "../geodesic-angle-BTldfFgs.js";
|
|
2
|
+
import { selectTrackingPhase } from "./tracking-slice.js";
|
|
2
3
|
import { selectAlignmentMatrix, selectGpsPositions, selectOdometryPositions, selectZeroReference } from "./app-selectors.js";
|
|
3
4
|
import { calcGpsCoords, distanceInMeters } from "gps-plus-slam-js";
|
|
4
5
|
import { mat4, quat, vec3 } from "gl-matrix";
|
|
@@ -13,19 +14,15 @@ const DEFAULT_TRACKING_QUALITY_OPTIONS = {
|
|
|
13
14
|
coverageDirectionSpreadDeg: 90,
|
|
14
15
|
convergenceRotationWarnDeg: 6,
|
|
15
16
|
convergenceTranslationWarnM: 2,
|
|
16
|
-
compassWarnDeg: 15,
|
|
17
|
-
compassFailDeg: 35,
|
|
18
17
|
warmupMinObservations: 10,
|
|
19
18
|
warmupMinCoverage: .5,
|
|
20
19
|
residualConfidenceTargetM: 3,
|
|
21
20
|
gpsAccuracyFloorM: 1,
|
|
22
|
-
firstAgreementMinStreak: 3,
|
|
23
21
|
degradedHoldoff: 3,
|
|
24
22
|
convergenceEmaAlpha: .3
|
|
25
23
|
};
|
|
26
24
|
const initialState = {
|
|
27
25
|
recentAlignments: [],
|
|
28
|
-
firstAgreementObservationIndex: null,
|
|
29
26
|
report: null,
|
|
30
27
|
degradedConsecutiveCount: 0,
|
|
31
28
|
smoothedConvergence: null
|
|
@@ -47,11 +44,6 @@ function emaBlend(prev, raw, alpha) {
|
|
|
47
44
|
if (prev === null) return raw;
|
|
48
45
|
return prev + (Number.isFinite(alpha) ? alpha : 1) * (raw - prev);
|
|
49
46
|
}
|
|
50
|
-
function wrapToHalfCircle(deg) {
|
|
51
|
-
let d = (deg + 180) % 360 - 180;
|
|
52
|
-
if (d < -180) d += 360;
|
|
53
|
-
return d;
|
|
54
|
-
}
|
|
55
47
|
function bearingDeg(north, east) {
|
|
56
48
|
let deg = Math.atan2(east, north) * 180 / Math.PI;
|
|
57
49
|
if (deg < 0) deg += 360;
|
|
@@ -87,6 +79,11 @@ function rampUp(value, low, high) {
|
|
|
87
79
|
if (value >= high) return 1;
|
|
88
80
|
return (value - low) / (high - low);
|
|
89
81
|
}
|
|
82
|
+
/** True iff every element of the matrix is a finite number (no NaN/Infinity). */
|
|
83
|
+
function isFiniteMatrix(m) {
|
|
84
|
+
for (let i = 0; i < m.length; i++) if (!Number.isFinite(m[i])) return false;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
90
87
|
/**
|
|
91
88
|
* §4.1 matrix-history convergence over the buffered snapshots.
|
|
92
89
|
*
|
|
@@ -118,7 +115,15 @@ function computeConvergence(snapshots, options = {}) {
|
|
|
118
115
|
let sumTransM = 0;
|
|
119
116
|
let pairCount = 0;
|
|
120
117
|
for (let i = 1; i < snapshots.length; i++) {
|
|
121
|
-
const
|
|
118
|
+
const prevM = snapshots[i - 1].matrix;
|
|
119
|
+
const currM = snapshots[i].matrix;
|
|
120
|
+
if (!isFiniteMatrix(prevM) || !isFiniteMatrix(currM)) {
|
|
121
|
+
sumRotDeg += rotFail;
|
|
122
|
+
sumTransM += transFail;
|
|
123
|
+
pairCount += 1;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const { rotationDeltaDeg, translationDeltaM } = matrixDelta(prevM, currM);
|
|
122
127
|
sumRotDeg += Math.abs(rotationDeltaDeg);
|
|
123
128
|
sumTransM += Math.abs(translationDeltaM);
|
|
124
129
|
pairCount += 1;
|
|
@@ -137,7 +142,8 @@ function computeConvergence(snapshots, options = {}) {
|
|
|
137
142
|
* the column-major layout that gl-matrix and the framework use.
|
|
138
143
|
*
|
|
139
144
|
* Rotation: extract the orientation quaternion with `mat4.getRotation`
|
|
140
|
-
* and compute the relative angle via `
|
|
145
|
+
* and compute the relative angle via the shared `geodesicAngleRad` kernel
|
|
146
|
+
* (radians, converted to degrees here).
|
|
141
147
|
* Translation: extract the origin column with `mat4.getTranslation` and
|
|
142
148
|
* compute the Euclidean distance.
|
|
143
149
|
*
|
|
@@ -161,15 +167,16 @@ function matrixDelta(prev, curr) {
|
|
|
161
167
|
mat4.getRotation(currQuat, currMat);
|
|
162
168
|
quat.normalize(prevQuat, prevQuat);
|
|
163
169
|
quat.normalize(currQuat, currQuat);
|
|
164
|
-
const angleRad =
|
|
165
|
-
const rotationDeltaDeg = Number.
|
|
170
|
+
const angleRad = geodesicAngleRad(prevQuat, currQuat);
|
|
171
|
+
const rotationDeltaDeg = Number.isFinite(angleRad) ? angleRad * 180 / Math.PI : 0;
|
|
166
172
|
const prevT = vec3.create();
|
|
167
173
|
const currT = vec3.create();
|
|
168
174
|
mat4.getTranslation(prevT, prevMat);
|
|
169
175
|
mat4.getTranslation(currT, currMat);
|
|
176
|
+
const rawTranslation = vec3.distance(prevT, currT);
|
|
170
177
|
return {
|
|
171
178
|
rotationDeltaDeg,
|
|
172
|
-
translationDeltaM:
|
|
179
|
+
translationDeltaM: Number.isFinite(rawTranslation) ? rawTranslation : 0
|
|
173
180
|
};
|
|
174
181
|
}
|
|
175
182
|
/**
|
|
@@ -319,56 +326,6 @@ function computeCoverage(odometryPositions, options = {}) {
|
|
|
319
326
|
};
|
|
320
327
|
}
|
|
321
328
|
/**
|
|
322
|
-
* §4.3 — Compare the alignment matrix's mapping of AR-forward to ENU
|
|
323
|
-
* against the device compass heading. Returns `score = null` whenever
|
|
324
|
-
* the sensor's `absolute !== true` so the aggregate excludes the
|
|
325
|
-
* sub-score (per Q2 in the plan).
|
|
326
|
-
*
|
|
327
|
-
* AR-forward in our `ARPose` convention is `(0, 0, -1)` (right-handed,
|
|
328
|
-
* Y-up). We rotate that by the alignment's 3×3 rotation, take its
|
|
329
|
-
* North/East components, and compare against the compass alpha.
|
|
330
|
-
*/
|
|
331
|
-
function computeCompassAgreement(alignmentMatrix, sensorOrientation, arPose, options = {}) {
|
|
332
|
-
const warn = options.warnDeg ?? DEFAULT_TRACKING_QUALITY_OPTIONS.compassWarnDeg;
|
|
333
|
-
const fail = options.failDeg ?? DEFAULT_TRACKING_QUALITY_OPTIONS.compassFailDeg;
|
|
334
|
-
if (!alignmentMatrix || !sensorOrientation || !arPose) return {
|
|
335
|
-
score: null,
|
|
336
|
-
headingDeltaDeg: null
|
|
337
|
-
};
|
|
338
|
-
if (sensorOrientation.absolute !== true) return {
|
|
339
|
-
score: null,
|
|
340
|
-
headingDeltaDeg: null
|
|
341
|
-
};
|
|
342
|
-
const q = arPose.orientation;
|
|
343
|
-
const fx = 0;
|
|
344
|
-
const fy = 0;
|
|
345
|
-
const fz = -1;
|
|
346
|
-
const x = q.x, y = q.y, z = q.z, w = q.w;
|
|
347
|
-
const tx = 2 * (y * fz - z * fy);
|
|
348
|
-
const ty = 2 * (z * fx - x * fz);
|
|
349
|
-
const tz = 2 * (x * fy - y * fx);
|
|
350
|
-
const arForwardLocal = [
|
|
351
|
-
fx + w * tx + (y * tz - z * ty),
|
|
352
|
-
fy + w * ty + (z * tx - x * tz),
|
|
353
|
-
fz + w * tz + (x * ty - y * tx)
|
|
354
|
-
];
|
|
355
|
-
const m = alignmentMatrix;
|
|
356
|
-
const enuN = m[0] * arForwardLocal[0] + m[4] * arForwardLocal[1] + m[8] * arForwardLocal[2];
|
|
357
|
-
m[1] * arForwardLocal[0] + m[5] * arForwardLocal[1] + m[9] * arForwardLocal[2];
|
|
358
|
-
const enuE = m[2] * arForwardLocal[0] + m[6] * arForwardLocal[1] + m[10] * arForwardLocal[2];
|
|
359
|
-
if (Math.hypot(enuN, enuE) < 1e-6) return {
|
|
360
|
-
score: null,
|
|
361
|
-
headingDeltaDeg: null
|
|
362
|
-
};
|
|
363
|
-
const alignmentHeadingDeg = bearingDeg(enuN, enuE);
|
|
364
|
-
const compassHeadingDeg = sensorOrientation.alpha;
|
|
365
|
-
const delta = Math.abs(wrapToHalfCircle(alignmentHeadingDeg - compassHeadingDeg));
|
|
366
|
-
return {
|
|
367
|
-
score: rampDown(delta, warn, fail),
|
|
368
|
-
headingDeltaDeg: delta
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
329
|
* §4.6 — Maximum lateral distance between raw GPS positions and the
|
|
373
330
|
* positions you would predict by transforming the matching odometry
|
|
374
331
|
* positions through the current alignment. Diagnostic only — never
|
|
@@ -418,9 +375,6 @@ const trackingQualitySlice = createSlice({
|
|
|
418
375
|
reportUpdated(state, action) {
|
|
419
376
|
state.report = action.payload;
|
|
420
377
|
},
|
|
421
|
-
firstAgreementReached(state, action) {
|
|
422
|
-
state.firstAgreementObservationIndex = action.payload;
|
|
423
|
-
},
|
|
424
378
|
/** §4.8 — update the hysteresis counter for ok → degraded holdoff. */
|
|
425
379
|
degradedCountUpdated(state, action) {
|
|
426
380
|
state.degradedConsecutiveCount = action.payload;
|
|
@@ -439,7 +393,7 @@ const trackingQualitySlice = createSlice({
|
|
|
439
393
|
}
|
|
440
394
|
}
|
|
441
395
|
});
|
|
442
|
-
const { snapshotPushed, snapshotsTrimmed, reportUpdated,
|
|
396
|
+
const { snapshotPushed, snapshotsTrimmed, reportUpdated, degradedCountUpdated, resetTrackingQuality } = trackingQualitySlice.actions;
|
|
443
397
|
const { smoothedConvergenceUpdated } = trackingQualitySlice.actions;
|
|
444
398
|
const trackingQualityReducer = trackingQualitySlice.reducer;
|
|
445
399
|
function selectTrackingQuality(state) {
|
|
@@ -448,9 +402,6 @@ function selectTrackingQuality(state) {
|
|
|
448
402
|
function selectRecentAlignments(state) {
|
|
449
403
|
return state.trackingQuality?.recentAlignments ?? EMPTY_SNAPSHOTS;
|
|
450
404
|
}
|
|
451
|
-
function selectFirstAgreementObservationIndex(state) {
|
|
452
|
-
return state.trackingQuality?.firstAgreementObservationIndex ?? null;
|
|
453
|
-
}
|
|
454
405
|
const EMPTY_SNAPSHOTS = Object.freeze([]);
|
|
455
406
|
/**
|
|
456
407
|
* Pure function — produces a {@link TrackingQualityReport} from a root
|
|
@@ -474,10 +425,7 @@ function computeTrackingQualityReport(rootState, options = {}) {
|
|
|
474
425
|
const odometryPositions = selectOdometryPositions(rootState);
|
|
475
426
|
const zeroRef = selectZeroReference(rootState);
|
|
476
427
|
const trackingPhase = selectTrackingPhase(rootState);
|
|
477
|
-
const sensorOrientation = selectLastSensorOrientation(rootState);
|
|
478
|
-
const lastPose = selectLastValidPose(rootState);
|
|
479
428
|
const snapshots = selectRecentAlignments(rootState);
|
|
480
|
-
const firstAgreementIdx = selectFirstAgreementObservationIndex(rootState);
|
|
481
429
|
const coverage = computeCoverage(odometryPositions, {
|
|
482
430
|
walkedDistanceM: opts.coverageWalkedDistanceM,
|
|
483
431
|
directionSpreadDeg: opts.coverageDirectionSpreadDeg
|
|
@@ -492,15 +440,10 @@ function computeTrackingQualityReport(rootState, options = {}) {
|
|
|
492
440
|
rotationWarnDeg: opts.convergenceRotationWarnDeg,
|
|
493
441
|
translationWarnM: opts.convergenceTranslationWarnM
|
|
494
442
|
});
|
|
495
|
-
const compass = computeCompassAgreement(alignmentMatrix, sensorOrientation, lastPose, {
|
|
496
|
-
warnDeg: opts.compassWarnDeg,
|
|
497
|
-
failDeg: opts.compassFailDeg
|
|
498
|
-
});
|
|
499
443
|
const gpsVsFusedMaxDivergenceM = computeGpsVsFusedDivergence(alignmentMatrix, gpsPositions, odometryPositions, zeroRef);
|
|
500
444
|
const subScores = {
|
|
501
445
|
convergence: clamp01(emaBlend(rootState.trackingQuality?.smoothedConvergence ?? null, convergence.score, opts.convergenceEmaAlpha)),
|
|
502
446
|
residualConsensus: clamp01(residual.score),
|
|
503
|
-
compassAgreement: compass.score === null ? null : clamp01(compass.score),
|
|
504
447
|
gpsAccuracy: clamp01(gpsAccuracy.score),
|
|
505
448
|
coverage: clamp01(coverage.score)
|
|
506
449
|
};
|
|
@@ -510,7 +453,6 @@ function computeTrackingQualityReport(rootState, options = {}) {
|
|
|
510
453
|
subScores.gpsAccuracy,
|
|
511
454
|
subScores.coverage
|
|
512
455
|
];
|
|
513
|
-
if (subScores.compassAgreement !== null) aggregateInputs.push(subScores.compassAgreement);
|
|
514
456
|
const confidence = clamp01(Math.min(...aggregateInputs));
|
|
515
457
|
const observationsSeen = gpsPositions.length;
|
|
516
458
|
let state;
|
|
@@ -529,8 +471,6 @@ function computeTrackingQualityReport(rootState, options = {}) {
|
|
|
529
471
|
medianRecentGpsAccuracyM: gpsAccuracy.medianM,
|
|
530
472
|
walkedDistanceM: coverage.walkedDistanceM,
|
|
531
473
|
directionSpreadDeg: coverage.directionSpreadDeg,
|
|
532
|
-
headingDeltaDeg: compass.headingDeltaDeg,
|
|
533
|
-
compassDriftDetected: firstAgreementIdx !== null && compass.headingDeltaDeg !== null && compass.headingDeltaDeg > opts.compassWarnDeg,
|
|
534
474
|
observationsSeen,
|
|
535
475
|
gpsVsFusedMaxDivergenceM
|
|
536
476
|
}
|
|
@@ -540,15 +480,14 @@ function computeTrackingQualityReport(rootState, options = {}) {
|
|
|
540
480
|
* Per-field tolerances for the {@link reportsEqual} dispatch gate.
|
|
541
481
|
*
|
|
542
482
|
* Why this exists: `tracking/poseReceived` fires on *every* XR frame
|
|
543
|
-
* (30–60 fps). The
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
* quality actually moved.
|
|
483
|
+
* (30–60 fps). The per-frame recompute reuses GPS/odometry windows that
|
|
484
|
+
* are unchanged between pose frames, so the float sub-scores and
|
|
485
|
+
* diagnostics (and `confidence`) jitter by imperceptible floating-point
|
|
486
|
+
* amounts on a held-still device. With a strict `!==` comparison every
|
|
487
|
+
* such frame produced a fresh `reportUpdated` dispatch → high Redux
|
|
488
|
+
* churn and a HUD re-render at frame rate. The tolerances below quantise
|
|
489
|
+
* those sub-perceptual changes so the gate only fires when the
|
|
490
|
+
* user-visible quality actually moved.
|
|
552
491
|
*
|
|
553
492
|
* The gate compares the freshly computed report against the *last
|
|
554
493
|
* dispatched* report (the stored `prev`), not against the previous
|
|
@@ -567,10 +506,9 @@ const REPORT_METRE_EPSILON_M = .001;
|
|
|
567
506
|
* (both `null` ⇒ equal; exactly one `null` ⇒ different) and otherwise
|
|
568
507
|
* compares with an absolute epsilon. Non-finite values are compared with
|
|
569
508
|
* {@link Object.is}, so a genuine finite↔NaN/Infinity transition still
|
|
570
|
-
* fires a dispatch, but a *persistently* NaN diagnostic
|
|
571
|
-
*
|
|
572
|
-
* `
|
|
573
|
-
* `Object.is(NaN, NaN)` is `true` whereas `NaN === NaN` is `false`.
|
|
509
|
+
* fires a dispatch, but a *persistently* NaN diagnostic does NOT churn
|
|
510
|
+
* the gate every frame — `Object.is(NaN, NaN)` is `true` whereas
|
|
511
|
+
* `NaN === NaN` is `false`.
|
|
574
512
|
*/
|
|
575
513
|
function nearlyEqual(a, b, eps) {
|
|
576
514
|
if (a === null || b === null) return a === b;
|
|
@@ -585,8 +523,8 @@ function nearlyEqual(a, b, eps) {
|
|
|
585
523
|
*
|
|
586
524
|
* Float fields use the per-field tolerances above
|
|
587
525
|
* ({@link REPORT_SCORE_EPSILON} et al.) so imperceptible per-frame
|
|
588
|
-
*
|
|
589
|
-
*
|
|
526
|
+
* jitter does not churn the store — see the constants' doc comment for
|
|
527
|
+
* the rationale.
|
|
590
528
|
*/
|
|
591
529
|
function reportsEqual(a, b) {
|
|
592
530
|
if (a === b) return true;
|
|
@@ -595,10 +533,10 @@ function reportsEqual(a, b) {
|
|
|
595
533
|
if (!nearlyEqual(a.confidence, b.confidence, REPORT_SCORE_EPSILON)) return false;
|
|
596
534
|
const sa = a.subScores;
|
|
597
535
|
const sb = b.subScores;
|
|
598
|
-
if (!nearlyEqual(sa.convergence, sb.convergence, REPORT_SCORE_EPSILON) || !nearlyEqual(sa.residualConsensus, sb.residualConsensus, REPORT_SCORE_EPSILON) || !nearlyEqual(sa.
|
|
536
|
+
if (!nearlyEqual(sa.convergence, sb.convergence, REPORT_SCORE_EPSILON) || !nearlyEqual(sa.residualConsensus, sb.residualConsensus, REPORT_SCORE_EPSILON) || !nearlyEqual(sa.gpsAccuracy, sb.gpsAccuracy, REPORT_SCORE_EPSILON) || !nearlyEqual(sa.coverage, sb.coverage, REPORT_SCORE_EPSILON)) return false;
|
|
599
537
|
const da = a.diagnostics;
|
|
600
538
|
const db = b.diagnostics;
|
|
601
|
-
return da.
|
|
539
|
+
return da.observationsSeen === db.observationsSeen && nearlyEqual(da.recentSumRotationDeltaDeg, db.recentSumRotationDeltaDeg, REPORT_ANGLE_EPSILON_DEG) && nearlyEqual(da.directionSpreadDeg, db.directionSpreadDeg, REPORT_ANGLE_EPSILON_DEG) && nearlyEqual(da.recentSumTranslationDeltaM, db.recentSumTranslationDeltaM, REPORT_METRE_EPSILON_M) && nearlyEqual(da.medianResidualM, db.medianResidualM, REPORT_METRE_EPSILON_M) && nearlyEqual(da.medianRecentGpsAccuracyM, db.medianRecentGpsAccuracyM, REPORT_METRE_EPSILON_M) && nearlyEqual(da.walkedDistanceM, db.walkedDistanceM, REPORT_METRE_EPSILON_M) && nearlyEqual(da.gpsVsFusedMaxDivergenceM, db.gpsVsFusedMaxDivergenceM, REPORT_METRE_EPSILON_M);
|
|
602
540
|
}
|
|
603
541
|
function matricesNearlyEqual(a, b) {
|
|
604
542
|
if (a.length !== b.length) return false;
|
|
@@ -650,16 +588,14 @@ function createTrackingQualityListenerMiddleware(options = {}) {
|
|
|
650
588
|
...DEFAULT_TRACKING_QUALITY_OPTIONS,
|
|
651
589
|
...options
|
|
652
590
|
};
|
|
653
|
-
let compassStreak = 0;
|
|
654
591
|
const listenerMiddleware = createListenerMiddleware();
|
|
655
592
|
listenerMiddleware.startListening({
|
|
656
593
|
predicate: (action) => inputActionPredicate(action),
|
|
657
594
|
effect: (action, api) => {
|
|
658
595
|
const state = api.getState();
|
|
659
596
|
if (action.type === TRACKING_QUALITY_INPUT_ACTIONS.startSession || action.type === TRACKING_QUALITY_INPUT_ACTIONS.resetTracking) {
|
|
660
|
-
compassStreak = 0;
|
|
661
597
|
const tq = state.trackingQuality;
|
|
662
|
-
if (tq && (tq.recentAlignments.length > 0 || tq.
|
|
598
|
+
if (tq && (tq.recentAlignments.length > 0 || tq.report !== null || tq.degradedConsecutiveCount > 0)) api.dispatch(resetTrackingQuality());
|
|
663
599
|
return;
|
|
664
600
|
}
|
|
665
601
|
if (action.type === TRACKING_QUALITY_INPUT_ACTIONS.gpsRecorded || action.type === TRACKING_QUALITY_INPUT_ACTIONS.setZeroPos) {
|
|
@@ -678,30 +614,6 @@ function createTrackingQualityListenerMiddleware(options = {}) {
|
|
|
678
614
|
}
|
|
679
615
|
}
|
|
680
616
|
}
|
|
681
|
-
const midState = api.getState();
|
|
682
|
-
const midTq = midState.trackingQuality;
|
|
683
|
-
if (midTq && midTq.firstAgreementObservationIndex === null) {
|
|
684
|
-
const snapshots = selectRecentAlignments(midState);
|
|
685
|
-
if (snapshots.length >= 2) {
|
|
686
|
-
const conv = computeConvergence(snapshots, {
|
|
687
|
-
rotationWarnDeg: opts.convergenceRotationWarnDeg,
|
|
688
|
-
translationWarnM: opts.convergenceTranslationWarnM
|
|
689
|
-
});
|
|
690
|
-
const sensorOr = selectLastSensorOrientation(midState);
|
|
691
|
-
const pose = selectLastValidPose(midState);
|
|
692
|
-
const compass = computeCompassAgreement(selectAlignmentMatrix(midState), sensorOr, pose, {
|
|
693
|
-
warnDeg: opts.compassWarnDeg,
|
|
694
|
-
failDeg: opts.compassFailDeg
|
|
695
|
-
});
|
|
696
|
-
if (conv.score >= .7 && compass.headingDeltaDeg !== null && compass.headingDeltaDeg <= opts.compassWarnDeg) {
|
|
697
|
-
compassStreak += 1;
|
|
698
|
-
if (compassStreak >= opts.firstAgreementMinStreak) {
|
|
699
|
-
const obsCount = selectGpsPositions(midState).length;
|
|
700
|
-
api.dispatch(firstAgreementReached(obsCount));
|
|
701
|
-
}
|
|
702
|
-
} else compassStreak = 0;
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
617
|
const next = api.getState();
|
|
706
618
|
const report = computeTrackingQualityReport(next, opts);
|
|
707
619
|
const prev = next.trackingQuality?.report ?? null;
|
|
@@ -720,4 +632,4 @@ function createTrackingQualityListenerMiddleware(options = {}) {
|
|
|
720
632
|
return listenerMiddleware.middleware;
|
|
721
633
|
}
|
|
722
634
|
//#endregion
|
|
723
|
-
export { DEFAULT_TRACKING_QUALITY_OPTIONS,
|
|
635
|
+
export { DEFAULT_TRACKING_QUALITY_OPTIONS, computeConvergence, computeCoverage, computeGpsAccuracy, computeGpsVsFusedDivergence, computeResidualConsensus, computeTrackingQualityReport, createTrackingQualityListenerMiddleware, degradedCountUpdated, matrixDelta, reportUpdated, resetTrackingQuality, selectRecentAlignments, selectTrackingQuality, snapshotPushed, snapshotsTrimmed, trackingQualityReducer };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as TrackingSliceState, c as poseLost, d as selectLastRestartedPayload, f as selectLastSensorOrientation, g as trackingReducer, h as selectTrackingPhase, i as TrackingPhase, l as poseReceived, m as selectLostFrameCount, n as PoseReceivedPayload, o as clearLastRestartedPayload, p as selectLastValidPose, r as ResetTransformData, s as originReset, t as DeviceOrientation, u as resetTracking } from "../tracking-slice-
|
|
1
|
+
import { a as TrackingSliceState, c as poseLost, d as selectLastRestartedPayload, f as selectLastSensorOrientation, g as trackingReducer, h as selectTrackingPhase, i as TrackingPhase, l as poseReceived, m as selectLostFrameCount, n as PoseReceivedPayload, o as clearLastRestartedPayload, p as selectLastValidPose, r as ResetTransformData, s as originReset, t as DeviceOrientation, u as resetTracking } from "../tracking-slice-BuAZxXZ5.js";
|
|
2
2
|
export { DeviceOrientation, PoseReceivedPayload, ResetTransformData, TrackingPhase, TrackingSliceState, clearLastRestartedPayload, originReset, poseLost, poseReceived, resetTracking, selectLastRestartedPayload, selectLastSensorOrientation, selectLastValidPose, selectLostFrameCount, selectTrackingPhase, trackingReducer };
|
|
@@ -2,11 +2,12 @@ import "./state/gps-event-coordinator.js";
|
|
|
2
2
|
import "./state/tracking-slice.js";
|
|
3
3
|
import "./state/recording-options.js";
|
|
4
4
|
import "./state/recording-slice.js";
|
|
5
|
+
import "./state/qr-detected-slice.js";
|
|
5
6
|
import "./state/gps-ar-pose-sampler.js";
|
|
6
7
|
import "./state/app-selectors.js";
|
|
7
8
|
import { selectTrackingQuality } from "./state/tracking-quality.js";
|
|
8
9
|
import "./state/persistence-middleware.js";
|
|
9
|
-
import "./
|
|
10
|
+
import "./create-slam-app-store-DkCHOpvb.js";
|
|
10
11
|
import "./state/recording-replayer.js";
|
|
11
12
|
import "./state/store-subscribers.js";
|
|
12
13
|
import { add2dImage, calcRelativeCoordsInMeters, recordGpsEvent as recordGpsEvent$1, setZeroPos as setZeroPos$1 } from "gps-plus-slam-js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as formatTimestamp, i as formatFrameFilename, n as SESSION_IMAGES_DIR, r as formatActionFilename, t as LEGACY_SESSION_IMAGES_DIR } from "../file-system-utils-
|
|
1
|
+
import { a as formatTimestamp, i as formatFrameFilename, n as SESSION_IMAGES_DIR, r as formatActionFilename, t as LEGACY_SESSION_IMAGES_DIR } from "../file-system-utils-DOajnMm-.js";
|
|
2
2
|
export { LEGACY_SESSION_IMAGES_DIR, SESSION_IMAGES_DIR, formatActionFilename, formatFrameFilename, formatTimestamp };
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, h as writeSessionMetadata
|
|
2
|
-
import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-
|
|
3
|
-
import { a as ZipActionEntry, c as loadEntriesFromSubdir, d as loadSessionMetadataFromBlob, f as readZipEntries, i as RecordedAction, l as loadGpsPathFromBlob, n as GpsPathCoord, o as ZipSubdirEntry, r as MAX_ACTION_FILE_SIZE, s as loadActionsFromZip, t as Entry, u as loadSessionMetadata } from "../zip-reader-
|
|
4
|
-
import { t as NullStorageBackend } from "../null-storage-backend-
|
|
5
|
-
import { t as OpfsStorageBackend } from "../opfs-storage-backend-
|
|
6
|
-
import { a as
|
|
7
|
-
import { a as
|
|
8
|
-
import {
|
|
9
|
-
export { type CreateSessionResult, type Entry, type ExportSessionAsZipOptions, type GpsPathCoord, MAX_ACTION_FILE_SIZE, NullStorageBackend, OpfsStorageBackend, type RecordedAction, type SessionMetadata, type StorageBackend, type
|
|
1
|
+
import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, h as writeSessionMetadata, i as createSession, l as listSessions, n as SessionMetadata, o as getSessionHandle, r as checkStorageQuota, s as getSessionsRootHandle, u as resetOpfsStorage } from "../opfs-storage-3VZh-qH6.js";
|
|
2
|
+
import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-BdVLD0dU.js";
|
|
3
|
+
import { a as ZipActionEntry, c as loadEntriesFromSubdir, d as loadSessionMetadataFromBlob, f as readZipEntries, i as RecordedAction, l as loadGpsPathFromBlob, n as GpsPathCoord, o as ZipSubdirEntry, r as MAX_ACTION_FILE_SIZE, s as loadActionsFromZip, t as Entry, u as loadSessionMetadata } from "../zip-reader-D9iPQwdQ.js";
|
|
4
|
+
import { t as NullStorageBackend } from "../null-storage-backend-B9rtyDfG.js";
|
|
5
|
+
import { t as OpfsStorageBackend } from "../opfs-storage-backend-JJiUJo-3.js";
|
|
6
|
+
import { a as formatTimestamp, i as formatFrameFilename, r as formatActionFilename } from "../file-system-utils-DOajnMm-.js";
|
|
7
|
+
import { a as downloadZip, c as syncToExternalZip, i as ZipExportResult, n as ZipContributorAddFile, o as exportSessionAsZip, r as ZipExportContributor, s as exportSessionHandleAsZip, t as ExportSessionAsZipOptions } from "../zip-export-ol0S_Ofd.js";
|
|
8
|
+
import { t as embedCoverageInSessionJson } from "../zip-coverage-embed-DCAREVmw.js";
|
|
9
|
+
export { type CreateSessionResult, type Entry, type ExportSessionAsZipOptions, type GpsPathCoord, MAX_ACTION_FILE_SIZE, NullStorageBackend, OpfsStorageBackend, type RecordedAction, type SessionMetadata, type StorageBackend, type ZipActionEntry, type ZipContributorAddFile, type ZipExportContributor, type ZipExportResult, type ZipSubdirEntry, checkStorageQuota, createSession, downloadZip, embedCoverageInSessionJson, exportSessionAsZip, exportSessionHandleAsZip, formatActionFilename, formatFrameFilename, formatTimestamp, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadataFromBlob, loadSessionMetadata as loadSessionMetadataFromZip, readZipEntries, resetOpfsStorage, resetSessionHandles, syncToExternalZip, writeSessionMetadata };
|
package/dist/storage/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MAX_ACTION_FILE_SIZE, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadata, loadSessionMetadataFromBlob, readZipEntries } from "./zip-reader.js";
|
|
2
2
|
import { formatActionFilename, formatFrameFilename, formatTimestamp } from "./file-system-utils.js";
|
|
3
3
|
import { NullStorageBackend } from "./null-storage-backend.js";
|
|
4
|
-
import { checkStorageQuota, createSession, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, resetOpfsStorage, resetSessionHandles, writeSessionMetadata
|
|
5
|
-
import { ensureScenarioDirectory, getCurrentScenarioHandle, initStorage, listSessions as listSessions$1, resetForNewSession, resetStorageState, setCurrentScenario, startSession, verifyWriteAccess, writeAction, writeFrame, writeSessionMetadata } from "./file-system.js";
|
|
4
|
+
import { checkStorageQuota, createSession, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, resetOpfsStorage, resetSessionHandles, writeSessionMetadata } from "./opfs-storage.js";
|
|
6
5
|
import { OpfsStorageBackend } from "./opfs-storage-backend.js";
|
|
7
|
-
import { downloadZip,
|
|
8
|
-
|
|
6
|
+
import { downloadZip, exportSessionAsZip, exportSessionHandleAsZip, syncToExternalZip } from "./zip-export.js";
|
|
7
|
+
import { embedCoverageInSessionJson } from "./zip-coverage-embed.js";
|
|
8
|
+
export { MAX_ACTION_FILE_SIZE, NullStorageBackend, OpfsStorageBackend, checkStorageQuota, createSession, downloadZip, embedCoverageInSessionJson, exportSessionAsZip, exportSessionHandleAsZip, formatActionFilename, formatFrameFilename, formatTimestamp, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadataFromBlob, loadSessionMetadata as loadSessionMetadataFromZip, readZipEntries, resetOpfsStorage, resetSessionHandles, syncToExternalZip, writeSessionMetadata };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as NullStorageBackend } from "../null-storage-backend-
|
|
1
|
+
import { t as NullStorageBackend } from "../null-storage-backend-B9rtyDfG.js";
|
|
2
2
|
export { NullStorageBackend };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as OpfsStorageBackend } from "../opfs-storage-backend-
|
|
1
|
+
import { t as OpfsStorageBackend } from "../opfs-storage-backend-JJiUJo-3.js";
|
|
2
2
|
export { OpfsStorageBackend };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSession, listSessions, writeAction, writeFrame, writeSessionMetadata } from "./opfs-storage.js";
|
|
2
2
|
//#region ../src/storage/opfs-storage-backend.ts
|
|
3
3
|
var OpfsStorageBackend = class {
|
|
4
|
-
async createSession(
|
|
5
|
-
return { sessionName: (await
|
|
4
|
+
async createSession(timestamp, _contextTag) {
|
|
5
|
+
return { sessionName: (await createSession(timestamp)).sessionName };
|
|
6
6
|
}
|
|
7
7
|
async listSessions() {
|
|
8
8
|
return listSessions();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, f as setSessionHandles, h as writeSessionMetadata, i as createSession, l as listSessions, m as writeFrame, n as SessionMetadata, o as getSessionHandle, p as writeAction, r as checkStorageQuota, s as getSessionsRootHandle, t as CreateSessionResult, u as resetOpfsStorage } from "../opfs-storage-
|
|
1
|
+
import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, f as setSessionHandles, h as writeSessionMetadata, i as createSession, l as listSessions, m as writeFrame, n as SessionMetadata, o as getSessionHandle, p as writeAction, r as checkStorageQuota, s as getSessionsRootHandle, t as CreateSessionResult, u as resetOpfsStorage } from "../opfs-storage-3VZh-qH6.js";
|
|
2
2
|
export { CreateSessionResult, SessionMetadata, checkStorageQuota, createSession, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, resetOpfsStorage, resetSessionHandles, setSessionHandles, writeAction, writeFrame, writeSessionMetadata };
|
|
@@ -121,10 +121,11 @@ function getSessionHandle() {
|
|
|
121
121
|
/**
|
|
122
122
|
* Set the active session handles externally.
|
|
123
123
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
124
|
+
* Lets a wrapping StorageBackend that creates sessions outside the flat layout
|
|
125
|
+
* (e.g. the recorder's `ScenarioWrappingStorageBackend`, which nests sessions
|
|
126
|
+
* under a named bucket) reuse opfs-storage's write infrastructure: it creates
|
|
127
|
+
* the session directory itself, then hands the handles here so subsequent
|
|
128
|
+
* `writeAction` / `writeFrame` / `writeSessionMetadata` calls target them.
|
|
128
129
|
*
|
|
129
130
|
* @internal
|
|
130
131
|
*/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-
|
|
1
|
+
import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-BdVLD0dU.js";
|
|
2
2
|
export { CreateSessionResult, StorageBackend };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger.js";
|
|
2
|
+
import { BlobReader, BlobWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from "@zip.js/zip.js";
|
|
3
|
+
//#region ../src/storage/zip-coverage-embed.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zip Coverage Embed — write a recording's H3 coverage into its `session.json`.
|
|
6
|
+
*
|
|
7
|
+
* The map-centric browser indexes legacy recordings (those predating the
|
|
8
|
+
* `h3Cells` field) by reading their full GPS path — slow, and repeated on every
|
|
9
|
+
* folder open. This primitive lets a one-time "upgrade" embed the derived
|
|
10
|
+
* coverage **inside the recording's own `session.json`**, so the recording
|
|
11
|
+
* indexes instantly on every future open in this app *and any other reader*
|
|
12
|
+
* (the portability the user asked for; O3 — in-zip rewrite).
|
|
13
|
+
*
|
|
14
|
+
* It is a pure transform `(zip, cells, resolution) -> zip`: it reads every entry
|
|
15
|
+
* and re-emits a new zip identical to the input except that `session.json` gains
|
|
16
|
+
* `h3Cells` + `h3Resolution`. It never mutates anything in place — the caller
|
|
17
|
+
* (the RecorderApp backfill) owns the safe write-then-verify-then-overwrite
|
|
18
|
+
* protocol around it.
|
|
19
|
+
*
|
|
20
|
+
* @see ./zip-coverage-embed.ts.md
|
|
21
|
+
* @see GpsPlusSlamJs_Docs/docs/2026-06-14-followup-progressive-map-browser-indexing-and-backfill.md (B3)
|
|
22
|
+
*/
|
|
23
|
+
const log = createLogger("ZipCoverageEmbed");
|
|
24
|
+
/**
|
|
25
|
+
* Return a new zip blob identical to `zip` except its `session.json` gains
|
|
26
|
+
* `h3Cells` + `h3Resolution`.
|
|
27
|
+
*
|
|
28
|
+
* **Skips (returns the input blob unchanged, by reference) when:**
|
|
29
|
+
* - the zip has no `session.json` (nothing to embed into);
|
|
30
|
+
* - `session.json` is present but unparseable (never write over a broken one);
|
|
31
|
+
* - `session.json` already carries `h3Cells` (idempotent — re-running the
|
|
32
|
+
* upgrade is a no-op, and new recordings are skipped).
|
|
33
|
+
*
|
|
34
|
+
* On any unexpected read/write failure it also returns the input untouched —
|
|
35
|
+
* it never emits a partial zip. Callers can detect a skip via reference
|
|
36
|
+
* equality (`result === zip`).
|
|
37
|
+
*
|
|
38
|
+
* Built on `@zip.js/zip.js` (the same library as the exporter) in store mode, so
|
|
39
|
+
* every non-`session.json` entry is re-emitted with byte-identical uncompressed
|
|
40
|
+
* content.
|
|
41
|
+
*/
|
|
42
|
+
async function embedCoverageInSessionJson(zip, h3Cells, h3Resolution) {
|
|
43
|
+
const reader = new ZipReader(new BlobReader(zip));
|
|
44
|
+
try {
|
|
45
|
+
const entries = await reader.getEntries();
|
|
46
|
+
const sessionEntry = entries.find((e) => !e.directory && e.filename.endsWith("session.json"));
|
|
47
|
+
if (!sessionEntry) {
|
|
48
|
+
log.warn("No session.json found; leaving zip untouched");
|
|
49
|
+
return zip;
|
|
50
|
+
}
|
|
51
|
+
let session;
|
|
52
|
+
try {
|
|
53
|
+
const text = await sessionEntry.getData(new TextWriter());
|
|
54
|
+
session = JSON.parse(text);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
log.warn("session.json unparseable; leaving zip untouched", err);
|
|
57
|
+
return zip;
|
|
58
|
+
}
|
|
59
|
+
if (session.h3Cells !== void 0) return zip;
|
|
60
|
+
const merged = {
|
|
61
|
+
...session,
|
|
62
|
+
h3Cells,
|
|
63
|
+
h3Resolution
|
|
64
|
+
};
|
|
65
|
+
const writer = new ZipWriter(new BlobWriter("application/zip"), { level: 0 });
|
|
66
|
+
try {
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
if (entry.directory || !entry.getData) continue;
|
|
69
|
+
if (entry === sessionEntry) await writer.add(entry.filename, new TextReader(JSON.stringify(merged)));
|
|
70
|
+
else {
|
|
71
|
+
const bytes = await entry.getData(new Uint8ArrayWriter());
|
|
72
|
+
await writer.add(entry.filename, new Uint8ArrayReader(bytes));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return await writer.close();
|
|
76
|
+
} catch (err) {
|
|
77
|
+
log.warn("Failed to re-emit zip; leaving original untouched", err);
|
|
78
|
+
return zip;
|
|
79
|
+
}
|
|
80
|
+
} catch (err) {
|
|
81
|
+
log.warn("Failed to read zip for coverage embed; leaving untouched", err);
|
|
82
|
+
return zip;
|
|
83
|
+
} finally {
|
|
84
|
+
await reader.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { embedCoverageInSessionJson };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as downloadZip, c as syncToExternalZip, i as ZipExportResult, n as ZipContributorAddFile, o as
|
|
2
|
-
export { ExportSessionAsZipOptions, ZipContributorAddFile, ZipExportContributor, ZipExportResult, downloadZip,
|
|
1
|
+
import { a as downloadZip, c as syncToExternalZip, i as ZipExportResult, n as ZipContributorAddFile, o as exportSessionAsZip, r as ZipExportContributor, s as exportSessionHandleAsZip, t as ExportSessionAsZipOptions } from "../zip-export-ol0S_Ofd.js";
|
|
2
|
+
export { ExportSessionAsZipOptions, ZipContributorAddFile, ZipExportContributor, ZipExportResult, downloadZip, exportSessionAsZip, exportSessionHandleAsZip, syncToExternalZip };
|