Skip to content

Commit

Permalink
feat: integrate station connectivity finder with service
Browse files Browse the repository at this point in the history
issue: #242
  • Loading branch information
CodeBear801 committed May 12, 2020
1 parent d93649f commit e23ecc6
Show file tree
Hide file tree
Showing 16 changed files with 188 additions and 102 deletions.
2 changes: 1 addition & 1 deletion integration/cmd/place-connectivity-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func main() {
}
indexer.Dump(flags.outputFolder)

connectivitymap.NewConnectivityMap(flags.maxRange).
connectivitymap.New(flags.maxRange).
Build(indexer, indexer, rankerStrategy, flags.numberOfWorkers).
Dump(flags.outputFolder)

Expand Down
5 changes: 5 additions & 0 deletions integration/service/oasis/connectivitymap/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ func (builder *connectivityMapBuilder) work(workerID int, source <-chan spatiali

ids := make([]IDAndWeight, 0, len(rankedResults))
for _, r := range rankedResults {
// skip connectivity to itself
if r.ID == p.ID {
continue
}

ids = append(ids, IDAndWeight{
ID: r.ID,
Weight: Weight{
Expand Down
4 changes: 2 additions & 2 deletions integration/service/oasis/connectivitymap/connectivity_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ type ConnectivityMap struct {
statistic *statistic
}

// NewConnectivityMap creates ConnectivityMap
func NewConnectivityMap(maxRange float64) *ConnectivityMap {
// New creates ConnectivityMap
func New(maxRange float64) *ConnectivityMap {
return &ConnectivityMap{
maxRange: maxRange,
statistic: newStatistic(),
Expand Down
2 changes: 1 addition & 1 deletion integration/service/oasis/connectivitymap/dumper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestDumpGivenObjectThenLoadAndThenCompareWithOriginalObject(t *testing.T) {
t.Errorf("During running serializeConnectivityMap for case %v, met error %v", c, err)
}

actual := NewConnectivityMap(0.0)
actual := New(0.0)
if err := deSerializeConnectivityMap(actual, path); err != nil {
t.Errorf("During running deSerializeConnectivityMap for case %v, met error %v", c, err)
}
Expand Down
32 changes: 11 additions & 21 deletions integration/service/oasis/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,26 @@ import (
"net/http"

"github.com/Telenav/osrm-backend/integration/api/oasis"
"github.com/Telenav/osrm-backend/integration/service/oasis/osrmconnector"
"github.com/Telenav/osrm-backend/integration/service/oasis/osrmhelper"
"github.com/Telenav/osrm-backend/integration/service/oasis/stationfinder"
"github.com/Telenav/osrm-backend/integration/service/oasis/selectionstrategy"
"github.com/golang/glog"
)

// Handler handles oasis request and provide response
type Handler struct {
osrmConnector *osrmconnector.OSRMConnector
finder stationfinder.StationFinder
resourceMgr *selectionstrategy.ResourceMgr
}

// New creates new Handler object
func New(osrmBackend, finderType, searchEndpoint, apiKey, apiSignature, dataFolderPath string) (*Handler, error) {
// @todo: need make sure connectivity is on and continues available
// simple request to guarantee server is alive after init
if len(osrmBackend) == 0 {
err := fmt.Errorf("empty osrmBackend end point")
return nil, err
}

finder, err := stationfinder.CreateStationsFinder(finderType, searchEndpoint, apiKey, apiSignature, dataFolderPath)
resourceMgr, err := selectionstrategy.NewResourceMgr(osrmBackend, finderType, searchEndpoint, apiKey, apiSignature, dataFolderPath)
if err != nil {
glog.Errorf("Failed in Handler's New() when try to call CreateStationsFinder(), met error = %+v\n", err)
glog.Errorf("Failed to create Handler due to error %+v.\n", err)
return nil, err
}

return &Handler{
osrmConnector: osrmconnector.NewOSRMConnector(osrmBackend),
finder: finder,
resourceMgr: resourceMgr,
}, nil
}

Expand All @@ -52,7 +42,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}

// generate route response based on given oasis's orig/destination
routeResp, err := osrmhelper.RequestRoute4InputOrigDest(oasisReq, h.osrmConnector)
routeResp, err := osrmhelper.RequestRoute4InputOrigDest(oasisReq, h.resourceMgr.OSRMConnector())
if err != nil {
glog.Error(err)
w.WriteHeader(http.StatusOK)
Expand All @@ -70,27 +60,27 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}

// check whether has enough energy
b, remainRange, err := hasEnoughEnergy(oasisReq.CurrRange, oasisReq.SafeLevel, routeResp)
b, remainRange, err := selectionstrategy.HasEnoughEnergy(oasisReq.CurrRange, oasisReq.SafeLevel, routeResp)
if err != nil {
glog.Error(err)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "%v", err)
return
}
if b {
generateOASISResponse4NoChargeNeeded(w, routeResp, remainRange)
selectionstrategy.GenerateOASISResponse4NoChargeNeeded(w, routeResp, remainRange)
return
}

// check whether could achieve by single charge
overlap := getOverlapChargeStations4OrigDest(oasisReq, routeResp.Routes[0].Distance, h.osrmConnector, h.finder)
overlap := selectionstrategy.GetOverlapChargeStations4OrigDest(oasisReq, routeResp.Routes[0].Distance, h.resourceMgr)
if len(overlap) > 0 {
generateResponse4SingleChargeStation(w, oasisReq, overlap, h.osrmConnector)
selectionstrategy.GenerateResponse4SingleChargeStation(w, oasisReq, overlap, h.resourceMgr)
return
}

// generate result for multiple charge
generateSolutions4MultipleCharge(w, oasisReq, routeResp, h.osrmConnector, h.finder)
selectionstrategy.GenerateSolutions4MultipleCharge(w, oasisReq, routeResp, h.resourceMgr)
return
}

Expand Down
4 changes: 4 additions & 0 deletions integration/service/oasis/selectionstrategy/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
Package selectionstrategy contains logic related with charge station selection related logic.
*/
package selectionstrategy
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package oasis
package selectionstrategy

import (
"encoding/json"
Expand All @@ -13,7 +13,7 @@ import (
// currRange: current energy level, represent by distance(unit: meters)
// destRange: energy level required to destination
// currRange - routeDistance > destRange means no charge station is needed
func hasEnoughEnergy(currRange, destRange float64, routeResp *route.Response) (bool, float64, error) {
func HasEnoughEnergy(currRange, destRange float64, routeResp *route.Response) (bool, float64, error) {
if len(routeResp.Routes) == 0 {
err := fmt.Errorf("route response contains no route result")
return false, 0, err
Expand Down Expand Up @@ -42,7 +42,8 @@ func hasEnoughEnergy(currRange, destRange float64, routeResp *route.Response) (b
return false, remainRange, nil
}

func generateOASISResponse4NoChargeNeeded(w http.ResponseWriter, routeResp *route.Response, remainRange float64) {
// GenerateOASISResponse4NoChargeNeeded generates response for no charge needed
func GenerateOASISResponse4NoChargeNeeded(w http.ResponseWriter, routeResp *route.Response, remainRange float64) {
w.WriteHeader(http.StatusOK)

solution := new(oasis.Solution)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package oasis
package selectionstrategy

import (
"strconv"
Expand All @@ -10,12 +10,12 @@ import (

func TestHasEnoughEnergyPositive1(t *testing.T) {
response := &route.Response{
Routes: []*route.Route{&route.Route{Distance: 10000.0}},
Routes: []*route.Route{{Distance: 10000.0}},
}

currRange := 20000.0
destRange := 5000.0
b, remainRange, err := hasEnoughEnergy(currRange, destRange, response)
b, remainRange, err := HasEnoughEnergy(currRange, destRange, response)
if !b || err != nil {
t.Errorf("Incorrect result generated for TesthasEnoughEnergyPositive1, return value is (%t, %v)", b, err)
}
Expand All @@ -29,12 +29,12 @@ func TestHasEnoughEnergyPositive1(t *testing.T) {

func TestHasEnoughEnergyPositive2(t *testing.T) {
response := &route.Response{
Routes: []*route.Route{&route.Route{Distance: 10000.0}},
Routes: []*route.Route{{Distance: 10000.0}},
}

currRange := 10000.0
destRange := 5000.0
b, remainRange, err := hasEnoughEnergy(currRange, destRange, response)
b, remainRange, err := HasEnoughEnergy(currRange, destRange, response)
if b || err != nil {
t.Errorf("Incorrect result generated for TesthasEnoughEnergyPositive1, return value is (%t, %v)", b, err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package oasis
package selectionstrategy

import (
"encoding/json"
Expand All @@ -10,6 +10,8 @@ import (
"github.com/Telenav/osrm-backend/integration/service/oasis/chargingstrategy"
"github.com/Telenav/osrm-backend/integration/service/oasis/haversine"
"github.com/Telenav/osrm-backend/integration/service/oasis/osrmconnector"
"github.com/Telenav/osrm-backend/integration/service/oasis/spatialindexer/ranker"
"github.com/Telenav/osrm-backend/integration/service/oasis/stationconnquerier"
"github.com/Telenav/osrm-backend/integration/service/oasis/stationfinder"
"github.com/Telenav/osrm-backend/integration/service/oasis/stationfinder/stationfinderalg"
"github.com/Telenav/osrm-backend/integration/service/oasis/stationgraph"
Expand All @@ -18,21 +20,43 @@ import (
"github.com/twpayne/go-polyline"
)

// GenerateSolutions4MultipleCharge generates solutions for multiple charge stations needed from orig to dest based on current energy status
// @todo: handle negative situation
func generateSolutions4MultipleCharge(w http.ResponseWriter, oasisReq *oasis.Request, routeResp *route.Response, oc *osrmconnector.OSRMConnector, finder stationfinder.StationFinder) {
solutions := generateSolutionsWithEarlistArrival(oasisReq, routeResp, oc, finder)
func GenerateSolutions4MultipleCharge(w http.ResponseWriter, oasisReq *oasis.Request, routeResp *route.Response, resourceMgr *ResourceMgr) {
//solutions := generateSolutions4SearchAlongRoute(oasisReq, routeResp, resourceMgr.osrmConnector, resourceMgr.stationFinder)
solutions := generateSolutions4ChargeStationBasedRoute(oasisReq, resourceMgr)

w.WriteHeader(http.StatusOK)
r := new(oasis.Response)
r.Code = "200"
r.Message = "Success."
for _, sol := range solutions {
r.Solutions = append(r.Solutions, sol)
}
r.Solutions = append(r.Solutions, solutions...)
json.NewEncoder(w).Encode(r)
}

func generateSolutionsWithEarlistArrival(oasisReq *oasis.Request, routeResp *route.Response, oc *osrmconnector.OSRMConnector, finder stationfinder.StationFinder) []*oasis.Solution {
func generateSolutions4ChargeStationBasedRoute(oasisReq *oasis.Request, resourceMgr *ResourceMgr) []*oasis.Solution {
targetSolutions := make([]*oasis.Solution, 0, 10)
querier := stationconnquerier.New(resourceMgr.spatialIndexerFinder,
ranker.CreateRanker(ranker.SimpleRanker, resourceMgr.osrmConnector),
resourceMgr.stationLocationQuerier,
resourceMgr.connectivityMap,
&nav.Location{Lat: oasisReq.Coordinates[0].Lat, Lon: oasisReq.Coordinates[0].Lon},
&nav.Location{Lat: oasisReq.Coordinates[1].Lat, Lon: oasisReq.Coordinates[1].Lon},
oasisReq.CurrRange,
oasisReq.MaxRange)
internalSolutions := stationgraph.NewStationGraph(oasisReq.CurrRange, oasisReq.MaxRange,
chargingstrategy.NewFakeChargingStrategy(oasisReq.MaxRange),
querier).GenerateChargeSolutions()

for _, sol := range internalSolutions {
targetSolution := sol.Convert2ExternalSolution()
targetSolutions = append(targetSolutions, targetSolution)
}

return targetSolutions
}

func generateSolutions4SearchAlongRoute(oasisReq *oasis.Request, routeResp *route.Response, oc *osrmconnector.OSRMConnector, finder stationfinder.StationFinder) []*oasis.Solution {
targetSolutions := make([]*oasis.Solution, 0)

chargeLocations := chargeLocationSelection(oasisReq, routeResp)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package oasis
package selectionstrategy

import (
"testing"
Expand All @@ -9,42 +9,42 @@ import (

var fakeRoute1 route.Route = route.Route{
Legs: []*route.Leg{
&route.Leg{
{
Distance: 37386.2,
Steps: []*route.Step{
&route.Step{
{
Distance: 449.5,
Geometry: "y~ecF|_qgVm@@kAJw@RqAf@a@PmBzAqA|Ae@v@a@|@aAzC",
},
&route.Step{
{
Distance: 243,
Geometry: "irfcFdqqgVEp@Ib@MZe@x@k@j@c@R_@Fm@DiBA",
},
&route.Step{
{
Distance: 207.7,
Geometry: "u|fcF|xqgV?zA?xA?h@?j@@tA?hA?h@",
},
&route.Step{
{
Distance: 344.6,
Geometry: "s|fcFrgrgV@h@tKHdA@t@@v@@",
},
&route.Step{
{
Distance: 28988.5,
Geometry: "gjfcFlirgVb@PZHZHj@PRJTJVRRTNXNd@DZ@\\A\\C`@Ih@Ih@Mn@Ot@OfA_@dDShAgA|FQ~@e@bCa@xBq@pDqB|K{@zEw@|Eq@vEO~@ANKr@EZGh@G`@[|Bm@hE_@fCIn@E^EZYpBw@bGM|@_AdHgBzN_@rCa@`CETCPIn@yAxKq@bFy@hGIh@e@fDKx@UbBCRId@Id@G`@}@dHy@tGKp@Kv@UdBIl@k@bEgAnIIt@Ih@Ip@If@YjBa@tCGf@Il@q@zEKv@g@rDuAfKg@xDsA~JyAxKOlAIp@QrAObAOjAKt@Kz@_@tCm@bEYpBUpA_@xBg@xCWtAa@|BYxAIb@AJMx@UtAa@~BUdBQjA_AdHqBhOYvBq@dFc@hDwAdKMz@Ir@Ib@Kt@QvAKp@]xBS~@g@nBIVIZYdAMb@q@bCK^k@jBcA`DcAbDaA`D{@jCQl@KXy@rC_A`Dc@|AOh@g@`Bw@fCK^cAxDSr@cAnDQj@Sn@w@dCu@jBGNiAzB[j@[j@aAdBINGJgAdBc@p@s@bAiAdBeAbBuB`DMPkDpFsCjEe@t@aCpD_@l@Yb@aBdCoAnBOR_AnASVOTGHMPu@jAiAdBm@`A_FzH_CnDqAlBaAvAy@bA_AjAGF_CtCcFlFeBjBkCrC[ZUVu@v@_@^mArAg@h@oCvC_@`@{C~CoArAqArASTqBtBgAjA}@`A{A~Ag@h@YZq@r@gCjCwB|BkDtDcBfBuHdIyA|AkAnAOPsAtAqAtA]^WXWX}@`Ae@f@QPcGnGoApAoCxCeHtHeJrJg@h@qAvA{FdGONMLoDvDs@v@oCzCg@l@w@~@cArAeAzA[f@]l@QXcB|Ci@hAs@zAm@lAs@xAs@xAaBjDeChFiD`HaDjGUb@qBhEsAtC_@t@iBpD[n@wArCwAtCwCjGS`@oCpFoCrFgAxBc@|@cAlBu@vA}@pBs@xAuEjJyAxCgG`MmBzDaAnBc@z@q@rAo@rAsAjCy@`BKXITIPkA|BkAbCeBjD_AjBe@~@y@dBk@fAmBzDqEdJcKpSWh@Sb@kA~BINGLs@vAq@tAwDvHeBlD{@dBmBzDe@`AKRo@tA_@v@Yh@cAnBcApBi@fA_CvEyA|Cm@pAuBlEm@tAu@lBo@|AkAlDABOh@CJCJCHGPADITSr@CJGTENe@dBi@zBw@|D[hBG\\[bB{@dFO~@G`@c@zDUhBQdBO`B]bEC^OxBcAzOiBbZIjAc@bH}@lN{@~MMtBw@bMUxCKpAY~Ck@|EGh@a@xCOfAIf@Id@Ib@Mx@Kn@Q`AG\\G\\Mh@I^Qv@Ml@i@tBW`AYfAQn@i@fBm@pBk@nB_@hAk@fBOd@eArCwBlGo@hBOb@Qf@}@jC_AlCs@tBs@~Bs@zBe@bBUx@U`AW`AU`AUdAU`A[vA[xA]hBId@Id@I`@UdAIl@]jBqC~Ne@bCKh@Kj@Q~@Mj@Kj@a@nBYtAMr@Mh@Oj@e@~Aw@`Cg@pAo@vAgAvBgAlBg@p@s@~@cBrBeE~EmAvAcAjAsA|AwChDiBvB{AhBuFvG{CpDaAhAcF`GeJrKyJhLu@|@ePnR]`@WZoAvAsEpFyFxGg@l@}@dAoAvA_BlByAdBqAzAcE|EoAzAcAjAqEjFyEtF{@bAe@h@",
},
&route.Step{
{
Distance: 467.2,
Geometry: "mx_dFbfgiVcAv@s@j@WV[\\eA`Am@h@]V[R[JYF_@D]@yAG[?W@UDUFSHSLQLc@`@",
},
&route.Step{
{
Distance: 6035.5,
Geometry: "so`dF`sgiVGf@NVR\\RZv@jAZf@LTV^RXl@~@b@r@`@n@TXRV~@dA^^d@b@VRFFTPf@\\BB^VXN`@TRJ\\R`Ah@`@TRJ`@NVLTLd@b@\\`@HJVXNJVLLPNPX^X^RVTVRVTVLPNPNPLPX\\RRLNNRZ^XZd@n@LPZ^DFBDRVr@z@RPZRJDPHXHj@JnATF@h@Jd@PPHd@ZPRPVR^LXNl@@HHr@Bb@Bb@@^B\\JbCBb@D`ADl@Dp@Dn@@XDf@DTHTLZV^JNPRVR\\VFDf@ZLHXNVXb@|@Rx@@DLp@Ln@ZbBXxADPRfAb@zBNv@Jj@FZR~@RpA`@bCLx@Nx@FVP~@^rBZ|AJh@DRf@fCJf@BNJd@RdA?P?DDRDVF`@Jf@FZJf@FZFZLn@FVFXX~AHb@Hb@Pz@Pz@Jd@PbARbALz@BNFd@B`@@f@@z@?~B?R?\\?x@?p@?lC?Z@l@Dz@Dx@?l@A|@Et@Kv@Kh@Md@Ob@MXEHMTQZ]n@KRKROZEHABQf@I\\GVETCNG^En@A`@Ad@@b@Dx@D|@@\\@b@@^@^?j@@dA?\\@f@Ax@A^Cj@Iz@APE`@E`@Gj@Gh@I`AEj@Cj@AnABdAFfAFz@Fl@Fp@BRH|@L~AFl@BVFl@BXDb@HbA^`FHjAz@hKDh@Fr@Ht@Hv@P~AFv@Hx@HfADj@B`@Dr@F|@Bl@Bj@@f@@`A?bAAx@Ez@IhAIx@UfBKx@Gr@UxCUxCCXEl@Eb@C^E`@C`@Gl@KdAGn@",
},
&route.Step{
{
Distance: 650.3,
Geometry: "aq}cFfesiVK^OXQLQDy@@O?OBYLeAr@[N_@Fa@DUAu@IcAOSCe@Em@Ei@?mA@u@Bo@Dg@Jk@Vw@PcAZcA`@KF",
},
&route.Step{
{
Distance: 0,
Geometry: "os~cFvmsiV",
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package oasis
package selectionstrategy

import (
"encoding/json"
Expand All @@ -12,7 +12,6 @@ import (
"github.com/Telenav/osrm-backend/integration/api/search/nearbychargestation"
"github.com/Telenav/osrm-backend/integration/service/oasis/osrmconnector"
"github.com/Telenav/osrm-backend/integration/service/oasis/osrmhelper"
"github.com/Telenav/osrm-backend/integration/service/oasis/stationfinder"
"github.com/Telenav/osrm-backend/integration/service/oasis/stationfinder/stationfinderalg"
"github.com/golang/glog"
)
Expand All @@ -25,14 +24,14 @@ const maxOverlapPointsNum = 500
// The energy level is safeRange + nearest charge station's distance to destination
// If there is one or several charge stations could be found in both origStationsResp and destStationsResp
// We think the result is reachable by single charge station
func getOverlapChargeStations4OrigDest(req *oasis.Request, routedistance float64, osrmConnector *osrmconnector.OSRMConnector, finder stationfinder.StationFinder) osrm.Coordinates {
func GetOverlapChargeStations4OrigDest(req *oasis.Request, routedistance float64, resourceMgr *ResourceMgr) osrm.Coordinates {
// only possible when currRange + maxRange > distance + safeRange
if req.CurrRange+req.MaxRange < routedistance+req.SafeLevel {
return nil
}

origStations := finder.NewOrigStationFinder(req)
destStations := finder.NewDestStationFinder(req)
origStations := resourceMgr.stationFinder.NewOrigStationFinder(req)
destStations := resourceMgr.stationFinder.NewDestStationFinder(req)
overlap := stationfinderalg.FindOverlapBetweenStations(origStations, destStations)

if len(overlap) == 0 {
Expand Down Expand Up @@ -61,9 +60,9 @@ type singleChargeStationCandidate struct {
durationToDest float64
}

// @todo these logic might refactored later: charge station status calculation should be moved away
func generateResponse4SingleChargeStation(w http.ResponseWriter, req *oasis.Request, overlapPoints osrm.Coordinates, osrmConnector *osrmconnector.OSRMConnector) bool {
candidate, err := pickChargeStationWithEarlistArrival(req, overlapPoints, osrmConnector)
// GenerateResponse4SingleChargeStation generates response for only single charge station needed from orig to dest based on current energy status
func GenerateResponse4SingleChargeStation(w http.ResponseWriter, req *oasis.Request, overlapPoints osrm.Coordinates, resourceMgr *ResourceMgr) bool {
candidate, err := pickChargeStationWithEarlistArrival(req, overlapPoints, resourceMgr.osrmConnector)

if err != nil {
w.WriteHeader(http.StatusOK)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package oasis
package selectionstrategy

import (
"testing"
Expand Down
Loading

0 comments on commit e23ecc6

Please sign in to comment.