예제 #1
0
def _group_by_identifier(sensor_grids):
    """Group sensor grids or views if they have the same full identifier."""
    group_func = lambda grid: grid.full_identifier  # noqa: E731

    ordered_sensor_grids = sorted(sensor_grids, key=group_func)

    # check if there is any duplicated identifiers
    ids = {grid.full_identifier for grid in sensor_grids}
    if len(list(ids)) == len(sensor_grids):
        # there is no duplicated identifier - return the original list
        return sensor_grids

    updated_grids = []
    for group_identifier, grids in itertools.groupby(ordered_sensor_grids, group_func):
        grids = list(grids)
        if len(grids) > 1:
            # merge grids into one
            sensors = []
            for grid in grids:
                sensors.extend(grid.sensors)
            joined_grid = SensorGrid(grids[0].identifier, sensors)
            joined_grid.group_identifier = grids[0].group_identifier
            updated_grids.append(joined_grid)
        else:
            updated_grids.append(grids[0])

    return updated_grids
예제 #2
0
def test_dict_to_object_sensor_grid():
    """Test the dict_to_object method with SensorGrid objects."""
    sensors = [Sensor((0, 0, 0), (0, 0, 1)), Sensor((0, 0, 10), (0, 0, 1))]
    sg_obj = SensorGrid('sg_1', sensors)
    sg_dict = sg_obj.to_dict()
    new_sg = dict_to_object(sg_dict)
    assert isinstance(new_sg, SensorGrid)
예제 #3
0
def test_assigning_group():
    sg = SensorGrid('sg_1', sensors)
    sg.group_identifier = 'floor_1/dining_room'
    str(sg)  # test string representation
    hash(sg)  # test hashability

    assert sg.identifier == 'sg_1'
    assert sg.group_identifier == 'floor_1/dining_room'
    assert len(sg) == 2
    assert sg[0] == sensors[0]
    assert sg[1] == sensors[1]
예제 #4
0
def test_move():
    sensor = Sensor((0, 0, 10), (0, 0, -1))
    sensors = [
        Sensor((0, 0, 0), (0, 0, 1)),
        Sensor((0, 0, 10), (0, 0, 1)), sensor
    ]
    sg = SensorGrid('sg_1', sensors)
    sg.move(pv.Vector3D(10, 20, 30))

    assert sensor.pos == (10, 20, 40)
    assert sensor.dir == (0, 0, -1)
예제 #5
0
def test_reflect():
    sensor = Sensor((1, 0, 2), (2, 0, 0))
    sensors = [
        Sensor((0, 0, 0), (0, 0, 1)),
        Sensor((0, 0, 10), (0, 0, 1)), sensor
    ]
    sg = SensorGrid('sg_1', sensors)
    sg.reflect(Plane(pv.Vector3D(1, 0, 0), pv.Point3D(0, 0, 0)))

    assert round(sensor.pos[0]) == -1
    assert round(sensor.pos[1]) == 0
    assert round(sensor.pos[2]) == 2
    assert round(sensor.dir[0]) == -2
    assert round(sensor.dir[1]) == 0
    assert round(sensor.dir[2]) == 0
예제 #6
0
def test_rotate_xy():
    sensor = Sensor((1, 0, 2), (2, 0, 0))
    sensors = [
        Sensor((0, 0, 0), (0, 0, 1)),
        Sensor((0, 0, 10), (0, 0, 1)), sensor
    ]
    sg = SensorGrid('sg_1', sensors)
    sg.rotate_xy(90, pv.Point3D(0, 0, 0))

    assert round(sensor.pos[0]) == 0
    assert round(sensor.pos[1]) == 1
    assert round(sensor.pos[2]) == 2
    assert round(sensor.dir[0]) == 0
    assert round(sensor.dir[1]) == 2
    assert round(sensor.dir[2]) == 0
