Skip to content

Commit

Permalink
feat(face3d): Improving is_centered_adjacent method for honeybee solv…
Browse files Browse the repository at this point in the history
…e adjacencies
  • Loading branch information
chriswmackey authored and Chris Mackey committed Jul 16, 2019
1 parent eaa55b6 commit 15781c6
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 16 deletions.
30 changes: 20 additions & 10 deletions ladybug_geometry/geometry3d/face.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import division

from .pointvector import Point3D, Vector3D
from .ray import Ray3D
from .line import LineSegment3D
from .plane import Plane
from .mesh import Mesh3D
Expand Down Expand Up @@ -565,32 +566,41 @@ def is_geometrically_equivalent(self, face, tolerance):
return False
return True

def is_centered_adjacent(self, face, tolerance, angle_tolerance):
def is_centered_adjacent(self, face, tolerance):
"""Check whether a given face is centered adjacent with this Face.
Centered adjacency is definied as being coplananar with this face and sharing
the same center point to within the tolerance.
Centered adjacency is definied as sharing the same center point as this face,
sharing the same area, and being next to one another to within the tolerance.
This is useful for identifying matching surfaces when you want to quickly
solve for adjacency and you are not concerned about false positives in cases
where one face does not perfectly match the other in terms of area or vertices.
where one face does not perfectly match the other in terms of vertices.
This means it is good enough for cases where users know how to set up their
model correctly.
Args:
face: Another face for which centered adjacency will be tested.
tolerance: The minimum difference between the coordinate values of two
centers at which they can be considered centered adjacent.
angle_tolerance: The max angle in radians that the plane normals can
differ from one another in order for them to be considered coplanar.
Returns:
True if centered adjacent. False if not centered adjacent.
"""
if not self.center.is_equivalent(face.center, tolerance):
if not self.center.is_equivalent(face.center, tolerance): # center check
return False
if not self.plane.is_coplanar_tolerance(face.plane, tolerance, angle_tolerance):
if not abs(self.area - face.area) <= tolerance: # area check
return False
return True
# construct a ray using this face's normal and a point on this face
v1 = self.boundary[-1] - self.boundary[0]
v2 = self.boundary[1] - self.boundary[0]
move_vec = Vector3D(
(v1.x + v2.x / 2), (v1.y + v2.y / 2), (v1.z + v2.z / 2)).normalize()
move_vec = move_vec * (tolerance + 0.00001)
point_on_face = self.boundary[0] + move_vec
test_ray = Ray3D(point_on_face, self.normal)
# shoot ray from this face to the other to verify adjacency
if face.intersect_line_ray(test_ray):
return True
return False

def is_sub_face(self, face, tolerance, angle_tolerance):
"""Check whether a given face is a sub-face of this face.
Expand Down Expand Up @@ -654,7 +664,7 @@ def validate_planarity(self, tolerance, raise_exception=True):
for _v in self.vertices:
if self._plane.distance_to_point(_v) >= tolerance:
if raise_exception is True:
raise AttributeError(
raise ValueError(
'Vertex {} is out of plane with its parent face.\nDistance '
'to plane is {}'.format(_v, self._plane.distance_to_point(_v)))
else:
Expand Down
12 changes: 6 additions & 6 deletions tests/face3d_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,12 +331,12 @@ def test_is_centered_adjacent(self):
face_6 = Face3D(pts_4, plane_1)
face_7 = Face3D(pts_5, plane_1)

assert face_1.is_centered_adjacent(face_2, 0.0001, 0.0001) is True
assert face_1.is_centered_adjacent(face_3, 0.0001, 0.0001) is True
assert face_1.is_centered_adjacent(face_4, 0.0001, 0.0001) is True
assert face_1.is_centered_adjacent(face_5, 0.0001, 0.0001) is False
assert face_1.is_centered_adjacent(face_6, 0.0001, 0.0001) is True
assert face_1.is_centered_adjacent(face_7, 0.0001, 0.0001) is True
assert face_1.is_centered_adjacent(face_2, 0.0001) is True
assert face_1.is_centered_adjacent(face_3, 0.0001) is True
assert face_1.is_centered_adjacent(face_4, 0.0001) is True
assert face_1.is_centered_adjacent(face_5, 0.0001) is False
assert face_1.is_centered_adjacent(face_6, 0.0001) is False
assert face_1.is_centered_adjacent(face_7, 0.0001) is True

def test_is_sub_face(self):
"""Test the is_sub_face method."""
Expand Down

0 comments on commit 15781c6

Please sign in to comment.