Skip to content

Instantly share code, notes, and snippets.

@nicohvi
Last active July 11, 2019 08:59
Show Gist options
  • Save nicohvi/6945e6d94b13324171811265d0158a0e to your computer and use it in GitHub Desktop.
Save nicohvi/6945e6d94b13324171811265d0158a0e to your computer and use it in GitHub Desktop.
// @flow
import { sdkService } from '@entur/journey'
import { first, flatten, without } from 'lodash'
import type { Coordinates } from '@entur/journey/flow-types'
import { DEFAULT_IGNORE_FIELDS } from '@entur/client-native/app/containers/WalkingDirections'
import { getDistanceBetweenLocations } from '@entur/client-commons/utils/location'
import type { BikeRentalStation, TripPattern } from '../../flow-types'
// N: for mange any-typer! Bruk typesystemet!
type BikeRentalStationPath = {
from: Coordinates,
to: Coordinates,
mode: string,
}
// Helper function
// Har denna för att enklare trekke ut lat & lon ur objekt, för att få rätt type.
function getLatLon(object: any): {longitude: number, latitude: number} {
// N: er dette kun for å filtere ut lat, long fra objektet? Da er jo noe som f.eks. R.pick(['longitude', 'latitude'], obj) bedre
// enn en helper-funksjon (finnes sikkert noe tilsvarende i lodash).
return {
longitude: object.longitude,
latitude: object.latitude,
}
}
// Gör ett resesök via Enturs SDK
function getLegsFromSDK(path: BikeRentalStationPath, walkSpeed: number) {
const { from, to, mode } = path
const legs = sdkService.getTripPatterns(
{ coordinates: getLatLon(from) },
{ coordinates: getLatLon(to) },
{ modes: [mode], walkSpeed },
without(DEFAULT_IGNORE_FIELDS, 'pointsOnLink', 'rentedBike')
)
return legs
}
// Helper function
// summerar ihop värdet i en property i ett objekt, key finns som parameter för att göra den mer generell.
function getTotalValue(list: Array<any>, key: string) { // her burde any -> { [key in Keys]: number }
return list.reduce((totalValue, currentItem) => totalValue + currentItem[key], 0)
}
// Skapa ett TripPattern av enstaka legs
// Ett TripPattern borde ha en lista med legs, och totala tiden & distansen för trip:et.
// PS: TripPattern.legs =
function mergeTripPatterns(tripPatterns: Array<TripPattern>): TripPattern {
return {
...first(tripPatterns),
distance: getTotalValue(tripPatterns, 'distance'),
duration: getTotalValue(tripPatterns, 'duration'),
legs: tripPatterns.map(tripPattern => first(tripPattern.legs)),
}
}
// Hämta alla stationer nära ett stoppested och returnera den närmsta stationen
function getNearestStation(referencePoint: Coordinates, stations: Array<BikeRentalStation>) {
const distances = stations.map(station => getDistanceBetweenLocations(
{ geometry: { coordinates: [referencePoint.longitude, referencePoint.latitude] } }, // hvorfor bruker du ikke hjelpefunksjonen?
{ geometry: { coordinates: [station.longitude, station.latitude] } }
))
return stations[distances.indexOf(Math.min(...distances))]
}
// The bread and butter function, denna är the big boss
// Målet är att ersätta en gånglänke mellan A och B med bysykkel!!!!
//
// Så tanken är:
// 1. Hämta byskkelstationer nära A och B.
// 2. Gör ett resesök där man åker såhär: A—> bysykkelStationA —> bysykkelStationB —> B
// 3. returnera detta nya resesöket (TripPattern)
export async function getBikeRentalStationLeg(
start: Coordinates, stop: Coordinates, walkSpeed: number,
) {
const [startStations, stopStations] = await Promise.all(
[start, stop].map(station => sdkService.getBikeRentalStationsByPosition(station, 200))
)
// dette ser bra ut, men tror jeg ville ekstrahert det ut i en egen funksjon.
// typ:
/*
async function getBikeRentalStationCandidates(start: Coordinates, stop: Coordinates) {
const startStation = await sdkService.getBikeRentalStationsByPosition(start, 200) // antar denne returnerer tomt array
if(empty(startStations)) return null // ingen grunn til å fortsette
const stopStations = await sdkService.getBikeRentalStationsByPosition(stop, 200)
if(empty(stopStations)) return null // samme som over
return {start: getNearestStation(start, startStations), stop: getNearestStation(stop, stopStations)}
og i hovedfunksjonen:
const stations = getBikeRentalStationCandidates(start, stop)
if(!stations) return // ingen grunn til å forsette
*/
const [startStation, stopStation] = [getNearestStation(start, startStations), getNearestStation(stop, stopStations)]
if (!startStation || !stopStation) return
// ingen grunn til å definere denne inne i funksjonen, burde defineres utenfor siden den er statisk.
const modes = ['foot', 'bicycle', 'foot']
const stops = [start, startStation, stopStation, stop]
// denne burde også være en egen funksjon. Det er ikke tydelig fra koden at du vil gå til første stasjon,
// deretter ta sykkel, og så gå fra siste stasjon.
// Tror jeg ville gjort noe slik:
/*
function getBicyclePath(stations, start, stop) {
return [merge, stations.start, stations.stop, stop].map((leg, idx, arr) => {
if(idx === stops.length -1) return null
const next = arr[idx+1];
return {
from: getLatLon(leg),
to: getLatLon(next),
mode: betweenStations(leg,next) ? 'bycicle' : 'walk'
}
}).filter(Boolean)
}
*/
const paths: Array<?BikeRentalStationPath> = stops.map((station, index, arr) => {
if (index === stops.length - 1) return null
const nextStop = arr[index + 1]
return {
from: getLatLon(station),
to: getLatLon(nextStop),
mode: modes[index], // forvirrrende bruk av indekser
}
})
const filteredPaths: Array<BikeRentalStationPath> = paths.filter(Boolean)
const patterns: Array<TripPattern> = flatten(
await Promise.all(filteredPaths.map(path => getLegsFromSDK(path, walkSpeed)))
)
if (!patterns) return
return {
from: startStation,
to: stopStation,
tripPattern: mergeTripPatterns(patterns),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment