Beispiel #1
0
def label_face(face, _attribute_, _font_, label_text, base_pts, labels, wire_frame):
    """Generate labels for a face or sub-face and add it to a list."""
    face_prop = get_attr_nested(face, _attribute_)

    # get a base plane and text height for the text label
    cent_pt = face.geometry.center  # base point for the text
    base_plane = Plane(face.normal, cent_pt)
    if base_plane.y.z < 0:  # base plane pointing downwards; rotate it
        base_plane = base_plane.rotate(base_plane.n, math.pi, base_plane.o)
    if _txt_height_ is None:  # auto-calculate default text height
        txt_len = len(face_prop) if len(face_prop) > 10 else 10
        largest_dim = max((face.geometry.max.x - face.geometry.min.x),
                           (face.geometry.max.y - face.geometry.min.y))
        txt_h = largest_dim / (txt_len * 2)
    else:
        txt_h = _txt_height_

    # move base plane origin a little to avoid overlaps of adjacent labels
    if base_plane.n.x != 0:
        m_vec = base_plane.y if base_plane.n.x < 0 else -base_plane.y
    else:
        m_vec = base_plane.y if base_plane.n.z < 0 else -base_plane.y
    base_plane = base_plane.move(m_vec * txt_h)

    # create the text label
    label = text_objects(face_prop, base_plane, txt_h, font=_font_,
                         horizontal_alignment=1, vertical_alignment=3)

    # append everything to the lists
    label_text.append(face_prop)
    base_pts.append(from_plane(base_plane))
    labels.append(label)
    wire_frame.extend(from_face3d_to_wireframe(face.geometry))
Beispiel #2
0
    def aperture_by_width_height(self,
                                 width,
                                 height,
                                 sill_height=1,
                                 aperture_name=None):
        """Add a single rectangular aperture to the center of this face.

        While the resulting aperture will always be in the plane of this Face,
        this method will not check to ensure that the aperture has all of its
        vertices completely within the boundary of this Face. The
        are_sub_faces_valid() method can be used afterwards to check this.

        Args:
            width: A number for the Aperture width.
            height: A number for the Aperture height.
            sill_height: A number for the sill height. Default: 1.
            aperture_name: Optional name for the aperture. If None, the default name
                will follow the convention "[face_name]_Glz[count]" where [count]
                is one more than the current numer of apertures in the face.
        
        Returns:
            The new Aperture object that has been generated.

        Usage:
            room = Room.from_box(3.0, 6.0, 3.2, 180)
            room[1].aperture_by_width_height(2, 2, .7)  # aperture in front
            room[2].aperture_by_width_height(4, 1.5, .5)  # aperture on right
            room[2].aperture_by_width_height(4, 0.5, 2.2)  # aperture on right
        """
        # Perform checks
        self._acceptable_sub_face_check(Aperture)
        # Generate the aperture geometry
        face_plane = Plane(self._geometry.plane.n, self._geometry.min)
        if face_plane.y.z < 0:
            face_plane = face_plane.rotate(face_plane.n, math.pi, face_plane.o)
        center2d = face_plane.xyz_to_xy(self._geometry.center)
        x_dist = width / 2
        lower_left = Point2D(center2d.x - x_dist, sill_height)
        lower_right = Point2D(center2d.x + x_dist, sill_height)
        upper_right = Point2D(center2d.x + x_dist, sill_height + height)
        upper_left = Point2D(center2d.x - x_dist, sill_height + height)
        ap_verts2d = (lower_left, lower_right, upper_right, upper_left)
        ap_verts3d = tuple(face_plane.xy_to_xyz(pt) for pt in ap_verts2d)
        ap_face = Face3D(ap_verts3d, self._geometry.plane)
        if self.normal.angle(ap_face.normal) > math.pi / 2:  # reversed normal
            ap_face = ap_face.flip()

        # Create the aperture and add it to this Face
        name = aperture_name or '{}_Glz{}'.format(self.display_name,
                                                  len(self.apertures))
        aperture = Aperture(name, ap_face)
        aperture._parent = self
        self._apertures.append(aperture)
        return aperture
Beispiel #3
0
def test_rotate():
    """Test the Plane rotate method."""
    pt = Point3D(2, 2, 2)
    vec = Vector3D(0, 2, 0)
    plane = Plane(vec, pt)
    origin_1 = Point3D(0, 0, 0)
    axis_1 = Vector3D(1, 0, 0)

    test_1 = plane.rotate(axis_1, math.pi, origin_1)
    assert test_1.o.x == pytest.approx(2, rel=1e-3)
    assert test_1.o.y == pytest.approx(-2, rel=1e-3)
    assert test_1.o.z == pytest.approx(-2, rel=1e-3)
    assert test_1.n.x == pytest.approx(0, rel=1e-3)
    assert test_1.n.y == pytest.approx(-1, rel=1e-3)
    assert test_1.n.z == pytest.approx(0, rel=1e-3)
    assert test_1.x.x == pytest.approx(1, rel=1e-3)
    assert test_1.x.y == pytest.approx(0, rel=1e-3)
    assert test_1.x.z == pytest.approx(0, rel=1e-3)
    assert test_1.y.x == pytest.approx(0, rel=1e-3)
    assert test_1.y.y == pytest.approx(0, rel=1e-3)
    assert test_1.y.z == pytest.approx(1, rel=1e-3)
    assert test_1.k == pytest.approx(2, rel=1e-3)

    test_2 = plane.rotate(axis_1, math.pi/2, origin_1)
    assert test_2.o.x == pytest.approx(2, rel=1e-3)
    assert test_2.o.y == pytest.approx(-2, rel=1e-3)
    assert test_2.o.z == pytest.approx(2, rel=1e-3)
    assert test_2.n.x == pytest.approx(0, rel=1e-3)
    assert test_2.n.y == pytest.approx(0, rel=1e-3)
    assert test_2.n.z == pytest.approx(1, rel=1e-3)
    assert test_2.x.x == pytest.approx(1, rel=1e-3)
    assert test_2.x.y == pytest.approx(0, rel=1e-3)
    assert test_2.x.z == pytest.approx(0, rel=1e-3)
    assert test_2.y.x == pytest.approx(0, rel=1e-3)
    assert test_2.y.y == pytest.approx(1, rel=1e-3)
    assert test_2.y.z == pytest.approx(0, rel=1e-3)
    assert test_2.k == pytest.approx(2, rel=1e-3)
Beispiel #4
0
    def rotate(self, angle, axis=None, origin=None):
        """Rotate this view by a certain angle around an axis and origin.

        Args:
            angle: An angle for rotation in degrees.
            axis: Rotation axis as a Vector3D. If None, self.up_vector will be
                used. (Default: None).
            origin: A ladybug_geometry Point3D for the origin around which the
                object will be rotated. If None, self.position is used. (Default: None).
        """
        view_up_vector = pv.Vector3D(*self.up_vector)
        view_position = pv.Point3D(*self.position)
        view_direction = pv.Vector3D(*self.direction)
        view_plane = Plane(n=view_up_vector, o=view_position, x=view_direction)
        axis = axis if axis is not None else view_up_vector
        position = origin if origin is not None else view_position

        rotated_plane = view_plane.rotate(axis, math.radians(angle), position)
        self._apply_plane_properties(rotated_plane, view_direction, view_up_vector)