예제 #7
0
def test_rotate():
    sensor = Sensor((0, 0, 0), (1, 0, 0))
    sensors = [
        Sensor((0, 0, 0), (0, 0, 1)),
        Sensor((0, 0, 10), (0, 0, 1)), sensor
    ]
    sg = SensorGrid('sg_1', sensors)
    sg.rotate(90, pv.Vector3D(0, 1, 1), pv.Point3D(0, 0, 20))

    assert round(sensor.pos[0], 3) == -14.142
    assert round(sensor.pos[1]) == -10
    assert round(sensor.pos[2]) == 10
    assert round(sensor.dir[0], 1) == 0.0
    assert round(sensor.dir[1], 3) == 0.707
    assert round(sensor.dir[2], 3) == -0.707
예제 #8
0
def test_scale():
    sensor = Sensor((1, 0, 2), (1, 0, 0))
    sensors = [
        Sensor((0, 0, 0), (0, 0, 1)),
        Sensor((0, 0, 10), (0, 0, 1)), sensor
    ]
    sg = SensorGrid('sg_1', sensors)
    sg.scale(2)

    assert round(sensor.pos[0]) == 2
    assert round(sensor.pos[1]) == 0
    assert round(sensor.pos[2]) == 4
    assert round(sensor.dir[0]) == 1
    assert round(sensor.dir[1]) == 0
    assert round(sensor.dir[2]) == 0
예제 #9
0
def test_from_planar_positions():
    positions = [[0, 0, 0], [0, 0, 5], [0, 0, 10]]
    plane_normal = [0, 0, 1]
    sg = SensorGrid.from_planar_positions('test_grid', positions, plane_normal)
    assert len(sg) == 3
    for sensor in sg:
        assert sensor.dir == (0, 0, 1)
예제 #10
0
def test_from_loc_dir():
    positions = [[0, 0, 0], [0, 0, 5], [0, 0, 10]]
    directions = [[0, 0, 1], [0, 0, -1], [0, 0, 10]]
    sg = SensorGrid.from_position_and_direction('sg', positions, directions)
    for count, sensor in enumerate(sg):
        list(sensor.pos) == positions[count]
        list(sensor.dir) == directions[count]
예제 #11
0
    def _load_grids(self) -> None:
        """Load sensor grids."""
        if self._sensor_grids_option == SensorGridOptions.Ignore:
            return
        if hasattr(self._hb_model.properties, 'radiance'):
            # list of unique sensor_grid identifiers in the model
            ids = set([
                grid.identifier
                for grid in self._hb_model.properties.radiance.sensor_grids
            ])

            # if all the grids have the same identifier, merge them into one grid
            if len(ids) == 1:
                id = self._hb_model.properties.radiance.sensor_grids[
                    0].identifier
                sensors = [
                    sensor
                    for grid in self._hb_model.properties.radiance.sensor_grids
                    for sensor in grid.sensors
                ]
                sensor_grid = SensorGrid(id, sensors)
                self._sensor_grids.data.append(
                    convert_sensor_grid(sensor_grid,
                                        self._sensor_grids_option))
            # else add them as separate grids
            else:
                for sensor_grid in self._hb_model.properties.radiance.sensor_grids:
                    self._sensor_grids.data.append(
                        convert_sensor_grid(sensor_grid,
                                            self._sensor_grids_option))
예제 #12
0
def test_from_file():
    sensor_grid = SensorGrid.from_file('./tests/assets/test_points.pts')
    assert sensor_grid.identifier == 'test_points'
    assert sensor_grid[0].pos == (0, 0, 0)
    assert sensor_grid[0].dir == (0, 0, 1)
    assert len(sensor_grid) == 3
    assert sensor_grid[1].to_radiance() == '0.2 0.3 0.4 0.5 0.6 0.7'
    assert sensor_grid[2].to_radiance() == '-10.0 -5.0 0.0 -50.0 -60.0 -70.0'
