Skip to content

Commit

Permalink
fix #16326
Browse files Browse the repository at this point in the history
  • Loading branch information
namdre committed Mar 12, 2025
1 parent eca6872 commit 92f4012
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
44 changes: 41 additions & 3 deletions tools/import/gtfs/gtfs2pt.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import subprocess
import collections
import zipfile
import rtree
import pandas as pd
pd.options.mode.chained_assignment = None # default='warn'

Expand All @@ -38,6 +39,7 @@
import route2poly # noqa
import sumolib # noqa
from sumolib.miscutils import humanReadableTime # noqa
from sumolib.net import lane2edge # noqa
import tracemapper # noqa

import gtfs2fcd # noqa
Expand Down Expand Up @@ -67,6 +69,8 @@ def get_options(args=None):
help="do not create access links")
ap.add_argument("--sort", action="store_true", default=False, category="processing",
help="sorting the output-file")
ap.add_argument("--stops", category="input", type=ap.file,
help="file with candidate stops (selected by proxmity)")
ap.add_argument("--patched-stops", category="input", dest="patchedStops", type=ap.file,
help="file with replacement stops (based on stop ids)")
ap.add_argument("-H", "--human-readable-time", category="output", dest="hrtime", default=False, action="store_true",
Expand Down Expand Up @@ -203,7 +207,7 @@ def mapFCD(options, typedNets):
subprocess.call(call, shell=True)


def traceMap(options, typedNets, fixedStops, invEdgeMap, radius=150):
def traceMap(options, typedNets, fixedStops, stopLookup, invEdgeMap, radius=150):
routes = collections.OrderedDict()
for mode in sorted(typedNets.keys()):
if options.verbose:
Expand All @@ -221,10 +225,15 @@ def traceMap(options, typedNets, fixedStops, invEdgeMap, radius=150):
if (minX < netBox[1][0] + radius and minY < netBox[1][1] + radius and
maxX > netBox[0][0] - radius and maxY > netBox[0][1] - radius):
vias = {}
if stopLookup.hasCandidates():
for idx, xy in enumerate(trace):
candidates = stopLookup.getCandidates(xy)
if candidates:
vias[idx] = [invEdgeMap[lane2edge(stop.lane)] for stop in candidates]
for idx in range(len(trace)):
fixed = fixedStops.get("%s.%s" % (tid, idx))
if fixed:
vias[idx] = invEdgeMap[fixed.lane[:fixed.lane.rfind("_")]]
vias[idx] = [invEdgeMap[lane2edge(fixed.lane)]]
mappedRoute = sumolib.route.mapTrace(trace, net, radius, verbose=options.verbose,
fillGaps=options.fill_gaps, gapPenalty=5000., vias=vias,
reversalPenalty=1000.)
Expand Down Expand Up @@ -382,6 +391,34 @@ def filter_trips(options, routes, stops, outf, begin, end):
outf.write(vehs)


class StopLookup:
def __init__(self, fname, net):
self._candidates = []
self._net = net
self._rtree = rtree.index.Index()
if fname:
self._candidates = list(sumolib.xml.parse(fname, ("busStop", "trainStop")))
for ri, stop in enumerate(self._candidates):
lane = net.getLane(stop.lane)
middle = (float(stop.startPos) + float(stop.endPos)) / 2
x, y = sumolib.geomhelper.positionAtShapeOffset(lane.getShape(), middle)
bbox = (x - 1, y - 1, x + 1, y + 1)
self._rtree.add(ri, bbox)

def hasCandidates(self):
return len(self._candidates) > 0

def getCandidates(self, xy, r=150):
if self._candidates:
stops = []
x, y = xy
for i in self._rtree.intersection((x - r, y - r, x + r, y + r)):
stops.append(self._candidates[i])
return stops
else:
return []


def main(options):
if options.verbose:
print('Loading net')
Expand All @@ -393,6 +430,7 @@ def main(options):
else:
options.bbox = [float(coord) for coord in options.bbox.split(",")]
fixedStops = {}
stopLookup = StopLookup(options.stops, net)
if options.patchedStops:
for stop in sumolib.xml.parse(options.patchedStops, ("busStop", "trainStop")):
fixedStops[stop.id] = stop
Expand Down Expand Up @@ -445,7 +483,7 @@ def main(options):
return
if options.mapperlib != "tracemapper":
print("Warning! No mapping library found, falling back to tracemapper.", file=sys.stderr)
routes = traceMap(options, typedNets, fixedStops, invEdgeMap)
routes = traceMap(options, typedNets, fixedStops, stopLookup, invEdgeMap)

if options.poly_output:
generate_polygons(net, routes, options.poly_output)
Expand Down
4 changes: 4 additions & 0 deletions tools/sumolib/net/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,10 @@ def convertShape(shapeString):
return cshape


def lane2edge(laneID):
return laneID[:laneID.rfind("_")]


def readNet(filename, **others):
""" load a .net.xml file
The following named options are supported:
Expand Down
11 changes: 6 additions & 5 deletions tools/sumolib/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@ def mapTrace(trace, net, delta, verbose=False, airDistFactor=2, fillGaps=0, gapP
for idx, pos in enumerate(trace):
newPaths = {}
if vias and idx in vias:
if net.hasEdge(vias[idx]):
candidates = [(net.getEdge(vias[idx]), 0.)]
else:
print("Unknown via edge %s for %s,%s" % (vias[idx], pos[0], pos[1]))
candidates = []
candidates = []
for edgeID in vias[idx]:
if net.hasEdge(edgeID):
candidates.append((net.getEdge(edgeID), 0.))
else:
print("Unknown via edge %s for %s,%s" % (edgeID, pos[0], pos[1]))
else:
candidates = net.getNeighboringEdges(pos[0], pos[1], delta, not net.hasInternal)
if debug:
Expand Down

0 comments on commit 92f4012

Please sign in to comment.