Skip to content

Commit

Permalink
fix(shademesh): Change method to only traingulate non planar quads
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswmackey authored and Chris Mackey committed Nov 24, 2023
1 parent 824b569 commit d7c5eb2
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 8 deletions.
28 changes: 20 additions & 8 deletions honeybee/shademesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def scale(self, factor, origin=None):
self.properties.scale(factor, origin)

def triangulate_and_remove_degenerate_faces(self, tolerance=0.01):
"""Triangulate all faces in the mesh and remove all degenerate faces from the result.
"""Triangulate non-planar faces in the mesh and remove all degenerate faces.
This is helpful for certain geometry interfaces that require perfectly
planar geometry without duplicate or colinear vertices.
Expand All @@ -231,16 +231,28 @@ def triangulate_and_remove_degenerate_faces(self, tolerance=0.01):
"""
new_faces, verts = [], self.geometry.vertices
for shd in self.faces:
shades = (shd,) if len(shd) == 3 else \
((shd[0], shd[1], shd[2]), (shd[2], shd[3], shd[0]))
for shade in enumerate(shades):
shd_verts = [verts[v] for v in shade]
shade_face = Face3D(shd_verts)
shd_verts = [verts[v] for v in shd]
shf = Face3D(shd_verts)
if not shf.check_planar(tolerance, raise_exception=False):
shades = ((shd[0], shd[1], shd[2]), (shd[2], shd[3], shd[0]))
for shade in shades:
shd_verts = [verts[v] for v in shade]
shade_face = Face3D(shd_verts)
try:
shade_face.remove_colinear_vertices(tolerance)
except AssertionError:
continue # degenerate face to remove
new_faces.append(shade)
else:
try:
shade_face.remove_colinear_vertices(tolerance)
new_face = shf.remove_colinear_vertices(tolerance)
except AssertionError:
continue # degenerate face to remove
new_faces.append(shade)
if len(new_face.vertices) == len(shd):
new_faces.append(shd)
else: # quad face with duplicate or colinear verts
new_sh = tuple(shd[shd_verts.index(v)] for v in new_face.vertices)
new_faces.append(new_sh)
self._geometry = Mesh3D(verts, new_faces)

def is_geo_equivalent(self, shade_mesh, tolerance=0.01):
Expand Down
47 changes: 47 additions & 0 deletions tests/shademesh_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,53 @@ def test_reflect():
assert test_2.geometry[2].z == pytest.approx(2, rel=1e-3)


def test_triangulate_and_remove_degenerate_faces():
"""Test the triangulate_and_remove_degenerate_faces method."""
pts = (Point3D(0, 0, 4), Point3D(0, 2, 4), Point3D(2, 2, 4),
Point3D(2, 0, 4), Point3D(4, 0, 4))
mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
shade = ShadeMesh('Awning_1', mesh)
shade.triangulate_and_remove_degenerate_faces(0.01)
assert len(shade.faces) == 2
assert len(shade.faces[0]) == 4
assert len(shade.faces[1]) == 3

pts = (Point3D(0, 0, 2), Point3D(0, 2, 4), Point3D(2, 2, 4),
Point3D(2, 0, 4), Point3D(4, 0, 4))
mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
shade = ShadeMesh('Awning_1', mesh)
shade.triangulate_and_remove_degenerate_faces(0.01)
assert len(shade.faces) == 3
assert len(shade.faces[0]) == 3
assert len(shade.faces[1]) == 3

pts = (Point3D(0, 2, 4), Point3D(0, 2, 4), Point3D(2, 2, 4),
Point3D(2, 0, 4), Point3D(4, 0, 4))
mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
shade = ShadeMesh('Awning_1', mesh)
shade.triangulate_and_remove_degenerate_faces(0.01)
assert len(shade.faces) == 2
assert len(shade.faces[0]) == 3
assert len(shade.faces[1]) == 3

pts = (Point3D(0, 0, 4), Point3D(0, 2, 4), Point3D(2, 2, 4),
Point3D(2, 0, 4), Point3D(2, 0, 4))
mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
shade = ShadeMesh('Awning_1', mesh)
shade.triangulate_and_remove_degenerate_faces(0.01)
assert len(shade.faces) == 1
assert len(shade.faces[0]) == 4

pts = (Point3D(1, 1, 4), Point3D(0, 2, 4), Point3D(2, 2, 4),
Point3D(2, 0, 4), Point3D(4, 0, 4))
mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
shade = ShadeMesh('Awning_1', mesh)
shade.triangulate_and_remove_degenerate_faces(0.01)
assert len(shade.faces) == 2
assert len(shade.faces[0]) == 3
assert len(shade.faces[1]) == 3


def test_to_dict():
"""Test the shade to_dict method."""
pts = (Point3D(0, 0, 4), Point3D(0, 2, 4), Point3D(2, 2, 4),
Expand Down

0 comments on commit d7c5eb2

Please sign in to comment.