Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

154 compute vehicle data all at once #168

Merged
merged 5 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 9 additions & 18 deletions Server/src/routes/track.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,32 +223,23 @@ export class TrackRoute {
const vehicles: Vehicle[] = await database.vehicles.getAll(track.uid)
const ret: z.infer<typeof APIVehicle>[] = await Promise.all(
vehicles.map(async (vehicle: Vehicle) => {
// get the current position of the vehicle
const heading: number = await VehicleService.getVehicleHeading(vehicle)
const speed: number = await VehicleService.getVehicleSpeed(vehicle)
const geo_pos = await VehicleService.getVehiclePosition(vehicle, heading, speed)
const trackKm = geo_pos ? GeoJSONUtils.getTrackKm(geo_pos) : undefined
// get the current data of the vehicle
const vehicleData = await VehicleService.getVehicleData(vehicle)
// If we know that, convert it in the API format.
const pos: z.infer<typeof Position> | undefined = geo_pos
? {
lat: GeoJSONUtils.getLatitude(geo_pos),
lng: GeoJSONUtils.getLongitude(geo_pos)
}
: undefined
// Also acquire the percentage position. It might happen that a percentage position is known, while the position is not.
// This might not make much sense.
const percentagePosition: number | undefined =
trackKm != null ? (await TrackService.getTrackKmAsPercentage(trackKm, track)) ?? undefined : undefined
const pos: z.infer<typeof Position> | undefined = {
lat: GeoJSONUtils.getLatitude(vehicleData.position),
lng: GeoJSONUtils.getLongitude(vehicleData.position)
}
return {
id: vehicle.uid,
track: vehicle.trackId,
name: vehicle.name ? vehicle.name : "Empty Name",
type: vehicle.typeId,
trackerIds: (await database.trackers.getByVehicleId(vehicle.uid)).map(y => y.uid),
pos,
percentagePosition,
heading,
speed
percentagePosition: vehicleData.percentagePosition,
heading: vehicleData.heading,
speed: vehicleData.speed
}
})
)
Expand Down
4 changes: 2 additions & 2 deletions Server/src/routes/tracker.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { authenticateJWT, jsonParser } from "."
import TrackerService from "../services/tracker.service"
import { LteRecordField0, LteRecordField6, UplinkLteTracker, UplinkTracker } from "../models/api.tracker"
import please_dont_crash from "../utils/please_dont_crash"
import { Log, Prisma, Tracker, Vehicle } from "@prisma/client"
import { Prisma, Tracker, Vehicle } from "@prisma/client"
import database from "../services/database.service"
import { Tracker as APITracker } from "../models/api"
import { z } from "zod"
Expand Down Expand Up @@ -71,7 +71,7 @@ export class TrackerRoute {
return
}

const lastLog = await database.logs.getLatestLog(undefined, tracker.uid,)
const lastLog = await database.logs.getLatestLog(undefined, tracker.uid)

const apiTracker: z.infer<typeof APITracker> = {
id: tracker.uid,
Expand Down
80 changes: 27 additions & 53 deletions Server/src/routes/vehicle.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import { logger } from "../utils/logger"
import { authenticateJWT, jsonParser } from "."
import { Log, Track, Tracker, Vehicle, VehicleType } from "@prisma/client"
import VehicleService from "../services/vehicle.service"
import { Feature, Point } from "geojson"
import please_dont_crash from "../utils/please_dont_crash"
import database from "../services/database.service"
import GeoJSONUtils from "../utils/geojsonUtils"
import TrackService from "../services/track.service"
import { z } from "zod"

/**
Expand Down Expand Up @@ -116,37 +114,20 @@ export class VehicleRoute {
}
}

const heading: number = await VehicleService.getVehicleHeading(userVehicle)
const speed: number = await VehicleService.getVehicleSpeed(userVehicle)
const pos: Feature<Point> | null = await VehicleService.getVehiclePosition(userVehicle, heading, speed)
if (!pos) {
logger.error(`Could not find position of vehicle with id ${userVehicle.uid}`)
res.sendStatus(404)
return
}
const userVehicleData = await VehicleService.getVehicleData(userVehicle)

const position: z.infer<typeof Position> = {
lat: GeoJSONUtils.getLatitude(pos),
lng: GeoJSONUtils.getLongitude(pos)
lat: GeoJSONUtils.getLatitude(userVehicleData.position),
lng: GeoJSONUtils.getLongitude(userVehicleData.position)
}
// TODO: this is a quite unnecessary database query, remove it?
const track: Track | null = await database.tracks.getById(userVehicle.trackId)
if (!track) {
logger.error(`Could not find track with id ${userVehicle.trackId}
obtained from the user vehicle with id ${userVehicle.uid}`)
res.sendStatus(500)
return
}
const userVehicleTrackKm: number | null = GeoJSONUtils.getTrackKm(pos)
if (userVehicleTrackKm == null) {
logger.error(`Could not compute track kilometer for vehicle with id ${userVehicle.uid}
at track with id ${userVehicle.trackId}`)
res.sendStatus(500)
return
}
const userVehicleSimplifiedHeading: number = await VehicleService.getVehicleTrackHeading(
userVehicle,
userVehicleTrackKm,
heading
)

const allVehiclesOnTrack: Vehicle[] | null = await database.vehicles.getAll(userVehicle.trackId)
if (allVehiclesOnTrack == null) {
Expand All @@ -157,64 +138,57 @@ export class VehicleRoute {
const appVehiclesNearUser: z.infer<typeof VehicleApp>[] = (
await Promise.all(
allVehiclesOnTrack.map(async v => {
const heading = await VehicleService.getVehicleHeading(v)
const speed = await VehicleService.getVehicleSpeed(v)
const pos = await VehicleService.getVehiclePosition(v, heading, speed)
const vehicleData = await VehicleService.getVehicleData(v)
const trackers = await database.trackers.getByVehicleId(v.uid)
const nearbyVehicleTrackKm: number | null = pos ? GeoJSONUtils.getTrackKm(pos) : null
if (nearbyVehicleTrackKm == null) {
logger.error(`Could not compute track kilometer for vehicle with id ${v.uid}
at track with id ${v.trackId}`)
// TODO: is this check really necessary? (could be be in the other return statement as well)
if (vehicleData.direction == null) {
logger.error(`Could not compute travelling direction for vehicle with id ${v.uid}
at track wit id ${v.trackId}`)
return {
id: v.uid,
name: v.name,
track: v.trackId,
type: v.typeId,
trackerIds: trackers.map(t => t.uid),
pos: pos ? { lat: GeoJSONUtils.getLatitude(pos), lng: GeoJSONUtils.getLongitude(pos) } : undefined,
percentagePosition: -1,
heading: heading,
pos: {
lat: GeoJSONUtils.getLatitude(vehicleData.position),
lng: GeoJSONUtils.getLongitude(vehicleData.position)
},
percentagePosition: vehicleData.direction ?? -1,
heading: vehicleData.heading,
headingTowardsUser: undefined
}
}
const nearbySimplifiedVehicleHeading: number = await VehicleService.getVehicleTrackHeading(
v,
nearbyVehicleTrackKm,
heading
)
return {
id: v.uid,
name: v.name,
track: v.trackId,
type: v.typeId,
trackerIds: trackers.map(t => t.uid),
pos: pos ? { lat: GeoJSONUtils.getLatitude(pos), lng: GeoJSONUtils.getLongitude(pos) } : undefined,
percentagePosition: (await TrackService.getTrackKmAsPercentage(nearbyVehicleTrackKm, track)) ?? -1,
heading: heading,
pos: {
lat: GeoJSONUtils.getLatitude(vehicleData.position),
lng: GeoJSONUtils.getLongitude(vehicleData.position)
},
percentagePosition: vehicleData.percentagePosition ?? -1,
heading: vehicleData.heading,
headingTowardsUser:
userVehicleSimplifiedHeading !== 0 && nearbySimplifiedVehicleHeading !== 0
? nearbySimplifiedVehicleHeading != userVehicleSimplifiedHeading
: undefined
userVehicleData.direction != null ? userVehicleData.direction != vehicleData.direction : undefined
}
})
)
).filter(v => v.id !== userVehicle.uid && v.track === track.uid && v.percentagePosition !== -1)

const percentagePositionOnTrack: number | null = await TrackService.getTrackKmAsPercentage(
userVehicleTrackKm,
track
)
if (percentagePositionOnTrack == null) {
if (userVehicleData.percentagePosition == null) {
logger.error(`Could not determine percentage position on track for user with vehicle ${userVehicle.uid}`)
res.sendStatus(500)
return
}
const ret: z.infer<typeof UpdateResponseApp> = {
pos: position,
heading: heading,
heading: userVehicleData.heading,
vehiclesNearUser: appVehiclesNearUser,
speed: speed,
percentagePositionOnTrack: percentagePositionOnTrack,
speed: userVehicleData.speed,
percentagePositionOnTrack: userVehicleData.percentagePosition,
passingPosition: undefined // TODO: Find out passingPosition
}
res.json(ret)
Expand Down
31 changes: 10 additions & 21 deletions Server/src/services/track.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ export default class TrackService {
/**
* Calculate projected track kilometer for a given position
* @param position position to calculate track kilometer for (does not need to be on the track)
* @param track optional`Track` to use for calculation, if none is given, the closest will be used
* @param track `Track` to use for calculation
* @returns track kilometer of `position` projected on `track`, `null` if an error occurs
*/
public static async getPointTrackKm(position: GeoJSON.Feature<GeoJSON.Point>, track?: Track): Promise<number | null> {
public static getPointTrackKm(position: GeoJSON.Feature<GeoJSON.Point>, track: Track): number | null {
// get the track kilometer value from projected point
const projectedPoint = await this.getProjectedPointOnTrack(position, track)
const projectedPoint = this.getProjectedPointOnTrack(position, track)
if (projectedPoint == null) {
logger.error(`Could not project position ${JSON.stringify(position)}.`)
return null
Expand All @@ -105,7 +105,7 @@ export default class TrackService {
* @param track `Track` to use for calculation as reference
* @returns percentage value of `trackKm` regarding `track`, `null` if an error occurs
*/
public static async getTrackKmAsPercentage(trackKm: number, track: Track): Promise<number | null> {
public static getTrackKmAsPercentage(trackKm: number, track: Track): number | null {
// get total track length in kilometers
const trackLength = this.getTrackLength(track)
if (trackLength == null) {
Expand All @@ -126,25 +126,13 @@ export default class TrackService {
/**
* Project a position onto a track
* @param position position to project onto the track
* @param track optional `Track` to project `position` onto, closest will be used, if none is given
* @param track `Track` to project `position` onto
* @returns track point, which is the `position` projected onto `track`, enriched with a track kilometer value, `null` if an error occurs
*/
public static async getProjectedPointOnTrack(
public static getProjectedPointOnTrack(
position: GeoJSON.Feature<GeoJSON.Point>,
track?: Track
): Promise<GeoJSON.Feature<GeoJSON.Point> | null> {
// check if track is given and else find the closest one
if (track == null) {
const tempTrack = await this.getClosestTrack(position)

// if an error occured while trying to find the closest track, there is nothing we can do
if (tempTrack == null) {
logger.error(`Could not find closest track for position ${JSON.stringify(position)}.`)
return null
}
track = tempTrack
}

track: Track
): GeoJSON.Feature<GeoJSON.Point> | null {
// converting feature collection of points from track to linestring to project position onto it
const trackData = GeoJSONUtils.parseGeoJSONFeatureCollectionPoints(track.data)
if (trackData == null) {
Expand Down Expand Up @@ -177,8 +165,9 @@ export default class TrackService {
* @param trackKm distance of `track` to get heading for
* @returns current heading (0-359) of `track` at distance `trackKm`, `null` if an error occurs
*/
public static async getTrackHeading(track: Track, trackKm: number): Promise<number | null> {
public static getTrackHeading(track: Track, trackKm: number): number | null {
// TODO quite inefficient? did not found anything from turf, that could do this in a simple way
// TODO: maybe enrich track with bearing as well

// validate track kilometer value
const trackLength = this.getTrackLength(track)
Expand Down
Loading