def test_polyface3d_to_from_dict_hole(): """Test the to/from dict of Polyface3D objects with a hole.""" bound_pts = [Point3D(0, 0), Point3D(3, 0), Point3D(3, 3), Point3D(0, 3)] hole_pts = [Point3D(1, 1), Point3D(2, 1), Point3D(2, 2), Point3D(1, 2)] face = Face3D(bound_pts, None, [hole_pts]) polyface = Polyface3D.from_offset_face(face, 1) polyface_dict = polyface.to_dict() new_polyface = Polyface3D.from_dict(polyface_dict) assert len(new_polyface.vertices) == 16 assert len(new_polyface.face_indices) == 10 assert len(new_polyface.faces) == 10 assert len(new_polyface.edge_indices) == 24 assert len(new_polyface.edges) == 24 assert len(new_polyface.naked_edges) == 0 assert len(new_polyface.non_manifold_edges) == 0 assert len(new_polyface.internal_edges) == 24 assert new_polyface.area == pytest.approx(32, rel=1e-3) assert new_polyface.volume == pytest.approx(8, rel=1e-3) assert new_polyface.is_solid assert new_polyface.faces[0].normal.z == pytest.approx(-1, rel=1e-3) assert new_polyface.faces[-1].normal.z == pytest.approx(1, rel=1e-3) assert new_polyface.faces[0].has_holes assert new_polyface.faces[-1].has_holes for face in polyface.faces: assert not face.is_clockwise
def test_group_by_orientation(): """Test the group_by_orientation method.""" pts_1 = (Point3D(0, 0), Point3D(15, 0), Point3D(10, 5), Point3D(5, 5)) pts_2 = (Point3D(15, 0), Point3D(15, 15), Point3D(10, 10), Point3D(10, 5)) pts_3 = (Point3D(0, 15), Point3D(5, 10), Point3D(10, 10), Point3D(15, 15)) pts_4 = (Point3D(0, 0), Point3D(5, 5), Point3D(5, 10), Point3D(0, 15)) pts_5 = (Point3D(5, 5), Point3D(10, 5), Point3D(10, 10), Point3D(5, 10)) pf_1 = Polyface3D.from_offset_face(Face3D(pts_1), 3) pf_2 = Polyface3D.from_offset_face(Face3D(pts_2), 3) pf_3 = Polyface3D.from_offset_face(Face3D(pts_3), 3) pf_4 = Polyface3D.from_offset_face(Face3D(pts_4), 3) pf_5 = Polyface3D.from_offset_face(Face3D(pts_5), 3) room_1 = Room.from_polyface3d('Zone1', pf_1) room_2 = Room.from_polyface3d('Zone2', pf_2) room_3 = Room.from_polyface3d('Zone3', pf_3) room_4 = Room.from_polyface3d('Zone4', pf_4) room_5 = Room.from_polyface3d('Zone5', pf_5) rooms = [room_1, room_2, room_3, room_4, room_5] adj_info = Room.solve_adjacency(rooms, 0.01) grouped_rooms, core_rooms, orientations = Room.group_by_orientation(rooms) assert len(grouped_rooms) == 4 assert len(core_rooms) == 1 assert orientations == [0.0, 90.0, 180.0, 270.0]
def test_polyface3d_init_from_faces_tolerance(): """Test the initialization of Polyface3D from_faces with a tolerance.""" pts_1 = [Point3D(0, 0, 0), Point3D(0, 2, 0), Point3D(2, 2, 0), Point3D(2, 0, 0)] pts_2 = [Point3D(0, 0, 0), Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(0, 2, 0)] pts_3 = [Point3D(0, 0, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(0, 0, 2)] pts_4 = [Point3D(2, 2, 0), Point3D(0, 2, 0), Point3D(0, 2, 2), Point3D(2, 2, 2)] pts_5 = [Point3D(2, 2, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(2, 2, 2)] pts_6 = [Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2)] pts_7 = [Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2.0001)] face_1 = Face3D(pts_1) face_2 = Face3D(pts_2) face_3 = Face3D(pts_3) face_4 = Face3D(pts_4) face_5 = Face3D(pts_5) face_6 = Face3D(pts_6) face_7 = Face3D(pts_7) polyface_1 = Polyface3D.from_faces( [face_1, face_2, face_3, face_4, face_5, face_6], 0.001) polyface_2 = Polyface3D.from_faces( [face_1, face_2, face_3, face_4, face_5, face_7], 0.001) polyface_3 = Polyface3D.from_faces( [face_1, face_2, face_3, face_4, face_5, face_7], 0.000001) assert polyface_1.is_solid assert polyface_2.is_solid assert not polyface_3.is_solid
def test_equality(): """Test the equality of Polyface3D objects.""" pts = [ Point3D(0, 0, 0), Point3D(0, 2, 0), Point3D(2, 2, 0), Point3D(2, 0, 0), Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2) ] face_indices = [[(0, 1, 2, 3)], [(0, 4, 5, 1)], [(0, 3, 7, 4)], [(2, 1, 5, 6)], [(2, 3, 7, 6)], [(4, 5, 6, 7)]] face_indices_2 = [[(0, 1, 2, 3)], [(0, 4, 5, 1)], [(0, 3, 7, 4)], [(2, 1, 5, 6)], [(2, 3, 7, 6)]] polyface = Polyface3D(pts, face_indices) polyface_dup = polyface.duplicate() polyface_alt = Polyface3D(pts, face_indices_2) assert polyface is polyface assert polyface is not polyface_dup assert polyface == polyface_dup assert hash(polyface) == hash(polyface_dup) assert polyface != polyface_alt assert hash(polyface) != hash(polyface_alt)
def test_polyface3d_to_from_dict_with_overlap(): """Test the to/from dict of Polyface3D objects with overlapping edges.""" pts_1 = [Point3D(0, 0, 0), Point3D(0, 2, 0), Point3D(2, 2, 0), Point3D(2, 0, 0)] pts_2 = [Point3D(0, 0, 0), Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(0, 2, 0)] pts_3 = [Point3D(0, 0, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(0, 0, 2)] pts_4 = [Point3D(2, 2, 0), Point3D(0, 2, 0), Point3D(0, 2, 2), Point3D(2, 2, 2)] pts_5 = [Point3D(2, 2, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(2, 2, 2)] pts_6 = [Point3D(0, 0, 2), Point3D(0, 1, 2), Point3D(2, 1, 2), Point3D(2, 0, 2)] pts_7 = [Point3D(0, 1, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 1, 2)] face_1 = Face3D(pts_1) face_2 = Face3D(pts_2) face_3 = Face3D(pts_3) face_4 = Face3D(pts_4) face_5 = Face3D(pts_5) face_6 = Face3D(pts_6) face_7 = Face3D(pts_7) polyface = Polyface3D.from_faces( [face_1, face_2, face_3, face_4, face_5, face_6, face_7], 0.01) new_polyface = polyface.merge_overlapping_edges(0.0001, 0.0001) assert new_polyface.is_solid assert len(new_polyface.naked_edges) == 0 assert len(new_polyface.internal_edges) == 13 polyface_dict = new_polyface.to_dict() dict_polyface = Polyface3D.from_dict(polyface_dict) assert isinstance(dict_polyface, Polyface3D) assert dict_polyface.to_dict() == polyface_dict assert dict_polyface.is_solid assert len(dict_polyface.naked_edges) == 0 assert len(dict_polyface.internal_edges) == 13
def test_polyface3d_init_from_faces_coplanar(): """Test the initialization of Polyface3D from_faces with two coplanar faces.""" # this is an important case that must be solved # can be done by iterating through naked edges and finding colinear ones pts_1 = [Point3D(0, 0, 0), Point3D(0, 2, 0), Point3D(2, 2, 0), Point3D(2, 0, 0)] pts_2 = [Point3D(0, 0, 0), Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(0, 2, 0)] pts_3 = [Point3D(0, 0, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(0, 0, 2)] pts_4 = [Point3D(2, 2, 0), Point3D(0, 2, 0), Point3D(0, 2, 2), Point3D(2, 2, 2)] pts_5 = [Point3D(2, 2, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(2, 2, 2)] pts_6 = [Point3D(0, 0, 2), Point3D(0, 1, 2), Point3D(2, 1, 2), Point3D(2, 0, 2)] pts_7 = [Point3D(0, 1, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 1, 2)] face_1 = Face3D(pts_1) face_2 = Face3D(pts_2) face_3 = Face3D(pts_3) face_4 = Face3D(pts_4) face_5 = Face3D(pts_5) face_6 = Face3D(pts_6) face_7 = Face3D(pts_7) polyface = Polyface3D.from_faces( [face_1, face_2, face_3, face_4, face_5, face_6, face_7], 0.01) polyface_2 = Polyface3D.from_faces( [face_1, face_2, face_3, face_4, face_5, face_7], 0.01) assert not polyface.is_solid assert len(polyface.naked_edges) != 0 new_polyface = polyface.merge_overlapping_edges(0.0001, 0.0001) assert new_polyface.is_solid assert len(new_polyface.naked_edges) == 0 assert len(new_polyface.internal_edges) == 13 new_polyface_2 = polyface_2.merge_overlapping_edges(0.0001, 0.0001) assert not new_polyface_2.is_solid assert len(new_polyface_2.naked_edges) != 0
def test_floor_mesh_grid(): """Test the generation of a mesh grid from the floor of a box.""" polyface = Polyface3D.from_box(5, 10, 3) floor_grid = polyface.faces[0].get_mesh_grid(1, 1, 1, True) assert len(floor_grid.faces) == 50 angle = -1 * math.radians(45) x_axis = Vector3D(1, 0, 0).rotate_xy(angle) base_plane = Plane(Vector3D(0, 0, 1), Point3D(0, 0, 0), x_axis) polyface = Polyface3D.from_box(5, 10, 3, base_plane) floor_grid = polyface.faces[0].get_mesh_grid(1, 1, 1, True) assert len(floor_grid.faces) == 50
def test_compute_bounding_box_extents_complex(): """Test the bounding box extents of ladybug_geometry.""" # South Room 1: 21 x 10.5 x 3 szone1 = Face3D( [Point3D(0, 0), Point3D(21, 0), Point3D(21, 10.5), Point3D(0, 10.5)]) sroom1 = Room.from_polyface3d('SouthRoom1', Polyface3D.from_offset_face(szone1, 3)) # North Room 1: 21 x 10.5 x 3 nzone1 = Face3D( [Point3D(0, 10.5), Point3D(21, 10.5), Point3D(21, 21), Point3D(0, 21)]) nroom1 = Room.from_polyface3d('NorthRoom1', Polyface3D.from_offset_face(nzone1, 3)) # South Room 2: 21 x 10.5 x 3 szone2 = Face3D([ Point3D(0, 0, 3), Point3D(21, 0, 3), Point3D(21, 10.5, 3), Point3D(0, 10.5, 3) ]) sroom2 = Room.from_polyface3d('SouthRoom2', Polyface3D.from_offset_face(szone2, 3)) # North Room 2: 21 x 10.5 x 3 nzone2 = Face3D([ Point3D(0, 10.5, 3), Point3D(21, 10.5, 3), Point3D(21, 21, 3), Point3D(0, 21, 3) ]) nroom2 = Room.from_polyface3d('NorthRoom2', Polyface3D.from_offset_face(nzone2, 3)) rooms = [sroom1, nroom1, sroom2, nroom2] model = Model('Four_Zone_Simple', rooms) # Rotate the buildings theta = 30.0 model.rotate_xy(theta, rooms[0].geometry.vertices[-1]) geoms = [room.geometry for room in model.rooms] xx, yy, zz = bounding_box_extents(geoms, math.radians(theta)) assert xx == pytest.approx(21, abs=1e-10) assert yy == pytest.approx(21, abs=1e-10) assert zz == pytest.approx(6, abs=1e-10)
def test_min_max_center(): """Test the Face3D min, max and center.""" polyface_1 = Polyface3D.from_box(2, 4, 2) polyface_2 = Polyface3D.from_box(math.sqrt(2), math.sqrt(2), 2, Plane( Vector3D(0, 0, 1), Point3D(1, 0, 0), Vector3D(1, 1, 0))) assert polyface_1.min == Point3D(0, 0, 0) assert polyface_1.max == Point3D(2, 4, 2) assert polyface_1.center == Point3D(1, 2, 1) assert polyface_1.volume == pytest.approx(16, rel=1e-3) assert polyface_2.min == Point3D(0, 0, 0) assert polyface_2.max == Point3D(2, 2, 2) assert polyface_2.center == Point3D(1, 1, 1) assert polyface_2.volume == pytest.approx(4, rel=1e-3)
def test_overlapping_bounding_boxes(): """Test the Polyface3D overlapping_bounding_boxes method.""" polyface_1 = Polyface3D.from_box(1, 1, 1, Plane(o=Point3D(1, 1, 2))) polyface_2 = Polyface3D.from_box(1, 1, 1, Plane(o=Point3D(1, 1, 1))) polyface_3 = Polyface3D.from_box(1, 1, 1, Plane(o=Point3D(2, 1, 2))) polyface_4 = Polyface3D.from_box(1, 1, 1, Plane(o=Point3D(1, 2, 2))) polyface_5 = Polyface3D.from_box(1, 1, 1, Plane(o=Point3D(0, 0, 0))) assert Polyface3D.overlapping_bounding_boxes(polyface_1, polyface_2, 0.01) assert Polyface3D.overlapping_bounding_boxes(polyface_1, polyface_3, 0.01) assert Polyface3D.overlapping_bounding_boxes(polyface_1, polyface_4, 0.01) assert not Polyface3D.overlapping_bounding_boxes(polyface_1, polyface_5, 0.01)
def test_polyface3d_init_from_offset_face(): """Test the initalization of Poyface3D from_offset_face.""" face = Face3D.from_rectangle(2, 2) polyface = Polyface3D.from_offset_face(face, 2) assert len(polyface.vertices) == 8 assert len(polyface.face_indices) == 6 assert len(polyface.faces) == 6 assert len(polyface.edge_indices) == 12 assert len(polyface.edges) == 12 assert len(polyface.naked_edges) == 0 assert len(polyface.non_manifold_edges) == 0 assert len(polyface.internal_edges) == 12 assert polyface.area == 24 assert polyface.volume == 8 assert polyface.is_solid for f in polyface.faces: assert f.is_clockwise is False for e in polyface.edges: assert e.length == 2 assert polyface.faces[0].normal.z == pytest.approx(-1, rel=1e-3) assert polyface.faces[-1].normal.z == pytest.approx(1, rel=1e-3) for face in polyface.faces: assert not face.is_clockwise
def test_polyface3d_init_solid(): """Test the initialization of Polyface3D and basic properties of solid objects.""" pts = [Point3D(0, 0, 0), Point3D(0, 2, 0), Point3D(2, 2, 0), Point3D(2, 0, 0), Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2)] face_indices = [[(0, 1, 2, 3)], [(0, 4, 5, 1)], [(0, 3, 7, 4)], [(2, 1, 5, 6)], [(2, 3, 7, 6)], [(4, 5, 6, 7)]] polyface = Polyface3D(pts, face_indices) assert len(polyface.vertices) == 8 assert len(polyface.face_indices) == 6 assert len(polyface.faces) == 6 assert len(polyface.edge_indices) == 12 assert len(polyface.edges) == 12 assert len(polyface.naked_edges) == 0 assert len(polyface.non_manifold_edges) == 0 assert len(polyface.internal_edges) == 12 assert polyface.area == 24 assert polyface.volume == 8 assert polyface.is_solid for face in polyface.faces: assert face.area == 4 assert face.is_clockwise is False assert polyface.faces[0].normal == Vector3D(0, 0, -1) assert polyface.faces[1].normal == Vector3D(-1, 0, 0) assert polyface.faces[2].normal == Vector3D(0, -1, 0) assert polyface.faces[3].normal == Vector3D(0, 1, 0) assert polyface.faces[4].normal == Vector3D(1, 0, 0) assert polyface.faces[5].normal == Vector3D(0, 0, 1)
def test_polyface3d_init_from_faces_open(): """Test the initialization of Polyface3D from_faces with an open object.""" pts_1 = [Point3D(0, 0, 0), Point3D(0, 2, 0), Point3D(2, 2, 0), Point3D(2, 0, 0)] pts_2 = [Point3D(0, 0, 0), Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(0, 2, 0)] pts_3 = [Point3D(0, 0, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(0, 0, 2)] pts_4 = [Point3D(2, 2, 0), Point3D(0, 2, 0), Point3D(0, 2, 2), Point3D(2, 2, 2)] pts_5 = [Point3D(2, 2, 0), Point3D(2, 0, 0), Point3D(2, 0, 2), Point3D(2, 2, 2)] face_1 = Face3D(pts_1) face_2 = Face3D(pts_2) face_3 = Face3D(pts_3) face_4 = Face3D(pts_4) face_5 = Face3D(pts_5) polyface = Polyface3D.from_faces([face_1, face_2, face_3, face_4, face_5], 0.01) assert len(polyface.vertices) == 8 assert len(polyface.face_indices) == 5 assert len(polyface.faces) == 5 assert len(polyface.edge_indices) == 12 assert len(polyface.edges) == 12 assert len(polyface.naked_edges) == 4 assert len(polyface.non_manifold_edges) == 0 assert len(polyface.internal_edges) == 8 assert polyface.area == 20 assert polyface.volume == 0 assert polyface.is_solid is False for face in polyface.faces: assert face.area == 4 assert face.is_clockwise is False
def test_to_dict_air_walls(): """Test the Model to_dict method with a multi-zone house.""" pts_1 = [Point3D(0, 0), Point3D(30, 0), Point3D(20, 10), Point3D(10, 10)] pts_2 = [Point3D(0, 0), Point3D(10, 10), Point3D(10, 20), Point3D(0, 30)] pts_3 = [Point3D(10, 20), Point3D(20, 20), Point3D(30, 30), Point3D(0, 30)] pts_4 = [Point3D(30, 0), Point3D(30, 30), Point3D(20, 20), Point3D(20, 10)] verts = [pts_1, pts_2, pts_3, pts_4] rooms = [] for i, f_vert in enumerate(verts): pface = Polyface3D.from_offset_face(Face3D(f_vert), 3) room = Room.from_polyface3d('PerimeterRoom{}'.format(i), pface) room.properties.energy.program_type = office_program room.properties.energy.add_default_ideal_air() rooms.append(room) rooms.append(Room.from_box('CoreRoom', 10, 10, 3, origin=Point3D(10, 10))) adj_info = Room.solve_adjacency(rooms, 0.01) for face_pair in adj_info['adjacent_faces']: face_pair[0].type = face_types.air_boundary face_pair[1].type = face_types.air_boundary model = Model('CorePerimeterOfficeFloor', rooms) model_dict = model.to_dict() assert model_dict['rooms'][-1]['faces'][1]['face_type'] == 'AirBoundary' new_model = Model.from_dict(model_dict) air_face_type = new_model.rooms[-1].faces[1] assert air_face_type.type == face_types.air_boundary assert isinstance(air_face_type.properties.energy.construction, AirBoundaryConstruction) model_idf_str = model.to.idf(model) assert model_idf_str.count('Construction:AirBoundary') == 1 assert model_idf_str.count('ZoneMixing') == 16
def test_envelope_components_by_type(): zone_pts = Face3D([ Point3D(0, 0, 0), Point3D(20, 0, 0), Point3D(20, 10, 0), Point3D(0, 10, 0) ]) room = Room.from_polyface3d('SouthRoom', Polyface3D.from_offset_face(zone_pts, 3)) door_pts = [ Point3D(2, 10, 0.01), Point3D(4, 10, 0.01), Point3D(4, 10, 2.50), Point3D(2, 10, 2.50) ] door = Door('FrontDoor', Face3D(door_pts)) room[3].add_door(door) # Door to north face room[1].apertures_by_ratio(0.3) # Window on south face ext_faces, int_faces = room.properties.energy.envelope_components_by_type() walls, roofs, floors, apertures, doors = ext_faces assert len(walls) == 4 assert len(roofs) == 1 assert len(floors) == 0 assert len(apertures) == 1 assert len(doors) == 1 for types in int_faces: assert len(types) == 0
def __init__(self, identifier, faces, tolerance=0, angle_tolerance=0): """Initialize Room.""" _BaseWithShade.__init__(self, identifier) # process the identifier # process the zone volume geometry if not isinstance(faces, tuple): faces = tuple(faces) for face in faces: assert isinstance(face, Face), \ 'Expected honeybee Face. Got {}'.format(type(face)) face._parent = self if tolerance == 0: self._faces = faces self._geometry = None # calculated later from faces or added by classmethods else: # try to get a closed volume between the faces room_polyface = Polyface3D.from_faces( tuple(face.geometry for face in faces), tolerance) if not room_polyface.is_solid and angle_tolerance != 0: ang_tol = math.radians(angle_tolerance) room_polyface = room_polyface.merge_overlapping_edges( tolerance, ang_tol) # replace honeybee face geometry with versions that are facing outwards if room_polyface.is_solid: for i, correct_face3d in enumerate(room_polyface.faces): faces[i]._geometry = correct_face3d self._faces = faces self._geometry = room_polyface self._multiplier = 1 # default value that can be overridden later self._story = None # default value that can be overridden later self._properties = RoomProperties(self) # properties for extensions
def test_polyface3d_init_from_polyface(): """Test the initalization of room from a Poyface3D.""" bound_pts = [Point3D(0, 0), Point3D(3, 0), Point3D(3, 3), Point3D(0, 3)] hole_pts = [ Point3D(1, 1, 0), Point3D(2, 1, 0), Point3D(2, 2, 0), Point3D(1, 2, 0) ] face = Face3D(bound_pts, None, [hole_pts]) polyface = Polyface3D.from_offset_face(face, 3) room = Room.from_polyface3d('Donut Zone', polyface) assert room.name == 'DonutZone' assert room.display_name == 'Donut Zone' assert isinstance(room.geometry, Polyface3D) assert len(room.geometry.vertices) == 16 assert len(room) == 10 assert room.center == Point3D(1.5, 1.5, 1.5) assert room.volume == 24 assert room.floor_area == 8 assert room.exposed_area == 56 assert room.exterior_wall_area == 48 assert room.exterior_aperture_area == 0 assert room.average_floor_height == 0 assert not room.has_parent assert room.check_solid(0.01, 1)
def geometry(self): """Get a ladybug_geometry Polyface3D object representing the room.""" if self._geometry is None: self._geometry = Polyface3D.from_faces( tuple(face.geometry for face in self._faces), 0) # use 0 tolerance return self._geometry
def check_solid(self, tolerance=0.01, angle_tolerance=1, raise_exception=True): """Check whether the Room is a closed solid to within the input tolerances. Args: tolerance: tolerance: The maximum difference between x, y, and z values at which face vertices are considered equivalent. This is used in determining whether the faces form a closed volume. Default: 0.01, suitable for objects in meters. angle_tolerance: The max angle difference in degrees that vertices are allowed to differ from one another in order to consider them colinear. Default: 1 degree. raise_exception: Boolean to note whether a ValueError should be raised if the room geometry does not form a closed solid. """ if self._geometry is not None and self.geometry.is_solid: return True face_geometries = tuple(face.geometry for face in self._faces) self._geometry = Polyface3D.from_faces(face_geometries, tolerance) if self.geometry.is_solid: return True ang_tol = math.radians(angle_tolerance) self._geometry = self.geometry.merge_overlapping_edges( tolerance, ang_tol) if self.geometry.is_solid: return True if raise_exception: raise ValueError( 'Room "{}" is not closed to within {} tolerance and {} angle ' 'tolerance.'.format(self.display_name, tolerance, angle_tolerance)) return False
def model_complete_office_floor(directory): pts_1 = [Point3D(0, 0), Point3D(30, 0), Point3D(20, 10), Point3D(10, 10)] pts_2 = [Point3D(0, 0), Point3D(10, 10), Point3D(10, 20), Point3D(0, 30)] pts_3 = [Point3D(10, 20), Point3D(20, 20), Point3D(30, 30), Point3D(0, 30)] pts_4 = [Point3D(30, 0), Point3D(30, 30), Point3D(20, 20), Point3D(20, 10)] verts = [pts_1, pts_2, pts_3, pts_4] rooms = [] for i, f_vert in enumerate(verts): pface = Polyface3D.from_offset_face(Face3D(f_vert), 3) room = Room.from_polyface3d('PerimeterRoom{}'.format(i), pface) room.properties.energy.program_type = prog_type_lib.office_program room.properties.energy.add_default_ideal_air() rooms.append(room) rooms.append(Room.from_box('CoreRoom', 10, 10, 3, origin=Point3D(10, 10))) adj_info = Room.solve_adjacency(rooms, 0.01) for face_pair in adj_info['adjacent_faces']: face_pair[0].type = face_types.air_boundary face_pair[1].type = face_types.air_boundary for room in rooms: for face in room: if isinstance(face.type, (Floor, RoofCeiling)): face.boundary_condition = boundary_conditions.adiabatic model = Model('Core_Perimeter_Office_Floor', rooms) dest_file = os.path.join(directory, 'model_complete_office_floor.json') with open(dest_file, 'w') as fp: json.dump(model.to_dict(), fp, indent=4)
def to_polyface3d(geo, meshing_parameters=None): """A Ladybug Polyface3D object from a Rhino Brep. Args: geo: A Rhino Brep, Surface or Mesh that will be converted into a single Ladybug Polyface3D. meshing_parameters: Optional Rhino Meshing Parameters to describe how curved faces should be converted into planar elements. If None, Rhino's Default Meshing Parameters will be used. """ mesh_par = meshing_parameters or rg.MeshingParameters.Default # default if not isinstance( geo, rg.Mesh) and _planar.has_curved_face(geo): # keep solidity return Polyface3D.from_faces(_planar.curved_solid_faces(geo, mesh_par), tolerance) return Polyface3D.from_faces(to_face3d(geo, mesh_par), tolerance)
def find_adjacency(rooms, tolerance=0.01): """Get a list with all adjacent pairs of Faces between input rooms. Note that this method does not change any boundary conditions of the input rooms or mutate them in any way. It's purely a geometric analysis of the faces between rooms. Args: rooms: A list of rooms for which adjacencies will be solved. tolerance: The minimum difference between the coordinate values of two faces at which they can be considered centered adjacent. Default: 0.01, suitable for objects in meters. Returns: A list of tuples with each tuple containing 2 objects for Faces that are adjacent to one another. """ adj_faces = [] # lists of adjacencies to track for i, room_1 in enumerate(rooms): try: for room_2 in rooms[i + 1:]: if not Polyface3D.overlapping_bounding_boxes( room_1.geometry, room_2.geometry, tolerance): continue # no overlap in bounding box; adjacency impossible for face_1 in room_1._faces: for face_2 in room_2._faces: if face_1.geometry.is_centered_adjacent( face_2.geometry, tolerance): adj_faces.append((face_1, face_2)) break except IndexError: pass # we have reached the end of the list of zones return adj_faces
def test_intersect_line_ray(): """Test the Polyface3D intersect_line_ray method.""" pts = (Point3D(0, 0, 2), Point3D(2, 0, 2), Point3D(2, 1, 2), Point3D(1, 1, 2), Point3D(1, 2, 2), Point3D(0, 2, 2)) plane = Plane(Vector3D(0, 0, 1), Point3D(0, 0, 2)) face = Face3D(pts, plane) polyface = Polyface3D.from_offset_face(face, 1) ray_1 = Ray3D(Point3D(0.5, 0.5, 0), Vector3D(0, 0, 1)) ray_2 = Ray3D(Point3D(0.5, 0.5, 0), Vector3D(0, 0, -1)) ray_3 = Ray3D(Point3D(1.5, 1.5, 0), Vector3D(0, 0, 1)) ray_4 = Ray3D(Point3D(-1, -1, 0), Vector3D(0, 0, 1)) line_1 = LineSegment3D(Point3D(0.5, 0.5, 0), Vector3D(0, 0, 3)) line_2 = LineSegment3D(Point3D(0.5, 0.5, 0), Vector3D(0, 0, 1)) assert polyface.does_intersect_line_ray_exist(ray_1) is True assert polyface.does_intersect_line_ray_exist(ray_2) is False assert polyface.does_intersect_line_ray_exist(ray_3) is False assert polyface.does_intersect_line_ray_exist(ray_4) is False assert polyface.does_intersect_line_ray_exist(line_1) is True assert polyface.does_intersect_line_ray_exist(line_2) is False assert polyface.intersect_line_ray(ray_1) == [ Point3D(0.5, 0.5, 2), Point3D(0.5, 0.5, 3) ] assert polyface.intersect_line_ray(ray_2) == [] assert polyface.intersect_line_ray(ray_3) == [] assert polyface.intersect_line_ray(ray_4) == [] assert polyface.intersect_line_ray(line_1) == [ Point3D(0.5, 0.5, 2), Point3D(0.5, 0.5, 3) ] assert polyface.intersect_line_ray(line_2) == []
def test_reflect(): """Test the Polyface3D reflect method.""" polyface = Polyface3D.from_box(1, 1, 1, Plane(o=Point3D(1, 1, 2))) origin_1 = Point3D(1, 0, 2) normal_1 = Vector3D(1, 0, 0) normal_2 = Vector3D(-1, -1, 0).normalize() test_1 = polyface.reflect(normal_1, origin_1) assert test_1[0].x == pytest.approx(1, rel=1e-3) assert test_1[0].y == pytest.approx(1, rel=1e-3) assert test_1[0].z == pytest.approx(2, rel=1e-3) assert test_1[2].x == pytest.approx(0, rel=1e-3) assert test_1[2].y == pytest.approx(2, rel=1e-3) assert test_1[2].z == pytest.approx(2, rel=1e-3) test_1 = polyface.reflect(normal_2, Point3D(0, 0, 2)) assert test_1[0].x == pytest.approx(-1, rel=1e-3) assert test_1[0].y == pytest.approx(-1, rel=1e-3) assert test_1[0].z == pytest.approx(2, rel=1e-3) assert test_1[2].x == pytest.approx(-2, rel=1e-3) assert test_1[2].y == pytest.approx(-2, rel=1e-3) assert test_1[2].z == pytest.approx(2, rel=1e-3) test_2 = polyface.reflect(normal_2, origin_1) assert test_2[0].x == pytest.approx(0, rel=1e-3) assert test_2[0].y == pytest.approx(0, rel=1e-3) assert test_2[0].z == pytest.approx(2, rel=1e-3) assert test_2[2].x == pytest.approx(-1, rel=1e-3) assert test_2[2].y == pytest.approx(-1, rel=1e-3) assert test_2[2].z == pytest.approx(2, rel=1e-3)
def test_rotate(): """Test the Polyface3D rotate method.""" polyface = Polyface3D.from_box(2, 2, 2, Plane(o=Point3D(0, 0, 2))) origin = Point3D(0, 0, 0) axis = Vector3D(1, 0, 0) test_1 = polyface.rotate(axis, math.pi, origin) assert test_1[0].x == pytest.approx(0, rel=1e-3) assert test_1[0].y == pytest.approx(0, rel=1e-3) assert test_1[0].z == pytest.approx(-2, rel=1e-3) assert test_1[2].x == pytest.approx(2, rel=1e-3) assert test_1[2].y == pytest.approx(-2, rel=1e-3) assert test_1[2].z == pytest.approx(-2, rel=1e-3) assert polyface.area == test_1.area assert polyface.volume == test_1.volume assert len(polyface.vertices) == len(test_1.vertices) test_2 = polyface.rotate(axis, math.pi / 2, origin) assert test_2[0].x == pytest.approx(0, rel=1e-3) assert test_2[0].y == pytest.approx(-2, rel=1e-3) assert test_2[0].z == pytest.approx(0, rel=1e-3) assert test_2[2].x == pytest.approx(2, rel=1e-3) assert test_2[2].y == pytest.approx(-2, rel=1e-3) assert test_2[2].z == pytest.approx(2, rel=1e-3) assert polyface.area == test_2.area assert polyface.volume == test_1.volume assert len(polyface.vertices) == len(test_2.vertices)
def test_polyface3d_init_open(): """Test the initalization of Poyface3D and basic properties of open objects.""" pts = [ Point3D(0, 0, 0), Point3D(0, 2, 0), Point3D(2, 2, 0), Point3D(2, 0, 0), Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2) ] face_indices = [[(0, 1, 2, 3)], [(0, 4, 5, 1)], [(0, 3, 7, 4)], [(2, 1, 5, 6)], [(2, 3, 7, 6)]] polyface = Polyface3D(pts, face_indices) assert len(polyface.vertices) == 8 assert len(polyface.face_indices) == 5 assert len(polyface.faces) == 5 assert len(polyface.edge_indices) == 12 assert len(polyface.edges) == 12 assert len(polyface.naked_edges) == 4 assert len(polyface.non_manifold_edges) == 0 assert len(polyface.internal_edges) == 8 assert polyface.area == 20 assert polyface.volume == 0 assert polyface.is_solid is False for face in polyface.faces: assert face.area == 4 assert face.is_clockwise is False
def test_bounding_rectangle(): """Test the bounding_rectangle methods with arrays of 3D objects.""" plane1 = Plane(o=Point3D(-5, 0, 0)) plane2 = Plane(o=Point3D(0, -4, 4)) plane3 = Plane(o=Point3D(2, 2, -4)) polyface1 = Polyface3D.from_box(2, 4, 2, plane1) polyface2 = Polyface3D.from_box(2, 4, 2, plane2) polyface3 = Polyface3D.from_box(2, 4, 2, plane3) min_pt, max_pt = bounding_rectangle([polyface1, polyface2, polyface3]) assert min_pt == Point2D(-5, -4) assert max_pt == Point2D(4, 6) x_dom, y_dom = bounding_rectangle_extents( [polyface1, polyface2, polyface3]) assert x_dom == 9 assert y_dom == 10
def test_afn_plenum_zone(): """Test case where no infiltration load exists.""" zone_pts = Face3D( [Point3D(0, 0), Point3D(20, 0), Point3D(20, 10), Point3D(0, 10)]) room = Room.from_polyface3d('PlenumRoom', Polyface3D.from_offset_face(zone_pts, 1)) room.properties.energy.program_type = prog_type_lib.plenum_program # Make model model = Model('PlenumSimple', [room]) # generate afn, w/ average leakage afn.generate(model.rooms, leakage_type='Medium', use_room_infiltration=True) faces = model.faces # check ext wall crack = faces[1].properties.energy.vent_crack chk_cof = CRACK_TEMPLATE_DATA['external_medium_cracks']['wall_flow_cof'] chk_exp = CRACK_TEMPLATE_DATA['external_medium_cracks']['wall_flow_exp'] assert crack.flow_coefficient == pytest.approx(chk_cof * faces[1].area, abs=1e-10) assert crack.flow_exponent == pytest.approx(chk_exp, abs=1e-10) # check roof crack = faces[5].properties.energy.vent_crack chk_cof = CRACK_TEMPLATE_DATA['external_medium_cracks']['roof_flow_cof'] chk_exp = CRACK_TEMPLATE_DATA['external_medium_cracks']['roof_flow_exp'] assert crack.flow_coefficient == pytest.approx(chk_cof * faces[5].area, abs=1e-10) assert crack.flow_exponent == pytest.approx(chk_exp, abs=1e-10) # generate afn, w/ tight leakage afn.generate(model.rooms, leakage_type='Excellent', use_room_infiltration=False) faces = model.faces # check ext wall crack = faces[1].properties.energy.vent_crack chk_cof = CRACK_TEMPLATE_DATA['external_excellent_cracks']['wall_flow_cof'] chk_exp = CRACK_TEMPLATE_DATA['external_excellent_cracks']['wall_flow_exp'] assert crack.flow_coefficient == pytest.approx(chk_cof * faces[1].area, abs=1e-10) assert crack.flow_exponent == pytest.approx(chk_exp, abs=1e-10) # check roof crack = faces[5].properties.energy.vent_crack chk_cof = CRACK_TEMPLATE_DATA['external_excellent_cracks']['roof_flow_cof'] chk_exp = CRACK_TEMPLATE_DATA['external_excellent_cracks']['roof_flow_exp'] assert crack.flow_coefficient == pytest.approx(chk_cof * faces[5].area, abs=1e-10) assert crack.flow_exponent == pytest.approx(chk_exp, abs=1e-10)
def model_complete_holes(directory): bound_pts = [Point3D(0, 0), Point3D(9, 0), Point3D(9, 9), Point3D(0, 9)] hole_pts = [ Point3D(3, 3, 0), Point3D(6, 3, 0), Point3D(6, 6, 0), Point3D(3, 6, 0) ] face = Face3D(bound_pts, None, [hole_pts]) polyface = Polyface3D.from_offset_face(face, 3) room = Room.from_polyface3d('DonutZone', polyface) ap_bound_pts = [ Point3D(0.5, 0, 0.5), Point3D(2.5, 0, 0.5), Point3D(2.5, 0, 2.5), Point3D(0.5, 0, 2.5) ] ap_hole_pts = [ Point3D(1, 0, 1), Point3D(2, 0, 1), Point3D(2, 0, 2), Point3D(1, 0, 2) ] ap_face = Face3D(ap_bound_pts, None, [ap_hole_pts]) ap = Aperture('HoleAperture', ap_face) for face in room.faces: if face.geometry.is_sub_face(ap_face, 0.01, 1.0): face.add_aperture(ap) shd_bound_pts = [ Point3D(0, 0, 6), Point3D(9, 0, 6), Point3D(9, 9, 6), Point3D(0, 9, 6) ] shd_hole_pts1 = [ Point3D(2, 2, 6), Point3D(4, 2, 6), Point3D(4, 4, 6), Point3D(2, 4, 6) ] shd_hole_pts2 = [ Point3D(5, 5, 6), Point3D(7, 5, 6), Point3D(7, 7, 6), Point3D(5, 7, 6) ] s_face = Face3D(shd_bound_pts, None, [shd_hole_pts1, shd_hole_pts2]) shd = Shade('Canopy', s_face) model = Model('Donut_Building', [room], orphaned_shades=[shd]) dest_file = os.path.join(directory, 'model_complete_holes.json') with open(dest_file, 'w') as fp: json.dump(model.to_dict(), fp, indent=4)
def test_bounding_rectangle_angle(): """Test the bounding_rectangle methods with an axis_angle.""" plane1 = Plane(o=Point3D(-5, 0, 0)) plane2 = Plane(o=Point3D(0, -4, 4)) plane3 = Plane(o=Point3D(2, 2, -4)) polyface1 = Polyface3D.from_box(2, 4, 2, plane1) polyface2 = Polyface3D.from_box(2, 4, 2, plane2) polyface3 = Polyface3D.from_box(2, 4, 2, plane3) min_pt, max_pt = bounding_rectangle([polyface1, polyface2, polyface3], 45) assert min_pt.x == pytest.approx(1.45, rel=1e-2) assert min_pt.y == pytest.approx(-4.89, rel=1e-2) assert max_pt.x == pytest.approx(-1.62, rel=1e-2) assert max_pt.y == pytest.approx(9.47, rel=1e-2) x_dom, y_dom = bounding_rectangle_extents( [polyface1, polyface2, polyface3], 45) assert x_dom == pytest.approx(10.6103, rel=1e-2) assert y_dom == pytest.approx(10.1589, rel=1e-2)