コード例 #1
0
def test_mesh3d_incorrect():
    """Test the initialization of Mesh3D objects with incorrect values."""
    pts = (Point3D(0, 0), Point3D(0, 2), Point3D(2, 2), Point3D(2, 0), Point3D(4, 0))
    with pytest.raises(AssertionError):
        Mesh3D(pts, [(0, 1, 2, 3, 5)])  # too many vertices in a face
    with pytest.raises(AssertionError):
        Mesh3D(pts, [])  # we need at least one face
    with pytest.raises(AssertionError):
        Mesh3D(pts, (0, 1, 2, 3))  # incorrect input type for face
    with pytest.raises(IndexError):
        Mesh3D(pts, [(0, 1, 2, 6)])  # incorrect index used by face
    with pytest.raises(TypeError):
        Mesh3D(pts, [(0.0, 1, 2, 6)])  # incorrect use of floats for face index
コード例 #2
0
def test_equality():
    """Test the equality of Mesh3D objects."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2))
    pts_2 = (Point3D(0.1, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    mesh_dup = mesh.duplicate()
    mesh_alt = Mesh3D(pts_2, [(0, 1, 2, 3)])

    assert mesh is mesh
    assert mesh is not mesh_dup
    assert mesh == mesh_dup
    assert hash(mesh) == hash(mesh_dup)
    assert mesh != mesh_alt
    assert hash(mesh) != hash(mesh_alt)
コード例 #3
0
def test_offset_mesh():
    """Test the offset_mesh method."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2))
    pts_rev = tuple(reversed(pts))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    mesh_rev = Mesh3D(pts_rev, [(0, 1, 2, 3)])

    new_mesh = mesh.offset_mesh(2)
    for v in new_mesh.vertices:
        assert v.z == 0

    new_mesh_rev = mesh_rev.offset_mesh(2)
    for v in new_mesh_rev.vertices:
        assert v.z == 4
コード例 #4
0
def test_mesh3d_init_two_faces():
    """Test the initialization of Mesh3D objects with two faces."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2),
           Point3D(2, 0, 2), Point3D(4, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])

    assert len(mesh.vertices) == 5
    assert len(mesh.faces) == 2
    assert mesh[0] == Point3D(0, 0, 2)
    assert mesh[1] == Point3D(0, 2, 2)
    assert mesh[2] == Point3D(2, 2, 2)
    assert mesh[3] == Point3D(2, 0, 2)
    assert mesh[4] == Point3D(4, 0, 2)
    assert mesh.area == 6

    assert mesh.min == Point3D(0, 0, 2)
    assert mesh.max == Point3D(4, 2, 2)
    assert mesh.center == Point3D(2, 1, 2)

    assert len(mesh.face_areas) == 2
    assert mesh.face_areas[0] == 4
    assert mesh.face_areas[1] == 2
    assert len(mesh.face_centroids) == 2
    assert mesh.face_centroids[0] == Point3D(1, 1, 2)
    assert mesh.face_centroids[1].x == pytest.approx(2.67, rel=1e-2)
    assert mesh.face_centroids[1].y == pytest.approx(0.67, rel=1e-2)
    assert mesh.face_centroids[1].z == pytest.approx(2, rel=1e-2)
    assert mesh._is_color_by_face is False
    assert mesh.colors is None
コード例 #5
0
def test_mesh3d_init():
    """Test the initialization of Mesh3D objects and basic properties."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2,
                                                       2), Point3D(2, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    str(mesh)  # test the string representation of the object

    assert len(mesh.vertices) == 4
    assert len(mesh.faces) == 1
    assert mesh[0] == Point3D(0, 0, 2)
    assert mesh[1] == Point3D(0, 2, 2)
    assert mesh[2] == Point3D(2, 2, 2)
    assert mesh[3] == Point3D(2, 0, 2)
    assert mesh.area == 4

    assert mesh.min == Point3D(0, 0, 2)
    assert mesh.max == Point3D(2, 2, 2)
    assert mesh.center == Point3D(1, 1, 2)

    assert len(mesh.face_areas) == 1
    assert mesh.face_areas[0] == 4
    assert len(mesh.face_centroids) == 1
    assert mesh.face_centroids[0] == Point3D(1, 1, 2)
    assert mesh._is_color_by_face is False
    assert mesh.colors is None
    assert len(mesh.vertex_connected_faces) == 4
    for vf in mesh.vertex_connected_faces:
        assert len(vf) == 1

    mesh.colors = []
    assert mesh.colors is None
コード例 #6
0
def test_rotate():
    """Test the Mesh3D rotate method."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2),
           Point3D(2, 0, 2), Point3D(4, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
    origin = Point3D(0, 0, 0)
    axis = Vector3D(1, 0, 0)

    test_1 = mesh.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 mesh.area == test_1.area
    assert len(mesh.vertices) == len(test_1.vertices)
    assert len(mesh.faces) == len(test_1.faces)

    test_2 = mesh.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 mesh.area == test_2.area
    assert len(mesh.vertices) == len(test_2.vertices)
    assert len(mesh.faces) == len(test_2.faces)
コード例 #7
0
def test_reflect():
    """Test the Mesh3D reflect method."""
    pts = (Point3D(1, 1, 2), Point3D(2, 1, 2), Point3D(2, 2,
                                                       2), Point3D(1, 2, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    origin_1 = Point3D(1, 0, 2)
    normal_1 = Vector3D(1, 0, 0)
    normal_2 = Vector3D(-1, -1, 0).normalize()

    test_1 = mesh.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 = mesh.reflect(normal_2, Point3D(0, 0, 0))
    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 = mesh.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)
コード例 #8
0
    def radial_positions_mesh(positions,
                              dir_count=8,
                              start_vector=Vector3D(0, -1, 0),
                              mesh_radius=1):
        """Generate a Mesh3D resembling a circle around each position.

        Args:
            positions: A list of (x, y ,z) tuples for position of sensors.
            dir_count: A positive integer for the number of radial directions
                to be generated around each position. (Default: 8).
            start_vector: A Vector3D to set the start direction of the generated
                directions. (Default: (0, -1, 0)).
            mesh_radius: A number for the radius of the radial mesh to be
                generated around each sensor. (Default: 1).
        """
        # set up the start vector and rotation angles
        st_vec = Vector3D(start_vector.x, start_vector.y, 0).normalize()
        st_vec = st_vec * mesh_radius
        inc_ang = (math.pi * 2) / dir_count
        st_vec = st_vec.rotate_xy(-inc_ang / 2)
        # loop through the positions and angles to create the mesh
        verts, faces = [], []
        v_count = 0
        for pt in positions:
            st_pt = Point3D(*pt)
            nxt_pt = st_pt.move(st_vec)
            verts.extend([st_pt, nxt_pt])
            for i in range(dir_count - 1):
                new_pt = verts[-1].rotate_xy(inc_ang, st_pt)
                new_f = (v_count, v_count + i + 1, v_count + i + 2)
                verts.append(new_pt)
                faces.append(new_f)
            faces.append((v_count, v_count + dir_count, v_count + 1))
            v_count += (dir_count + 1)
        return Mesh3D(verts, faces)
コード例 #9
0
def test_join_meshes():
    """Test the join_meshes method."""
    pts1 = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2))
    pts2 = (Point3D(2, 2, 2), Point3D(2, 4, 2), Point3D(4, 4, 2), Point3D(4, 2, 2))
    mesh1 = Mesh3D(pts1, [(0, 1, 2, 3)])
    mesh2 = Mesh3D(pts2, [(0, 1, 2, 3)])
    mesh1.face_centroids
    mesh2.face_centroids
    mesh1.face_normals
    mesh2.face_normals

    joined_mesh = Mesh3D.join_meshes([mesh1, mesh2])

    assert isinstance(joined_mesh, Mesh3D)
    assert len(joined_mesh.faces) == 2
    assert len(joined_mesh.vertices) == 8
コード例 #10
0
def test_mesh3d_to_from_dict():
    """Test the to/from dict of Mesh3D objects."""
    pts = (Point3D(0, 0), Point3D(0, 2), Point3D(2, 2), Point3D(2, 0))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    mesh_dict = mesh.to_dict()
    new_mesh = Mesh3D.from_dict(mesh_dict)
    assert isinstance(new_mesh, Mesh3D)
    assert new_mesh.to_dict() == mesh_dict
コード例 #11
0
def to_mesh3d(mesh, color_by_face=True):
    """Ladybug Mesh3D from Rhino Mesh."""
    if isinstance(mesh, Mesh3D):
        return mesh
    elif isinstance(mesh, bpy.types.Object):
        lb_verts = tuple(
            to_point3d(mesh.matrix_world @ pt.co) for pt in mesh.data.vertices)
        lb_faces, colors = _extract_mesh_faces_colors(mesh, mesh.data,
                                                      color_by_face)
        return Mesh3D(lb_verts, lb_faces, colors)
コード例 #12
0
def test_face_normals():
    """Test the Mesh3D face_normals property."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2), Point3D(2, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])

    assert len(mesh.face_normals) == 1
    assert mesh.face_normals[0] == Vector3D(0, 0, -1)
    assert len(mesh.vertex_normals) == 4
    for vert_norm in mesh.vertex_normals:
        assert vert_norm == Vector3D(0, 0, -1)
コード例 #13
0
def test_height_field_mesh():
    """Test the height_field_mesh method."""
    pts = (Point3D(0, 0, 0), Point3D(2, 0, 0), Point3D(2, 2, 0), Point3D(0, 2, 0))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    values = [-1, 0, 1, 2]

    new_mesh = mesh.height_field_mesh(values, (0, 3))
    assert new_mesh[0].z == 0
    assert new_mesh[1].z == 1
    assert new_mesh[2].z == 2
    assert new_mesh[3].z == 3
コード例 #14
0
    def _generate_bottom_from_top(m_top, v_top):
        """Get a joined mesh and vectors for top and bottom from only top vectors."""
        # reverse the vectors and negate all the z values of the sky patch mesh
        verts = tuple(Point3D(pt.x, pt.y, -pt.z) for pt in m_top.vertices)
        faces = tuple(face[::-1] for face in m_top.faces)
        m_bottom = Mesh3D(verts, faces)
        v_bottom = tuple(Vector3D(v.x, v.y, -v.z) for v in v_top)

        # join everything together
        patch_mesh = Mesh3D.join_meshes([m_top, m_bottom])
        patch_vectors = v_top + v_bottom
        return patch_mesh, patch_vectors
コード例 #15
0
    def dome_radial_patches(self, azimuth_count=72, altitude_count=18):
        """Get Vector3Ds and a correcponding Mesh3D for a a radial dome.

        Args:
            azimuth_count: A positive integer for the number of times that
                the horizontal circle will be subdivided into azimuth
                patches. (Default: 72).
            altitude_count: A positive integer for the number of times that
                the dome quarter-circle will be subdivided into altitude
                patches. (Default: 18).

        Returns:
            A tuple with two elements

            -   patch_mesh: A ladybug_geometry Mesh3D that represents the patches at
                the input azimuth_count and altitude_count.

            -   patch_vectors: A list of ladybug_geometry Vector3D with one vector
                per mesh face. These will align with the faces of the patch_mesh.
                All vectors are unit vectors.
        """
        # set up starting vectors and points
        base_vec, rotate_axis = Vector3D(0, 1, 0), Vector3D(1, 0, 0)
        horiz_angle = -2 * math.pi / azimuth_count
        vertical_angle = math.pi / (2 * altitude_count)

        # loop through the patch values and generate points for each vertex
        vertices, faces = [], []
        pt_i = -2  # track the number of vertices in the mesh
        for row_i in range(altitude_count - 1):
            pt_i += 2  # advance the number of vertices by two
            vec1 = base_vec.rotate(rotate_axis, vertical_angle * row_i)
            vec2 = vec1.rotate(rotate_axis, vertical_angle)
            vertices.extend((Point3D(v.x, v.y, v.z) for v in (vec1, vec2)))
            for _ in range(azimuth_count):  # generate the row of patches
                vec3 = vec1.rotate_xy(horiz_angle)
                vec4 = vec2.rotate_xy(horiz_angle)
                vertices.extend((Point3D(v.x, v.y, v.z) for v in (vec3, vec4)))
                faces.append((pt_i, pt_i + 1, pt_i + 3, pt_i + 2))
                pt_i += 2  # advance the number of vertices by two
                vec1, vec2 = vec3, vec4  # reset vec1 and vec2 for the next patch

        # add triangular faces to represent the last circular patch
        end_vert_i = len(vertices)
        start_vert_i = len(vertices) - azimuth_count * 2 - 1
        vertices.append(Point3D(0, 0, 1))
        for tr_i in range(0, azimuth_count * 2, 2):
            faces.append((start_vert_i + tr_i, end_vert_i, start_vert_i + tr_i + 2))

        # create the Mesh3D object and derive the patch vectors from the mesh
        patch_mesh = Mesh3D(vertices, faces)
        patch_vectors = patch_mesh.face_normals
        return patch_mesh, patch_vectors
コード例 #16
0
def test_height_field_mesh_faces():
    """Test the height_field_mesh method with values for faces."""
    pts = (Point3D(0, 0, 0), Point3D(2, 0, 0), Point3D(2, 2, 0),
           Point3D(0, 2, 0), Point3D(4, 0, 0))
    mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
    values = [-1, 1]

    new_mesh = mesh.height_field_mesh(values, (1, 2))
    assert new_mesh[0].z == 1
    assert new_mesh[1].z == 1
    assert new_mesh[2].z == 1.5
    assert new_mesh[3].z == 1.5
    assert new_mesh[4].z == 2
コード例 #17
0
def test_mesh3d_to_from_json():
    """Test the to/from dict with JSON serialization of Mesh3D objects."""
    pts = (Point3D(0, 0), Point3D(0, 2), Point3D(2, 2), Point3D(2, 0))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    mesh_dict = mesh.to_dict()
    geo_file = './tests/json/json_mesh.json'
    with open(geo_file, 'w') as fp:
        json.dump(mesh_dict, fp)
    with open(geo_file, 'r') as fp:
        new_mesh_dict = json.load(fp)
    new_mesh = Mesh3D.from_dict(new_mesh_dict)
    assert isinstance(new_mesh, Mesh3D)
    assert new_mesh.to_dict() == mesh_dict
    os.remove(geo_file)
コード例 #18
0
def test_scale_world_origin():
    """Test the Mesh2D scale method with None origin."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2),
           Point3D(2, 0, 2), Point3D(4, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])

    new_mesh_1 = mesh.scale(2)
    assert new_mesh_1[0] == Point3D(0, 0, 4)
    assert new_mesh_1[1] == Point3D(0, 4, 4)
    assert new_mesh_1[2] == Point3D(4, 4, 4)
    assert new_mesh_1[3] == Point3D(4, 0, 4)
    assert new_mesh_1[4] == Point3D(8, 0, 4)
    assert new_mesh_1.area == 24
    assert len(mesh.vertices) == len(new_mesh_1.vertices)
    assert len(mesh.faces) == len(new_mesh_1.faces)
コード例 #19
0
def test_scale():
    """Test the Mesh3D scale method."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2),
           Point3D(2, 0, 2), Point3D(4, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])
    origin_1 = Point3D(2, 0, 2)

    new_mesh_1 = mesh.scale(2, origin_1)
    assert new_mesh_1[0] == Point3D(-2, 0, 2)
    assert new_mesh_1[1] == Point3D(-2, 4, 2)
    assert new_mesh_1[2] == Point3D(2, 4, 2)
    assert new_mesh_1[3] == Point3D(2, 0, 2)
    assert new_mesh_1[4] == Point3D(6, 0, 2)
    assert new_mesh_1.area == 24
    assert len(mesh.vertices) == len(new_mesh_1.vertices)
    assert len(mesh.faces) == len(new_mesh_1.faces)