예제 #13
0
def test_split_single_grid():
    """Test splitting a sensor grid."""
    sensor_grid = SensorGrid.from_file(
        './tests/assets/grid/sensor_grid_split.pts')
    folder = './tests/assets/temp'
    info = sensor_grid.to_files(folder, 1, 'single_grid')
    assert len(info) == 1
    assert info[0]['count'] == sensor_grid.count
예제 #14
0
def test_from_mesh3d():
    mesh_2d = Mesh2D.from_grid(Point2D(1, 1), 8, 2, 0.25, 1)
    mesh = Mesh3D.from_mesh2d(mesh_2d)
    sg = SensorGrid.from_mesh3d('sg_1', mesh)

    assert len(sg.sensors) == 16
    assert len(sg.mesh.vertices) == 27
    assert len(sg.mesh.faces) == 16
    assert mesh.area == 4
def test_to_radial_grid():
    positions = [[0, 0, 0], [0, 0, 5], [0, 0, 10]]
    plane_normal = [0, 0, 1]
    sg = SensorGrid.from_planar_positions('test_grid', positions, plane_normal)
    assert len(sg) == 3

    new_sg = sg.to_radial_grid(dir_count=8)
    assert len(new_sg) == 3 * 8
    assert new_sg.identifier == sg.identifier
예제 #16
0
def test_creation():
    sg = SensorGrid('sg_1', sensors)
    str(sg)  # test string representation
    hash(sg)  # test hashability

    assert sg.identifier == 'sg_1'
    assert len(sg) == 2
    assert sg[0] == sensors[0]
    assert sg[1] == sensors[1]
예제 #17
0
def test_from_rooms_radial():
    runner = CliRunner()
    input_hb_model = './tests/assets/model/model_radiance_dynamic_states.hbjson'

    result = runner.invoke(from_rooms_radial, [input_hb_model])
    assert result.exit_code == 0
    sg_dict = json.loads(result.output)
    new_grids = [SensorGrid.from_dict(sg) for sg in sg_dict]
    assert len(new_grids) == 2
    assert all(isinstance(sg, SensorGrid) for sg in new_grids)
def test_from_positions_radial():
    sg = SensorGrid.from_positions_radial('glare_grid', [(0, 0, 0.8),
                                                         (2, 2, 0.8)],
                                          mesh_radius=1)

    assert len(sg.sensors) == 16
    assert len(list(sg.positions)) == 16
    assert len(list(sg.directions)) == 16
    assert len(sg.mesh.faces) == 16
    print(sg.mesh)
예제 #19
0
    def _aperture_view_factor(project_folder,
                              apertures,
                              size=0.2,
                              ambient_division=1000,
                              receiver='rflux_sky.sky',
                              octree='scene.oct',
                              calc_folder='dmtx_aperture_grouping'):
        """Calculates the view factor for each aperture by sensor points."""

        # Instantiate dictionary that will store the sensor count for each aperture. We need
        # a OrderedDict so that we can split the rfluxmtx output file by each aperture
        # (sensor count) in the correct order.
        ap_dict = OrderedDict()

        meshes = []
        # Create a mesh for each aperture and add the the sensor count to dict.
        for aperture in apertures:
            ap_mesh = aperture.geometry.mesh_grid(size,
                                                  flip=True,
                                                  generate_centroids=False)
            meshes.append(ap_mesh)
            ap_dict[aperture.display_name] = {
                'sensor_count': len(ap_mesh.faces)
            }

        # Create a sensor grid from joined aperture mesh.
        grid_mesh = SensorGrid.from_mesh3d('aperture_grid',
                                           Mesh3D.join_meshes(meshes))

        # Write sensor grid to pts file.
        sensors = grid_mesh.to_file(os.path.join(project_folder, calc_folder),
                                    file_name='apertures')

        # rfluxmtx options
        rfluxOpt = RfluxmtxOptions()
        rfluxOpt.ad = ambient_division
        rfluxOpt.lw = 1.0 / float(rfluxOpt.ad)
        rfluxOpt.I = True
        rfluxOpt.h = True

        # rfluxmtx command
        rflux = Rfluxmtx()
        rflux.options = rfluxOpt
        rflux.receivers = receiver
        rflux.sensors = sensors
        rflux.octree = octree
        rflux.output = os.path.join(calc_folder, 'apertures_vf.mtx')

        # Run rfluxmtx command
        rflux.run(cwd=project_folder)

        # Get the output file of the rfluxmtx command.
        mtx_file = os.path.join(project_folder, rflux.output)

        return mtx_file, ap_dict
