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