コード例 #20
0
def test_move():
    """Test the Mesh3D move method."""
    pts = (Point3D(0, 0, 2), Point3D(0, 2, 2), Point3D(2, 2, 2),
           Point3D(2, 0, 2), Point3D(4, 0, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3), (2, 3, 4)])

    vec_1 = Vector3D(2, 2, -1)
    new_mesh = mesh.move(vec_1)
    assert new_mesh[0] == Point3D(2, 2, 1)
    assert new_mesh[1] == Point3D(2, 4, 1)
    assert new_mesh[2] == Point3D(4, 4, 1)
    assert new_mesh[3] == Point3D(4, 2, 1)
    assert new_mesh[4] == Point3D(6, 2, 1)

    assert mesh.area == new_mesh.area
    assert len(mesh.vertices) == len(new_mesh.vertices)
    assert len(mesh.faces) == len(new_mesh.faces)
コード例 #21
0
    def envelope_mesh(self):
        """Compute a Mesh3D representing the solar envelope boundary."""
        # extract the relevant proprties from the input geometry
        pt2ds, poly2ds = self.geometry_point2ds, self.obstacle_polygon2ds
        vec2ds = self.sun_vector2ds if self.solar_rights else self.sun_vector2ds_reversed
        altitudes = self._sun_altitudes()
        obs_heights = [face[0].z for face in self._obstacle_faces]
        base_height = self.base_height

        # loop through the points to get the height of each one
        pt_heights = self._compute_point_heights(pt2ds, poly2ds, obs_heights,
                                                 vec2ds, altitudes,
                                                 base_height)

        # turn the mesh point heights into a full Mesh3D
        new_vertices = [
            Point3D(pt.x, pt.y, h) for pt, h in zip(pt2ds, pt_heights)
        ]
        return Mesh3D(new_vertices, self._geometry_mesh.faces)
