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 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 solve_adjacency(rooms, tolerance=0.01): """Solve for all adjacencies between a list of input 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 dictionary of adjacency information with the following keys. - adjacent_faces - A list of tuples with each tuple containing 2 objects for Faces paired in the process of solving adjacency. This data can be used to assign custom properties to the new adjacent Faces (like making all adjacencies an AirBoundary face type or assigning custom materials/constructions). - adjacent_apertures - A list of tuples with each tuple containing 2 objects for Apertures paired in the process of solving adjacency. - adjacent_doors - A list of tuples with each tuple containing 2 objects for Doors paired in the process of solving adjacency. """ # lists of adjacencies to track adj_info = { 'adjacent_faces': [], 'adjacent_apertures': [], 'adjacent_doors': [] } # solve all adjacencies between rooms 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 not isinstance(face_2.boundary_condition, Surface): if face_1.geometry.is_centered_adjacent( face_2.geometry, tolerance): face_info = face_1.set_adjacency(face_2) adj_info['adjacent_faces'].append( (face_1, face_2)) adj_info['adjacent_apertures'].extend( face_info['adjacent_apertures']) adj_info['adjacent_doors'].extend( face_info['adjacent_doors']) break except IndexError: pass # we have reached the end of the list of zones return adj_info