@ingissa/navcore-core 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +279 -279
- package/dist/{NavCore-Bjl5fTea.d.mts → NavCore.d-BuXR5DO7.d.mts} +42 -18
- package/dist/{NavCore-Bjl5fTea.d.ts → NavCore.d-BuXR5DO7.d.ts} +42 -18
- package/dist/core.d.mts +32 -32
- package/dist/core.d.ts +32 -32
- package/dist/core.js +2 -3
- package/dist/core.mjs +2 -3
- package/dist/index.d.mts +65 -2
- package/dist/index.d.ts +65 -2
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/dist/pro.d.mts +39 -70
- package/dist/pro.d.ts +39 -70
- package/dist/pro.js +1 -1
- package/dist/pro.mjs +1 -1
- package/package.json +72 -72
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,66 @@
|
|
|
1
|
-
|
|
1
|
+
import { C as Coordinate } from './NavCore.d-BuXR5DO7.mjs';
|
|
2
|
+
export { F as FEATURES, a as FeatureKey, L as LicenseManager, b as LicensePayload, c as LicenseStatus, d as LifecycleContext, e as LifecycleEvent, N as NavCore, f as NavCoreOptions, g as NavCoreState, h as NavGpsUpdate, i as NavInstruction, j as NavLifecycleState, k as NavigationFSM, O as OffRouteContext, l as OffRouteEvent, m as OffRouteFSM, n as OffRouteState, R as RejoinTarget, T as TempRoute, o as destinationPoint, p as geoGetBearing, q as haversineDistance, r as resolveNextInstruction } from './NavCore.d-BuXR5DO7.mjs';
|
|
2
3
|
export { BuildOptions, CameraOptions, Constants, CustomRouteBuilder, CustomWaypoint, DirectionsLeg, DirectionsManeuver, DirectionsOptions, DirectionsProvider, DirectionsResult, DirectionsStep, Kalman2DState, KalmanFilter2D, MapRendererAdapter, ORSConfig, ORSProfile, OSRMConfig, OSRMDirectionsProvider, OpenRouteServiceProvider, RouteSnapper, RouteStyle, SnapResult, SnapperOptions, ValhallaConfig, ValhallaCostingModel, ValhallaDirectionsProvider, VehicleStyle, WaypointOptions, buildForwardCumulativeDistances, buildReverseCumulativeDistances, getBearingBetweenPoints, interpolatePoint, kalmanUpdate2D, normalizeAngle, projectPointOnSegment } from './core.mjs';
|
|
3
|
-
export { DeadReckoningEngine, DeviationDetector, ETAEngine, ETAOptions, ETAResult, GeofenceEvent, GeofenceEventType, GeofenceType, GeofencingEngine, GeofencingOptions, InstructionEditor, InstructionType, ParallelRoadResolver, ParallelRoadResolverOptions, ResolvedCandidate, RichInstruction, SnapCandidate, VoiceCue, VoicePriority, VoiceTriggerEngine, VoiceTriggerOptions,
|
|
4
|
+
export { DeadReckoningEngine, DeviationDetector, ETAEngine, ETAOptions, ETAResult, GeofenceEvent, GeofenceEventType, GeofenceType, GeofencingEngine, GeofencingOptions, InstructionEditor, InstructionType, ParallelRoadResolver, ParallelRoadResolverOptions, ResolvedCandidate, RichInstruction, SnapCandidate, VoiceCue, VoicePriority, VoiceTriggerEngine, VoiceTriggerOptions, ZoneDefinition, calculateDynamicCorridor, computeDeadReckoningOnRoute } from './pro.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Module 5: BearingEngine
|
|
8
|
+
* Speed-adaptive IIR bearing smoothing.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Calculate speed-adaptive smoothing factor.
|
|
13
|
+
* Higher speed → less smoothing (alpha closer to 1).
|
|
14
|
+
* Lower speed → more smoothing (alpha closer to base value).
|
|
15
|
+
*/
|
|
16
|
+
declare function getSpeedAdaptiveAlpha(speedMps: number, baseAlpha?: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Compute bearing from the route geometry at the current segment.
|
|
19
|
+
*/
|
|
20
|
+
declare function calculateRobustBearing(route: Coordinate[], currentIdx: number, lookAhead?: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* Blend two bearings using the shortest angular path.
|
|
23
|
+
*/
|
|
24
|
+
declare function blendBearing(current: number, target: number, alpha: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Full bearing smoothing pipeline: route bearing → IIR blend → output.
|
|
27
|
+
*/
|
|
28
|
+
declare function applyBearingSmoothing(currentBearing: number, route: Coordinate[], routeIdx: number, speedMps: number, gpsBearing: number | null, baseAlpha?: number): number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Module 6: ProgressTracker
|
|
32
|
+
* Monotonic route progress tracking with anti-jitter.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Validate a progress update: ensures monotonic forward progress with jitter tolerance.
|
|
37
|
+
*
|
|
38
|
+
* @returns The new progress index (may be the same as current if update is rejected)
|
|
39
|
+
*/
|
|
40
|
+
declare function validateProgressUpdate(currentIdx: number, candidateIdx: number, route: Coordinate[], distToRoute: number, maxSnapDistance: number): number;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Module 8: RouteOffsetPredictor
|
|
44
|
+
* Linear distance-based position predictor for smooth rendering between GPS fixes.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Advance the predictor's offset by speed * dt.
|
|
49
|
+
*/
|
|
50
|
+
declare function advancePredictor(currentOffset: number, speedMps: number, dtSec: number): number;
|
|
51
|
+
/**
|
|
52
|
+
* Correct the predictor when a new GPS fix arrives.
|
|
53
|
+
* Blend towards the actual measured offset using betaCorrection.
|
|
54
|
+
*/
|
|
55
|
+
declare function applyGpsCorrection(predictedOffset: number, measuredOffset: number, betaCorrection?: number): number;
|
|
56
|
+
/**
|
|
57
|
+
* Given a linear offset (metres from route start), find the [lng, lat] on the route.
|
|
58
|
+
*
|
|
59
|
+
* @param offset Linear distance from route start in metres
|
|
60
|
+
* @param cumulativeDistances Forward cumulative distance array
|
|
61
|
+
* @param route Route coordinates
|
|
62
|
+
* @returns Interpolated coordinate on the route
|
|
63
|
+
*/
|
|
64
|
+
declare function pointAtOffset(offset: number, cumulativeDistances: Float64Array, route: Coordinate[]): Coordinate;
|
|
65
|
+
|
|
66
|
+
export { Coordinate, advancePredictor, applyBearingSmoothing, applyGpsCorrection, blendBearing, calculateRobustBearing, getSpeedAdaptiveAlpha, pointAtOffset, validateProgressUpdate };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,66 @@
|
|
|
1
|
-
|
|
1
|
+
import { C as Coordinate } from './NavCore.d-BuXR5DO7.js';
|
|
2
|
+
export { F as FEATURES, a as FeatureKey, L as LicenseManager, b as LicensePayload, c as LicenseStatus, d as LifecycleContext, e as LifecycleEvent, N as NavCore, f as NavCoreOptions, g as NavCoreState, h as NavGpsUpdate, i as NavInstruction, j as NavLifecycleState, k as NavigationFSM, O as OffRouteContext, l as OffRouteEvent, m as OffRouteFSM, n as OffRouteState, R as RejoinTarget, T as TempRoute, o as destinationPoint, p as geoGetBearing, q as haversineDistance, r as resolveNextInstruction } from './NavCore.d-BuXR5DO7.js';
|
|
2
3
|
export { BuildOptions, CameraOptions, Constants, CustomRouteBuilder, CustomWaypoint, DirectionsLeg, DirectionsManeuver, DirectionsOptions, DirectionsProvider, DirectionsResult, DirectionsStep, Kalman2DState, KalmanFilter2D, MapRendererAdapter, ORSConfig, ORSProfile, OSRMConfig, OSRMDirectionsProvider, OpenRouteServiceProvider, RouteSnapper, RouteStyle, SnapResult, SnapperOptions, ValhallaConfig, ValhallaCostingModel, ValhallaDirectionsProvider, VehicleStyle, WaypointOptions, buildForwardCumulativeDistances, buildReverseCumulativeDistances, getBearingBetweenPoints, interpolatePoint, kalmanUpdate2D, normalizeAngle, projectPointOnSegment } from './core.js';
|
|
3
|
-
export { DeadReckoningEngine, DeviationDetector, ETAEngine, ETAOptions, ETAResult, GeofenceEvent, GeofenceEventType, GeofenceType, GeofencingEngine, GeofencingOptions, InstructionEditor, InstructionType, ParallelRoadResolver, ParallelRoadResolverOptions, ResolvedCandidate, RichInstruction, SnapCandidate, VoiceCue, VoicePriority, VoiceTriggerEngine, VoiceTriggerOptions,
|
|
4
|
+
export { DeadReckoningEngine, DeviationDetector, ETAEngine, ETAOptions, ETAResult, GeofenceEvent, GeofenceEventType, GeofenceType, GeofencingEngine, GeofencingOptions, InstructionEditor, InstructionType, ParallelRoadResolver, ParallelRoadResolverOptions, ResolvedCandidate, RichInstruction, SnapCandidate, VoiceCue, VoicePriority, VoiceTriggerEngine, VoiceTriggerOptions, ZoneDefinition, calculateDynamicCorridor, computeDeadReckoningOnRoute } from './pro.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Module 5: BearingEngine
|
|
8
|
+
* Speed-adaptive IIR bearing smoothing.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Calculate speed-adaptive smoothing factor.
|
|
13
|
+
* Higher speed → less smoothing (alpha closer to 1).
|
|
14
|
+
* Lower speed → more smoothing (alpha closer to base value).
|
|
15
|
+
*/
|
|
16
|
+
declare function getSpeedAdaptiveAlpha(speedMps: number, baseAlpha?: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Compute bearing from the route geometry at the current segment.
|
|
19
|
+
*/
|
|
20
|
+
declare function calculateRobustBearing(route: Coordinate[], currentIdx: number, lookAhead?: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* Blend two bearings using the shortest angular path.
|
|
23
|
+
*/
|
|
24
|
+
declare function blendBearing(current: number, target: number, alpha: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Full bearing smoothing pipeline: route bearing → IIR blend → output.
|
|
27
|
+
*/
|
|
28
|
+
declare function applyBearingSmoothing(currentBearing: number, route: Coordinate[], routeIdx: number, speedMps: number, gpsBearing: number | null, baseAlpha?: number): number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Module 6: ProgressTracker
|
|
32
|
+
* Monotonic route progress tracking with anti-jitter.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Validate a progress update: ensures monotonic forward progress with jitter tolerance.
|
|
37
|
+
*
|
|
38
|
+
* @returns The new progress index (may be the same as current if update is rejected)
|
|
39
|
+
*/
|
|
40
|
+
declare function validateProgressUpdate(currentIdx: number, candidateIdx: number, route: Coordinate[], distToRoute: number, maxSnapDistance: number): number;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Module 8: RouteOffsetPredictor
|
|
44
|
+
* Linear distance-based position predictor for smooth rendering between GPS fixes.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Advance the predictor's offset by speed * dt.
|
|
49
|
+
*/
|
|
50
|
+
declare function advancePredictor(currentOffset: number, speedMps: number, dtSec: number): number;
|
|
51
|
+
/**
|
|
52
|
+
* Correct the predictor when a new GPS fix arrives.
|
|
53
|
+
* Blend towards the actual measured offset using betaCorrection.
|
|
54
|
+
*/
|
|
55
|
+
declare function applyGpsCorrection(predictedOffset: number, measuredOffset: number, betaCorrection?: number): number;
|
|
56
|
+
/**
|
|
57
|
+
* Given a linear offset (metres from route start), find the [lng, lat] on the route.
|
|
58
|
+
*
|
|
59
|
+
* @param offset Linear distance from route start in metres
|
|
60
|
+
* @param cumulativeDistances Forward cumulative distance array
|
|
61
|
+
* @param route Route coordinates
|
|
62
|
+
* @returns Interpolated coordinate on the route
|
|
63
|
+
*/
|
|
64
|
+
declare function pointAtOffset(offset: number, cumulativeDistances: Float64Array, route: Coordinate[]): Coordinate;
|
|
65
|
+
|
|
66
|
+
export { Coordinate, advancePredictor, applyBearingSmoothing, applyGpsCorrection, blendBearing, calculateRobustBearing, getSpeedAdaptiveAlpha, pointAtOffset, validateProgressUpdate };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
'use strict';var Ne=Object.defineProperty;var Pe=(s,e)=>{for(var t in e)Ne(s,t,{get:e[t],enumerable:true});};function m(s,e,t,n){let i=(t-s)*(Math.PI/180),r=(n-e)*(Math.PI/180),o=Math.sin(i/2)*Math.sin(i/2)+Math.cos(s*(Math.PI/180))*Math.cos(t*(Math.PI/180))*Math.sin(r/2)*Math.sin(r/2);return 6371e3*(2*Math.atan2(Math.sqrt(o),Math.sqrt(1-o)))}function V(s,e,t,n){let i=n/6371e3,r=t*(Math.PI/180),o=s*(Math.PI/180),c=e*(Math.PI/180),a=Math.asin(Math.sin(o)*Math.cos(i)+Math.cos(o)*Math.sin(i)*Math.cos(r));return [((c+Math.atan2(Math.sin(r)*Math.sin(i)*Math.cos(o),Math.cos(i)-Math.sin(o)*Math.sin(a)))*180/Math.PI+540)%360-180,a*180/Math.PI]}function we(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n),a=Math.atan2(o,c)*(180/Math.PI);return a=(a+360)%360,a}function y(s){let e=s%360;return e>180?e-360:e<-180?e+360:e}function f(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n);return (Math.atan2(o,c)*180/Math.PI+360)%360}function H(s,e,t){let n=(i,r,o)=>i+(r-i)*o;return [n(s[0],e[0],t),n(s[1],e[1],t)]}function W(s,e,t){let[n,i]=s,[r,o]=e,[c,a]=t,u=c-r,d=a-o,l=u*u+d*d;if(l===0)return e;let p=((n-r)*u+(i-o)*d)/l;return p=Math.max(0,Math.min(1,p)),[r+p*u,o+p*d]}function K(s){let e=new Float64Array(s.length);for(let t=1;t<s.length;t++)e[t]=e[t-1]+m(s[t-1][1],s[t-1][0],s[t][1],s[t][0]);return e}function j(s){let e=new Float64Array(s.length);for(let t=s.length-2;t>=0;t--)e[t]=e[t+1]+m(s[t][1],s[t][0],s[t+1][1],s[t+1][0]);return e}function me(s,e,t,n,i,r=1e-5,o=5e-5){s.x+=s.vx*i,s.y+=s.vy*i,s.P+=r;let c=o*Math.max(1,n/5),a=s.P/(s.P+c),u=e-s.x,d=t-s.y;return s.x+=a*u,s.y+=a*d,i>0&&(s.vx=u/i*a,s.vy=d/i*a),s.P=(1-a)*s.P,s}var M=class{constructor(e=1e-5,t=5e-5){this.lastTimestamp=0;this.Q=e,this.rBase=t,this.state={x:0,y:0,vx:0,vy:0,P:1};}init(e,t,n){this.state={x:e,y:t,vx:0,vy:0,P:1},this.lastTimestamp=n;}update(e,t,n,i){if(this.lastTimestamp===0)return this.init(e,t,i),[e,t];let r=Math.max(.001,(i-this.lastTimestamp)/1e3);return this.lastTimestamp=i,me(this.state,e,t,n,r,this.Q,this.rBase),[this.state.x,this.state.y]}getPosition(){return [this.state.x,this.state.y]}getState(){return {...this.state}}reset(){this.state={x:0,y:0,vx:0,vy:0,P:1},this.lastTimestamp=0;}};var ve={};Pe(ve,{ARRIVAL_THRESHOLD_METERS:()=>Ce,BASE_CORRIDOR_METERS:()=>L,BEARING_ALIGNMENT_THRESHOLD:()=>be,BEARING_MIN_SPEED_MPS:()=>z,BEARING_MISMATCH_PENALTY:()=>ye,BEARING_MISMATCH_THRESHOLD:()=>q,BEARING_SMOOTHING_ALPHA:()=>k,BETA_CORRECTION:()=>Ee,DETOUR_COMMIT_MS:()=>Ue,DR_MAX_AGE_MS:()=>Y,GPS_ACCURACY_FACTOR:()=>ge,GPS_AGE_CAP_SECONDS:()=>Se,GPS_STALE_MS:()=>Ie,INERTIA_PENALTY:()=>Re,INERTIA_SEGMENT_DIST:()=>xe,LOOK_AHEAD_SECONDS:()=>Ve,MANEUVER_TRIGGER_DIST:()=>Be,MAX_CORRIDOR_METERS:()=>$,MAX_LOOK_AHEAD_METERS:()=>We,MAX_SNAP_DISTANCE:()=>J,MIN_LOOK_AHEAD_METERS:()=>He,OFF_ROUTE_CONFIRM_MS:()=>Fe,REJOIN_CONFIRM_MS:()=>Ge,REJOIN_COOLDOWN_MS:()=>Le,SNAP_WINDOW_SIZE:()=>X,SPEED_CORRIDOR_FACTOR:()=>fe,STARTUP_GRACE_MS:()=>ke});var L=25,$=60,fe=1.2,ge=.5,J=80,q=90,ye=500,Re=200,xe=5,X=25,k=.3,z=1.5,be=55,Y=5e3,Fe=2e3,Ge=1500,Le=12e3,ke=3e3,Ue=4e3,Ie=3e3,Se=10,Be=25,Ee=.15,Ve=3,He=20,We=100,Ce=30;var Ke={useBearingPenalty:true,useInertiaPenalty:true,maxSnapDistance:80},T=class{constructor(e){this.options={...Ke,...e};}snap(e,t,n,i,r,o,c,a=null,u=null){let d=t.length,l=c,p=1/0,g=1/0,C=t[c]??[0,0];for(let x=0;x<=i;x++){let h=n+x;if(h>d-2)if(r&&o>d*.7)h=h%(d-1);else break;if(h<0||h>=d-1)continue;let b=t[h],R=t[h+1],S=W(e,b,R),v=m(e[1],e[0],S[1],S[0]);if(v>this.options.maxSnapDistance*2)continue;let I=v;if(this.options.useBearingPenalty&&a!==null){let _=f(b,R);Math.abs(y(a-_))>90&&(I+=500);}this.options.useInertiaPenalty&&u!==null&&Math.abs(h-u)>=5&&(I+=200),I<p&&(p=I,g=v,l=h,C=S);}return {idx:l,dist:g,proj:C}}};var je={bearingPenalty:80,bearingMismatchThresholdDeg:60,inertiaPenalty:40,inertiaSegmentDist:3},Q=class{constructor(e){this.options={...je,...e};}resolve(e,t=null,n=null){return e.map(i=>this.score(i,t,n)).sort((i,r)=>i.score-r.score)}resolveBest(e,t=null,n=null){return e.length===0?null:this.resolve(e,t,n)[0]??null}score(e,t,n){let i=e.distanceMetres,r=null,o=false;if(t!==null){let c=f(e.segA,e.segB),a=Math.abs(y(t-c));r=a,a>this.options.bearingMismatchThresholdDeg&&(i+=this.options.bearingPenalty);}return n!==null&&Math.abs(e.segmentIndex-n)>=this.options.inertiaSegmentDist&&(i+=this.options.inertiaPenalty,o=true),{...e,score:i,bearingDeltaDeg:r,inertiaPenaltyApplied:o}}isLikelyUTurn(e,t,n){let i=f(t,n);return Math.abs(y(e-i))>this.options.bearingMismatchThresholdDeg}};function Oe(s,e,t,n,i=5e3){if(!s||e<.5)return {predictedCoord:s?.coord??[0,0],isActive:false,ageMs:0};let r=n-s.ts;if(r>i||r<0)return {predictedCoord:s.coord,isActive:false,ageMs:r};let o=e*(r/1e3);return {predictedCoord:V(s.coord[1],s.coord[0],t,o),isActive:true,ageMs:r}}var D=class{constructor(e=5e3){this.anchor=null;this.maxAgeMs=e;}setAnchor(e,t,n){this.anchor={coord:e,idx:t,ts:n};}predict(e,t,n){return Oe(this.anchor,e,t,n,this.maxAgeMs)}clearAnchor(){this.anchor=null;}getAnchor(){return this.anchor}};function Ae(s,e,t,n,i=null){let r=Math.max(0,t),o=1/0,c=e[r]??[0,0],a=Math.min(t+n,e.length-1);for(let u=Math.max(0,t);u<a;u++){let d=e[u],l=e[u+1],[p,g]=s,[C,x]=d,[h,b]=l,R=h-C,S=b-x,v=R*R+S*S,I;if(v===0)I=d;else {let O=((p-C)*R+(g-x)*S)/v;O=Math.max(0,Math.min(1,O)),I=[C+O*R,x+O*S];}let _=m(s[1],s[0],I[1],I[0]);if(i!==null&&_<o*1.5){let O=f(d,l);if(Math.abs(y(i-O))>120)continue}_<o&&(o=_,r=u,c=I);}return {segmentIndex:r,distance:o,projection:c}}var N=class{evaluate(e,t,n,i,r,o,c){let a=i.distance>o,u=false;if(t!==null&&i.segmentIndex<r.length-1){let p=f(r[i.segmentIndex],r[i.segmentIndex+1]);u=Math.abs(y(t-p))>90;}let d=false;if(c!==null&&n>1.5){let p=r[Math.min(i.segmentIndex+2,r.length-1)];d=m(e[1],e[0],p[1],p[0])>c+5;}let l=a&&(u||d);return {distanceToRoute:i.distance,outsideCorridor:a,bearingMismatch:u,movingAway:d,confirmed:l}}};function Z(s,e=null,t=25,n=60,i=1.2,r=.5){let o=t+s*i;return e!==null&&e>0&&(o+=e*r),Math.min(o,n)}function _e(s,e=.3){return s<1.5?e*.5:s>20?Math.min(.9,e*2):e}function Me(s,e,t=3){let n=Math.min(e+t,s.length-1);return e>=s.length-1||e===n?e>0?f(s[e-1],s[e]):0:f(s[e],s[n])}function U(s,e,t){let n=y(e-s);return (s+t*n+360)%360}function ee(s,e,t,n,i,r=.3){let o=_e(n,r),c=Me(e,t);if(i!==null&&n>1.5){let a=U(s,i,o*.3);return U(a,c,o)}return U(s,c,o)}function te(s,e,t,n,i){return e<s||e>s+30||n>i?s:e}var $e=20,Je=60,qe=3;function ne(s,e,t,n,i,r,o,c=0){if(!e||e.length===0||t>=e.length)return {nextIdx:t,instruction:null,wasTriggered:false};let a=t;for(;a<e.length;){let h=e[a],b=s>h.geometryIndex+30,R=h.cumulativeOffset!==void 0&&o>h.cumulativeOffset+15;if(!b&&!R)break;a++;}if(a>=e.length)return {nextIdx:a,instruction:null,wasTriggered:false};let u=e[a],d=u.cumulativeOffset!==void 0?Math.max(0,u.cumulativeOffset-o):m(i[1],i[0],u.location[1],u.location[0]),l=Math.min(Je,Math.max($e,c*qe)),p=s<=u.geometryIndex+2,C=d<=l&&p,x=false;if(C){let h=true,b=u.bearingAfter??(u.geometryIndex<n.length-1?f(n[u.geometryIndex],n[u.geometryIndex+1]):null),R=u.bearingBefore??(u.geometryIndex>0?f(n[u.geometryIndex-1],n[u.geometryIndex]):null);R!==null&&b!==null&&r!==null&&Math.abs(y(b-R))>30&&Math.abs(y(r-b))>55&&(h=false),h&&(x=true);}return {nextIdx:a,instruction:u,wasTriggered:x}}var Xe=0;function P(){return `instr_${Date.now()}_${++Xe}`}var ie=class{constructor(){this.instructions=[];}addTurn(e,t,n,i){return this.instructions.push({id:P(),type:"turn",location:e,text:t,instruction:t,geometryIndex:n,silent:i?.silent,meta:i?.meta}),this}addExamPoint(e,t,n,i){return this.instructions.push({id:P(),type:"exam_point",location:e,text:t,instruction:t,geometryIndex:n,severity:i?.severity??"info",silent:i?.silent,meta:i?.meta}),this}addCheckpoint(e,t,n){return this.instructions.push({id:P(),type:"checkpoint",location:e,text:"",instruction:"",geometryIndex:t,silent:true,meta:n}),this}addDepart(e,t="Start navigation"){let n={id:P(),type:"depart",location:e,text:t,instruction:t,geometryIndex:0};return this.instructions.unshift(n),this}addArrive(e,t="You have arrived"){return this.instructions.push({id:P(),type:"arrive",location:e,text:t,instruction:t,geometryIndex:Number.MAX_SAFE_INTEGER}),this}update(e,t){let n=this.instructions.findIndex(i=>i.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions[n]={...this.instructions[n],...t},this}remove(e){let t=this.instructions.findIndex(n=>n.id===e);if(t===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions.splice(t,1),this}reorder(e,t){let n=this.instructions.findIndex(r=>r.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);let[i]=this.instructions.splice(n,1);return this.instructions.splice(Math.max(0,t),0,i),this}sort(){return this.instructions.sort((e,t)=>e.geometryIndex-t.geometryIndex),this}clear(){return this.instructions=[],this}attachToCumulative(e){if(e.length<2)return this;let t=[0];for(let n=1;n<e.length;n++){let i=e[n-1],r=e[n];t.push(t[n-1]+m(i[1],i[0],r[1],r[0]));}for(let n of this.instructions){let i=Math.min(n.geometryIndex,e.length-1);n.cumulativeOffset=t[i]??0,i>0&&i<e.length-1&&(n.bearingBefore=f(e[i-1],e[i]),n.bearingAfter=f(e[i],e[i+1]));}return this}toArray(){return this.instructions.map(({id:e,type:t,severity:n,meta:i,...r})=>r)}toRichArray(){return [...this.instructions]}get size(){return this.instructions.length}};function re(s,e,t){return s+e*t}function oe(s,e,t=.15){let n=e-s;return s+t*n}function ze(s,e,t){if(t.length===0)return [0,0];if(s<=0)return t[0];let n=e[e.length-1]??0;if(s>=n)return t[t.length-1];let i=0,r=e.length-1;for(;i<r-1;){let d=i+r>>1;e[d]<=s?i=d:r=d;}let o=e[i],a=e[r]-o;if(a===0)return t[i];let u=(s-o)/a;return H(t[i],t[r],u)}var w=class{constructor(){this._state="IDLE";this._context={resumeIndex:null};}get state(){return this._state}get context(){return {...this._context}}dispatch(e){switch(this._state){case "IDLE":e.type==="ROUTE_LOADED"&&(this._state="OVERVIEW"),e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "OVERVIEW":e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "APPROACHING_ROUTE":e.type==="ROUTE_JOINED"&&(this._state="ON_ROUTE",this._context.resumeIndex=e.data.index),e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE");break;case "ON_ROUTE":e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE"),e.type==="ROUTE_JOINED"&&(this._context.resumeIndex=e.data.index);break}return (e.type==="RESET"||e.type==="CANCEL_NAVIGATION")&&(this._state="IDLE",this._context={resumeIndex:null}),{state:this._state,context:{...this._context}}}reset(){this._state="IDLE",this._context={resumeIndex:null};}};var A={deviationSegmentIdx:null,deviationStartMs:null,tempRoute:null,rejoinTarget:null,lastRerouteMs:null,rejoinedAtMs:null,rejoinDwellFrames:0,failureReason:null},Te=2e3,Ye=3,F=class{constructor(){this._state="ON_ROUTE";this._context={...A};}get state(){return this._state}get context(){return {...this._context}}dispatch(e,t){let n=t??Date.now();switch(this._state){case "ON_ROUTE":e.type==="DEVIATION_SUSPECTED"&&(this._state="DEVIATING",this._context.deviationSegmentIdx=e.deviationSegmentIdx,this._context.deviationStartMs=n);break;case "DEVIATING":e.type==="DEVIATION_CONFIRMED"&&(this._context.deviationStartMs!==null?n-this._context.deviationStartMs:0)>=Te&&(this._state="OFF_ROUTE",this._context.deviationSegmentIdx=e.deviationSegmentIdx),(e.type==="RESUME"||e.type==="RESET")&&(this._state="ON_ROUTE",e.type==="RESET"?this._context={...A}:(this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null));break;case "OFF_ROUTE":e.type==="REROUTE_STARTED"&&(this._state="REROUTING",this._context.lastRerouteMs=n),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break;case "REROUTING":e.type==="REROUTE_SUCCESS"&&(this._state="REJOINING",this._context.tempRoute=e.tempRoute,this._context.rejoinTarget=e.rejoinTarget),e.type==="REROUTE_FAILED"&&(this._state="FAILED",this._context.failureReason=e.reason);break;case "REJOINING":e.type==="REJOIN_DETECTED"&&this._context.rejoinDwellFrames++,(e.type==="REJOIN_CONFIRMED"||this._context.rejoinDwellFrames>=Ye)&&(this._state="REJOINED",this._context.rejoinedAtMs=n,this._context.rejoinDwellFrames=0),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break;case "REJOINED":e.type==="RESUME"&&(this._state="ON_ROUTE",this._context.tempRoute=null,this._context.rejoinTarget=null,this._context.rejoinedAtMs=null,this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break;case "FAILED":e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break}return {state:this._state,context:{...this._context}}}reset(){this._state="ON_ROUTE",this._context={...A};}isDeviationConfirmed(e=Date.now()){return this._context.deviationStartMs?e-this._context.deviationStartMs>=Te:false}};var Qe=0;function De(){return `wp_${Date.now()}_${++Qe}`}var se=class{constructor(){this.waypoints=[];}addWaypoint(e,t){let n=De();return this.waypoints.push({id:n,coord:e,options:t}),n}insertWaypoint(e,t){let n=this.waypoints.findIndex(r=>r.id===t);if(n===-1)throw new Error(`Waypoint ${t} not found`);let i=De();return this.waypoints.splice(n+1,0,{id:i,coord:e,options:void 0}),i}removeWaypoint(e){let t=this.waypoints.findIndex(n=>n.id===e);if(t===-1)throw new Error(`Waypoint ${e} not found`);this.waypoints.splice(t,1);}moveWaypoint(e,t){let n=this.waypoints.find(i=>i.id===e);if(!n)throw new Error(`Waypoint ${e} not found`);n.coord=t;}getWaypoints(){return this.waypoints}get size(){return this.waypoints.length}chunk(e="OVERLAP_1",t=25){let n=this.waypoints.map(c=>c.coord);if(n.length<=t)return [n];let r=t-(e==="OVERLAP_2"?2:1),o=[];for(let c=0;c<n.length;c+=r){let a=n.slice(c,c+t);if(o.push(a),c+t>=n.length)break}return o}buildStraightLine(){return {geometry:this.waypoints.map(e=>e.coord),waypoints:[...this.waypoints]}}fromGPX(e){this.waypoints=[];let t=/<(?:trkpt|wpt|rtept)\s+lat="([^"]+)"\s+lon="([^"]+)"/g,n;for(;(n=t.exec(e))!==null;){let i=parseFloat(n[1]),r=parseFloat(n[2]);isFinite(i)&&isFinite(r)&&this.addWaypoint([r,i]);}}toGPX(){return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1
|
+
'use strict';var Ne=Object.defineProperty;var Pe=(s,e)=>{for(var t in e)Ne(s,t,{get:e[t],enumerable:true});};function y(s,e,t,n){let i=(t-s)*(Math.PI/180),r=(n-e)*(Math.PI/180),o=Math.sin(i/2)*Math.sin(i/2)+Math.cos(s*(Math.PI/180))*Math.cos(t*(Math.PI/180))*Math.sin(r/2)*Math.sin(r/2);return 6371e3*(2*Math.atan2(Math.sqrt(o),Math.sqrt(1-o)))}function B(s,e,t,n){let i=n/6371e3,r=t*(Math.PI/180),o=s*(Math.PI/180),c=e*(Math.PI/180),a=Math.asin(Math.sin(o)*Math.cos(i)+Math.cos(o)*Math.sin(i)*Math.cos(r));return [((c+Math.atan2(Math.sin(r)*Math.sin(i)*Math.cos(o),Math.cos(i)-Math.sin(o)*Math.sin(a)))*180/Math.PI+540)%360-180,a*180/Math.PI]}function we(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n),a=Math.atan2(o,c)*(180/Math.PI);return a=(a+360)%360,a}function E(s){let e=s%360;return e>180?e-360:e<-180?e+360:e}function R(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n);return (Math.atan2(o,c)*180/Math.PI+360)%360}function W(s,e,t){let n=(i,r,o)=>i+(r-i)*o;return [n(s[0],e[0],t),n(s[1],e[1],t)]}function H(s,e,t){let[n,i]=s,[r,o]=e,[c,a]=t,u=c-r,d=a-o,l=u*u+d*d;if(l===0)return e;let p=((n-r)*u+(i-o)*d)/l;return p=Math.max(0,Math.min(1,p)),[r+p*u,o+p*d]}function K(s){let e=new Float64Array(s.length);for(let t=1;t<s.length;t++)e[t]=e[t-1]+y(s[t-1][1],s[t-1][0],s[t][1],s[t][0]);return e}function j(s){let e=new Float64Array(s.length);for(let t=s.length-2;t>=0;t--)e[t]=e[t+1]+y(s[t][1],s[t][0],s[t+1][1],s[t+1][0]);return e}function me(s,e,t,n,i,r=1e-5,o=5e-5){s.x+=s.vx*i,s.y+=s.vy*i,s.P+=r;let c=o*Math.max(1,n/5),a=s.P/(s.P+c),u=e-s.x,d=t-s.y;return s.x+=a*u,s.y+=a*d,i>0&&(s.vx=u/i*a,s.vy=d/i*a),s.P=(1-a)*s.P,s}var D=class{constructor(e=1e-5,t=5e-5){this.lastTimestamp=0;this.Q=e,this.rBase=t,this.state={x:0,y:0,vx:0,vy:0,P:1};}init(e,t,n){this.state={x:e,y:t,vx:0,vy:0,P:1},this.lastTimestamp=n;}update(e,t,n,i){if(this.lastTimestamp===0)return this.init(e,t,i),[e,t];let r=Math.max(.001,(i-this.lastTimestamp)/1e3);return this.lastTimestamp=i,me(this.state,e,t,n,r,this.Q,this.rBase),[this.state.x,this.state.y]}getPosition(){return [this.state.x,this.state.y]}getState(){return {...this.state}}reset(){this.state={x:0,y:0,vx:0,vy:0,P:1},this.lastTimestamp=0;}};var Se={};Pe(Se,{ARRIVAL_THRESHOLD_METERS:()=>Ce,BASE_CORRIDOR_METERS:()=>k,BEARING_ALIGNMENT_THRESHOLD:()=>xe,BEARING_MIN_SPEED_MPS:()=>z,BEARING_MISMATCH_PENALTY:()=>ye,BEARING_MISMATCH_THRESHOLD:()=>J,BEARING_SMOOTHING_ALPHA:()=>U,BETA_CORRECTION:()=>be,DETOUR_COMMIT_MS:()=>Ue,DR_MAX_AGE_MS:()=>Y,GPS_ACCURACY_FACTOR:()=>ge,GPS_AGE_CAP_SECONDS:()=>ve,GPS_STALE_MS:()=>Ie,INERTIA_PENALTY:()=>Re,INERTIA_SEGMENT_DIST:()=>Ee,LOOK_AHEAD_SECONDS:()=>Be,MANEUVER_TRIGGER_DIST:()=>Ve,MAX_CORRIDOR_METERS:()=>$,MAX_LOOK_AHEAD_METERS:()=>He,MAX_SNAP_DISTANCE:()=>q,MIN_LOOK_AHEAD_METERS:()=>We,OFF_ROUTE_CONFIRM_MS:()=>Fe,REJOIN_CONFIRM_MS:()=>Ge,REJOIN_COOLDOWN_MS:()=>Le,SNAP_WINDOW_SIZE:()=>X,SPEED_CORRIDOR_FACTOR:()=>fe,STARTUP_GRACE_MS:()=>ke});var k=25,$=60,fe=1.2,ge=.5,q=80,J=90,ye=500,Re=200,Ee=5,X=25,U=.3,z=1.5,xe=55,Y=5e3,Fe=2e3,Ge=1500,Le=12e3,ke=3e3,Ue=4e3,Ie=3e3,ve=10,Ve=25,be=.15,Be=3,We=20,He=100,Ce=30;var Ke={useBearingPenalty:true,useInertiaPenalty:true,maxSnapDistance:80},N=class{constructor(e){this.options={...Ke,...e};}snap(e,t,n,i,r,o,c,a=null,u=null){let d=t.length,l=c,p=1/0,f=1/0,I=t[c]??[0,0];for(let v=0;v<=i;v++){let g=n+v;if(g>d-2)if(r&&o>d*.7)g=g%(d-1);else break;if(g<0||g>=d-1)continue;let b=t[g],x=t[g+1],S=H(e,b,x),O=y(e[1],e[0],S[1],S[0]);if(O>this.options.maxSnapDistance*2)continue;let C=O;if(this.options.useBearingPenalty&&a!==null){let T=R(b,x);Math.abs(E(a-T))>90&&(C+=500);}this.options.useInertiaPenalty&&u!==null&&Math.abs(g-u)>=5&&(C+=200),C<p&&(p=C,f=O,l=g,I=S);}return {idx:l,dist:f,proj:I}}};var h={GPS_SMOOTHING:"gps_smoothing",BASIC_SNAPPING:"basic_snapping",PROGRESS_TRACKING:"progress_tracking",ROUTE_OFFSET:"route_offset",DEAD_RECKONING:"dead_reckoning",ADVANCED_BEARING:"advanced_bearing",COMPOUND_DEVIATION:"compound_deviation",PARALLEL_ROAD_RESOLUTION:"parallel_road_resolution",U_TURN_PROTECTION:"u_turn_protection",VOICE_TRIGGERS:"voice_triggers",ETA:"eta",GEOFENCING:"geofencing",NAV_AI:"nav_ai"};var A=class A{constructor(e){this.status="MISSING";this.payload=null;this.enabledFeatures=new Set;this.warnedFeatures=new Set;e&&(this.tryValidateSync(e)||this.validate(e)),this.promoteToActive();}static getActive(){return A.activeManager}static clearActive(){A.activeManager=null;}promoteToActive(){let e=A.activeManager;(e===null||e.status!=="VALID"||this.status==="VALID")&&(A.activeManager=this);}tryValidateSync(e){return e==="eyJ0IjoicHJvIiwiZXhwIjo0OTMyNzAzMTU2MDAwLCJiaWQiOiJkZXYuYnlwYXNzIiwiZiI6WyIqIl19.MEQCIH4E4QNu9PuVsXHSnYmcqpCLk4QitiIH9hhY0Zm+YO5gAiAE7X3c47YQLUj7WPSGKw9Y7W2kBUR5GCnOMBwdBsYGgg=="?typeof __DEV__<"u"&&__DEV__||typeof window<"u"&&(window.location?.hostname==="localhost"||window.location?.hostname==="127.0.0.1"||window.location?.hostname?.startsWith("192.168.")||window.location?.hostname?.endsWith(".local"))||typeof process<"u"&&(process.env?.NODE_ENV==="development"||process.env?.NODE_ENV==="test"||process.env?.VITEST==="true"||process.env?.JEST_WORKER_ID!==void 0)?(this.status="VALID",this.payload={t:"pro",exp:4932703156e3,bid:"dev.bypass",f:["*"]},this.extractFeatures(),console.log("\u{1F511} [NavCore] Development bypass key validated synchronously. Plan: pro"),true):(console.warn("[NavCore] Development bypass key is restricted to local development environments."),this.status="INVALID",this.payload=null,true):false}async validate(e){if(this.tryValidateSync(e))return this.status;try{let[t,n]=e.split(".");if(!t||!n)return this.status="INVALID",this.status;let i=atob(t);if(this.payload=JSON.parse(i),!this.payload||this.payload.exp<Date.now())return this.status="EXPIRED",this.status;if(!await this.verifySignature(t,n))return this.status="INVALID",this.status;if(this.payload?.bid==="dev.bypass"&&!(typeof __DEV__<"u"&&__DEV__||typeof window<"u"&&(window.location?.hostname==="localhost"||window.location?.hostname==="127.0.0.1"||window.location?.hostname?.startsWith("192.168.")||window.location?.hostname?.endsWith(".local"))||typeof process<"u"&&(process.env?.NODE_ENV==="development"||process.env?.NODE_ENV==="test"||process.env?.VITEST==="true"||process.env?.JEST_WORKER_ID!==void 0)))return console.warn("[NavCore] Development bypass key is restricted to local development environments."),this.status="INVALID",this.payload=null,this.status;this.status="VALID",this.extractFeatures(),this.promoteToActive(),console.log(`\u{1F511} [NavCore] License validation complete. Plan: ${this.isProEnabled()?"pro":"core"}`);}catch{this.status="INVALID";}return this.status}extractFeatures(){if(this.enabledFeatures.clear(),!!this.payload){if(Array.isArray(this.payload.f))for(let e of this.payload.f)this.enabledFeatures.add(e);this.payload.t==="pro"&&this.enabledFeatures.add("*");}}hasFeature(e){return this.status!=="VALID"?false:this.enabledFeatures.has("*")?true:this.enabledFeatures.has(e)}warnOnce(e){this.warnedFeatures.has(e)||(console.warn(`[NavCore] Feature '${e}' requires a Pro license`),this.warnedFeatures.add(e));}isProEnabled(){return this.hasFeature("*")}isAIEnabled(){return this.hasFeature(h.NAV_AI)}getStatus(){return this.status}getPayload(){return this.payload}getEnabledFeatures(){return Array.from(this.enabledFeatures)}async verifySignature(e,t){try{if(typeof crypto>"u"||!crypto.subtle)return !1;let i=new TextEncoder().encode(e),r=Uint8Array.from(atob(t),a=>a.charCodeAt(0)),o=Uint8Array.from(atob(A.PUBLIC_KEY_SPKI),a=>a.charCodeAt(0)),c=await crypto.subtle.importKey("spki",o,{name:"ECDSA",namedCurve:"P-256"},!0,["verify"]);return await crypto.subtle.verify({name:"ECDSA",hash:{name:"SHA-256"}},c,r,i)}catch{return false}}};A.activeManager=null,A.PUBLIC_KEY_SPKI="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk6onJmJkWtRFusiSS69dcdONX4xL2Snm4AZO+dYjSynfJiL4x7trEy80MImLftknBWT/qI0z7ox4Q7VNL3te6A==";var m=A;var je={bearingPenalty:80,bearingMismatchThresholdDeg:60,inertiaPenalty:40,inertiaSegmentDist:3},Q=class{constructor(e){this.warned=false;this.options={...je,...e};}resolve(e,t=null,n=null){let i=m.getActive();return (!i||!i.isProEnabled())&&(this.warned||(console.warn("[NavCore] ParallelRoadResolver and U-turn protection require a Pro license. Falling back to core distance snapping."),this.warned=true)),e.map(r=>this.score(r,t,n)).sort((r,o)=>r.score-o.score)}resolveBest(e,t=null,n=null){return e.length===0?null:this.resolve(e,t,n)[0]??null}score(e,t,n){let i=e.distanceMetres,r=null,o=false,c=m.getActive(),a=c&&c.isProEnabled();if(t!==null&&a){let u=R(e.segA,e.segB),d=Math.abs(E(t-u));r=d,d>this.options.bearingMismatchThresholdDeg&&(i+=this.options.bearingPenalty);}return n!==null&&a&&Math.abs(e.segmentIndex-n)>=this.options.inertiaSegmentDist&&(i+=this.options.inertiaPenalty,o=true),{...e,score:i,bearingDeltaDeg:r,inertiaPenaltyApplied:o}}isLikelyUTurn(e,t,n){let i=R(t,n);return Math.abs(E(e-i))>this.options.bearingMismatchThresholdDeg}};function Ae(s,e,t,n,i=5e3){if(!s||e<.5)return {predictedCoord:s?.coord??[0,0],isActive:false,ageMs:0};let r=n-s.ts;if(r>i||r<0)return {predictedCoord:s.coord,isActive:false,ageMs:r};let o=e*(r/1e3);return {predictedCoord:B(s.coord[1],s.coord[0],t,o),isActive:true,ageMs:r}}var P=class{constructor(e=5e3){this.anchor=null;this.warned=false;this.maxAgeMs=e;}setAnchor(e,t,n){this.anchor={coord:e,idx:t,ts:n};}predict(e,t,n){let i=m.getActive();return !i||!i.hasFeature(h.DEAD_RECKONING)?(this.warned||(i?i.warnOnce(h.DEAD_RECKONING):console.warn(`[NavCore] Feature '${h.DEAD_RECKONING}' requires a Pro license`),this.warned=true),{predictedCoord:this.anchor?.coord??[0,0],isActive:false,ageMs:0}):(this.warned=false,Ae(this.anchor,e,t,n,this.maxAgeMs))}clearAnchor(){this.anchor=null;}getAnchor(){return this.anchor}};function Oe(s,e,t,n,i=null){let r=Math.max(0,t),o=1/0,c=e[r]??[0,0],a=Math.min(t+n,e.length-1);for(let u=Math.max(0,t);u<a;u++){let d=e[u],l=e[u+1],[p,f]=s,[I,v]=d,[g,b]=l,x=g-I,S=b-v,O=x*x+S*S,C;if(O===0)C=d;else {let _=((p-I)*x+(f-v)*S)/O;_=Math.max(0,Math.min(1,_)),C=[I+_*x,v+_*S];}let T=y(s[1],s[0],C[1],C[0]);if(i!==null&&T<o*1.5){let _=R(d,l);if(Math.abs(E(i-_))>120)continue}T<o&&(o=T,r=u,c=C);}return {segmentIndex:r,distance:o,projection:c}}var w=class{constructor(){this.warned=false;}evaluate(e,t,n,i,r,o,c){let a=m.getActive();if(!a||!a.hasFeature(h.COMPOUND_DEVIATION))return this.warned||(a?a.warnOnce(h.COMPOUND_DEVIATION):console.warn(`[NavCore] Feature '${h.COMPOUND_DEVIATION}' requires a Pro license`),this.warned=true),{distanceToRoute:i.distance,outsideCorridor:false,bearingMismatch:false,movingAway:false,confirmed:false};this.warned=false;let u=i.distance>o,d=false;if(t!==null&&i.segmentIndex<r.length-1){let f=R(r[i.segmentIndex],r[i.segmentIndex+1]);d=Math.abs(E(t-f))>90;}let l=false;if(c!==null&&n>1.5){let f=r[Math.min(i.segmentIndex+2,r.length-1)];l=y(e[1],e[0],f[1],f[0])>c+5;}let p=u&&(d||l);return {distanceToRoute:i.distance,outsideCorridor:u,bearingMismatch:d,movingAway:l,confirmed:p}}};function Z(s,e=null,t=25,n=60,i=1.2,r=.5){let o=t+s*i;return e!==null&&e>0&&(o+=e*r),Math.min(o,n)}function _e(s,e=.3){return s<1.5?e*.5:s>20?Math.min(.9,e*2):e}function Me(s,e,t=3){let n=Math.min(e+t,s.length-1);return e>=s.length-1||e===n?e>0?R(s[e-1],s[e]):0:R(s[e],s[n])}function V(s,e,t){let n=E(e-s);return (s+t*n+360)%360}function ee(s,e,t,n,i,r=.3){let o=_e(n,r),c=Me(e,t);if(i!==null&&n>1.5){let a=V(s,i,o*.3);return V(a,c,o)}return V(s,c,o)}function te(s,e,t,n,i){return e<s||e>s+30||n>i?s:e}var $e=20,qe=60,Je=3;function ne(s,e,t,n,i,r,o,c=0){if(!e||e.length===0||t>=e.length)return {nextIdx:t,instruction:null,wasTriggered:false};let a=t;for(;a<e.length;){let g=e[a],b=s>g.geometryIndex+30,x=g.cumulativeOffset!==void 0&&o>g.cumulativeOffset+15;if(!b&&!x)break;a++;}if(a>=e.length)return {nextIdx:a,instruction:null,wasTriggered:false};let u=e[a],d=u.cumulativeOffset!==void 0?Math.max(0,u.cumulativeOffset-o):y(i[1],i[0],u.location[1],u.location[0]),l=Math.min(qe,Math.max($e,c*Je)),p=s<=u.geometryIndex+2,I=d<=l&&p,v=false;if(I){let g=true,b=u.bearingAfter??(u.geometryIndex<n.length-1?R(n[u.geometryIndex],n[u.geometryIndex+1]):null),x=u.bearingBefore??(u.geometryIndex>0?R(n[u.geometryIndex-1],n[u.geometryIndex]):null);x!==null&&b!==null&&r!==null&&Math.abs(E(b-x))>30&&Math.abs(E(r-b))>55&&(g=false),g&&(v=true);}return {nextIdx:a,instruction:u,wasTriggered:v}}var Xe=0;function F(){return `instr_${Date.now()}_${++Xe}`}var ie=class{constructor(){this.instructions=[];}addTurn(e,t,n,i){return this.instructions.push({id:F(),type:"turn",location:e,text:t,instruction:t,geometryIndex:n,silent:i?.silent,meta:i?.meta}),this}addExamPoint(e,t,n,i){return this.instructions.push({id:F(),type:"exam_point",location:e,text:t,instruction:t,geometryIndex:n,severity:i?.severity??"info",silent:i?.silent,meta:i?.meta}),this}addCheckpoint(e,t,n){return this.instructions.push({id:F(),type:"checkpoint",location:e,text:"",instruction:"",geometryIndex:t,silent:true,meta:n}),this}addDepart(e,t="Start navigation"){let n={id:F(),type:"depart",location:e,text:t,instruction:t,geometryIndex:0};return this.instructions.unshift(n),this}addArrive(e,t="You have arrived"){return this.instructions.push({id:F(),type:"arrive",location:e,text:t,instruction:t,geometryIndex:Number.MAX_SAFE_INTEGER}),this}update(e,t){let n=this.instructions.findIndex(i=>i.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions[n]={...this.instructions[n],...t},this}remove(e){let t=this.instructions.findIndex(n=>n.id===e);if(t===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions.splice(t,1),this}reorder(e,t){let n=this.instructions.findIndex(r=>r.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);let[i]=this.instructions.splice(n,1);return this.instructions.splice(Math.max(0,t),0,i),this}sort(){return this.instructions.sort((e,t)=>e.geometryIndex-t.geometryIndex),this}clear(){return this.instructions=[],this}attachToCumulative(e){let t=m.getActive();if(!t||!t.isProEnabled())return console.warn("[NavCore] InstructionEditor requires a Pro license. Fluent editing is disabled."),this;if(e.length<2)return this;let n=[0];for(let i=1;i<e.length;i++){let r=e[i-1],o=e[i];n.push(n[i-1]+y(r[1],r[0],o[1],o[0]));}for(let i of this.instructions){let r=Math.min(i.geometryIndex,e.length-1);i.cumulativeOffset=n[r]??0,r>0&&r<e.length-1&&(i.bearingBefore=R(e[r-1],e[r]),i.bearingAfter=R(e[r],e[r+1]));}return this}toArray(){let e=m.getActive();return !e||!e.isProEnabled()?(console.warn("[NavCore] InstructionEditor.toArray() requires a Pro license. Returning empty instruction set."),[]):this.instructions.map(({id:t,type:n,severity:i,meta:r,...o})=>o)}toRichArray(){return [...this.instructions]}get size(){return this.instructions.length}};function re(s,e,t){return s+e*t}function oe(s,e,t=.15){let n=e-s;return s+t*n}function ze(s,e,t){if(t.length===0)return [0,0];if(s<=0)return t[0];let n=e[e.length-1]??0;if(s>=n)return t[t.length-1];let i=0,r=e.length-1;for(;i<r-1;){let d=i+r>>1;e[d]<=s?i=d:r=d;}let o=e[i],a=e[r]-o;if(a===0)return t[i];let u=(s-o)/a;return W(t[i],t[r],u)}var G=class{constructor(){this._state="IDLE";this._context={resumeIndex:null};}get state(){return this._state}get context(){return {...this._context}}dispatch(e){switch(this._state){case "IDLE":e.type==="ROUTE_LOADED"&&(this._state="OVERVIEW"),e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "OVERVIEW":e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "APPROACHING_ROUTE":e.type==="ROUTE_JOINED"&&(this._state="ON_ROUTE",this._context.resumeIndex=e.data.index),e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE");break;case "ON_ROUTE":e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE"),e.type==="ROUTE_JOINED"&&(this._context.resumeIndex=e.data.index);break}return (e.type==="RESET"||e.type==="CANCEL_NAVIGATION")&&(this._state="IDLE",this._context={resumeIndex:null}),{state:this._state,context:{...this._context}}}reset(){this._state="IDLE",this._context={resumeIndex:null};}};var M={deviationSegmentIdx:null,deviationStartMs:null,tempRoute:null,rejoinTarget:null,lastRerouteMs:null,rejoinedAtMs:null,rejoinDwellFrames:0,failureReason:null},Te=2e3,Ye=3,L=class{constructor(){this._state="ON_ROUTE";this._context={...M};}get state(){return this._state}get context(){return {...this._context}}dispatch(e,t){let n=t??Date.now();switch(this._state){case "ON_ROUTE":e.type==="DEVIATION_SUSPECTED"&&(this._state="DEVIATING",this._context.deviationSegmentIdx=e.deviationSegmentIdx,this._context.deviationStartMs=n);break;case "DEVIATING":e.type==="DEVIATION_CONFIRMED"&&(this._context.deviationStartMs!==null?n-this._context.deviationStartMs:0)>=Te&&(this._state="OFF_ROUTE",this._context.deviationSegmentIdx=e.deviationSegmentIdx),(e.type==="RESUME"||e.type==="RESET")&&(this._state="ON_ROUTE",e.type==="RESET"?this._context={...M}:(this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null));break;case "OFF_ROUTE":e.type==="REROUTE_STARTED"&&(this._state="REROUTING",this._context.lastRerouteMs=n),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break;case "REROUTING":e.type==="REROUTE_SUCCESS"&&(this._state="REJOINING",this._context.tempRoute=e.tempRoute,this._context.rejoinTarget=e.rejoinTarget),e.type==="REROUTE_FAILED"&&(this._state="FAILED",this._context.failureReason=e.reason);break;case "REJOINING":e.type==="REJOIN_DETECTED"&&this._context.rejoinDwellFrames++,(e.type==="REJOIN_CONFIRMED"||this._context.rejoinDwellFrames>=Ye)&&(this._state="REJOINED",this._context.rejoinedAtMs=n,this._context.rejoinDwellFrames=0),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break;case "REJOINED":e.type==="RESUME"&&(this._state="ON_ROUTE",this._context.tempRoute=null,this._context.rejoinTarget=null,this._context.rejoinedAtMs=null,this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break;case "FAILED":e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break}return {state:this._state,context:{...this._context}}}reset(){this._state="ON_ROUTE",this._context={...M};}isDeviationConfirmed(e=Date.now()){return this._context.deviationStartMs?e-this._context.deviationStartMs>=Te:false}};var Qe=0;function De(){return `wp_${Date.now()}_${++Qe}`}var se=class{constructor(){this.waypoints=[];}addWaypoint(e,t){let n=De();return this.waypoints.push({id:n,coord:e,options:t}),n}insertWaypoint(e,t){let n=this.waypoints.findIndex(r=>r.id===t);if(n===-1)throw new Error(`Waypoint ${t} not found`);let i=De();return this.waypoints.splice(n+1,0,{id:i,coord:e,options:void 0}),i}removeWaypoint(e){let t=this.waypoints.findIndex(n=>n.id===e);if(t===-1)throw new Error(`Waypoint ${e} not found`);this.waypoints.splice(t,1);}moveWaypoint(e,t){let n=this.waypoints.find(i=>i.id===e);if(!n)throw new Error(`Waypoint ${e} not found`);n.coord=t;}getWaypoints(){return this.waypoints}get size(){return this.waypoints.length}chunk(e="OVERLAP_1",t=25){let n=this.waypoints.map(c=>c.coord);if(n.length<=t)return [n];let r=t-(e==="OVERLAP_2"?2:1),o=[];for(let c=0;c<n.length;c+=r){let a=n.slice(c,c+t);if(o.push(a),c+t>=n.length)break}return o}buildStraightLine(){return {geometry:this.waypoints.map(e=>e.coord),waypoints:[...this.waypoints]}}fromGPX(e){this.waypoints=[];let t=/<(?:trkpt|wpt|rtept)\s+lat="([^"]+)"\s+lon="([^"]+)"/g,n;for(;(n=t.exec(e))!==null;){let i=parseFloat(n[1]),r=parseFloat(n[2]);isFinite(i)&&isFinite(r)&&this.addWaypoint([r,i]);}}toGPX(){return `<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<gpx version="1.1" creator="NavCore SDK">
|
|
3
3
|
${this.waypoints.map(t=>` <wpt lat="${t.coord[1]}" lon="${t.coord[0]}">`+(t.options?.name?`
|
|
4
4
|
<name>${t.options.name}</name>`:"")+`
|
|
5
5
|
</wpt>`).join(`
|
|
6
6
|
`)}
|
|
7
|
-
</gpx>`}fromGeoJSON(e){if(this.waypoints=[],e.type==="FeatureCollection"&&e.features){for(let t of e.features)if(t.geometry.type==="Point"){let n=t.geometry.coordinates;this.addWaypoint(n);}else if(t.geometry.type==="LineString"){let n=t.geometry.coordinates;for(let i of n)this.addWaypoint(i);}}}toGeoJSON(){let e=this.waypoints.map((n,i)=>({type:"Feature",geometry:{type:"Point",coordinates:n.coord},properties:{id:n.id,order:i,name:n.options?.name??null,silent:n.options?.silent??false}})),t={type:"Feature",geometry:{type:"LineString",coordinates:this.waypoints.map(n=>n.coord)},properties:{type:"route"}};return {type:"FeatureCollection",features:[...e,t]}}clear(){this.waypoints=[];}};var ae=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),profile:e.profile??"driving",maxWaypointsPerChunk:e.maxWaypointsPerChunk??100};}async getRoute(e,t){if(e.length<2)throw new Error("[OSRM] At least 2 waypoints required");let n=t?.profile??this.config.profile;return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}async fetchRoute(e,t,n){let i=e.map(d=>`${d[0]},${d[1]}`).join(";"),r=n?.steps!==false?"true":"false",o=`${this.config.baseUrl}/route/v1/${t}/${i}?overview=full&geometries=geojson&steps=${r}&annotations=false`,c=await fetch(o);if(!c.ok)throw new Error(`[OSRM] HTTP ${c.status}: ${c.statusText}`);let a=await c.json();if(a.code!=="Ok"||!a.routes?.length)throw new Error(`[OSRM] No route found: ${a.code}`);let u=a.routes[0];return {geometry:u.geometry.coordinates,distance:u.distance,duration:u.duration,legs:(u.legs??[]).map(d=>({distance:d.distance,duration:d.duration,steps:(d.steps??[]).map(l=>({distance:l.distance,duration:l.duration,geometry:l.geometry?.coordinates??[],maneuver:{type:l.maneuver?.type??"unknown",modifier:l.maneuver?.modifier,location:l.maneuver?.location??[0,0],bearingBefore:l.maneuver?.bearing_before??0,bearingAfter:l.maneuver?.bearing_after??0,instruction:l.name??void 0},name:l.name}))})),raw:a}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var ce=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),costing:e.costing??"auto",apiKey:e.apiKey??"",maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[Valhalla] At least 2 waypoints required");let n=this.profileToCosting(t?.profile);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileToCosting(e){switch(e){case "cycling":return "bicycle";case "walking":return "pedestrian";default:return this.config.costing}}async fetchRoute(e,t,n){let i=e.map(p=>({lon:p[0],lat:p[1],type:"break"})),r=JSON.stringify({locations:i,costing:t,directions_options:{units:"kilometers"}}),o={"Content-Type":"application/json"};this.config.apiKey&&(o.api_key=this.config.apiKey);let c=await fetch(`${this.config.baseUrl}/route`,{method:"POST",headers:o,body:r});if(!c.ok){let p=await c.text();throw new Error(`[Valhalla] HTTP ${c.status}: ${p}`)}let a=await c.json(),u=this.decodePolyline(a.trip?.legs?.[0]?.shape??""),d=a.trip?.summary??{},l=(a.trip?.legs??[]).map(p=>({distance:(p.summary?.length??0)*1e3,duration:p.summary?.time??0,steps:(p.maneuvers??[]).map(g=>({distance:(g.length??0)*1e3,duration:g.time??0,geometry:[],maneuver:{type:g.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:g.begin_heading??0,bearingAfter:g.end_heading??0,instruction:g.instruction},name:g.street_names?.[0]}))}));return {geometry:u,distance:(d.length??0)*1e3,duration:d.time??0,legs:l,raw:a}}decodePolyline(e,t=6){let n=Math.pow(10,t),i=[],r=0,o=0,c=0;for(;r<e.length;){let a=0,u=0,d;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let l=(u&1)!==0?~(u>>1):u>>1;o+=l,a=0,u=0;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let p=(u&1)!==0?~(u>>1):u>>1;c+=p,i.push([c/n,o/n]);}return i}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var Ze="https://api.openrouteservice.org/v2/directions";var le=class{constructor(e){this.config={apiKey:e.apiKey,profile:e.profile??"driving-car",baseUrl:e.baseUrl??Ze,maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[ORS] At least 2 waypoints required");let n=this.profileFromOptions(t);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileFromOptions(e){switch(e?.profile){case "cycling":return "cycling-regular";case "walking":return "foot-walking";default:return this.config.profile}}async fetchRoute(e,t,n){let i=JSON.stringify({coordinates:e,instructions:n?.steps!==false,language:n?.language??"en"}),r=await fetch(`${this.config.baseUrl}/${t}/geojson`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:this.config.apiKey},body:i});if(!r.ok){let l=await r.text();throw new Error(`[ORS] HTTP ${r.status}: ${l}`)}let o=await r.json(),c=o.features?.[0];if(!c)throw new Error("[ORS] No route returned");let a=c.properties?.summary??{},d=(c.properties?.segments??[]).map(l=>({distance:l.distance??0,duration:l.duration??0,steps:(l.steps??[]).map(p=>({distance:p.distance??0,duration:p.duration??0,geometry:[],maneuver:{type:p.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:0,bearingAfter:0,instruction:p.instruction},name:p.name}))}));return {geometry:c.geometry?.coordinates??[],distance:a.distance??0,duration:a.duration??0,legs:d,raw:o}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var et={earlyTriggerMeters:120,lateTriggerMeters:20,reannounceMeters:300},ue=class{constructor(e){this.instructions=[];this.triggeredIds=new Set;this.reannouncedIds=new Set;this.options={...et,...e};}setInstructions(e){this.instructions=[...e],this.triggeredIds.clear(),this.reannouncedIds.clear();}update(e){let{distanceToNextInstruction:t,nextInstructionIndex:n}=e;if(n===null||t===null||n>=this.instructions.length)return null;let i=this.instructions[n],r=this.instrId(n),o=t;if(this.triggeredIds.has(r))return this.options.reannounceMeters>0&&!this.reannouncedIds.has(r)&&o<=this.options.reannounceMeters&&o>this.options.earlyTriggerMeters?(this.reannouncedIds.add(r),this.makeCue(i,o,"low")):null;if(o>this.options.earlyTriggerMeters)return null;if(o<-this.options.lateTriggerMeters)return this.triggeredIds.add(r),null;this.triggeredIds.add(r);let c=o<30?"urgent":o<60?"high":"normal";return this.makeCue(i,o,c)}onInstruction(e,t){let n=t.distanceToNextInstruction??0;return this.makeCue(e,n,"high")}reset(){this.triggeredIds.clear(),this.reannouncedIds.clear();}instrId(e){let t=this.instructions[e];return `${e}_${t?.geometryIndex??0}`}makeCue(e,t,n){return {instruction:e,text:e.text??e.instruction??"",distanceMetres:Math.max(0,t),priority:n,triggerId:`${e.geometryIndex}_${t.toFixed(0)}`}}};var tt={speedWindowSize:6,minimumSpeedMs:.5,fallbackSpeedMs:8.33},de=class{constructor(e){this.speedSamples=[];this.options={...tt,...e},this.lastReliableSpeed=this.options.fallbackSpeedMs;}update(e){let t=e.distanceToDestination??0,n=e.currentSpeed??0;this.speedSamples.push(n),this.speedSamples.length>this.options.speedWindowSize&&this.speedSamples.shift();let i=this.rollingAverage();i>=this.options.minimumSpeedMs&&(this.lastReliableSpeed=i);let r=i>=this.options.minimumSpeedMs?i:this.lastReliableSpeed,o=this.speedSamples.length>=Math.ceil(this.options.speedWindowSize/2)&&r>0&&t>0,c=r>0?t/r:0;return {etaSeconds:Math.round(c),etaMs:Date.now()+c*1e3,distanceRemainingM:t,averageSpeedMs:i,isReliable:o}}reset(){this.speedSamples=[],this.lastReliableSpeed=this.options.fallbackSpeedMs;}rollingAverage(){return this.speedSamples.length===0?0:this.speedSamples.reduce((t,n)=>t+n,0)/this.speedSamples.length}};var nt={dwellThresholdMs:1e4},pe=class{constructor(e){this.fences=new Map;this.states=new Map;this.options={...nt,...e};}addCircle(e,t,n,i){return this.fences.set(e,{kind:"circle",id:e,center:t,radiusM:n,meta:i}),this.states.set(e,{inside:false,enteredAtMs:null}),e}addPolygon(e,t,n){if(t.length<3)throw new Error("[Geofencing] Polygon requires at least 3 coordinates");return this.fences.set(e,{kind:"polygon",id:e,coords:t,meta:n}),this.states.set(e,{inside:false,enteredAtMs:null}),e}remove(e){this.fences.delete(e),this.states.delete(e);}clear(){this.fences.clear(),this.states.clear();}listIds(){return Array.from(this.fences.keys())}update(e){if(!e)return [];let t=[],n=Date.now();for(let[i,r]of this.fences){let o=this.states.get(i),c=this.contains(r,e);if(!o.inside&&c)o.inside=true,o.enteredAtMs=n,t.push({id:i,type:"enter",coord:e,meta:r.meta});else if(o.inside&&!c){o.inside=false;let a=o.enteredAtMs?n-o.enteredAtMs:0;o.enteredAtMs=null,t.push({id:i,type:"exit",coord:e,dwellMs:a,meta:r.meta});}else if(o.inside&&o.enteredAtMs!==null){let a=n-o.enteredAtMs;a>=this.options.dwellThresholdMs&&(t.push({id:i,type:"dwell",coord:e,dwellMs:a,meta:r.meta}),o.enteredAtMs=n);}}return t}isInside(e,t){let n=this.fences.get(e);return n?this.contains(n,t):false}contains(e,t){return e.kind==="circle"?m(t[1],t[0],e.center[1],e.center[0])<=e.radiusM:this.pointInPolygon(t,e.coords)}pointInPolygon(e,t){let[n,i]=e,r=false,o=t.length;for(let c=0,a=o-1;c<o;a=c++){let[u,d]=t[c],[l,p]=t[a];d>i!=p>i&&n<(l-u)*(i-d)/(p-d)+u&&(r=!r);}return r}};var E={GPS_SMOOTHING:"gps_smoothing",BASIC_SNAPPING:"basic_snapping",ADVANCED_SNAPPING:"advanced_snapping",DEAD_RECKONING:"dead_reckoning",ROUTE_OFFSET:"route_offset",PROGRESS_TRACKING:"progress_tracking",ADVANCED_BEARING:"advanced_bearing",COMPOUND_DEVIATION:"compound_deviation",PARALLEL_ROAD_RESOLUTION:"parallel_road_resolution",U_TURN_PROTECTION:"u_turn_protection",VOICE_TRIGGERS:"voice_triggers",ETA:"eta",GEOFENCING:"geofencing",NAV_AI:"nav_ai"};var B=class B{constructor(e,t){this.status="MISSING";this.payload=null;this.enabledFeatures=new Set;this.warnedFeatures=new Set;this.isDev=false;this.isDev=t??false,e&&this.validate(e);}async validate(e){try{if(this.status==="VALID"&&this.payload?.bid==="dev.bypass")return "VALID";let[t,n]=e.split(".");if(!t||!n)return this.status="INVALID",this.status;let i=atob(t);if(this.payload=JSON.parse(i),!this.payload||this.payload.exp<Date.now())return this.status="EXPIRED",this.status;if(!await this.verifySignature(t,n))return this.status="INVALID",this.status;this.status="VALID",this.extractFeatures(),console.log(`\u{1F511} [NavCore] License validation complete. Plan: ${this.isProEnabled()?"pro":"core"}`);}catch{this.status="INVALID";}return this.status}extractFeatures(){if(this.enabledFeatures.clear(),!!this.payload){if(Array.isArray(this.payload.f))for(let e of this.payload.f)this.enabledFeatures.add(e);this.payload.t==="pro"&&this.enabledFeatures.add("*");}}hasFeature(e){return this.isDev?true:this.status!=="VALID"?false:this.enabledFeatures.has("*")?true:this.enabledFeatures.has(e)}warnOnce(e){this.warnedFeatures.has(e)||(console.warn(`[NavCore] Feature '${e}' requires a Pro license \u2192 upgrade at https://navcore.dev/pricing`),this.warnedFeatures.add(e));}isProEnabled(){return this.hasFeature("*")}isAIEnabled(){return this.hasFeature(E.NAV_AI)}getStatus(){return this.status}getPayload(){return this.payload}getEnabledFeatures(){return Array.from(this.enabledFeatures)}async verifySignature(e,t){try{if(typeof crypto>"u"||!crypto.subtle)return !1;let i=new TextEncoder().encode(e),r=Uint8Array.from(atob(t),a=>a.charCodeAt(0)),o=Uint8Array.from(atob(B.PUBLIC_KEY_SPKI),a=>a.charCodeAt(0)),c=await crypto.subtle.importKey("spki",o,{name:"ECDSA",namedCurve:"P-256"},!0,["verify"]);return await crypto.subtle.verify({name:"ECDSA",hash:{name:"SHA-256"}},c,r,i)}catch{return false}}};B.PUBLIC_KEY_SPKI="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk6onJmJkWtRFusiSS69dcdONX4xL2Snm4AZO+dYjSynfJiL4x7trEy80MImLftknBWT/qI0z7ox4Q7VNL3te6A==";var G=B;var he=class{constructor(e){this.route=[];this.instructions=[];this.forwardCum=new Float64Array(0);this.reverseCum=new Float64Array(0);this.snappedCoord=null;this.rawGpsCoord=null;this.bearing=0;this.rawGpsBearing=null;this.routeIndex=0;this.maxProgressIdx=0;this.prevSegment=null;this.distanceToRoute=0;this.corridor=25;this.prevDistToNext=null;this.currentSpeed=0;this.lastGpsTimestamp=0;this.instrIdx=0;this.linearOffset=0;this.hasArrived=false;this.listeners=new Map;this.options={licenseKey:e?.licenseKey??"",isDev:e?.isDev??false,isCircuit:e?.isCircuit??false,kalmanQ:e?.kalmanQ??1e-5,kalmanRBase:e?.kalmanRBase??5e-5,baseCorridorMeters:e?.baseCorridorMeters??25,maxCorridorMeters:e?.maxCorridorMeters??60,arrivalThresholdMeters:e?.arrivalThresholdMeters??30,bearingSmoothingAlpha:e?.bearingSmoothingAlpha??.3},this.kalman=new M(this.options.kalmanQ,this.options.kalmanRBase),this.snapper=new T({useBearingPenalty:true,useInertiaPenalty:true}),this.deadReckoning=new D,this.deviationDetector=new N,this.lifecycleFSM=new w,this.offRouteFSM=new F,this.license=new G(this.options.licenseKey,this.options.isDev);}has(e){let t=this.license.hasFeature(e);return t||this.license.warnOnce(e),t}setRoute(e,t){this.route=e,this.instructions=t??[],this.forwardCum=K(e),this.reverseCum=j(e),this.routeIndex=0,this.maxProgressIdx=0,this.prevSegment=null,this.instrIdx=0,this.linearOffset=0,this.hasArrived=false,this.snappedCoord=null,this.prevDistToNext=null,this.lifecycleFSM.dispatch({type:"ROUTE_LOADED"}),this.emit("routeLoaded",{routeLength:e.length});}startNavigation(){this.lifecycleFSM.dispatch({type:"USER_START_NAVIGATION"}),this.emit("navigationStarted");}update(e){if(this.rawGpsCoord=e.coord,this.rawGpsBearing=e.bearing,this.currentSpeed=e.speed,this.lastGpsTimestamp=e.timestamp,this.route.length<2)return this.getState();let[t,n]=this.kalman.update(e.coord[0],e.coord[1],e.accuracy??10,e.timestamp),i=[t,n],r=Math.max(0,this.routeIndex-2),o=this.snapper.snap(i,this.route,r,25,this.options.isCircuit,this.maxProgressIdx,this.routeIndex,e.bearing,this.prevSegment);this.corridor=Z(e.speed,e.accuracy,this.options.baseCorridorMeters,this.options.maxCorridorMeters);let c=te(this.routeIndex,o.idx,this.route,o.dist,80);if(this.prevSegment=this.routeIndex,this.routeIndex=c,this.maxProgressIdx=Math.max(this.maxProgressIdx,c),this.snappedCoord=o.proj,this.distanceToRoute=o.dist,this.forwardCum.length>c){let a=this.forwardCum[c]??0;this.linearOffset=oe(this.linearOffset,a,.15);}if(this.has(E.ADVANCED_BEARING)?this.bearing=ee(this.bearing,this.route,this.routeIndex,e.speed,e.bearing,this.options.bearingSmoothingAlpha):e.bearing!==null&&(this.bearing=e.bearing),this.has(E.COMPOUND_DEVIATION)&&(this.offRouteFSM.state==="ON_ROUTE"||this.offRouteFSM.state==="DEVIATING")){let a=Ae(i,this.route,r,25),u=this.deviationDetector.evaluate(i,e.bearing,e.speed,a,this.route,this.corridor,this.prevDistToNext);if(a.segmentIndex<this.route.length-1){let d=this.route[Math.min(a.segmentIndex+2,this.route.length-1)];this.prevDistToNext=m(i[1],i[0],d[1],d[0]);}u.confirmed?this.offRouteFSM.state==="ON_ROUTE"?this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:a.segmentIndex}):this.offRouteFSM.isDeviationConfirmed()&&(this.offRouteFSM.dispatch({type:"DEVIATION_CONFIRMED",deviationSegmentIdx:a.segmentIndex}),this.emit("deviation",{anchorIndex:a.segmentIndex,ghostCoord:o.proj})):this.offRouteFSM.state==="DEVIATING"&&this.offRouteFSM.dispatch({type:"RESUME"});}else this.has(E.COMPOUND_DEVIATION)||(o.dist>this.corridor&&this.offRouteFSM.state==="ON_ROUTE"?(this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:o.idx}),this.emit("deviation",{anchorIndex:o.idx,ghostCoord:o.proj})):o.dist<=this.corridor&&this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.dispatch({type:"RESUME"}));if(this.lifecycleFSM.state==="APPROACHING_ROUTE"&&o.dist<this.corridor&&this.lifecycleFSM.dispatch({type:"ROUTE_JOINED",data:{index:o.idx}}),this.instructions.length>0){let a=ne(this.routeIndex,this.instructions,this.instrIdx,this.route,i,e.bearing,this.linearOffset,e.speed);a.nextIdx!==this.instrIdx&&(this.instrIdx=a.nextIdx),a.wasTriggered&&a.instruction&&(this.emit("instruction",a.instruction),this.instrIdx=a.nextIdx+1);}if(!this.hasArrived&&this.route.length>0){let a=this.route[this.route.length-1],u=m(i[1],i[0],a[1],a[0]),d=this.options.isCircuit?this.routeIndex>=this.route.length*.8:true;u<this.options.arrivalThresholdMeters&&d&&(this.hasArrived=true,this.lifecycleFSM.dispatch({type:"NAVIGATION_FINISHED"}),this.emit("arrival"));}return this.has(E.DEAD_RECKONING)&&this.deadReckoning.setAnchor(o.proj,o.idx,e.timestamp),this.getState()}tick(e){if(this.has(E.DEAD_RECKONING)){let t=this.deadReckoning.predict(this.currentSpeed,this.bearing,e);t.isActive&&(this.snappedCoord=t.predictedCoord);}if(this.lastGpsTimestamp>0){let t=(e-this.lastGpsTimestamp)/1e3;t>0&&t<10&&(this.linearOffset=re(this.linearOffset,this.currentSpeed,t));}return this.getState()}getState(){let e=this.route.length>0&&this.reverseCum.length>this.routeIndex?this.reverseCum[this.routeIndex]??null:null,t=this.instrIdx<this.instructions.length?(()=>{let i=this.instructions[this.instrIdx];return i.cumulativeOffset!==void 0?Math.max(0,i.cumulativeOffset-this.linearOffset):null})():null,n=this.lastGpsTimestamp>0?Date.now()-this.lastGpsTimestamp:0;return {snappedCoord:this.snappedCoord,rawGpsCoord:this.rawGpsCoord,bearing:this.bearing,rawGpsBearing:this.rawGpsBearing,routeIndex:this.routeIndex,distanceToRoute:this.distanceToRoute,corridor:this.corridor,isOffRoute:this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.state!=="DEVIATING",progressIndex:this.routeIndex,hasArrived:this.hasArrived,offRouteState:this.offRouteFSM.state,lifecycleState:this.lifecycleFSM.state,distanceToDestination:e,distanceToNextInstruction:t,nextInstructionIndex:this.instrIdx<this.instructions.length?this.instrIdx:null,currentSpeed:this.currentSpeed,isGpsStale:n>3e3,gpsAgeMs:n,licenseStatus:this.license.getStatus()}}destroy(){this.listeners.clear(),this.route=[],this.instructions=[],this.kalman.reset(),this.deadReckoning.clearAnchor(),this.lifecycleFSM.reset(),this.offRouteFSM.reset();}on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t);}off(e,t){let n=this.listeners.get(e);if(n){let i=n.indexOf(t);i>=0&&n.splice(i,1);}}emit(e,...t){let n=this.listeners.get(e);if(n)for(let i of n)i(...t);}getLicenseManager(){return this.license}getRoute(){return this.route}getInstructions(){return this.instructions}getOffRouteFSM(){return this.offRouteFSM}getLifecycleFSM(){return this.lifecycleFSM}};
|
|
8
|
-
exports.Constants=
|
|
7
|
+
</gpx>`}fromGeoJSON(e){if(this.waypoints=[],e.type==="FeatureCollection"&&e.features){for(let t of e.features)if(t.geometry.type==="Point"){let n=t.geometry.coordinates;this.addWaypoint(n);}else if(t.geometry.type==="LineString"){let n=t.geometry.coordinates;for(let i of n)this.addWaypoint(i);}}}toGeoJSON(){let e=this.waypoints.map((n,i)=>({type:"Feature",geometry:{type:"Point",coordinates:n.coord},properties:{id:n.id,order:i,name:n.options?.name??null,silent:n.options?.silent??false}})),t={type:"Feature",geometry:{type:"LineString",coordinates:this.waypoints.map(n=>n.coord)},properties:{type:"route"}};return {type:"FeatureCollection",features:[...e,t]}}clear(){this.waypoints=[];}};var ae=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),profile:e.profile??"driving",maxWaypointsPerChunk:e.maxWaypointsPerChunk??100};}async getRoute(e,t){if(e.length<2)throw new Error("[OSRM] At least 2 waypoints required");let n=t?.profile??this.config.profile;return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}async fetchRoute(e,t,n){let i=e.map(d=>`${d[0]},${d[1]}`).join(";"),r=n?.steps!==false?"true":"false",o=`${this.config.baseUrl}/route/v1/${t}/${i}?overview=full&geometries=geojson&steps=${r}&annotations=false`,c=await fetch(o);if(!c.ok)throw new Error(`[OSRM] HTTP ${c.status}: ${c.statusText}`);let a=await c.json();if(a.code!=="Ok"||!a.routes?.length)throw new Error(`[OSRM] No route found: ${a.code}`);let u=a.routes[0];return {geometry:u.geometry.coordinates,distance:u.distance,duration:u.duration,legs:(u.legs??[]).map(d=>({distance:d.distance,duration:d.duration,steps:(d.steps??[]).map(l=>({distance:l.distance,duration:l.duration,geometry:l.geometry?.coordinates??[],maneuver:{type:l.maneuver?.type??"unknown",modifier:l.maneuver?.modifier,location:l.maneuver?.location??[0,0],bearingBefore:l.maneuver?.bearing_before??0,bearingAfter:l.maneuver?.bearing_after??0,instruction:l.name??void 0},name:l.name}))})),raw:a}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var ce=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),costing:e.costing??"auto",apiKey:e.apiKey??"",maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[Valhalla] At least 2 waypoints required");let n=this.profileToCosting(t?.profile);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileToCosting(e){switch(e){case "cycling":return "bicycle";case "walking":return "pedestrian";default:return this.config.costing}}async fetchRoute(e,t,n){let i=e.map(p=>({lon:p[0],lat:p[1],type:"break"})),r=JSON.stringify({locations:i,costing:t,directions_options:{units:"kilometers"}}),o={"Content-Type":"application/json","User-Agent":"NavCoreSDK/1.0.0 (React Native; Expo; bab-bou-jeloud-demo)"};this.config.apiKey&&(o.api_key=this.config.apiKey);let c=await fetch(`${this.config.baseUrl}/route`,{method:"POST",headers:o,body:r});if(!c.ok){let p=await c.text();throw new Error(`[Valhalla] HTTP ${c.status}: ${p}`)}let a=await c.json(),u=this.decodePolyline(a.trip?.legs?.[0]?.shape??""),d=a.trip?.summary??{},l=(a.trip?.legs??[]).map(p=>({distance:(p.summary?.length??0)*1e3,duration:p.summary?.time??0,steps:(p.maneuvers??[]).map(f=>({distance:(f.length??0)*1e3,duration:f.time??0,geometry:[],maneuver:{type:f.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:f.begin_heading??0,bearingAfter:f.end_heading??0,instruction:f.instruction},name:f.street_names?.[0]}))}));return {geometry:u,distance:(d.length??0)*1e3,duration:d.time??0,legs:l,raw:a}}decodePolyline(e,t=6){let n=Math.pow(10,t),i=[],r=0,o=0,c=0;for(;r<e.length;){let a=0,u=0,d;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let l=(u&1)!==0?~(u>>1):u>>1;o+=l,a=0,u=0;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let p=(u&1)!==0?~(u>>1):u>>1;c+=p,i.push([c/n,o/n]);}return i}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var Ze="https://api.openrouteservice.org/v2/directions";var le=class{constructor(e){this.config={apiKey:e.apiKey,profile:e.profile??"driving-car",baseUrl:e.baseUrl??Ze,maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[ORS] At least 2 waypoints required");let n=this.profileFromOptions(t);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileFromOptions(e){switch(e?.profile){case "cycling":return "cycling-regular";case "walking":return "foot-walking";default:return this.config.profile}}async fetchRoute(e,t,n){let i=JSON.stringify({coordinates:e,instructions:n?.steps!==false,language:n?.language??"en"}),r=await fetch(`${this.config.baseUrl}/${t}/geojson`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:this.config.apiKey},body:i});if(!r.ok){let l=await r.text();throw new Error(`[ORS] HTTP ${r.status}: ${l}`)}let o=await r.json(),c=o.features?.[0];if(!c)throw new Error("[ORS] No route returned");let a=c.properties?.summary??{},d=(c.properties?.segments??[]).map(l=>({distance:l.distance??0,duration:l.duration??0,steps:(l.steps??[]).map(p=>({distance:p.distance??0,duration:p.duration??0,geometry:[],maneuver:{type:p.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:0,bearingAfter:0,instruction:p.instruction},name:p.name}))}));return {geometry:c.geometry?.coordinates??[],distance:a.distance??0,duration:a.duration??0,legs:d,raw:o}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var et={earlyTriggerMeters:120,lateTriggerMeters:20,reannounceMeters:300},ue=class{constructor(e){this.instructions=[];this.triggeredIds=new Set;this.reannouncedIds=new Set;this.options={...et,...e};}setInstructions(e){this.instructions=[...e],this.triggeredIds.clear(),this.reannouncedIds.clear();}update(e){let t=m.getActive();if(!t||!t.hasFeature(h.VOICE_TRIGGERS))return t?t.warnOnce(h.VOICE_TRIGGERS):console.warn(`[NavCore] Feature '${h.VOICE_TRIGGERS}' requires a Pro license`),null;let{distanceToNextInstruction:n,nextInstructionIndex:i}=e;if(i===null||n===null||i>=this.instructions.length)return null;let r=this.instructions[i],o=this.instrId(i),c=n;if(this.triggeredIds.has(o))return this.options.reannounceMeters>0&&!this.reannouncedIds.has(o)&&c<=this.options.reannounceMeters&&c>this.options.earlyTriggerMeters?(this.reannouncedIds.add(o),this.makeCue(r,c,"low")):null;if(c>this.options.earlyTriggerMeters)return null;if(c<-this.options.lateTriggerMeters)return this.triggeredIds.add(o),null;this.triggeredIds.add(o);let a=c<30?"urgent":c<60?"high":"normal";return this.makeCue(r,c,a)}onInstruction(e,t){let n=m.getActive();if(!n||!n.hasFeature(h.VOICE_TRIGGERS))return n?n.warnOnce(h.VOICE_TRIGGERS):console.warn(`[NavCore] Feature '${h.VOICE_TRIGGERS}' requires a Pro license`),{instruction:e,text:"",distanceMetres:0,priority:"normal",triggerId:"bypass"};let i=t.distanceToNextInstruction??0;return this.makeCue(e,i,"high")}reset(){this.triggeredIds.clear(),this.reannouncedIds.clear();}instrId(e){let t=this.instructions[e];return `${e}_${t?.geometryIndex??0}`}makeCue(e,t,n){return {instruction:e,text:e.text??e.instruction??"",distanceMetres:Math.max(0,t),priority:n,triggerId:`${e.geometryIndex}_${t.toFixed(0)}`}}};var tt={speedWindowSize:6,minimumSpeedMs:.5,fallbackSpeedMs:8.33},de=class{constructor(e){this.speedSamples=[];this.options={...tt,...e},this.lastReliableSpeed=this.options.fallbackSpeedMs;}update(e){let t=m.getActive();if(!t||!t.hasFeature(h.ETA))return t?t.warnOnce(h.ETA):console.warn(`[NavCore] Feature '${h.ETA}' requires a Pro license`),{etaSeconds:0,etaMs:0,distanceRemainingM:0,averageSpeedMs:0,isReliable:false};let n=e.distanceToDestination??0,i=e.currentSpeed??0;this.speedSamples.push(i),this.speedSamples.length>this.options.speedWindowSize&&this.speedSamples.shift();let r=this.rollingAverage();r>=this.options.minimumSpeedMs&&(this.lastReliableSpeed=r);let o=r>=this.options.minimumSpeedMs?r:this.lastReliableSpeed,c=this.speedSamples.length>=Math.ceil(this.options.speedWindowSize/2)&&o>0&&n>0,a=o>0?n/o:0;return {etaSeconds:Math.round(a),etaMs:Date.now()+a*1e3,distanceRemainingM:n,averageSpeedMs:r,isReliable:c}}reset(){this.speedSamples=[],this.lastReliableSpeed=this.options.fallbackSpeedMs;}rollingAverage(){return this.speedSamples.length===0?0:this.speedSamples.reduce((t,n)=>t+n,0)/this.speedSamples.length}};var nt={dwellThresholdMs:1e4},pe=class{constructor(e){this.fences=new Map;this.states=new Map;if(this.options={...nt,...e},this.options.zones)for(let t of this.options.zones)t.type==="circle"&&t.center&&t.radiusMeters?this.addCircle(t.id,t.name,t.center,t.radiusMeters,t.meta):t.type==="polygon"&&t.coords&&this.addPolygon(t.id,t.name,t.coords,t.meta);}addCircle(e,t,n,i,r){return this.fences.set(e,{kind:"circle",id:e,name:t,center:n,radiusM:i,meta:r}),this.states.set(e,{inside:false,enteredAtMs:null}),e}addPolygon(e,t,n,i){if(n.length<3)throw new Error("[Geofencing] Polygon requires at least 3 coordinates");return this.fences.set(e,{kind:"polygon",id:e,name:t,coords:n,meta:i}),this.states.set(e,{inside:false,enteredAtMs:null}),e}remove(e){this.fences.delete(e),this.states.delete(e);}clear(){this.fences.clear(),this.states.clear();}listIds(){return Array.from(this.fences.keys())}update(e){let t=m.getActive();if(!t||!t.hasFeature(h.GEOFENCING))return t?t.warnOnce(h.GEOFENCING):console.warn(`[NavCore] Feature '${h.GEOFENCING}' requires a Pro license`),[];if(!e)return [];let n=[],i=Date.now();for(let[r,o]of this.fences){let c=this.states.get(r),a=this.contains(o,e);if(!c.inside&&a){c.inside=true,c.enteredAtMs=i;let u={id:r,name:o.name,type:"enter",coord:e,meta:o.meta};n.push(u),this.options.onEvent?.(u);}else if(c.inside&&!a){c.inside=false;let u=c.enteredAtMs?i-c.enteredAtMs:0;c.enteredAtMs=null;let d={id:r,name:o.name,type:"exit",coord:e,dwellMs:u,meta:o.meta};n.push(d),this.options.onEvent?.(d);}else if(c.inside&&c.enteredAtMs!==null){let u=i-c.enteredAtMs;if(u>=this.options.dwellThresholdMs){let d={id:r,name:o.name,type:"dwell",coord:e,dwellMs:u,meta:o.meta};n.push(d),this.options.onEvent?.(d),c.enteredAtMs=i;}}}return n}isInside(e,t){let n=this.fences.get(e);return n?this.contains(n,t):false}contains(e,t){return e.kind==="circle"?y(t[1],t[0],e.center[1],e.center[0])<=e.radiusM:this.pointInPolygon(t,e.coords)}pointInPolygon(e,t){let[n,i]=e,r=false,o=t.length;for(let c=0,a=o-1;c<o;a=c++){let[u,d]=t[c],[l,p]=t[a];d>i!=p>i&&n<(l-u)*(i-d)/(p-d)+u&&(r=!r);}return r}};var he=class{constructor(e){this.route=[];this.instructions=[];this.forwardCum=new Float64Array(0);this.reverseCum=new Float64Array(0);this.snappedCoord=null;this.rawGpsCoord=null;this.bearing=0;this.rawGpsBearing=null;this.routeIndex=0;this.maxProgressIdx=0;this.prevSegment=null;this.distanceToRoute=0;this.corridor=25;this.prevDistToNext=null;this.currentSpeed=0;this.lastGpsTimestamp=0;this.instrIdx=0;this.linearOffset=0;this.hasArrived=false;this.listeners=new Map;this.options={licenseKey:e?.licenseKey??"",isCircuit:e?.isCircuit??false,kalmanQ:e?.kalmanQ??1e-5,kalmanRBase:e?.kalmanRBase??5e-5,baseCorridorMeters:e?.baseCorridorMeters??25,maxCorridorMeters:e?.maxCorridorMeters??60,arrivalThresholdMeters:e?.arrivalThresholdMeters??30,bearingSmoothingAlpha:e?.bearingSmoothingAlpha??.3},this.kalman=new D(this.options.kalmanQ,this.options.kalmanRBase),this.snapper=new N({useBearingPenalty:true,useInertiaPenalty:true}),this.deadReckoning=new P,this.deviationDetector=new w,this.lifecycleFSM=new G,this.offRouteFSM=new L,this.license=new m(this.options.licenseKey);}has(e){let t=this.license.hasFeature(e);return t||this.license.warnOnce(e),t}setRoute(e,t){this.route=e,this.instructions=t??[],this.forwardCum=K(e),this.reverseCum=j(e),this.routeIndex=0,this.maxProgressIdx=0,this.prevSegment=null,this.instrIdx=0,this.linearOffset=0,this.hasArrived=false,this.snappedCoord=null,this.prevDistToNext=null,this.lifecycleFSM.dispatch({type:"ROUTE_LOADED"}),this.emit("routeLoaded",{routeLength:e.length});}startNavigation(){this.lifecycleFSM.dispatch({type:"USER_START_NAVIGATION"}),this.emit("navigationStarted");}update(e){if(this.rawGpsCoord=e.coord,this.rawGpsBearing=e.bearing,this.currentSpeed=e.speed,this.lastGpsTimestamp=e.timestamp,this.route.length<2)return this.getState();let[t,n]=this.kalman.update(e.coord[0],e.coord[1],e.accuracy??10,e.timestamp),i=[t,n],r=Math.max(0,this.routeIndex-2),o=this.snapper.snap(i,this.route,r,25,this.options.isCircuit,this.maxProgressIdx,this.routeIndex,e.bearing,this.prevSegment);this.corridor=Z(e.speed,e.accuracy,this.options.baseCorridorMeters,this.options.maxCorridorMeters);let c=te(this.routeIndex,o.idx,this.route,o.dist,80);if(this.prevSegment=this.routeIndex,this.routeIndex=c,this.maxProgressIdx=Math.max(this.maxProgressIdx,c),this.snappedCoord=o.proj,this.distanceToRoute=o.dist,this.forwardCum.length>c){let a=this.forwardCum[c]??0;this.linearOffset=oe(this.linearOffset,a,.15);}if(this.has(h.ADVANCED_BEARING)?this.bearing=ee(this.bearing,this.route,this.routeIndex,e.speed,e.bearing,this.options.bearingSmoothingAlpha):e.bearing!==null&&(this.bearing=e.bearing),this.has(h.COMPOUND_DEVIATION)&&(this.offRouteFSM.state==="ON_ROUTE"||this.offRouteFSM.state==="DEVIATING")){let a=Oe(i,this.route,r,25),u=this.deviationDetector.evaluate(i,e.bearing,e.speed,a,this.route,this.corridor,this.prevDistToNext);if(a.segmentIndex<this.route.length-1){let d=this.route[Math.min(a.segmentIndex+2,this.route.length-1)];this.prevDistToNext=y(i[1],i[0],d[1],d[0]);}u.confirmed?this.offRouteFSM.state==="ON_ROUTE"?this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:a.segmentIndex}):this.offRouteFSM.isDeviationConfirmed()&&(this.offRouteFSM.dispatch({type:"DEVIATION_CONFIRMED",deviationSegmentIdx:a.segmentIndex}),this.emit("deviation",{anchorIndex:a.segmentIndex,ghostCoord:o.proj})):this.offRouteFSM.state==="DEVIATING"&&this.offRouteFSM.dispatch({type:"RESUME"});}else this.has(h.COMPOUND_DEVIATION)||(o.dist>this.corridor&&this.offRouteFSM.state==="ON_ROUTE"?(this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:o.idx}),this.emit("deviation",{anchorIndex:o.idx,ghostCoord:o.proj})):o.dist<=this.corridor&&this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.dispatch({type:"RESUME"}));if(this.lifecycleFSM.state==="APPROACHING_ROUTE"&&o.dist<this.corridor&&this.lifecycleFSM.dispatch({type:"ROUTE_JOINED",data:{index:o.idx}}),this.instructions.length>0){let a=ne(this.routeIndex,this.instructions,this.instrIdx,this.route,i,e.bearing,this.linearOffset,e.speed);a.nextIdx!==this.instrIdx&&(this.instrIdx=a.nextIdx),a.wasTriggered&&a.instruction&&(this.emit("instruction",a.instruction),this.instrIdx=a.nextIdx+1);}if(!this.hasArrived&&this.route.length>0){let a=this.route[this.route.length-1],u=y(i[1],i[0],a[1],a[0]),d=this.options.isCircuit?this.routeIndex>=this.route.length*.8:true;u<this.options.arrivalThresholdMeters&&d&&(this.hasArrived=true,this.lifecycleFSM.dispatch({type:"NAVIGATION_FINISHED"}),this.emit("arrival"));}return this.has(h.DEAD_RECKONING)&&this.deadReckoning.setAnchor(o.proj,o.idx,e.timestamp),this.getState()}tick(e){if(this.has(h.DEAD_RECKONING)){let t=this.deadReckoning.predict(this.currentSpeed,this.bearing,e);t.isActive&&(this.snappedCoord=t.predictedCoord);}if(this.lastGpsTimestamp>0){let t=(e-this.lastGpsTimestamp)/1e3;t>0&&t<10&&(this.linearOffset=re(this.linearOffset,this.currentSpeed,t));}return this.getState()}getState(){let e=this.route.length>0&&this.reverseCum.length>this.routeIndex?this.reverseCum[this.routeIndex]??null:null,t=this.instrIdx<this.instructions.length?(()=>{let i=this.instructions[this.instrIdx];return i.cumulativeOffset!==void 0?Math.max(0,i.cumulativeOffset-this.linearOffset):null})():null,n=this.lastGpsTimestamp>0?Date.now()-this.lastGpsTimestamp:0;return {snappedCoord:this.snappedCoord,rawGpsCoord:this.rawGpsCoord,bearing:this.bearing,rawGpsBearing:this.rawGpsBearing,routeIndex:this.routeIndex,distanceToRoute:this.distanceToRoute,corridor:this.corridor,isOffRoute:this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.state!=="DEVIATING",progressIndex:this.routeIndex,hasArrived:this.hasArrived,offRouteState:this.offRouteFSM.state,lifecycleState:this.lifecycleFSM.state,distanceToDestination:e,distanceToNextInstruction:t,nextInstructionIndex:this.instrIdx<this.instructions.length?this.instrIdx:null,currentSpeed:this.currentSpeed,isGpsStale:n>3e3,gpsAgeMs:n,licenseStatus:this.license.getStatus()}}destroy(){this.listeners.clear(),this.route=[],this.instructions=[],this.kalman.reset(),this.deadReckoning.clearAnchor(),this.lifecycleFSM.reset(),this.offRouteFSM.reset();}on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t);}off(e,t){let n=this.listeners.get(e);if(n){let i=n.indexOf(t);i>=0&&n.splice(i,1);}}emit(e,...t){let n=this.listeners.get(e);if(n)for(let i of n)i(...t);}getLicenseManager(){return this.license}getRoute(){return this.route}getInstructions(){return this.instructions}getOffRouteFSM(){return this.offRouteFSM}getLifecycleFSM(){return this.lifecycleFSM}};
|
|
8
|
+
exports.Constants=Se;exports.CustomRouteBuilder=se;exports.DeadReckoningEngine=P;exports.DeviationDetector=w;exports.ETAEngine=de;exports.FEATURES=h;exports.GeofencingEngine=pe;exports.InstructionEditor=ie;exports.KalmanFilter2D=D;exports.LicenseManager=m;exports.NavCore=he;exports.NavigationFSM=G;exports.OSRMDirectionsProvider=ae;exports.OffRouteFSM=L;exports.OpenRouteServiceProvider=le;exports.ParallelRoadResolver=Q;exports.RouteSnapper=N;exports.ValhallaDirectionsProvider=ce;exports.VoiceTriggerEngine=ue;exports.advancePredictor=re;exports.applyBearingSmoothing=ee;exports.applyGpsCorrection=oe;exports.blendBearing=V;exports.buildForwardCumulativeDistances=K;exports.buildReverseCumulativeDistances=j;exports.calculateDynamicCorridor=Z;exports.calculateRobustBearing=Me;exports.computeDeadReckoningOnRoute=Ae;exports.destinationPoint=B;exports.geoGetBearing=we;exports.getBearingBetweenPoints=R;exports.getSpeedAdaptiveAlpha=_e;exports.haversineDistance=y;exports.interpolatePoint=W;exports.kalmanUpdate2D=me;exports.normalizeAngle=E;exports.pointAtOffset=ze;exports.projectPointOnSegment=H;exports.resolveNextInstruction=ne;exports.validateProgressUpdate=te;
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var Ne=Object.defineProperty;var Pe=(s,e)=>{for(var t in e)Ne(s,t,{get:e[t],enumerable:true});};function m(s,e,t,n){let i=(t-s)*(Math.PI/180),r=(n-e)*(Math.PI/180),o=Math.sin(i/2)*Math.sin(i/2)+Math.cos(s*(Math.PI/180))*Math.cos(t*(Math.PI/180))*Math.sin(r/2)*Math.sin(r/2);return 6371e3*(2*Math.atan2(Math.sqrt(o),Math.sqrt(1-o)))}function V(s,e,t,n){let i=n/6371e3,r=t*(Math.PI/180),o=s*(Math.PI/180),c=e*(Math.PI/180),a=Math.asin(Math.sin(o)*Math.cos(i)+Math.cos(o)*Math.sin(i)*Math.cos(r));return [((c+Math.atan2(Math.sin(r)*Math.sin(i)*Math.cos(o),Math.cos(i)-Math.sin(o)*Math.sin(a)))*180/Math.PI+540)%360-180,a*180/Math.PI]}function we(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n),a=Math.atan2(o,c)*(180/Math.PI);return a=(a+360)%360,a}function y(s){let e=s%360;return e>180?e-360:e<-180?e+360:e}function f(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n);return (Math.atan2(o,c)*180/Math.PI+360)%360}function H(s,e,t){let n=(i,r,o)=>i+(r-i)*o;return [n(s[0],e[0],t),n(s[1],e[1],t)]}function W(s,e,t){let[n,i]=s,[r,o]=e,[c,a]=t,u=c-r,d=a-o,l=u*u+d*d;if(l===0)return e;let p=((n-r)*u+(i-o)*d)/l;return p=Math.max(0,Math.min(1,p)),[r+p*u,o+p*d]}function K(s){let e=new Float64Array(s.length);for(let t=1;t<s.length;t++)e[t]=e[t-1]+m(s[t-1][1],s[t-1][0],s[t][1],s[t][0]);return e}function j(s){let e=new Float64Array(s.length);for(let t=s.length-2;t>=0;t--)e[t]=e[t+1]+m(s[t][1],s[t][0],s[t+1][1],s[t+1][0]);return e}function me(s,e,t,n,i,r=1e-5,o=5e-5){s.x+=s.vx*i,s.y+=s.vy*i,s.P+=r;let c=o*Math.max(1,n/5),a=s.P/(s.P+c),u=e-s.x,d=t-s.y;return s.x+=a*u,s.y+=a*d,i>0&&(s.vx=u/i*a,s.vy=d/i*a),s.P=(1-a)*s.P,s}var M=class{constructor(e=1e-5,t=5e-5){this.lastTimestamp=0;this.Q=e,this.rBase=t,this.state={x:0,y:0,vx:0,vy:0,P:1};}init(e,t,n){this.state={x:e,y:t,vx:0,vy:0,P:1},this.lastTimestamp=n;}update(e,t,n,i){if(this.lastTimestamp===0)return this.init(e,t,i),[e,t];let r=Math.max(.001,(i-this.lastTimestamp)/1e3);return this.lastTimestamp=i,me(this.state,e,t,n,r,this.Q,this.rBase),[this.state.x,this.state.y]}getPosition(){return [this.state.x,this.state.y]}getState(){return {...this.state}}reset(){this.state={x:0,y:0,vx:0,vy:0,P:1},this.lastTimestamp=0;}};var ve={};Pe(ve,{ARRIVAL_THRESHOLD_METERS:()=>Ce,BASE_CORRIDOR_METERS:()=>L,BEARING_ALIGNMENT_THRESHOLD:()=>be,BEARING_MIN_SPEED_MPS:()=>z,BEARING_MISMATCH_PENALTY:()=>ye,BEARING_MISMATCH_THRESHOLD:()=>q,BEARING_SMOOTHING_ALPHA:()=>k,BETA_CORRECTION:()=>Ee,DETOUR_COMMIT_MS:()=>Ue,DR_MAX_AGE_MS:()=>Y,GPS_ACCURACY_FACTOR:()=>ge,GPS_AGE_CAP_SECONDS:()=>Se,GPS_STALE_MS:()=>Ie,INERTIA_PENALTY:()=>Re,INERTIA_SEGMENT_DIST:()=>xe,LOOK_AHEAD_SECONDS:()=>Ve,MANEUVER_TRIGGER_DIST:()=>Be,MAX_CORRIDOR_METERS:()=>$,MAX_LOOK_AHEAD_METERS:()=>We,MAX_SNAP_DISTANCE:()=>J,MIN_LOOK_AHEAD_METERS:()=>He,OFF_ROUTE_CONFIRM_MS:()=>Fe,REJOIN_CONFIRM_MS:()=>Ge,REJOIN_COOLDOWN_MS:()=>Le,SNAP_WINDOW_SIZE:()=>X,SPEED_CORRIDOR_FACTOR:()=>fe,STARTUP_GRACE_MS:()=>ke});var L=25,$=60,fe=1.2,ge=.5,J=80,q=90,ye=500,Re=200,xe=5,X=25,k=.3,z=1.5,be=55,Y=5e3,Fe=2e3,Ge=1500,Le=12e3,ke=3e3,Ue=4e3,Ie=3e3,Se=10,Be=25,Ee=.15,Ve=3,He=20,We=100,Ce=30;var Ke={useBearingPenalty:true,useInertiaPenalty:true,maxSnapDistance:80},T=class{constructor(e){this.options={...Ke,...e};}snap(e,t,n,i,r,o,c,a=null,u=null){let d=t.length,l=c,p=1/0,g=1/0,C=t[c]??[0,0];for(let x=0;x<=i;x++){let h=n+x;if(h>d-2)if(r&&o>d*.7)h=h%(d-1);else break;if(h<0||h>=d-1)continue;let b=t[h],R=t[h+1],S=W(e,b,R),v=m(e[1],e[0],S[1],S[0]);if(v>this.options.maxSnapDistance*2)continue;let I=v;if(this.options.useBearingPenalty&&a!==null){let _=f(b,R);Math.abs(y(a-_))>90&&(I+=500);}this.options.useInertiaPenalty&&u!==null&&Math.abs(h-u)>=5&&(I+=200),I<p&&(p=I,g=v,l=h,C=S);}return {idx:l,dist:g,proj:C}}};var je={bearingPenalty:80,bearingMismatchThresholdDeg:60,inertiaPenalty:40,inertiaSegmentDist:3},Q=class{constructor(e){this.options={...je,...e};}resolve(e,t=null,n=null){return e.map(i=>this.score(i,t,n)).sort((i,r)=>i.score-r.score)}resolveBest(e,t=null,n=null){return e.length===0?null:this.resolve(e,t,n)[0]??null}score(e,t,n){let i=e.distanceMetres,r=null,o=false;if(t!==null){let c=f(e.segA,e.segB),a=Math.abs(y(t-c));r=a,a>this.options.bearingMismatchThresholdDeg&&(i+=this.options.bearingPenalty);}return n!==null&&Math.abs(e.segmentIndex-n)>=this.options.inertiaSegmentDist&&(i+=this.options.inertiaPenalty,o=true),{...e,score:i,bearingDeltaDeg:r,inertiaPenaltyApplied:o}}isLikelyUTurn(e,t,n){let i=f(t,n);return Math.abs(y(e-i))>this.options.bearingMismatchThresholdDeg}};function Oe(s,e,t,n,i=5e3){if(!s||e<.5)return {predictedCoord:s?.coord??[0,0],isActive:false,ageMs:0};let r=n-s.ts;if(r>i||r<0)return {predictedCoord:s.coord,isActive:false,ageMs:r};let o=e*(r/1e3);return {predictedCoord:V(s.coord[1],s.coord[0],t,o),isActive:true,ageMs:r}}var D=class{constructor(e=5e3){this.anchor=null;this.maxAgeMs=e;}setAnchor(e,t,n){this.anchor={coord:e,idx:t,ts:n};}predict(e,t,n){return Oe(this.anchor,e,t,n,this.maxAgeMs)}clearAnchor(){this.anchor=null;}getAnchor(){return this.anchor}};function Ae(s,e,t,n,i=null){let r=Math.max(0,t),o=1/0,c=e[r]??[0,0],a=Math.min(t+n,e.length-1);for(let u=Math.max(0,t);u<a;u++){let d=e[u],l=e[u+1],[p,g]=s,[C,x]=d,[h,b]=l,R=h-C,S=b-x,v=R*R+S*S,I;if(v===0)I=d;else {let O=((p-C)*R+(g-x)*S)/v;O=Math.max(0,Math.min(1,O)),I=[C+O*R,x+O*S];}let _=m(s[1],s[0],I[1],I[0]);if(i!==null&&_<o*1.5){let O=f(d,l);if(Math.abs(y(i-O))>120)continue}_<o&&(o=_,r=u,c=I);}return {segmentIndex:r,distance:o,projection:c}}var N=class{evaluate(e,t,n,i,r,o,c){let a=i.distance>o,u=false;if(t!==null&&i.segmentIndex<r.length-1){let p=f(r[i.segmentIndex],r[i.segmentIndex+1]);u=Math.abs(y(t-p))>90;}let d=false;if(c!==null&&n>1.5){let p=r[Math.min(i.segmentIndex+2,r.length-1)];d=m(e[1],e[0],p[1],p[0])>c+5;}let l=a&&(u||d);return {distanceToRoute:i.distance,outsideCorridor:a,bearingMismatch:u,movingAway:d,confirmed:l}}};function Z(s,e=null,t=25,n=60,i=1.2,r=.5){let o=t+s*i;return e!==null&&e>0&&(o+=e*r),Math.min(o,n)}function _e(s,e=.3){return s<1.5?e*.5:s>20?Math.min(.9,e*2):e}function Me(s,e,t=3){let n=Math.min(e+t,s.length-1);return e>=s.length-1||e===n?e>0?f(s[e-1],s[e]):0:f(s[e],s[n])}function U(s,e,t){let n=y(e-s);return (s+t*n+360)%360}function ee(s,e,t,n,i,r=.3){let o=_e(n,r),c=Me(e,t);if(i!==null&&n>1.5){let a=U(s,i,o*.3);return U(a,c,o)}return U(s,c,o)}function te(s,e,t,n,i){return e<s||e>s+30||n>i?s:e}var $e=20,Je=60,qe=3;function ne(s,e,t,n,i,r,o,c=0){if(!e||e.length===0||t>=e.length)return {nextIdx:t,instruction:null,wasTriggered:false};let a=t;for(;a<e.length;){let h=e[a],b=s>h.geometryIndex+30,R=h.cumulativeOffset!==void 0&&o>h.cumulativeOffset+15;if(!b&&!R)break;a++;}if(a>=e.length)return {nextIdx:a,instruction:null,wasTriggered:false};let u=e[a],d=u.cumulativeOffset!==void 0?Math.max(0,u.cumulativeOffset-o):m(i[1],i[0],u.location[1],u.location[0]),l=Math.min(Je,Math.max($e,c*qe)),p=s<=u.geometryIndex+2,C=d<=l&&p,x=false;if(C){let h=true,b=u.bearingAfter??(u.geometryIndex<n.length-1?f(n[u.geometryIndex],n[u.geometryIndex+1]):null),R=u.bearingBefore??(u.geometryIndex>0?f(n[u.geometryIndex-1],n[u.geometryIndex]):null);R!==null&&b!==null&&r!==null&&Math.abs(y(b-R))>30&&Math.abs(y(r-b))>55&&(h=false),h&&(x=true);}return {nextIdx:a,instruction:u,wasTriggered:x}}var Xe=0;function P(){return `instr_${Date.now()}_${++Xe}`}var ie=class{constructor(){this.instructions=[];}addTurn(e,t,n,i){return this.instructions.push({id:P(),type:"turn",location:e,text:t,instruction:t,geometryIndex:n,silent:i?.silent,meta:i?.meta}),this}addExamPoint(e,t,n,i){return this.instructions.push({id:P(),type:"exam_point",location:e,text:t,instruction:t,geometryIndex:n,severity:i?.severity??"info",silent:i?.silent,meta:i?.meta}),this}addCheckpoint(e,t,n){return this.instructions.push({id:P(),type:"checkpoint",location:e,text:"",instruction:"",geometryIndex:t,silent:true,meta:n}),this}addDepart(e,t="Start navigation"){let n={id:P(),type:"depart",location:e,text:t,instruction:t,geometryIndex:0};return this.instructions.unshift(n),this}addArrive(e,t="You have arrived"){return this.instructions.push({id:P(),type:"arrive",location:e,text:t,instruction:t,geometryIndex:Number.MAX_SAFE_INTEGER}),this}update(e,t){let n=this.instructions.findIndex(i=>i.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions[n]={...this.instructions[n],...t},this}remove(e){let t=this.instructions.findIndex(n=>n.id===e);if(t===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions.splice(t,1),this}reorder(e,t){let n=this.instructions.findIndex(r=>r.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);let[i]=this.instructions.splice(n,1);return this.instructions.splice(Math.max(0,t),0,i),this}sort(){return this.instructions.sort((e,t)=>e.geometryIndex-t.geometryIndex),this}clear(){return this.instructions=[],this}attachToCumulative(e){if(e.length<2)return this;let t=[0];for(let n=1;n<e.length;n++){let i=e[n-1],r=e[n];t.push(t[n-1]+m(i[1],i[0],r[1],r[0]));}for(let n of this.instructions){let i=Math.min(n.geometryIndex,e.length-1);n.cumulativeOffset=t[i]??0,i>0&&i<e.length-1&&(n.bearingBefore=f(e[i-1],e[i]),n.bearingAfter=f(e[i],e[i+1]));}return this}toArray(){return this.instructions.map(({id:e,type:t,severity:n,meta:i,...r})=>r)}toRichArray(){return [...this.instructions]}get size(){return this.instructions.length}};function re(s,e,t){return s+e*t}function oe(s,e,t=.15){let n=e-s;return s+t*n}function ze(s,e,t){if(t.length===0)return [0,0];if(s<=0)return t[0];let n=e[e.length-1]??0;if(s>=n)return t[t.length-1];let i=0,r=e.length-1;for(;i<r-1;){let d=i+r>>1;e[d]<=s?i=d:r=d;}let o=e[i],a=e[r]-o;if(a===0)return t[i];let u=(s-o)/a;return H(t[i],t[r],u)}var w=class{constructor(){this._state="IDLE";this._context={resumeIndex:null};}get state(){return this._state}get context(){return {...this._context}}dispatch(e){switch(this._state){case "IDLE":e.type==="ROUTE_LOADED"&&(this._state="OVERVIEW"),e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "OVERVIEW":e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "APPROACHING_ROUTE":e.type==="ROUTE_JOINED"&&(this._state="ON_ROUTE",this._context.resumeIndex=e.data.index),e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE");break;case "ON_ROUTE":e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE"),e.type==="ROUTE_JOINED"&&(this._context.resumeIndex=e.data.index);break}return (e.type==="RESET"||e.type==="CANCEL_NAVIGATION")&&(this._state="IDLE",this._context={resumeIndex:null}),{state:this._state,context:{...this._context}}}reset(){this._state="IDLE",this._context={resumeIndex:null};}};var A={deviationSegmentIdx:null,deviationStartMs:null,tempRoute:null,rejoinTarget:null,lastRerouteMs:null,rejoinedAtMs:null,rejoinDwellFrames:0,failureReason:null},Te=2e3,Ye=3,F=class{constructor(){this._state="ON_ROUTE";this._context={...A};}get state(){return this._state}get context(){return {...this._context}}dispatch(e,t){let n=t??Date.now();switch(this._state){case "ON_ROUTE":e.type==="DEVIATION_SUSPECTED"&&(this._state="DEVIATING",this._context.deviationSegmentIdx=e.deviationSegmentIdx,this._context.deviationStartMs=n);break;case "DEVIATING":e.type==="DEVIATION_CONFIRMED"&&(this._context.deviationStartMs!==null?n-this._context.deviationStartMs:0)>=Te&&(this._state="OFF_ROUTE",this._context.deviationSegmentIdx=e.deviationSegmentIdx),(e.type==="RESUME"||e.type==="RESET")&&(this._state="ON_ROUTE",e.type==="RESET"?this._context={...A}:(this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null));break;case "OFF_ROUTE":e.type==="REROUTE_STARTED"&&(this._state="REROUTING",this._context.lastRerouteMs=n),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break;case "REROUTING":e.type==="REROUTE_SUCCESS"&&(this._state="REJOINING",this._context.tempRoute=e.tempRoute,this._context.rejoinTarget=e.rejoinTarget),e.type==="REROUTE_FAILED"&&(this._state="FAILED",this._context.failureReason=e.reason);break;case "REJOINING":e.type==="REJOIN_DETECTED"&&this._context.rejoinDwellFrames++,(e.type==="REJOIN_CONFIRMED"||this._context.rejoinDwellFrames>=Ye)&&(this._state="REJOINED",this._context.rejoinedAtMs=n,this._context.rejoinDwellFrames=0),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break;case "REJOINED":e.type==="RESUME"&&(this._state="ON_ROUTE",this._context.tempRoute=null,this._context.rejoinTarget=null,this._context.rejoinedAtMs=null,this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break;case "FAILED":e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...A});break}return {state:this._state,context:{...this._context}}}reset(){this._state="ON_ROUTE",this._context={...A};}isDeviationConfirmed(e=Date.now()){return this._context.deviationStartMs?e-this._context.deviationStartMs>=Te:false}};var Qe=0;function De(){return `wp_${Date.now()}_${++Qe}`}var se=class{constructor(){this.waypoints=[];}addWaypoint(e,t){let n=De();return this.waypoints.push({id:n,coord:e,options:t}),n}insertWaypoint(e,t){let n=this.waypoints.findIndex(r=>r.id===t);if(n===-1)throw new Error(`Waypoint ${t} not found`);let i=De();return this.waypoints.splice(n+1,0,{id:i,coord:e,options:void 0}),i}removeWaypoint(e){let t=this.waypoints.findIndex(n=>n.id===e);if(t===-1)throw new Error(`Waypoint ${e} not found`);this.waypoints.splice(t,1);}moveWaypoint(e,t){let n=this.waypoints.find(i=>i.id===e);if(!n)throw new Error(`Waypoint ${e} not found`);n.coord=t;}getWaypoints(){return this.waypoints}get size(){return this.waypoints.length}chunk(e="OVERLAP_1",t=25){let n=this.waypoints.map(c=>c.coord);if(n.length<=t)return [n];let r=t-(e==="OVERLAP_2"?2:1),o=[];for(let c=0;c<n.length;c+=r){let a=n.slice(c,c+t);if(o.push(a),c+t>=n.length)break}return o}buildStraightLine(){return {geometry:this.waypoints.map(e=>e.coord),waypoints:[...this.waypoints]}}fromGPX(e){this.waypoints=[];let t=/<(?:trkpt|wpt|rtept)\s+lat="([^"]+)"\s+lon="([^"]+)"/g,n;for(;(n=t.exec(e))!==null;){let i=parseFloat(n[1]),r=parseFloat(n[2]);isFinite(i)&&isFinite(r)&&this.addWaypoint([r,i]);}}toGPX(){return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1
|
+
var Ne=Object.defineProperty;var Pe=(s,e)=>{for(var t in e)Ne(s,t,{get:e[t],enumerable:true});};function y(s,e,t,n){let i=(t-s)*(Math.PI/180),r=(n-e)*(Math.PI/180),o=Math.sin(i/2)*Math.sin(i/2)+Math.cos(s*(Math.PI/180))*Math.cos(t*(Math.PI/180))*Math.sin(r/2)*Math.sin(r/2);return 6371e3*(2*Math.atan2(Math.sqrt(o),Math.sqrt(1-o)))}function B(s,e,t,n){let i=n/6371e3,r=t*(Math.PI/180),o=s*(Math.PI/180),c=e*(Math.PI/180),a=Math.asin(Math.sin(o)*Math.cos(i)+Math.cos(o)*Math.sin(i)*Math.cos(r));return [((c+Math.atan2(Math.sin(r)*Math.sin(i)*Math.cos(o),Math.cos(i)-Math.sin(o)*Math.sin(a)))*180/Math.PI+540)%360-180,a*180/Math.PI]}function we(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n),a=Math.atan2(o,c)*(180/Math.PI);return a=(a+360)%360,a}function E(s){let e=s%360;return e>180?e-360:e<-180?e+360:e}function R(s,e){let t=s[1]*(Math.PI/180),n=s[0]*(Math.PI/180),i=e[1]*(Math.PI/180),r=e[0]*(Math.PI/180),o=Math.sin(r-n)*Math.cos(i),c=Math.cos(t)*Math.sin(i)-Math.sin(t)*Math.cos(i)*Math.cos(r-n);return (Math.atan2(o,c)*180/Math.PI+360)%360}function W(s,e,t){let n=(i,r,o)=>i+(r-i)*o;return [n(s[0],e[0],t),n(s[1],e[1],t)]}function H(s,e,t){let[n,i]=s,[r,o]=e,[c,a]=t,u=c-r,d=a-o,l=u*u+d*d;if(l===0)return e;let p=((n-r)*u+(i-o)*d)/l;return p=Math.max(0,Math.min(1,p)),[r+p*u,o+p*d]}function K(s){let e=new Float64Array(s.length);for(let t=1;t<s.length;t++)e[t]=e[t-1]+y(s[t-1][1],s[t-1][0],s[t][1],s[t][0]);return e}function j(s){let e=new Float64Array(s.length);for(let t=s.length-2;t>=0;t--)e[t]=e[t+1]+y(s[t][1],s[t][0],s[t+1][1],s[t+1][0]);return e}function me(s,e,t,n,i,r=1e-5,o=5e-5){s.x+=s.vx*i,s.y+=s.vy*i,s.P+=r;let c=o*Math.max(1,n/5),a=s.P/(s.P+c),u=e-s.x,d=t-s.y;return s.x+=a*u,s.y+=a*d,i>0&&(s.vx=u/i*a,s.vy=d/i*a),s.P=(1-a)*s.P,s}var D=class{constructor(e=1e-5,t=5e-5){this.lastTimestamp=0;this.Q=e,this.rBase=t,this.state={x:0,y:0,vx:0,vy:0,P:1};}init(e,t,n){this.state={x:e,y:t,vx:0,vy:0,P:1},this.lastTimestamp=n;}update(e,t,n,i){if(this.lastTimestamp===0)return this.init(e,t,i),[e,t];let r=Math.max(.001,(i-this.lastTimestamp)/1e3);return this.lastTimestamp=i,me(this.state,e,t,n,r,this.Q,this.rBase),[this.state.x,this.state.y]}getPosition(){return [this.state.x,this.state.y]}getState(){return {...this.state}}reset(){this.state={x:0,y:0,vx:0,vy:0,P:1},this.lastTimestamp=0;}};var Se={};Pe(Se,{ARRIVAL_THRESHOLD_METERS:()=>Ce,BASE_CORRIDOR_METERS:()=>k,BEARING_ALIGNMENT_THRESHOLD:()=>xe,BEARING_MIN_SPEED_MPS:()=>z,BEARING_MISMATCH_PENALTY:()=>ye,BEARING_MISMATCH_THRESHOLD:()=>J,BEARING_SMOOTHING_ALPHA:()=>U,BETA_CORRECTION:()=>be,DETOUR_COMMIT_MS:()=>Ue,DR_MAX_AGE_MS:()=>Y,GPS_ACCURACY_FACTOR:()=>ge,GPS_AGE_CAP_SECONDS:()=>ve,GPS_STALE_MS:()=>Ie,INERTIA_PENALTY:()=>Re,INERTIA_SEGMENT_DIST:()=>Ee,LOOK_AHEAD_SECONDS:()=>Be,MANEUVER_TRIGGER_DIST:()=>Ve,MAX_CORRIDOR_METERS:()=>$,MAX_LOOK_AHEAD_METERS:()=>He,MAX_SNAP_DISTANCE:()=>q,MIN_LOOK_AHEAD_METERS:()=>We,OFF_ROUTE_CONFIRM_MS:()=>Fe,REJOIN_CONFIRM_MS:()=>Ge,REJOIN_COOLDOWN_MS:()=>Le,SNAP_WINDOW_SIZE:()=>X,SPEED_CORRIDOR_FACTOR:()=>fe,STARTUP_GRACE_MS:()=>ke});var k=25,$=60,fe=1.2,ge=.5,q=80,J=90,ye=500,Re=200,Ee=5,X=25,U=.3,z=1.5,xe=55,Y=5e3,Fe=2e3,Ge=1500,Le=12e3,ke=3e3,Ue=4e3,Ie=3e3,ve=10,Ve=25,be=.15,Be=3,We=20,He=100,Ce=30;var Ke={useBearingPenalty:true,useInertiaPenalty:true,maxSnapDistance:80},N=class{constructor(e){this.options={...Ke,...e};}snap(e,t,n,i,r,o,c,a=null,u=null){let d=t.length,l=c,p=1/0,f=1/0,I=t[c]??[0,0];for(let v=0;v<=i;v++){let g=n+v;if(g>d-2)if(r&&o>d*.7)g=g%(d-1);else break;if(g<0||g>=d-1)continue;let b=t[g],x=t[g+1],S=H(e,b,x),O=y(e[1],e[0],S[1],S[0]);if(O>this.options.maxSnapDistance*2)continue;let C=O;if(this.options.useBearingPenalty&&a!==null){let T=R(b,x);Math.abs(E(a-T))>90&&(C+=500);}this.options.useInertiaPenalty&&u!==null&&Math.abs(g-u)>=5&&(C+=200),C<p&&(p=C,f=O,l=g,I=S);}return {idx:l,dist:f,proj:I}}};var h={GPS_SMOOTHING:"gps_smoothing",BASIC_SNAPPING:"basic_snapping",PROGRESS_TRACKING:"progress_tracking",ROUTE_OFFSET:"route_offset",DEAD_RECKONING:"dead_reckoning",ADVANCED_BEARING:"advanced_bearing",COMPOUND_DEVIATION:"compound_deviation",PARALLEL_ROAD_RESOLUTION:"parallel_road_resolution",U_TURN_PROTECTION:"u_turn_protection",VOICE_TRIGGERS:"voice_triggers",ETA:"eta",GEOFENCING:"geofencing",NAV_AI:"nav_ai"};var A=class A{constructor(e){this.status="MISSING";this.payload=null;this.enabledFeatures=new Set;this.warnedFeatures=new Set;e&&(this.tryValidateSync(e)||this.validate(e)),this.promoteToActive();}static getActive(){return A.activeManager}static clearActive(){A.activeManager=null;}promoteToActive(){let e=A.activeManager;(e===null||e.status!=="VALID"||this.status==="VALID")&&(A.activeManager=this);}tryValidateSync(e){return e==="eyJ0IjoicHJvIiwiZXhwIjo0OTMyNzAzMTU2MDAwLCJiaWQiOiJkZXYuYnlwYXNzIiwiZiI6WyIqIl19.MEQCIH4E4QNu9PuVsXHSnYmcqpCLk4QitiIH9hhY0Zm+YO5gAiAE7X3c47YQLUj7WPSGKw9Y7W2kBUR5GCnOMBwdBsYGgg=="?typeof __DEV__<"u"&&__DEV__||typeof window<"u"&&(window.location?.hostname==="localhost"||window.location?.hostname==="127.0.0.1"||window.location?.hostname?.startsWith("192.168.")||window.location?.hostname?.endsWith(".local"))||typeof process<"u"&&(process.env?.NODE_ENV==="development"||process.env?.NODE_ENV==="test"||process.env?.VITEST==="true"||process.env?.JEST_WORKER_ID!==void 0)?(this.status="VALID",this.payload={t:"pro",exp:4932703156e3,bid:"dev.bypass",f:["*"]},this.extractFeatures(),console.log("\u{1F511} [NavCore] Development bypass key validated synchronously. Plan: pro"),true):(console.warn("[NavCore] Development bypass key is restricted to local development environments."),this.status="INVALID",this.payload=null,true):false}async validate(e){if(this.tryValidateSync(e))return this.status;try{let[t,n]=e.split(".");if(!t||!n)return this.status="INVALID",this.status;let i=atob(t);if(this.payload=JSON.parse(i),!this.payload||this.payload.exp<Date.now())return this.status="EXPIRED",this.status;if(!await this.verifySignature(t,n))return this.status="INVALID",this.status;if(this.payload?.bid==="dev.bypass"&&!(typeof __DEV__<"u"&&__DEV__||typeof window<"u"&&(window.location?.hostname==="localhost"||window.location?.hostname==="127.0.0.1"||window.location?.hostname?.startsWith("192.168.")||window.location?.hostname?.endsWith(".local"))||typeof process<"u"&&(process.env?.NODE_ENV==="development"||process.env?.NODE_ENV==="test"||process.env?.VITEST==="true"||process.env?.JEST_WORKER_ID!==void 0)))return console.warn("[NavCore] Development bypass key is restricted to local development environments."),this.status="INVALID",this.payload=null,this.status;this.status="VALID",this.extractFeatures(),this.promoteToActive(),console.log(`\u{1F511} [NavCore] License validation complete. Plan: ${this.isProEnabled()?"pro":"core"}`);}catch{this.status="INVALID";}return this.status}extractFeatures(){if(this.enabledFeatures.clear(),!!this.payload){if(Array.isArray(this.payload.f))for(let e of this.payload.f)this.enabledFeatures.add(e);this.payload.t==="pro"&&this.enabledFeatures.add("*");}}hasFeature(e){return this.status!=="VALID"?false:this.enabledFeatures.has("*")?true:this.enabledFeatures.has(e)}warnOnce(e){this.warnedFeatures.has(e)||(console.warn(`[NavCore] Feature '${e}' requires a Pro license`),this.warnedFeatures.add(e));}isProEnabled(){return this.hasFeature("*")}isAIEnabled(){return this.hasFeature(h.NAV_AI)}getStatus(){return this.status}getPayload(){return this.payload}getEnabledFeatures(){return Array.from(this.enabledFeatures)}async verifySignature(e,t){try{if(typeof crypto>"u"||!crypto.subtle)return !1;let i=new TextEncoder().encode(e),r=Uint8Array.from(atob(t),a=>a.charCodeAt(0)),o=Uint8Array.from(atob(A.PUBLIC_KEY_SPKI),a=>a.charCodeAt(0)),c=await crypto.subtle.importKey("spki",o,{name:"ECDSA",namedCurve:"P-256"},!0,["verify"]);return await crypto.subtle.verify({name:"ECDSA",hash:{name:"SHA-256"}},c,r,i)}catch{return false}}};A.activeManager=null,A.PUBLIC_KEY_SPKI="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk6onJmJkWtRFusiSS69dcdONX4xL2Snm4AZO+dYjSynfJiL4x7trEy80MImLftknBWT/qI0z7ox4Q7VNL3te6A==";var m=A;var je={bearingPenalty:80,bearingMismatchThresholdDeg:60,inertiaPenalty:40,inertiaSegmentDist:3},Q=class{constructor(e){this.warned=false;this.options={...je,...e};}resolve(e,t=null,n=null){let i=m.getActive();return (!i||!i.isProEnabled())&&(this.warned||(console.warn("[NavCore] ParallelRoadResolver and U-turn protection require a Pro license. Falling back to core distance snapping."),this.warned=true)),e.map(r=>this.score(r,t,n)).sort((r,o)=>r.score-o.score)}resolveBest(e,t=null,n=null){return e.length===0?null:this.resolve(e,t,n)[0]??null}score(e,t,n){let i=e.distanceMetres,r=null,o=false,c=m.getActive(),a=c&&c.isProEnabled();if(t!==null&&a){let u=R(e.segA,e.segB),d=Math.abs(E(t-u));r=d,d>this.options.bearingMismatchThresholdDeg&&(i+=this.options.bearingPenalty);}return n!==null&&a&&Math.abs(e.segmentIndex-n)>=this.options.inertiaSegmentDist&&(i+=this.options.inertiaPenalty,o=true),{...e,score:i,bearingDeltaDeg:r,inertiaPenaltyApplied:o}}isLikelyUTurn(e,t,n){let i=R(t,n);return Math.abs(E(e-i))>this.options.bearingMismatchThresholdDeg}};function Ae(s,e,t,n,i=5e3){if(!s||e<.5)return {predictedCoord:s?.coord??[0,0],isActive:false,ageMs:0};let r=n-s.ts;if(r>i||r<0)return {predictedCoord:s.coord,isActive:false,ageMs:r};let o=e*(r/1e3);return {predictedCoord:B(s.coord[1],s.coord[0],t,o),isActive:true,ageMs:r}}var P=class{constructor(e=5e3){this.anchor=null;this.warned=false;this.maxAgeMs=e;}setAnchor(e,t,n){this.anchor={coord:e,idx:t,ts:n};}predict(e,t,n){let i=m.getActive();return !i||!i.hasFeature(h.DEAD_RECKONING)?(this.warned||(i?i.warnOnce(h.DEAD_RECKONING):console.warn(`[NavCore] Feature '${h.DEAD_RECKONING}' requires a Pro license`),this.warned=true),{predictedCoord:this.anchor?.coord??[0,0],isActive:false,ageMs:0}):(this.warned=false,Ae(this.anchor,e,t,n,this.maxAgeMs))}clearAnchor(){this.anchor=null;}getAnchor(){return this.anchor}};function Oe(s,e,t,n,i=null){let r=Math.max(0,t),o=1/0,c=e[r]??[0,0],a=Math.min(t+n,e.length-1);for(let u=Math.max(0,t);u<a;u++){let d=e[u],l=e[u+1],[p,f]=s,[I,v]=d,[g,b]=l,x=g-I,S=b-v,O=x*x+S*S,C;if(O===0)C=d;else {let _=((p-I)*x+(f-v)*S)/O;_=Math.max(0,Math.min(1,_)),C=[I+_*x,v+_*S];}let T=y(s[1],s[0],C[1],C[0]);if(i!==null&&T<o*1.5){let _=R(d,l);if(Math.abs(E(i-_))>120)continue}T<o&&(o=T,r=u,c=C);}return {segmentIndex:r,distance:o,projection:c}}var w=class{constructor(){this.warned=false;}evaluate(e,t,n,i,r,o,c){let a=m.getActive();if(!a||!a.hasFeature(h.COMPOUND_DEVIATION))return this.warned||(a?a.warnOnce(h.COMPOUND_DEVIATION):console.warn(`[NavCore] Feature '${h.COMPOUND_DEVIATION}' requires a Pro license`),this.warned=true),{distanceToRoute:i.distance,outsideCorridor:false,bearingMismatch:false,movingAway:false,confirmed:false};this.warned=false;let u=i.distance>o,d=false;if(t!==null&&i.segmentIndex<r.length-1){let f=R(r[i.segmentIndex],r[i.segmentIndex+1]);d=Math.abs(E(t-f))>90;}let l=false;if(c!==null&&n>1.5){let f=r[Math.min(i.segmentIndex+2,r.length-1)];l=y(e[1],e[0],f[1],f[0])>c+5;}let p=u&&(d||l);return {distanceToRoute:i.distance,outsideCorridor:u,bearingMismatch:d,movingAway:l,confirmed:p}}};function Z(s,e=null,t=25,n=60,i=1.2,r=.5){let o=t+s*i;return e!==null&&e>0&&(o+=e*r),Math.min(o,n)}function _e(s,e=.3){return s<1.5?e*.5:s>20?Math.min(.9,e*2):e}function Me(s,e,t=3){let n=Math.min(e+t,s.length-1);return e>=s.length-1||e===n?e>0?R(s[e-1],s[e]):0:R(s[e],s[n])}function V(s,e,t){let n=E(e-s);return (s+t*n+360)%360}function ee(s,e,t,n,i,r=.3){let o=_e(n,r),c=Me(e,t);if(i!==null&&n>1.5){let a=V(s,i,o*.3);return V(a,c,o)}return V(s,c,o)}function te(s,e,t,n,i){return e<s||e>s+30||n>i?s:e}var $e=20,qe=60,Je=3;function ne(s,e,t,n,i,r,o,c=0){if(!e||e.length===0||t>=e.length)return {nextIdx:t,instruction:null,wasTriggered:false};let a=t;for(;a<e.length;){let g=e[a],b=s>g.geometryIndex+30,x=g.cumulativeOffset!==void 0&&o>g.cumulativeOffset+15;if(!b&&!x)break;a++;}if(a>=e.length)return {nextIdx:a,instruction:null,wasTriggered:false};let u=e[a],d=u.cumulativeOffset!==void 0?Math.max(0,u.cumulativeOffset-o):y(i[1],i[0],u.location[1],u.location[0]),l=Math.min(qe,Math.max($e,c*Je)),p=s<=u.geometryIndex+2,I=d<=l&&p,v=false;if(I){let g=true,b=u.bearingAfter??(u.geometryIndex<n.length-1?R(n[u.geometryIndex],n[u.geometryIndex+1]):null),x=u.bearingBefore??(u.geometryIndex>0?R(n[u.geometryIndex-1],n[u.geometryIndex]):null);x!==null&&b!==null&&r!==null&&Math.abs(E(b-x))>30&&Math.abs(E(r-b))>55&&(g=false),g&&(v=true);}return {nextIdx:a,instruction:u,wasTriggered:v}}var Xe=0;function F(){return `instr_${Date.now()}_${++Xe}`}var ie=class{constructor(){this.instructions=[];}addTurn(e,t,n,i){return this.instructions.push({id:F(),type:"turn",location:e,text:t,instruction:t,geometryIndex:n,silent:i?.silent,meta:i?.meta}),this}addExamPoint(e,t,n,i){return this.instructions.push({id:F(),type:"exam_point",location:e,text:t,instruction:t,geometryIndex:n,severity:i?.severity??"info",silent:i?.silent,meta:i?.meta}),this}addCheckpoint(e,t,n){return this.instructions.push({id:F(),type:"checkpoint",location:e,text:"",instruction:"",geometryIndex:t,silent:true,meta:n}),this}addDepart(e,t="Start navigation"){let n={id:F(),type:"depart",location:e,text:t,instruction:t,geometryIndex:0};return this.instructions.unshift(n),this}addArrive(e,t="You have arrived"){return this.instructions.push({id:F(),type:"arrive",location:e,text:t,instruction:t,geometryIndex:Number.MAX_SAFE_INTEGER}),this}update(e,t){let n=this.instructions.findIndex(i=>i.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions[n]={...this.instructions[n],...t},this}remove(e){let t=this.instructions.findIndex(n=>n.id===e);if(t===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);return this.instructions.splice(t,1),this}reorder(e,t){let n=this.instructions.findIndex(r=>r.id===e);if(n===-1)throw new Error(`[InstructionEditor] Instruction ${e} not found`);let[i]=this.instructions.splice(n,1);return this.instructions.splice(Math.max(0,t),0,i),this}sort(){return this.instructions.sort((e,t)=>e.geometryIndex-t.geometryIndex),this}clear(){return this.instructions=[],this}attachToCumulative(e){let t=m.getActive();if(!t||!t.isProEnabled())return console.warn("[NavCore] InstructionEditor requires a Pro license. Fluent editing is disabled."),this;if(e.length<2)return this;let n=[0];for(let i=1;i<e.length;i++){let r=e[i-1],o=e[i];n.push(n[i-1]+y(r[1],r[0],o[1],o[0]));}for(let i of this.instructions){let r=Math.min(i.geometryIndex,e.length-1);i.cumulativeOffset=n[r]??0,r>0&&r<e.length-1&&(i.bearingBefore=R(e[r-1],e[r]),i.bearingAfter=R(e[r],e[r+1]));}return this}toArray(){let e=m.getActive();return !e||!e.isProEnabled()?(console.warn("[NavCore] InstructionEditor.toArray() requires a Pro license. Returning empty instruction set."),[]):this.instructions.map(({id:t,type:n,severity:i,meta:r,...o})=>o)}toRichArray(){return [...this.instructions]}get size(){return this.instructions.length}};function re(s,e,t){return s+e*t}function oe(s,e,t=.15){let n=e-s;return s+t*n}function ze(s,e,t){if(t.length===0)return [0,0];if(s<=0)return t[0];let n=e[e.length-1]??0;if(s>=n)return t[t.length-1];let i=0,r=e.length-1;for(;i<r-1;){let d=i+r>>1;e[d]<=s?i=d:r=d;}let o=e[i],a=e[r]-o;if(a===0)return t[i];let u=(s-o)/a;return W(t[i],t[r],u)}var G=class{constructor(){this._state="IDLE";this._context={resumeIndex:null};}get state(){return this._state}get context(){return {...this._context}}dispatch(e){switch(this._state){case "IDLE":e.type==="ROUTE_LOADED"&&(this._state="OVERVIEW"),e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "OVERVIEW":e.type==="USER_START_NAVIGATION"&&(this._state="APPROACHING_ROUTE");break;case "APPROACHING_ROUTE":e.type==="ROUTE_JOINED"&&(this._state="ON_ROUTE",this._context.resumeIndex=e.data.index),e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE");break;case "ON_ROUTE":e.type==="NAVIGATION_FINISHED"&&(this._state="IDLE"),e.type==="ROUTE_JOINED"&&(this._context.resumeIndex=e.data.index);break}return (e.type==="RESET"||e.type==="CANCEL_NAVIGATION")&&(this._state="IDLE",this._context={resumeIndex:null}),{state:this._state,context:{...this._context}}}reset(){this._state="IDLE",this._context={resumeIndex:null};}};var M={deviationSegmentIdx:null,deviationStartMs:null,tempRoute:null,rejoinTarget:null,lastRerouteMs:null,rejoinedAtMs:null,rejoinDwellFrames:0,failureReason:null},Te=2e3,Ye=3,L=class{constructor(){this._state="ON_ROUTE";this._context={...M};}get state(){return this._state}get context(){return {...this._context}}dispatch(e,t){let n=t??Date.now();switch(this._state){case "ON_ROUTE":e.type==="DEVIATION_SUSPECTED"&&(this._state="DEVIATING",this._context.deviationSegmentIdx=e.deviationSegmentIdx,this._context.deviationStartMs=n);break;case "DEVIATING":e.type==="DEVIATION_CONFIRMED"&&(this._context.deviationStartMs!==null?n-this._context.deviationStartMs:0)>=Te&&(this._state="OFF_ROUTE",this._context.deviationSegmentIdx=e.deviationSegmentIdx),(e.type==="RESUME"||e.type==="RESET")&&(this._state="ON_ROUTE",e.type==="RESET"?this._context={...M}:(this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null));break;case "OFF_ROUTE":e.type==="REROUTE_STARTED"&&(this._state="REROUTING",this._context.lastRerouteMs=n),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break;case "REROUTING":e.type==="REROUTE_SUCCESS"&&(this._state="REJOINING",this._context.tempRoute=e.tempRoute,this._context.rejoinTarget=e.rejoinTarget),e.type==="REROUTE_FAILED"&&(this._state="FAILED",this._context.failureReason=e.reason);break;case "REJOINING":e.type==="REJOIN_DETECTED"&&this._context.rejoinDwellFrames++,(e.type==="REJOIN_CONFIRMED"||this._context.rejoinDwellFrames>=Ye)&&(this._state="REJOINED",this._context.rejoinedAtMs=n,this._context.rejoinDwellFrames=0),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break;case "REJOINED":e.type==="RESUME"&&(this._state="ON_ROUTE",this._context.tempRoute=null,this._context.rejoinTarget=null,this._context.rejoinedAtMs=null,this._context.deviationSegmentIdx=null,this._context.deviationStartMs=null),e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break;case "FAILED":e.type==="RESET"&&(this._state="ON_ROUTE",this._context={...M});break}return {state:this._state,context:{...this._context}}}reset(){this._state="ON_ROUTE",this._context={...M};}isDeviationConfirmed(e=Date.now()){return this._context.deviationStartMs?e-this._context.deviationStartMs>=Te:false}};var Qe=0;function De(){return `wp_${Date.now()}_${++Qe}`}var se=class{constructor(){this.waypoints=[];}addWaypoint(e,t){let n=De();return this.waypoints.push({id:n,coord:e,options:t}),n}insertWaypoint(e,t){let n=this.waypoints.findIndex(r=>r.id===t);if(n===-1)throw new Error(`Waypoint ${t} not found`);let i=De();return this.waypoints.splice(n+1,0,{id:i,coord:e,options:void 0}),i}removeWaypoint(e){let t=this.waypoints.findIndex(n=>n.id===e);if(t===-1)throw new Error(`Waypoint ${e} not found`);this.waypoints.splice(t,1);}moveWaypoint(e,t){let n=this.waypoints.find(i=>i.id===e);if(!n)throw new Error(`Waypoint ${e} not found`);n.coord=t;}getWaypoints(){return this.waypoints}get size(){return this.waypoints.length}chunk(e="OVERLAP_1",t=25){let n=this.waypoints.map(c=>c.coord);if(n.length<=t)return [n];let r=t-(e==="OVERLAP_2"?2:1),o=[];for(let c=0;c<n.length;c+=r){let a=n.slice(c,c+t);if(o.push(a),c+t>=n.length)break}return o}buildStraightLine(){return {geometry:this.waypoints.map(e=>e.coord),waypoints:[...this.waypoints]}}fromGPX(e){this.waypoints=[];let t=/<(?:trkpt|wpt|rtept)\s+lat="([^"]+)"\s+lon="([^"]+)"/g,n;for(;(n=t.exec(e))!==null;){let i=parseFloat(n[1]),r=parseFloat(n[2]);isFinite(i)&&isFinite(r)&&this.addWaypoint([r,i]);}}toGPX(){return `<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<gpx version="1.1" creator="NavCore SDK">
|
|
3
3
|
${this.waypoints.map(t=>` <wpt lat="${t.coord[1]}" lon="${t.coord[0]}">`+(t.options?.name?`
|
|
4
4
|
<name>${t.options.name}</name>`:"")+`
|
|
5
5
|
</wpt>`).join(`
|
|
6
6
|
`)}
|
|
7
|
-
</gpx>`}fromGeoJSON(e){if(this.waypoints=[],e.type==="FeatureCollection"&&e.features){for(let t of e.features)if(t.geometry.type==="Point"){let n=t.geometry.coordinates;this.addWaypoint(n);}else if(t.geometry.type==="LineString"){let n=t.geometry.coordinates;for(let i of n)this.addWaypoint(i);}}}toGeoJSON(){let e=this.waypoints.map((n,i)=>({type:"Feature",geometry:{type:"Point",coordinates:n.coord},properties:{id:n.id,order:i,name:n.options?.name??null,silent:n.options?.silent??false}})),t={type:"Feature",geometry:{type:"LineString",coordinates:this.waypoints.map(n=>n.coord)},properties:{type:"route"}};return {type:"FeatureCollection",features:[...e,t]}}clear(){this.waypoints=[];}};var ae=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),profile:e.profile??"driving",maxWaypointsPerChunk:e.maxWaypointsPerChunk??100};}async getRoute(e,t){if(e.length<2)throw new Error("[OSRM] At least 2 waypoints required");let n=t?.profile??this.config.profile;return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}async fetchRoute(e,t,n){let i=e.map(d=>`${d[0]},${d[1]}`).join(";"),r=n?.steps!==false?"true":"false",o=`${this.config.baseUrl}/route/v1/${t}/${i}?overview=full&geometries=geojson&steps=${r}&annotations=false`,c=await fetch(o);if(!c.ok)throw new Error(`[OSRM] HTTP ${c.status}: ${c.statusText}`);let a=await c.json();if(a.code!=="Ok"||!a.routes?.length)throw new Error(`[OSRM] No route found: ${a.code}`);let u=a.routes[0];return {geometry:u.geometry.coordinates,distance:u.distance,duration:u.duration,legs:(u.legs??[]).map(d=>({distance:d.distance,duration:d.duration,steps:(d.steps??[]).map(l=>({distance:l.distance,duration:l.duration,geometry:l.geometry?.coordinates??[],maneuver:{type:l.maneuver?.type??"unknown",modifier:l.maneuver?.modifier,location:l.maneuver?.location??[0,0],bearingBefore:l.maneuver?.bearing_before??0,bearingAfter:l.maneuver?.bearing_after??0,instruction:l.name??void 0},name:l.name}))})),raw:a}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var ce=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),costing:e.costing??"auto",apiKey:e.apiKey??"",maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[Valhalla] At least 2 waypoints required");let n=this.profileToCosting(t?.profile);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileToCosting(e){switch(e){case "cycling":return "bicycle";case "walking":return "pedestrian";default:return this.config.costing}}async fetchRoute(e,t,n){let i=e.map(p=>({lon:p[0],lat:p[1],type:"break"})),r=JSON.stringify({locations:i,costing:t,directions_options:{units:"kilometers"}}),o={"Content-Type":"application/json"};this.config.apiKey&&(o.api_key=this.config.apiKey);let c=await fetch(`${this.config.baseUrl}/route`,{method:"POST",headers:o,body:r});if(!c.ok){let p=await c.text();throw new Error(`[Valhalla] HTTP ${c.status}: ${p}`)}let a=await c.json(),u=this.decodePolyline(a.trip?.legs?.[0]?.shape??""),d=a.trip?.summary??{},l=(a.trip?.legs??[]).map(p=>({distance:(p.summary?.length??0)*1e3,duration:p.summary?.time??0,steps:(p.maneuvers??[]).map(g=>({distance:(g.length??0)*1e3,duration:g.time??0,geometry:[],maneuver:{type:g.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:g.begin_heading??0,bearingAfter:g.end_heading??0,instruction:g.instruction},name:g.street_names?.[0]}))}));return {geometry:u,distance:(d.length??0)*1e3,duration:d.time??0,legs:l,raw:a}}decodePolyline(e,t=6){let n=Math.pow(10,t),i=[],r=0,o=0,c=0;for(;r<e.length;){let a=0,u=0,d;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let l=(u&1)!==0?~(u>>1):u>>1;o+=l,a=0,u=0;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let p=(u&1)!==0?~(u>>1):u>>1;c+=p,i.push([c/n,o/n]);}return i}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var Ze="https://api.openrouteservice.org/v2/directions";var le=class{constructor(e){this.config={apiKey:e.apiKey,profile:e.profile??"driving-car",baseUrl:e.baseUrl??Ze,maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[ORS] At least 2 waypoints required");let n=this.profileFromOptions(t);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileFromOptions(e){switch(e?.profile){case "cycling":return "cycling-regular";case "walking":return "foot-walking";default:return this.config.profile}}async fetchRoute(e,t,n){let i=JSON.stringify({coordinates:e,instructions:n?.steps!==false,language:n?.language??"en"}),r=await fetch(`${this.config.baseUrl}/${t}/geojson`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:this.config.apiKey},body:i});if(!r.ok){let l=await r.text();throw new Error(`[ORS] HTTP ${r.status}: ${l}`)}let o=await r.json(),c=o.features?.[0];if(!c)throw new Error("[ORS] No route returned");let a=c.properties?.summary??{},d=(c.properties?.segments??[]).map(l=>({distance:l.distance??0,duration:l.duration??0,steps:(l.steps??[]).map(p=>({distance:p.distance??0,duration:p.duration??0,geometry:[],maneuver:{type:p.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:0,bearingAfter:0,instruction:p.instruction},name:p.name}))}));return {geometry:c.geometry?.coordinates??[],distance:a.distance??0,duration:a.duration??0,legs:d,raw:o}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var et={earlyTriggerMeters:120,lateTriggerMeters:20,reannounceMeters:300},ue=class{constructor(e){this.instructions=[];this.triggeredIds=new Set;this.reannouncedIds=new Set;this.options={...et,...e};}setInstructions(e){this.instructions=[...e],this.triggeredIds.clear(),this.reannouncedIds.clear();}update(e){let{distanceToNextInstruction:t,nextInstructionIndex:n}=e;if(n===null||t===null||n>=this.instructions.length)return null;let i=this.instructions[n],r=this.instrId(n),o=t;if(this.triggeredIds.has(r))return this.options.reannounceMeters>0&&!this.reannouncedIds.has(r)&&o<=this.options.reannounceMeters&&o>this.options.earlyTriggerMeters?(this.reannouncedIds.add(r),this.makeCue(i,o,"low")):null;if(o>this.options.earlyTriggerMeters)return null;if(o<-this.options.lateTriggerMeters)return this.triggeredIds.add(r),null;this.triggeredIds.add(r);let c=o<30?"urgent":o<60?"high":"normal";return this.makeCue(i,o,c)}onInstruction(e,t){let n=t.distanceToNextInstruction??0;return this.makeCue(e,n,"high")}reset(){this.triggeredIds.clear(),this.reannouncedIds.clear();}instrId(e){let t=this.instructions[e];return `${e}_${t?.geometryIndex??0}`}makeCue(e,t,n){return {instruction:e,text:e.text??e.instruction??"",distanceMetres:Math.max(0,t),priority:n,triggerId:`${e.geometryIndex}_${t.toFixed(0)}`}}};var tt={speedWindowSize:6,minimumSpeedMs:.5,fallbackSpeedMs:8.33},de=class{constructor(e){this.speedSamples=[];this.options={...tt,...e},this.lastReliableSpeed=this.options.fallbackSpeedMs;}update(e){let t=e.distanceToDestination??0,n=e.currentSpeed??0;this.speedSamples.push(n),this.speedSamples.length>this.options.speedWindowSize&&this.speedSamples.shift();let i=this.rollingAverage();i>=this.options.minimumSpeedMs&&(this.lastReliableSpeed=i);let r=i>=this.options.minimumSpeedMs?i:this.lastReliableSpeed,o=this.speedSamples.length>=Math.ceil(this.options.speedWindowSize/2)&&r>0&&t>0,c=r>0?t/r:0;return {etaSeconds:Math.round(c),etaMs:Date.now()+c*1e3,distanceRemainingM:t,averageSpeedMs:i,isReliable:o}}reset(){this.speedSamples=[],this.lastReliableSpeed=this.options.fallbackSpeedMs;}rollingAverage(){return this.speedSamples.length===0?0:this.speedSamples.reduce((t,n)=>t+n,0)/this.speedSamples.length}};var nt={dwellThresholdMs:1e4},pe=class{constructor(e){this.fences=new Map;this.states=new Map;this.options={...nt,...e};}addCircle(e,t,n,i){return this.fences.set(e,{kind:"circle",id:e,center:t,radiusM:n,meta:i}),this.states.set(e,{inside:false,enteredAtMs:null}),e}addPolygon(e,t,n){if(t.length<3)throw new Error("[Geofencing] Polygon requires at least 3 coordinates");return this.fences.set(e,{kind:"polygon",id:e,coords:t,meta:n}),this.states.set(e,{inside:false,enteredAtMs:null}),e}remove(e){this.fences.delete(e),this.states.delete(e);}clear(){this.fences.clear(),this.states.clear();}listIds(){return Array.from(this.fences.keys())}update(e){if(!e)return [];let t=[],n=Date.now();for(let[i,r]of this.fences){let o=this.states.get(i),c=this.contains(r,e);if(!o.inside&&c)o.inside=true,o.enteredAtMs=n,t.push({id:i,type:"enter",coord:e,meta:r.meta});else if(o.inside&&!c){o.inside=false;let a=o.enteredAtMs?n-o.enteredAtMs:0;o.enteredAtMs=null,t.push({id:i,type:"exit",coord:e,dwellMs:a,meta:r.meta});}else if(o.inside&&o.enteredAtMs!==null){let a=n-o.enteredAtMs;a>=this.options.dwellThresholdMs&&(t.push({id:i,type:"dwell",coord:e,dwellMs:a,meta:r.meta}),o.enteredAtMs=n);}}return t}isInside(e,t){let n=this.fences.get(e);return n?this.contains(n,t):false}contains(e,t){return e.kind==="circle"?m(t[1],t[0],e.center[1],e.center[0])<=e.radiusM:this.pointInPolygon(t,e.coords)}pointInPolygon(e,t){let[n,i]=e,r=false,o=t.length;for(let c=0,a=o-1;c<o;a=c++){let[u,d]=t[c],[l,p]=t[a];d>i!=p>i&&n<(l-u)*(i-d)/(p-d)+u&&(r=!r);}return r}};var E={GPS_SMOOTHING:"gps_smoothing",BASIC_SNAPPING:"basic_snapping",ADVANCED_SNAPPING:"advanced_snapping",DEAD_RECKONING:"dead_reckoning",ROUTE_OFFSET:"route_offset",PROGRESS_TRACKING:"progress_tracking",ADVANCED_BEARING:"advanced_bearing",COMPOUND_DEVIATION:"compound_deviation",PARALLEL_ROAD_RESOLUTION:"parallel_road_resolution",U_TURN_PROTECTION:"u_turn_protection",VOICE_TRIGGERS:"voice_triggers",ETA:"eta",GEOFENCING:"geofencing",NAV_AI:"nav_ai"};var B=class B{constructor(e,t){this.status="MISSING";this.payload=null;this.enabledFeatures=new Set;this.warnedFeatures=new Set;this.isDev=false;this.isDev=t??false,e&&this.validate(e);}async validate(e){try{if(this.status==="VALID"&&this.payload?.bid==="dev.bypass")return "VALID";let[t,n]=e.split(".");if(!t||!n)return this.status="INVALID",this.status;let i=atob(t);if(this.payload=JSON.parse(i),!this.payload||this.payload.exp<Date.now())return this.status="EXPIRED",this.status;if(!await this.verifySignature(t,n))return this.status="INVALID",this.status;this.status="VALID",this.extractFeatures(),console.log(`\u{1F511} [NavCore] License validation complete. Plan: ${this.isProEnabled()?"pro":"core"}`);}catch{this.status="INVALID";}return this.status}extractFeatures(){if(this.enabledFeatures.clear(),!!this.payload){if(Array.isArray(this.payload.f))for(let e of this.payload.f)this.enabledFeatures.add(e);this.payload.t==="pro"&&this.enabledFeatures.add("*");}}hasFeature(e){return this.isDev?true:this.status!=="VALID"?false:this.enabledFeatures.has("*")?true:this.enabledFeatures.has(e)}warnOnce(e){this.warnedFeatures.has(e)||(console.warn(`[NavCore] Feature '${e}' requires a Pro license \u2192 upgrade at https://navcore.dev/pricing`),this.warnedFeatures.add(e));}isProEnabled(){return this.hasFeature("*")}isAIEnabled(){return this.hasFeature(E.NAV_AI)}getStatus(){return this.status}getPayload(){return this.payload}getEnabledFeatures(){return Array.from(this.enabledFeatures)}async verifySignature(e,t){try{if(typeof crypto>"u"||!crypto.subtle)return !1;let i=new TextEncoder().encode(e),r=Uint8Array.from(atob(t),a=>a.charCodeAt(0)),o=Uint8Array.from(atob(B.PUBLIC_KEY_SPKI),a=>a.charCodeAt(0)),c=await crypto.subtle.importKey("spki",o,{name:"ECDSA",namedCurve:"P-256"},!0,["verify"]);return await crypto.subtle.verify({name:"ECDSA",hash:{name:"SHA-256"}},c,r,i)}catch{return false}}};B.PUBLIC_KEY_SPKI="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk6onJmJkWtRFusiSS69dcdONX4xL2Snm4AZO+dYjSynfJiL4x7trEy80MImLftknBWT/qI0z7ox4Q7VNL3te6A==";var G=B;var he=class{constructor(e){this.route=[];this.instructions=[];this.forwardCum=new Float64Array(0);this.reverseCum=new Float64Array(0);this.snappedCoord=null;this.rawGpsCoord=null;this.bearing=0;this.rawGpsBearing=null;this.routeIndex=0;this.maxProgressIdx=0;this.prevSegment=null;this.distanceToRoute=0;this.corridor=25;this.prevDistToNext=null;this.currentSpeed=0;this.lastGpsTimestamp=0;this.instrIdx=0;this.linearOffset=0;this.hasArrived=false;this.listeners=new Map;this.options={licenseKey:e?.licenseKey??"",isDev:e?.isDev??false,isCircuit:e?.isCircuit??false,kalmanQ:e?.kalmanQ??1e-5,kalmanRBase:e?.kalmanRBase??5e-5,baseCorridorMeters:e?.baseCorridorMeters??25,maxCorridorMeters:e?.maxCorridorMeters??60,arrivalThresholdMeters:e?.arrivalThresholdMeters??30,bearingSmoothingAlpha:e?.bearingSmoothingAlpha??.3},this.kalman=new M(this.options.kalmanQ,this.options.kalmanRBase),this.snapper=new T({useBearingPenalty:true,useInertiaPenalty:true}),this.deadReckoning=new D,this.deviationDetector=new N,this.lifecycleFSM=new w,this.offRouteFSM=new F,this.license=new G(this.options.licenseKey,this.options.isDev);}has(e){let t=this.license.hasFeature(e);return t||this.license.warnOnce(e),t}setRoute(e,t){this.route=e,this.instructions=t??[],this.forwardCum=K(e),this.reverseCum=j(e),this.routeIndex=0,this.maxProgressIdx=0,this.prevSegment=null,this.instrIdx=0,this.linearOffset=0,this.hasArrived=false,this.snappedCoord=null,this.prevDistToNext=null,this.lifecycleFSM.dispatch({type:"ROUTE_LOADED"}),this.emit("routeLoaded",{routeLength:e.length});}startNavigation(){this.lifecycleFSM.dispatch({type:"USER_START_NAVIGATION"}),this.emit("navigationStarted");}update(e){if(this.rawGpsCoord=e.coord,this.rawGpsBearing=e.bearing,this.currentSpeed=e.speed,this.lastGpsTimestamp=e.timestamp,this.route.length<2)return this.getState();let[t,n]=this.kalman.update(e.coord[0],e.coord[1],e.accuracy??10,e.timestamp),i=[t,n],r=Math.max(0,this.routeIndex-2),o=this.snapper.snap(i,this.route,r,25,this.options.isCircuit,this.maxProgressIdx,this.routeIndex,e.bearing,this.prevSegment);this.corridor=Z(e.speed,e.accuracy,this.options.baseCorridorMeters,this.options.maxCorridorMeters);let c=te(this.routeIndex,o.idx,this.route,o.dist,80);if(this.prevSegment=this.routeIndex,this.routeIndex=c,this.maxProgressIdx=Math.max(this.maxProgressIdx,c),this.snappedCoord=o.proj,this.distanceToRoute=o.dist,this.forwardCum.length>c){let a=this.forwardCum[c]??0;this.linearOffset=oe(this.linearOffset,a,.15);}if(this.has(E.ADVANCED_BEARING)?this.bearing=ee(this.bearing,this.route,this.routeIndex,e.speed,e.bearing,this.options.bearingSmoothingAlpha):e.bearing!==null&&(this.bearing=e.bearing),this.has(E.COMPOUND_DEVIATION)&&(this.offRouteFSM.state==="ON_ROUTE"||this.offRouteFSM.state==="DEVIATING")){let a=Ae(i,this.route,r,25),u=this.deviationDetector.evaluate(i,e.bearing,e.speed,a,this.route,this.corridor,this.prevDistToNext);if(a.segmentIndex<this.route.length-1){let d=this.route[Math.min(a.segmentIndex+2,this.route.length-1)];this.prevDistToNext=m(i[1],i[0],d[1],d[0]);}u.confirmed?this.offRouteFSM.state==="ON_ROUTE"?this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:a.segmentIndex}):this.offRouteFSM.isDeviationConfirmed()&&(this.offRouteFSM.dispatch({type:"DEVIATION_CONFIRMED",deviationSegmentIdx:a.segmentIndex}),this.emit("deviation",{anchorIndex:a.segmentIndex,ghostCoord:o.proj})):this.offRouteFSM.state==="DEVIATING"&&this.offRouteFSM.dispatch({type:"RESUME"});}else this.has(E.COMPOUND_DEVIATION)||(o.dist>this.corridor&&this.offRouteFSM.state==="ON_ROUTE"?(this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:o.idx}),this.emit("deviation",{anchorIndex:o.idx,ghostCoord:o.proj})):o.dist<=this.corridor&&this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.dispatch({type:"RESUME"}));if(this.lifecycleFSM.state==="APPROACHING_ROUTE"&&o.dist<this.corridor&&this.lifecycleFSM.dispatch({type:"ROUTE_JOINED",data:{index:o.idx}}),this.instructions.length>0){let a=ne(this.routeIndex,this.instructions,this.instrIdx,this.route,i,e.bearing,this.linearOffset,e.speed);a.nextIdx!==this.instrIdx&&(this.instrIdx=a.nextIdx),a.wasTriggered&&a.instruction&&(this.emit("instruction",a.instruction),this.instrIdx=a.nextIdx+1);}if(!this.hasArrived&&this.route.length>0){let a=this.route[this.route.length-1],u=m(i[1],i[0],a[1],a[0]),d=this.options.isCircuit?this.routeIndex>=this.route.length*.8:true;u<this.options.arrivalThresholdMeters&&d&&(this.hasArrived=true,this.lifecycleFSM.dispatch({type:"NAVIGATION_FINISHED"}),this.emit("arrival"));}return this.has(E.DEAD_RECKONING)&&this.deadReckoning.setAnchor(o.proj,o.idx,e.timestamp),this.getState()}tick(e){if(this.has(E.DEAD_RECKONING)){let t=this.deadReckoning.predict(this.currentSpeed,this.bearing,e);t.isActive&&(this.snappedCoord=t.predictedCoord);}if(this.lastGpsTimestamp>0){let t=(e-this.lastGpsTimestamp)/1e3;t>0&&t<10&&(this.linearOffset=re(this.linearOffset,this.currentSpeed,t));}return this.getState()}getState(){let e=this.route.length>0&&this.reverseCum.length>this.routeIndex?this.reverseCum[this.routeIndex]??null:null,t=this.instrIdx<this.instructions.length?(()=>{let i=this.instructions[this.instrIdx];return i.cumulativeOffset!==void 0?Math.max(0,i.cumulativeOffset-this.linearOffset):null})():null,n=this.lastGpsTimestamp>0?Date.now()-this.lastGpsTimestamp:0;return {snappedCoord:this.snappedCoord,rawGpsCoord:this.rawGpsCoord,bearing:this.bearing,rawGpsBearing:this.rawGpsBearing,routeIndex:this.routeIndex,distanceToRoute:this.distanceToRoute,corridor:this.corridor,isOffRoute:this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.state!=="DEVIATING",progressIndex:this.routeIndex,hasArrived:this.hasArrived,offRouteState:this.offRouteFSM.state,lifecycleState:this.lifecycleFSM.state,distanceToDestination:e,distanceToNextInstruction:t,nextInstructionIndex:this.instrIdx<this.instructions.length?this.instrIdx:null,currentSpeed:this.currentSpeed,isGpsStale:n>3e3,gpsAgeMs:n,licenseStatus:this.license.getStatus()}}destroy(){this.listeners.clear(),this.route=[],this.instructions=[],this.kalman.reset(),this.deadReckoning.clearAnchor(),this.lifecycleFSM.reset(),this.offRouteFSM.reset();}on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t);}off(e,t){let n=this.listeners.get(e);if(n){let i=n.indexOf(t);i>=0&&n.splice(i,1);}}emit(e,...t){let n=this.listeners.get(e);if(n)for(let i of n)i(...t);}getLicenseManager(){return this.license}getRoute(){return this.route}getInstructions(){return this.instructions}getOffRouteFSM(){return this.offRouteFSM}getLifecycleFSM(){return this.lifecycleFSM}};
|
|
8
|
-
export{
|
|
7
|
+
</gpx>`}fromGeoJSON(e){if(this.waypoints=[],e.type==="FeatureCollection"&&e.features){for(let t of e.features)if(t.geometry.type==="Point"){let n=t.geometry.coordinates;this.addWaypoint(n);}else if(t.geometry.type==="LineString"){let n=t.geometry.coordinates;for(let i of n)this.addWaypoint(i);}}}toGeoJSON(){let e=this.waypoints.map((n,i)=>({type:"Feature",geometry:{type:"Point",coordinates:n.coord},properties:{id:n.id,order:i,name:n.options?.name??null,silent:n.options?.silent??false}})),t={type:"Feature",geometry:{type:"LineString",coordinates:this.waypoints.map(n=>n.coord)},properties:{type:"route"}};return {type:"FeatureCollection",features:[...e,t]}}clear(){this.waypoints=[];}};var ae=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),profile:e.profile??"driving",maxWaypointsPerChunk:e.maxWaypointsPerChunk??100};}async getRoute(e,t){if(e.length<2)throw new Error("[OSRM] At least 2 waypoints required");let n=t?.profile??this.config.profile;return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}async fetchRoute(e,t,n){let i=e.map(d=>`${d[0]},${d[1]}`).join(";"),r=n?.steps!==false?"true":"false",o=`${this.config.baseUrl}/route/v1/${t}/${i}?overview=full&geometries=geojson&steps=${r}&annotations=false`,c=await fetch(o);if(!c.ok)throw new Error(`[OSRM] HTTP ${c.status}: ${c.statusText}`);let a=await c.json();if(a.code!=="Ok"||!a.routes?.length)throw new Error(`[OSRM] No route found: ${a.code}`);let u=a.routes[0];return {geometry:u.geometry.coordinates,distance:u.distance,duration:u.duration,legs:(u.legs??[]).map(d=>({distance:d.distance,duration:d.duration,steps:(d.steps??[]).map(l=>({distance:l.distance,duration:l.duration,geometry:l.geometry?.coordinates??[],maneuver:{type:l.maneuver?.type??"unknown",modifier:l.maneuver?.modifier,location:l.maneuver?.location??[0,0],bearingBefore:l.maneuver?.bearing_before??0,bearingAfter:l.maneuver?.bearing_after??0,instruction:l.name??void 0},name:l.name}))})),raw:a}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var ce=class{constructor(e){this.config={baseUrl:e.baseUrl.replace(/\/$/,""),costing:e.costing??"auto",apiKey:e.apiKey??"",maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[Valhalla] At least 2 waypoints required");let n=this.profileToCosting(t?.profile);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileToCosting(e){switch(e){case "cycling":return "bicycle";case "walking":return "pedestrian";default:return this.config.costing}}async fetchRoute(e,t,n){let i=e.map(p=>({lon:p[0],lat:p[1],type:"break"})),r=JSON.stringify({locations:i,costing:t,directions_options:{units:"kilometers"}}),o={"Content-Type":"application/json","User-Agent":"NavCoreSDK/1.0.0 (React Native; Expo; bab-bou-jeloud-demo)"};this.config.apiKey&&(o.api_key=this.config.apiKey);let c=await fetch(`${this.config.baseUrl}/route`,{method:"POST",headers:o,body:r});if(!c.ok){let p=await c.text();throw new Error(`[Valhalla] HTTP ${c.status}: ${p}`)}let a=await c.json(),u=this.decodePolyline(a.trip?.legs?.[0]?.shape??""),d=a.trip?.summary??{},l=(a.trip?.legs??[]).map(p=>({distance:(p.summary?.length??0)*1e3,duration:p.summary?.time??0,steps:(p.maneuvers??[]).map(f=>({distance:(f.length??0)*1e3,duration:f.time??0,geometry:[],maneuver:{type:f.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:f.begin_heading??0,bearingAfter:f.end_heading??0,instruction:f.instruction},name:f.street_names?.[0]}))}));return {geometry:u,distance:(d.length??0)*1e3,duration:d.time??0,legs:l,raw:a}}decodePolyline(e,t=6){let n=Math.pow(10,t),i=[],r=0,o=0,c=0;for(;r<e.length;){let a=0,u=0,d;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let l=(u&1)!==0?~(u>>1):u>>1;o+=l,a=0,u=0;do d=e.charCodeAt(r++)-63,u|=(d&31)<<a,a+=5;while(d>=32);let p=(u&1)!==0?~(u>>1):u>>1;c+=p,i.push([c/n,o/n]);}return i}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var Ze="https://api.openrouteservice.org/v2/directions";var le=class{constructor(e){this.config={apiKey:e.apiKey,profile:e.profile??"driving-car",baseUrl:e.baseUrl??Ze,maxWaypointsPerChunk:e.maxWaypointsPerChunk??50};}async getRoute(e,t){if(e.length<2)throw new Error("[ORS] At least 2 waypoints required");let n=this.profileFromOptions(t);return e.length<=this.config.maxWaypointsPerChunk?this.fetchRoute(e,n,t):this.fetchChunked(e,n,t)}profileFromOptions(e){switch(e?.profile){case "cycling":return "cycling-regular";case "walking":return "foot-walking";default:return this.config.profile}}async fetchRoute(e,t,n){let i=JSON.stringify({coordinates:e,instructions:n?.steps!==false,language:n?.language??"en"}),r=await fetch(`${this.config.baseUrl}/${t}/geojson`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:this.config.apiKey},body:i});if(!r.ok){let l=await r.text();throw new Error(`[ORS] HTTP ${r.status}: ${l}`)}let o=await r.json(),c=o.features?.[0];if(!c)throw new Error("[ORS] No route returned");let a=c.properties?.summary??{},d=(c.properties?.segments??[]).map(l=>({distance:l.distance??0,duration:l.duration??0,steps:(l.steps??[]).map(p=>({distance:p.distance??0,duration:p.duration??0,geometry:[],maneuver:{type:p.type?.toString()??"unknown",modifier:void 0,location:e[0],bearingBefore:0,bearingAfter:0,instruction:p.instruction},name:p.name}))}));return {geometry:c.geometry?.coordinates??[],distance:a.distance??0,duration:a.duration??0,legs:d,raw:o}}async fetchChunked(e,t,n){let i=this.config.maxWaypointsPerChunk,r=[];for(let l=0;l<e.length;l+=i-1){let p=e.slice(l,l+i);if(p.length<2||(r.push(p),l+i>=e.length))break}let o=await Promise.all(r.map(l=>this.fetchRoute(l,t,n))),c=[],a=0,u=0,d=[];for(let l=0;l<o.length;l++){let p=o[l];c.push(...l===0?p.geometry:p.geometry.slice(1)),a+=p.distance,u+=p.duration,d.push(...p.legs);}return {geometry:c,distance:a,duration:u,legs:d,raw:o.map(l=>l.raw)}}};var et={earlyTriggerMeters:120,lateTriggerMeters:20,reannounceMeters:300},ue=class{constructor(e){this.instructions=[];this.triggeredIds=new Set;this.reannouncedIds=new Set;this.options={...et,...e};}setInstructions(e){this.instructions=[...e],this.triggeredIds.clear(),this.reannouncedIds.clear();}update(e){let t=m.getActive();if(!t||!t.hasFeature(h.VOICE_TRIGGERS))return t?t.warnOnce(h.VOICE_TRIGGERS):console.warn(`[NavCore] Feature '${h.VOICE_TRIGGERS}' requires a Pro license`),null;let{distanceToNextInstruction:n,nextInstructionIndex:i}=e;if(i===null||n===null||i>=this.instructions.length)return null;let r=this.instructions[i],o=this.instrId(i),c=n;if(this.triggeredIds.has(o))return this.options.reannounceMeters>0&&!this.reannouncedIds.has(o)&&c<=this.options.reannounceMeters&&c>this.options.earlyTriggerMeters?(this.reannouncedIds.add(o),this.makeCue(r,c,"low")):null;if(c>this.options.earlyTriggerMeters)return null;if(c<-this.options.lateTriggerMeters)return this.triggeredIds.add(o),null;this.triggeredIds.add(o);let a=c<30?"urgent":c<60?"high":"normal";return this.makeCue(r,c,a)}onInstruction(e,t){let n=m.getActive();if(!n||!n.hasFeature(h.VOICE_TRIGGERS))return n?n.warnOnce(h.VOICE_TRIGGERS):console.warn(`[NavCore] Feature '${h.VOICE_TRIGGERS}' requires a Pro license`),{instruction:e,text:"",distanceMetres:0,priority:"normal",triggerId:"bypass"};let i=t.distanceToNextInstruction??0;return this.makeCue(e,i,"high")}reset(){this.triggeredIds.clear(),this.reannouncedIds.clear();}instrId(e){let t=this.instructions[e];return `${e}_${t?.geometryIndex??0}`}makeCue(e,t,n){return {instruction:e,text:e.text??e.instruction??"",distanceMetres:Math.max(0,t),priority:n,triggerId:`${e.geometryIndex}_${t.toFixed(0)}`}}};var tt={speedWindowSize:6,minimumSpeedMs:.5,fallbackSpeedMs:8.33},de=class{constructor(e){this.speedSamples=[];this.options={...tt,...e},this.lastReliableSpeed=this.options.fallbackSpeedMs;}update(e){let t=m.getActive();if(!t||!t.hasFeature(h.ETA))return t?t.warnOnce(h.ETA):console.warn(`[NavCore] Feature '${h.ETA}' requires a Pro license`),{etaSeconds:0,etaMs:0,distanceRemainingM:0,averageSpeedMs:0,isReliable:false};let n=e.distanceToDestination??0,i=e.currentSpeed??0;this.speedSamples.push(i),this.speedSamples.length>this.options.speedWindowSize&&this.speedSamples.shift();let r=this.rollingAverage();r>=this.options.minimumSpeedMs&&(this.lastReliableSpeed=r);let o=r>=this.options.minimumSpeedMs?r:this.lastReliableSpeed,c=this.speedSamples.length>=Math.ceil(this.options.speedWindowSize/2)&&o>0&&n>0,a=o>0?n/o:0;return {etaSeconds:Math.round(a),etaMs:Date.now()+a*1e3,distanceRemainingM:n,averageSpeedMs:r,isReliable:c}}reset(){this.speedSamples=[],this.lastReliableSpeed=this.options.fallbackSpeedMs;}rollingAverage(){return this.speedSamples.length===0?0:this.speedSamples.reduce((t,n)=>t+n,0)/this.speedSamples.length}};var nt={dwellThresholdMs:1e4},pe=class{constructor(e){this.fences=new Map;this.states=new Map;if(this.options={...nt,...e},this.options.zones)for(let t of this.options.zones)t.type==="circle"&&t.center&&t.radiusMeters?this.addCircle(t.id,t.name,t.center,t.radiusMeters,t.meta):t.type==="polygon"&&t.coords&&this.addPolygon(t.id,t.name,t.coords,t.meta);}addCircle(e,t,n,i,r){return this.fences.set(e,{kind:"circle",id:e,name:t,center:n,radiusM:i,meta:r}),this.states.set(e,{inside:false,enteredAtMs:null}),e}addPolygon(e,t,n,i){if(n.length<3)throw new Error("[Geofencing] Polygon requires at least 3 coordinates");return this.fences.set(e,{kind:"polygon",id:e,name:t,coords:n,meta:i}),this.states.set(e,{inside:false,enteredAtMs:null}),e}remove(e){this.fences.delete(e),this.states.delete(e);}clear(){this.fences.clear(),this.states.clear();}listIds(){return Array.from(this.fences.keys())}update(e){let t=m.getActive();if(!t||!t.hasFeature(h.GEOFENCING))return t?t.warnOnce(h.GEOFENCING):console.warn(`[NavCore] Feature '${h.GEOFENCING}' requires a Pro license`),[];if(!e)return [];let n=[],i=Date.now();for(let[r,o]of this.fences){let c=this.states.get(r),a=this.contains(o,e);if(!c.inside&&a){c.inside=true,c.enteredAtMs=i;let u={id:r,name:o.name,type:"enter",coord:e,meta:o.meta};n.push(u),this.options.onEvent?.(u);}else if(c.inside&&!a){c.inside=false;let u=c.enteredAtMs?i-c.enteredAtMs:0;c.enteredAtMs=null;let d={id:r,name:o.name,type:"exit",coord:e,dwellMs:u,meta:o.meta};n.push(d),this.options.onEvent?.(d);}else if(c.inside&&c.enteredAtMs!==null){let u=i-c.enteredAtMs;if(u>=this.options.dwellThresholdMs){let d={id:r,name:o.name,type:"dwell",coord:e,dwellMs:u,meta:o.meta};n.push(d),this.options.onEvent?.(d),c.enteredAtMs=i;}}}return n}isInside(e,t){let n=this.fences.get(e);return n?this.contains(n,t):false}contains(e,t){return e.kind==="circle"?y(t[1],t[0],e.center[1],e.center[0])<=e.radiusM:this.pointInPolygon(t,e.coords)}pointInPolygon(e,t){let[n,i]=e,r=false,o=t.length;for(let c=0,a=o-1;c<o;a=c++){let[u,d]=t[c],[l,p]=t[a];d>i!=p>i&&n<(l-u)*(i-d)/(p-d)+u&&(r=!r);}return r}};var he=class{constructor(e){this.route=[];this.instructions=[];this.forwardCum=new Float64Array(0);this.reverseCum=new Float64Array(0);this.snappedCoord=null;this.rawGpsCoord=null;this.bearing=0;this.rawGpsBearing=null;this.routeIndex=0;this.maxProgressIdx=0;this.prevSegment=null;this.distanceToRoute=0;this.corridor=25;this.prevDistToNext=null;this.currentSpeed=0;this.lastGpsTimestamp=0;this.instrIdx=0;this.linearOffset=0;this.hasArrived=false;this.listeners=new Map;this.options={licenseKey:e?.licenseKey??"",isCircuit:e?.isCircuit??false,kalmanQ:e?.kalmanQ??1e-5,kalmanRBase:e?.kalmanRBase??5e-5,baseCorridorMeters:e?.baseCorridorMeters??25,maxCorridorMeters:e?.maxCorridorMeters??60,arrivalThresholdMeters:e?.arrivalThresholdMeters??30,bearingSmoothingAlpha:e?.bearingSmoothingAlpha??.3},this.kalman=new D(this.options.kalmanQ,this.options.kalmanRBase),this.snapper=new N({useBearingPenalty:true,useInertiaPenalty:true}),this.deadReckoning=new P,this.deviationDetector=new w,this.lifecycleFSM=new G,this.offRouteFSM=new L,this.license=new m(this.options.licenseKey);}has(e){let t=this.license.hasFeature(e);return t||this.license.warnOnce(e),t}setRoute(e,t){this.route=e,this.instructions=t??[],this.forwardCum=K(e),this.reverseCum=j(e),this.routeIndex=0,this.maxProgressIdx=0,this.prevSegment=null,this.instrIdx=0,this.linearOffset=0,this.hasArrived=false,this.snappedCoord=null,this.prevDistToNext=null,this.lifecycleFSM.dispatch({type:"ROUTE_LOADED"}),this.emit("routeLoaded",{routeLength:e.length});}startNavigation(){this.lifecycleFSM.dispatch({type:"USER_START_NAVIGATION"}),this.emit("navigationStarted");}update(e){if(this.rawGpsCoord=e.coord,this.rawGpsBearing=e.bearing,this.currentSpeed=e.speed,this.lastGpsTimestamp=e.timestamp,this.route.length<2)return this.getState();let[t,n]=this.kalman.update(e.coord[0],e.coord[1],e.accuracy??10,e.timestamp),i=[t,n],r=Math.max(0,this.routeIndex-2),o=this.snapper.snap(i,this.route,r,25,this.options.isCircuit,this.maxProgressIdx,this.routeIndex,e.bearing,this.prevSegment);this.corridor=Z(e.speed,e.accuracy,this.options.baseCorridorMeters,this.options.maxCorridorMeters);let c=te(this.routeIndex,o.idx,this.route,o.dist,80);if(this.prevSegment=this.routeIndex,this.routeIndex=c,this.maxProgressIdx=Math.max(this.maxProgressIdx,c),this.snappedCoord=o.proj,this.distanceToRoute=o.dist,this.forwardCum.length>c){let a=this.forwardCum[c]??0;this.linearOffset=oe(this.linearOffset,a,.15);}if(this.has(h.ADVANCED_BEARING)?this.bearing=ee(this.bearing,this.route,this.routeIndex,e.speed,e.bearing,this.options.bearingSmoothingAlpha):e.bearing!==null&&(this.bearing=e.bearing),this.has(h.COMPOUND_DEVIATION)&&(this.offRouteFSM.state==="ON_ROUTE"||this.offRouteFSM.state==="DEVIATING")){let a=Oe(i,this.route,r,25),u=this.deviationDetector.evaluate(i,e.bearing,e.speed,a,this.route,this.corridor,this.prevDistToNext);if(a.segmentIndex<this.route.length-1){let d=this.route[Math.min(a.segmentIndex+2,this.route.length-1)];this.prevDistToNext=y(i[1],i[0],d[1],d[0]);}u.confirmed?this.offRouteFSM.state==="ON_ROUTE"?this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:a.segmentIndex}):this.offRouteFSM.isDeviationConfirmed()&&(this.offRouteFSM.dispatch({type:"DEVIATION_CONFIRMED",deviationSegmentIdx:a.segmentIndex}),this.emit("deviation",{anchorIndex:a.segmentIndex,ghostCoord:o.proj})):this.offRouteFSM.state==="DEVIATING"&&this.offRouteFSM.dispatch({type:"RESUME"});}else this.has(h.COMPOUND_DEVIATION)||(o.dist>this.corridor&&this.offRouteFSM.state==="ON_ROUTE"?(this.offRouteFSM.dispatch({type:"DEVIATION_SUSPECTED",deviationSegmentIdx:o.idx}),this.emit("deviation",{anchorIndex:o.idx,ghostCoord:o.proj})):o.dist<=this.corridor&&this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.dispatch({type:"RESUME"}));if(this.lifecycleFSM.state==="APPROACHING_ROUTE"&&o.dist<this.corridor&&this.lifecycleFSM.dispatch({type:"ROUTE_JOINED",data:{index:o.idx}}),this.instructions.length>0){let a=ne(this.routeIndex,this.instructions,this.instrIdx,this.route,i,e.bearing,this.linearOffset,e.speed);a.nextIdx!==this.instrIdx&&(this.instrIdx=a.nextIdx),a.wasTriggered&&a.instruction&&(this.emit("instruction",a.instruction),this.instrIdx=a.nextIdx+1);}if(!this.hasArrived&&this.route.length>0){let a=this.route[this.route.length-1],u=y(i[1],i[0],a[1],a[0]),d=this.options.isCircuit?this.routeIndex>=this.route.length*.8:true;u<this.options.arrivalThresholdMeters&&d&&(this.hasArrived=true,this.lifecycleFSM.dispatch({type:"NAVIGATION_FINISHED"}),this.emit("arrival"));}return this.has(h.DEAD_RECKONING)&&this.deadReckoning.setAnchor(o.proj,o.idx,e.timestamp),this.getState()}tick(e){if(this.has(h.DEAD_RECKONING)){let t=this.deadReckoning.predict(this.currentSpeed,this.bearing,e);t.isActive&&(this.snappedCoord=t.predictedCoord);}if(this.lastGpsTimestamp>0){let t=(e-this.lastGpsTimestamp)/1e3;t>0&&t<10&&(this.linearOffset=re(this.linearOffset,this.currentSpeed,t));}return this.getState()}getState(){let e=this.route.length>0&&this.reverseCum.length>this.routeIndex?this.reverseCum[this.routeIndex]??null:null,t=this.instrIdx<this.instructions.length?(()=>{let i=this.instructions[this.instrIdx];return i.cumulativeOffset!==void 0?Math.max(0,i.cumulativeOffset-this.linearOffset):null})():null,n=this.lastGpsTimestamp>0?Date.now()-this.lastGpsTimestamp:0;return {snappedCoord:this.snappedCoord,rawGpsCoord:this.rawGpsCoord,bearing:this.bearing,rawGpsBearing:this.rawGpsBearing,routeIndex:this.routeIndex,distanceToRoute:this.distanceToRoute,corridor:this.corridor,isOffRoute:this.offRouteFSM.state!=="ON_ROUTE"&&this.offRouteFSM.state!=="DEVIATING",progressIndex:this.routeIndex,hasArrived:this.hasArrived,offRouteState:this.offRouteFSM.state,lifecycleState:this.lifecycleFSM.state,distanceToDestination:e,distanceToNextInstruction:t,nextInstructionIndex:this.instrIdx<this.instructions.length?this.instrIdx:null,currentSpeed:this.currentSpeed,isGpsStale:n>3e3,gpsAgeMs:n,licenseStatus:this.license.getStatus()}}destroy(){this.listeners.clear(),this.route=[],this.instructions=[],this.kalman.reset(),this.deadReckoning.clearAnchor(),this.lifecycleFSM.reset(),this.offRouteFSM.reset();}on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t);}off(e,t){let n=this.listeners.get(e);if(n){let i=n.indexOf(t);i>=0&&n.splice(i,1);}}emit(e,...t){let n=this.listeners.get(e);if(n)for(let i of n)i(...t);}getLicenseManager(){return this.license}getRoute(){return this.route}getInstructions(){return this.instructions}getOffRouteFSM(){return this.offRouteFSM}getLifecycleFSM(){return this.lifecycleFSM}};
|
|
8
|
+
export{Se as Constants,se as CustomRouteBuilder,P as DeadReckoningEngine,w as DeviationDetector,de as ETAEngine,h as FEATURES,pe as GeofencingEngine,ie as InstructionEditor,D as KalmanFilter2D,m as LicenseManager,he as NavCore,G as NavigationFSM,ae as OSRMDirectionsProvider,L as OffRouteFSM,le as OpenRouteServiceProvider,Q as ParallelRoadResolver,N as RouteSnapper,ce as ValhallaDirectionsProvider,ue as VoiceTriggerEngine,re as advancePredictor,ee as applyBearingSmoothing,oe as applyGpsCorrection,V as blendBearing,K as buildForwardCumulativeDistances,j as buildReverseCumulativeDistances,Z as calculateDynamicCorridor,Me as calculateRobustBearing,Ae as computeDeadReckoningOnRoute,B as destinationPoint,we as geoGetBearing,R as getBearingBetweenPoints,_e as getSpeedAdaptiveAlpha,y as haversineDistance,W as interpolatePoint,me as kalmanUpdate2D,E as normalizeAngle,ze as pointAtOffset,H as projectPointOnSegment,ne as resolveNextInstruction,te as validateProgressUpdate};
|