Skip to content

Commit

Permalink
Completed conversion to new graph generation technique.
Browse files Browse the repository at this point in the history
  • Loading branch information
jteresco committed Jun 26, 2016
1 parent 3b40d24 commit 353b099
Showing 1 changed file with 137 additions and 120 deletions.
257 changes: 137 additions & 120 deletions siteupdate/python-teresco/siteupdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,6 @@ def length(self):
def set_segment_name(self):
"""compute and set a segment name based on names of all
concurrent routes, used for graph edge labels"""
# hate to use a global here, maybe fix later
self.segment_name = ""
if self.concurrent is None:
if self.route.system.active_or_preview():
Expand All @@ -448,6 +447,22 @@ def gra_line(self):
line += str(self.waypoint2.colocated[0].vertex_num) + ' '
line += self.segment_name
return line

def edge_line_with_labels(self):
"""compute the line that should represent this segment in an
alternate format for a potential future graph file format
(2 waypoint labels, edge label)"""
line = ""
if self.waypoint1.colocated is None:
line += str(self.waypoint1.unique_name) + ' '
else:
line += str(self.waypoint1.colocated[0].unique_name) + ' '
if self.waypoint2.colocated is None:
line += str(self.waypoint2.unique_name) + ' '
else:
line += str(self.waypoint2.colocated[0].unique_name) + ' '
line += self.segment_name
return line

class Route:
"""This class encapsulates the contents of one .csv file line
Expand Down Expand Up @@ -534,7 +549,7 @@ def read_wpt(self,all_waypoints,path="../../../HighwayData/hwy_data"):
other_w.colocated.append(w)
w.colocated = other_w.colocated
if w.is_hidden != other_w.is_hidden:
print("\nERROR: hidden waypoint colocated with visible, " + str(w) + " and " + str(other_w))
print("\nWARNING: hidden waypoint colocated with visible, " + str(w) + " and " + str(other_w))
#print("New colocation found: " + str(w) + " with " + str(other_w))
all_waypoints.insert(w)
# add HighwaySegment, if not first point
Expand Down Expand Up @@ -899,6 +914,7 @@ class HighwayGraphVertexInfo:
def __init__(self,waypoint_list):
self.lat = waypoint_list[0].lat
self.lng = waypoint_list[0].lng
self.unique_name = waypoint_list[0].unique_name
self.is_hidden = waypoint_list[0].is_hidden
self.regions = set()
self.systems = set()
Expand All @@ -907,12 +923,18 @@ def __init__(self,waypoint_list):
self.systems.add(w.route.system)
self.incident_edges = []

# printable string
def __str__(self):
return self.unique_name

class HighwayGraphEdgeInfo:
"""This class encapsulates information needed for a highway graph
edge.
"""

def __init__(self,s,graph):
# temp debug
self.written = False
self.segment_name = s.segment_name
self.vertex1 = graph.vertices[s.waypoint1.unique_name]
self.vertex2 = graph.vertices[s.waypoint2.unique_name]
Expand All @@ -928,9 +950,36 @@ def __init__(self,s,graph):
continue
self.route_names_and_systems.append((cs.route.list_entry_name(), cs.route.system))

graph.vertices[s.waypoint1.unique_name].incident_edges.append(self)
graph.vertices[s.waypoint2.unique_name].incident_edges.append(self)
# checks for the very unusual cases where an edge ends up
# in the system as itself and its "reverse"
duplicate = False
for e in graph.vertices[s.waypoint1.unique_name].incident_edges:
if e.vertex1 == self.vertex2 and e.vertex2 == self.vertex1:
duplicate = True

for e in graph.vertices[s.waypoint2.unique_name].incident_edges:
if e.vertex1 == self.vertex2 and e.vertex2 == self.vertex1:
duplicate = True

if not duplicate:
graph.vertices[s.waypoint1.unique_name].incident_edges.append(self)
graph.vertices[s.waypoint2.unique_name].incident_edges.append(self)

# compute an edge label, optionally resticted by systems
def label(self,systems=None):
the_label = ""
for (name, system) in self.route_names_and_systems:
if systems is None or system in systems:
if the_label == "":
the_label = name
else:
the_label += ","+name

return the_label

# printable string for this edge
def __str__(self):
return "HighwayGraphEdgeInfo: " + self.segment_name + " from " + str(self.vertex1) + " to " + str(self.vertex2)

class HighwayGraph:
"""This class implements the capability to create graph
Expand Down Expand Up @@ -1069,140 +1118,108 @@ def edge_count(self):
edges += len(v.incident_edges)
return edges//2

