Skip to content

Commit cbd4753

Browse files
2 parents 770f012 + a394736 commit cbd4753

16 files changed

Lines changed: 557 additions & 7 deletions

package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"author": "Nora Söderlund",
99
"devDependencies": {
1010
"@cloudflare/workers-types": "^4.20230518.0",
11+
"@types/geolib": "^2.0.23",
1112
"@types/itty-router-extras": "^0.4.0",
1213
"@types/react": "^18.2.6",
1314
"sass": "^1.62.1",
@@ -17,6 +18,7 @@
1718
"dependencies": {
1819
"@ridetracker/authservice": "^0.9.2",
1920
"@ridetracker/discordwebhooksclient": "^0.9.0",
21+
"geolib": "^3.3.4",
2022
"itty-router": "^3.0.12",
2123
"itty-router-extras": "^0.4.2",
2224
"react": "^18.2.0",

src/controllers/activities/getActivitySessions.ts renamed to src/controllers/activities/sessions/getActivitySessions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Session } from "../../models/Session";
1+
import { Session } from "../../../models/Session";
22

33
export default async function getActivitySessions(bucket: R2Bucket, activityId: string): Promise<Session[] | null> {
44
const activity = await bucket.get(`activities/${activityId}.json`);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Session } from "../../../../models/Session";
2+
import { SessionsInsights } from "../../../../models/SessionsInsights";
3+
4+
export default async function createActivitySessionsInsights(bucket: R2Bucket, activityId: string, insights: SessionsInsights): Promise<void> {
5+
await bucket.put(`activities/insights/${activityId}.json`, JSON.stringify(insights), {
6+
customMetadata: {
7+
"type": "insights",
8+
"activity": activityId
9+
}
10+
});
11+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Session } from "../../../../models/Session";
2+
3+
export default async function getActivitySessionsInsights(bucket: R2Bucket, activityId: string): Promise<Session[] | null> {
4+
const activity = await bucket.get(`activities/insights/${activityId}.json`);
5+
6+
if(!activity)
7+
return null;
8+
9+
return await activity.json<Session[]>();
10+
};
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { Coordinate } from "../../models/Coordinate";
2+
import { Session } from "../../models/Session";
3+
import { getDistance } from "geolib";
4+
5+
const significantChange = 1;
6+
7+
// TODO: change to be a percentage of overall distance
8+
const significantDistance = 100;
9+
10+
export default function getSignificantAltitudeChanges(locations: Session["locations"]) {
11+
const points: {
12+
coordinate: Coordinate;
13+
altitude: number;
14+
distance: number;
15+
}[] = [];
16+
17+
if(!locations.length)
18+
return [];
19+
20+
const start = locations[0];
21+
const end = locations[1];
22+
23+
let accumulatedDistance = 0;
24+
25+
points.push({
26+
coordinate: {
27+
latitude: start.coords.latitude,
28+
longitude: start.coords.longitude
29+
},
30+
31+
altitude: start.coords.altitude,
32+
33+
distance: accumulatedDistance
34+
});
35+
36+
for(let index = 1; index < locations.length - 1; index++) {
37+
const location = locations[index];
38+
const previous = points[points.length - 1];
39+
40+
const distance = getDistance(previous.coordinate, location.coords);
41+
42+
accumulatedDistance += getDistance(locations[index - 1].coords, location.coords);
43+
44+
if(distance < significantDistance) {
45+
//console.log(`Skipping coordinate because ${distance} m is less than 100 m`);
46+
47+
continue;
48+
}
49+
50+
const difference = Math.abs(location.coords.altitude - previous.altitude);
51+
52+
if(difference < significantChange) {
53+
//console.log(`Skipping altitude change because ${difference} is less than significant change of ${significantChange}`);
54+
55+
continue;
56+
}
57+
58+
if(difference < location.coords.altitudeAccuracy) {
59+
//console.log(`Skipping altitude elevation because ${difference} is less than accuracy of ${location.coords.altitudeAccuracy}`);
60+
61+
continue;
62+
}
63+
64+
points.push({
65+
coordinate: {
66+
latitude: location.coords.latitude,
67+
longitude: location.coords.longitude
68+
},
69+
70+
altitude: location.coords.altitude,
71+
72+
distance: accumulatedDistance
73+
});
74+
}
75+
76+
if(locations.length > 1) {
77+
const location = locations[locations.length - 1];
78+
79+
accumulatedDistance += getDistance(locations[locations.length - 2].coords, location.coords);
80+
81+
points.push({
82+
coordinate: {
83+
latitude: end.coords.latitude,
84+
longitude: end.coords.longitude
85+
},
86+
87+
altitude: end.coords.altitude,
88+
89+
distance: accumulatedDistance
90+
});
91+
}
92+
93+
return points;
94+
};
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Coordinate } from "../../models/Coordinate";
2+
import { Session } from "../../models/Session";
3+
import { getDistance } from "geolib";
4+
5+
const significantChange = 4;
6+
7+
// TODO: change to be a percentage of overall distance
8+
const significantDistance = 100;
9+
10+
export default function getSignificantSpeedChanges(locations: Session["locations"]) {
11+
const points: {
12+
coordinate: Coordinate;
13+
speed: number;
14+
distance: number;
15+
}[] = [];
16+
17+
if(!locations.length)
18+
return [];
19+
20+
const start = locations[0];
21+
const end = locations[1];
22+
23+
let accumulatedDistance = 0;
24+
25+
points.push({
26+
coordinate: {
27+
latitude: start.coords.latitude,
28+
longitude: start.coords.longitude
29+
},
30+
31+
speed: start.coords.speed,
32+
distance: 0
33+
});
34+
35+
for(let index = 1; index < locations.length - 1; index++) {
36+
const location = locations[index];
37+
const previous = points[points.length - 1];
38+
39+
const distance = getDistance(previous.coordinate, location.coords);
40+
41+
accumulatedDistance += getDistance(locations[index - 1].coords, location.coords);
42+
43+
if(distance < significantDistance) {
44+
//console.log(`Skipping coordinate because ${distance} m is less than 100 m`);
45+
46+
continue;
47+
}
48+
49+
const difference = Math.abs(location.coords.speed - previous.speed);
50+
51+
if(difference < significantChange) {
52+
//console.log(`Skipping speed change because ${difference} is less than significant change of ${significantChange}`);
53+
54+
continue;
55+
}
56+
57+
points.push({
58+
coordinate: {
59+
latitude: location.coords.latitude,
60+
longitude: location.coords.longitude
61+
},
62+
63+
speed: location.coords.speed,
64+
65+
distance: accumulatedDistance
66+
});
67+
}
68+
69+
if(locations.length > 1) {
70+
const location = locations[locations.length - 1];
71+
72+
accumulatedDistance += getDistance(locations[locations.length - 2].coords, location.coords);
73+
74+
points.push({
75+
coordinate: {
76+
latitude: end.coords.latitude,
77+
longitude: end.coords.longitude
78+
},
79+
80+
speed: end.coords.speed,
81+
82+
distance: accumulatedDistance
83+
});
84+
}
85+
86+
return points;
87+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export default function getSignificantStats(items: number[]) {
2+
const sum = items.reduce((accumulated, speed) => accumulated + speed, 0);
3+
const average = sum / items.length;
4+
5+
return {
6+
minimum: Math.min(...items),
7+
maximum: Math.max(...items),
8+
average
9+
};
10+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { getDistance } from "geolib";
2+
import { Coordinate } from "../../models/Coordinate";
3+
4+
export default function getStrippedPolylineByCoordinates(points: Coordinate[], distance: number): (any & Coordinate)[] {
5+
let filteredCoordinates = [
6+
points[0]
7+
];
8+
9+
for(let index = 1; index < points.length - 1; index++) {
10+
if(getDistance(points[index], filteredCoordinates[filteredCoordinates.length - 1]) >= distance)
11+
filteredCoordinates.push(points[index]);
12+
}
13+
14+
filteredCoordinates.push(points[points.length - 1]);
15+
16+
return filteredCoordinates;
17+
};

src/domains/router.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { handleActivityRouteRequest } from "../routes/activities/[activityId]/ro
33
import { handleActivitySessionsRequest } from "../routes/activities/[activityId]/sessions";
44
import { withAuth } from "@ridetracker/authservice";
55
import { handleActivitySessionsAltitudeRequest } from "../routes/activities/[activityId]/sessions/altitude";
6+
import { handleActivitySessionsSpeedRequest } from "../routes/activities/[activityId]/sessions/speed";
7+
import { handleActivitySessionsInsightsRequest } from "../routes/activities/[activityId]/sessions/insights";
68

79
export default function createRouter() {
810
const router = ThrowableRouter();
911

1012
router.get("/activities/:activityId/route", withAuth("user", "DATABASE"), withParams, handleActivityRouteRequest);
1113
router.get("/api/activities/:activityId/sessions", withAuth("user", "DATABASE"), withParams, handleActivitySessionsRequest);
12-
router.get("/api/activities/:activityId/sessions/altitude", withAuth("user", "DATABASE"), withParams, handleActivitySessionsAltitudeRequest);
14+
router.get("/api/activities/:activityId/sessions/insights", withAuth("user", "DATABASE"), withParams, handleActivitySessionsInsightsRequest);
1315

1416
return router;
1517
};

0 commit comments

Comments
 (0)