gps-plus-slam-app-framework 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.
Files changed (200) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +222 -0
  3. package/dist/alignment-lerper-D9BeDwZX.d.ts +29 -0
  4. package/dist/app-selectors-DyMzxCEC.d.ts +140 -0
  5. package/dist/ar/camera-blit-capture.d.ts +2 -0
  6. package/dist/ar/camera-blit-capture.js +253 -0
  7. package/dist/ar/capture-failure-tracker.d.ts +2 -0
  8. package/dist/ar/capture-failure-tracker.js +45 -0
  9. package/dist/ar/chromium-camera-access-workaround.d.ts +2 -0
  10. package/dist/ar/chromium-camera-access-workaround.js +32 -0
  11. package/dist/ar/depth-sampler.d.ts +3 -0
  12. package/dist/ar/depth-sampler.js +147 -0
  13. package/dist/ar/image-capture.d.ts +2 -0
  14. package/dist/ar/image-capture.js +152 -0
  15. package/dist/ar/index.d.ts +12 -0
  16. package/dist/ar/index.js +12 -0
  17. package/dist/ar/replay-scene.d.ts +2 -0
  18. package/dist/ar/replay-scene.js +325 -0
  19. package/dist/ar/scene-node-names.d.ts +2 -0
  20. package/dist/ar/scene-node-names.js +16 -0
  21. package/dist/ar/tracking-state.d.ts +2 -0
  22. package/dist/ar/tracking-state.js +164 -0
  23. package/dist/ar/webxr-session.d.ts +4 -0
  24. package/dist/ar/webxr-session.js +890 -0
  25. package/dist/ar/xr-camera-texture.d.ts +2 -0
  26. package/dist/ar/xr-camera-texture.js +39 -0
  27. package/dist/ar/xr-error-handler.d.ts +2 -0
  28. package/dist/ar/xr-error-handler.js +37 -0
  29. package/dist/ar-types-B-ORgk6Z.d.ts +82 -0
  30. package/dist/camera-blit-capture-DHuyrrxr.d.ts +108 -0
  31. package/dist/camera-follower-BMqPddxx.d.ts +29 -0
  32. package/dist/capture-failure-tracker-2Q6oI2uQ.d.ts +52 -0
  33. package/dist/chromium-camera-access-workaround-CU5zSKNr.d.ts +61 -0
  34. package/dist/community-license-key-ChZLCJyO.d.ts +21 -0
  35. package/dist/concurrency-p6gB30fT.d.ts +24 -0
  36. package/dist/css3d-renderer-manager-rgLMVAvd.d.ts +23 -0
  37. package/dist/depth-sampler-BNCtnEoP.d.ts +108 -0
  38. package/dist/failure-tracker-1sQ_Cgyw.d.ts +49 -0
  39. package/dist/file-system-BsQgYCU3.d.ts +128 -0
  40. package/dist/file-system-utils-5cWO8Xyv.d.ts +24 -0
  41. package/dist/format-file-size-onGq0k1Q.d.ts +24 -0
  42. package/dist/fused-path-DtqCSqJh.d.ts +25 -0
  43. package/dist/geo-types-Xx-LVcnw.d.ts +29 -0
  44. package/dist/gps-Ddzr2KlX.d.ts +54 -0
  45. package/dist/gps-compass-cubes-C-6JEnpR.d.ts +22 -0
  46. package/dist/gps-error-handler-VPuNOuf8.d.ts +40 -0
  47. package/dist/gps-event-markers-DpEy2qRd.d.ts +67 -0
  48. package/dist/h3-ref-point-CFhayNSZ.d.ts +59 -0
  49. package/dist/image-capture-2pKjYUS6.d.ts +130 -0
  50. package/dist/index.d.ts +56 -0
  51. package/dist/index.js +61 -0
  52. package/dist/leaflet-map-overlay-CvfQXTye.d.ts +114 -0
  53. package/dist/lerp-utils-87NWjUOD.d.ts +20 -0
  54. package/dist/licensing/community-license-key.d.ts +2 -0
  55. package/dist/licensing/community-license-key.js +21 -0
  56. package/dist/licensing/index.d.ts +2 -0
  57. package/dist/licensing/index.js +2 -0
  58. package/dist/list-formatter-DKQQVLcl.d.ts +14 -0
  59. package/dist/logger-B81iwxx0.d.ts +74 -0
  60. package/dist/map-overlay-DuiZuCTx.d.ts +153 -0
  61. package/dist/null-storage-backend-CsWvQwN8.d.ts +11 -0
  62. package/dist/opfs-storage-ChOzF_Wp.d.ts +181 -0
  63. package/dist/opfs-storage-backend-CVcmfJHN.d.ts +11 -0
  64. package/dist/permission-checker-jO2ziCWC.d.ts +146 -0
  65. package/dist/persistence-middleware-DrptY02i.d.ts +31 -0
  66. package/dist/recorder-slice-fcwAXrsh.d.ts +35 -0
  67. package/dist/recording-coordinator-DzflP07_.d.ts +81 -0
  68. package/dist/recording-options-BYUFX8iU.d.ts +166 -0
  69. package/dist/recording-replayer-oOzPITrd.d.ts +32 -0
  70. package/dist/ref-point-importer-B_wn5ABk.d.ts +62 -0
  71. package/dist/ref-point-loader-Pt1smgHS.d.ts +117 -0
  72. package/dist/ref-points/h3-ref-point.d.ts +2 -0
  73. package/dist/ref-points/h3-ref-point.js +74 -0
  74. package/dist/ref-points/index.d.ts +2 -0
  75. package/dist/ref-points/index.js +2 -0
  76. package/dist/ref-points-slice-tC-Wd6XJ.d.ts +48 -0
  77. package/dist/reference-points-CFWy8_wj.d.ts +68 -0
  78. package/dist/replay-engine-DuX316ae.d.ts +103 -0
  79. package/dist/replay-scene-DtUm6bsr.d.ts +109 -0
  80. package/dist/routing-slice-BlHTM8eh.d.ts +23 -0
  81. package/dist/scene-node-names-DPsaE2z3.d.ts +14 -0
  82. package/dist/sensors/gps-error-handler.d.ts +2 -0
  83. package/dist/sensors/gps-error-handler.js +53 -0
  84. package/dist/sensors/gps.d.ts +2 -0
  85. package/dist/sensors/gps.js +93 -0
  86. package/dist/sensors/index.d.ts +4 -0
  87. package/dist/sensors/index.js +4 -0
  88. package/dist/sensors/permission-checker.d.ts +2 -0
  89. package/dist/sensors/permission-checker.js +397 -0
  90. package/dist/state/app-selectors.d.ts +2 -0
  91. package/dist/state/app-selectors.js +35 -0
  92. package/dist/state/index.d.ts +17 -0
  93. package/dist/state/index.js +13 -0
  94. package/dist/state/persistence-middleware.d.ts +2 -0
  95. package/dist/state/persistence-middleware.js +71 -0
  96. package/dist/state/recorder-slice.d.ts +2 -0
  97. package/dist/state/recorder-slice.js +47 -0
  98. package/dist/state/recording-coordinator.d.ts +2 -0
  99. package/dist/state/recording-coordinator.js +150 -0
  100. package/dist/state/recording-options.d.ts +2 -0
  101. package/dist/state/recording-options.js +192 -0
  102. package/dist/state/recording-replayer.d.ts +2 -0
  103. package/dist/state/recording-replayer.js +39 -0
  104. package/dist/state/ref-points-slice.d.ts +2 -0
  105. package/dist/state/ref-points-slice.js +44 -0
  106. package/dist/state/replay-engine.d.ts +2 -0
  107. package/dist/state/replay-engine.js +230 -0
  108. package/dist/state/routing-slice.d.ts +2 -0
  109. package/dist/state/routing-slice.js +13 -0
  110. package/dist/state/store-subscribers.d.ts +3 -0
  111. package/dist/state/store-subscribers.js +97 -0
  112. package/dist/state/store.d.ts +9 -0
  113. package/dist/state/store.js +71 -0
  114. package/dist/state/subscribe-to-selector.d.ts +2 -0
  115. package/dist/state/subscribe-to-selector.js +26 -0
  116. package/dist/storage/file-system-utils.d.ts +2 -0
  117. package/dist/storage/file-system-utils.js +31 -0
  118. package/dist/storage/file-system.d.ts +2 -0
  119. package/dist/storage/file-system.js +229 -0
  120. package/dist/storage/index.d.ts +11 -0
  121. package/dist/storage/index.js +10 -0
  122. package/dist/storage/null-storage-backend.d.ts +2 -0
  123. package/dist/storage/null-storage-backend.js +8 -0
  124. package/dist/storage/opfs-storage-backend.d.ts +2 -0
  125. package/dist/storage/opfs-storage-backend.js +15 -0
  126. package/dist/storage/opfs-storage.d.ts +2 -0
  127. package/dist/storage/opfs-storage.js +242 -0
  128. package/dist/storage/ref-point-importer.d.ts +2 -0
  129. package/dist/storage/ref-point-importer.js +163 -0
  130. package/dist/storage/ref-point-loader.d.ts +2 -0
  131. package/dist/storage/ref-point-loader.js +248 -0
  132. package/dist/storage/ref-point-recovery.d.ts +28 -0
  133. package/dist/storage/ref-point-recovery.js +159 -0
  134. package/dist/storage/storage-backend.d.ts +2 -0
  135. package/dist/storage/storage-backend.js +1 -0
  136. package/dist/storage/zip-export.d.ts +2 -0
  137. package/dist/storage/zip-export.js +214 -0
  138. package/dist/storage/zip-reader.d.ts +2 -0
  139. package/dist/storage/zip-reader.js +190 -0
  140. package/dist/storage-backend-BcEItnFr.d.ts +20 -0
  141. package/dist/store-C7PKOj8S.d.ts +96 -0
  142. package/dist/store-subscribers-CuoIzB5T.d.ts +77 -0
  143. package/dist/subscribe-to-selector-UTZ0KkAc.d.ts +26 -0
  144. package/dist/test-utils/browser-mocks.d.ts +294 -0
  145. package/dist/test-utils/browser-mocks.js +568 -0
  146. package/dist/test-utils/zip-round-trip-helpers.d.ts +60 -0
  147. package/dist/test-utils/zip-round-trip-helpers.js +207 -0
  148. package/dist/three-dispose-CCBHjE_a.d.ts +30 -0
  149. package/dist/tracking-state-B9QfuZCg.d.ts +101 -0
  150. package/dist/types/ar-types.d.ts +2 -0
  151. package/dist/types/ar-types.js +1 -0
  152. package/dist/types/geo-types.d.ts +2 -0
  153. package/dist/types/geo-types.js +1 -0
  154. package/dist/types/index.d.ts +3 -0
  155. package/dist/types/index.js +1 -0
  156. package/dist/utils/concurrency.d.ts +2 -0
  157. package/dist/utils/concurrency.js +40 -0
  158. package/dist/utils/failure-tracker.d.ts +2 -0
  159. package/dist/utils/failure-tracker.js +48 -0
  160. package/dist/utils/format-file-size.d.ts +2 -0
  161. package/dist/utils/format-file-size.js +41 -0
  162. package/dist/utils/fused-path.d.ts +2 -0
  163. package/dist/utils/fused-path.js +44 -0
  164. package/dist/utils/index.d.ts +7 -0
  165. package/dist/utils/index.js +7 -0
  166. package/dist/utils/list-formatter.d.ts +2 -0
  167. package/dist/utils/list-formatter.js +17 -0
  168. package/dist/utils/logger.d.ts +2 -0
  169. package/dist/utils/logger.js +226 -0
  170. package/dist/vis-colors-Qi2vlRGt.d.ts +63 -0
  171. package/dist/visualization/alignment-lerper.d.ts +2 -0
  172. package/dist/visualization/alignment-lerper.js +68 -0
  173. package/dist/visualization/camera-follower.d.ts +2 -0
  174. package/dist/visualization/camera-follower.js +51 -0
  175. package/dist/visualization/css3d-renderer-manager.d.ts +2 -0
  176. package/dist/visualization/css3d-renderer-manager.js +41 -0
  177. package/dist/visualization/gps-compass-cubes.d.ts +2 -0
  178. package/dist/visualization/gps-compass-cubes.js +129 -0
  179. package/dist/visualization/gps-event-markers.d.ts +2 -0
  180. package/dist/visualization/gps-event-markers.js +159 -0
  181. package/dist/visualization/index.d.ts +12 -0
  182. package/dist/visualization/index.js +12 -0
  183. package/dist/visualization/leaflet-map-overlay.d.ts +2 -0
  184. package/dist/visualization/leaflet-map-overlay.js +313 -0
  185. package/dist/visualization/lerp-utils.d.ts +2 -0
  186. package/dist/visualization/lerp-utils.js +22 -0
  187. package/dist/visualization/map-overlay.d.ts +2 -0
  188. package/dist/visualization/map-overlay.js +241 -0
  189. package/dist/visualization/reference-points.d.ts +2 -0
  190. package/dist/visualization/reference-points.js +160 -0
  191. package/dist/visualization/three-dispose.d.ts +2 -0
  192. package/dist/visualization/three-dispose.js +55 -0
  193. package/dist/visualization/vis-colors.d.ts +2 -0
  194. package/dist/visualization/vis-colors.js +74 -0
  195. package/dist/webxr-session-COlSrXdL.d.ts +316 -0
  196. package/dist/xr-camera-texture-BbukNE79.d.ts +53 -0
  197. package/dist/xr-error-handler-DTHfmvrl.d.ts +24 -0
  198. package/dist/zip-export-Rtpi75JJ.d.ts +87 -0
  199. package/dist/zip-reader-D7pkpX8K.d.ts +97 -0
  200. package/package.json +104 -0
