33from __future__ import division
44
55from math import pi
6-
6+ from compas . utilities import flatten
77
88__all__ = ['mesh_dual' ]
99
1010
1111PI2 = 2.0 * pi
1212
1313
14- def mesh_dual (mesh , cls = None ):
14+ def mesh_dual (mesh , cls = None , include_boundary = False ):
1515 """Construct the dual of a mesh.
1616
1717 Parameters
@@ -21,20 +21,36 @@ def mesh_dual(mesh, cls=None):
2121 cls : Type[:class:`~compas.datastructures.Mesh`], optional
2222 The type of the dual mesh.
2323 Defaults to the type of the provided mesh object.
24+ include_boundary: bool, optional
25+ Whether to include boundary faces for the dual mesh
26+ If True, create faces on boundaries including all original mesh boundary vertices.
2427
2528 Returns
2629 -------
2730 :class:`~compas.datastructures.Mesh`
2831 The dual mesh object.
2932
33+ Examples
34+ --------
35+ >>> import compas
36+ >>> from compas.datastructures import Mesh
37+ >>> mesh = Mesh.from_obj(compas.get('faces.obj'))
38+ >>> mesh.delete_face(11)
39+ >>> mesh.delete_face(6)
40+ >>> mesh.delete_face(7)
41+ >>> mesh.quads_to_triangles()
42+ >>> mesh = mesh.subdivide('corner')
43+ >>> dual = mesh.dual(include_boundary=True)
44+
3045 """
3146 if not cls :
3247 cls = type (mesh )
3348
3449 dual = cls ()
3550
3651 face_centroid = {face : mesh .face_centroid (face ) for face in mesh .faces ()}
37- inner = list (set (mesh .vertices ()) - set (mesh .vertices_on_boundary ()))
52+ outer = set (flatten (mesh .vertices_on_boundaries ()))
53+ inner = list (set (mesh .vertices ()) - outer )
3854 vertex_xyz = {}
3955 face_vertices = {}
4056
@@ -52,4 +68,39 @@ def mesh_dual(mesh, cls=None):
5268 for face in face_vertices :
5369 dual .add_face (face_vertices [face ], fkey = face )
5470
71+ if not include_boundary :
72+ return dual
73+
74+ for boundary in mesh .faces_on_boundaries ():
75+ for face in boundary :
76+ if not dual .has_vertex (face ):
77+ x , y , z = face_centroid [face ]
78+ dual .add_vertex (key = face , x = x , y = y , z = z )
79+
80+ edge_vertex = {}
81+ for boundary in mesh .edges_on_boundaries ():
82+ for u , v in boundary :
83+ x , y , z = mesh .edge_midpoint (u , v )
84+ edge_vertex [u , v ] = edge_vertex [v , u ] = dual .add_vertex (x = x , y = y , z = z )
85+
86+ vertex_vertex = {}
87+ for boundary in mesh .vertices_on_boundaries ():
88+ if boundary [0 ] == boundary [- 1 ]:
89+ boundary = boundary [:- 1 ]
90+ for vertex in boundary :
91+ x , y , z = mesh .vertex_coordinates (vertex )
92+ vertex_vertex [vertex ] = dual .add_vertex (x = x , y = y , z = z )
93+
94+ for boundary in mesh .vertices_on_boundaries ():
95+ if boundary [0 ] == boundary [- 1 ]:
96+ boundary = boundary [:- 1 ]
97+ for vertex in boundary :
98+ vertices = [vertex_vertex [vertex ]]
99+ nbrs = mesh .vertex_neighbors (vertex , ordered = True )[::- 1 ]
100+ vertices .append (edge_vertex [vertex , nbrs [0 ]])
101+ for nbr in nbrs [:- 1 ]:
102+ vertices .append (mesh .halfedge_face (vertex , nbr ))
103+ vertices .append (edge_vertex [vertex , nbrs [- 1 ]])
104+ dual .add_face (vertices [::- 1 ])
105+
55106 return dual
0 commit comments