gps-plus-slam-js 1.4.0 → 1.6.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/index.d.ts CHANGED
@@ -133,6 +133,27 @@ interface RawDeviceOrientation {
133
133
  /** Whether alpha is relative to magnetic north. */
134
134
  absolute: boolean;
135
135
  }
136
+ /**
137
+ * Raw `AbsoluteOrientationSensor` (Generic Sensor API) reading — an
138
+ * Earth-referenced (magnetic ENU) device orientation, captured per GPS event as
139
+ * a GPS-independent north reference. See
140
+ * GpsPlusSlamJs_Docs/docs/2026-06-25-absolute-orientation-sensor-plan.md §5.
141
+ *
142
+ * Unlike {@link RawDeviceOrientation} (whose `absolute` flag is `false` on most
143
+ * Android browsers), this quaternion is magnetometer-fused and meaningfully
144
+ * absolute. Stored verbatim — magnetic→true correction (WMM declination) and the
145
+ * AR→north composition happen offline/at-consumption, not here.
146
+ */
147
+ interface RawAbsoluteOrientation {
148
+ /** [x,y,z,w] quaternion mapping device-frame → Earth ENU (+X East, +Y (magnetic) North, +Z Up). */
149
+ quaternion: Quaternion;
150
+ /** Reference frame the quaternion is expressed in. We capture the raw `'device'` frame. */
151
+ referenceFrame: 'device' | 'screen';
152
+ /** `screen.orientation.angle` at sample time — needed to reconstruct the `'device'` frame. */
153
+ screenAngleDeg: number;
154
+ /** Sensor reading time (epoch ms) — lets magnetometer warm-up be detected offline. */
155
+ sampleTimestamp: number;
156
+ }
136
157
  /**
137
158
  * Convert Euler angles from W3C DeviceOrientationEvent to a Quaternion.
138
159
  * Rotation order: ZXY intrinsic (per W3C DeviceOrientation spec §3.1).
@@ -145,6 +166,41 @@ interface RawDeviceOrientation {
145
166
  */
146
167
  declare const eulerToQuaternion: (alpha: number, beta: number, gamma: number) => Quaternion;
147
168
  //#endregion
169
+ //#region ../src/state/models/compass-trust.d.ts
170
+ /**
171
+ * Phase 4 Stage A — magnetometer consistency-trust state machine
172
+ * (CLOSED / INTERNAL ONLY).
173
+ *
174
+ * A pure, deterministic reducer that earns (or withholds) trust in the absolute
175
+ * compass by comparing it against the **GPS-only** alignment yaw over time. It
176
+ * exists to feed the *steady-state* Stage B/C use of the compass (detection /
177
+ * soft-prior correction) — it is built in the same iteration as Stage 0 but is
178
+ * **deliberately orthogonal to the Stage-0 cold-start handover**, which stays
179
+ * GPS-intrinsic and never consults trust (plan §7b "the circularity trap").
180
+ *
181
+ * The cardinal property (plan §4c item 9, §10): a **consistently-biased**
182
+ * magnetometer must NEVER reach "trusted" once GPS yaw is observable — its
183
+ * disagreement keeps it out of the trusted state, and a sustained disagreement
184
+ * raises the figure-8 recalibration recommendation instead.
185
+ *
186
+ * Trust ordering (plan §7b Stage A):
187
+ * - Before GPS yaw is observable there is nothing trustworthy to validate
188
+ * against ⇒ the machine is `dormant` (Stage 0's unconditional override holds).
189
+ * - Once observable, agreement within tolerance for a sustained streak ⇒
190
+ * `trusted`; a later large disagreement drops it back to `untrusted`.
191
+ *
192
+ * See the colocated `.md` sidecar for the API, invariants and test strategy.
193
+ */
194
+ type TrustState = 'dormant' | 'untrusted' | 'trusted';
195
+ /** Serializable trust memory (survives Redux round-trips). */
196
+ interface TrustMemory {
197
+ readonly state: TrustState;
198
+ readonly agreeStreak: number;
199
+ readonly disagreeStreak: number;
200
+ /** Derived per-step: surface the figure-8 prompt (observable + sustained disagreement). */
201
+ readonly recommendRecalibration: boolean;
202
+ }
203
+ //#endregion
148
204
  //#region ../src/state/models/gpsEvents.d.ts
149
205
  /**
150
206
  * Plain object representing GPS events state.
@@ -166,6 +222,36 @@ interface GpsEventsState {
166
222
  gpsAccuracyMedian: number | null;
167
223
  gpsAccuracyMean: number | null;
168
224
  currentGpsPosGeoHash: string | null;
225
+ /**
226
+ * Odometry position + GPS timestamp of the last sample admitted into the
227
+ * stored history (Proposal B distance-gating). Null until the first sample
228
+ * and after any rebuild that empties the history. Always reflects the last
229
+ * *stored* sample (the only current reason to skip storing is gating itself);
230
+ * the incremental path reads it to gate the next sample, and the batch path
231
+ * recomputes it from the stored arrays — which is why both origin-jump
232
+ * handlers (which rebuild via the batch path) reset it for free. Kept
233
+ * serializable (plain tuple) so it survives Redux round-trips. Only
234
+ * meaningful when `useDistanceGating` is on.
235
+ */
236
+ lastAdmittedOdomPos: Vector3 | null;
237
+ lastAdmittedTs: number | null;
238
+ /**
239
+ * Phase-4 Stage 0 (only present when `useCompassColdStartOverride` is on):
240
+ * ring buffer of the last N GPS-only solved yaw bearings (deg) feeding the
241
+ * intrinsic observability gate, and the last applied override bearing driving
242
+ * the snap-correction across incremental calls. **Absent** when the override is
243
+ * off ⇒ byte-identical state shape for every existing consumer. Reset on
244
+ * origin-jump rebuilds (the batch path rebuilds the window from prefixes).
245
+ */
246
+ coldStartYawWindowDeg?: number[];
247
+ coldStartAppliedBearingDeg?: number | null;
248
+ /**
249
+ * Phase-4 Stage C (only present when `useCompassRotationPrior` is on): the
250
+ * compass consistency-trust memory, updated each observation from the windowed
251
+ * compass-vs-GPS-only-yaw agreement (gated on observability). Absent otherwise
252
+ * ⇒ byte-identical state shape. Reset to dormant on origin-jump rebuilds.
253
+ */
254
+ compassTrust?: TrustMemory;
169
255
  }
170
256
  //#endregion
171
257
  //#region ../src/state/types.d.ts
@@ -221,6 +307,13 @@ interface GpsPoint extends RawGpsPoint {
221
307
  coordinates: Vector3;
222
308
  readonly weight: number;
223
309
  deviceRotation?: Quaternion;
310
+ /**
311
+ * Raw AbsoluteOrientationSensor reading captured with this GPS event — the
312
+ * GPS-independent (magnetic ENU) device orientation. Paired 1:1 with the
313
+ * event's `odomRotation`, so the offline AR→north composition is exact.
314
+ * `undefined` on recordings/devices without the sensor (most non-Chrome-Android).
315
+ */
316
+ absoluteOrientation?: RawAbsoluteOrientation;
224
317
  }
