Skip to content

Commit

Permalink
Feat: query api for plan details (#23)
Browse files Browse the repository at this point in the history
* feat: implement plan itinerary depiction

* feat: minor adjustments, conversion to shadcn

* feat: plan parsing, depiction of computed plans

* feat: QueryBatchOverview changed to buttons for switching plans

* chore: remove unused demo file

* fix: minor naming fixes
  • Loading branch information
Kvnstrck authored Jan 14, 2025
1 parent 6bc71b9 commit bd5f60a
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 111 deletions.
12 changes: 12 additions & 0 deletions visual-debugger/src/data-processing/Query-Batch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
"from":"Aachen HBF",
"to": "Aachen West",
"class": "Regional"
},
{
"index":2,
"from":"Aachen West",
"to": "Aachen HBF",
"class": "Regional"
},
{
"index":3,
"from":"Aachen Bushof",
"to": "Aachen Schanz",
"class": "Regional"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Plan type used for parsing plan responses
*/
export interface Plan{
requestParameters:string;
debugOutput: number[];
from:Place;
to: Place;
direct: Itinerary[];
itineraries: Itinerary[];
previousPageCursor: string;
nextPageCursor: string;
}

/**
* Place type used for parsing plan responses
*/
export interface Place{
name:string;
stopId:string;
lat:number;
lon:number;
level: number;
arrival: string;
departure:string;
scheduledArrival: string;
scheduledDeparture: string;
scheduledTrack:string;
track:string;
vertexType:string;
}

/**
* Itinerary type used for parsing plan responses
*/
export interface Itinerary {
duration:number;
startTime:string;
endTime:string;
transfers:number;
legs:Leg[];
}

/**
* Leg type used for parsing plan responses
*/
export interface Leg {
mode:string;
from:Place;
to:Place;
duration:number;
startTime:string;
endTime:string;
scheduledStartTime:string;
scheduledEndTime:string;
realTime:boolean;
legGeometry:EncodedPolyline;
}

/**
* EncodedPolyline type used for parsing plan responses
*/
export interface EncodedPolyline {
points:string;
length:number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* location type used for storing stop information
*/
export interface Location {
type: string;
tokens: number[][];
name: string;
id: string;
lat: number;
lon: number;
level: number;
zip: string;
areas: Area[];
score: number;
}

/**
* area type used for storing information about the area of a stop
*/
export interface Area {
name: string;
adminLevel: number;
matched: boolean;
default: boolean;
}

/**
* Query type used for storing information about a single query
*/
export interface Query {
index: number;
from:string;
fromStopID:string;
to: string;
toStopID: string;
class:string;
}

/**
* Type used for storing all queries in a Batch
*/
export interface Batch {
queries: Query[];
}
56 changes: 56 additions & 0 deletions visual-debugger/src/data-processing/planParsing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {interpolatedQueryStore, computedPlanStore, currentPlanStore} from "../sveltestore.ts";
import type {Query} from "./parsing-types/queryInterpolationTypes.ts";
import type {Plan} from "./parsing-types/planParsingTypes.ts"
import axios from "axios";

/**
* Base URL of the MOTIS API
*/
const motisApiUrlBase = 'http://localhost:8080/api/v1/'

/**
* data of the interpolated queries
*/
let queries: Query[]

/**
* Interaction function that is accessed by the frontend to get the plan for all queries
*/
export async function computePlan(){
//get read file content from storage
interpolatedQueryStore.subscribe(file_data => {
queries = file_data;
})

// if store is empty abort data processing
if(queries == undefined){return}

let plans: Plan[] = [];
let index =0;

// compute the plan for each query
for(const query of queries){
plans[index] = await computePlanForQuery(query)
index++;
}

// put computed plans into storage and set first plan as active
computedPlanStore.set(plans)
currentPlanStore.set(plans[0])
}

/**
* Calls the MOTIS API for a specific query and returns the plan for it
* @param query the query to get the plan for
*/
export async function computePlanForQuery(query:Query){
const response = await axios
.get(
//configuration for api call parameters
`${motisApiUrlBase}plan/?fromPlace=${query.fromStopID}&toPlace=${query.toStopID}`
)
let plan: Plan = response.data
return plan
}


Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from "axios";
import {queryJsonStringStore, interpolatedQueryStore} from "../sveltestore";
import type { Location, Batch } from "./parsing-types/queryInterpolationTypes.ts"

/**
* Base URL of the MOTIS API
Expand All @@ -11,66 +12,20 @@ const motisApiUrlBase = 'http://localhost:8080/api/v1/'
*/
let queryFileContent: string

/**
* location type used for storing stop information
*/
export interface Location {
type: string;
tokens: number[][];
name: string;
id: string;
lat: number;
lon: number;
level: number;
zip: string;
areas: Area[];
score: number;
}

/**
* area type used for storing information about the area of a stop
*/
export interface Area {
name: string;
adminLevel: number;
matched: boolean;
default: boolean;
}

/**
* Query type used for storing information about a single query
*/
export interface Query {
index: number;
from:string;
fromStopID:string;
to: string;
toStopID: string;
class:string;
}

/**
* Type used for storing all queries in a Batch
*/
interface Batch {
queries: Query[];
}

/**
* Reads the query batch and generates the nearest stops for the read query trips
* @param query_batch path to the query batch JSON file
* @return the query batch dataset with stop id's
*/
export async function buildQueryDataset(query_batch:string) {

// parse query batch file into readable queries
let batch: Batch = JSON.parse(query_batch)
let queries = batch.queries

// call MOTIS API to search for the nearest stations to the start and end point of the query
for (const queryTrip of queries) {
queryTrip.fromStopID = await getLocationId(queryTrip.from)
queryTrip.toStopID = await getLocationId(queryTrip.to)
queryTrip.fromStopID = await computeLocationId(queryTrip.from)
queryTrip.toStopID = await computeLocationId(queryTrip.to)
}

// update store with the new queries
Expand All @@ -82,7 +37,7 @@ export async function buildQueryDataset(query_batch:string) {
* @param locationName location the most similar stop id is needed of
* @return the id of the most similar location to the input string
*/
async function getLocationId (locationName:string){
async function computeLocationId (locationName:string){
const response = await axios
.get(
//configuration for api call parameters
Expand All @@ -95,7 +50,7 @@ async function getLocationId (locationName:string){
/**
* Interaction method for printing queries to page
*/
export function getQueryAttributes(){
export function computeQueryAttributes(){

//get read file content from storage
queryJsonStringStore.subscribe(file_data => {
Expand Down
7 changes: 0 additions & 7 deletions visual-debugger/src/demo.spec.ts

This file was deleted.

47 changes: 27 additions & 20 deletions visual-debugger/src/lib/components/ui/FileUpload.svelte
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
<script lang="ts">
import {queryJsonStringStore} from "../../../sveltestore";
let file: File | null = null; // Use TypeScript's File type
const handleFileChange = (event: Event): void => {
const input = event.target as HTMLInputElement;
file = input.files ? input.files[0] : null;
console.log(file?.name); // Logs the file name
import {computeQueryAttributes} from "../../../data-processing/queryBuild.ts";
let file: File | null = null;
// put content of read file as string into storage
file?.text().then((file_content_string) => {
queryJsonStringStore.set(file_content_string);
}
)
// When file was first uploaded, parse and interpolate the queries
$: if(!($queryJsonStringStore=="DEFAULT")){computeQueryAttributes()}
};
</script>

<div>
<input type="file" on:change={handleFileChange} />
{#if file}
<p>Selected file: {file.name}</p>
{/if}
</div>
/**
* Gets the uploaded file and puts its content into the svelte store
* @param event event that the file was uploaded
*/
const putFileIntoStorage = (event: Event): void => {
const input = event.target as HTMLInputElement;
file = input.files ? input.files[0] : null;
// put content of read file as string into storage
file?.text().then((file_content_string) => {
queryJsonStringStore.set(file_content_string);
}
)
};
</script>

<div>
<input type="file" on:change={putFileIntoStorage} />
{#if file}
<p>Selected file: {file.name}</p>
{/if}
</div>
34 changes: 34 additions & 0 deletions visual-debugger/src/lib/components/ui/PlanOverview.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import {currentPlanStore} from "../../../sveltestore.ts";
import type {Itinerary, Plan} from "../../../data-processing/parsing-types/planParsingTypes.ts";
import PlanEntry from "$lib/components/ui/subcomponents/PlanEntry.svelte";
let itineraries: Itinerary[]
// let queries be up-to-date with the store
currentPlanStore.subscribe((data) => {
if (data == undefined) {
itineraries = []
}else{
itineraries = data.itineraries;
}
}
)
</script>

<h2>Plan of Query(Routing results)</h2>
<div class="rounded-border">
{#each itineraries as itinerary}
<PlanEntry startTime="{itinerary.startTime}" endTime="{itinerary.endTime}"
duration="{itinerary.duration.toString()}" transfers="{itinerary.transfers.toString()}"/>
{/each}
</div>


<style>
.rounded-border {
border: 1px solid black;
border-radius: 8px;
padding: 10px;
}
</style>
10 changes: 0 additions & 10 deletions visual-debugger/src/lib/components/ui/QueryBatchEntry.svelte

This file was deleted.

Loading

0 comments on commit bd5f60a

Please sign in to comment.