Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nils_penzel committed Sep 8, 2024
1 parent 448ef02 commit 5121e36
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 61 deletions.
30 changes: 12 additions & 18 deletions src/routes/api/whitelist/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,12 @@ export const POST = async (event) => {
return error(403);
}
const parameters: BookingRequestParameters[] = JSON.parse(await event.request.json());
if (parameters.length == 0) {
const requests = parameters.length;
if (requests == 0) {
return json({ status: 1, message: 'Es wurden keine Daten übermittelt.' }, { status: 400 });
}
const requiredCapacity: Capacity = {
bikes: parameters[0].numBikes,
luggage: parameters[0].luggage,
wheelchairs: parameters[0].numWheelchairs,
passengers: parameters[0].numPassengers
};
const requests = parameters.length;
if(requests==0 || requests>2){

if(requests>2){
return json({ status: 1, message: 'Die API erwartet ein Array mit entweder einem oder zwei Einträgen, für die erste und letzte Meile.' }, { status: 400 });
}
getValidBookings(parameters[0]);
getValidBookings(parameters[1]);
Expand All @@ -56,14 +50,14 @@ const getValidBookings = async (
wheelchairs: p.numWheelchairs,
passengers: p.numPassengers
};
const oneCoordinates: Coordinates = p.userChosen;
const userChosen: Coordinates = p.userChosen;
if (p.busStops.length == 0) {
return json({ status: 1, message: 'Es wurden keine Haltestellen angegeben.' }, { status: 400 });
}

let travelDurations = [];
try {
travelDurations = (await oneToMany(oneCoordinates, p.busStops, Direction.Forward)).map((res) =>
travelDurations = (await oneToMany(userChosen, p.busStops, Direction.Forward)).map((res) =>
secondsToMs(res.duration)
);
} catch (e) {
Expand All @@ -75,7 +69,7 @@ const getValidBookings = async (
{
status: 2,
message:
'Die ausgewählten Koordinaten konnten in den Open Street Map Daten nicht zugeordnet werden.'
'Das Straßenrouting war nicht erfolgreich. Mögliche Gründe: (1) Die angegebenen Koordinaten wurden nicht in den Open Street Map Daten gefunden, (2) Die Reisezeit überschreitet eine Stunde.'
},
{ status: 400 }
);
Expand All @@ -99,13 +93,13 @@ const getValidBookings = async (
}

const dbResult: BookingApiQueryResult = await bookingApiQuery(
oneCoordinates,
userChosen,
requiredCapacity,
maxIntervals.expandedSearchInterval,
p.busStops
);
if (dbResult.companies.length == 0) {
return determineError(oneCoordinates, requiredCapacity);
return determineError(userChosen, requiredCapacity);
}

for (let index = 0; index != travelDurations.length; ++index) {
Expand All @@ -127,12 +121,12 @@ const getValidBookings = async (
};
continue;
}
const targetZones = dbResult.targetZoneIds.get(index);
if (targetZones == undefined) {
const busStopZones = dbResult.busStopZoneIds.get(index);
if (busStopZones == undefined) {
return json({ status: 500 });
}
const currentCompanies = dbResult.companies.filter(
(c) => targetZones.find((zId) => zId == c.zoneId) != undefined
(c) => busStopZones.find((zId) => zId == c.zoneId) != undefined
);
if (currentCompanies.length == 0) {
results[index] = {
Expand Down
48 changes: 33 additions & 15 deletions src/routes/api/whitelist/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { Company } from '$lib/compositionTypes';

export type BookingApiQueryResult = {
companies: Company[];
targetZoneIds: Map<number, number[]>;
busStopZoneIds: Map<number, number[]>;
};

const selectAvailabilities = (eb: ExpressionBuilder<Database, 'vehicle'>, interval: Interval) => {
Expand Down Expand Up @@ -137,7 +137,7 @@ export const bookingApiQuery = async (
start: Coordinates,
requiredCapacities: Capacity,
expandedSearchInterval: Interval,
targets: Coordinates[]
busStops: Coordinates[]
): Promise<BookingApiQueryResult> => {
interface CoordinateTable {
index: number;
Expand All @@ -146,10 +146,10 @@ export const bookingApiQuery = async (
}

const dbResult = await db
.with('targets', (db) => {
const cteValues = targets.map(
(target, i) =>
sql<string>`SELECT cast(${i} as integer) AS index, ${target.lat} AS latitude, ${target.lng} AS longitude`
.with('busStops', (db) => {
const cteValues = busStops.map(
(busStop, i) =>
sql<string>`SELECT cast(${i} as integer) AS index, ${busStop.lat} AS latitude, ${busStop.lng} AS longitude`
);
return db
.selectFrom(
Expand All @@ -166,17 +166,17 @@ export const bookingApiQuery = async (
selectCompanies(eb, expandedSearchInterval, requiredCapacities),
jsonArrayFrom(
eb
.selectFrom('targets')
.selectFrom('busStops')
.where(
sql<boolean>`ST_Covers(zone.area, ST_SetSRID(ST_MakePoint(cast(targets.longitude as float), cast(targets.latitude as float)), ${SRID}))`
sql<boolean>`ST_Covers(zone.area, ST_SetSRID(ST_MakePoint(cast(busStops.longitude as float), cast(busStops.latitude as float)), ${SRID}))`
)
.select(['targets.index as targetIndex', 'zone.id as zoneId'])
).as('target')
.select(['busStops.index as busStopIndex', 'zone.id as zoneId'])
).as('busStopZone')
])
.executeTakeFirst();

if (dbResult == undefined) {
return { companies: [], targetZoneIds: new Map<number, number[]>() };
return { companies: [], busStopZoneIds: new Map<number, number[]>() };
}

const companies = dbResult.companies
Expand Down Expand Up @@ -224,12 +224,30 @@ export const bookingApiQuery = async (
);
})
);
const a = groupBy(
dbResult.busStopZone,
(b) => b.busStopIndex,
(b) => b.zoneId
);
const zoneContainsBusStop: (boolean)[][] = [];
for(let busStopIdx=0;busStopIdx!=busStops.length;++busStopIdx){
const buffer=new Array<boolean>(dbResult.companies.length);
const busStopZones=a.get(busStopIdx);
if(busStopZones!=undefined){
for(let companyIdx=0;companyIdx!=dbResult.companies.length;++companyIdx){
buffer[companyIdx]=busStopZones.find((z)=>z==dbResult.companies[companyIdx].zone)!=undefined;
}
zoneContainsBusStop[busStopIdx]=buffer;
}else{
zoneContainsBusStop[busStopIdx]=[];
}
}
return {
companies,
targetZoneIds: groupBy(
dbResult.target,
(t) => t.targetIndex,
(t) => t.zoneId
busStopZoneIds: groupBy(
dbResult.busStopZone,
(b) => b.busStopIndex,
(b) => b.zoneId
)
};
};
Expand Down
100 changes: 72 additions & 28 deletions src/routes/api/whitelist/tourScheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,37 +124,57 @@ export class TourScheduler {
timestamps: Date[][],
travelDurations: number[],
companies: Company[],
required: Capacity
required: Capacity,
companyMayServeBusStop:boolean[][]
) {
this.companyMayServeBusStop = companyMayServeBusStop;
this.timestamps = timestamps;
this.required = required;
this.companies = companies;
this.travelDurations = travelDurations;
this.insertDurations = new Array<EventInsertion[][]>(companies.length);
this.appendDurations = new Array<EventInsertion[][]>(companies.length);
this.prependDurations = new Array<EventInsertion[][]>(companies.length);
this.connectDurations = new Array<EventInsertion[][]>(companies.length);
this.possibleInsertionsByVehicle = new Map<number, Range[]>();
this.startFixed = startFixed;
this.userChosen = userChosen;
this.busStops = busStops;

this.possibleInsertionsByVehicle = new Map<number, Range[]>();

this.userChosenFromMany = [];
this.userChosenToMany = [];
this.busStops = busStops;
this.busStopFromMany = new Array<Coordinates[]>(busStops.length);
this.busStopToMany = new Array<Coordinates[]>(busStops.length);

this.userChosenToDuration = [];
this.userChosenFromDuration = [];
this.busStopToDurations = new Array<number[]>(busStops.length);
this.busStopFromDurations = new Array<number[]>(busStops.length);

this.insertDurations = new Array<EventInsertion[][]>(companies.length);
this.appendDurations = new Array<EventInsertion[][]>(companies.length);
this.prependDurations = new Array<EventInsertion[][]>(companies.length);
this.connectDurations = new Array<EventInsertion[][]>(companies.length);

this.insertionIndexesUserChosenFromDurationIndexes=[];
this.insertionIndexesUserChosenToDurationIndexes=[];
this.insertionIndexesBusStopFromDurationIndexes=[];
this.insertionIndexesBusStopToDurationIndexes=[];

this.companyIndexesUserChosenFromDurationIndexes=new Array<number>(companies.length);
this.companyIndexesUserChosenToDurationIndexes=new Array<number>(companies.length);
this.companyIndexesBusStopFromDurationIndexes=new Array<number[]>(companies.length);
this.companyIndexesBusStopToDurationIndexes=new Array<number[]>(companies.length);

this.answers = new Array<Answer[]>(busStops.length);
}
companyMayServeBusStop: boolean[][];
timestamps: Date[][];
required: Capacity;
companies: Company[];
startFixed: boolean;
travelDurations: number[];
userChosen: Coordinates;
busStops: Coordinates[];

possibleInsertionsByVehicle: Map<number, Range[]>;

userChosenFromMany: Coordinates[];
userChosenToMany: Coordinates[];
Expand All @@ -166,16 +186,24 @@ export class TourScheduler {
busStopToDurations: number[][];
busStopFromDurations: number[][];

insertionIndexesUserChosenFromDurationIndexes: number[][][];
insertionIndexesUserChosenToDurationIndexes: number[][][];
insertionIndexesBusStopFromDurationIndexes: number[][][][];
insertionIndexesBusStopToDurationIndexes: number[][][][];

companyIndexesUserChosenFromDurationIndexes: number[];
companyIndexesUserChosenToDurationIndexes: number[];
companyIndexesBusStopFromDurationIndexes: number[][];
companyIndexesBusStopToDurationIndexes: number[][];

insertDurations: EventInsertion[][][];
appendDurations: EventInsertion[][][];
prependDurations: EventInsertion[][][];
connectDurations: EventInsertion[][][];

possibleInsertionsByVehicle: Map<number, Range[]>;
answers: Answer[][];

createTourConcatenations = async () => {
//this.newTours.concat(companies.map((c) => new NewTour(c.id, 1, c.coordinates)));
this.simulateCapacities();
this.gatherRoutingCoordinates();
this.routing();
Expand All @@ -186,44 +214,60 @@ export class TourScheduler {
private simulateCapacities() {
this.companies.forEach((c) => {
c.vehicles.forEach((v) => {
const allEvents = v.tours.flatMap((t) => t.events);
const simulation = new CapacitySimulation(
v.bike_capacity,
v.wheelchair_capacity,
v.seats,
v.storage_space
);
const insertions = simulation.getPossibleInsertionRanges(allEvents, this.required);
this.possibleInsertionsByVehicle.set(v.id, insertions);
this.possibleInsertionsByVehicle.set(v.id, simulation.getPossibleInsertionRanges(v.tours.flatMap((t) => t.events), this.required));
});
});
}

private gatherRoutingCoordinates() {
this.companies.forEach((c) => {
for (let busStopIdx = 0; busStopIdx != this.busStops.length; ++busStopIdx) {
this.busStopFromMany[busStopIdx].push(c.coordinates);
this.busStopToMany[busStopIdx].push(c.coordinates);
}
this.userChosenFromMany.push(c.coordinates);
this.userChosenToMany.push(c.coordinates);
c.vehicles.forEach((v) => {
this.companies.forEach((c, companyIdx) => {
this.addCompanyCoordinates(c.coordinates, companyIdx);
c.vehicles.forEach((v, vehicleIdx) => {
const allEvents = v.tours.flatMap((t) => t.events);
const insertions = this.possibleInsertionsByVehicle.get(v.id)!;
forEachInsertion(insertions, (insertionIdx) => {
const prev = allEvents[insertionIdx].coordinates;
const next = allEvents[insertionIdx + 1].coordinates;
for (let busStopIdx = 0; busStopIdx != this.busStops.length; ++busStopIdx) {
this.busStopFromMany[busStopIdx].push(prev);
this.busStopToMany[busStopIdx].push(next);
}
this.userChosenFromMany.push(prev);
this.userChosenToMany.push(next);
this.addCoordinates(allEvents[insertionIdx].coordinates, allEvents[insertionIdx + 1].coordinates, companyIdx, vehicleIdx, insertionIdx);
});
});
});
}

private addCompanyCoordinates(c: Coordinates, companyIdx: number){
for (let busStopIdx = 0; busStopIdx != this.busStops.length; ++busStopIdx) {
if(!this.companyMayServeBusStop[busStopIdx][companyIdx]){
continue;
}
this.busStopFromMany[busStopIdx].push(c);
this.companyIndexesBusStopFromDurationIndexes[companyIdx][busStopIdx] = this.busStopFromMany.length;
this.busStopToMany[busStopIdx].push(c);
this.companyIndexesBusStopToDurationIndexes[companyIdx][busStopIdx] = this.busStopToMany.length;
}
this.userChosenFromMany.push(c);
this.userChosenToMany.push(c);
}

private addCoordinates(prev: Coordinates, next: Coordinates, companyIdx: number, vehicleIdx: number, insertionIdx: number) {
for (let busStopIdx = 0; busStopIdx != this.busStops.length; ++busStopIdx) {
if(!this.companyMayServeBusStop[busStopIdx][companyIdx]){
continue;
}
this.busStopFromMany[busStopIdx].push(prev);
this.insertionIndexesBusStopFromDurationIndexes[companyIdx][vehicleIdx][insertionIdx][busStopIdx] = this.busStopFromMany[busStopIdx].length;
this.busStopToMany[busStopIdx].push(next);
this.insertionIndexesBusStopToDurationIndexes[companyIdx][vehicleIdx][insertionIdx][busStopIdx] = this.busStopToMany[busStopIdx].length;
}
this.userChosenFromMany.push(prev);
this.insertionIndexesUserChosenFromDurationIndexes[companyIdx][vehicleIdx][insertionIdx] = this.busStopFromMany.length;
this.userChosenToMany.push(next);
this.insertionIndexesUserChosenToDurationIndexes[companyIdx][vehicleIdx][insertionIdx] = this.busStopToMany.length;
}

private async routing() {
this.userChosenFromDuration = (
await oneToMany(this.userChosen, this.userChosenFromMany, Direction.Backward)
Expand Down

0 comments on commit 5121e36

Please sign in to comment.