# FaceNetwork methods

**URL:** <https://forum.compas-framework.org/t/facenetwork-methods/49>\
**Category:** compas\
**Created:** [February 11, 2018, 5:46pm UTC](https://forum.compas-framework.org/t/facenetwork-methods/49 "2018-02-11T17:46:39Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![SalMo](https://avatars.discourse-cdn.com/v4/letter/s/a5b964/32.png) [@SalMo](https://forum.compas-framework.org/u/SalMo)\
**Post date:** [February 11, 2018, 5:46pm UTC](https://forum.compas-framework.org/t/facenetwork-methods/49/1 "2018-02-11T17:46:39Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![tomvanmele](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.compas-framework.org/tomvanmele/32/13_2.png) [@tomvanmele](https://forum.compas-framework.org/u/tomvanmele)\
**Post date:** [February 12, 2018, 5:50am UTC](https://forum.compas-framework.org/t/facenetwork-methods/49/2 "2018-02-12T05:50:23Z")

</div>

hi,

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

```python
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.

```python
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

---

<div class="post-metadata">

**Author:** ![SalMo](https://avatars.discourse-cdn.com/v4/letter/s/a5b964/32.png) [@SalMo](https://forum.compas-framework.org/u/SalMo)\
**Post date:** [February 12, 2018, 2:36pm UTC](https://forum.compas-framework.org/t/facenetwork-methods/49/3 "2018-02-12T14:36:36Z")

</div>

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:

 ![NetworkPlotter](https://us1.discourse-cdn.com/flex015/uploads/compas_framework1/original/1X/50cb84c1ba453652d68ec197196367e7136d696e.png)  
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: {}}}

---

<div class="post-metadata">

**Author:** ![tomvanmele](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.compas-framework.org/tomvanmele/32/13_2.png) [@tomvanmele](https://forum.compas-framework.org/u/tomvanmele)\
**Post date:** [February 15, 2018, 3:17pm UTC](https://forum.compas-framework.org/t/facenetwork-methods/49/4 "2018-02-15T15:17:17Z")

</div>

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:

```python
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

---

<div class="post-metadata">

**Author:** ![tomvanmele](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.compas-framework.org/tomvanmele/32/13_2.png) [@tomvanmele](https://forum.compas-framework.org/u/tomvanmele)\
**Post date:** [February 15, 2018, 3:18pm UTC](https://forum.compas-framework.org/t/facenetwork-methods/49/5 "2018-02-15T15:18:31Z")

</div>

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

```python
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()

```
