Skip to content

Commit

Permalink
Merge pull request #168 from kieler/154-compute-vehicle-data-all-at-once
Browse files Browse the repository at this point in the history
154 compute vehicle data all at once
  • Loading branch information
Kebslock authored Sep 15, 2023
2 parents 4d59997 + 25f888f commit b64f95d
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 291 deletions.
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

0 comments on commit b64f95d

Please sign in to comment.