Source code for honeybee.facetype

"""Face Types."""
from ladybug_geometry.geometry3d.pointvector import Vector3D
import re
import math


class _FaceType(object):
    __slots__ = ()

    def __init__(self):
        pass

    @property
    def name(self):
        return self.__class__.__name__

    def ToString(self):
        return self.__repr__()

    def __eq__(self, other):
        return self.__class__ == other.__class__

    def __ne__(self, other):
        return not self.__eq__(other)

    def __repr__(self):
        return self.name


[docs]class Wall(_FaceType): """Type for walls.""" __slots__ = () pass
[docs]class RoofCeiling(_FaceType): """Type for roofs and ceilings.""" __slots__ = () pass
[docs]class Floor(_FaceType): """Type for floors.""" __slots__ = () pass
[docs]class AirBoundary(_FaceType): """Type for air boundaries (aka. virtual partitions) between Rooms.""" __slots__ = () pass
class _FaceTypes(object): """Face types.""" def __init__(self): self._wall = Wall() self._roof_ceiling = RoofCeiling() self._floor = Floor() self._air_boundary = AirBoundary() self._type_name_dict = None @property def wall(self): return self._wall @property def roof_ceiling(self): return self._roof_ceiling @property def floor(self): return self._floor @property def air_boundary(self): return self._air_boundary def by_name(self, face_type_name): """Get a Face Type instance from its name. This method will correct for capitalization as well as the presence of spaces and underscores. Args: face_type_name: A text string for the face type (eg. "Wall"). """ if self._type_name_dict is None: self._build_type_name_dict() try: return self._type_name_dict[re.sub(r'[\s_]', '', face_type_name.lower())] except KeyError: raise ValueError( '"{}" is not a valid face type name.\nChoose from the following' ': {}'.format(face_type_name, list(self._type_name_dict.keys()))) def _build_type_name_dict(self): """Build a dictionary that can be used to lookup face types by name.""" attr = [atr for atr in dir(self) if not atr.startswith('_')] clean_attr = [re.sub(r'[\s_]', '', atr.lower()) for atr in attr] self._type_name_dict = {} for atr_name, atr in zip(clean_attr, attr): try: full_attr = getattr(self, '_' + atr) self._type_name_dict[atr_name] = full_attr except AttributeError: pass # callable method that has no static default object def __contains__(self, value): return isinstance(value, _FaceType) def __repr__(self): attr = [atr for atr in dir(self) if not atr.startswith('_') and atr != 'by_name'] return 'Face Types:\n{}'.format('\n'.join(attr)) face_types = _FaceTypes()
[docs]def get_type_from_normal(normal_vector, roof_angle=60, floor_angle=130): """Return face type based on the angle between Z axis and normal vector. Angles between 0 and roof_angle will be set to roof_ceiling. Angles between roof_angle and floor_angle will be set to wall. Angles larger than floor angle will be set to floor. Args: normal_vector: Normal vector as a ladybug_geometry Vector3D. roof_angle: A number between 0 and 90 to set the angle from the horizontal plane below which faces will be considered roofs instead of walls. 90 indicates that all vertical faces are roofs and 0 indicates that all horizontal faces are walls. (Default: 60, recommended by the ASHRAE 90.1 standard). floor_angle: A number between 90 and 180 to set the angle from the horizontal plane above which faces will be considered floors instead of walls. 180 indicates that all vertical faces are floors and 0 indicates that all horizontal faces are walls. (Default: 130, recommended by the ASHRAE 90.1 standard). Returns: Face type instance. """ z_axis = Vector3D(0, 0, 1) angle = math.degrees(z_axis.angle(normal_vector)) if angle < roof_angle: return face_types.roof_ceiling elif roof_angle <= angle < floor_angle: return face_types.wall else: return face_types.floor return face_types.wall