225
318
  interface GpsMarker {
226
319
  id: string;
@@ -312,6 +405,16 @@ interface GpsModel {
312
405
  zero: LatLong;
313
406
  gpsEvents: GpsEventsType;
314
407
  odometryPath: OdometryPath;
408
+ /**
409
+ * Runtime opt-in for the Phase-4 Stage-0 cold-start compass yaw override
410
+ * (closed/internal alignment feature). Set via `setColdStartOverrideEnabled`
411
+ * — must be dispatched **after** `setZeroPos` (state is null before it). When
412
+ * truthy the reducer threads `{ useCompassColdStartOverride: true }` into the
413
+ * solve; absent/false ⇒ byte-identical to today. A debug/experiment flag —
414
+ * keep OFF until the §6a field matrix re-tunes the thresholds. See
415
+ * GpsPlusSlamJs_Docs/docs/2026-06-26-absolute-orientation-sensor-phase4-stage0-followup.md.
416
+ */
417
+ coldStartOverrideEnabled?: boolean;
315
418
  }
316
419
  interface GpsSlamState {
317
420
  gpsData: GpsModel | null;
@@ -323,6 +426,12 @@ interface RecordGpsEventPayload {
323
426
  odomRotation: Quaternion;
324
427
  rawGpsPoint: RawGpsPoint;
325
428
  rawDeviceOrientation?: RawDeviceOrientation;
429
+ /**
430
+ * Raw AbsoluteOrientationSensor reading at GPS-event time (Phase 1 capture).
431
+ * Optional ⇒ old recordings remain valid untouched; the field is simply absent
432
+ * on devices/platforms without the sensor.
433
+ */
434
+ rawAbsoluteOrientation?: RawAbsoluteOrientation;
326
435
  }
327
436
  interface OdometryTrackingRestartedPayload {
328
437
  lastValidOdomPos: Vector3;
@@ -429,6 +538,7 @@ declare const recordGpsEvent: _$_reduxjs_toolkit0.ActionCreatorWithPayload<Recor
429
538
  declare const odometryTrackingRestarted: _$_reduxjs_toolkit0.ActionCreatorWithPayload<OdometryTrackingRestartedPayload, "gpsData/odometryTrackingRestarted">;
430
539
  declare const arLoopClosureDetected: _$_reduxjs_toolkit0.ActionCreatorWithPayload<ArLoopClosureDetectedPayload, "gpsData/arLoopClosureDetected">;
431
540
  declare const add2dImage: _$_reduxjs_toolkit0.ActionCreatorWithPayload<ArImageCapture, "gpsData/add2dImage">;
541
+ declare const setColdStartOverrideEnabled: _$_reduxjs_toolkit0.ActionCreatorWithPayload<boolean, "gpsData/setColdStartOverrideEnabled">;
432
542
  declare const gpsDataReducer: (state: GpsModel | null | undefined, action: _$redux.UnknownAction) => GpsModel | null;
433
543
  //#endregion
434
544
  //#region ../src/state/gpsElementsSlice.d.ts
@@ -495,6 +605,106 @@ declare const getOpenStreetMapLink: (coord: LatLong, zoomLevel?: number) => stri
495
605
  */
496
606
  declare const fusedGpsFromOdom: (alignmentMatrix: Matrix4, odomPosition: Vector3, zeroRef: LatLong) => LatLongAlt;
497
607
  //#endregion
608
+ //#region ../src/math/magnetic-declination.d.ts
609
+ /**
610
+ * Pure, dependency-free World Magnetic Model 2025 (WMM2025) magnetic-declination
611
+ * synthesis.
612
+ *
613
+ * Sign convention (WMM): declination D is the angle of the horizontal magnetic
614
+ * field measured clockwise (EAST) from geographic (true) north, EAST-positive.
615
+ * To convert a compass (magnetic) heading to a true heading:
616
+ *
617
+ * trueHeading = normalize(magneticHeading + D)
618
+ *
619
+ * Example: a magnetic heading of 90 deg at a location with D = +5 deg (5 deg
620
+ * EAST) corresponds to a true heading of 95 deg.
621
+ *
622
+ * The Gauss coefficients below are the official WMM2025 model (epoch 2025.0,
623
+ * valid 2025.0-2030.0), transcribed verbatim from the NOAA-distributed
624
+ * WMM.COF (header "2025.0 WMM-2025 11/13/2024"). Source mirror:
625
+ * https://github.com/boxpet/pygeomag (pygeomag/wmm/WMM_2025.COF)
626
+ * Acceptance oracle (official NOAA test values):
627
+ * https://www.ncei.noaa.gov/sites/default/files/2025-02/WMM2025testvalues.pdf
628
+ *
629
+ * The synthesis follows the standard WMM technical-report algorithm: decimal
630
+ * year -> time-adjusted Gauss coefficients -> geodetic-to-geocentric mapping
631
+ * (WGS-84) -> Schmidt semi-normalized associated Legendre functions ->
632
+ * spherical-harmonic field components (X north, Y east, Z down) ->
633
+ * D = atan2(Y, X).
634
+ */
635
+ /** Model epoch (decimal year) of WMM2025. */
636
+ declare const WMM2025_EPOCH = 2025;
637
+ /** Validity window of WMM2025 (decimal years), inclusive lower / exclusive upper. */
638
+ declare const WMM2025_VALID_FROM = 2025;
639
+ declare const WMM2025_VALID_TO = 2030;
640
+ /**
641
+ * Magnetic declination in degrees, EAST-positive (WMM convention).
642
+ * D = atan2(Y, X) where X is geodetic-north and Y is geodetic-east field.
643
+ *
644
+ * @param latDeg geodetic latitude in degrees (-90..90)
645
+ * @param lonDeg geodetic longitude in degrees (-180..180)
646
+ * @param opts.altitudeKm height above WGS-84 ellipsoid in km (default 0)
647
+ * @param opts.date Date or epoch-millis; defaults to a fixed in-model decimal year
648
+ * @returns declination in degrees, or NaN if inputs are non-finite.
649
+ */
650
+ declare function magneticDeclinationDeg(latDeg: number, lonDeg: number, opts?: {
651
+ altitudeKm?: number;
652
+ date?: Date | number;
653
+ }): number;
654
+ /**
655
+ * Convert a magnetic heading to a true heading:
656
+ * trueHeading = normalize(magneticDeg + D)
657
+ * where D is the magnetic declination (EAST-positive). Result is in [0, 360).
658
+ */
659
+ declare function magneticToTrueHeadingDeg(magneticDeg: number, latDeg: number, lonDeg: number, opts?: {
660
+ altitudeKm?: number;
661
+ date?: Date | number;
662
+ }): number;
663
+ //#endregion
664
+ //#region ../src/math/orientation-heading.d.ts
665
+ /**
666
+ * Magnetic heading in degrees (0 = North, 90 = East, clockwise) from a
667
+ * device→ENU quaternion, derived by rotating the device camera-forward (−Z)
668
+ * into ENU and taking its horizontal bearing.
669
+ *
670
+ * Returns `null` when the camera points within ~5° of straight up/down, where
671
+ * the horizontal projection is too small for a stable bearing (the v3 guard).
672
+ *
673
+ * This is an *indicative* read-out (the exact forward axis depends on how the
674
+ * phone is held); the rigorous AR→north comparison is {@link arNorthBearingDeg}.
675
+ */
676
+ declare function magneticHeadingFromEnuQuat(q: Quaternion): number | null;
677
+ /**
678
+ * The composed AR→ENU rotation: maps a vector expressed in the AR (WebXR)
679
+ * frame into the magnetic ENU frame, using **only** the sensor reading and the
680
+ * AR pose — never GPS.
681
+ *
682
+ * q(AR→ENU) = q(device→ENU)_sensor ∘ q(device→AR)⁻¹_arPose
683
+ *
684
+ * This is the GPS-independent estimate of the alignment's own rotation (plan §3).
685
+ * Both inputs ride in the same recorded GPS event, so pairing is exact.
686
+ */
687
+ declare function arToEnuRotation(qSensorDeviceToEnu: Quaternion, qArPoseDeviceToAr: Quaternion): Quaternion;
688
+ /**
689
+ * Magnetic bearing (deg, 0 = North, 90 = East, clockwise) that the AR frame's
690
+ * north axis (−Z) points toward, computed independently of GPS from the sensor
691
+ * quaternion + the AR pose. This is the "AR→north" yaw the Phase-2 harness
692
+ * compares against the GPS-derived alignment matrix's yaw (plan §3, §4c kernel 4).
693
+ *
694
+ * Returns `null` if the AR-north axis maps near-vertical in ENU (degenerate,
695
+ * e.g. a physically impossible pose); horizontal otherwise.
696
+ *
697
+ * NOTE: this is a **magnetic** bearing. Correct to true north via the WMM
698
+ * declination module before comparing against a geographic-ENU alignment.
699
+ */
700
+ declare function arNorthBearingDeg(qSensorDeviceToEnu: Quaternion, qArPoseDeviceToAr: Quaternion): number | null;
701
+ /**
702
+ * Signed smallest-magnitude difference between two bearings, in (−180, 180].
703
+ * Positive = `a` is clockwise (east) of `b`. Useful for the AR→north vs
704
+ * alignment-yaw discrepancy (plan §3) and the Phase-4 trust comparisons.
705
+ */
706
+ declare function bearingDeltaDeg(a: number, b: number): number;
707
+ //#endregion
498
708
  //#region ../src/state/selectors.d.ts
499
709
  /** Returns the 4×4 alignment matrix, or null if not yet computed. */
500
710
  declare const getAlignmentMatrix: (state: GpsSlamState) => Matrix4 | null;
@@ -534,4 +744,4 @@ declare function validateLicenseKey(key: string): LicenseValidationResult;
534
744
  //#region ../src/index.d.ts
535
745
  declare const LIB_VERSION = "1.0.0";
536
746
  //#endregion
537
- export { type Add2dImagePayload, type ArElementsState, type ArImageCapture, type ArLoopClosureDetectedPayload, type AreaPolygon, type CreateGpsSlamStoreOptions, type DetectedArPlane, type EventArea, type FloorDetection, type GpsElementsState, type GpsLine, type GpsMarker, type GpsModel, type GpsPoint, type GpsSlamDispatch, type GpsSlamState, type GpsSlamStore, type HeatArea, type HeatMapTile, IDENTITY_MATRIX4, IDENTITY_QUATERNION, LIB_VERSION, type LatLong, type LatLongAlt, type LicenseValidationResult, type Matrix4, type OdometryPath, type OdometryTrackingRestartedPayload, type Quaternion, type RawDeviceOrientation, type RawGpsPoint, type RecordGpsEventPayload, type RootState, type Vector3, type Vector4, ZERO_VECTOR3, add2dImage, addArea, addCornerToEventArea, addHeatMapArea, addLine, addMarker, addOrUpdateArPlane, addToHeatMaps, anchorEventAreaInWorldSpace, arElementsReducer, arLoopClosureDetected, calcGeoHash, calcGpsCoords, calcQuadKey, calcRelativeCoordsInMeters, cloneMatrix4, cloneQuaternion, cloneVector3, correctArDriftForEventArea, createGpsSlamStore, distanceInMeters, distanceInMetersRelative, enuQuaternionToNUE, eulerToQuaternion, finishEventArea, fromMatrix4, fromQuaternion, fromVector3, fusedGpsFromOdom, geoHashToLatLong, getAlignmentMatrix, getAlignmentRotation, getGoogleMapsDirectionsLink, getGoogleMapsLink, getGpsAccuracyStats, getGpsPositions, getOdometryPositions, getOdometryRotations, getOpenStreetMapLink, getZeroReference, gpsDataReducer, gpsElementsReducer, invertQuaternion, isIdentityMatrix4, isIdentityQuaternion, isNearIdentityQuaternion, multiplyQuaternions, normalizeQuaternion, nueQuaternionToENU, nueQuaternionToWebXR, nueToWebXR, odometryTrackingRestarted, quadKeyToLatLong, quaternionMagnitude, quaternionsEquivalent, recordGpsEvent, recordPhoneHeight, resetArElements, resetGpsElements, sanitizeForDevTools, setZeroPos, startEventArea, toEarthCenteredCoordinates, toMatrix4, toQuaternion, toVector3, validateLicenseKey, webxrQuaternionToNUE, webxrToNUE };
747
+ export { type Add2dImagePayload, type ArElementsState, type ArImageCapture, type ArLoopClosureDetectedPayload, type AreaPolygon, type CreateGpsSlamStoreOptions, type DetectedArPlane, type EventArea, type FloorDetection, type GpsElementsState, type GpsLine, type GpsMarker, type GpsModel, type GpsPoint, type GpsSlamDispatch, type GpsSlamState, type GpsSlamStore, type HeatArea, type HeatMapTile, IDENTITY_MATRIX4, IDENTITY_QUATERNION, LIB_VERSION, type LatLong, type LatLongAlt, type LicenseValidationResult, type Matrix4, type OdometryPath, type OdometryTrackingRestartedPayload, type Quaternion, type RawAbsoluteOrientation, type RawDeviceOrientation, type RawGpsPoint, type RecordGpsEventPayload, type RootState, type Vector3, type Vector4, WMM2025_EPOCH, WMM2025_VALID_FROM, WMM2025_VALID_TO, ZERO_VECTOR3, add2dImage, addArea, addCornerToEventArea, addHeatMapArea, addLine, addMarker, addOrUpdateArPlane, addToHeatMaps, anchorEventAreaInWorldSpace, arElementsReducer, arLoopClosureDetected, arNorthBearingDeg, arToEnuRotation, bearingDeltaDeg, calcGeoHash, calcGpsCoords, calcQuadKey, calcRelativeCoordsInMeters, cloneMatrix4, cloneQuaternion, cloneVector3, correctArDriftForEventArea, createGpsSlamStore, distanceInMeters, distanceInMetersRelative, enuQuaternionToNUE, eulerToQuaternion, finishEventArea, fromMatrix4, fromQuaternion, fromVector3, fusedGpsFromOdom, geoHashToLatLong, getAlignmentMatrix, getAlignmentRotation, getGoogleMapsDirectionsLink, getGoogleMapsLink, getGpsAccuracyStats, getGpsPositions, getOdometryPositions, getOdometryRotations, getOpenStreetMapLink, getZeroReference, gpsDataReducer, gpsElementsReducer, invertQuaternion, isIdentityMatrix4, isIdentityQuaternion, isNearIdentityQuaternion, magneticDeclinationDeg, magneticHeadingFromEnuQuat, magneticToTrueHeadingDeg, multiplyQuaternions, normalizeQuaternion, nueQuaternionToENU, nueQuaternionToWebXR, nueToWebXR, odometryTrackingRestarted, quadKeyToLatLong, quaternionMagnitude, quaternionsEquivalent, recordGpsEvent, recordPhoneHeight, resetArElements, resetGpsElements, sanitizeForDevTools, setColdStartOverrideEnabled, setZeroPos, startEventArea, toEarthCenteredCoordinates, toMatrix4, toQuaternion, toVector3, validateLicenseKey, webxrQuaternionToNUE, webxrToNUE };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /*! gps-plus-slam-js | (c) 2026 cs-util-com | UNLICENSED — see EULA.md */
2
- import{configureStore as e,createSlice as t}from"@reduxjs/toolkit";import{ed25519 as n}from"@noble/curves/ed25519.js";import{hexToBytes as r}from"@noble/curves/utils.js";import{mat4 as i,quat as a,vec3 as o,vec4 as s}from"gl-matrix";import{castDraft as c}from"immer";let l=!1;function u(){l=!0}function d(){if(!l)throw Error(`gps-plus-slam-js: license not activated. Construct your store via createRecorderStore() from gps-plus-slam-app-framework, or pass a valid licenseKey to createGpsSlamStore(). See EULA §3.`)}function f(e){return((...t)=>(d(),e(...t)))}function p(e){let t=((...t)=>(d(),e(...t)));return Object.assign(t,e),t.toString=()=>e.type,t}function m(e){return(t,n)=>(d(),e(t,n))}function h(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=`=`.repeat((4-t.length%4)%4),r=atob(t+n);return Uint8Array.from(r,e=>e.charCodeAt(0))}function g(e){let t=new Date,i=e.indexOf(`.`);if(i<=0||i>=e.length-1)throw Error(`Invalid license key format: expected "payload.signature" with base64url-encoded parts.`);let a,o;try{a=h(e.substring(0,i)),o=h(e.substring(i+1))}catch{throw Error(`Invalid license key format: base64url decoding failed.`)}let s=r(`dfe5c62120b7a0ce962b17907a15b27cf1b056e6619bf6ce55e6e094b322a470`);if(!n.verify(o,a,s))throw Error(`Invalid license key: signature verification failed.`);let c=JSON.parse(new TextDecoder().decode(a));if(typeof c!=`object`||!c)throw Error(`Invalid license key: payload must be a JSON object.`);let{type:l,exp:d}=c;if(l!==`community`)throw Error(`Invalid license key: "type" must be "community".`);if(typeof d!=`number`||!Number.isFinite(d))throw Error(`Invalid license key: "exp" must be a finite number (Unix timestamp in seconds).`);if(d<Math.floor(t.getTime()/1e3)){let e=new Date(d*1e3);throw Error(`License key expired on ${e.toISOString()}. Update to the latest version for a renewed community key.`)}return u(),{type:l,expiresAt:new Date(d*1e3)}}const _=180/Math.PI,v=e=>{let t=e[0],n=e[1],r=e[2],i=e[3],a=2*(i*t+n*r),o=1-2*(t*t+n*n),s=Math.atan2(a,o)*_,c=2*(i*n-r*t),l=Math.abs(c)>=1?Math.sign(c)*90:Math.asin(c)*_,u=2*(i*r+t*n),d=1-2*(n*n+r*r);return{pitch:l,yaw:Math.atan2(u,d)*_,roll:s}},y=1/298.257223563,b=y*(2-y),x=40075016.6856/360,S=39940652.7422/360,ee=Math.PI/180,C=180/Math.PI,w=`0123456789bcdefghjkmnpqrstuvwxyz`,T=[16,8,4,2,1],E=(e,t,n)=>Math.min(Math.max(e,t),n),te=e=>E(e,-180,180),D=e=>e*ee,ne=e=>e*C,re=e=>{if(!Number.isFinite(e))throw RangeError(`Coordinate values must be finite numbers`);return String(e)},ie=e=>({lat:re(e.lat),lon:re(e.lon)}),ae=(e,t=0)=>{let n=D(e.lat),r=D(e.lon),i=Math.sin(n),a=Math.cos(n),s=Math.sin(r),c=Math.cos(r),l=6378137/Math.sqrt(1-b*i*i),u=(l+t)*a*c,d=(l+t)*a*s,f=(l*(1-b)+t)*i;return o.fromValues(u,d,f)},oe=f((e,t)=>{if(t<1||t>23)throw RangeError(`levelOfDetail must be between 1 and 23 (inclusive)`);let n=E(e.lat,-85.05112878,85.05112878),r=te(e.lon),i=Math.sin(D(n)),a=256*2**t,o=(r+180)/360*a,s=(.5-Math.log((1+i)/(1-i))/(4*Math.PI))*a,c=2**t-1,l=E(Math.floor(o/256),0,c),u=E(Math.floor(s/256),0,c),d=``;for(let e=t;e>0;--e){let t=0,n=1<<e-1;(l&n)!==0&&(t+=1),(u&n)!==0&&(t+=2),d+=t.toString()}return d}),se=f(e=>{if(!/^[0-3]+$/.test(e))throw Error(`QuadKey must consist of digits 0-3`);let t=e.length;if(t===0)throw Error(`QuadKey must not be empty`);let n=0,r=0;for(let i=0;i<t;i+=1){let a=Number.parseInt(e[i],10),o=1<<t-i-1;a&1&&(n+=o),a&2&&(r+=o)}let i=256*2**t,a=(n+.5)*256,o=(r+.5)*256,s=a/i,c=o/i,l=s*360-180;return{lat:ne(Math.atan(Math.sinh(Math.PI*(1-2*c)))),lon:l}}),ce=f((e,t)=>{if(t<=0)throw RangeError(`precision must be greater than 0`);let n=-90,r=90,i=-180,a=180,o=``,s=0,c=0,l=!0;for(;o.length<t;){if(l){let t=(i+a)/2;e.lon>=t?(c|=T[s],i=t):a=t}else{let t=(n+r)/2;e.lat>=t?(c|=T[s],n=t):r=t}l=!l,s<4?s+=1:(o+=w[c],s=0,c=0)}return o}),le=f(e=>{if(e.length===0)throw Error(`geoHash must not be empty`);let t=-90,n=90,r=-180,i=180,a=!0;for(let o of e){let e=w.indexOf(o);if(e===-1)throw Error(`Invalid geohash character: ${o}`);for(let o of T){if(a){let t=(r+i)/2;(e&o)===0?i=t:r=t}else{let r=(t+n)/2;(e&o)===0?n=r:t=r}a=!a}}return{lat:(t+n)/2,lon:(r+i)/2}}),ue=f((e,t)=>{let n=D(e.lat),r=D(t.lat),i=r-n,a=D(t.lon-e.lon),o=Math.sin(i/2),s=Math.sin(a/2),c=o*o+Math.cos(n)*Math.cos(r)*s*s,l=Math.min(1,Math.max(0,c));return 6371008.8*(2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l)))}),de=f((e,t)=>{let n=O(e,t);return Math.hypot(n[0],n[2])}),O=f((e,t,n=0,r=0)=>{let i=(t.lon-e.lon)*x*Math.cos(D(e.lat)),a=(t.lat-e.lat)*S,s=n-r;return o.fromValues(a,s,i)}),k=f((e,t)=>{let n=t[0],r=t[2];return{lat:n/S+e.lat,lon:r/(x*Math.cos(D(e.lat)))+e.lon}}),fe=f((e,t=0)=>ae(e,t)),A=e=>{let{lat:t,lon:n}=ie(e);return`${t}%2C${n}`},pe=f(e=>`https://www.google.com/maps/search/?api=1&query=${A(e)}`),me=f((e,t)=>`https://www.google.com/maps/dir/?api=1&origin=${A(t)}&destination=${A(e)}`),he=f((e,t=19)=>{let{lat:n,lon:r}=ie(e);return`https://www.openstreetmap.org/query?lat=${n}&lon=${r}#map=${t}/${n}/${r}`}),ge=f((e,t,n)=>{let r=i.fromValues(...e),a=o.fromValues(t[0],t[1],t[2]),s=o.create();o.transformMat4(s,a,r);let{lat:c,lon:l}=k(n,s);return{lat:c,lon:l,altitude:s[1]}}),_e=()=>({points:[]}),ve=()=>({gpsMarkers:[],gpsLines:[],areas:[],heatMap:{},heatAreas:{}}),j=()=>({arPlanes:{},floorDetections:[],eventAreas:[],currentEventAreaId:null,currentEventAreaPoints:[]}),M=e=>o.fromValues(e[0],e[1],e[2]),N=e=>a.fromValues(e[0],e[1],e[2],e[3]),ye=e=>i.fromValues(...e),P=e=>[e[0],e[1],e[2]],F=e=>[e[0],e[1],e[2],e[3]],I=e=>[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15]],L=e=>[e[0],e[1],e[2]],be=e=>[e[0],e[1],e[2],e[3]],xe=e=>[...e],R=Object.freeze([0,0,0,1]),z=Object.freeze([0,0,0]),B=Object.freeze([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]),V=e=>{let t=Ce(e);if(t===0)return R;let n=1/t;return[e[0]*n,e[1]*n,e[2]*n,e[3]*n]},Se=e=>{for(let t=0;t<16;t++)if(e[t]!==B[t])return!1;return!0},Ce=e=>Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]+e[3]*e[3]),we=e=>e[0]===0&&e[1]===0&&e[2]===0&&e[3]===1,Te=(e,t)=>Math.abs(e[0])<t&&Math.abs(e[1])<t&&Math.abs(e[2])<t&&Math.abs(e[3]-1)<t,Ee=(e,t,n=1e-10)=>{let r=Math.abs(e[0]-t[0])<n&&Math.abs(e[1]-t[1])<n&&Math.abs(e[2]-t[2])<n&&Math.abs(e[3]-t[3])<n,i=Math.abs(e[0]+t[0])<n&&Math.abs(e[1]+t[1])<n&&Math.abs(e[2]+t[2])<n&&Math.abs(e[3]+t[3])<n;return r||i},De=(e,t)=>{let n=a.create();return a.multiply(n,e,t),[n[0],n[1],n[2],n[3]]},Oe=e=>{let t=a.create();return a.invert(t,e),[t[0],t[1],t[2],t[3]]},H=e=>[-e[2],e[1],e[0]],ke=e=>[e[2],e[1],-e[0]],U=e=>[-e[2],e[1],e[0],e[3]],Ae=e=>[e[2],e[1],-e[0],e[3]],W=e=>[e[1],e[2],e[0],e[3]],je=e=>[e[2],e[0],e[1],e[3]],G=(e,t,n)=>{if(!Number.isFinite(e)||!Number.isFinite(t)||!Number.isFinite(n))throw Error(`eulerToQuaternion: non-finite input (alpha=${e}, beta=${t}, gamma=${n})`);let r=e*Math.PI/180,i=t*Math.PI/180,o=n*Math.PI/180,s=a.create(),c=a.create(),l=a.create();a.setAxisAngle(s,[0,0,1],r),a.setAxisAngle(c,[1,0,0],i),a.setAxisAngle(l,[0,1,0],o);let u=a.create();return a.multiply(u,s,c),a.multiply(u,u,l),[u[0],u[1],u[2],u[3]]},Me=t({name:`arElements`,initialState:j(),reducers:{recordPhoneHeight:(e,t)=>{e.floorDetections.push(t.payload)},addOrUpdateArPlane:(e,t)=>{let n=t.payload;if(n.parentPlaneId){delete e.arPlanes[n.planeId];return}e.arPlanes[n.planeId]=c(n)},startEventArea:(e,t)=>{e.currentEventAreaId=t.payload.id,e.currentEventAreaPoints=[]},addCornerToEventArea:(e,t)=>{e.currentEventAreaId&&e.currentEventAreaPoints.push(c(L(t.payload.position)))},correctArDriftForEventArea:(e,t)=>{let n=t.payload.drift;for(let t of e.currentEventAreaPoints)t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]},finishEventArea:(e,t)=>{e.currentEventAreaId&&(e.eventAreas.push({id:e.currentEventAreaId,label:t.payload.label,polygon:[],isInArSpace:!0,arPoints:e.currentEventAreaPoints}),e.currentEventAreaId=null,e.currentEventAreaPoints=[])},anchorEventAreaInWorldSpace:(e,t)=>{let{areaId:n,alignmentMatrix:r,zeroRef:i}=t.payload,a=e.eventAreas.findIndex(e=>e.id===n);if(a===-1)return;let s=e.eventAreas[a];if(!s.isInArSpace||!s.arPoints)throw Error(`The area ${s.id} is already anchored in world space`);let c=ye(r),l=s.arPoints.map(e=>{let t=M(e);return k(i,o.transformMat4(o.create(),t,c))});e.eventAreas[a]={...s,isInArSpace:!1,polygon:l,arPoints:void 0}},resetArElements:()=>j()}}),{recordPhoneHeight:Ne,addOrUpdateArPlane:Pe,startEventArea:Fe,addCornerToEventArea:Ie,correctArDriftForEventArea:Le,finishEventArea:Re,anchorEventAreaInWorldSpace:ze,resetArElements:Be}=Me.actions,Ve=p(Ne),He=p(Pe),Ue=p(Fe),We=p(Ie),Ge=p(Le),Ke=p(Re),qe=p(ze),Je=p(Be),Ye=m(Me.reducer);function Xe(e,t,n,r){let{inCentroid:i,refCentroid:a,refVec:s,tmp:c}=r;o.set(i,0,0,0),o.set(a,0,0,0);let l=0;for(let n=0;n<e.length;n++){let r=t[n][3];o.scaleAndAdd(i,i,e[n],r),K(s,t[n]),o.scaleAndAdd(a,a,s,r),l+=r}if(l===0)throw Error(`Weights must not sum to zero when solving Kabsch`);let u=1/l;if(o.scale(i,i,u),o.scale(a,a,u),!n)return{inCentroid:i,refCentroid:a,scaleRatio:1};let d=0,f=0;for(let n=0;n<e.length;n++)o.subtract(c,e[n],i),d+=o.length(c),K(s,t[n]),o.subtract(c,s,a),f+=o.length(c);return{inCentroid:i,refCentroid:a,scaleRatio:d===0?1:f/d}}function Ze(e,t,n,r,a,s,c){let{negCentroid:l,scaleVec:u}=c;return i.fromRotationTranslation(e,r,n),s&&(o.set(u,a,a,a),i.scale(e,e,u)),o.negate(l,t),i.translate(e,e,l),e}function Qe(e,t,n={}){let r=e.length;if(r!==t.length)throw Error(`Length of the point lists was not equal: ${r} vs ${t.length}`);if(r===0)return i.create();let s=n.solveRotation??!0,c=n.solveScale??!1,l=n.ignoreYAxisForRotation??!1,u=n.rotationIterations??9,{inCentroid:d,refCentroid:f,scaleRatio:p}=Xe(e,t,c,{inCentroid:o.create(),refCentroid:o.create(),refVec:o.create(),tmp:o.create()}),m=a.create();s?new $e(l).solve(e,t,d,f,m,u):a.identity(m);let h={negCentroid:o.create(),scaleVec:o.create()};return Ze(i.create(),d,f,m,p,c,h)}var $e=class e{ignoreYAxis;static twoPi=Math.PI*2;static basisX=o.fromValues(1,0,0);static basisY=o.fromValues(0,1,0);static basisZ=o.fromValues(0,0,1);constructor(e){this.ignoreYAxis=e}solve(t,n,r,i,o,s){let c=this.transposeMultSubtract(t,n,r,i);if(this.ignoreYAxis){let t=c[0][0],n=c[0][2],r=c[2][0],i=c[2][2],s=Math.atan2(r-n,t+i);a.setAxisAngle(o,e.basisY,s)}else this.extractRotation(c,o,s)}transposeMultSubtract(e,t,n,r){let i=[o.create(),o.create(),o.create()],a=o.clone(n),s=o.clone(r);this.ignoreYAxis&&(a[1]=0,s[1]=0);let c=o.create(),l=o.create(),u=o.create();for(let n=0;n<e.length;n++){o.copy(c,e[n]),K(u,t[n]),this.ignoreYAxis&&(c[1]=0,u[1]=0);let r=t[n][3];o.subtract(c,c,a),o.scale(c,c,r),o.subtract(l,u,s),i[0][0]+=c[0]*l[0],i[1][0]+=c[1]*l[0],i[2][0]+=c[2]*l[0],i[0][1]+=c[0]*l[1],i[1][1]+=c[1]*l[1],i[2][1]+=c[2]*l[1],i[0][2]+=c[0]*l[2],i[1][2]+=c[1]*l[2],i[2][2]+=c[2]*l[2]}return i}extractRotation(t,n,r){let i=[o.create(),o.create(),o.create()],s=o.create(),c=o.create(),l=o.create();for(let u=0;u<r;u++){this.fillMatrixFromQuaternion(n,i),o.cross(s,i[0],t[0]),o.cross(l,i[1],t[1]),o.add(s,s,l),o.cross(l,i[2],t[2]),o.add(s,s,l);let r=o.dot(i[0],t[0])+o.dot(i[1],t[1])+o.dot(i[2],t[2])+1e-9;r=Math.abs(r),o.scale(s,s,1/r);let u=o.length(s);if(u<1e-9)break;o.scale(c,s,1/u);let d=u%e.twoPi,f=a.create();a.setAxisAngle(f,c,d),a.multiply(n,f,n),a.normalize(n,n)}}fillMatrixFromQuaternion(t,n){o.transformQuat(n[0],e.basisX,t),o.transformQuat(n[1],e.basisY,t),o.transformQuat(n[2],e.basisZ,t)}};const K=(e,t)=>(e[0]=t[0],e[1]=t[1],e[2]=t[2],e);function et(e,t,n,r,i,a,o=Math.random){let s=Array.from(e);if(n>s.length)throw RangeError(`minSampleSize must be smaller than the number of elements: minSampleSize=${n}, elements=${s.length}`);return rt(s,tt(s,t,n,r,i,a,o),i,a)}function tt(e,t,n,r,i,a,o){let s=null,c=Array(n),l=new Uint8Array(e.length);for(let u=0;u<r;u+=1){it(e,n,o,c,l);let{inliers:r,outliers:u}=nt(e,l,i(c),a);if(s===null||n+r.length>=t){let e=[...c,...r],t=i(e),n=q(t,`createModel must assign totalModelError for comparison during RANSAC`);(s===null||n<s.error)&&(t.inliers=e,t.outliers=u,s={model:t,error:n})}}return s?.model??null}function nt(e,t,n,r){let i=[],a=[];for(let o=0;o<e.length;o+=1){if(t?.[o])continue;let s=e[o];(r(n,s)?i:a).push(s)}return{inliers:i,outliers:a}}function rt(e,t,n,r){let i=t??n(e);q(i,`RANSAC failed to produce a model with totalModelError`);let{inliers:a,outliers:o}=nt(e,null,i,r);return a.length>0&&(i=n(a),q(i,`createModel must assign totalModelError for final RANSAC model`)),i.inliers=a,i.outliers=o,i}function q(e,t){let{totalModelError:n}=e;if(n==null)throw Error(t);return n}function it(e,t,n,r,i){i.fill(0);let a=0;for(;a<t;){let t=Math.floor(n()*e.length);i[t]||(i[t]=1,r[a]=e[t],a+=1)}}const at={useOnlyRecentData:!1,recentSeconds:180,includeTimeWeight:!0,weightByTimeFactor:2500,ignoreYAxisForRotation:!0,useRansac:!1,ransacInlierRatio:.95,ransacSampleRatio:.3,ransacMaxIterations:230,ransacErrorTolerance:1,geohashPrecision:8,geohashWindowSize:10,gpsAccuracyExponent:.1,altitudeAlignmentMode:`separate1D`,altitudeAggregator:`mean`,altitudeSampleSet:`all`,gpsVerticalAccuracyExponent:5},ot=e=>e.map(e=>L(e)),st=e=>e.map(e=>V(e)),ct=e=>e.map(Nt),lt=e=>e.map(e=>[e[0],e[1],e[2],e[3]]),J=e=>Array.isArray(e)?e:P(e),Y=e=>Array.isArray(e)?e:F(e),ut=(e,t,n,r)=>({odometryPosOffset:L(J(e)),odometryRotOffset:V(Y(t)),latestLoopClosureFixPointPos:n?L(J(n)):null,latestLoopClosureFixPointRot:r?V(Y(r)):null}),dt=(e,t,n,r)=>({odometryPositions:[],odometryRotations:[],gpsPositions:[],gpsPositionsVec4:[],alignmentMatrix:[...B],alignmentRotation:[...R],alignmentTranslation:[...z],alignmentRotationInDegree:[...z],...ut(e,t,n,r),gpsAccuracyMedian:null,gpsAccuracyMean:null,currentGpsPosGeoHash:null}),ft=()=>dt(z,R,null,null),pt=(e,t,n,r)=>{let i=e.map(e=>J(e)),a=t.map(e=>V(Y(e))),o=n.map(Nt),s=r.gpsAccuracyExponent;for(let e of o)e.weight=X(e.latLongAccuracy,s);let c=o.map(jt),l=r.includeTimeWeight?Dt(c,o,r.weightByTimeFactor):c,u=r.useOnlyRecentData?Tt(o,r.recentSeconds):0,d=i.slice(u).map(M),f=o.slice(u);return{allPositionTuples:i,allRotationTuples:a,allGpsPoints:o,allVec4Tuples:l,solverPositionsTyped:d,solverGpsPoints:f,solverWeightedVec4Tuples:l.slice(u),solverVerticalWeights:Et(f,r)}},mt=e=>{let{odometryPositions:t,odometryRotations:n,gpsPoints:r,odometryPosOffset:i=z,odometryRotOffset:s=R,latestLoopClosureFixPointPos:c=null,latestLoopClosureFixPointRot:l=null,alignmentConfig:u,random:d}=e;if(t.length!==n.length||t.length!==r.length)throw Error(`GpsEvents requires odometry positions, rotations, and gps points to have identical lengths`);let f={...at,...u??{}};if(t.length===0)return dt(i,s,c,l);let{allPositionTuples:p,allRotationTuples:m,allGpsPoints:h,allVec4Tuples:g,solverPositionsTyped:_,solverGpsPoints:v,solverWeightedVec4Tuples:y,solverVerticalWeights:b}=pt(t,n,r,f),x=vt(_,y,b,f,d??Math.random),S=a.create(),ee=o.create(),C=o.create();gt(x.matrix,S,ee,C);let{mean:w,median:T}=kt(h),E=Ot(r,f.geohashPrecision,f.geohashWindowSize);return{odometryPositions:ot(p),odometryRotations:st(m),gpsPositions:ct(h),gpsPositionsVec4:lt(g),alignmentMatrix:I(x.matrix),alignmentRotation:F(S),alignmentTranslation:P(ee),alignmentRotationInDegree:P(C),...ut(i,s,c,l),gpsAccuracyMedian:T,gpsAccuracyMean:w,currentGpsPosGeoHash:E}},X=(e,t)=>e!=null&&e>0?1/Math.max(e,1)**+t:1,ht=(e,t,n,r,i,s)=>{let c=e.odometryPositions,l=e.odometryRotations,u=e.gpsPositions,d=e.gpsPositionsVec4;c.push(J(t)),l.push(V(Y(n)));let f=Nt(r);u.push(f);let p={...at,...i??{}};f.weight=X(f.latLongAccuracy,p.gpsAccuracyExponent);let m=jt(f);if(p.includeTimeWeight){d.push(m);let e=Dt(d,u,p.weightByTimeFactor);for(let t=0;t<e.length;t++)d[t]=e[t]}else d.push(m);let h=0;p.useOnlyRecentData&&(h=Tt(u,p.recentSeconds));let g=vt(c.slice(h).map(M),d.slice(h),Et(u.slice(h),p),p,s??Math.random);e.alignmentMatrix=I(g.matrix);let _=a.create(),v=o.create(),y=o.create();gt(g.matrix,_,v,y),e.alignmentRotation=F(_),e.alignmentTranslation=P(v),e.alignmentRotationInDegree=P(y);let{mean:b,median:x}=kt(u);e.gpsAccuracyMean=b,e.gpsAccuracyMedian=x,e.currentGpsPosGeoHash=Ot(u,p.geohashPrecision,p.geohashWindowSize)},gt=(e,t,n,r)=>{i.getRotation(t,e),a.normalize(t,t),i.getTranslation(n,e),At(t,r)},Z=o.create(),_t=o.create(),vt=(e,t,n,r,a)=>{if(e.length===0)return{matrix:i.create(),meanError:0};let o=e.length,c=[];for(let r=0;r<o;r+=1){let i=t[r];c.push({odom:e[r],ref:s.fromValues(i[0],i[1],i[2],i[3]),verticalWeight:n[r]??1})}let l,u,d;if(r.useRansac&&c.length>=3){let e=c.length,t=Math.max(3,Math.min(e,Math.ceil(e*r.ransacSampleRatio))),n=et(c,Math.max(t,Math.min(e,Math.ceil(e*r.ransacInlierRatio))),t,r.ransacMaxIterations,e=>St(e,r.ignoreYAxisForRotation),(e,t)=>Ct(e,t)<e.meanAlignmentError+r.ransacErrorTolerance,a);l=n.alignmentMatrix,u=n.meanAlignmentError,n.inliers!==void 0&&(d=Array.from(n.inliers))}else{let e=St(c,r.ignoreYAxisForRotation);l=e.alignmentMatrix,u=e.meanAlignmentError}return r.altitudeAlignmentMode===`separate1D`&&yt(l,c,d,r),{matrix:l,meanError:u}},yt=(e,t,n,r)=>{let i=r.altitudeSampleSet===`horizontalInliers`&&n!==void 0&&n.length>0?n:t;if(i.length===0)return;let a=Array(i.length),o=Array(i.length);for(let e=0;e<i.length;e+=1){let t=i[e];a[e]=t.ref[1]-t.odom[1];let n=t.verticalWeight;o[e]=n>0&&Number.isFinite(n)?n:0}e[13]=r.altitudeAggregator===`median`?xt(a,o):bt(a,o)},bt=(e,t)=>{let n=0,r=0;for(let i=0;i<e.length;i+=1)n+=e[i]*t[i],r+=t[i];if(r>0&&Number.isFinite(r))return n/r;let i=0;for(let t=0;t<e.length;t+=1)i+=e[t];return e.length===0?0:i/e.length},xt=(e,t)=>{if(e.length===0)return 0;if(e.length===1)return e[0];let n=e.map((e,t)=>t);n.sort((t,n)=>e[t]-e[n]);let r=0;for(let e=0;e<t.length;e+=1)r+=t[e];if(!(r>0)||!Number.isFinite(r)){let t=n.map(t=>e[t]);return t[Math.floor((t.length-1)/2)]}let i=r/2,a=0;for(let r=0;r<n.length;r+=1)if(a+=t[n[r]],a>=i)return e[n[r]];return e[n[n.length-1]]},St=(e,t)=>{let n=Array.from(e),r=n.length,i=Array(r),a=Array(r);for(let e=0;e<r;e+=1)i[e]=n[e].odom,a[e]=n[e].ref;let s=Qe(i,a,{ignoreYAxisForRotation:t}),c=0;for(let e=0;e<r;e+=1)o.transformMat4(Z,i[e],s),c+=wt(Z,n[e].ref);return{alignmentMatrix:s,meanAlignmentError:r===0?0:c/r,totalModelError:c}},Ct=(e,t)=>(o.transformMat4(Z,t.odom,e.alignmentMatrix),wt(Z,t.ref)),wt=(e,t)=>(o.set(_t,t[0],t[1],t[2]),o.squaredDistance(e,_t)),Tt=(e,t)=>{if(e.length===0||t<=0)return 0;let n=e[e.length-1].timestamp-t*1e3;for(let t=0;t<e.length;t+=1)if(e[t].timestamp>=n)return t;return 0},Et=(e,t)=>{let n=t.gpsVerticalAccuracyExponent,r=e.map(e=>{let t=e.altitudeAccuracy;return X(t!=null&&Number.isFinite(t)&&t>0?t:e.latLongAccuracy,n)});if(!t.includeTimeWeight||e.length<2)return r;let i=e[e.length-1].timestamp,a=e[0].timestamp,o=Math.max(1,i-a),s=t.weightByTimeFactor;return r.map((t,n)=>{if(!(t>0&&Number.isFinite(t)))return 0;let r=s*((i-e[n].timestamp)/o)+1;return 1/(1/t+r)})},Dt=(e,t,n)=>{if(e.length<2)return e.map(e=>[e[0],e[1],e[2],e[3]]);let r=t[t.length-1].timestamp,i=t[0].timestamp,a=Math.max(1,r-i);return e.map((e,i)=>{let o=n*((r-t[i].timestamp)/a)+1,s=t[i].weight;if(!(s>0&&Number.isFinite(s)))return[e[0],e[1],e[2],0];let c=1/(1/s+o);return[e[0],e[1],e[2],c]})},Q=new Map,Ot=(e,t,n)=>{if(e.length===0)return null;let r=Math.max(0,e.length-n);Q.clear();for(let n=r;n<e.length;n+=1){let r=e[n],i=ce(Mt(r),t),a=Q.get(i);a?(a.count+=1,a.index=n):Q.set(i,{count:1,index:n})}let i=null,a=-1,o=-1;for(let[e,{count:t,index:n}]of Q)(t>a||t===a&&n>o)&&(i=e,a=t,o=n);return i},kt=e=>{let t=e.map(e=>e.latLongAccuracy).filter(e=>typeof e==`number`&&Number.isFinite(e));if(t.length===0)return{mean:null,median:null};let n=t.reduce((e,t)=>e+t,0)/t.length,r=t.slice().sort((e,t)=>e-t),i=Math.floor(r.length/2);return{mean:n,median:r.length%2==0?(r[i-1]+r[i])/2:r[i]}},At=(e,t)=>{let n=e[0],r=e[1],i=e[2],a=e[3],s=2*(a*n+r*i),c=1-2*(n*n+r*r),l=Math.atan2(s,c),u=2*(a*r-i*n),d;d=Math.abs(u)>=1?Math.PI/2*Math.sign(u):Math.asin(u);let f=2*(a*i+n*r),p=1-2*(r*r+i*i),m=Math.atan2(f,p),h=180/Math.PI,g=t??o.create();return g[0]=l*h,g[1]=d*h,g[2]=m*h,g},jt=e=>[e.coordinates[0],e.coordinates[1],e.coordinates[2],e.weight>0&&Number.isFinite(e.weight)?e.weight:1],Mt=e=>({lat:e.latitude,lon:e.longitude}),Nt=e=>({...e,zeroRef:{lat:e.zeroRef.lat,lon:e.zeroRef.lon},coordinates:[e.coordinates[0],e.coordinates[1],e.coordinates[2]],timestamp:e.timestamp,deviceRotation:e.deviceRotation?V(Y(e.deviceRotation)):void 0}),Pt=({lat:e,lon:t})=>{if(!Number.isFinite(e))throw Error(`Invalid latitude value: ${e}`);if(!Number.isFinite(t))throw Error(`Invalid longitude value: ${t}`);if(e<-90||e>90)throw Error(`Invalid latitude range: ${e}`);if(t<-180||t>180)throw Error(`Invalid longitude range: ${t}`)},Ft=o.fromValues(1,1,1),It=(e,t)=>[e[0]+t[0],e[1]+t[1],e[2]+t[2]],Lt=(e,t,n)=>{let r=O(t,{lat:e.latitude,lon:e.longitude},e.altitude??0,0),i=n?.alpha!=null&&n?.beta!=null&&n?.gamma!=null?W(G(n.alpha,n.beta,n.gamma)):void 0;return{...e,zeroRef:t,coordinates:P(r),weight:1,deviceRotation:i}},Rt=(e,t,n)=>{if(e)return G(e.alpha,e.beta,e.gamma);if(t)return t;throw Error(`Sensor rotation missing for ${n}: neither raw orientation nor legacy quaternion provided`)},zt=e=>{let t=a.invert(a.create(),e);if(!t)throw Error(`Encountered non-invertible quaternion`);return t},Bt=e=>{let t=zt(a.normalize(a.create(),N(e.lastSensorRot))),n=a.normalize(a.create(),N(e.lastValidOdomRot)),r=a.multiply(a.create(),t,n),i=a.normalize(a.create(),N(e.newSensorRot)),o=a.multiply(a.create(),i,r),s=a.normalize(a.create(),N(e.newOdomRot)),c=a.multiply(a.create(),o,s);return a.normalize(c,c),F(c)},Vt=(e,t)=>{let n=i.create();return i.fromRotationTranslationScale(n,a.normalize(a.create(),N(t)),M(e),Ft),n},Ht=(e,t,n)=>{let r=o.create(),s=o.create(),c=a.create(),l=a.create();i.getTranslation(r,e),i.getTranslation(s,t),i.getRotation(c,e),i.getRotation(l,t);let u=o.create();o.lerp(u,r,s,n);let d=a.create();return a.slerp(d,c,l,n),i.fromRotationTranslation(i.create(),d,u)},Ut=(e,t)=>{if(e.length===0)return[];let n=e[e.length-1],r=i.invert(i.create(),n);if(!r)throw Error(`End pose matrix is not invertible`);let a=i.multiply(i.create(),t,r),o=i.create(),s=e.length-1;return e.map((e,t)=>{let n=Ht(o,a,s<=0?1:t/s);return i.multiply(i.create(),n,e)})},Wt=(e,t,n)=>{for(let r=e.length-1;r>=0;--r)if(n(e[r],t))return r;return-1},Gt=(e,t)=>e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2],Kt=(e,t)=>e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[3]===t[3],qt=t({name:`gpsData`,initialState:null,reducers:{setZeroPos:{reducer:(e,t)=>e===null?{zero:t.payload,gpsEvents:ft(),odometryPath:_e()}:e,prepare:e=>(Pt(e),{payload:e})},recordGpsEvent:(e,t)=>{if(!e)return e;let{odomPosition:n,odomRotation:r,rawGpsPoint:i,rawDeviceOrientation:a}=t.payload,o=Lt(i,e.zero,a);ht(e.gpsEvents,H(n),U(r),o)},odometryTrackingRestarted:(e,t)=>{if(!e)return e;let n=It(e.gpsEvents.odometryPosOffset,H(t.payload.lastValidOdomPos)),r=Rt(t.payload.lastSensorOrientation,t.payload.lastSensorRot,`lastSensor`),i=Rt(t.payload.newSensorOrientation,t.payload.newSensorRot,`newSensor`);e.gpsEvents=c(mt({odometryPositions:[],odometryRotations:[],gpsPoints:[],odometryPosOffset:n,odometryRotOffset:Bt({...t.payload,lastValidOdomRot:U(t.payload.lastValidOdomRot),newOdomRot:U(t.payload.newOdomRot),lastSensorRot:W(r),newSensorRot:W(i)}),latestLoopClosureFixPointPos:null,latestLoopClosureFixPointRot:null}))},arLoopClosureDetected:(e,t)=>{if(!e)return e;let n=e.gpsEvents;if(n.odometryPositions.length===0)return e;let r=n.latestLoopClosureFixPointPos?Wt(n.odometryPositions,n.latestLoopClosureFixPointPos,Gt):0,s=n.latestLoopClosureFixPointRot?Wt(n.odometryRotations,n.latestLoopClosureFixPointRot,Kt):0;if(r<0||s<0)throw Error(`Loop closure fix point could not be located in history`);if(r!==s)throw Error(`Loop closure fix point indices for position and rotation diverged`);let l=n.odometryPositions.slice(0,r).map(e=>L(e)),u=n.odometryRotations.slice(0,r).map(e=>V(e)),d=n.odometryPositions.slice(r).map(e=>L(e)),f=n.odometryRotations.slice(r).map(e=>V(e)),p=d.map((e,t)=>Vt(e,f[t])),m=Vt(H(t.payload.lastPos),V(U(t.payload.lastRot)));p.push(m);let h=Ut(p,Vt(H(t.payload.newPos),V(U(t.payload.newRot)))),g=[],_=[],v=o.create();for(let e=0;e<h.length-1;e+=1){let t=h[e],n=o.create();i.getTranslation(n,t);let r=a.create();if(i.getRotation(r,t),a.normalize(r,r),i.getScaling(v,t),Math.hypot(v[0]-1,v[1]-1,v[2]-1)>.05)throw Error(`Unexpected scale drift encountered during loop closure correction`);g.push(P(n)),_.push(F(r))}e.gpsEvents=c(mt({odometryPositions:l.concat(g),odometryRotations:u.concat(_),gpsPoints:n.gpsPositions,odometryPosOffset:n.odometryPosOffset,odometryRotOffset:n.odometryRotOffset,latestLoopClosureFixPointPos:null,latestLoopClosureFixPointRot:null}))},add2dImage:(e,t)=>{if(!e)return e;e.odometryPath.points.push(c({imageFile:t.payload.imageFile,screenRotation:t.payload.screenRotation,position:H(t.payload.position),rotation:V(U(t.payload.rotation)),capturedAt:t.payload.capturedAt,width:t.payload.width,height:t.payload.height}))}}}),{setZeroPos:Jt,recordGpsEvent:Yt,odometryTrackingRestarted:Xt,arLoopClosureDetected:Zt,add2dImage:Qt}=qt.actions,$t=p(Jt),en=p(Yt),tn=p(Xt),nn=p(Zt),rn=p(Qt),an=m(qt.reducer),on=t({name:`gpsElements`,initialState:ve(),reducers:{addMarker:(e,t)=>{e.gpsMarkers.push(t.payload)},addLine:(e,t)=>{e.gpsLines.push(t.payload)},addArea:(e,t)=>{e.areas.push(t.payload)},addToHeatMaps:(e,t)=>{let{category:n,tiles:r}=t.payload,i=e.heatMap[n]??{};e.heatMap[n]={...i,...r}},addHeatMapArea:(e,t)=>{let n=t.payload,r=n.category;if(e.heatAreas[r]||(e.heatAreas[r]={}),e.heatAreas[r][n.geoHash])throw Error(`HeatArea collision detected for GeoHash: ${n.geoHash}`);e.heatAreas[r][n.geoHash]=n},resetGpsElements:()=>ve()}}),{addMarker:sn,addLine:cn,addArea:ln,addToHeatMaps:un,addHeatMapArea:dn,resetGpsElements:fn}=on.actions,pn=p(sn),mn=p(cn),hn=p(ln),gn=p(un),_n=p(dn),vn=p(fn),yn=m(on.reducer),bn=()=>({gpsData:null,gpsElements:ve(),arElements:j()}),xn=e=>{let t=Array.from({length:Math.min(e.length,4)},(t,n)=>e[n].toFixed(2));e.length>4&&t.push(`…`);let n=`[${t.join(`, `)}]`;if(e.length===4){let{pitch:t,yaw:r,roll:i}=v(e);return`${n} (pitch=${t.toFixed(0)}°, yaw=${r.toFixed(0)}°, roll=${i.toFixed(0)}°)`}return n},Sn=e=>(e.length===3||e.length===4||e.length===16)&&e.every(e=>typeof e==`number`),$=(e,t=0)=>{if(t>10||e==null)return e;if(Array.isArray(e))return Sn(e)?xn(e):e.map(e=>$(e,t+1));if(typeof e==`object`){let n={};for(let[r,i]of Object.entries(e))n[r]=$(i,t+1);return n}return e},Cn=(t={})=>{let{preloadedState:n,enableDevToolsSanitizers:r=!0,enableDevChecks:i=!0,licenseKey:a}=t;if(a==null)throw Error(`License key required. Pass options.licenseKey or use createRecorderStore() from gps-plus-slam-app-framework. See EULA §3.`);g(a);let o=bn(),s=n?{gpsData:n.gpsData??o.gpsData,gpsElements:n.gpsElements??o.gpsElements,arElements:n.arElements??o.arElements}:void 0;return e({reducer:{gpsData:an,gpsElements:yn,arElements:Ye},preloadedState:s,middleware:e=>e({serializableCheck:i,immutableCheck:i}),devTools:r?{actionSanitizer:$,stateSanitizer:$}:!0})},wn=[],Tn=[],En=[],Dn={median:null,mean:null},On=f(function(e){let t=e.gpsData?.gpsEvents;return!t||t.gpsPositions.length===0?null:t.alignmentMatrix}),kn=f(function(e){let t=e.gpsData?.gpsEvents;return!t||t.gpsPositions.length===0?null:t.alignmentRotation}),An=f(function(e){return e.gpsData?.gpsEvents?.odometryPositions??wn}),jn=f(function(e){return e.gpsData?.gpsEvents?.odometryRotations??Tn}),Mn=f(function(e){return e.gpsData?.gpsEvents?.gpsPositions??En}),Nn=f(function(e){return e.gpsData?.zero??null}),Pn=f(function(e){let t=e.gpsData?.gpsEvents?.gpsAccuracyMedian??null,n=e.gpsData?.gpsEvents?.gpsAccuracyMean??null;return t===null&&n===null?Dn:{median:t,mean:n}}),Fn=`1.0.0`;export{B as IDENTITY_MATRIX4,R as IDENTITY_QUATERNION,Fn as LIB_VERSION,z as ZERO_VECTOR3,rn as add2dImage,hn as addArea,We as addCornerToEventArea,_n as addHeatMapArea,mn as addLine,pn as addMarker,He as addOrUpdateArPlane,gn as addToHeatMaps,qe as anchorEventAreaInWorldSpace,Ye as arElementsReducer,nn as arLoopClosureDetected,ce as calcGeoHash,k as calcGpsCoords,oe as calcQuadKey,O as calcRelativeCoordsInMeters,xe as cloneMatrix4,be as cloneQuaternion,L as cloneVector3,Ge as correctArDriftForEventArea,Cn as createGpsSlamStore,ue as distanceInMeters,de as distanceInMetersRelative,W as enuQuaternionToNUE,G as eulerToQuaternion,Ke as finishEventArea,ye as fromMatrix4,N as fromQuaternion,M as fromVector3,ge as fusedGpsFromOdom,le as geoHashToLatLong,On as getAlignmentMatrix,kn as getAlignmentRotation,me as getGoogleMapsDirectionsLink,pe as getGoogleMapsLink,Pn as getGpsAccuracyStats,Mn as getGpsPositions,An as getOdometryPositions,jn as getOdometryRotations,he as getOpenStreetMapLink,Nn as getZeroReference,an as gpsDataReducer,yn as gpsElementsReducer,Oe as invertQuaternion,Se as isIdentityMatrix4,we as isIdentityQuaternion,Te as isNearIdentityQuaternion,De as multiplyQuaternions,V as normalizeQuaternion,je as nueQuaternionToENU,Ae as nueQuaternionToWebXR,ke as nueToWebXR,tn as odometryTrackingRestarted,se as quadKeyToLatLong,Ce as quaternionMagnitude,Ee as quaternionsEquivalent,en as recordGpsEvent,Ve as recordPhoneHeight,Je as resetArElements,vn as resetGpsElements,$ as sanitizeForDevTools,$t as setZeroPos,Ue as startEventArea,fe as toEarthCenteredCoordinates,I as toMatrix4,F as toQuaternion,P as toVector3,g as validateLicenseKey,U as webxrQuaternionToNUE,H as webxrToNUE};
2
+ import{configureStore as e,createSlice as t}from"@reduxjs/toolkit";import{ed25519 as n}from"@noble/curves/ed25519.js";import{hexToBytes as r}from"@noble/curves/utils.js";import{mat4 as i,quat as a,vec3 as o,vec4 as s}from"gl-matrix";import{castDraft as c}from"immer";let l=!1;function u(){l=!0}function d(){if(!l)throw Error(`gps-plus-slam-js: license not activated. Construct your store via createRecorderStore() from gps-plus-slam-app-framework, or pass a valid licenseKey to createGpsSlamStore(). See EULA §3.`)}function f(e){return((...t)=>(d(),e(...t)))}function p(e){let t=((...t)=>(d(),e(...t)));return Object.assign(t,e),t.toString=()=>e.type,t}function m(e){return(t,n)=>(d(),e(t,n))}function h(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=`=`.repeat((4-t.length%4)%4),r=atob(t+n);return Uint8Array.from(r,e=>e.charCodeAt(0))}function g(e){let t=new Date,i=e.indexOf(`.`);if(i<=0||i>=e.length-1)throw Error(`Invalid license key format: expected "payload.signature" with base64url-encoded parts.`);let a,o;try{a=h(e.substring(0,i)),o=h(e.substring(i+1))}catch{throw Error(`Invalid license key format: base64url decoding failed.`)}let s=r(`dfe5c62120b7a0ce962b17907a15b27cf1b056e6619bf6ce55e6e094b322a470`);if(!n.verify(o,a,s))throw Error(`Invalid license key: signature verification failed.`);let c=JSON.parse(new TextDecoder().decode(a));if(typeof c!=`object`||!c)throw Error(`Invalid license key: payload must be a JSON object.`);let{type:l,exp:d}=c;if(l!==`community`)throw Error(`Invalid license key: "type" must be "community".`);if(typeof d!=`number`||!Number.isFinite(d))throw Error(`Invalid license key: "exp" must be a finite number (Unix timestamp in seconds).`);if(d<Math.floor(t.getTime()/1e3)){let e=new Date(d*1e3);throw Error(`License key expired on ${e.toISOString()}. Update to the latest version for a renewed community key.`)}return u(),{type:l,expiresAt:new Date(d*1e3)}}const _=180/Math.PI,v=e=>{let t=e[0],n=e[1],r=e[2],i=e[3],a=2*(i*t+n*r),o=1-2*(t*t+n*n),s=Math.atan2(a,o)*_,c=2*(i*n-r*t),l=Math.abs(c)>=1?Math.sign(c)*90:Math.asin(c)*_,u=2*(i*r+t*n),d=1-2*(n*n+r*r);return{pitch:l,yaw:Math.atan2(u,d)*_,roll:s}},y=1/298.257223563,b=y*(2-y),x=40075016.6856/360,S=39940652.7422/360,C=Math.PI/180,w=180/Math.PI,T=`0123456789bcdefghjkmnpqrstuvwxyz`,E=[16,8,4,2,1],D=(e,t,n)=>Math.min(Math.max(e,t),n),ee=e=>D(e,-180,180),O=e=>e*C,k=e=>e*w,A=e=>{if(!Number.isFinite(e))throw RangeError(`Coordinate values must be finite numbers`);return String(e)},j=e=>({lat:A(e.lat),lon:A(e.lon)}),te=(e,t=0)=>{let n=O(e.lat),r=O(e.lon),i=Math.sin(n),a=Math.cos(n),s=Math.sin(r),c=Math.cos(r),l=6378137/Math.sqrt(1-b*i*i),u=(l+t)*a*c,d=(l+t)*a*s,f=(l*(1-b)+t)*i;return o.fromValues(u,d,f)},ne=f((e,t)=>{if(t<1||t>23)throw RangeError(`levelOfDetail must be between 1 and 23 (inclusive)`);let n=D(e.lat,-85.05112878,85.05112878),r=ee(e.lon),i=Math.sin(O(n)),a=256*2**t,o=(r+180)/360*a,s=(.5-Math.log((1+i)/(1-i))/(4*Math.PI))*a,c=2**t-1,l=D(Math.floor(o/256),0,c),u=D(Math.floor(s/256),0,c),d=``;for(let e=t;e>0;--e){let t=0,n=1<<e-1;(l&n)!==0&&(t+=1),(u&n)!==0&&(t+=2),d+=t.toString()}return d}),re=f(e=>{if(!/^[0-3]+$/.test(e))throw Error(`QuadKey must consist of digits 0-3`);let t=e.length;if(t===0)throw Error(`QuadKey must not be empty`);let n=0,r=0;for(let i=0;i<t;i+=1){let a=Number.parseInt(e[i],10),o=1<<t-i-1;a&1&&(n+=o),a&2&&(r+=o)}let i=256*2**t,a=(n+.5)*256,o=(r+.5)*256,s=a/i,c=o/i,l=s*360-180;return{lat:k(Math.atan(Math.sinh(Math.PI*(1-2*c)))),lon:l}}),ie=f((e,t)=>{if(t<=0)throw RangeError(`precision must be greater than 0`);let n=-90,r=90,i=-180,a=180,o=``,s=0,c=0,l=!0;for(;o.length<t;){if(l){let t=(i+a)/2;e.lon>=t?(c|=E[s],i=t):a=t}else{let t=(n+r)/2;e.lat>=t?(c|=E[s],n=t):r=t}l=!l,s<4?s+=1:(o+=T[c],s=0,c=0)}return o}),ae=f(e=>{if(e.length===0)throw Error(`geoHash must not be empty`);let t=-90,n=90,r=-180,i=180,a=!0;for(let o of e){let e=T.indexOf(o);if(e===-1)throw Error(`Invalid geohash character: ${o}`);for(let o of E){if(a){let t=(r+i)/2;(e&o)===0?i=t:r=t}else{let r=(t+n)/2;(e&o)===0?n=r:t=r}a=!a}}return{lat:(t+n)/2,lon:(r+i)/2}}),oe=f((e,t)=>{let n=O(e.lat),r=O(t.lat),i=r-n,a=O(t.lon-e.lon),o=Math.sin(i/2),s=Math.sin(a/2),c=o*o+Math.cos(n)*Math.cos(r)*s*s,l=Math.min(1,Math.max(0,c));return 6371008.8*(2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l)))}),se=f((e,t)=>{let n=ce(e,t);return Math.hypot(n[0],n[2])}),ce=f((e,t,n=0,r=0)=>{let i=(t.lon-e.lon)*x*Math.cos(O(e.lat)),a=(t.lat-e.lat)*S,s=n-r;return o.fromValues(a,s,i)}),le=f((e,t)=>{let n=t[0],r=t[2];return{lat:n/S+e.lat,lon:r/(x*Math.cos(O(e.lat)))+e.lon}}),ue=f((e,t=0)=>te(e,t)),de=e=>{let{lat:t,lon:n}=j(e);return`${t}%2C${n}`},fe=f(e=>`https://www.google.com/maps/search/?api=1&query=${de(e)}`),pe=f((e,t)=>`https://www.google.com/maps/dir/?api=1&origin=${de(t)}&destination=${de(e)}`),me=f((e,t=19)=>{let{lat:n,lon:r}=j(e);return`https://www.openstreetmap.org/query?lat=${n}&lon=${r}#map=${t}/${n}/${r}`}),he=f((e,t,n)=>{let r=i.fromValues(...e),a=o.fromValues(t[0],t[1],t[2]),s=o.create();o.transformMat4(s,a,r);let{lat:c,lon:l}=le(n,s);return{lat:c,lon:l,altitude:s[1]}}),ge=()=>({points:[]}),_e=()=>({gpsMarkers:[],gpsLines:[],areas:[],heatMap:{},heatAreas:{}}),ve=()=>({arPlanes:{},floorDetections:[],eventAreas:[],currentEventAreaId:null,currentEventAreaPoints:[]}),M=e=>o.fromValues(e[0],e[1],e[2]),N=e=>a.fromValues(e[0],e[1],e[2],e[3]),ye=e=>i.fromValues(...e),P=e=>[e[0],e[1],e[2]],F=e=>[e[0],e[1],e[2],e[3]],I=e=>[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15]],L=e=>[e[0],e[1],e[2]],be=e=>[e[0],e[1],e[2],e[3]],xe=e=>[...e],R=Object.freeze([0,0,0,1]),z=Object.freeze([0,0,0]),Se=Object.freeze([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]),B=e=>{let t=we(e);if(t===0)return R;let n=1/t;return[e[0]*n,e[1]*n,e[2]*n,e[3]*n]},Ce=e=>{for(let t=0;t<16;t++)if(e[t]!==Se[t])return!1;return!0},we=e=>Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]+e[3]*e[3]),Te=e=>e[0]===0&&e[1]===0&&e[2]===0&&e[3]===1,Ee=(e,t)=>Math.abs(e[0])<t&&Math.abs(e[1])<t&&Math.abs(e[2])<t&&Math.abs(e[3]-1)<t,De=(e,t,n=1e-10)=>{let r=Math.abs(e[0]-t[0])<n&&Math.abs(e[1]-t[1])<n&&Math.abs(e[2]-t[2])<n&&Math.abs(e[3]-t[3])<n,i=Math.abs(e[0]+t[0])<n&&Math.abs(e[1]+t[1])<n&&Math.abs(e[2]+t[2])<n&&Math.abs(e[3]+t[3])<n;return r||i},Oe=(e,t)=>{let n=a.create();return a.multiply(n,e,t),[n[0],n[1],n[2],n[3]]},ke=e=>{let t=a.create();return a.invert(t,e),[t[0],t[1],t[2],t[3]]},V=e=>[-e[2],e[1],e[0]],Ae=e=>[e[2],e[1],-e[0]],H=e=>[-e[2],e[1],e[0],e[3]],je=e=>[e[2],e[1],-e[0],e[3]],U=e=>[e[1],e[2],e[0],e[3]],Me=e=>[e[2],e[0],e[1],e[3]],Ne=(e,t,n)=>{if(!Number.isFinite(e)||!Number.isFinite(t)||!Number.isFinite(n))throw Error(`eulerToQuaternion: non-finite input (alpha=${e}, beta=${t}, gamma=${n})`);let r=e*Math.PI/180,i=t*Math.PI/180,o=n*Math.PI/180,s=a.create(),c=a.create(),l=a.create();a.setAxisAngle(s,[0,0,1],r),a.setAxisAngle(c,[1,0,0],i),a.setAxisAngle(l,[0,1,0],o);let u=a.create();return a.multiply(u,s,c),a.multiply(u,u,l),[u[0],u[1],u[2],u[3]]},Pe=t({name:`arElements`,initialState:ve(),reducers:{recordPhoneHeight:(e,t)=>{e.floorDetections.push(t.payload)},addOrUpdateArPlane:(e,t)=>{let n=t.payload;if(n.parentPlaneId){delete e.arPlanes[n.planeId];return}e.arPlanes[n.planeId]=c(n)},startEventArea:(e,t)=>{e.currentEventAreaId=t.payload.id,e.currentEventAreaPoints=[]},addCornerToEventArea:(e,t)=>{e.currentEventAreaId&&e.currentEventAreaPoints.push(c(L(t.payload.position)))},correctArDriftForEventArea:(e,t)=>{let n=t.payload.drift;for(let t of e.currentEventAreaPoints)t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]},finishEventArea:(e,t)=>{e.currentEventAreaId&&(e.eventAreas.push({id:e.currentEventAreaId,label:t.payload.label,polygon:[],isInArSpace:!0,arPoints:e.currentEventAreaPoints}),e.currentEventAreaId=null,e.currentEventAreaPoints=[])},anchorEventAreaInWorldSpace:(e,t)=>{let{areaId:n,alignmentMatrix:r,zeroRef:i}=t.payload,a=e.eventAreas.findIndex(e=>e.id===n);if(a===-1)return;let s=e.eventAreas[a];if(!s.isInArSpace||!s.arPoints)throw Error(`The area ${s.id} is already anchored in world space`);let c=ye(r),l=s.arPoints.map(e=>{let t=M(e);return le(i,o.transformMat4(o.create(),t,c))});e.eventAreas[a]={...s,isInArSpace:!1,polygon:l,arPoints:void 0}},resetArElements:()=>ve()}}),{recordPhoneHeight:Fe,addOrUpdateArPlane:Ie,startEventArea:Le,addCornerToEventArea:Re,correctArDriftForEventArea:ze,finishEventArea:Be,anchorEventAreaInWorldSpace:Ve,resetArElements:He}=Pe.actions,Ue=p(Fe),We=p(Ie),Ge=p(Le),Ke=p(Re),qe=p(ze),Je=p(Be),Ye=p(Ve),Xe=p(He),Ze=m(Pe.reducer);function Qe(e,t,n,r){let{inCentroid:i,refCentroid:a,refVec:s,tmp:c}=r;o.set(i,0,0,0),o.set(a,0,0,0);let l=0;for(let n=0;n<e.length;n++){let r=t[n][3];o.scaleAndAdd(i,i,e[n],r),nt(s,t[n]),o.scaleAndAdd(a,a,s,r),l+=r}if(l===0)throw Error(`Weights must not sum to zero when solving Kabsch`);let u=1/l;if(o.scale(i,i,u),o.scale(a,a,u),!n)return{inCentroid:i,refCentroid:a,scaleRatio:1};let d=0,f=0;for(let n=0;n<e.length;n++)o.subtract(c,e[n],i),d+=o.length(c),nt(s,t[n]),o.subtract(c,s,a),f+=o.length(c);return{inCentroid:i,refCentroid:a,scaleRatio:d===0?1:f/d}}function $e(e,t,n,r,a,s,c){let{negCentroid:l,scaleVec:u}=c;return i.fromRotationTranslation(e,r,n),s&&(o.set(u,a,a,a),i.scale(e,e,u)),o.negate(l,t),i.translate(e,e,l),e}function et(e,t,n={}){let r=e.length;if(r!==t.length)throw Error(`Length of the point lists was not equal: ${r} vs ${t.length}`);if(r===0)return i.create();let s=n.solveRotation??!0,c=n.solveScale??!1,l=n.ignoreYAxisForRotation??!1,u=n.rotationIterations??9,{inCentroid:d,refCentroid:f,scaleRatio:p}=Qe(e,t,c,{inCentroid:o.create(),refCentroid:o.create(),refVec:o.create(),tmp:o.create()}),m=a.create();s?new tt(l).solve(e,t,d,f,m,u):a.identity(m);let h={negCentroid:o.create(),scaleVec:o.create()};return $e(i.create(),d,f,m,p,c,h)}var tt=class e{ignoreYAxis;static twoPi=Math.PI*2;static basisX=o.fromValues(1,0,0);static basisY=o.fromValues(0,1,0);static basisZ=o.fromValues(0,0,1);constructor(e){this.ignoreYAxis=e}solve(t,n,r,i,o,s){let c=this.transposeMultSubtract(t,n,r,i);if(this.ignoreYAxis){let t=c[0][0],n=c[0][2],r=c[2][0],i=c[2][2],s=Math.atan2(r-n,t+i);a.setAxisAngle(o,e.basisY,s)}else this.extractRotation(c,o,s)}transposeMultSubtract(e,t,n,r){let i=[o.create(),o.create(),o.create()],a=o.clone(n),s=o.clone(r);this.ignoreYAxis&&(a[1]=0,s[1]=0);let c=o.create(),l=o.create(),u=o.create();for(let n=0;n<e.length;n++){o.copy(c,e[n]),nt(u,t[n]),this.ignoreYAxis&&(c[1]=0,u[1]=0);let r=t[n][3];o.subtract(c,c,a),o.scale(c,c,r),o.subtract(l,u,s),i[0][0]+=c[0]*l[0],i[1][0]+=c[1]*l[0],i[2][0]+=c[2]*l[0],i[0][1]+=c[0]*l[1],i[1][1]+=c[1]*l[1],i[2][1]+=c[2]*l[1],i[0][2]+=c[0]*l[2],i[1][2]+=c[1]*l[2],i[2][2]+=c[2]*l[2]}return i}extractRotation(t,n,r){let i=[o.create(),o.create(),o.create()],s=o.create(),c=o.create(),l=o.create();for(let u=0;u<r;u++){this.fillMatrixFromQuaternion(n,i),o.cross(s,i[0],t[0]),o.cross(l,i[1],t[1]),o.add(s,s,l),o.cross(l,i[2],t[2]),o.add(s,s,l);let r=o.dot(i[0],t[0])+o.dot(i[1],t[1])+o.dot(i[2],t[2])+1e-9;r=Math.abs(r),o.scale(s,s,1/r);let u=o.length(s);if(u<1e-9)break;o.scale(c,s,1/u);let d=u%e.twoPi,f=a.create();a.setAxisAngle(f,c,d),a.multiply(n,f,n),a.normalize(n,n)}}fillMatrixFromQuaternion(t,n){o.transformQuat(n[0],e.basisX,t),o.transformQuat(n[1],e.basisY,t),o.transformQuat(n[2],e.basisZ,t)}};const nt=(e,t)=>(e[0]=t[0],e[1]=t[1],e[2]=t[2],e);function rt(e,t,n,r,i,a,o=Math.random){let s=Array.from(e);if(n>s.length)throw RangeError(`minSampleSize must be smaller than the number of elements: minSampleSize=${n}, elements=${s.length}`);return ot(s,it(s,t,n,r,i,a,o),i,a)}function it(e,t,n,r,i,a,o){let s=null,c=Array(n),l=new Uint8Array(e.length);for(let u=0;u<r;u+=1){ct(e,n,o,c,l);let{inliers:r,outliers:u}=at(e,l,i(c),a);if(s===null||n+r.length>=t){let e=[...c,...r],t=i(e),n=st(t,`createModel must assign totalModelError for comparison during RANSAC`);(s===null||n<s.error)&&(t.inliers=e,t.outliers=u,s={model:t,error:n})}}return s?.model??null}function at(e,t,n,r){let i=[],a=[];for(let o=0;o<e.length;o+=1){if(t?.[o])continue;let s=e[o];(r(n,s)?i:a).push(s)}return{inliers:i,outliers:a}}function ot(e,t,n,r){let i=t??n(e);st(i,`RANSAC failed to produce a model with totalModelError`);let{inliers:a,outliers:o}=at(e,null,i,r);return a.length>0&&(i=n(a),st(i,`createModel must assign totalModelError for final RANSAC model`)),i.inliers=a,i.outliers=o,i}function st(e,t){let{totalModelError:n}=e;if(n==null)throw Error(t);return n}function ct(e,t,n,r,i){i.fill(0);let a=0;for(;a<t;){let t=Math.floor(n()*e.length);i[t]||(i[t]=1,r[a]=e[t],a+=1)}}const lt=.08,ut=180/Math.PI,dt=e=>(e%360+360)%360,ft=(e,t)=>{let[n,r,i,a]=e,[o,s,c]=t,l=2*(r*c-i*s),u=2*(i*o-n*c),d=2*(n*s-r*o);return[o+a*l+(r*d-i*u),s+a*u+(i*l-n*d),c+a*d+(n*u-r*l)]};function pt(e){let[t,n,r,i]=e,a=-2*(t*r+i*n),o=-2*(n*r-i*t);return Math.hypot(a,o)<lt?null:dt(Math.atan2(a,o)*ut)}const mt=[0,0,-1];function ht(e,t){return Oe(e,ke(t))}function gt(e,t){let[n,r]=ft(ht(e,t),mt);return Math.hypot(n,r)<lt?null:dt(Math.atan2(n,r)*ut)}function W(e,t){let n=((e-t+180)%360+360)%360-180;return n===-180&&(n=180),n}const _t=Math.PI/180,vt=180/Math.PI,yt=2025,bt=2025,xt=2030,St=6378137;St*(1-1/298.257223563);const Ct=[[1,0,-29351.8,0,12,0],[1,1,-1410.8,4545.4,9.7,-21.5],[2,0,-2556.6,0,-11.6,0],[2,1,2951.1,-3133.6,-5.2,-27.7],[2,2,1649.3,-815.1,-8,-12.1],[3,0,1361,0,-1.3,0],[3,1,-2404.1,-56.6,-4.2,4],[3,2,1243.8,237.5,.4,-.3],[3,3,453.6,-549.5,-15.6,-4.1],[4,0,895,0,-1.6,0],[4,1,799.5,278.6,-2.4,-1.1],[4,2,55.7,-133.9,-6,4.1],[4,3,-281.1,212,5.6,1.6],[4,4,12.1,-375.6,-7,-4.4],[5,0,-233.2,0,.6,0],[5,1,368.9,45.4,1.4,-.5],[5,2,187.2,220.2,0,2.2],[5,3,-138.7,-122.9,.6,.4],[5,4,-142,43,2.2,1.7],[5,5,20.9,106.1,.9,1.9],[6,0,64.4,0,-.2,0],[6,1,63.8,-18.4,-.4,.3],[6,2,76.9,16.8,.9,-1.6],[6,3,-115.7,48.8,1.2,-.4],[6,4,-40.9,-59.8,-.9,.9],[6,5,14.9,10.9,.3,.7],[6,6,-60.7,72.7,.9,.9],[7,0,79.5,0,-0,0],[7,1,-77,-48.9,-.1,.6],[7,2,-8.8,-14.4,-.1,.5],[7,3,59.3,-1,.5,-.8],[7,4,15.8,23.4,-.1,0],[7,5,2.5,-7.4,-.8,-1],[7,6,-11.1,-25.1,-.8,.6],[7,7,14.2,-2.3,.8,-.2],[8,0,23.2,0,-.1,0],[8,1,10.8,7.1,.2,-.2],[8,2,-17.5,-12.6,0,.5],[8,3,2,11.4,.5,-.4],[8,4,-21.7,-9.7,-.1,.4],[8,5,16.9,12.7,.3,-.5],[8,6,15,.7,.2,-.6],[8,7,-16.8,-5.2,-0,.3],[8,8,.9,3.9,.2,.2],[9,0,4.6,0,-0,0],[9,1,7.8,-24.8,-.1,-.3],[9,2,3,12.2,.1,.3],[9,3,-.2,8.3,.3,-.3],[9,4,-2.5,-3.3,-.3,.3],[9,5,-13.1,-5.2,0,.2],[9,6,2.4,7.2,.3,-.1],[9,7,8.6,-.6,-.1,-.2],[9,8,-8.7,.8,.1,.4],[9,9,-12.9,10,-.1,.1],[10,0,-1.3,0,.1,0],[10,1,-6.4,3.3,0,0],[10,2,.2,0,.1,-0],[10,3,2,2.4,.1,-.2],[10,4,-1,5.3,-0,.1],[10,5,-.6,-9.1,-.3,-.1],[10,6,-.9,.4,0,.1],[10,7,1.5,-4.2,-.1,0],[10,8,.9,-3.8,-.1,-.1],[10,9,-2.7,.9,-0,.2],[10,10,-3.9,-9.1,-0,-0],[11,0,2.9,0,0,0],[11,1,-1.5,0,-0,-0],[11,2,-2.5,2.9,0,.1],[11,3,2.4,-.6,0,-0],[11,4,-.6,.2,0,.1],[11,5,-.1,.5,-.1,-0],[11,6,-.6,-.3,0,-0],[11,7,-.1,-1.2,-0,.1],[11,8,1.1,-1.7,-.1,-0],[11,9,-1,-2.9,-.1,0],[11,10,-.2,-1.8,-.1,0],[11,11,2.6,-2.3,-.1,0],[12,0,-2,0,0,0],[12,1,-.2,-1.3,0,-0],[12,2,.3,.7,-0,0],[12,3,1.2,1,-0,-.1],[12,4,-1.3,-1.4,-0,.1],[12,5,.6,-0,-0,-0],[12,6,.6,.6,.1,-0],[12,7,.5,-.1,-0,-0],[12,8,-.1,.8,0,0],[12,9,-.4,.1,0,-0],[12,10,-.2,-1,-.1,-0],[12,11,-1.3,.1,-0,0],[12,12,-.7,.2,-.1,-.1]];function wt(){let e=()=>Array.from({length:13},()=>Array(13).fill(0)),t={g:e(),h:e(),gdot:e(),hdot:e()};for(let[e,n,r,i,a,o]of Ct)t.g[e][n]=r,t.h[e][n]=i,t.gdot[e][n]=a,t.hdot[e][n]=o;return t}const G=wt();function Tt(){let e=Array(169).fill(0),t=Array(169).fill(0),n=Array(13).fill(0),r=Array(13).fill(0),i=Array(169).fill(0),a=Array(169).fill(0),o=(e,t)=>e*13+t;for(let e=1;e<=12;e++)for(let t=0;t<=e;t++){let n=G.g[e][t],r=G.h[e][t],s=G.gdot[e][t],c=G.hdot[e][t];i[o(t,e)]=n,a[o(t,e)]=s,t!==0&&(i[o(e,t-1)]=r,a[o(e,t-1)]=c)}e[o(0,0)]=1;for(let s=1;s<=12;s++){e[o(0,s)]=e[o(0,s-1)]*(2*s-1)/s;let c=2;for(let n=0,r=(s-n+1)/1;r>0;r--,n+=1){if(t[o(n,s)]=((s-1)*(s-1)-n*n)/((2*s-1)*(2*s-3)),n>0){let t=(s-n+1)*c/(s+n);e[o(n,s)]=e[o(n-1,s)]*Math.sqrt(t),c=1,i[o(s,n-1)]=e[o(n,s)]*i[o(s,n-1)],a[o(s,n-1)]=e[o(n,s)]*a[o(s,n-1)]}i[o(n,s)]=e[o(n,s)]*i[o(n,s)],a[o(n,s)]=e[o(n,s)]*a[o(n,s)]}n[s]=s+1,r[s]=s}return t[o(1,1)]=0,r[0]=0,{snorm:e,k:t,fn:n,fm:r,c:i,cd:a,idx:o}}const Et=Tt();function Dt(e){return e%4==0&&e%100!=0||e%400==0?366:365}function Ot(e){let t=e.getUTCFullYear(),n=Date.UTC(t,0,1);return t+Math.floor((e.getTime()-n)/864e5)/Dt(t)}let kt=!1;function At(e){return e===void 0?2027.5:typeof e==`number`?e>1e4?Ot(new Date(e)):e:Ot(e)}function jt(e,t,n){let r=St/1e3,i=6356752.314245179/1e3,a=r*r,o=i*i,s=a-o,c=a*a;c-o*o;let l=t*t,u=n*n,d=Math.sqrt(a-s*l),f=e*d,p=(f+a)/(f+o)*((f+a)/(f+o)),m=t/Math.sqrt(p*u+l),h=Math.sqrt(1-m*m),g=Math.sqrt(e*e+2*f+(c-22083078973482.75*l)/(d*d)),_=Math.sqrt(a*u+o*l);return{r:g,ct:m,st:h,ca:(e+_)/g,sa:s/_*t*n/g}}function Mt(e,t,n,r,i,a,o,s){if(i===a){e[r(a,i)]=o*e[r(a-1,i-1)],t[r(a,i)]=o*t[r(a-1,i-1)]+s*e[r(a-1,i-1)];return}if(i===1&&a===0){e[r(a,i)]=s*e[r(a,i-1)],t[r(a,i)]=s*t[r(a,i-1)]-o*e[r(a,i-1)];return}a>i-2&&(e[r(a,i-2)]=0,t[r(a,i-2)]=0),e[r(a,i)]=s*e[r(a,i-1)]-n[r(a,i)]*e[r(a,i-2)],t[r(a,i)]=s*t[r(a,i-1)]-o*e[r(a,i-1)]-n[r(a,i)]*t[r(a,i-2)]}function Nt(e,t,n,r){let i=r-yt;(r<2025||r>=2030)&&!kt&&(kt=!0,console.warn(`magneticDeclinationDeg: date ${r.toFixed(3)} is outside the WMM2025 validity window [${bt}, ${xt}); using linear secular extrapolation (accuracy degrades).`));let{snorm:a,k:o,fn:s,fm:c,c:l,cd:u,idx:d}=Et,f=t*_t,p=e*_t,m=Math.sin(f),h=Math.sin(p),g=Math.cos(f),_=Math.cos(p),v=Array(13).fill(0),y=Array(13).fill(0);v[0]=0,y[0]=1,v[1]=m,y[1]=g;let{r:b,ct:x,st:S,ca:C,sa:w}=jt(n,h,_);for(let e=2;e<=12;e++)v[e]=m*y[e-1]+g*v[e-1],y[e]=g*y[e-1]-m*v[e-1];let T=6371.2/b,E=T*T,D=0,ee=0,O=0,k=a.slice(),A=Array(169).fill(0);for(let e=1;e<=12;e++){E*=T;for(let t=0,n=(e+t+1)/1;n>0;n--,t+=1){Mt(k,A,o,d,e,t,S,x);let n=l[d(t,e)]+i*u[d(t,e)],r=E*k[d(t,e)],a,f;if(t===0)a=n*y[t],f=n*v[t];else{let r=l[d(e,t-1)]+i*u[d(e,t-1)];a=n*y[t]+r*v[t],f=n*v[t]-r*y[t]}D-=E*a*A[d(t,e)],ee+=c[t]*f*r,O+=s[e]*a*r}}let j;return j=S===0?0:ee/S,{x:-D*C-O*w,y:j,z:D*w-O*C}}function Pt(e){let t=e%360;return t<0?t+360:t}function Ft(e,t,n){if(!Number.isFinite(e)||!Number.isFinite(t))return NaN;let r=n?.altitudeKm??0;if(!Number.isFinite(r))return NaN;let{x:i,y:a}=Nt(e,t,r,At(n?.date));return Math.atan2(a,i)*vt}function It(e,t,n,r){return Pt(e+Ft(t,n,r))}const K=Math.PI/180,Lt=180/Math.PI,q=e=>(e%360+360)%360,J=e=>e<0?0:e>1?1:e,Rt=e=>{let t=0,n=0;for(let r of e)t+=Math.sin(r*K),n+=Math.cos(r*K);return t===0&&n===0?0:q(Math.atan2(t,n)*Lt)},zt=e=>{if(e.length===0)return 0;let t=Rt(e),n=0;for(let r of e){let e=Math.abs(W(r,t));e>n&&(n=e)}return n},Bt=(e,t,n)=>n<=0?+(e<=t):J((t+n-e)/n),Vt=(e,t,n)=>n<=0?+(e>=t):J((e-(t-n))/n),Ht=(e,t,n)=>{if(e.length<n.minWindow)return 0;let r=Bt(zt(e),n.collapseThresholdDeg,n.rampWidthDeg),i=Vt(t,n.baselineMinM,n.baselineRampM);return Math.min(r,i)},Ut=e=>J(1-e),Wt=(e,t,n)=>{let r=J(n),i=Math.cos(e*K),a=Math.sin(e*K),o=Math.cos(t*K),s=Math.sin(t*K),c=o+(i-o)*r,l=s+(a-s)*r;return q(Math.hypot(c,l)<1e-9?t:Math.atan2(l,c)*Lt)},Gt=(e,t,n)=>{if(e===null)return q(t);let r=J(n);return q(e+W(t,e)*r)},Y=e=>q(Math.atan2(e[2],e[0])*Lt),Kt=(e,t,n)=>{let r=i.fromValues(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15]),a=W(n,Y(e)),s=o.fromValues(t[0],t[1],t[2]),c=o.create();o.transformMat4(c,s,r);let l=i.create();i.fromYRotation(l,-a*K);let u=i.create();i.fromTranslation(u,c),i.multiply(u,u,l);let d=o.fromValues(-c[0],-c[1],-c[2]);i.translate(u,u,d);let f=i.create();return i.multiply(f,u,r),I(f)},qt=()=>({state:`dormant`,agreeStreak:0,disagreeStreak:0,recommendRecalibration:!1}),Jt=(e,t,n)=>{if(!t.gpsYawObservable)return{state:`dormant`,agreeStreak:0,disagreeStreak:0,recommendRecalibration:!1};let r=Math.abs(t.agreementDeltaDeg);if(r<=n.agreeToleranceDeg){let t=e.agreeStreak+1;return{state:t>=n.minAgreeStreak?`trusted`:`untrusted`,agreeStreak:t,disagreeStreak:0,recommendRecalibration:!1}}let i=e.disagreeStreak+1;return{state:e.state===`trusted`&&r>n.dropToleranceDeg?`untrusted`:e.state===`trusted`?`trusted`:`untrusted`,agreeStreak:0,disagreeStreak:i,recommendRecalibration:i>=n.recalibrateAfterStreak}},Yt=e=>e<0?0:e>1?1:e,Xt=e=>+(e===`trusted`),Zt=(e,t,n)=>{let r=Yt(e),i=Yt(t);return Yt(1-r+r*i*n.steadyStateMaxWeight)},Qt={useOnlyRecentData:!1,recentSeconds:180,includeTimeWeight:!0,weightByTimeFactor:2500,ignoreYAxisForRotation:!0,useRansac:!1,ransacInlierRatio:.95,ransacSampleRatio:.3,ransacMaxIterations:230,ransacErrorTolerance:1,geohashPrecision:8,geohashWindowSize:10,gpsAccuracyExponent:.1,altitudeAlignmentMode:`separate1D`,altitudeAggregator:`mean`,altitudeSampleSet:`all`,gpsVerticalAccuracyExponent:5,useOutlierRejection:!1,outlierThresholdMeters:10,outlierRetainRatio:.6,useDistanceGating:!1,minSampleDistanceMeters:1,maxSampleIntervalMs:3e3,useCompassColdStartOverride:!1,coldStartObservabilityCollapseDeg:12,coldStartObservabilityRampDeg:8,coldStartObservabilityWindow:5,coldStartBaselineMinM:15,coldStartBaselineRampM:10,coldStartSnapAlpha:.5,useCompassRotationPrior:!1,compassSteadyStateMaxWeight:.3},$t=e=>e.map(e=>L(e)),en=e=>e.map(e=>B(e)),tn=e=>e.map(Un),nn=e=>e.map(e=>[e[0],e[1],e[2],e[3]]),X=e=>Array.isArray(e)?e:P(e),Z=e=>Array.isArray(e)?e:F(e),rn=(e,t,n,r)=>({odometryPosOffset:L(X(e)),odometryRotOffset:B(Z(t)),latestLoopClosureFixPointPos:n?L(X(n)):null,latestLoopClosureFixPointRot:r?B(Z(r)):null}),an=(e,t,n,r)=>({odometryPositions:[],odometryRotations:[],gpsPositions:[],gpsPositionsVec4:[],alignmentMatrix:[...Se],alignmentRotation:[...R],alignmentTranslation:[...z],alignmentRotationInDegree:[...z],...rn(e,t,n,r),gpsAccuracyMedian:null,gpsAccuracyMean:null,currentGpsPosGeoHash:null,lastAdmittedOdomPos:null,lastAdmittedTs:null}),on=()=>an(z,R,null,null),sn=(e,t,n,r)=>{let i=e.map(e=>X(e)),a=t.map(e=>B(Z(e))),o=n.map(Un),s=r.gpsAccuracyExponent;for(let e of o)e.weight=dn(e.latLongAccuracy,s);let c=o.map(Vn),l=r.includeTimeWeight?In(c,o,r.weightByTimeFactor):c,u=r.useOnlyRecentData?Pn(o,r.recentSeconds):0,d=i.slice(u).map(M),f=o.slice(u);return{allPositionTuples:i,allRotationTuples:a,allGpsPoints:o,allVec4Tuples:l,solverPositionsTyped:d,solverGpsPoints:f,solverWeightedVec4Tuples:l.slice(u),solverVerticalWeights:Fn(f,r)}},cn=(e,t,n,r,i)=>{if(e==null||t==null)return!0;let a=n[0]-e[0],o=n[2]-e[2],s=i.minSampleDistanceMeters*i.minSampleDistanceMeters;return a*a+o*o>=s||r-t>=i.maxSampleIntervalMs},ln=(e,t,n,r)=>{if(!r.useDistanceGating)return{odometryPositions:e,odometryRotations:t,gpsPoints:n};let i=[],a=[],o=[],s=null,c=null;for(let l=0;l<n.length;l+=1){let u=X(e[l]),d=n[l].timestamp;cn(s,c,u,d,r)&&(i.push(e[l]),a.push(t[l]),o.push(n[l]),s=u,c=d)}return{odometryPositions:i,odometryRotations:a,gpsPoints:o}},un=e=>{let{odometryPositions:t,odometryRotations:n,gpsPoints:r,odometryPosOffset:i=z,odometryRotOffset:s=R,latestLoopClosureFixPointPos:c=null,latestLoopClosureFixPointRot:l=null,alignmentConfig:u,random:d}=e;if(t.length!==n.length||t.length!==r.length)throw Error(`GpsEvents requires odometry positions, rotations, and gps points to have identical lengths`);let f={...Qt,...u??{}};if(t.length===0)return an(i,s,c,l);let p=ln(t,n,r,f),{allPositionTuples:m,allRotationTuples:h,allGpsPoints:g,allVec4Tuples:_,solverPositionsTyped:v,solverGpsPoints:y,solverWeightedVec4Tuples:b,solverVerticalWeights:x}=sn(p.odometryPositions,p.odometryRotations,p.gpsPoints,f),S=On(hn(v,b,x,f,d??Math.random).matrix,v,b,x,g,h,f,d??Math.random),C=S.matrix,w=a.create(),T=o.create(),E=o.create();pn(C,w,T,E);let{mean:D,median:ee}=zn(g),O=Rn(p.gpsPoints,f.geohashPrecision,f.geohashWindowSize),k=m.length-1,A=k>=0?L(m[k]):null,j=k>=0?p.gpsPoints[k]?.timestamp??null:null;return{odometryPositions:$t(m),odometryRotations:en(h),gpsPositions:tn(g),gpsPositionsVec4:nn(_),alignmentMatrix:I(C),alignmentRotation:F(w),alignmentTranslation:P(T),alignmentRotationInDegree:P(E),...rn(i,s,c,l),gpsAccuracyMedian:ee,gpsAccuracyMean:D,currentGpsPosGeoHash:O,lastAdmittedOdomPos:A,lastAdmittedTs:j,...S.fields}},dn=(e,t)=>e!=null&&e>0?1/Math.max(e,1)**+t:1,fn=(e,t,n,r,i,s)=>{let c={...Qt,...i??{}},l=X(t);if(c.useDistanceGating&&!cn(e.lastAdmittedOdomPos,e.lastAdmittedTs,l,r.timestamp,c))return;let u=e.odometryPositions,d=e.odometryRotations,f=e.gpsPositions,p=e.gpsPositionsVec4;u.push(l),d.push(B(Z(n)));let m=Un(r);f.push(m),m.weight=dn(m.latLongAccuracy,c.gpsAccuracyExponent);let h=Vn(m);if(c.includeTimeWeight){p.push(h);let e=In(p,f,c.weightByTimeFactor);for(let t=0;t<e.length;t++)p[t]=e[t]}else p.push(h);let g=0;c.useOnlyRecentData&&(g=Pn(f,c.recentSeconds));let _=u.slice(g).map(M),v=p.slice(g),y=Dn(e,hn(_,v,Fn(f.slice(g),c),c,s??Math.random).matrix,_,v,f,d,c);e.alignmentMatrix=I(y);let b=a.create(),x=o.create(),S=o.create();pn(y,b,x,S),e.alignmentRotation=F(b),e.alignmentTranslation=P(x),e.alignmentRotationInDegree=P(S);let{mean:C,median:w}=zn(f);e.gpsAccuracyMean=C,e.gpsAccuracyMedian=w,e.currentGpsPosGeoHash=Rn(f,c.geohashPrecision,c.geohashWindowSize),e.lastAdmittedOdomPos=L(l),e.lastAdmittedTs=r.timestamp},pn=(e,t,n,r)=>{i.getRotation(t,e),a.normalize(t,t),i.getTranslation(n,e),Bn(t,r)},Q=o.create(),mn=o.create(),hn=(e,t,n,r,a)=>{if(e.length===0)return{matrix:i.create(),meanError:0};let o=e.length,c=[];for(let r=0;r<o;r+=1){let i=t[r];c.push({odom:e[r],ref:s.fromValues(i[0],i[1],i[2],i[3]),verticalWeight:n[r]??1})}let l,u,d;if(r.useRansac&&c.length>=3){let e=c.length,t=Math.max(3,Math.min(e,Math.ceil(e*r.ransacSampleRatio))),n=rt(c,Math.max(t,Math.min(e,Math.ceil(e*r.ransacInlierRatio))),t,r.ransacMaxIterations,e=>kn(e,r.ignoreYAxisForRotation),(e,t)=>An(e,t)<e.meanAlignmentError+r.ransacErrorTolerance,a);l=n.alignmentMatrix,u=n.meanAlignmentError,n.inliers!==void 0&&(d=Array.from(n.inliers))}else if(r.useOutlierRejection&&c.length>=4){let{model:e,inliers:t}=Nn(c,r);l=e.alignmentMatrix,u=e.meanAlignmentError,d=t}else{let e=kn(c,r.ignoreYAxisForRotation);l=e.alignmentMatrix,u=e.meanAlignmentError}return r.altitudeAlignmentMode===`separate1D`&&gn(l,c,d,r),{matrix:l,meanError:u}},gn=(e,t,n,r)=>{let i=r.altitudeSampleSet===`horizontalInliers`&&n!==void 0&&n.length>0?n:t;if(i.length===0)return;let a=Array(i.length),o=Array(i.length);for(let e=0;e<i.length;e+=1){let t=i[e];a[e]=t.ref[1]-t.odom[1];let n=t.verticalWeight;o[e]=n>0&&Number.isFinite(n)?n:0}e[13]=r.altitudeAggregator===`median`?vn(a,o):_n(a,o)},_n=(e,t)=>{let n=0,r=0;for(let i=0;i<e.length;i+=1)n+=e[i]*t[i],r+=t[i];if(r>0&&Number.isFinite(r))return n/r;let i=0;for(let t=0;t<e.length;t+=1)i+=e[t];return e.length===0?0:i/e.length},vn=(e,t)=>{if(e.length===0)return 0;if(e.length===1)return e[0];let n=e.map((e,t)=>t);n.sort((t,n)=>e[t]-e[n]);let r=0;for(let e=0;e<t.length;e+=1)r+=t[e];if(!(r>0)||!Number.isFinite(r)){let t=n.map(t=>e[t]);return t[Math.floor((t.length-1)/2)]}let i=r/2,a=0;for(let r=0;r<n.length;r+=1)if(a+=t[n[r]],a>=i)return e[n[r]];return e[n[n.length-1]]},yn=e=>{let t=0;for(let n=1;n<e.length;n+=1){let r=e[n].coordinates,i=e[n-1].coordinates;t+=Math.hypot(r[0]-i[0],r[2]-i[2])}return t},bn=(e,t)=>{let n=o.create(),r=0;for(let i=0;i<e.length;i+=1){let a=t[i][3];o.scaleAndAdd(n,n,e[i],a),r+=a}return r>0&&o.scale(n,n,1/r),n},xn=(e,t)=>{let n=[];for(let r=0;r<e.length;r+=1){let i=e[r].absoluteOrientation,a=t[r];if(!i||!a)continue;let o=gt(i.quaternion,a);if(o===null)continue;let s=((o+Ft(e[r].latitude,e[r].longitude,{date:e[r].timestamp||void 0}))%360+360)%360;Number.isFinite(s)&&n.push(s)}return n.length===0?null:Rt(n)},Sn=e=>({collapseThresholdDeg:e.coldStartObservabilityCollapseDeg,rampWidthDeg:e.coldStartObservabilityRampDeg,minWindow:e.coldStartObservabilityWindow,baselineMinM:e.coldStartBaselineMinM,baselineRampM:e.coldStartBaselineRampM}),Cn=(e,t,n,r,i)=>{let a=e.length,o=Math.max(1,a-r.coldStartObservabilityWindow+1),s=[];for(let c=o;c<=a;c+=1){let a=hn(e.slice(0,c),t.slice(0,c),n.slice(0,c),r,i);s.push(Y(a.matrix))}return s},wn={agreeToleranceDeg:8,minAgreeStreak:3,dropToleranceDeg:20,recalibrateAfterStreak:4},Tn=(e,t,n,r,i,a,o,s,c)=>{let l=xn(r,i);if(l===null)return{matrix:e,appliedBearingDeg:o,trust:s};let u=a.length>0?a[a.length-1]:Y(e),d=Ht(a,yn(r),Sn(c)),f,p=s;c.useCompassRotationPrior?(p=Jt(s??qt(),{gpsYawObservable:d>=.5,agreementDeltaDeg:W(l,u)},wn),f=Zt(d,Xt(p.state),{steadyStateMaxWeight:c.compassSteadyStateMaxWeight})):f=Ut(d);let m=Gt(o,Wt(l,u,f),c.coldStartSnapAlpha);return{matrix:ye(Kt(e,bn(t,n),m)),appliedBearingDeg:m,trust:p}},En=e=>e.useCompassColdStartOverride||e.useCompassRotationPrior,Dn=(e,t,n,r,i,a,o)=>{if(!En(o))return t;let s=e.coldStartYawWindowDeg?[...e.coldStartYawWindowDeg]:[];for(s.push(Y(t));s.length>o.coldStartObservabilityWindow;)s.shift();let c=Tn(t,n,r,i,a,s,e.coldStartAppliedBearingDeg??null,e.compassTrust,o);return e.coldStartYawWindowDeg=s,e.coldStartAppliedBearingDeg=c.appliedBearingDeg,c.trust!==void 0&&(e.compassTrust=c.trust),c.matrix},On=(e,t,n,r,i,a,o,s)=>{if(!En(o))return{matrix:e,fields:{}};let c=Cn(t,n,r,o,s),l=Tn(e,t,n,i,a,c,null,void 0,o),u={coldStartYawWindowDeg:c,coldStartAppliedBearingDeg:l.appliedBearingDeg};return l.trust!==void 0&&(u.compassTrust=l.trust),{matrix:l.matrix,fields:u}},kn=(e,t)=>{let n=Array.from(e),r=n.length,i=Array(r),a=Array(r);for(let e=0;e<r;e+=1)i[e]=n[e].odom,a[e]=n[e].ref;let s=et(i,a,{ignoreYAxisForRotation:t}),c=0;for(let e=0;e<r;e+=1)o.transformMat4(Q,i[e],s),c+=jn(Q,n[e].ref);return{alignmentMatrix:s,meanAlignmentError:r===0?0:c/r,totalModelError:c}},An=(e,t)=>(o.transformMat4(Q,t.odom,e.alignmentMatrix),jn(Q,t.ref)),jn=(e,t)=>(o.set(mn,t[0],t[1],t[2]),o.squaredDistance(e,mn)),Mn=(e,t)=>{o.transformMat4(Q,t.odom,e.alignmentMatrix);let n=Q[0]-t.ref[0],r=Q[2]-t.ref[2];return n*n+r*r},Nn=(e,t)=>{let n=e.length,r=Math.max(3,Math.ceil(t.outlierRetainRatio*n)),i=t.outlierThresholdMeters*t.outlierThresholdMeters,a=Array.from(e),o=kn(a,t.ignoreYAxisForRotation);for(;a.length>r;){let e=-1,n=-1;for(let t=0;t<a.length;t+=1){let r=Mn(o,a[t]);r>n&&(n=r,e=t)}if(n<=i||e<0)break;a=a.filter((t,n)=>n!==e),o=kn(a,t.ignoreYAxisForRotation)}return{model:o,inliers:a}},Pn=(e,t)=>{if(e.length===0||t<=0)return 0;let n=e[e.length-1].timestamp-t*1e3;for(let t=0;t<e.length;t+=1)if(e[t].timestamp>=n)return t;return 0},Fn=(e,t)=>{let n=t.gpsVerticalAccuracyExponent,r=e.map(e=>{let t=e.altitudeAccuracy;return dn(t!=null&&Number.isFinite(t)&&t>0?t:e.latLongAccuracy,n)});if(!t.includeTimeWeight||e.length<2)return r;let i=e[e.length-1].timestamp,a=e[0].timestamp,o=Math.max(1,i-a),s=t.weightByTimeFactor;return r.map((t,n)=>{if(!(t>0&&Number.isFinite(t)))return 0;let r=s*((i-e[n].timestamp)/o)+1;return 1/(1/t+r)})},In=(e,t,n)=>{if(e.length<2)return e.map(e=>[e[0],e[1],e[2],e[3]]);let r=t[t.length-1].timestamp,i=t[0].timestamp,a=Math.max(1,r-i);return e.map((e,i)=>{let o=n*((r-t[i].timestamp)/a)+1,s=t[i].weight;if(!(s>0&&Number.isFinite(s)))return[e[0],e[1],e[2],0];let c=1/(1/s+o);return[e[0],e[1],e[2],c]})},Ln=new Map,Rn=(e,t,n)=>{if(e.length===0)return null;let r=Math.max(0,e.length-n);Ln.clear();for(let n=r;n<e.length;n+=1){let r=e[n],i=ie(Hn(r),t),a=Ln.get(i);a?(a.count+=1,a.index=n):Ln.set(i,{count:1,index:n})}let i=null,a=-1,o=-1;for(let[e,{count:t,index:n}]of Ln)(t>a||t===a&&n>o)&&(i=e,a=t,o=n);return i},zn=e=>{let t=e.map(e=>e.latLongAccuracy).filter(e=>typeof e==`number`&&Number.isFinite(e));if(t.length===0)return{mean:null,median:null};let n=t.reduce((e,t)=>e+t,0)/t.length,r=t.slice().sort((e,t)=>e-t),i=Math.floor(r.length/2);return{mean:n,median:r.length%2==0?(r[i-1]+r[i])/2:r[i]}},Bn=(e,t)=>{let n=e[0],r=e[1],i=e[2],a=e[3],s=2*(a*n+r*i),c=1-2*(n*n+r*r),l=Math.atan2(s,c),u=2*(a*r-i*n),d;d=Math.abs(u)>=1?Math.PI/2*Math.sign(u):Math.asin(u);let f=2*(a*i+n*r),p=1-2*(r*r+i*i),m=Math.atan2(f,p),h=180/Math.PI,g=t??o.create();return g[0]=l*h,g[1]=d*h,g[2]=m*h,g},Vn=e=>[e.coordinates[0],e.coordinates[1],e.coordinates[2],e.weight>0&&Number.isFinite(e.weight)?e.weight:1],Hn=e=>({lat:e.latitude,lon:e.longitude}),Un=e=>({...e,zeroRef:{lat:e.zeroRef.lat,lon:e.zeroRef.lon},coordinates:[e.coordinates[0],e.coordinates[1],e.coordinates[2]],timestamp:e.timestamp,deviceRotation:e.deviceRotation?B(Z(e.deviceRotation)):void 0,absoluteOrientation:e.absoluteOrientation?{...e.absoluteOrientation,quaternion:[e.absoluteOrientation.quaternion[0],e.absoluteOrientation.quaternion[1],e.absoluteOrientation.quaternion[2],e.absoluteOrientation.quaternion[3]]}:void 0}),Wn=({lat:e,lon:t})=>{if(!Number.isFinite(e))throw Error(`Invalid latitude value: ${e}`);if(!Number.isFinite(t))throw Error(`Invalid longitude value: ${t}`);if(e<-90||e>90)throw Error(`Invalid latitude range: ${e}`);if(t<-180||t>180)throw Error(`Invalid longitude range: ${t}`)},Gn=o.fromValues(1,1,1),Kn=(e,t)=>[e[0]+t[0],e[1]+t[1],e[2]+t[2]],qn=(e,t,n,r)=>{let i=ce(t,{lat:e.latitude,lon:e.longitude},e.altitude??0,0),a=n?.alpha!=null&&n?.beta!=null&&n?.gamma!=null?U(Ne(n.alpha,n.beta,n.gamma)):void 0;return{...e,zeroRef:t,coordinates:P(i),weight:1,deviceRotation:a,absoluteOrientation:r}},Jn=(e,t,n)=>{if(e)return Ne(e.alpha,e.beta,e.gamma);if(t)return t;throw Error(`Sensor rotation missing for ${n}: neither raw orientation nor legacy quaternion provided`)},Yn=e=>{let t=a.invert(a.create(),e);if(!t)throw Error(`Encountered non-invertible quaternion`);return t},Xn=e=>{let t=Yn(a.normalize(a.create(),N(e.lastSensorRot))),n=a.normalize(a.create(),N(e.lastValidOdomRot)),r=a.multiply(a.create(),t,n),i=a.normalize(a.create(),N(e.newSensorRot)),o=a.multiply(a.create(),i,r),s=a.normalize(a.create(),N(e.newOdomRot)),c=a.multiply(a.create(),o,s);return a.normalize(c,c),F(c)},Zn=(e,t)=>{let n=i.create();return i.fromRotationTranslationScale(n,a.normalize(a.create(),N(t)),M(e),Gn),n},Qn=(e,t,n)=>{let r=o.create(),s=o.create(),c=a.create(),l=a.create();i.getTranslation(r,e),i.getTranslation(s,t),i.getRotation(c,e),i.getRotation(l,t);let u=o.create();o.lerp(u,r,s,n);let d=a.create();return a.slerp(d,c,l,n),i.fromRotationTranslation(i.create(),d,u)},$n=(e,t)=>{if(e.length===0)return[];let n=e[e.length-1],r=i.invert(i.create(),n);if(!r)throw Error(`End pose matrix is not invertible`);let a=i.multiply(i.create(),t,r),o=i.create(),s=e.length-1;return e.map((e,t)=>{let n=Qn(o,a,s<=0?1:t/s);return i.multiply(i.create(),n,e)})},er=(e,t,n)=>{for(let r=e.length-1;r>=0;--r)if(n(e[r],t))return r;return-1},tr=e=>e.coldStartOverrideEnabled?{useCompassColdStartOverride:!0}:void 0,nr=(e,t)=>e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2],rr=(e,t)=>e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[3]===t[3],ir=t({name:`gpsData`,initialState:null,reducers:{setZeroPos:{reducer:(e,t)=>e===null?{zero:t.payload,gpsEvents:on(),odometryPath:ge()}:e,prepare:e=>(Wn(e),{payload:e})},recordGpsEvent:(e,t)=>{if(!e)return e;let{odomPosition:n,odomRotation:r,rawGpsPoint:i,rawDeviceOrientation:a,rawAbsoluteOrientation:o}=t.payload,s=qn(i,e.zero,a,o);fn(e.gpsEvents,V(n),H(r),s,tr(e))},setColdStartOverrideEnabled:(e,t)=>{if(!e)return e;e.coldStartOverrideEnabled=t.payload},odometryTrackingRestarted:(e,t)=>{if(!e)return e;let n=Kn(e.gpsEvents.odometryPosOffset,V(t.payload.lastValidOdomPos)),r=Jn(t.payload.lastSensorOrientation,t.payload.lastSensorRot,`lastSensor`),i=Jn(t.payload.newSensorOrientation,t.payload.newSensorRot,`newSensor`);e.gpsEvents=c(un({odometryPositions:[],odometryRotations:[],gpsPoints:[],odometryPosOffset:n,odometryRotOffset:Xn({...t.payload,lastValidOdomRot:H(t.payload.lastValidOdomRot),newOdomRot:H(t.payload.newOdomRot),lastSensorRot:U(r),newSensorRot:U(i)}),latestLoopClosureFixPointPos:null,latestLoopClosureFixPointRot:null,alignmentConfig:tr(e)}))},arLoopClosureDetected:(e,t)=>{if(!e)return e;let n=e.gpsEvents;if(n.odometryPositions.length===0)return e;let r=n.latestLoopClosureFixPointPos?er(n.odometryPositions,n.latestLoopClosureFixPointPos,nr):0,s=n.latestLoopClosureFixPointRot?er(n.odometryRotations,n.latestLoopClosureFixPointRot,rr):0;if(r<0||s<0)throw Error(`Loop closure fix point could not be located in history`);if(r!==s)throw Error(`Loop closure fix point indices for position and rotation diverged`);let l=n.odometryPositions.slice(0,r).map(e=>L(e)),u=n.odometryRotations.slice(0,r).map(e=>B(e)),d=n.odometryPositions.slice(r).map(e=>L(e)),f=n.odometryRotations.slice(r).map(e=>B(e)),p=d.map((e,t)=>Zn(e,f[t])),m=Zn(V(t.payload.lastPos),B(H(t.payload.lastRot)));p.push(m);let h=$n(p,Zn(V(t.payload.newPos),B(H(t.payload.newRot)))),g=[],_=[],v=o.create();for(let e=0;e<h.length-1;e+=1){let t=h[e],n=o.create();i.getTranslation(n,t);let r=a.create();if(i.getRotation(r,t),a.normalize(r,r),i.getScaling(v,t),Math.hypot(v[0]-1,v[1]-1,v[2]-1)>.05)throw Error(`Unexpected scale drift encountered during loop closure correction`);g.push(P(n)),_.push(F(r))}e.gpsEvents=c(un({odometryPositions:l.concat(g),odometryRotations:u.concat(_),gpsPoints:n.gpsPositions,odometryPosOffset:n.odometryPosOffset,odometryRotOffset:n.odometryRotOffset,latestLoopClosureFixPointPos:null,latestLoopClosureFixPointRot:null,alignmentConfig:tr(e)}))},add2dImage:(e,t)=>{if(!e)return e;e.odometryPath.points.push(c({imageFile:t.payload.imageFile,screenRotation:t.payload.screenRotation,position:V(t.payload.position),rotation:B(H(t.payload.rotation)),capturedAt:t.payload.capturedAt,width:t.payload.width,height:t.payload.height}))}}}),{setZeroPos:ar,recordGpsEvent:or,odometryTrackingRestarted:sr,arLoopClosureDetected:cr,add2dImage:lr,setColdStartOverrideEnabled:ur}=ir.actions,dr=p(ar),fr=p(or),pr=p(sr),mr=p(cr),hr=p(lr),gr=p(ur),_r=m(ir.reducer),vr=t({name:`gpsElements`,initialState:_e(),reducers:{addMarker:(e,t)=>{e.gpsMarkers.push(t.payload)},addLine:(e,t)=>{e.gpsLines.push(t.payload)},addArea:(e,t)=>{e.areas.push(t.payload)},addToHeatMaps:(e,t)=>{let{category:n,tiles:r}=t.payload,i=e.heatMap[n]??{};e.heatMap[n]={...i,...r}},addHeatMapArea:(e,t)=>{let n=t.payload,r=n.category;if(e.heatAreas[r]||(e.heatAreas[r]={}),e.heatAreas[r][n.geoHash])throw Error(`HeatArea collision detected for GeoHash: ${n.geoHash}`);e.heatAreas[r][n.geoHash]=n},resetGpsElements:()=>_e()}}),{addMarker:yr,addLine:br,addArea:xr,addToHeatMaps:Sr,addHeatMapArea:Cr,resetGpsElements:wr}=vr.actions,Tr=p(yr),Er=p(br),Dr=p(xr),Or=p(Sr),kr=p(Cr),Ar=p(wr),jr=m(vr.reducer),Mr=()=>({gpsData:null,gpsElements:_e(),arElements:ve()}),Nr=e=>{let t=Array.from({length:Math.min(e.length,4)},(t,n)=>e[n].toFixed(2));e.length>4&&t.push(`…`);let n=`[${t.join(`, `)}]`;if(e.length===4){let{pitch:t,yaw:r,roll:i}=v(e);return`${n} (pitch=${t.toFixed(0)}°, yaw=${r.toFixed(0)}°, roll=${i.toFixed(0)}°)`}return n},Pr=e=>(e.length===3||e.length===4||e.length===16)&&e.every(e=>typeof e==`number`),$=(e,t=0)=>{if(t>10||e==null)return e;if(Array.isArray(e))return Pr(e)?Nr(e):e.map(e=>$(e,t+1));if(typeof e==`object`){let n={};for(let[r,i]of Object.entries(e))n[r]=$(i,t+1);return n}return e},Fr=(t={})=>{let{preloadedState:n,enableDevToolsSanitizers:r=!0,enableDevChecks:i=!0,licenseKey:a}=t;if(a==null)throw Error(`License key required. Pass options.licenseKey or use createRecorderStore() from gps-plus-slam-app-framework. See EULA §3.`);g(a);let o=Mr(),s=n?{gpsData:n.gpsData??o.gpsData,gpsElements:n.gpsElements??o.gpsElements,arElements:n.arElements??o.arElements}:void 0;return e({reducer:{gpsData:_r,gpsElements:jr,arElements:Ze},preloadedState:s,middleware:e=>e({serializableCheck:i,immutableCheck:i}),devTools:r?{actionSanitizer:$,stateSanitizer:$}:!0})},Ir=[],Lr=[],Rr=[],zr={median:null,mean:null},Br=f(function(e){let t=e.gpsData?.gpsEvents;return!t||t.gpsPositions.length===0?null:t.alignmentMatrix}),Vr=f(function(e){let t=e.gpsData?.gpsEvents;return!t||t.gpsPositions.length===0?null:t.alignmentRotation}),Hr=f(function(e){return e.gpsData?.gpsEvents?.odometryPositions??Ir}),Ur=f(function(e){return e.gpsData?.gpsEvents?.odometryRotations??Lr}),Wr=f(function(e){return e.gpsData?.gpsEvents?.gpsPositions??Rr}),Gr=f(function(e){return e.gpsData?.zero??null}),Kr=f(function(e){let t=e.gpsData?.gpsEvents?.gpsAccuracyMedian??null,n=e.gpsData?.gpsEvents?.gpsAccuracyMean??null;return t===null&&n===null?zr:{median:t,mean:n}}),qr=`1.0.0`;export{Se as IDENTITY_MATRIX4,R as IDENTITY_QUATERNION,qr as LIB_VERSION,yt as WMM2025_EPOCH,bt as WMM2025_VALID_FROM,xt as WMM2025_VALID_TO,z as ZERO_VECTOR3,hr as add2dImage,Dr as addArea,Ke as addCornerToEventArea,kr as addHeatMapArea,Er as addLine,Tr as addMarker,We as addOrUpdateArPlane,Or as addToHeatMaps,Ye as anchorEventAreaInWorldSpace,Ze as arElementsReducer,mr as arLoopClosureDetected,gt as arNorthBearingDeg,ht as arToEnuRotation,W as bearingDeltaDeg,ie as calcGeoHash,le as calcGpsCoords,ne as calcQuadKey,ce as calcRelativeCoordsInMeters,xe as cloneMatrix4,be as cloneQuaternion,L as cloneVector3,qe as correctArDriftForEventArea,Fr as createGpsSlamStore,oe as distanceInMeters,se as distanceInMetersRelative,U as enuQuaternionToNUE,Ne as eulerToQuaternion,Je as finishEventArea,ye as fromMatrix4,N as fromQuaternion,M as fromVector3,he as fusedGpsFromOdom,ae as geoHashToLatLong,Br as getAlignmentMatrix,Vr as getAlignmentRotation,pe as getGoogleMapsDirectionsLink,fe as getGoogleMapsLink,Kr as getGpsAccuracyStats,Wr as getGpsPositions,Hr as getOdometryPositions,Ur as getOdometryRotations,me as getOpenStreetMapLink,Gr as getZeroReference,_r as gpsDataReducer,jr as gpsElementsReducer,ke as invertQuaternion,Ce as isIdentityMatrix4,Te as isIdentityQuaternion,Ee as isNearIdentityQuaternion,Ft as magneticDeclinationDeg,pt as magneticHeadingFromEnuQuat,It as magneticToTrueHeadingDeg,Oe as multiplyQuaternions,B as normalizeQuaternion,Me as nueQuaternionToENU,je as nueQuaternionToWebXR,Ae as nueToWebXR,pr as odometryTrackingRestarted,re as quadKeyToLatLong,we as quaternionMagnitude,De as quaternionsEquivalent,fr as recordGpsEvent,Ue as recordPhoneHeight,Xe as resetArElements,Ar as resetGpsElements,$ as sanitizeForDevTools,gr as setColdStartOverrideEnabled,dr as setZeroPos,Ge as startEventArea,ue as toEarthCenteredCoordinates,I as toMatrix4,F as toQuaternion,P as toVector3,g as validateLicenseKey,H as webxrQuaternionToNUE,V as webxrToNUE};
@@ -35,6 +35,6 @@
35
35
  * @see docs/2026-04-25-private-key-security-plan.md — secret-backed renewal