@@ -0,0 +1,159 @@
1
+ import { createLogger } from "../utils/logger.js";
2
+ import { disposeMeshArray } from "./three-dispose.js";
3
+ import { getArWorldGroup, getScene } from "../ar/webxr-session.js";
4
+ import { VIS_COLORS } from "./vis-colors.js";
5
+ import * as THREE from "three";
6
+ //#region ../src/visualization/gps-event-markers.ts
7
+ /**
8
+ * GPS Event Markers Visualizer
9
+ *
10
+ * Creates and manages Three.js meshes for visualizing GPS events
11
+ * in the 3D AR scene. Shows two types of markers:
12
+ * - Raw GPS markers (yellow): Where GPS readings were received — added to scene root
13
+ * - Fused markers (cyan): AR odometry positions — added to arWorldGroup so that
14
+ * scene-graph propagation (arWorldGroup.matrix × odomPos) handles alignment
15
+ *
16
+ * ARCHITECTURE NOTE:
17
+ * - Raw GPS markers are in scene root (GPS world space), fixed forever
18
+ * - Fused markers are children of arWorldGroup with position = raw odom coords;
19
+ * when applyAlignmentMatrix() updates arWorldGroup.matrix, all fused markers'
20
+ * world positions update automatically via Three.js scene-graph propagation.
21
+ */
22
+ const log = createLogger("GpsEventVisualizer");
23
+ /** Sphere radius in meters (8cm - smaller than reference point markers) */
24
+ const GPS_MARKER_RADIUS = .08;
25
+ /** Slightly larger radius for alignment snapshots to stand out */
26
+ const SNAPSHOT_MARKER_RADIUS = .1;
27
+ /**
28
+ * Manager for GPS event visualization
29
+ */
30
+ var GpsEventVisualizer = class {
31
+ rawGpsMarkers = [];
32
+ fusedMarkers = [];
33
+ snapshotMarkers = [];
34
+ zeroRef = null;
35
+ eventCounter = 0;
36
+ snapshotCounter = 0;
37
+ /**
38
+ * Set the GPS zero reference (origin for coordinate conversion).
39
+ * Must be called before adding GPS events.
40
+ *
41
+ * @param zero - GPS coordinates of the origin
42
+ */
43
+ setZeroRef(zero) {
44
+ this.zeroRef = zero;
45
+ }
46
+ /**
47
+ * Get the current zero reference
48
+ */
49
+ getZeroRef() {
50
+ return this.zeroRef;
51
+ }
52
+ /**
53
+ * Add a GPS event to the visualization.
54
+ * Creates both a raw GPS marker and a fused alignment marker.
55
+ *
56
+ * @param gpsCoords - GPS position as [x, y, z] meters from zero reference
57
+ * @param odomPosition - AR odometry position at the time of GPS reading
58
+ */
59
+ addGpsEvent(gpsCoords, odomPosition) {
60
+ if (!this.zeroRef) {
61
+ log.warn("No zero reference set");
62
+ return;
63
+ }
64
+ const scene = getScene();
65
+ if (!scene) {
66
+ log.warn("Scene not available");
67
+ return;
68
+ }
69
+ const eventId = this.eventCounter++;
70
+ const rawMesh = this.createMarkerMesh(VIS_COLORS.RAW_GPS.hex, "raw-gps", eventId);
71
+ rawMesh.position.set(gpsCoords[0], gpsCoords[1], gpsCoords[2]);
72
+ scene.add(rawMesh);
73
+ this.rawGpsMarkers.push(rawMesh);
74
+ const arWorldGroup = getArWorldGroup();
75
+ if (!arWorldGroup) {
76
+ log.warn("arWorldGroup not available, skipping fused marker");
77
+ return;
78
+ }
79
+ const fusedMesh = this.createMarkerMesh(VIS_COLORS.FUSED_VIO.hex, "fused", eventId);
80
+ fusedMesh.position.set(odomPosition[0], odomPosition[1], odomPosition[2]);
81
+ arWorldGroup.add(fusedMesh);
82
+ this.fusedMarkers.push(fusedMesh);
83
+ log.debug(`Added GPS event ${eventId}: raw=[${gpsCoords.join(",")}] odom=[${odomPosition.join(",")}]`);
84
+ }
85
+ /**
86
+ * Add an alignment snapshot marker at the given NUE position.
87
+ * Snapshots represent the system's best GPS estimate at each alignment update.
88
+ * Added to scene root (GPS world space), not arWorldGroup.
89
+ */
90
+ addAlignmentSnapshot(nuePosition) {
91
+ const scene = getScene();
92
+ if (!scene) {
93
+ log.warn("Scene not available for alignment snapshot");
94
+ return;
95
+ }
96
+ const id = this.snapshotCounter++;
97
+ const mesh = this.createMarkerMesh(VIS_COLORS.ALIGNMENT_SNAPSHOT.hex, "alignment-snapshot", id, SNAPSHOT_MARKER_RADIUS, .5);
98
+ mesh.position.set(nuePosition[0], nuePosition[1], nuePosition[2]);
99
+ scene.add(mesh);
100
+ this.snapshotMarkers.push(mesh);
101
+ log.debug(`Added alignment snapshot ${id}: pos=[${nuePosition.join(",")}]`);
102
+ }
103
+ /**
104
+ * Get the NUE positions of all alignment snapshot markers.
105
+ * Used at session end to convert to GPS coordinates for the summary map.
106
+ */
107
+ getAlignmentSnapshotPositions() {
108
+ return this.snapshotMarkers.map((m) => [
109
+ m.position.x,
110
+ m.position.y,
111
+ m.position.z
112
+ ]);
113
+ }
114
+ /**
115
+ * Create a sphere marker mesh with the given color and name.
116
+ */
117
+ createMarkerMesh(color, namePrefix, eventId, radius = GPS_MARKER_RADIUS, opacity = .3) {
118
+ const geometry = new THREE.SphereGeometry(radius, 12, 12);
119
+ const material = new THREE.MeshBasicMaterial({
120
+ color,
121
+ transparent: true,
122
+ opacity,
123
+ depthWrite: false
124
+ });
125
+ const mesh = new THREE.Mesh(geometry, material);
126
+ mesh.name = `${namePrefix}-${eventId}`;
127
+ return mesh;
128
+ }
129
+ /**
130
+ * Clear all markers from the scene and reset state.
131
+ */
132
+ clearAll() {
133
+ const scene = getScene();
134
+ const arWorldGroup = getArWorldGroup();
135
+ disposeMeshArray(this.rawGpsMarkers, scene);
136
+ disposeMeshArray(this.fusedMarkers, arWorldGroup);
137
+ disposeMeshArray(this.snapshotMarkers, scene);
138
+ this.zeroRef = null;
139
+ this.eventCounter = 0;
140
+ this.snapshotCounter = 0;
141
+ }
142
+ /**
143
+ * Get count of visible markers.
144
+ */
145
+ getCounts() {
146
+ return {
147
+ raw: this.rawGpsMarkers.length,
148
+ fused: this.fusedMarkers.length,
149
+ snapshots: this.snapshotMarkers.length
150
+ };
151
+ }
152
+ };
153
+ /**
154
+ * Singleton instance for global use.
155
+ * Import this to visualize GPS events.
156
+ */
157
+ const gpsEventVisualizer = new GpsEventVisualizer();
158
+ //#endregion
159
+ export { GpsEventVisualizer, gpsEventVisualizer };
@@ -0,0 +1,12 @@
1
+ import { n as createCameraFollower, t as CameraFollower } from "../camera-follower-BMqPddxx.js";
2
+ import { n as createAlignmentLerper, t as AlignmentLerper } from "../alignment-lerper-D9BeDwZX.js";
3
+ import { n as createCss3dRendererManager, t as Css3dRendererManager } from "../css3d-renderer-manager-rgLMVAvd.js";
4
+ import { i as createGpsCompassCubes, n as COMPASS_CUBE_SIZE, r as GpsCompassCubes, t as COMPASS_CUBE_DISTANCE } from "../gps-compass-cubes-C-6JEnpR.js";
5
+ import { n as gpsEventVisualizer, t as GpsEventVisualizer } from "../gps-event-markers-DpEy2qRd.js";
6
+ import { a as DEFAULT_Z_OFFSET, n as DEFAULT_LEAFLET_MAP_SIZE_PX, o as LeafletMapOverlay, r as DEFAULT_WORLD_SIZE, s as LeafletMapOverlayOptions } from "../leaflet-map-overlay-CvfQXTye.js";
7
+ import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-87NWjUOD.js";
8
+ import { a as MapOverlayOptions, c as tileXYToLatLon, i as MapOverlay, n as DEFAULT_MAP_SIZE, o as TextureLoaderInterface, r as DEFAULT_ZOOM, s as latLonToTileXY, t as DEFAULT_HEIGHT_OFFSET } from "../map-overlay-DuiZuCTx.js";
9
+ import { n as refPointVisualizer, t as RefPointVisualizer } from "../reference-points-CFWy8_wj.js";
10
+ import { n as disposeMeshArray, r as disposeObject3D, t as DisposeOptions } from "../three-dispose-CCBHjE_a.js";
11
+ import { t as VIS_COLORS } from "../vis-colors-Qi2vlRGt.js";
12
+ export { type AlignmentLerper, COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, type CameraFollower, type Css3dRendererManager, DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_LERP_RATE, DEFAULT_MAP_SIZE, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, type DisposeOptions, type GpsCompassCubes, GpsEventVisualizer, LeafletMapOverlay, type LeafletMapOverlayOptions, MapOverlay, type MapOverlayOptions, RefPointVisualizer, type TextureLoaderInterface, VIS_COLORS, clampedAlpha, createAlignmentLerper, createCameraFollower, createCss3dRendererManager, createGpsCompassCubes, disposeMeshArray, disposeObject3D, gpsEventVisualizer, latLonToTileXY, refPointVisualizer, tileXYToLatLon };
@@ -0,0 +1,12 @@
1
+ import { disposeMeshArray, disposeObject3D } from "./three-dispose.js";
2
+ import { createCss3dRendererManager } from "./css3d-renderer-manager.js";
3
+ import { DEFAULT_LERP_RATE, clampedAlpha } from "./lerp-utils.js";
4
+ import { createCameraFollower } from "./camera-follower.js";
5
+ import { createAlignmentLerper } from "./alignment-lerper.js";
6
+ import { VIS_COLORS } from "./vis-colors.js";
7
+ import { COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, createGpsCompassCubes } from "./gps-compass-cubes.js";
8
+ import { GpsEventVisualizer, gpsEventVisualizer } from "./gps-event-markers.js";
9
+ import { DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_WORLD_SIZE, DEFAULT_Z_OFFSET, LeafletMapOverlay } from "./leaflet-map-overlay.js";
10
+ import { DEFAULT_HEIGHT_OFFSET, DEFAULT_MAP_SIZE, DEFAULT_ZOOM, MapOverlay, latLonToTileXY, tileXYToLatLon } from "./map-overlay.js";
11
+ import { RefPointVisualizer, refPointVisualizer } from "./reference-points.js";
12
+ export { COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_LERP_RATE, DEFAULT_MAP_SIZE, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, GpsEventVisualizer, LeafletMapOverlay, MapOverlay, RefPointVisualizer, VIS_COLORS, clampedAlpha, createAlignmentLerper, createCameraFollower, createCss3dRendererManager, createGpsCompassCubes, disposeMeshArray, disposeObject3D, gpsEventVisualizer, latLonToTileXY, refPointVisualizer, tileXYToLatLon };
@@ -0,0 +1,2 @@
1
+ import { a as DEFAULT_Z_OFFSET, i as DEFAULT_ZOOM, n as DEFAULT_LEAFLET_MAP_SIZE_PX, o as LeafletMapOverlay, r as DEFAULT_WORLD_SIZE, s as LeafletMapOverlayOptions, t as DEFAULT_HEIGHT_OFFSET } from "../leaflet-map-overlay-CvfQXTye.js";
2
+ export { DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, LeafletMapOverlay, LeafletMapOverlayOptions };
@@ -0,0 +1,313 @@
1
+ import { createLogger } from "../utils/logger.js";
2
+ import { VIS_COLORS } from "./vis-colors.js";
3
+ import { CSS3DObject } from "three/addons/renderers/CSS3DRenderer.js";
4
+ import L from "leaflet";
5
+ //#region ../src/visualization/leaflet-map-overlay.ts
6
+ const log = createLogger("LeafletMapOverlay");
7
+ /** Default pixel size of the Leaflet map container */
8
+ const DEFAULT_LEAFLET_MAP_SIZE_PX = 600;
9
+ /** Default world-space size in meters (matches old MapOverlay) */
10
+ const DEFAULT_WORLD_SIZE = 10;
11
+ /** Default height offset below camera (negative = below) */
12
+ const DEFAULT_HEIGHT_OFFSET = -4;
13
+ /** Default forward offset from parent (negative = forward in parent-local Z) */
14
+ const DEFAULT_Z_OFFSET = -1;
15
+ /** Default zoom level for the Leaflet map */
16
+ const DEFAULT_ZOOM = 17;
17
+ /** Minimum allowed zoom level */
18
+ const MIN_ZOOM = 0;
19
+ /** Maximum allowed zoom level */
20
+ const MAX_ZOOM = 19;
21
+ var LeafletMapOverlay = class {
22
+ scene;
23
+ camera;
24
+ mapParent;
25
+ worldSize;
26
+ heightOffset;
27
+ mapSizePx;
28
+ tileServerUrl;
29
+ onTileError;
30
+ offscreenRoot;
31
+ zoomLevel;
32
+ gpsPosition = null;
33
+ visible = false;
34
+ mapContainer = null;
35
+ leafletMap = null;
36
+ tileLayer = null;
37
+ cssObject = null;
38
+ rawGpsPoints = [];
39
+ fusedPoints = [];
40
+ snapshotPoints = [];
41
+ refPoints = [];
42
+ userMarker = null;
43
+ rawGpsPolyline = null;
44
+ fusedPolyline = null;
45
+ snapshotPolyline = null;
46
+ constructor(scene, camera, options = {}) {
47
+ this.scene = scene;
48
+ this.camera = camera;
49
+ this.mapParent = options.mapParent ?? camera;
50
+ this.worldSize = options.worldSize ?? 10;
51
+ this.heightOffset = options.heightOffset ?? -4;
52
+ this.mapSizePx = options.mapSizePx ?? 600;
53
+ this.zoomLevel = options.zoomLevel ?? 17;
54
+ this.tileServerUrl = options.tileServerUrl ?? "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
55
+ this.onTileError = options.onTileError;
56
+ this.offscreenRoot = options.offscreenRoot ?? document.body;
57
+ }
58
+ setGpsPosition(lat, lon) {
59
+ this.gpsPosition = {
60
+ lat,
61
+ lon
62
+ };
63
+ if (this.leafletMap) {
64
+ this.leafletMap.setView([lat, lon], this.zoomLevel);
65
+ this.updateUserMarker();
66
+ }
67
+ }
68
+ getGpsPosition() {
69
+ return this.gpsPosition;
70
+ }
71
+ show() {
72
+ if (!this.gpsPosition) {
73
+ log.warn("Cannot show map — no GPS position set");
74
+ return;
75
+ }
76
+ if (this.visible) return;
77
+ this.createLeafletMap();
78
+ this.createCssObject();
79
+ this.applyBufferedOverlays();
80
+ this.visible = true;
81
+ log.info("Leaflet map overlay shown");
82
+ }
83
+ hide() {
84
+ if (!this.visible) return;
85
+ this.removeCssObject();
86
+ this.visible = false;
87
+ log.info("Leaflet map overlay hidden");
88
+ }
89
+ toggle() {
90
+ if (this.visible) this.hide();
91
+ else this.show();
92
+ }
93
+ isVisible() {
94
+ return this.visible;
95
+ }
96
+ addRawGpsPoint(lat, lon) {
97
+ this.rawGpsPoints.push([lat, lon]);
98
+ if (this.leafletMap) {
99
+ if (!this.rawGpsPolyline) this.rawGpsPolyline = L.polyline([], {
100
+ color: VIS_COLORS.RAW_GPS.css,
101
+ weight: 3,
102
+ opacity: .8
103
+ }).addTo(this.leafletMap);
104
+ this.rawGpsPolyline.addLatLng([lat, lon]);
105
+ }
106
+ }
107
+ addFusedPoint(lat, lon) {
108
+ this.fusedPoints.push([lat, lon]);
109
+ if (this.leafletMap) {
110
+ if (!this.fusedPolyline) this.fusedPolyline = L.polyline([], {
111
+ color: VIS_COLORS.FUSED_VIO.css,
112
+ weight: 3,
113
+ opacity: .8
114
+ }).addTo(this.leafletMap);
115
+ this.fusedPolyline.addLatLng([lat, lon]);
116
+ }
117
+ }
118
+ addAlignmentSnapshot(lat, lon) {
119
+ this.snapshotPoints.push([lat, lon]);
120
+ if (this.leafletMap) {
121
+ if (!this.snapshotPolyline) this.snapshotPolyline = L.polyline([], {
122
+ color: VIS_COLORS.ALIGNMENT_SNAPSHOT.css,
123
+ weight: 3,
124
+ opacity: .8
125
+ }).addTo(this.leafletMap);
126
+ this.snapshotPolyline.addLatLng([lat, lon]);
127
+ }
128
+ }
129
+ addRefPoint(lat, lon, name) {
130
+ const marker = this.leafletMap ? this.createRefPointMarker(lat, lon, name, false) : null;
131
+ this.refPoints.push({
132
+ lat,
133
+ lng: lon,
134
+ name,
135
+ isPrior: false,
136
+ marker
137
+ });
138
+ }
139
+ addPriorRefPoint(lat, lon, name) {
140
+ const marker = this.leafletMap ? this.createRefPointMarker(lat, lon, name, true) : null;
141
+ this.refPoints.push({
142
+ lat,
143
+ lng: lon,
144
+ name,
145
+ isPrior: true,
146
+ marker
147
+ });
148
+ }
149
+ addPriorRefPoints(refPoints) {
150
+ for (const rp of refPoints) this.addPriorRefPoint(rp.lat, rp.lon, rp.name);
151
+ }
152
+ clearPriorRefPoints() {
153
+ this.refPoints = this.refPoints.filter((rp) => {
154
+ if (rp.isPrior) {
155
+ rp.marker?.remove();
156
+ return false;
157
+ }
158
+ return true;
159
+ });
160
+ }
161
+ setZoomLevel(zoom) {
162
+ this.zoomLevel = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom));
163
+ if (this.leafletMap) this.leafletMap.setZoom(this.zoomLevel);
164
+ }
165
+ getZoomLevel() {
166
+ return this.zoomLevel;
167
+ }
168
+ /** Increment zoom level by 1 (clamped at MAX_ZOOM). */
169
+ zoomIn() {
170
+ this.setZoomLevel(this.zoomLevel + 1);
171
+ }
172
+ /** Decrement zoom level by 1 (clamped at MIN_ZOOM). */
173
+ zoomOut() {
174
+ this.setZoomLevel(this.zoomLevel - 1);
175
+ }
176
+ getWorldSize() {
177
+ return this.worldSize;
178
+ }
179
+ getHeightOffset() {
180
+ return this.heightOffset;
181
+ }
182
+ getMapSizePx() {
183
+ return this.mapSizePx;
184
+ }
185
+ /** Expose the Leaflet map instance for testing and advanced usage. */
186
+ getLeafletMap() {
187
+ return this.leafletMap;
188
+ }
189
+ /**
190
+ * No-op — kept for backward compatibility with the frame-loop call
191
+ * in main.ts. The CSS3DObject is a child of the parent, so Three.js
192
+ * scene graph propagation handles positioning automatically.
193
+ */
194
+ updatePosition() {}
195
+ dispose() {
196
+ this.hide();
197
+ this.destroyLeafletMap();
198
+ this.rawGpsPoints = [];
199
+ this.fusedPoints = [];
200
+ this.snapshotPoints = [];
201
+ this.refPoints = [];
202
+ this.cssObject = null;
203
+ log.info("Leaflet map overlay disposed");
204
+ }
205
+ createLeafletMap() {
206
+ if (this.leafletMap) return;
207
+ this.mapContainer = document.createElement("div");
208
+ this.mapContainer.style.width = `${this.mapSizePx}px`;
209
+ this.mapContainer.style.height = `${this.mapSizePx}px`;
210
+ this.mapContainer.style.background = "white";
211
+ this.mapContainer.style.position = "fixed";
212
+ this.mapContainer.style.left = "-9999px";
213
+ this.mapContainer.style.top = "-9999px";
214
+ this.mapContainer.style.pointerEvents = "none";
215
+ this.offscreenRoot.appendChild(this.mapContainer);
216
+ const pos = this.gpsPosition;
217
+ this.leafletMap = L.map(this.mapContainer, {
218
+ center: [pos.lat, pos.lon],
219
+ zoom: this.zoomLevel,
220
+ zoomControl: false,
221
+ attributionControl: false
222
+ });
223
+ this.tileLayer = L.tileLayer(this.tileServerUrl, { maxZoom: MAX_ZOOM });
224
+ this.tileLayer.on("tileerror", (e) => {
225
+ log.error("Failed to load map tile:", e.error);
226
+ this.onTileError?.(e.error);
227
+ });
228
+ this.tileLayer.addTo(this.leafletMap);
229
+ }
230
+ destroyLeafletMap() {
231
+ this.userMarker?.remove();
232
+ this.userMarker = null;
233
+ this.rawGpsPolyline?.remove();
234
+ this.rawGpsPolyline = null;
235
+ this.fusedPolyline?.remove();
236
+ this.fusedPolyline = null;
237
+ this.snapshotPolyline?.remove();
238
+ this.snapshotPolyline = null;
239
+ for (const rp of this.refPoints) {
240
+ rp.marker?.remove();
241
+ rp.marker = null;
242
+ }
243
+ if (this.leafletMap) {
244
+ this.leafletMap.remove();
245
+ this.leafletMap = null;
246
+ }
247
+ if (this.mapContainer?.parentElement) this.mapContainer.parentElement.removeChild(this.mapContainer);
248
+ this.mapContainer = null;
249
+ this.tileLayer = null;
250
+ }
251
+ createCssObject() {
252
+ if (!this.mapContainer) return;
253
+ if (this.cssObject) {
254
+ this.mapParent.add(this.cssObject);
255
+ return;
256
+ }
257
+ this.mapContainer.style.position = "";
258
+ this.mapContainer.style.left = "";
259
+ this.mapContainer.style.top = "";
260
+ this.cssObject = new CSS3DObject(this.mapContainer);
261
+ const scale = this.worldSize / this.mapSizePx;
262
+ this.cssObject.scale.set(scale, scale, scale);
263
+ this.cssObject.position.set(0, this.heightOffset, -1);
264
+ this.cssObject.rotation.x = -Math.PI / 2;
265
+ this.mapParent.add(this.cssObject);
266
+ }
267
+ removeCssObject() {
268
+ if (this.cssObject) this.mapParent.remove(this.cssObject);
269
+ }
270
+ applyBufferedOverlays() {
271
+ if (!this.leafletMap) return;
272
+ this.updateUserMarker();
273
+ if (this.rawGpsPoints.length > 0) this.rawGpsPolyline = L.polyline(this.rawGpsPoints, {
274
+ color: VIS_COLORS.RAW_GPS.css,
275
+ weight: 3,
276
+ opacity: .8
277
+ }).addTo(this.leafletMap);
278
+ if (this.fusedPoints.length > 0) this.fusedPolyline = L.polyline(this.fusedPoints, {
279
+ color: VIS_COLORS.FUSED_VIO.css,
280
+ weight: 3,
281
+ opacity: .8
282
+ }).addTo(this.leafletMap);
283
+ if (this.snapshotPoints.length > 0) this.snapshotPolyline = L.polyline(this.snapshotPoints, {
284
+ color: VIS_COLORS.ALIGNMENT_SNAPSHOT.css,
285
+ weight: 3,
286
+ opacity: .8
287
+ }).addTo(this.leafletMap);
288
+ for (const rp of this.refPoints) if (!rp.marker) rp.marker = this.createRefPointMarker(rp.lat, rp.lng, rp.name, rp.isPrior);
289
+ }
290
+ updateUserMarker() {
291
+ if (!this.gpsPosition || !this.leafletMap) return;
292
+ if (this.userMarker) this.userMarker.setLatLng([this.gpsPosition.lat, this.gpsPosition.lon]);
293
+ else this.userMarker = L.marker([this.gpsPosition.lat, this.gpsPosition.lon], { icon: L.divIcon({
294
+ className: "",
295
+ html: `<div style="background:${VIS_COLORS.USER_POSITION.css};width:14px;height:14px;border-radius:50%;border:3px solid white;box-shadow:0 0 6px rgba(59,130,246,0.6);"></div>`,
296
+ iconSize: [14, 14],
297
+ iconAnchor: [7, 7]
298
+ }) }).addTo(this.leafletMap);
299
+ }
300
+ createRefPointMarker(lat, lon, name, isPrior) {
301
+ const color = isPrior ? VIS_COLORS.PRIOR_REF_POINT.css : VIS_COLORS.CURRENT_REF_POINT.css;
302
+ const opacity = isPrior ? "opacity:0.8;" : "";
303
+ const label = isPrior ? `📌 ${name} (prior)` : name;
304
+ return L.marker([lat, lon], { icon: L.divIcon({
305
+ className: "",
306
+ html: `<div style="background:${color};width:12px;height:12px;border-radius:50%;border:2px solid white;${opacity}"></div>`,
307
+ iconSize: [12, 12],
308
+ iconAnchor: [6, 6]
309
+ }) }).bindPopup(label).addTo(this.leafletMap);
310
+ }
311
+ };
312
+ //#endregion
313
+ export { DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, LeafletMapOverlay };
@@ -0,0 +1,2 @@
1
+ import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-87NWjUOD.js";
2
+ export { DEFAULT_LERP_RATE, clampedAlpha };
@@ -0,0 +1,22 @@
1
+ //#region ../src/visualization/lerp-utils.ts
2
+ /**
3
+ * Shared lerp utilities for visualization modules.
4
+ *
5
+ * Both alignment-lerper and camera-follower need the same smoothing
6
+ * rate constant and clamped-alpha formula. Centralised here (R3) to
7
+ * keep the two modules in sync.
8
+ */
9
+ /** Default speed multiplier — ~90 % convergence in ~0.3 s at 60 fps. */
10
+ const DEFAULT_LERP_RATE = 8;
11
+ /**
12
+ * Compute a frame-rate-independent lerp/slerp factor clamped to [0, 1].
13
+ *
14
+ * @param lerpRate Speed multiplier (higher = faster convergence).
15
+ * @param dt Delta time in seconds since last frame.
16
+ * @returns The interpolation alpha, guaranteed ≤ 1.0.
17
+ */
18
+ function clampedAlpha(lerpRate, dt) {
19
+ return Math.min(lerpRate * dt, 1);
20
+ }
21
+ //#endregion
22
+ export { DEFAULT_LERP_RATE, clampedAlpha };
@@ -0,0 +1,2 @@
1
+ import { a as MapOverlayOptions, c as tileXYToLatLon, i as MapOverlay, n as DEFAULT_MAP_SIZE, o as TextureLoaderInterface, r as DEFAULT_ZOOM, s as latLonToTileXY, t as DEFAULT_HEIGHT_OFFSET } from "../map-overlay-DuiZuCTx.js";
2
+ export { DEFAULT_HEIGHT_OFFSET, DEFAULT_MAP_SIZE, DEFAULT_ZOOM, MapOverlay, MapOverlayOptions, TextureLoaderInterface, latLonToTileXY, tileXYToLatLon };