Reputation: 165
I have a list of line segments, each with x and y coordinates of their "from" and "to" points, as seen below (example below is truncated, it's quite long).
[
{'f': {'x': 15.0, 'y': -5.0}, 't': {'x': 16.0, 'y': -5.0}},
{'f': {'x': 3.0, 'y': -7.0}, 't': {'x': 5.0, 'y': -7.0}},
{'f': {'x': 9.0, 'y': -7.0}, 't': {'x': 10.0, 'y': -7.0}},
{'f': {'x': 10.0, 'y': -4.0}, 't': {'x': 10.0, 'y': -5.0}},
{'f': {'x': 9.0, 'y': -4.0}, 't': {'x': 10.0, 'y': -4.0}},
{'f': {'x': 4.0, 'y': -4.0}, 't': {'x': 5.0, 'y': -4.0}},
...
]
I also have a function, lines_connected
, which takes two of these list items (lines) as its a
and b
parameters, and returns True
if the end of either line is on some part of the other (but False
if they just intersect without one ending at the other, or if they don't "touch" at all). Using this, I need to find all groups (presumably as lists within a list) of lines which "connect" as described above. Not every line within a group is necessarily connected directly to every other line, but they are connected via other lines in the group.
What is the best way to group these lines into these "connected groups"?
Upvotes: 2
Views: 702
Reputation: 114578
This is a graph problem. You can convert your list into a networkx graph pretty easily, with your endpoints being the nodes and segments being edges:
import networkx as nx
def to_xy(p, key='f'):
d = p[key]
return (d['x'], d['y'])
segments = [...]
g = nx.Graph()
for seg in segments:
g.add_edge(to_xy(seg, 'f'), to_xy(seg, 't'), obj=seg)
For reference, I've added an obj
attribute to each edge, which points to the original dict used to construct it.
Now to get the groups, all you have to do is get the connected components of the graph: The edges within each component will be interconnected segments. These can be obtained according to the description of the deprecated connected_component_subgraphs
method:
components = map(g.subgraph, nx.connected_components(g))
edges = [list(nx.get_edge_attributes(sg, 'obj').values()) for sg in components]
To check if any two points are connected somehow, just check if there's a path from the starting point of one to the other, as here:
nx.has_path(g, to_xy(s1), to_xy(s2))
It does not matter if you use f
or t
for the endpoints.
Upvotes: 1
Reputation: 1321
One way of doing this would be to use a network based approach. You could use networkx for this.
In this setup each line segment would be a node and the output of lines_connected
will determine whether there is an edge between them or not. So, if lines_connected
spits out True for any two segments a
and b
then you can create an edge between two nodes. Else you don't.
Finally you get the "connected groups" by using connected subcomponent graphs as in
import networkx as nx
#G would be your Node-Edge Graph created with line segments and the outuput of lines_connected
sub_graphs = nx.connected_component_subgraphs(G)
Upvotes: 2