class GPS { parse(trips) { this.trips = trips this.regions = this.getRegions() this.data = this.trips.map(t => t.path).reduce((a, b) => a.concat(b), []) } getRegions() { var trips = []; var s = 0; for(let i=0; i<=this.trips.length; i++) { while(i < this.trips.length - 2) { const cur = this.trips[i]; const nxt = this.trips[i+1]; if((nxt.startTime - cur.endTime) > 3600 * 24 * 7 || distance(cur.center, nxt.center) > 100000) { break; } i++; } let trip = this.trips.slice(s, i); let dist = trip.reduce((sum, p) => p.distance + sum, 0); if (dist > 30000) { trips.push({ lat: median(trip.map(v => v.center.lat)), lng: median(trip.map(v => v.center.lng)), timestamp: median(trip.map(v => v.startTime)), distance: dist, name: median(trip.map(t => t.name)) }); } s = i; } return trips; } getInfo() { let i = { points: this.trips.reduce((sum, p) => p.path.length + sum, 0), distance: this.trips.reduce((sum, p) => p.distance + sum, 0), topSpeed: this.trips.reduce((max, p) => p.topSpeed > max ? p.topSpeed : max, 0), ascendHeight: this.trips.reduce((sum, p) => p.ascendHeight + sum, 0), descendHeight: this.trips.reduce((sum, p) => p.descendHeight + sum, 0), movementTime: this.trips.reduce((sum, p) => p.movementTime + sum, 0), totalTime: this.trips.reduce((sum, p) => p.totalTime + sum, 0) }; i.avgSpeed = i.distance / i.movementTime * 3.6; return i; } } function distance (a, b) { // Convert degrees to radians var lat1 = a.lat * Math.PI / 180.0; var lon1 = a.lng * Math.PI / 180.0; var lat2 = b.lat * Math.PI / 180.0; var lon2 = b.lng * Math.PI / 180.0; // radius of earth in metres var r = 6378100; // P var rho1 = r * Math.cos(lat1); var z1 = r * Math.sin(lat1); var x1 = rho1 * Math.cos(lon1); var y1 = rho1 * Math.sin(lon1); // Q var rho2 = r * Math.cos(lat2); var z2 = r * Math.sin(lat2); var x2 = rho2 * Math.cos(lon2); var y2 = rho2 * Math.sin(lon2); // Dot product var dot = (x1 * x2 + y1 * y2 + z1 * z2); var cos_theta = dot / (r * r); var theta = Math.acos(cos_theta); // Distance in Metres return r * theta; } function timeFormat(sec, x = "time") { if(isNaN(sec)) return "NaN"; let d = new Date(sec*1000); let t = new Date(null,null,null,null,null,sec).toTimeString().match(/\d{2}:\d{2}:\d{2}/)[0]; switch(x) { case "time": if(sec < 3600*24) return t; else return Math.floor(sec/3600/24) + "d " + t; case "datetime": return d.toLocaleDateString('de-DE', { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", }); case "date": return d.toLocaleDateString('de-DE', { year: "numeric", month: "2-digit", day: "2-digit" }); case "short": return d.toLocaleDateString('de-DE', { year: "numeric", month: "2-digit" }); } } function median(values) { values.sort( function(a,b) {return a - b;} ); var half = Math.floor(values.length/2); return values[half]; } function avg(v) { return v.reduce((a,b) => a+b, 0)/v.length; } function smoothOut(vector, variance) { var t_avg = avg(vector)*variance; var ret = Array(vector.length); for (var i = 0; i < vector.length; i++) { (function () { var prev = i>0 ? ret[i-1] : vector[i]; var next = i