def matching_waypoint(self, label, vinfo, regions=None, systems=None):
# determine if the vertex list entry given in label and vinfo
# belongs in the subset restricted by the listed regions and/or
# systems
region_match = regions is None
if not region_match:
for r in regions:
if r in vinfo.regions:
region_match = True
system_match = systems is None
if not system_match:
for s in systems:
if s in vinfo.systems:
system_match = True
return region_match and system_match


def num_matching_waypoints(self, regions=None, systems=None):
# count up the waypoints in or colocated in the system(s)
# and/or regions(s)
matching_waypoints = 0
for label, vinfo in self.vertices.items():
if self.matching_waypoint(label, vinfo, regions, systems):
matching_waypoints += 1

return matching_waypoints

def matching_edges(self, regions=None, systems=None):
# return a set of edges from the graph, optionally
# restricted by region or system
edge_set = set()
for v in self.vertices.values():
for e in v.incident_edges:
if regions is None or e.region in regions:
system_match = systems is None
if not system_match:
for (r, s) in e.route_names_and_systems:
if s in systems:
system_match = True
if system_match:
edge_set.add(e)

return edge_set

def write_master_gra(self,filename):
grafile = open(filename, 'w')
grafile.write(str(len(self.unique_waypoints)) + ' ' +
str(self.unique_edges) + '\n')
grafile.write(str(len(self.vertices)) + ' ' + str(self.edge_count()) + '\n')
# number waypoint entries as we go to support original .gra
# format output
vertex_num = 0
for label, pointlist in self.unique_waypoints.items():
grafile.write(label + ' ' + str(pointlist[0].lat) + ' ' + str(pointlist[0].lng) + '\n')
pointlist[0].vertex_num = vertex_num
for label, vinfo in self.vertices.items():
grafile.write(label + ' ' + str(vinfo.lat) + ' ' + str(vinfo.lng) + '\n')
vinfo.vertex_num = vertex_num
vertex_num += 1

# visit unique segments as edges
for h in self.highway_systems:
if h.devel():
continue
for r in h.route_list:
for s in r.segment_list:
if s.segment_name is not None:
grafile.write(s.gra_line() + '\n')
# sanity check
if len(self.vertices) != vertex_num:
print("ERROR: computed " + str(len(self.vertices)) + " waypoints but wrote " + str(vertex_num))

# now edges, only print if not already printed
edge = 0
for v in self.vertices.values():
for e in v.incident_edges:
if not e.written:
e.written = True
grafile.write(str(e.vertex1.vertex_num) + ' ' + str(e.vertex2.vertex_num) + ' ' + e.label() + '\n')
edge += 1

# sanity checks
for v in self.vertices.values():
for e in v.incident_edges:
if not e.written:
print("ERROR: never wrote edge " + str(e.vertex1.vertex_num) + ' ' + str(e.vertex2.vertex_num) + ' ' + e.label() + '\n')
if self.edge_count() != edge:
print("ERROR: computed " + str(self.edge_count()) + " edges but wrote " + str(edge))

grafile.close()

def write_subgraph_gra(self,filename,regions,systems):
grafile = open(filename, 'w')

# count up the waypoints in or colocated in the system(s)
# and/or regions(s)
matching_waypoints = 0
for label, pointlist in self.unique_waypoints.items():
for w in pointlist:
if (regions is None or w.route.region in regions) and \
(systems is None or w.route.system in systems):
matching_waypoints += 1
break