예제 #20
0
def test_split_grid_single():
    input_grid = './tests/assets/grid/sensor_grid_single.pts'
    output_folder = './tests/assets/temp'
    runner = CliRunner()
    result = runner.invoke(split_grid, [input_grid, '100', '--folder', output_folder])
    assert result.exit_code == 0
    # check the file is created and named correctly
    pts_file = os.path.join(output_folder, 'sensor_grid_single_0000.pts')
    assert os.path.isfile(pts_file)
    grid = SensorGrid.from_file(pts_file)
    assert grid.count == 21
예제 #21
0
def test_split_grid():
    """Test splitting a sensor grid."""
    sensor_grid = SensorGrid.from_file(
        './tests/assets/grid/sensor_grid_split.pts')
    folder = './tests/assets/temp'
    info = sensor_grid.to_files(folder, 6, 'test_sensor_grid')
    assert len(info) == 6
    for i in range(6 - 1):
        assert info[i]['count'] == 4

    assert info[-1]['count'] == 1
예제 #22
0
def test_to_and_from_dict():
    sg = SensorGrid('sg', sensors)
    sg_dict = sg.to_dict()
    assert sg_dict == {
        'type':
        'SensorGrid',
        'identifier':
        'sg',
        'sensors': [{
            'pos': (0, 0, 0),
            'dir': (0, 0, 1)
        }, {
            'pos': (0, 0, 10),
            'dir': (0, 0, 1)
        }]
    }

    sensor_from = SensorGrid.from_dict(sg_dict)
    assert sensor_from == sg
    assert sg_dict == sensor_from.to_dict()
예제 #23
0
def test_merge_grid():
    base_name = 'sensor_grid_merge'
    input_folder = './tests/assets/grid'
    output_folder = './tests/assets/temp'
    runner = CliRunner()
    result = runner.invoke(
        merge_grid, [input_folder, base_name, '--folder', output_folder])
    assert result.exit_code == 0
    # check the file is created
    pts_file = os.path.join(output_folder, base_name + '.pts')
    assert os.path.isfile(pts_file)
    grid = SensorGrid.from_file(pts_file)
    assert grid.count == 21
예제 #24
0
def test_split_grid():
    input_grid = './tests/assets/grid/sensor_grid_split.pts'
    output_folder = './tests/assets/temp'
    runner = CliRunner()
    result = runner.invoke(split_grid, [input_grid, '5', '--folder', output_folder])
    assert result.exit_code == 0
    # check the file is created
    for count in range(4):
        pts_file = os.path.join(output_folder, 'sensor_grid_split_%04d.pts' % count)
        assert os.path.isfile(pts_file)
        grid = SensorGrid.from_file(pts_file)
        if count != 3:
            assert grid.count == 5
        else:
            assert grid.count == 6
예제 #25
0
def test_invalid_input():
    with pytest.raises(ValueError):
        SensorGrid('sg_1', ((0, 0, 0, 0, 0, 1), ))
예제 #26
0
def test_updating_values():
    sg = SensorGrid('sg_1', sensors)
    # sensor is immutable - hence no assignment
    with pytest.raises(TypeError):
        sg.sensors[0] = Sensor((0, 0, 100), (0, 0, -10))
