If it were me, I would run the network through a TopologyBuilder and then use a PythonCaller to run a DepthFirstSearch.
Using strictly regular transformers, I would try the ShortestPathFinder, cloning your stat point and making from-to lines for ever end point.
If it were me, I would run the network through a TopologyBuilder and then use a PythonCaller to run a DepthFirstSearch.
Using strictly regular transformers, I would try the ShortestPathFinder, cloning your stat point and making from-to lines for ever end point.
honestly,i was trying to do it by looping but i did not success but i will try ur suggestion but about shortestpathfinder ,i was thinking about it but the problem i want to do it by unknown lines with different id not i define for each line which point will be the start and the end . thanks for reply
honestly,i was trying to do it by looping but i did not success but i will try ur suggestion but about shortestpathfinder ,i was thinking about it but the problem i want to do it by unknown lines with different id not i define for each line which point will be the start and the end . thanks for reply
I don't have a script for exactly what you want to do. A DFS requires the data to be in a graph. The following code sets up a weighted graph and has a method for DFS, but you would have to adapt the close method of the FeatureProcessor to output what you want.
Note that the edge port of the topologyBuider should be connected to the python caller.
Also note that you probably don't care about edge weights and can simplify the code to remove them.
Third note, this arbitrarily assigns the first node as the start node, presumably your data has some way of indicating which is the start node.
import fme
import fmeobjects
# Graph class structure adapted from http://www.bogotobogo.com/python/python_graph_data_structures.php
class Vertex:
def __init__(self, node):
self.id = node
self.adjacent = {}
def __str__(self):
return str(self.id) + ':'+str([x.id for x in self.adjacent])
def add_neighbor(self, neighbor, weight=0, edgeID=0):
self.adjacent[neighbor.id] = (edgeID,weight)
def get_connections(self):
return self.adjacent.keys()
def get_id(self):
return self.id
def get_weight(self, neighbor):
return self.adjacent[neighbor][1]
def get_edgeID(self, neighbor):
return self.adjacent[neighbor][0]
class Graph:
def __init__(self):
self.vert_dict = {}
self.num_vertices = 0
def __iter__(self):
return iter(self.vert_dict.values())
def add_vertex(self, node):
self.num_vertices = self.num_vertices + 1
new_vertex = Vertex(node)
self.vert_dict[node] = new_vertex
return new_vertex
def get_vertex(self, n):
if n in self.vert_dict:
return self.vert_dict[n]
else:
return None
def add_edge(self, frm, to, cost = 0, edgeID=0):
if frm not in self.vert_dict:
self.add_vertex(frm)
if to not in self.vert_dict:
self.add_vertex(to)
self.vert_dict[frm].add_neighbor(self.vert_dict[to], cost, edgeID)
self.vert_dict[to].add_neighbor(self.vert_dict[frm], cost, edgeID)
def get_vertices(self):
return self.vert_dict.keys()
def DFS(G,v,seen=None,path=None, cost=None):
if seen is None: seen = []
if path is None:
path = []
if cost is None:
cost = 0
seen.append(v)
paths = []
w = G.get_vertex(v)
for s in w.get_connections():
c = w.get_weight(s)
eID = w.get_edgeID(s)
if s not in seen:
s_path = path + [eID]
s_cost = cost + c
paths.append(((s_path), s_cost, s))
paths.extend(DFS(G, s, seen, s_path, s_cost))
return paths
class FeatureProcessor(object):
def __init__(self):
self.graph = Graph()
self.featureList =[]
def input(self,feature):
#get the nodes and id of the edge
arcID = feature.getAttribute('_edge_id')
fN = feature.getAttribute('_from_node')
tN = feature.getAttribute('_to_node')
#calculate the length of the edge
length = feature.getGeometry().getLength(False)
#add them to the graph
self.graph.add_edge(fN,tN,length, arcID)
#add feature to featureList
self.featureList.append(feature)
def close(self):
sV = self.graph.get_vertices()[0]
paths = DFS(self.graph, sV)
I don't have a script for exactly what you want to do. A DFS requires the data to be in a graph. The following code sets up a weighted graph and has a method for DFS, but you would have to adapt the close method of the FeatureProcessor to output what you want.
Note that the edge port of the topologyBuider should be connected to the python caller.
Also note that you probably don't care about edge weights and can simplify the code to remove them.
Third note, this arbitrarily assigns the first node as the start node, presumably your data has some way of indicating which is the start node.
import fme
import fmeobjects
# Graph class structure adapted from http://www.bogotobogo.com/python/python_graph_data_structures.php
class Vertex:
def __init__(self, node):
self.id = node
self.adjacent = {}
def __str__(self):
return str(self.id) + ':'+str([x.id for x in self.adjacent])
def add_neighbor(self, neighbor, weight=0, edgeID=0):
self.adjacent[neighbor.id] = (edgeID,weight)
def get_connections(self):
return self.adjacent.keys()
def get_id(self):
return self.id
def get_weight(self, neighbor):
return self.adjacent[neighbor][1]
def get_edgeID(self, neighbor):
return self.adjacent[neighbor][0]
class Graph:
def __init__(self):
self.vert_dict = {}
self.num_vertices = 0
def __iter__(self):
return iter(self.vert_dict.values())
def add_vertex(self, node):
self.num_vertices = self.num_vertices + 1
new_vertex = Vertex(node)
self.vert_dict[node] = new_vertex
return new_vertex
def get_vertex(self, n):
if n in self.vert_dict:
return self.vert_dict[n]
else:
return None
def add_edge(self, frm, to, cost = 0, edgeID=0):
if frm not in self.vert_dict:
self.add_vertex(frm)
if to not in self.vert_dict:
self.add_vertex(to)
self.vert_dict[frm].add_neighbor(self.vert_dict[to], cost, edgeID)
self.vert_dict[to].add_neighbor(self.vert_dict[frm], cost, edgeID)
def get_vertices(self):
return self.vert_dict.keys()
def DFS(G,v,seen=None,path=None, cost=None):
if seen is None: seen = []
if path is None:
path = []
if cost is None:
cost = 0
seen.append(v)
paths = []
w = G.get_vertex(v)
for s in w.get_connections():
c = w.get_weight(s)
eID = w.get_edgeID(s)
if s not in seen:
s_path = path + [eID]
s_cost = cost + c
paths.append(((s_path), s_cost, s))
paths.extend(DFS(G, s, seen, s_path, s_cost))
return paths
class FeatureProcessor(object):
def __init__(self):
self.graph = Graph()
self.featureList =[]
def input(self,feature):
#get the nodes and id of the edge
arcID = feature.getAttribute('_edge_id')
fN = feature.getAttribute('_from_node')
tN = feature.getAttribute('_to_node')
#calculate the length of the edge
length = feature.getGeometry().getLength(False)
#add them to the graph
self.graph.add_edge(fN,tN,length, arcID)
#add feature to featureList
self.featureList.append(feature)
def close(self):
sV = self.graph.get_vertices()[0]
paths = DFS(self.graph, sV)
it will be nice,if u have example for this script pf python caller in fme ,i want to see how it looks like the result inside FME
where should i write my start node .Thanks for helping
If it were me, I would run the network through a TopologyBuilder and then use a PythonCaller to run a DepthFirstSearch.
Using strictly regular transformers, I would try the ShortestPathFinder, cloning your stat point and making from-to lines for ever end point.
Similarly, for a recent project the solution was ShortestPathFinder for an identical problem.
This performs network/graph tracing quite effectively:
- Remove all the non-intersection intermediate line vertices with VertexRemover as don't want their vertex coordinates in the final path result.
- Create an unconstrained join between all Start and End Nodes to return groups of StartNodeID and EndNodeID
- Create To-From Lines with these Point pairs and feed these into ShortestPathFinder, which will return Path Features. Path features are a collection of all the individual path segment features and their vertices
- Rationalise these to single polylines using GeometryRefiner which will orient all the path segments in the correct direction.
- Return all the path vertices from Start to End Point with CoordinateExtractor. This will return all path point coordinates in order from start to end of the path.
Similarly, for a recent project the solution was ShortestPathFinder for an identical problem.
This performs network/graph tracing quite effectively:
- Remove all the non-intersection intermediate line vertices with VertexRemover as don't want their vertex coordinates in the final path result.
- Create an unconstrained join between all Start and End Nodes to return groups of StartNodeID and EndNodeID
- Create To-From Lines with these Point pairs and feed these into ShortestPathFinder, which will return Path Features. Path features are a collection of all the individual path segment features and their vertices
- Rationalise these to single polylines using GeometryRefiner which will orient all the path segments in the correct direction.
- Return all the path vertices from Start to End Point with CoordinateExtractor. This will return all path point coordinates in order from start to end of the path.
could i ask ,
Create an unconstrained join between all Start and End Nodes to return groups of StartNodeID and EndNodeID
please,could you explain more ,i did not get this step
and also what u mean in this step Create To-From Lines with these Point pairs .
which transformers are doing theses steps
i need at the end each line id and if did vertex remover so the lines are intersected will be one line and may be get new id but i need the original id or each line,is it possible
Thanks alot for helping
Hi @gogopotter90, here is my attempt at it with ShortestPathFinder:

