Source code for honeybee_plus.geometryoperation
"""Collection of methods for geometrical operations."""
from .vectormath.euclid import math, Vector3
[docs]def strip_point_list(pts):
"""Flatten a list of list of points."""
if not hasattr(pts[0], '__iter__') or hasattr(pts[0], 'X'):
return pts
elif hasattr(pts[0][0], '__iter__') and not hasattr(pts[0][0][0], '__iter__'):
# base face has multiple faces and this is one of them
return pts[0]
else:
# pts are nested than what it should be, just strip them onece more
return strip_point_list(pts[0])
[docs]def normal_from_points(pts):
"""Calculate normal vector for a list of points.
This method uses the pts[-1], pts[0] and pts[1] to calculate the normal
assuming the points are representing a planar surface
"""
# pts = strip_point_list(pts)
try:
# vector between first point and the second point on the list
v1 = Vector3(pts[1].X - pts[0].X,
pts[1].Y - pts[0].Y,
pts[1].Z - pts[0].Z)
# vector between first point and the last point in the list
v2 = Vector3(pts[-1].X - pts[0].X,
pts[-1].Y - pts[0].Y,
pts[-1].Z - pts[0].Z)
except AttributeError:
# vector between first point and the second point on the list
v1 = Vector3(pts[1][0] - pts[0][0],
pts[1][1] - pts[0][1],
pts[1][2] - pts[0][2])
# vector between first point and the last point in the list
v2 = Vector3(pts[-1][0] - pts[0][0],
pts[-1][1] - pts[0][1],
pts[-1][2] - pts[0][2])
return tuple(v1.cross(v2).normalize())
except IndexError:
raise ValueError('Length of input points should be 3!')
else:
return tuple(v1.cross(v2).normalize())
[docs]def up_vector_from_points(pts):
"""Calculate up vector for a surface from points."""
x_axis = Vector3(pts[1][0] - pts[0][0],
pts[1][1] - pts[0][1],
pts[1][2] - pts[0][2])
normal = Vector3(*normal_from_points(pts))
return tuple(normal.cross(x_axis).normalize())
[docs]def center_point_from_points(pts):
"""Calculate center point.
This method finds the center point by averging x, y and z values.
"""
x, y, z = 0, 0, 0
try:
pt_count = float(len(pts))
for pt in pts:
x += pt[0]
y += pt[1]
z += pt[2]
except IndexError:
raise IndexError("Each point should be a list or a tuple with 3 values.")
except TypeError:
raise TypeError("Pts should be a list or a tuple of points.")
return x / pt_count, y / pt_count, z / pt_count
[docs]def vector_angle_to_z_axis(vector):
"""Calculate angle between vectoe and (0, 0, 1) in degrees."""
z_axis = Vector3(0, 0, 1)
try:
return math.degrees(z_axis.angle(Vector3(*vector)))
except TypeError:
# Vectors from Dynamo are not iterable!
return math.degrees(z_axis.angle(Vector3(vector.X, vector.Y, vector.Z)))
[docs]def vector_angle(vector1, vector2):
"""Calculate vector angle between two vectors."""
try:
v1 = Vector3(*vector1)
except TypeError:
v1 = Vector3(vector1.X, vector1.Y, vector1.Z)
try:
return math.degrees(v1.angle(Vector3(*vector2)))
except TypeError:
# Vectors from Dynamo are not iterable!
return math.degrees(v1.angle(Vector3(vector2.X, vector2.Y, vector2.Z)))
if __name__ == "__main__":
pts = ((0, 0, 0), (10, 10, 0), (10, 0, 0))
srfVector = normal_from_points(pts)
print(vector_angle_to_z_axis(srfVector))
print(center_point_from_points(pts))