Network_find_cycles

After updating COMPAS to the version 15.1 today, “network_find_cycles” gives me the following error:

network_find_cycles(network)
File “C:\Users\msalma\Documents\compas-dev\compas\src\compas\datastructures\network\duality.py”, line 64, in network_find_cycles
u = sorted(network.nodes(True), key=lambda x: (x[1][1], x[1][0]))[0][0]
File “C:\Users\msalma\Documents\compas-dev\compas\src\compas\datastructures\network\duality.py”, line 64, in
u = sorted(network.nodes(True), key=lambda x: (x[1][1], x[1][0]))[0][0]
KeyError: 1

Before updating I used to do the following, and it was working:

mesh=Mesh.from_data(network.to_data())
mesh.halfedge=network.halfedge
network_find_faces(mesh)

this indeed will not work anymore.
can you give me a bit more info about what you are trying to do?

I have the following network for example and I want to find its cycles (faces):

I thought replacing the previous three lines with only “network_find_cycles(network)” would give me the same result! But I get the mentioned error.

the old use of network_find_cycles was a bit of a hack and therefore is no longer supported.
in this case, something along the lines of the following should work.

network = Network.from_lines(lines)
points = network.to_points()
cycles = network_find_cycles(network)
mesh = Mesh.from_vertices_and_faces(points, cycles)
mesh.delete_face(0)  # if you don't want the "outside" face to exist

that said, it seems that there is still a bug in the version of the code for network_find_cycles you have. perhaps i fixed it after releasing. try updating to the latest repo changes.

the part of the code that gave you an error should read

u = sorted(network.nodes(True), key=lambda x: (x[1]['y'], x[1]['x']))[0][0]

note however, that this was not the source of the error.

1 Like

the cycles are essentially the faces of the corresponding mesh. however, with the difference that the cycles are polylines rather than polygons. therefore they are explicitly closed when they form a closed loop. this means that in that case the first and last vertex of the cycle is the same. this gets filtered out automatically by the mesh constructor but can be useful information in other use cases.

1 Like

After re-updating, I don’t get the error. Thanks!

Trying to run the following lines for the below network:

network = Network.from_lines(lines)
points = network.to_points()
cycles = network_find_cycles(network)
mesh = Mesh.from_vertices_and_faces(points, cycles)

I get the following error:

face_net=Mesh.from_vertices_and_faces(points, cycles)
File “C:\Users\msalma\Documents\compas-dev\compas\src\compas\datastructures\mesh\core\mesh.py”, line 403, in from_vertices_and_faces
mesh.add_face(face)
File “C:\Users\msalma\Documents\compas-dev\compas\src\compas\datastructures\mesh\core\halfedge.py”, line 658, in add_face
if u not in self.halfedge[v]:
KeyError: 11

Do know have an idea on what the problem might be?

cycles = network_find_cycles(network, breakpoints=network.leaves())

or your input lines are not “clean”.
if they come from Rhino, use low precision in the from_lines function…

well, I am using the same nodal coordinates, as the first example posted here and it works for the first example:

coordinates for the first example:
{0: [-40.0, 55.0, 0.0], 1: [-35.0, 55.0, 0.0], 2: [-30.0, 55.0, 0.0], 3: [-40.0, 60.0, 0.0], 4: [-35.0, 60.0, 0.0], 5: [-30.0, 60.0, 0.0], 6: [-37.5, 57.5, 0.0], 7: [-32.5, 57.5, 0.0], 8: [-40.0, 53.82, 0.0], 9: [-28.82, 55.0, 0.0], 10: [-30.0, 53.82, 0.0], 11: [-35.0, 61.18, 0.0]}

coordinates for the second example:
{0: [-40.0, 55.0, 0.0], 1: [-35.0, 55.0, 0.0], 2: [-30.0, 55.0, 0.0], 4: [-35.0, 60.0, 0.0], 6: [-37.5, 57.5, 0.0], 7: [-32.5, 57.5, 0.0], 8: [-40.0, 53.82, 0.0], 10: [-30.0, 53.82, 0.0], 11: [-35.0, 61.18, 0.0]}

Also, using breakpoints.

for me this works perfectly.

from compas.datastructures import Network
from compas.datastructures import Mesh
from compas.datastructures import network_find_cycles
from compas_plotters import NetworkPlotter
from compas_plotters import MeshPlotter

data = {0: [-40.0, 55.0, 0.0], 1: [-35.0, 55.0, 0.0], 2: [-30.0, 55.0, 0.0], 4: [-35.0, 60.0, 0.0], 6: [-37.5, 57.5, 0.0], 7: [-32.5, 57.5, 0.0], 8: [-40.0, 53.82, 0.0], 10: [-30.0, 53.82, 0.0], 11: [-35.0, 61.18, 0.0]}
key_index = {key: index for index, key in enumerate(data)}

nodes = data.values()
edges = [(0, 8), (0, 1), (1, 2), (10, 2), (0, 6), (6, 4), (4, 11), (4, 7), (7, 2)]
edges = [(key_index[u], key_index[v]) for u, v in edges]

network = Network.from_nodes_and_edges(nodes, edges)

points = network.to_points()
cycles = network_find_cycles(network, breakpoints=network.leaves())

mesh = Mesh.from_vertices_and_faces(points, cycles)

# plotter = NetworkPlotter(network, figsize=(8, 5))
# plotter.draw_nodes(text='key', radius=0.03)
# plotter.draw_edges()
# plotter.show()

plotter = MeshPlotter(mesh, figsize=(8, 5))
plotter.draw_vertices()
plotter.draw_edges(keys=list(set(mesh.edges()) - set(mesh.edges_on_boundary())))
plotter.draw_faces(text='key', keys=list(set(mesh.faces()) - set(mesh.faces_on_boundary())))
plotter.show()

produces this:

Your code works for me too, but only if I redefine the indexing as you did. Otherwise, it raises an error:

dev\compas\src\compas\datastructures\network\core\network.py", line 181, in to_points
return [self.node_coordinates(key) for key in self.nodes()]
dev\compas\src\compas\datastructures\network\core\network.py", line 309, in node_coordinates
return [self.node[key][axis] for axis in axes]
KeyError: ‘x’

What if I want to keep the node indices as they are in the dictionary?

In my case, I have a little function (below) of making a network, by adding the nodes and the edges one by one from a dictionary of nodes and edges, and plot of it is the last figure I sent, but as explained I cannot make a mesh out of it!

net=Network()
for ind, ver in vertex_dic.items():
    net.add_node(ind, {'x': ver[0], 'y': ver[1], 'z': ver[2]})
for edge in edge_dic.values():
    net.add_edge(edge[0], edge[1])

procedure is very similar

from compas.datastructures import Network
from compas.datastructures import Mesh
from compas.datastructures import network_find_cycles
from compas_plotters import MeshPlotter

nodes = {0: [-40.0, 55.0, 0.0], 1: [-35.0, 55.0, 0.0], 2: [-30.0, 55.0, 0.0], 4: [-35.0, 60.0, 0.0], 6: [-37.5, 57.5, 0.0], 7: [-32.5, 57.5, 0.0], 8: [-40.0, 53.82, 0.0], 10: [-30.0, 53.82, 0.0], 11: [-35.0, 61.18, 0.0]}
edges = [(0, 8), (0, 1), (1, 2), (10, 2), (0, 6), (6, 4), (4, 11), (4, 7), (7, 2)]

network = Network()

for key, xyz in nodes.items():
    network.add_node(key, x=xyz[0], y=xyz[1], z=xyz[2])
for u, v in edges:
    network.add_edge(u, v)

points = {key: network.node_coordinates(key) for key in network.nodes()}
cycles = network_find_cycles(network, breakpoints=network.leaves())

mesh = Mesh.from_vertices_and_faces(points, cycles)

plotter = MeshPlotter(mesh, figsize=(8, 5))
plotter.draw_vertices(text='key', radius=0.25)
plotter.draw_edges(keys=list(set(mesh.edges()) - set(mesh.edges_on_boundary())))
plotter.draw_faces(text='key', keys=list(set(mesh.faces()) - set(mesh.faces_on_boundary())))
plotter.show()
1 Like

Yesss, now it works! Using network.to_points() instead of {key: network.node_coordinates(key) for key in network.nodes()} caused the problem!

Quick question. Are the revisions that you made in the past few days, are going to take effect for the conda installation soon?

will release a new version tonight

1 Like