# count up the segments that are in or colocated in the
# system(s) and/or region(s)
matching_segments = 0
for h in self.highway_systems:
if h.devel():
continue
if systems is not None and h not in systems:
continue
for route in h.route_list:
if regions is None or route.region in regions:
for s in route.segment_list:
if s.segment_name is not None:
# always count if we have the name
matching_segments += 1

elif systems is not None:
# If we don't have the name, might need to
# count anyway, if the name is attached to
# a segment not in our system. But make
# sure we only count it once, and do so by
# counting only if this route's segment is
# the first in the list from included systems
in_sys_count = 0
first_in_sys = False
named_in_sys = False
for cs in s.concurrent:
if cs.route.system in systems:
if in_sys_count == 0:
first_in_sys = True
if cs.segment_name is not None:
named_in_sys = True
in_sys_count += 1
#print("Does not have segment name, in_sys_count = " + str(in_sys_count) + ", first_in_sys = " + str(first_in_sys) + ", named_in_sys = " + str(named_in_sys))
if not named_in_sys and first_in_sys:
#print("Does not have segment name but counting")
matching_segments += 1


print('(' + str(matching_waypoints) + ',' + str(matching_segments) + ') ', end="", flush=True)
grafile = open(filename, 'w')
matching_edges = self.matching_edges(regions, systems)
print('(' + str(self.num_matching_waypoints(regions, systems)) + ',' + str(len(matching_edges)) + ') ', end="", flush=True)
# ready to write the header
grafile.write(str(matching_waypoints) + ' ' + str(matching_segments) + '\n')
grafile.write(str(self.num_matching_waypoints(regions, systems)) + ' ' + str(len(matching_edges)) + '\n')

# write waypoint/vertex data
# write waypoints
vertex_num = 0
for label, pointlist in graph_data.unique_waypoints.items():
for w in pointlist:
if (regions is None or w.route.region in regions) and \
(systems is None or w.route.system in systems):
grafile.write(label + ' ' + str(pointlist[0].lat) + ' ' + str(pointlist[0].lng) + '\n')
pointlist[0].vertex_num = vertex_num
vertex_num += 1
break
# sanity check
if matching_waypoints != vertex_num:
print("ERROR: computed " + str(matching_waypoints) + " waypoints but wrote " + str(vertex_num))


# write edge data
edge_num = 0
for h in self.highway_systems:
if h.devel():
continue
if systems is not None and h not in systems:
continue
for route in h.route_list:
if regions is None or route.region in regions:
for s in route.segment_list:
if s.segment_name is not None:
edge_num += 1
grafile.write(s.gra_line() + '\n')
elif systems is not None:
# similar check as above in case we're
# responsible for writing even though not
# the "owner" by having the segment name
in_sys_count = 0
first_in_sys = False
named_in_sys = False
cs_with_name = None
for cs in s.concurrent:
if cs.route.system in systems:
if in_sys_count == 0:
first_in_sys = True
if cs.segment_name is not None:
named_in_sys = True
in_sys_count += 1
if cs.segment_name is not None:
cs_with_name = cs
if not named_in_sys and first_in_sys:
edge_num += 1
grafile.write(cs_with_name.gra_line() + '\n')

# sanity check on number of edges
if matching_segments != edge_num:
print("ERROR: computed " + str(matching_segments) + " edges but wrote " + str(edge_num))
for label, vinfo in self.vertices.items():
if self.matching_waypoint(label, vinfo, regions, systems):
grafile.write(label + ' ' + str(vinfo.lat) + ' ' + str(vinfo.lng) + '\n')
vinfo.vertex_num = vertex_num
vertex_num += 1

# write edges
edge = 0
for e in matching_edges:
grafile.write(str(e.vertex1.vertex_num) + ' ' + str(e.vertex2.vertex_num) + ' ' + e.label(systems) + '\n')
edge += 1

grafile.close()

def format_clinched_mi(clinched,total):
"""return a nicely-formatted string for a given number of miles
clinched and total miles, including percentage"""
Expand Down

0 comments on commit 353b099

Please sign in to comment.