@codewithvincent/react-native-gps-filter
Version:
Kalman-based adaptive GPS filter for React Native.
91 lines (90 loc) • 4.46 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocationFilter = void 0;
//@ts-ignore
const kalmanjs_1 = __importDefault(require("kalmanjs"));
const locationFilters_1 = require("../utils/locationFilters");
const helpers_1 = require("../utils/helpers");
class LocationFilter {
constructor() {
this.kalmanFilterLat = new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions);
this.kalmanFilterLon = new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions);
this.consecutiveRejectCount = 0;
this.totalDistanceTraveled = 0;
this.lastAcceptedPredictedLocation = null;
this.currentSpeed = 0;
}
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 speed = location.coords.speed || 0;
const { minDelta, maxDelta, maxAllowedDelta, mode } = (0, locationFilters_1.getAdaptiveThresholds)(speed);
const isMoving = speed > locationFilters_1.GPS_SPEED_THRESHOLD;
if (!this.lastAcceptedPredictedLocation) {
this.kalmanFilterLat.filter(location.coords.latitude);
this.kalmanFilterLon.filter(location.coords.longitude);
this.lastAcceptedPredictedLocation = location;
return {
result: true,
acceptedLocation: location,
predictedLocation: location,
distanceTraveled: 0,
};
}
const predictedLat = this.kalmanFilterLat.filter(location.coords.latitude);
const predictedLon = this.kalmanFilterLon.filter(location.coords.longitude);
const predictedDelta = (0, helpers_1.getDistanceFromLatLonInMeters)(predictedLat, predictedLon, location.coords.latitude, location.coords.longitude);
if (predictedDelta > maxAllowedDelta) {
this.consecutiveRejectCount += 1;
if (this.consecutiveRejectCount > locationFilters_1.KALMAN_REJECT_THRESHOLD) {
this.kalmanFilterLat = new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions);
this.kalmanFilterLon = new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions);
this.consecutiveRejectCount = 0;
}
return { result: false, reason: `kalman_reject_${mode}` };
}
else {
this.consecutiveRejectCount = 0;
}
const predictedLocation = Object.assign(Object.assign({}, location), { coords: Object.assign(Object.assign({}, location.coords), { latitude: predictedLat, longitude: predictedLon }) });
const lastAccepted = this.lastAcceptedPredictedLocation;
const distanceSinceLast = (0, helpers_1.getDistanceFromLatLonInMeters)(predictedLat, predictedLon, lastAccepted.coords.latitude, lastAccepted.coords.longitude);
if (isMoving &&
distanceSinceLast > minDelta &&
distanceSinceLast < maxDelta) {
this.totalDistanceTraveled += distanceSinceLast;
this.lastAcceptedPredictedLocation = predictedLocation;
this.currentSpeed = speed;
if (onPredictLocation) {
onPredictLocation(predictedLocation);
}
return {
result: true,
acceptedLocation: location,
predictedLocation,
distanceTraveled: this.totalDistanceTraveled,
};
}
else {
return { result: false, reason: `distance_too_small_or_noise_${mode}` };
}
}
resetFilters() {
this.kalmanFilterLat = new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions);
this.kalmanFilterLon = new kalmanjs_1.default(locationFilters_1.kalmanFilterOptions);
this.consecutiveRejectCount = 0;
this.totalDistanceTraveled = 0;
this.lastAcceptedPredictedLocation = null;
this.currentSpeed = 0;
}
}
exports.LocationFilter = LocationFilter;