try:  # import ladybug_rhino dependencies
    from ladybug_rhino.grasshopper import all_required_inputs
    from ladybug_rhino.togeometry import to_mesh3d, to_face3d
except ImportError as e:
    raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))

if all_required_inputs(ghenv.Component):
    # set the default name and process the points to tuples
    name = clean_and_id_rad_string('SensorGrid') if _name_ is None else _name_
    pts = [(pt.X, pt.Y, pt.Z) for pt in _positions]

    # create the sensor grid object
    id = clean_rad_string(name) if '/' not in name else clean_rad_string(
        name.split('/')[0])
    if len(_directions_) == 0:
        grid = SensorGrid.from_planar_positions(id, pts, (0, 0, 1))
    else:
        vecs = [(vec.X, vec.Y, vec.Z) for vec in _directions_]
        grid = SensorGrid.from_position_and_direction(id, pts, vecs)

    # set the display name
    if _name_ is not None:
        grid.display_name = _name_
    if '/' in name:
        grid.group_identifier = \
            '/'.join(clean_rad_string(key) for key in name.split('/')[1:])
    if mesh_ is not None:
        grid.mesh = to_mesh3d(mesh_)
    if base_geo_ is not None:
        grid.base_geometry = to_face3d(base_geo_)
예제 #28
0
            lb_mesh = to_joined_gridded_mesh3d(floor_faces, _grid_size,
                                               _dist_floor_)

            # remove points outside of the room volume if requested
            if remove_out_:
                pattern = [
                    room.geometry.is_point_inside(pt)
                    for pt in lb_mesh.face_centroids
                ]
                lb_mesh, vertex_pattern = lb_mesh.remove_faces(pattern)

            # extract positions and directions from the mesh
            base_points = [from_point3d(pt) for pt in lb_mesh.face_centroids]
            base_poss = [(pt.x, pt.y, pt.z) for pt in lb_mesh.face_centroids]
            base_dirs = [(vec.x, vec.y, vec.z) for vec in lb_mesh.face_normals]

            # create the sensor grid
            s_grid = SensorGrid.from_position_and_direction(
                room.identifier, base_poss, base_dirs)
            s_grid.display_name = clean_rad_string(room.display_name)
            s_grid.room_identifier = room.identifier
            s_grid.mesh = lb_mesh

            # append everything to the lists
            grid.append(s_grid)
            points.append(base_points)
            mesh.append(from_mesh3d(lb_mesh))

    # convert the lists of points to data trees
    points = list_to_data_tree(points)
예제 #29
0
def test_to_radiance():
    sg = SensorGrid('sg', sensors)
    sg.to_radiance() == \
        """0.0 0.0 0.0 0.0 0.0 1.0\n0.0 0.0 10.0 0.0 0.0 1.0"""
try:  # import the honeybee-radiance dependencies
    from honeybee_radiance.sensorgrid import SensorGrid
except ImportError as e:
    raise ImportError('\nFailed to import honeybee_radiance:\n\t{}'.format(e))

try:  # import ladybug_rhino dependencies
    from ladybug_rhino.grasshopper import all_required_inputs
    from ladybug_rhino.togeometry import to_mesh3d
except ImportError as e:
    raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))

if all_required_inputs(ghenv.Component):
    # set the default name and process the points to tuples
    name = 'SensorGrid' if _name_ is None else _name_
    pts = [(pt.X, pt.Y, pt.Z) for pt in _positions]

    # create the sensor grid object
    if len(_directions_) == 0:
        grid = SensorGrid.from_planar_positions(clean_and_id_rad_string(name),
                                                pts, (0, 0, 1))
    else:
        vecs = [(vec.X, vec.Y, vec.Z) for vec in _directions_]
        grid = SensorGrid.from_position_and_direction(
            clean_and_id_rad_string(name), pts, vecs)

    # set the display name
    if _name_ is not None:
        grid.display_name = _name_
    if mesh_ is not None:
        grid.mesh = to_mesh3d(mesh_)