Skip to main content
Solved

Trace the path of line and extract the id for each line then repeat from start point and start again to the next path in the map....


gogopotter90
Contributor
Forum|alt.badge.img+13

 

i have network of many lines in the map and i want to define start point from one line of different lines then i want to flow in each direction till the end as picture above

start point will start then go in the first direction but it will find first intersection point with 3 directon so go one by one as example then it finds second intersection point with 3 direction then fo in first line till reach end line 1 and give me the coordinate of the last point (last vertices 1 )

 

then come bk to second intersection point and continue in the second line but it finds the third intersection point so go till end line 2 and extract vertices then come bk to third intersection point and go to end line 3 and extract vertices then come bk to second intersection point and go to last direct ion till end line 4 and give me coordintaes of last point and after finish it return back to the first intersection point and till reach end line 5 and so on .

 

at the end i want to check the end coordinates of each last line and extract the id for the whole path from start point till end line 1 and from start point till end line 2 and so on for each path as possible .

 

i was thinking alot but i am still not sure how can i apply it , i hope if someone suggests ideas and which transformers should i use to do it .

My FME version 2018

Thanks alot

 

Best answer by alyssaatsafe

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.

View original
Did this help you find an answer to your question?

11 replies

jdh
Contributor
Forum|alt.badge.img+28
  • Contributor
  • February 10, 2020

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.

gogopotter90
Contributor
Forum|alt.badge.img+13
  • Author
  • Contributor
  • February 10, 2020
jdh wrote:

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


jdh
Contributor
Forum|alt.badge.img+28
  • Contributor
  • February 10, 2020
gogopotter90 wrote:

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)

gogopotter90
Contributor
Forum|alt.badge.img+13
  • Author
  • Contributor
  • February 11, 2020
jdh wrote:

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


bwn
Evangelist
Forum|alt.badge.img+26
  • Evangelist
  • February 11, 2020
jdh wrote:

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.

gogopotter90
Contributor
Forum|alt.badge.img+13
  • Author
  • Contributor
  • February 11, 2020
bwn wrote:

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


  • Best Answer
  • February 18, 2020

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.


gogopotter90
Contributor
Forum|alt.badge.img+13
  • Author
  • Contributor
  • February 22, 2020
alyssaatsafe wrote:

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


gogopotter90 wrote:

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).


gogopotter90
Contributor
Forum|alt.badge.img+13
  • Author
  • Contributor
  • February 25, 2020
alyssaatsafe wrote:

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


gogopotter90 wrote:

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).


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings