FaceNetwork methods

I want to find the faces of my “Network”, How can I make a “FaceNetwork” out of my “Network”?

UPDATE:
Just used:
lines = network_1.to_lines(axes=‘xyz’)
network_2 = FaceNetwork.from_lines(lines)
network_find_faces(network_2, breakpoints=network_2.leaves())

hi,

that will work, but the from_data and to_data methods are more suitable for this:

n2 = FaceNetwork.from_data(n1.to_data())

perhaps, ideally, it should be the responsibility of the network_find_faces function. it could check for the availability of an add_face method on the network that was passed into it as an argument.

if not hasattr(network, 'add_face'):
    from compas.datastructures import FaceNetwork
    network = FaceNetwork.from_data(network.to_data())

will add something along those lines to the next release…

best,
tom

1 Like

Now if I want to find the boundary vertices of a network using “vertices_on_boundary” from FaceNetwork, I use:

face_net = FaceNetwork.from_data(network.to_data())
vertix_list = face_net.vertices_on_boundary(ordered=True)

when “ordered=True”, it looks like that the method is stuck somewhere and never stops. Could this be related to the WARNING?

when “ordered=False”, it returns a list which includes all the vertices. Could it be because of the non-consecutive vertex keys?

for example for below network:


face_net.vertex = {4: {‘y’: 14.67, ‘x’: -42.67, ‘z’: 0.0}, 5: {‘y’: 14.5, ‘x’: -42.0, ‘z’: 0.0}, 41: {‘y’: 14.33, ‘x’: -42.17, ‘z’: 0.0}, 42: {‘y’: 14.17, ‘x’: -42.5, ‘z’: 0.0}, 13: {‘y’: 14.67, ‘x’: -43.0, ‘z’: 0.0}, 14: {‘y’: 14.33, ‘x’: -43.0, ‘z’: 0.0}, 47: {‘y’: 14.5, ‘x’: -42.33, ‘z’: 0.0}, 16: {‘y’: 14.33, ‘x’: -42.67, ‘z’: 0.0}, 22: {‘y’: 14.5, ‘x’: -42.5, ‘z’: 0.0}, 23: {‘y’: 14.67, ‘x’: -42.17, ‘z’: 0.0}, 24: {‘y’: 14.5, ‘x’: -42.83, ‘z’: 0.0}, 27: {‘y’: 14.33, ‘x’: -42.5, ‘z’: 0.0}}

face_net.edge = {4: {24: {}, 42: {}, 13: {}, 22: {}}, 5: {41: {}, 23: {}}, 41: {27: {}, 47: {}}, 42: {23: {}, 47: {}}, 13: {24: {}}, 14: {24: {}}, 47: {}, 16: {24: {}, 27: {}, 22: {}, 14: {}}, 22: {42: {}, 27: {}}, 23: {47: {}}, 24: {}, 27: {47: {}}}

hi,

the vertices_on_boundary method assumes that the faces of the network have been identified. therefore, if it finds a vertex that connects to a neighbour with a half-edge that points to None, it assumes that vertex is on the boundary. if ordered=False, it will just return all vertices for which this is the case. if ordered=True, it will start at a random vertex of the ones identified and try to cycle through the remaining identified vertices to create an ordered boundary.

in your case, the network has been converted to a face-network, but the faces have not yet been identified (this needs to be done explicitly). therefore, all vertices of the face-network will qualify as being on the boundary (since they all connect to their neighbours with half-edges that point to None).

when ordering is not important, the method will thus still return all vertices of the network (even though this is not correct).

however, when the boundary vertices are requested in order, the method indeed gets stuck in an infinite loop, because it tries to use information that is simply not there.

to solve the problem, try finding the faces, and then ask for the vertices on the boundary. this should give you the expected result:

face_net = FaceNetwork.from_data(network.to_data())
network_find_faces(face_net)
face_net.delete_face(0)
vertex_list = face_net.vertices_on_boundary(ordered=True)

to be honest, you are using what is probably the oldest part of the framework that, until now, was probably only used by me. it relies on many assumptions that are only true for the context it was designed for. in the next release, i will make sure that this gets moved entirely to a specialised package, like compas_ags, or that the assumptions are a bit clearer and can no longer lead to this unexpected behaviour.

note that because of your question i also found a small bug in the function _find_first_neighbour of the duality module of the topology package, which it used by network_find_faces. this is now fixed in hotfix 0.1.0-#44.

best,
tom

by the way, the Y coordinate of vertex 42 in your example seems wrong…

import compas
from compas.datastructures import FaceNetwork
from compas.topology import network_find_faces
from compas.plotters import FaceNetworkPlotter

vertex = {4: {'y': 14.67, 'x': -42.67, 'z': 0.0}, 5: {'y': 14.5, 'x': -42.0, 'z': 0.0}, 41: {'y': 14.33, 'x': -42.17, 'z': 0.0}, 42: {'y': 14.67, 'x': -42.5, 'z': 0.0}, 13: {'y': 14.67, 'x': -43.0, 'z': 0.0}, 14: {'y': 14.33, 'x': -43.0, 'z': 0.0}, 47: {'y': 14.5, 'x': -42.33, 'z': 0.0}, 16: {'y': 14.33, 'x': -42.67, 'z': 0.0}, 22: {'y': 14.5, 'x': -42.5, 'z': 0.0}, 23: {'y': 14.67, 'x': -42.17, 'z': 0.0}, 24: {'y': 14.5, 'x': -42.83, 'z': 0.0}, 27: {'y': 14.33, 'x': -42.5, 'z': 0.0}}
edge = {4: {24: {}, 42: {}, 13: {}, 22: {}}, 5: {41: {}, 23: {}}, 41: {27: {}, 47: {}}, 42: {23: {}, 47: {}}, 13: {24: {}}, 14: {24: {}}, 47: {}, 16: {24: {}, 27: {}, 22: {}, 14: {}}, 22: {42: {}, 27: {}}, 23: {47: {}}, 24: {}, 27: {47: {}}}


network = FaceNetwork()

for key, attr in vertex.items():
    network.add_vertex(key=key, attr_dict=attr)

for u in edge:
    for v in edge[u]:
        network.add_edge(u, v, attr_dict=edge[u][v])

network_find_faces(network)
network.delete_face(0)
print(network.vertices_on_boundary(ordered=True))

plotter = FaceNetworkPlotter(network, figsize=(10, 7))
plotter.draw_vertices(radius=0.01, text='key')
plotter.draw_edges()
plotter.draw_faces(text={key: str(key) for key in network.faces()})
plotter.show()