Add a way to playback GPX tracks as mock locations

This commit is contained in:
Lucas Verney 2018-08-22 19:34:20 +02:00
parent 3685c4bf92
commit 7a7cd21376
8 changed files with 107 additions and 23 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@ yarn-error.log*
.zanata-cache .zanata-cache
po/*.po po/*.po
po/*.pot po/*.pot
tests/*.gpx
# Editor directories and files # Editor directories and files
.idea .idea

View File

@ -141,6 +141,12 @@ python -m server
to spawn the server-side part, listening on `localhost:8081`. to spawn the server-side part, listening on `localhost:8081`.
### Useful scripts for dev
You can run `scripts/gps_to_gpx.py` on your GPX trace to create a
`src/tools/mock_gpx.json` file ready to be used as a mocking source for the
position data (just edit the `src/constants.js` file accordingly).
## Translating ## Translating

34
scripts/gps_to_js.py Normal file
View File

@ -0,0 +1,34 @@
import json
import os
import sys
import gpxpy
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit('Usage: %s GPX_FILE' % sys.argv[0])
with open (sys.argv[1], 'r') as fh:
gpx = gpxpy.parse(fh)
json_out = []
for track in gpx.tracks:
for segment in track.segments:
for point in segment.points:
# TODO: Other fields
json_out.append({
'time': point.time.isoformat(),
'coords': {
'accuracy': point.horizontal_dilution,
'altitudeAccuracy': point.vertical_dilution,
'heading': None,
'latitude': point.latitude,
'longitude': point.longitude
}
})
break
break
script_dir = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(script_dir, '../src/tools/mock_gpx.json'), 'w') as fh:
json.dump(json_out, fh)

View File

@ -113,7 +113,21 @@ export const REPORT_TYPES_ORDER = ['gcum', 'interrupt', 'obstacle', 'pothole', '
export const MIN_DISTANCE_REPORT_DETAILS = 40; // in meters export const MIN_DISTANCE_REPORT_DETAILS = 40; // in meters
export const MOCK_LOCATION = false; export const MOCK_LOCATION = false;
export const MOCK_LOCATION_USE_GPX = true;
export const MOCK_LOCATION_GPX_PLAYBACK_SPEED = 2.0;
export const MOCK_LOCATION_UPDATE_INTERVAL = 5 * 1000; // in milliseconds export const MOCK_LOCATION_UPDATE_INTERVAL = 5 * 1000; // in milliseconds
// Small area in Montrouge
export const MOCK_LOCATION_LAT_MIN = 48.81788;
export const MOCK_LOCATION_LNG_MIN = 2.31723;
export const MOCK_LOCATION_LAT_MAX = 48.81952;
export const MOCK_LOCATION_LNG_MAX = 2.32077;
// Paris
/*
export const MOCK_LOCATION_LAT_MIN = 48.854031;
export const MOCK_LOCATION_LNG_MIN = 2.281279;
export const MOCK_LOCATION_LAT_MAX = 48.886123;
export const MOCK_LOCATION_LNG_MAX = 2.392742;
*/
export const UPDATE_REPORTS_DISTANCE_THRESHOLD = 500; // in meters export const UPDATE_REPORTS_DISTANCE_THRESHOLD = 500; // in meters

View File

@ -1,4 +1,18 @@
import { EARTH_RADIUS } from '@/constants'; import moment from 'moment';
import {
EARTH_RADIUS,
MOCK_LOCATION_GPX_PLAYBACK_SPEED,
MOCK_LOCATION_UPDATE_INTERVAL,
MOCK_LOCATION_USE_GPX,
MOCK_LOCATION_LAT_MIN, MOCK_LOCATION_LAT_MAX,
MOCK_LOCATION_LNG_MIN, MOCK_LOCATION_LNG_MAX,
} from '@/constants';
let mockGPX = null;
if (process.env.NODE_ENV !== 'production') {
mockGPX = require('@/tools/mock_gpx.json'); // eslint-disable-line global-require
}
export function distance(latLng1, latLng2) { export function distance(latLng1, latLng2) {
const lat1 = (latLng1[0] * Math.PI) / 180; const lat1 = (latLng1[0] * Math.PI) / 180;
@ -16,21 +30,7 @@ export function distance(latLng1, latLng2) {
return EARTH_RADIUS * c; return EARTH_RADIUS * c;
} }
export function mockLocation() { export function mockLocationRandom() {
// Over Paris
/*
const LAT_MIN = 48.854031;
const LNG_MIN = 2.281279;
const LAT_MAX = 48.886123;
const LNG_MAX = 2.392742;
*/
// Over small area
const LAT_MIN = 48.81788;
const LNG_MIN = 2.31723;
const LAT_MAX = 48.81952;
const LNG_MAX = 2.32077;
let heading = null; let heading = null;
if (Math.random() > 0.25) { if (Math.random() > 0.25) {
heading = Math.random() * 360; heading = Math.random() * 360;
@ -38,8 +38,14 @@ export function mockLocation() {
const newLocation = { const newLocation = {
coords: { coords: {
accuracy: 10, // In meters accuracy: 10, // In meters
latitude: (Math.random() * (LAT_MAX - LAT_MIN)) + LAT_MIN, latitude: (
longitude: (Math.random() * (LNG_MAX - LNG_MIN)) + LNG_MIN, (Math.random() * (MOCK_LOCATION_LAT_MAX - MOCK_LOCATION_LAT_MIN))
+ MOCK_LOCATION_LAT_MIN
),
longitude: (
(Math.random() * (MOCK_LOCATION_LNG_MAX - MOCK_LOCATION_LNG_MIN))
+ MOCK_LOCATION_LNG_MIN
),
heading, heading,
}, },
timestamp: new Date().getTime(), timestamp: new Date().getTime(),
@ -48,6 +54,32 @@ export function mockLocation() {
return newLocation; return newLocation;
} }
export function mockLocationWithGPX(index, setPosition) {
setPosition(mockGPX[index]);
if (index < mockGPX.length) {
const delay = (
moment(mockGPX[index + 1].time).valueOf()
- moment(mockGPX[index].time).valueOf()
);
setTimeout(
() => mockLocationWithGPX(index + 1, setPosition),
delay / MOCK_LOCATION_GPX_PLAYBACK_SPEED,
);
}
}
export function mockLocation(setPosition) {
if (MOCK_LOCATION_USE_GPX) {
mockLocationWithGPX(0, setPosition);
return null;
}
setPosition(mockLocationRandom());
return setInterval(
() => setPosition(mockLocationRandom()),
MOCK_LOCATION_UPDATE_INTERVAL,
);
}
export function storageAvailable(type) { export function storageAvailable(type) {
let storage; let storage;
try { try {

1
src/tools/mock_gpx.json Normal file
View File

@ -0,0 +1 @@
[]

View File

@ -166,11 +166,7 @@ export default {
// Set up a watcher // Set up a watcher
let watchID = null; let watchID = null;
if (constants.MOCK_LOCATION) { if (constants.MOCK_LOCATION) {
setPosition(mockLocation()); watchID = mockLocation(setPosition);
watchID = setInterval(
() => setPosition(mockLocation()),
constants.MOCK_LOCATION_UPDATE_INTERVAL,
);
} else { } else {
if (!('geolocation' in navigator)) { if (!('geolocation' in navigator)) {
const $t = this.$t.bind(this); const $t = this.$t.bind(this);

0
tests/.gitkeep Normal file
View File