Not sure how your input lines look like, but the idea here is to identify the end nodes from the number of occurrence of the vertices - if they are intersection points, the occurrence would be more than once. This would only work if each line has only begin and end nodes, not any vertices in the middle. To ensure that the first Chopper is used to break down the line segments. The resulted paths from ShortestPathFinder contains all the segments with begin and end node coordinates.
I've also attached the workspace and a shapefile for the sample data. Hope this helps.
Hi @gogopotter90, here is my attempt at it with ShortestPathFinder:

Not sure how your input lines look like, but the idea here is to identify the end nodes from the number of occurrence of the vertices - if they are intersection points, the occurrence would be more than once. This would only work if each line has only begin and end nodes, not any vertices in the middle. To ensure that the first Chopper is used to break down the line segments. The resulted paths from ShortestPathFinder contains all the segments with begin and end node coordinates.
I've also attached the workspace and a shapefile for the sample data. Hope this helps.
sry for that i like ur idea but iam using fme 2018 so iam not able to open it .could u provide me with version 2018.Thanks alot
sry for that i like ur idea but iam using fme 2018 so iam not able to open it .could u provide me with version 2018.Thanks alot
Sorry for the delayed response. Please see attached workspace recreated in 2018 version. PathFinder_2018.fmwI noticed the LineBuilder in this version (Build 18283) didn't have GroupBy function, so I added a FeatureHolder and a Sorter so that the From/To Lines were created with correct pairs of start/end nodes (i.e. start and end nodes have the same _count number).
Sorry for the delayed response. Please see attached workspace recreated in 2018 version. PathFinder_2018.fmwI noticed the LineBuilder in this version (Build 18283) didn't have GroupBy function, so I added a FeatureHolder and a Sorter so that the From/To Lines were created with correct pairs of start/end nodes (i.e. start and end nodes have the same _count number).
could i ask if i have area between lines ,which transformers suggested u to continue following the path .Thanks alot for upload another version
could i ask if i have area between lines ,which transformers suggested u to continue following the path .Thanks alot for upload another version
Could you give a bit more details (or an example if that's easier) on your case? By having area between lines, does that mean the input data has mixed geometry of polygons and line segments? If so, the Chopper could still work to break down the polygon into its exterior lines (Mode: By Vertex, Maximum Vertices: 2).