UNPKG

@codewithvincent/react-native-gps-filter

Version:

Kalman-based adaptive GPS filter for React Native.

120 lines (119 loc) 5.75 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.useLocationStore = void 0; //@ts-ignore const zustand_1 = require("zustand"); //@ts-ignore const kalmanjs_1 = __importDefault(require("kalmanjs")); const locationFilters_1 = require("../utils/locationFilters"); const helpers_1 = require("../utils/helpers"); const MIN_DISTANCE_FOR_ROUTE_DRAWING = 10; // meters, adjust as needed //@ts-ignore exports.useLocationStore = (0, zustand_1.create)((set, get) => ({ kalmanFilterLat: new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions), kalmanFilterLon: new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions), consecutiveRejectCount: 0, totalDistanceTraveled: 0, lastAcceptedPredictedLocation: null, currentSpeed: 0, runStartTimeInMillis: Date.now(), routeCoordinates: [], //@ts-ignore filterAndAddLocation(location, onPredictLocation) { const now = Date.now(); const age = now - location.timestamp; if (age > 10000) return { result: false, reason: "old" }; //@ts-ignore if (location.coords.accuracy <= 0) return { result: false, reason: "no_accuracy" }; //@ts-ignore if (location.coords.accuracy > 100) return { result: false, reason: "inaccurate" }; const state = get(); const speed = location.coords.speed || 0; const { minDelta, maxDelta, maxAllowedDelta, mode } = (0, locationFilters_1.getAdaptiveThresholds)(speed); const isMoving = speed > locationFilters_1.GPS_SPEED_THRESHOLD; if (!state.lastAcceptedPredictedLocation) { state.kalmanFilterLat.filter(location.coords.latitude); state.kalmanFilterLon.filter(location.coords.longitude); set({ lastAcceptedPredictedLocation: location }); return { result: true, acceptedLocation: location, predictedLocation: location, distanceTraveled: 0, }; } const predictedLat = state.kalmanFilterLat.filter(location.coords.latitude); const predictedLon = state.kalmanFilterLon.filter(location.coords.longitude); const predictedDelta = (0, helpers_1.getDistanceFromLatLonInMeters)(predictedLat, predictedLon, location.coords.latitude, location.coords.longitude); if (predictedDelta > maxAllowedDelta) { const rejectCount = state.consecutiveRejectCount + 1; if (rejectCount > locationFilters_1.KALMAN_REJECT_THRESHOLD) { set({ kalmanFilterLat: new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions), kalmanFilterLon: new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions), consecutiveRejectCount: 0, }); } else { set({ consecutiveRejectCount: rejectCount }); } return { result: false, reason: `kalman_reject_${mode}` }; } else { set({ consecutiveRejectCount: 0 }); } const predictedLocation = Object.assign(Object.assign({}, location), { coords: Object.assign(Object.assign({}, location.coords), { latitude: predictedLat, longitude: predictedLon }) }); const lastAccepted = state.lastAcceptedPredictedLocation; const distanceSinceLast = (0, helpers_1.getDistanceFromLatLonInMeters)(predictedLat, predictedLon, lastAccepted.coords.latitude, lastAccepted.coords.longitude); if (isMoving && distanceSinceLast > minDelta && distanceSinceLast < maxDelta) { const newTotalDistance = state.totalDistanceTraveled + distanceSinceLast; const routeCoordinates = [...state.routeCoordinates]; const lastPointInRoute = routeCoordinates.length ? routeCoordinates[routeCoordinates.length - 1] : null; if (!lastPointInRoute || (0, helpers_1.getDistanceFromLatLonInMeters)(lastPointInRoute[1], lastPointInRoute[0], predictedLocation.coords.latitude, predictedLocation.coords.longitude) >= MIN_DISTANCE_FOR_ROUTE_DRAWING) { routeCoordinates.push([ predictedLocation.coords.longitude, predictedLocation.coords.latitude, ]); console.log("Adding significant point to route:", routeCoordinates.slice(-1)[0]); } set({ totalDistanceTraveled: newTotalDistance, lastAcceptedPredictedLocation: predictedLocation, currentSpeed: speed, routeCoordinates, }); if (onPredictLocation) { onPredictLocation(predictedLocation); } return { result: true, acceptedLocation: location, predictedLocation, distanceTraveled: newTotalDistance, }; } else { return { result: false, reason: `distance_too_small_or_noise_${mode}` }; } }, resetFilters() { set({ kalmanFilterLat: new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions), kalmanFilterLon: new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions), consecutiveRejectCount: 0, totalDistanceTraveled: 0, lastAcceptedPredictedLocation: null, currentSpeed: 0, runStartTimeInMillis: Date.now(), routeCoordinates: [], }); }, }));