geography entity with tests
This commit is contained in:
parent
ed99b442eb
commit
6dd4837c89
|
@ -6,7 +6,7 @@ import { IDefaultParams } from '../../domain/types/default-params.type';
|
||||||
export class DefaultParamsProvider {
|
export class DefaultParamsProvider {
|
||||||
constructor(private readonly configService: ConfigService) {}
|
constructor(private readonly configService: ConfigService) {}
|
||||||
|
|
||||||
getParams(): IDefaultParams {
|
getParams = (): IDefaultParams => {
|
||||||
return {
|
return {
|
||||||
DEFAULT_IDENTIFIER: parseInt(
|
DEFAULT_IDENTIFIER: parseInt(
|
||||||
this.configService.get('DEFAULT_IDENTIFIER'),
|
this.configService.get('DEFAULT_IDENTIFIER'),
|
||||||
|
@ -33,5 +33,5 @@ export class DefaultParamsProvider {
|
||||||
georouterUrl: this.configService.get('GEOROUTER_URL'),
|
georouterUrl: this.configService.get('GEOROUTER_URL'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,12 @@ export class MatcherGeodesic implements IGeodesic {
|
||||||
this._geod = Geodesic.WGS84;
|
this._geod = Geodesic.WGS84;
|
||||||
}
|
}
|
||||||
|
|
||||||
inverse(
|
inverse = (
|
||||||
lon1: number,
|
lon1: number,
|
||||||
lat1: number,
|
lat1: number,
|
||||||
lon2: number,
|
lon2: number,
|
||||||
lat2: number,
|
lat2: number,
|
||||||
): { azimuth: number; distance: number } {
|
): { azimuth: number; distance: number } => {
|
||||||
const { azi2: azimuth, s12: distance } = this._geod.Inverse(
|
const { azi2: azimuth, s12: distance } = this._geod.Inverse(
|
||||||
lat1,
|
lat1,
|
||||||
lon1,
|
lon1,
|
||||||
|
@ -23,5 +23,5 @@ export class MatcherGeodesic implements IGeodesic {
|
||||||
lon2,
|
lon2,
|
||||||
);
|
);
|
||||||
return { azimuth, distance };
|
return { azimuth, distance };
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,12 @@ export class GeorouterCreator implements ICreateGeorouter {
|
||||||
private readonly geodesic: MatcherGeodesic,
|
private readonly geodesic: MatcherGeodesic,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
create(type: string, url: string): IGeorouter {
|
create = (type: string, url: string): IGeorouter => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'graphhopper':
|
case 'graphhopper':
|
||||||
return new GraphhopperGeorouter(url, this.httpService, this.geodesic);
|
return new GraphhopperGeorouter(url, this.httpService, this.geodesic);
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown geocoder');
|
throw new Error('Unknown geocoder');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,50 +27,50 @@ export class GraphhopperGeorouter implements IGeorouter {
|
||||||
this._geodesic = geodesic;
|
this._geodesic = geodesic;
|
||||||
}
|
}
|
||||||
|
|
||||||
async route(
|
route = async (
|
||||||
paths: Array<Path>,
|
paths: Array<Path>,
|
||||||
settings: GeorouterSettings,
|
settings: GeorouterSettings,
|
||||||
): Promise<Array<NamedRoute>> {
|
): Promise<Array<NamedRoute>> => {
|
||||||
this._setDefaultUrlArgs();
|
this._setDefaultUrlArgs();
|
||||||
this._setWithTime(settings.withTime);
|
this._setWithTime(settings.withTime);
|
||||||
this._setWithPoints(settings.withPoints);
|
this._setWithPoints(settings.withPoints);
|
||||||
this._setWithDistance(settings.withDistance);
|
this._setWithDistance(settings.withDistance);
|
||||||
this._paths = paths;
|
this._paths = paths;
|
||||||
return await this._getRoutes();
|
return await this._getRoutes();
|
||||||
}
|
};
|
||||||
|
|
||||||
_setDefaultUrlArgs(): void {
|
_setDefaultUrlArgs = (): void => {
|
||||||
this._urlArgs = [
|
this._urlArgs = [
|
||||||
'vehicle=car',
|
'vehicle=car',
|
||||||
'weighting=fastest',
|
'weighting=fastest',
|
||||||
'points_encoded=false',
|
'points_encoded=false',
|
||||||
];
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
_setWithTime(withTime: boolean): void {
|
_setWithTime = (withTime: boolean): void => {
|
||||||
this._withTime = withTime;
|
this._withTime = withTime;
|
||||||
if (withTime) {
|
if (withTime) {
|
||||||
this._urlArgs.push('details=time');
|
this._urlArgs.push('details=time');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_setWithPoints(withPoints: boolean): void {
|
_setWithPoints = (withPoints: boolean): void => {
|
||||||
this._withPoints = withPoints;
|
this._withPoints = withPoints;
|
||||||
if (!withPoints) {
|
if (!withPoints) {
|
||||||
this._urlArgs.push('calc_points=false');
|
this._urlArgs.push('calc_points=false');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_setWithDistance(withDistance: boolean): void {
|
_setWithDistance = (withDistance: boolean): void => {
|
||||||
this._withDistance = withDistance;
|
this._withDistance = withDistance;
|
||||||
if (withDistance) {
|
if (withDistance) {
|
||||||
this._urlArgs.push('instructions=true');
|
this._urlArgs.push('instructions=true');
|
||||||
} else {
|
} else {
|
||||||
this._urlArgs.push('instructions=false');
|
this._urlArgs.push('instructions=false');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
async _getRoutes(): Promise<Array<NamedRoute>> {
|
_getRoutes = async (): Promise<Array<NamedRoute>> => {
|
||||||
const routes = Promise.all(
|
const routes = Promise.all(
|
||||||
this._paths.map(async (path) => {
|
this._paths.map(async (path) => {
|
||||||
const url: string = [
|
const url: string = [
|
||||||
|
@ -95,20 +95,25 @@ export class GraphhopperGeorouter implements IGeorouter {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return routes;
|
return routes;
|
||||||
}
|
};
|
||||||
|
|
||||||
_getUrl(): string {
|
_getUrl = (): string => {
|
||||||
return [this._url, this._urlArgs.join('&')].join('');
|
return [this._url, this._urlArgs.join('&')].join('');
|
||||||
}
|
};
|
||||||
|
|
||||||
_createRoute(response: AxiosResponse<GraphhopperResponse>): Route {
|
_createRoute = (response: AxiosResponse<GraphhopperResponse>): Route => {
|
||||||
const route = new Route(this._geodesic);
|
const route = new Route(this._geodesic);
|
||||||
if (response.data.paths && response.data.paths[0]) {
|
if (response.data.paths && response.data.paths[0]) {
|
||||||
const shortestPath = response.data.paths[0];
|
const shortestPath = response.data.paths[0];
|
||||||
route.distance = shortestPath.distance ?? 0;
|
route.distance = shortestPath.distance ?? 0;
|
||||||
route.duration = shortestPath.time ? shortestPath.time / 1000 : 0;
|
route.duration = shortestPath.time ? shortestPath.time / 1000 : 0;
|
||||||
if (shortestPath.points && shortestPath.points.coordinates) {
|
if (shortestPath.points && shortestPath.points.coordinates) {
|
||||||
route.setPoints(shortestPath.points.coordinates);
|
route.setPoints(
|
||||||
|
shortestPath.points.coordinates.map((coordinate) => ({
|
||||||
|
lon: coordinate[0],
|
||||||
|
lat: coordinate[1],
|
||||||
|
})),
|
||||||
|
);
|
||||||
if (
|
if (
|
||||||
shortestPath.details &&
|
shortestPath.details &&
|
||||||
shortestPath.details.time &&
|
shortestPath.details.time &&
|
||||||
|
@ -130,14 +135,14 @@ export class GraphhopperGeorouter implements IGeorouter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return route;
|
return route;
|
||||||
}
|
};
|
||||||
|
|
||||||
_generateSpacetimePoints(
|
_generateSpacetimePoints = (
|
||||||
points: Array<Array<number>>,
|
points: Array<Array<number>>,
|
||||||
snappedWaypoints: Array<Array<number>>,
|
snappedWaypoints: Array<Array<number>>,
|
||||||
durations: Array<Array<number>>,
|
durations: Array<Array<number>>,
|
||||||
instructions: Array<GraphhopperInstruction>,
|
instructions: Array<GraphhopperInstruction>,
|
||||||
): Array<SpacetimePoint> {
|
): Array<SpacetimePoint> => {
|
||||||
const indices = this._getIndices(points, snappedWaypoints);
|
const indices = this._getIndices(points, snappedWaypoints);
|
||||||
const times = this._getTimes(durations, indices);
|
const times = this._getTimes(durations, indices);
|
||||||
const distances = this._getDistances(instructions, indices);
|
const distances = this._getDistances(instructions, indices);
|
||||||
|
@ -149,12 +154,12 @@ export class GraphhopperGeorouter implements IGeorouter {
|
||||||
distances.find((distance) => distance.index == index)?.distance,
|
distances.find((distance) => distance.index == index)?.distance,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
_getIndices(
|
_getIndices = (
|
||||||
points: Array<Array<number>>,
|
points: Array<Array<number>>,
|
||||||
snappedWaypoints: Array<Array<number>>,
|
snappedWaypoints: Array<Array<number>>,
|
||||||
): Array<number> {
|
): Array<number> => {
|
||||||
const indices = snappedWaypoints.map((waypoint) =>
|
const indices = snappedWaypoints.map((waypoint) =>
|
||||||
points.findIndex(
|
points.findIndex(
|
||||||
(point) => point[0] == waypoint[0] && point[1] == waypoint[1],
|
(point) => point[0] == waypoint[0] && point[1] == waypoint[1],
|
||||||
|
@ -199,12 +204,12 @@ export class GraphhopperGeorouter implements IGeorouter {
|
||||||
indices[missedWaypoint.originIndex] = missedWaypoint.nearest;
|
indices[missedWaypoint.originIndex] = missedWaypoint.nearest;
|
||||||
}
|
}
|
||||||
return indices;
|
return indices;
|
||||||
}
|
};
|
||||||
|
|
||||||
_getTimes(
|
_getTimes = (
|
||||||
durations: Array<Array<number>>,
|
durations: Array<Array<number>>,
|
||||||
indices: Array<number>,
|
indices: Array<number>,
|
||||||
): Array<{ index: number; duration: number }> {
|
): Array<{ index: number; duration: number }> => {
|
||||||
const times: Array<{ index: number; duration: number }> = [];
|
const times: Array<{ index: number; duration: number }> = [];
|
||||||
let duration = 0;
|
let duration = 0;
|
||||||
for (const [origin, destination, stepDuration] of durations) {
|
for (const [origin, destination, stepDuration] of durations) {
|
||||||
|
@ -249,12 +254,12 @@ export class GraphhopperGeorouter implements IGeorouter {
|
||||||
duration += stepDuration;
|
duration += stepDuration;
|
||||||
}
|
}
|
||||||
return times;
|
return times;
|
||||||
}
|
};
|
||||||
|
|
||||||
_getDistances(
|
_getDistances = (
|
||||||
instructions: Array<GraphhopperInstruction>,
|
instructions: Array<GraphhopperInstruction>,
|
||||||
indices: Array<number>,
|
indices: Array<number>,
|
||||||
): Array<{ index: number; distance: number }> {
|
): Array<{ index: number; distance: number }> => {
|
||||||
let distance = 0;
|
let distance = 0;
|
||||||
const distances: Array<{ index: number; distance: number }> = [
|
const distances: Array<{ index: number; distance: number }> = [
|
||||||
{
|
{
|
||||||
|
@ -276,7 +281,7 @@ export class GraphhopperGeorouter implements IGeorouter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return distances;
|
return distances;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type GraphhopperResponse = {
|
type GraphhopperResponse = {
|
||||||
|
|
|
@ -12,7 +12,7 @@ export class Messager extends MessageBroker {
|
||||||
super(configService.get<string>('RMQ_EXCHANGE'));
|
super(configService.get<string>('RMQ_EXCHANGE'));
|
||||||
}
|
}
|
||||||
|
|
||||||
publish(routingKey: string, message: string): void {
|
publish = (routingKey: string, message: string): void => {
|
||||||
this._amqpConnection.publish(this.exchange, routingKey, message);
|
this._amqpConnection.publish(this.exchange, routingKey, message);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,10 @@ export class Actor {
|
||||||
person: Person;
|
person: Person;
|
||||||
role: Role;
|
role: Role;
|
||||||
step: Step;
|
step: Step;
|
||||||
|
|
||||||
|
constructor(person: Person, role: Role, step: Step) {
|
||||||
|
this.person = person;
|
||||||
|
this.role = role;
|
||||||
|
this.step = step;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,32 +3,129 @@ import { IRequestGeography } from '../interfaces/geography-request.interface';
|
||||||
import { PointType } from '../types/geography.enum';
|
import { PointType } from '../types/geography.enum';
|
||||||
import { Point } from '../types/point.type';
|
import { Point } from '../types/point.type';
|
||||||
import { find } from 'geo-tz';
|
import { find } from 'geo-tz';
|
||||||
import { Waypoint } from '../types/waypoint';
|
|
||||||
import { Route } from './route';
|
import { Route } from './route';
|
||||||
|
import { Role } from '../types/role.enum';
|
||||||
|
import { IGeorouter } from '../interfaces/georouter.interface';
|
||||||
|
import { Waypoint } from './waypoint';
|
||||||
|
import { Actor } from './actor';
|
||||||
|
import { Person } from './person';
|
||||||
|
import { Step } from '../types/step.enum';
|
||||||
|
import { Path } from '../types/path.type';
|
||||||
|
|
||||||
export class Geography {
|
export class Geography {
|
||||||
_geographyRequest: IRequestGeography;
|
_geographyRequest: IRequestGeography;
|
||||||
waypoints: Array<Waypoint>;
|
_person: Person;
|
||||||
|
_points: Array<Point>;
|
||||||
originType: PointType;
|
originType: PointType;
|
||||||
destinationType: PointType;
|
destinationType: PointType;
|
||||||
timezones: Array<string>;
|
timezones: Array<string>;
|
||||||
driverRoute: Route;
|
driverRoute: Route;
|
||||||
passengerRoute: Route;
|
passengerRoute: Route;
|
||||||
|
|
||||||
constructor(geographyRequest: IRequestGeography, defaultTimezone: string) {
|
constructor(
|
||||||
|
geographyRequest: IRequestGeography,
|
||||||
|
defaultTimezone: string,
|
||||||
|
person: Person,
|
||||||
|
) {
|
||||||
this._geographyRequest = geographyRequest;
|
this._geographyRequest = geographyRequest;
|
||||||
this.waypoints = [];
|
this._person = person;
|
||||||
this.originType = PointType.OTHER;
|
this._points = [];
|
||||||
this.destinationType = PointType.OTHER;
|
this.originType = undefined;
|
||||||
|
this.destinationType = undefined;
|
||||||
this.timezones = [defaultTimezone];
|
this.timezones = [defaultTimezone];
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init = (): void => {
|
||||||
this._validateWaypoints();
|
this._validateWaypoints();
|
||||||
this._setTimezones();
|
this._setTimezones();
|
||||||
}
|
this._setPointTypes();
|
||||||
|
};
|
||||||
|
|
||||||
_validateWaypoints() {
|
createRoutes = async (
|
||||||
|
roles: Array<Role>,
|
||||||
|
georouter: IGeorouter,
|
||||||
|
): Promise<void> => {
|
||||||
|
let driverWaypoints: Array<Waypoint> = [];
|
||||||
|
let passengerWaypoints: Array<Waypoint> = [];
|
||||||
|
const paths: Array<Path> = [];
|
||||||
|
if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) {
|
||||||
|
if (this._points.length == 2) {
|
||||||
|
// 2 points => same route for driver and passenger
|
||||||
|
const commonPath: Path = {
|
||||||
|
key: RouteKey.COMMON,
|
||||||
|
points: this._points,
|
||||||
|
};
|
||||||
|
driverWaypoints = this._createWaypoints(commonPath.points, Role.DRIVER);
|
||||||
|
passengerWaypoints = this._createWaypoints(
|
||||||
|
commonPath.points,
|
||||||
|
Role.PASSENGER,
|
||||||
|
);
|
||||||
|
paths.push(commonPath);
|
||||||
|
} else {
|
||||||
|
const driverPath: Path = {
|
||||||
|
key: RouteKey.DRIVER,
|
||||||
|
points: this._points,
|
||||||
|
};
|
||||||
|
driverWaypoints = this._createWaypoints(driverPath.points, Role.DRIVER);
|
||||||
|
const passengerPath: Path = {
|
||||||
|
key: RouteKey.PASSENGER,
|
||||||
|
points: [this._points[0], this._points[this._points.length - 1]],
|
||||||
|
};
|
||||||
|
passengerWaypoints = this._createWaypoints(
|
||||||
|
passengerPath.points,
|
||||||
|
Role.PASSENGER,
|
||||||
|
);
|
||||||
|
paths.push(driverPath, passengerPath);
|
||||||
|
}
|
||||||
|
} else if (roles.includes(Role.DRIVER)) {
|
||||||
|
const driverPath: Path = {
|
||||||
|
key: RouteKey.DRIVER,
|
||||||
|
points: this._points,
|
||||||
|
};
|
||||||
|
driverWaypoints = this._createWaypoints(driverPath.points, Role.DRIVER);
|
||||||
|
paths.push(driverPath);
|
||||||
|
} else if (roles.includes(Role.PASSENGER)) {
|
||||||
|
const passengerPath: Path = {
|
||||||
|
key: RouteKey.PASSENGER,
|
||||||
|
points: [this._points[0], this._points[this._points.length - 1]],
|
||||||
|
};
|
||||||
|
passengerWaypoints = this._createWaypoints(
|
||||||
|
passengerPath.points,
|
||||||
|
Role.PASSENGER,
|
||||||
|
);
|
||||||
|
paths.push(passengerPath);
|
||||||
|
}
|
||||||
|
const routes = await georouter.route(paths, {
|
||||||
|
withDistance: false,
|
||||||
|
withPoints: true,
|
||||||
|
withTime: false,
|
||||||
|
});
|
||||||
|
if (routes.some((route) => route.key == RouteKey.COMMON)) {
|
||||||
|
this.driverRoute = routes.find(
|
||||||
|
(route) => route.key == RouteKey.COMMON,
|
||||||
|
).route;
|
||||||
|
this.passengerRoute = routes.find(
|
||||||
|
(route) => route.key == RouteKey.COMMON,
|
||||||
|
).route;
|
||||||
|
this.driverRoute.setWaypoints(driverWaypoints);
|
||||||
|
this.passengerRoute.setWaypoints(passengerWaypoints);
|
||||||
|
} else {
|
||||||
|
if (routes.some((route) => route.key == RouteKey.DRIVER)) {
|
||||||
|
this.driverRoute = routes.find(
|
||||||
|
(route) => route.key == RouteKey.DRIVER,
|
||||||
|
).route;
|
||||||
|
this.driverRoute.setWaypoints(driverWaypoints);
|
||||||
|
}
|
||||||
|
if (routes.some((route) => route.key == RouteKey.PASSENGER)) {
|
||||||
|
this.passengerRoute = routes.find(
|
||||||
|
(route) => route.key == RouteKey.PASSENGER,
|
||||||
|
).route;
|
||||||
|
this.passengerRoute.setWaypoints(passengerWaypoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_validateWaypoints = (): void => {
|
||||||
if (this._geographyRequest.waypoints.length < 2) {
|
if (this._geographyRequest.waypoints.length < 2) {
|
||||||
throw new MatcherException(3, 'At least 2 waypoints are required');
|
throw new MatcherException(3, 'At least 2 waypoints are required');
|
||||||
}
|
}
|
||||||
|
@ -39,19 +136,25 @@ export class Geography {
|
||||||
`Waypoint { Lon: ${point.lon}, Lat: ${point.lat} } is not valid`,
|
`Waypoint { Lon: ${point.lon}, Lat: ${point.lat} } is not valid`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.waypoints.push({
|
this._points.push(point);
|
||||||
point,
|
|
||||||
actors: [],
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
_setTimezones() {
|
_setTimezones = (): void => {
|
||||||
this.timezones = find(
|
this.timezones = find(
|
||||||
this._geographyRequest.waypoints[0].lat,
|
this._geographyRequest.waypoints[0].lat,
|
||||||
this._geographyRequest.waypoints[0].lon,
|
this._geographyRequest.waypoints[0].lon,
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
_setPointTypes = (): void => {
|
||||||
|
this.originType =
|
||||||
|
this._geographyRequest.waypoints[0].type ?? PointType.OTHER;
|
||||||
|
this.destinationType =
|
||||||
|
this._geographyRequest.waypoints[
|
||||||
|
this._geographyRequest.waypoints.length - 1
|
||||||
|
].type ?? PointType.OTHER;
|
||||||
|
};
|
||||||
|
|
||||||
_isValidPoint = (point: Point): boolean =>
|
_isValidPoint = (point: Point): boolean =>
|
||||||
this._isValidLongitude(point.lon) && this._isValidLatitude(point.lat);
|
this._isValidLongitude(point.lon) && this._isValidLatitude(point.lat);
|
||||||
|
@ -61,4 +164,24 @@ export class Geography {
|
||||||
|
|
||||||
_isValidLatitude = (latitude: number): boolean =>
|
_isValidLatitude = (latitude: number): boolean =>
|
||||||
latitude >= -90 && latitude <= 90;
|
latitude >= -90 && latitude <= 90;
|
||||||
|
|
||||||
|
_createWaypoints = (points: Array<Point>, role: Role): Array<Waypoint> => {
|
||||||
|
return points.map((point, index) => {
|
||||||
|
const waypoint = new Waypoint(point);
|
||||||
|
if (index == 0) {
|
||||||
|
waypoint.addActor(new Actor(this._person, role, Step.START));
|
||||||
|
} else if (index == points.length - 1) {
|
||||||
|
waypoint.addActor(new Actor(this._person, role, Step.FINISH));
|
||||||
|
} else {
|
||||||
|
waypoint.addActor(new Actor(this._person, role, Step.INTERMEDIATE));
|
||||||
|
}
|
||||||
|
return waypoint;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum RouteKey {
|
||||||
|
COMMON = 'common',
|
||||||
|
DRIVER = 'driver',
|
||||||
|
PASSENGER = 'passenger',
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Route } from './route';
|
import { Route } from './route';
|
||||||
|
|
||||||
export class NamedRoute {
|
export type NamedRoute = {
|
||||||
key: string;
|
key: string;
|
||||||
route: Route;
|
route: Route;
|
||||||
}
|
};
|
||||||
|
|
|
@ -17,7 +17,7 @@ export class Person {
|
||||||
this._defaultMarginDuration = defaultMarginDuration;
|
this._defaultMarginDuration = defaultMarginDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init = (): void => {
|
||||||
this.setIdentifier(
|
this.setIdentifier(
|
||||||
this._personRequest.identifier ?? this._defaultIdentifier,
|
this._personRequest.identifier ?? this._defaultIdentifier,
|
||||||
);
|
);
|
||||||
|
@ -30,13 +30,13 @@ export class Person {
|
||||||
this._defaultMarginDuration,
|
this._defaultMarginDuration,
|
||||||
this._defaultMarginDuration,
|
this._defaultMarginDuration,
|
||||||
]);
|
]);
|
||||||
}
|
};
|
||||||
|
|
||||||
setIdentifier(identifier: number) {
|
setIdentifier = (identifier: number): void => {
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
}
|
};
|
||||||
|
|
||||||
setMarginDurations(marginDurations: Array<number>) {
|
setMarginDurations = (marginDurations: Array<number>): void => {
|
||||||
this.marginDurations = marginDurations;
|
this.marginDurations = marginDurations;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { IGeodesic } from '../interfaces/geodesic.interface';
|
import { IGeodesic } from '../interfaces/geodesic.interface';
|
||||||
|
import { Point } from '../types/point.type';
|
||||||
import { SpacetimePoint } from './spacetime-point';
|
import { SpacetimePoint } from './spacetime-point';
|
||||||
import { Waypoint } from './waypoint';
|
import { Waypoint } from './waypoint';
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ export class Route {
|
||||||
backAzimuth: number;
|
backAzimuth: number;
|
||||||
distanceAzimuth: number;
|
distanceAzimuth: number;
|
||||||
waypoints: Array<Waypoint>;
|
waypoints: Array<Waypoint>;
|
||||||
points: Array<Array<number>>;
|
points: Array<Point>;
|
||||||
spacetimePoints: Array<SpacetimePoint>;
|
spacetimePoints: Array<SpacetimePoint>;
|
||||||
_geodesic: IGeodesic;
|
_geodesic: IGeodesic;
|
||||||
|
|
||||||
|
@ -25,31 +26,31 @@ export class Route {
|
||||||
this._geodesic = geodesic;
|
this._geodesic = geodesic;
|
||||||
}
|
}
|
||||||
|
|
||||||
setWaypoints(waypoints: Array<Waypoint>): void {
|
setWaypoints = (waypoints: Array<Waypoint>): void => {
|
||||||
this.waypoints = waypoints;
|
this.waypoints = waypoints;
|
||||||
this._setAzimuth(waypoints.map((waypoint) => waypoint.point));
|
this._setAzimuth(waypoints.map((waypoint) => waypoint.point));
|
||||||
}
|
};
|
||||||
|
|
||||||
setPoints(points: Array<Array<number>>): void {
|
setPoints = (points: Array<Point>): void => {
|
||||||
this.points = points;
|
this.points = points;
|
||||||
this._setAzimuth(points);
|
this._setAzimuth(points);
|
||||||
}
|
};
|
||||||
|
|
||||||
setSpacetimePoints(spacetimePoints: Array<SpacetimePoint>): void {
|
setSpacetimePoints = (spacetimePoints: Array<SpacetimePoint>): void => {
|
||||||
this.spacetimePoints = spacetimePoints;
|
this.spacetimePoints = spacetimePoints;
|
||||||
}
|
};
|
||||||
|
|
||||||
_setAzimuth(points: Array<Array<number>>): void {
|
_setAzimuth = (points: Array<Point>): void => {
|
||||||
const inverse = this._geodesic.inverse(
|
const inverse = this._geodesic.inverse(
|
||||||
points[0][0],
|
points[0].lon,
|
||||||
points[0][1],
|
points[0].lat,
|
||||||
points[points.length - 1][0],
|
points[points.length - 1].lon,
|
||||||
points[points.length - 1][1],
|
points[points.length - 1].lat,
|
||||||
);
|
);
|
||||||
this.fwdAzimuth =
|
this.fwdAzimuth =
|
||||||
inverse.azimuth >= 0 ? inverse.azimuth : 360 - Math.abs(inverse.azimuth);
|
inverse.azimuth >= 0 ? inverse.azimuth : 360 - Math.abs(inverse.azimuth);
|
||||||
this.backAzimuth =
|
this.backAzimuth =
|
||||||
this.fwdAzimuth > 180 ? this.fwdAzimuth - 180 : this.fwdAzimuth + 180;
|
this.fwdAzimuth > 180 ? this.fwdAzimuth - 180 : this.fwdAzimuth + 180;
|
||||||
this.distanceAzimuth = inverse.distance;
|
this.distanceAzimuth = inverse.distance;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,31 +34,31 @@ export class Time {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init = (): void => {
|
||||||
this._validateBaseDate();
|
this._validateBaseDate();
|
||||||
this._validatePunctualRequest();
|
this._validatePunctualRequest();
|
||||||
this._validateRecurrentRequest();
|
this._validateRecurrentRequest();
|
||||||
this._setPunctualRequest();
|
this._setPunctualRequest();
|
||||||
this._setRecurrentRequest();
|
this._setRecurrentRequest();
|
||||||
this._setMargindurations();
|
this._setMargindurations();
|
||||||
}
|
};
|
||||||
|
|
||||||
_validateBaseDate() {
|
_validateBaseDate = (): void => {
|
||||||
if (!this._timeRequest.departure && !this._timeRequest.fromDate) {
|
if (!this._timeRequest.departure && !this._timeRequest.fromDate) {
|
||||||
throw new MatcherException(3, 'departure or fromDate is required');
|
throw new MatcherException(3, 'departure or fromDate is required');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_validatePunctualRequest() {
|
_validatePunctualRequest = (): void => {
|
||||||
if (this._timeRequest.departure) {
|
if (this._timeRequest.departure) {
|
||||||
this.fromDate = this.toDate = new Date(this._timeRequest.departure);
|
this.fromDate = this.toDate = new Date(this._timeRequest.departure);
|
||||||
if (!this._isDate(this.fromDate)) {
|
if (!this._isDate(this.fromDate)) {
|
||||||
throw new MatcherException(3, 'Wrong departure date');
|
throw new MatcherException(3, 'Wrong departure date');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_validateRecurrentRequest() {
|
_validateRecurrentRequest = (): void => {
|
||||||
if (this._timeRequest.fromDate) {
|
if (this._timeRequest.fromDate) {
|
||||||
this.fromDate = new Date(this._timeRequest.fromDate);
|
this.fromDate = new Date(this._timeRequest.fromDate);
|
||||||
if (!this._isDate(this.fromDate)) {
|
if (!this._isDate(this.fromDate)) {
|
||||||
|
@ -77,9 +77,9 @@ export class Time {
|
||||||
if (this._timeRequest.fromDate) {
|
if (this._timeRequest.fromDate) {
|
||||||
this._validateSchedule();
|
this._validateSchedule();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_validateSchedule() {
|
_validateSchedule = (): void => {
|
||||||
if (!this._timeRequest.schedule) {
|
if (!this._timeRequest.schedule) {
|
||||||
throw new MatcherException(3, 'Schedule is required');
|
throw new MatcherException(3, 'Schedule is required');
|
||||||
}
|
}
|
||||||
|
@ -96,17 +96,17 @@ export class Time {
|
||||||
throw new MatcherException(3, `Wrong time for ${day} in schedule`);
|
throw new MatcherException(3, `Wrong time for ${day} in schedule`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
_setPunctualRequest() {
|
_setPunctualRequest = (): void => {
|
||||||
if (this._timeRequest.departure) {
|
if (this._timeRequest.departure) {
|
||||||
this.frequency = TimingFrequency.FREQUENCY_PUNCTUAL;
|
this.frequency = TimingFrequency.FREQUENCY_PUNCTUAL;
|
||||||
this.schedule[TimingDays[this.fromDate.getDay()]] =
|
this.schedule[TimingDays[this.fromDate.getDay()]] =
|
||||||
this.fromDate.getHours() + ':' + this.fromDate.getMinutes();
|
this.fromDate.getHours() + ':' + this.fromDate.getMinutes();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_setRecurrentRequest() {
|
_setRecurrentRequest = (): void => {
|
||||||
if (this._timeRequest.fromDate) {
|
if (this._timeRequest.fromDate) {
|
||||||
this.frequency = TimingFrequency.FREQUENCY_RECURRENT;
|
this.frequency = TimingFrequency.FREQUENCY_RECURRENT;
|
||||||
if (!this.toDate) {
|
if (!this.toDate) {
|
||||||
|
@ -117,15 +117,15 @@ export class Time {
|
||||||
}
|
}
|
||||||
this._setSchedule();
|
this._setSchedule();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_setSchedule() {
|
_setSchedule = (): void => {
|
||||||
Object.keys(this._timeRequest.schedule).map((day) => {
|
Object.keys(this._timeRequest.schedule).map((day) => {
|
||||||
this.schedule[day] = this._timeRequest.schedule[day];
|
this.schedule[day] = this._timeRequest.schedule[day];
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
_setMargindurations() {
|
_setMargindurations = (): void => {
|
||||||
if (this._timeRequest.marginDuration) {
|
if (this._timeRequest.marginDuration) {
|
||||||
const duration = Math.abs(this._timeRequest.marginDuration);
|
const duration = Math.abs(this._timeRequest.marginDuration);
|
||||||
this.marginDurations = {
|
this.marginDurations = {
|
||||||
|
@ -155,7 +155,7 @@ export class Time {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_isDate = (date: Date): boolean => {
|
_isDate = (date: Date): boolean => {
|
||||||
return date instanceof Date && isFinite(+date);
|
return date instanceof Date && isFinite(+date);
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
|
import { Point } from '../types/point.type';
|
||||||
import { Actor } from './actor';
|
import { Actor } from './actor';
|
||||||
|
|
||||||
export class Waypoint {
|
export class Waypoint {
|
||||||
point: Array<number>;
|
point: Point;
|
||||||
actors: Array<Actor>;
|
actors: Array<Actor>;
|
||||||
|
|
||||||
|
constructor(point: Point) {
|
||||||
|
this.point = point;
|
||||||
|
this.actors = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
addActor = (actor: Actor) => this.actors.push(actor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
import { PointType } from './geography.enum';
|
||||||
|
|
||||||
export type Point = {
|
export type Point = {
|
||||||
lon: number;
|
lon: number;
|
||||||
lat: number;
|
lat: number;
|
||||||
|
type?: PointType;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class MatchUseCase {
|
||||||
@InjectMapper() private readonly _mapper: Mapper,
|
@InjectMapper() private readonly _mapper: Mapper,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(matchQuery: MatchQuery): Promise<ICollection<Match>> {
|
execute = async (matchQuery: MatchQuery): Promise<ICollection<Match>> => {
|
||||||
try {
|
try {
|
||||||
// const paths = [];
|
// const paths = [];
|
||||||
// for (let i = 0; i < 1; i++) {
|
// for (let i = 0; i < 1; i++) {
|
||||||
|
@ -73,5 +73,5 @@ export class MatchUseCase {
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export class MatchProfile extends AutomapperProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
override get profile() {
|
override get profile() {
|
||||||
return (mapper) => {
|
return (mapper: Mapper) => {
|
||||||
createMap(mapper, Match, MatchPresenter);
|
createMap(mapper, Match, MatchPresenter);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,60 +39,65 @@ export class MatchQuery {
|
||||||
this._setExclusions();
|
this._setExclusions();
|
||||||
}
|
}
|
||||||
|
|
||||||
_setPerson() {
|
createRoutes = (): void => {
|
||||||
|
this.geography.createRoutes(this.roles, this.algorithmSettings.georouter);
|
||||||
|
};
|
||||||
|
|
||||||
|
_setPerson = (): void => {
|
||||||
this.person = new Person(
|
this.person = new Person(
|
||||||
this._matchRequest,
|
this._matchRequest,
|
||||||
this._defaultParams.DEFAULT_IDENTIFIER,
|
this._defaultParams.DEFAULT_IDENTIFIER,
|
||||||
this._defaultParams.MARGIN_DURATION,
|
this._defaultParams.MARGIN_DURATION,
|
||||||
);
|
);
|
||||||
this.person.init();
|
this.person.init();
|
||||||
}
|
};
|
||||||
|
|
||||||
_setRoles() {
|
_setRoles = (): void => {
|
||||||
this.roles = [];
|
this.roles = [];
|
||||||
if (this._matchRequest.driver) this.roles.push(Role.DRIVER);
|
if (this._matchRequest.driver) this.roles.push(Role.DRIVER);
|
||||||
if (this._matchRequest.passenger) this.roles.push(Role.PASSENGER);
|
if (this._matchRequest.passenger) this.roles.push(Role.PASSENGER);
|
||||||
if (this.roles.length == 0) this.roles.push(Role.PASSENGER);
|
if (this.roles.length == 0) this.roles.push(Role.PASSENGER);
|
||||||
}
|
};
|
||||||
|
|
||||||
_setTime() {
|
_setTime = (): void => {
|
||||||
this.time = new Time(
|
this.time = new Time(
|
||||||
this._matchRequest,
|
this._matchRequest,
|
||||||
this._defaultParams.MARGIN_DURATION,
|
this._defaultParams.MARGIN_DURATION,
|
||||||
this._defaultParams.VALIDITY_DURATION,
|
this._defaultParams.VALIDITY_DURATION,
|
||||||
);
|
);
|
||||||
this.time.init();
|
this.time.init();
|
||||||
}
|
};
|
||||||
|
|
||||||
_setGeography() {
|
_setGeography = (): void => {
|
||||||
this.geography = new Geography(
|
this.geography = new Geography(
|
||||||
this._matchRequest,
|
this._matchRequest,
|
||||||
this._defaultParams.DEFAULT_TIMEZONE,
|
this._defaultParams.DEFAULT_TIMEZONE,
|
||||||
|
this.person,
|
||||||
);
|
);
|
||||||
this.geography.init();
|
this.geography.init();
|
||||||
}
|
};
|
||||||
|
|
||||||
_setRequirement() {
|
_setRequirement = (): void => {
|
||||||
this.requirement = new Requirement(
|
this.requirement = new Requirement(
|
||||||
this._matchRequest,
|
this._matchRequest,
|
||||||
this._defaultParams.DEFAULT_SEATS,
|
this._defaultParams.DEFAULT_SEATS,
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
_setAlgorithmSettings() {
|
_setAlgorithmSettings = (): void => {
|
||||||
this.algorithmSettings = new AlgorithmSettings(
|
this.algorithmSettings = new AlgorithmSettings(
|
||||||
this._matchRequest,
|
this._matchRequest,
|
||||||
this._defaultParams.DEFAULT_ALGORITHM_SETTINGS,
|
this._defaultParams.DEFAULT_ALGORITHM_SETTINGS,
|
||||||
this.time.frequency,
|
this.time.frequency,
|
||||||
this._georouterCreator,
|
this._georouterCreator,
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
_setExclusions() {
|
_setExclusions = (): void => {
|
||||||
this.exclusions = [];
|
this.exclusions = [];
|
||||||
if (this._matchRequest.identifier)
|
if (this._matchRequest.identifier)
|
||||||
this.exclusions.push(this._matchRequest.identifier);
|
this.exclusions.push(this._matchRequest.identifier);
|
||||||
if (this._matchRequest.exclusions)
|
if (this._matchRequest.exclusions)
|
||||||
this.exclusions.push(...this._matchRequest.exclusions);
|
this.exclusions.push(...this._matchRequest.exclusions);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,66 @@
|
||||||
import { Geography } from '../../../domain/entities/geography';
|
import { Person } from '../../../domain/entities/person';
|
||||||
|
import { Geography, RouteKey } from '../../../domain/entities/geography';
|
||||||
|
import { Role } from '../../../domain/types/role.enum';
|
||||||
|
import { NamedRoute } from '../../../domain/entities/named-route';
|
||||||
|
import { Route } from '../../../domain/entities/route';
|
||||||
|
import { IGeodesic } from '../../../domain/interfaces/geodesic.interface';
|
||||||
|
import { PointType } from '../../../domain/types/geography.enum';
|
||||||
|
|
||||||
|
const person: Person = new Person(
|
||||||
|
{
|
||||||
|
identifier: 1,
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
900,
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockGeodesic: IGeodesic = {
|
||||||
|
inverse: jest.fn().mockImplementation(() => ({
|
||||||
|
azimuth: 45,
|
||||||
|
distance: 50000,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockGeorouter = {
|
||||||
|
route: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
return [
|
||||||
|
<NamedRoute>{
|
||||||
|
key: RouteKey.COMMON,
|
||||||
|
route: new Route(mockGeodesic),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
return [
|
||||||
|
<NamedRoute>{
|
||||||
|
key: RouteKey.DRIVER,
|
||||||
|
route: new Route(mockGeodesic),
|
||||||
|
},
|
||||||
|
<NamedRoute>{
|
||||||
|
key: RouteKey.PASSENGER,
|
||||||
|
route: new Route(mockGeodesic),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
return [
|
||||||
|
<NamedRoute>{
|
||||||
|
key: RouteKey.DRIVER,
|
||||||
|
route: new Route(mockGeodesic),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
return [
|
||||||
|
<NamedRoute>{
|
||||||
|
key: RouteKey.PASSENGER,
|
||||||
|
route: new Route(mockGeodesic),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
describe('Geography entity', () => {
|
describe('Geography entity', () => {
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
|
@ -16,29 +78,35 @@ describe('Geography entity', () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
);
|
);
|
||||||
expect(geography).toBeDefined();
|
expect(geography).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('init', () => {
|
describe('init', () => {
|
||||||
it('should initialize a geography request', () => {
|
it('should initialize a geography request with point types', () => {
|
||||||
const geography = new Geography(
|
const geography = new Geography(
|
||||||
{
|
{
|
||||||
waypoints: [
|
waypoints: [
|
||||||
{
|
{
|
||||||
lat: 49.440041,
|
lat: 49.440041,
|
||||||
lon: 1.093912,
|
lon: 1.093912,
|
||||||
|
type: PointType.LOCALITY,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
lat: 50.630992,
|
lat: 50.630992,
|
||||||
lon: 3.045432,
|
lon: 3.045432,
|
||||||
|
type: PointType.LOCALITY,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
);
|
);
|
||||||
geography.init();
|
geography.init();
|
||||||
expect(geography.waypoints.length).toBe(2);
|
expect(geography._points.length).toBe(2);
|
||||||
|
expect(geography.originType).toBe(PointType.LOCALITY);
|
||||||
|
expect(geography.destinationType).toBe(PointType.LOCALITY);
|
||||||
});
|
});
|
||||||
it('should throw an exception if waypoints are empty', () => {
|
it('should throw an exception if waypoints are empty', () => {
|
||||||
const geography = new Geography(
|
const geography = new Geography(
|
||||||
|
@ -46,6 +114,7 @@ describe('Geography entity', () => {
|
||||||
waypoints: [],
|
waypoints: [],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
});
|
});
|
||||||
|
@ -60,6 +129,7 @@ describe('Geography entity', () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
});
|
});
|
||||||
|
@ -78,6 +148,7 @@ describe('Geography entity', () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
});
|
});
|
||||||
|
@ -96,8 +167,113 @@ describe('Geography entity', () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('create route', () => {
|
||||||
|
it('should create routes as driver and passenger', async () => {
|
||||||
|
const geography = new Geography(
|
||||||
|
{
|
||||||
|
waypoints: [
|
||||||
|
{
|
||||||
|
lat: 49.440041,
|
||||||
|
lon: 1.093912,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lat: 50.630992,
|
||||||
|
lon: 3.045432,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
|
);
|
||||||
|
geography.init();
|
||||||
|
await geography.createRoutes(
|
||||||
|
[Role.DRIVER, Role.PASSENGER],
|
||||||
|
mockGeorouter,
|
||||||
|
);
|
||||||
|
expect(geography.driverRoute.waypoints.length).toBe(2);
|
||||||
|
expect(geography.passengerRoute.waypoints.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create routes as driver and passenger with 3 waypoints', async () => {
|
||||||
|
const geography = new Geography(
|
||||||
|
{
|
||||||
|
waypoints: [
|
||||||
|
{
|
||||||
|
lat: 49.440041,
|
||||||
|
lon: 1.093912,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lat: 49.781215,
|
||||||
|
lon: 2.198475,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lat: 50.630992,
|
||||||
|
lon: 3.045432,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
|
);
|
||||||
|
geography.init();
|
||||||
|
await geography.createRoutes(
|
||||||
|
[Role.DRIVER, Role.PASSENGER],
|
||||||
|
mockGeorouter,
|
||||||
|
);
|
||||||
|
expect(geography.driverRoute.waypoints.length).toBe(3);
|
||||||
|
expect(geography.passengerRoute.waypoints.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create routes as driver', async () => {
|
||||||
|
const geography = new Geography(
|
||||||
|
{
|
||||||
|
waypoints: [
|
||||||
|
{
|
||||||
|
lat: 49.440041,
|
||||||
|
lon: 1.093912,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lat: 50.630992,
|
||||||
|
lon: 3.045432,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
|
);
|
||||||
|
geography.init();
|
||||||
|
await geography.createRoutes([Role.DRIVER], mockGeorouter);
|
||||||
|
expect(geography.driverRoute.waypoints.length).toBe(2);
|
||||||
|
expect(geography.passengerRoute).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create routes as passenger', async () => {
|
||||||
|
const geography = new Geography(
|
||||||
|
{
|
||||||
|
waypoints: [
|
||||||
|
{
|
||||||
|
lat: 49.440041,
|
||||||
|
lon: 1.093912,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lat: 50.630992,
|
||||||
|
lon: 3.045432,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'Europe/Paris',
|
||||||
|
person,
|
||||||
|
);
|
||||||
|
geography.init();
|
||||||
|
await geography.createRoutes([Role.PASSENGER], mockGeorouter);
|
||||||
|
expect(geography.passengerRoute.waypoints.length).toBe(2);
|
||||||
|
expect(geography.driverRoute).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,10 +24,14 @@ describe('Route entity', () => {
|
||||||
});
|
});
|
||||||
it('should set waypoints and geodesic values for a route', () => {
|
it('should set waypoints and geodesic values for a route', () => {
|
||||||
const route = new Route(mockGeodesic);
|
const route = new Route(mockGeodesic);
|
||||||
const waypoint1: Waypoint = new Waypoint();
|
const waypoint1: Waypoint = new Waypoint({
|
||||||
waypoint1.point = [0, 0];
|
lon: 0,
|
||||||
const waypoint2: Waypoint = new Waypoint();
|
lat: 0,
|
||||||
waypoint2.point = [10, 10];
|
});
|
||||||
|
const waypoint2: Waypoint = new Waypoint({
|
||||||
|
lon: 10,
|
||||||
|
lat: 10,
|
||||||
|
});
|
||||||
route.setWaypoints([waypoint1, waypoint2]);
|
route.setWaypoints([waypoint1, waypoint2]);
|
||||||
expect(route.waypoints.length).toBe(2);
|
expect(route.waypoints.length).toBe(2);
|
||||||
expect(route.fwdAzimuth).toBe(45);
|
expect(route.fwdAzimuth).toBe(45);
|
||||||
|
@ -37,8 +41,14 @@ describe('Route entity', () => {
|
||||||
it('should set points and geodesic values for a route', () => {
|
it('should set points and geodesic values for a route', () => {
|
||||||
const route = new Route(mockGeodesic);
|
const route = new Route(mockGeodesic);
|
||||||
route.setPoints([
|
route.setPoints([
|
||||||
[10, 10],
|
{
|
||||||
[20, 20],
|
lon: 10,
|
||||||
|
lat: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lon: 20,
|
||||||
|
lat: 20,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
expect(route.points.length).toBe(2);
|
expect(route.points.length).toBe(2);
|
||||||
expect(route.fwdAzimuth).toBe(315);
|
expect(route.fwdAzimuth).toBe(315);
|
||||||
|
|
Loading…
Reference in New Issue