in libs/apls/osmnx_funcs.py [0:0]
def is_endpoint(G, node, strict=True):
"""
Return True if the node is a "real" endpoint of an edge in the network, \
otherwise False. OSM data includes lots of nodes that exist only as points \
to help streets bend around curves. An end point is a node that either: \
1) is its own neighbor, ie, it self-loops. \
2) or, has no incoming edges or no outgoing edges, ie, all its incident \
edges point inward or all its incident edges point outward. \
3) or, it does not have exactly two neighbors and degree of 2 or 4. \
4) or, if strict mode is false, if its edges have different OSM IDs. \
Parameters
----------
G : networkx multidigraph
node : int
the node to examine
strict : bool
if False, allow nodes to be end points even if they fail all other rules \
but have edges with different OSM IDs
Returns
-------
bool
"""
neighbors = set(list(G.predecessors(node)) + list(G.successors(node)))
n = len(neighbors)
d = G.degree(node)
if node in neighbors:
# if the node appears in its list of neighbors, it self-loops. this is
# always an endpoint.
return True
# if node has no incoming edges or no outgoing edges, it must be an endpoint
elif G.out_degree(node)==0 or G.in_degree(node)==0:
return True
elif not (n==2 and (d==2 or d==4)):
# else, if it does NOT have 2 neighbors AND either 2 or 4 directed
# edges, it is an endpoint. either it has 1 or 3+ neighbors, in which
# case it is a dead-end or an intersection of multiple streets or it has
# 2 neighbors but 3 degree (indicating a change from oneway to twoway)
# or more than 4 degree (indicating a parallel edge) and thus is an
# endpoint
return True
elif not strict:
# non-strict mode
osmids = []
# add all the edge OSM IDs for incoming edges
for u in G.predecessors(node):
for key in G[u][node]:
osmids.append(G.edges[u, node, key]['osmid'])
# add all the edge OSM IDs for outgoing edges
for v in G.successors(node):
for key in G[node][v]:
osmids.append(G.edges[node, v, key]['osmid'])
# if there is more than 1 OSM ID in the list of edge OSM IDs then it is
# an endpoint, if not, it isn't
return len(set(osmids)) > 1
else:
# if none of the preceding rules returned true, then it is not an endpoint
return False