コード例 #22
0
def test_rotate_xy():
    """Test the Mesh3D rotate_xy method."""
    pts = (Point3D(1, 1, 2), Point3D(2, 1, 2), Point3D(2, 2, 2), Point3D(1, 2, 2))
    mesh = Mesh3D(pts, [(0, 1, 2, 3)])
    origin_1 = Point3D(1, 1, 0)

    test_1 = mesh.rotate_xy(math.pi, 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(0, rel=1e-3)
    assert test_1[2].z == pytest.approx(2, rel=1e-3)

    test_2 = mesh.rotate_xy(math.pi / 2, origin_1)
    assert test_2[0].x == pytest.approx(1, rel=1e-3)
    assert test_2[0].y == pytest.approx(1, rel=1e-3)
    assert test_1[0].z == pytest.approx(2, rel=1e-3)
    assert test_2[2].x == pytest.approx(0, rel=1e-3)
    assert test_2[2].y == pytest.approx(2, rel=1e-3)
    assert test_1[2].z == pytest.approx(2, rel=1e-3)
コード例 #23
0
sky_mask, view_vecs = view_sphere.dome_radial_patches(az_count, alt_count)
sky_mask = sky_mask.scale(radius)
if center_pt3d != Point3D():
    m_vec = Vector3D(center_pt3d.x, center_pt3d.y, center_pt3d.z)
    sky_mask = sky_mask.move(m_vec)
if projection_ is not None:
    if projection_.title() == 'Orthographic':
        pts = (Compass.point3d_to_orthographic(pt) for pt in sky_mask.vertices)
    elif projection_.title() == 'Stereographic':
        pts = (Compass.point3d_to_stereographic(pt, radius, center_pt3d)
               for pt in sky_mask.vertices)
    else:
        raise ValueError(
            'Projection type "{}" is not recognized.'.format(projection_))
    pts3d = tuple(Point3D(pt.x, pt.y, center_pt3d.z) for pt in pts)
    sky_mask = Mesh3D(pts3d, sky_mask.faces)
sky_pattern = [True] * len(
    view_vecs)  # pattern to be adjusted by the various masks

# account for the orientation and any of the projection strategies
orient_pattern, strategy_pattern = None, None
if direction is not None:
    orient_pattern, dir_angles = view_sphere.orientation_pattern(
        direction, view_vecs)
    apply_mask_to_sky(sky_pattern, orient_pattern)
    if overhang_proj_ or left_fin_proj_ or right_fin_proj_:
        strategy_pattern = [False] * len(view_vecs)
        if overhang_proj_:
            over_pattern = view_sphere.overhang_pattern(
                direction, overhang_proj_, view_vecs)
            apply_mask_to_base_mask(strategy_pattern, over_pattern,
コード例 #24
0
def to_mesh3d(mesh, color_by_face=True):
    """Ladybug Mesh3D from Rhino Mesh."""
    lb_verts = tuple(to_point3d(pt) for pt in mesh.Vertices)
    lb_faces, colors = _extract_mesh_faces_colors(mesh, color_by_face)
    return Mesh3D(lb_verts, lb_faces, colors)
コード例 #25
0
def draw_dome(dome_data, center, dome_name, legend_par):
    """Draw the dome mesh, compass, legend, and title for a sky dome.

    Args:
        dome_data: List of radiation values for the dome data
        center: Point3D for the center of the sun path.
        dome_name: Text for the dome name, which will appear in the title.
        legend_par: Legend parameters to be used for the dome

    Returns:
        dome_mesh: A colored mesh for the dome based on dome_data.
        dome_compass: A compass for the dome.
        dome_legend: A leend for the colored dome mesh.
        dome_title: A title for the dome.
        values: A list of radiation values that align with the dome_mesh faces.
    """
    # create the dome mesh and ensure patch values align with mesh faces
    if len(dome_data) == 145:  # tregenza sky
        lb_mesh = view_sphere.tregenza_dome_mesh_high_res.scale(radius)
        values = []  # high res dome has 3 x 3 faces per patch; we must convert
        tot_i = 0  # track the total number of patches converted
        for patch_i in view_sphere.TREGENZA_PATCHES_PER_ROW:
            row_vals = []
            for val in dome_data[tot_i:tot_i + patch_i]:
                row_vals.extend([val] * 3)
            for i in range(3):
                values.extend(row_vals)
            tot_i += patch_i
        values = values + [dome_data[-1]
                           ] * 18  # last patch has triangular faces
    else:  #reinhart sky
        lb_mesh = view_sphere.reinhart_dome_mesh.scale(radius)
        values = dome_data + [dome_data[-1]
                              ] * 11  # last patch has triangular faces

    # move and/or rotate the mesh as needed
    if north != 0:
        lb_mesh = lb_mesh.rotate_xy(math.radians(north), Point3D())
    if center != Point3D():
        lb_mesh = lb_mesh.move(Vector3D(center.x, center.y, center.z))

    # project the mesh if requested
    if projection_ is not None:
        if projection_.title() == 'Orthographic':
            pts = (Compass.point3d_to_orthographic(pt)
                   for pt in lb_mesh.vertices)
        elif projection_.title() == 'Stereographic':
            pts = (Compass.point3d_to_stereographic(pt, radius, center)
                   for pt in lb_mesh.vertices)
        else:
            raise ValueError(
                'Projection type "{}" is not recognized.'.format(projection_))
        pts3d = tuple(Point3D(pt.x, pt.y, z) for pt in pts)
        lb_mesh = Mesh3D(pts3d, lb_mesh.faces)

    # output the dome visualization, including legend and compass
    move_fac = radius * 0.15
    min_pt = lb_mesh.min.move(Vector3D(-move_fac, -move_fac, 0))
    max_pt = lb_mesh.max.move(Vector3D(move_fac, move_fac, 0))
    graphic = GraphicContainer(values, min_pt, max_pt, legend_par)
    graphic.legend_parameters.title = 'kWh/m2'
    lb_mesh.colors = graphic.value_colors
    dome_mesh = from_mesh3d(lb_mesh)
    dome_legend = legend_objects(graphic.legend)
    dome_compass = compass_objects(
        Compass(radius, Point2D(center.x, center.y), north), z, None,
        projection_, graphic.legend_parameters.font)

    # construct a title from the metadata
    st, end = metadata[2], metadata[3]
    time_str = '{} - {}'.format(st, end) if st != end else st
    title_txt = '{} Radiation\n{}\n{}'.format(
        dome_name, time_str, '\n'.join([dat for dat in metadata[4:]]))
    dome_title = text_objects(title_txt, graphic.lower_title_location,
                              graphic.legend_parameters.text_height,
                              graphic.legend_parameters.font)

    return dome_mesh, dome_compass, dome_legend, dome_title, values
コード例 #26
0
    def dome_patches(self, division_count=1, subdivide_in_place=False):
        """Get Vector3Ds and a correcponding Mesh3D for a dome.

        Args:
            division_count: A positive integer for the number of times that the
                original Tregenza patches are subdivided. 1 indicates that the
                original Tregenza patches will be used, 2 indicates
                the Reinhart patches will be used, and so on. (Default: 1).
            subdivide_in_place: A boolean to note whether patches should be
                subdivided according to the extension of Tregenza's original
                logic through the Reinhart method (False) or they should be
                simply divided into 4 in place (True). The latter is useful
                for making higher resolution Mesh visualizations of an
                inherently low-resolution dome.

        Returns:
            A tuple with two elements

            -   patch_mesh: A ladybug_geometry Mesh3D that represents the dome at
                the input division_count. There is one quad face per patch except
                for the last circular patch, which is represented by a number of
                triangles equal to division_count * 6.

            -   patch_vectors: A list of ladybug_geometry Vector3D with one vector
                per patch. These will align with the faces of the patch_mesh up
                until the last circular patch, which will have a single vector
                for the several triangular faces. All vectors are unit vectors.
        """
        # compute constants to be used in the generation of patch points
        patch_row_count = self._patch_row_count_array(division_count)
        base_vec = Vector3D(0, 1, 0)
        rotate_axis = Vector3D(1, 0, 0)
        vertical_angle = math.pi / (2 * len(patch_row_count) + division_count) if \
            subdivide_in_place else math.pi / (2 * len(patch_row_count) + 1)

        # loop through the patch values and generate points for each vertex
        vertices, faces = [], []
        pt_i = -2  # track the number of vertices in the mesh
        for row_i, row_count in enumerate(patch_row_count):
            pt_i += 2  # advance the number of vertices by two
            horiz_angle = -2 * math.pi / row_count  # horizontal angle of each patch
            vec01 = base_vec.rotate(rotate_axis, vertical_angle * row_i)
            vec02 = vec01.rotate(rotate_axis, vertical_angle)
            correction_angle = -horiz_angle / 2
            if subdivide_in_place:
                correction_angle * division_count
            vec1 = vec01.rotate_xy(correction_angle)
            vec2 = vec02.rotate_xy(correction_angle)
            vertices.extend((Point3D(v.x, v.y, v.z) for v in (vec1, vec2)))
            for _ in range(row_count):  # generate the row of patches
                vec3 = vec1.rotate_xy(horiz_angle)
                vec4 = vec2.rotate_xy(horiz_angle)
                vertices.extend((Point3D(v.x, v.y, v.z) for v in (vec3, vec4)))
                faces.append((pt_i, pt_i + 1, pt_i + 3, pt_i + 2))
                pt_i += 2  # advance the number of vertices by two
                vec1, vec2 = vec3, vec4  # reset vec1 and vec2 for the next patch

        # add triangular faces to represent the last circular patch
        end_vert_i = len(vertices)
        start_vert_i = len(vertices) - patch_row_count[-1] * 2 - 1
        vertices.append(Point3D(0, 0, 1))
        for tr_i in range(0, patch_row_count[-1] * 2, 2):
            faces.append((start_vert_i + tr_i, end_vert_i, start_vert_i + tr_i + 2))

        # create the Mesh3D object and derive the patch vectors from the mesh
        patch_mesh = Mesh3D(vertices, faces)
        patch_vectors = patch_mesh.face_normals[:-patch_row_count[-1]] + \
            (Vector3D(0, 0, 1),)
        return patch_mesh, patch_vectors