36
36
  * @see ../../GpsPlusSlamJs_Docs/docs/2026-05-01-community-key-resign-cross-repo-issue.md
37
37
  */
38
- declare const COMMUNITY_LICENSE_KEY = "eyJ0eXBlIjoiY29tbXVuaXR5IiwiZXhwIjoxODEzNjExMTUxfQ.LME4b_CjbvN33kS--UkXfFbns-93P7erNYM4JThcbwvCosKH77Ta-7lHkuZgzxIiuzUMW6uYQ3G5YgE0aySqCw";
38
+ declare const COMMUNITY_LICENSE_KEY = "eyJ0eXBlIjoiY29tbXVuaXR5IiwiZXhwIjoxODE0MDQ4ODExfQ.93uD-XHsPVXAAVkr163KYmYcRxMXpi4qkdntamr9kUWsU9q5-zb67ptgISNOOfdLDJnejod4auPokrYlF1zqBQ";
39
39
  //#endregion
40
40
  export { COMMUNITY_LICENSE_KEY };
@@ -1,2 +1,2 @@
1
1
  /*! gps-plus-slam-js | (c) 2026 cs-util-com | UNLICENSED — see EULA.md */
2
- const e=`eyJ0eXBlIjoiY29tbXVuaXR5IiwiZXhwIjoxODEzNjExMTUxfQ.LME4b_CjbvN33kS--UkXfFbns-93P7erNYM4JThcbwvCosKH77Ta-7lHkuZgzxIiuzUMW6uYQ3G5YgE0aySqCw`;export{e as COMMUNITY_LICENSE_KEY};
2
+ const e=`eyJ0eXBlIjoiY29tbXVuaXR5IiwiZXhwIjoxODE0MDQ4ODExfQ.93uD-XHsPVXAAVkr163KYmYcRxMXpi4qkdntamr9kUWsU9q5-zb67ptgISNOOfdLDJnejod4auPokrYlF1zqBQ`;export{e as COMMUNITY_LICENSE_KEY};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gps-plus-slam-js",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "TypeScript library for real-time GPS + AR odometry alignment.",
5
5
  "author": "cs-util-com",
6
6
  "keywords": [