Beispiel #1
0
    def transform(self, m: Matrix44) -> 'MText':
        """ Transform the MTEXT entity by transformation matrix `m` inplace. """
        dxf = self.dxf
        old_extrusion = Vec3(dxf.extrusion)
        new_extrusion, _ = transform_extrusion(old_extrusion, m)

        if dxf.hasattr('rotation') and not dxf.hasattr('text_direction'):
            # MTEXT is not an OCS entity, but I don't know how else to convert
            # a rotation angle for an entity just defined by an extrusion vector.
            # It's correct for the most common case: extrusion=(0, 0, 1)
            ocs = OCS(old_extrusion)
            dxf.text_direction = ocs.to_wcs(Vec3.from_deg_angle(dxf.rotation))

        dxf.discard('rotation')

        old_text_direction = Vec3(dxf.text_direction)
        new_text_direction = m.transform_direction(old_text_direction)

        old_char_height_vec = old_extrusion.cross(
            old_text_direction).normalize(dxf.char_height)
        new_char_height_vec = m.transform_direction(old_char_height_vec)
        oblique = new_text_direction.angle_between(new_char_height_vec)
        dxf.char_height = new_char_height_vec.magnitude * math.sin(oblique)

        if dxf.hasattr('width'):
            width_vec = old_text_direction.normalize(dxf.width)
            dxf.width = m.transform_direction(width_vec).magnitude

        dxf.insert = m.transform(dxf.insert)
        dxf.text_direction = new_text_direction
        dxf.extrusion = new_extrusion
        return self
 def transform(self, m: Matrix44):
     self.bounding_box = BoundingBox([
         m.transform(self.bounding_box.extmin),
         m.transform(self.bounding_box.extmax),
     ])
     for e in self.entities:
         e.transform(m)
Beispiel #3
0
 def transform(self, m: Matrix44) -> "Point":
     """Transform the POINT entity by transformation matrix `m` inplace."""
     self.dxf.location = m.transform(self.dxf.location)
     transform_thickness_and_extrusion_without_ocs(self, m)
     # ignore dxf.angle!
     self.post_transform(m)
     return self
Beispiel #4
0
    def transform(self, m: Matrix44) -> "MText":
        """Transform the MTEXT entity by transformation matrix `m` inplace."""
        dxf = self.dxf
        old_extrusion = Vec3(dxf.extrusion)
        new_extrusion, _ = transform_extrusion(old_extrusion, m)
        self.convert_rotation_to_text_direction()

        old_text_direction = Vec3(dxf.text_direction)
        new_text_direction = m.transform_direction(old_text_direction)

        old_vertical_direction = old_extrusion.cross(old_text_direction)
        old_char_height_vec = old_vertical_direction.normalize(dxf.char_height)
        new_char_height_vec = m.transform_direction(old_char_height_vec)
        oblique = new_text_direction.angle_between(new_char_height_vec)
        dxf.char_height = new_char_height_vec.magnitude * math.sin(oblique)

        if dxf.hasattr("width"):
            width_vec = old_text_direction.normalize(dxf.width)
            dxf.width = m.transform_direction(width_vec).magnitude

        dxf.insert = m.transform(dxf.insert)
        dxf.text_direction = new_text_direction
        dxf.extrusion = new_extrusion
        if self.has_columns:
            hscale = m.transform_direction(
                old_text_direction.normalize()).magnitude
            vscale = m.transform_direction(
                old_vertical_direction.normalize()).magnitude
            self._columns.transform(m, hscale, vscale)  # type: ignore
        self.post_transform(m)
        return self
Beispiel #5
0
 def transform(self, m: Matrix44) -> 'XLine':
     """ Transform the XLINE/RAY entity by transformation matrix `m` inplace.
     """
     self.dxf.start = m.transform(self.dxf.start)
     self.dxf.unit_vector = m.transform_direction(
         self.dxf.unit_vector).normalize()
     return self
Beispiel #6
0
    def transform(self, m: Matrix44) -> 'Point':
        """ Transform POINT entity by transformation matrix `m` inplace.

        .. versionadded:: 0.13

        """
        self.dxf.location = m.transform(self.dxf.location)
        transform_thickness_and_extrusion_without_ocs(self, m)
        # ignore dxf.angle!
        return self
Beispiel #7
0
def transform_xdata_tags(tags: Tags, m: Matrix44) -> Iterator[DXFTag]:
    for tag in tags:
        code, value = tag
        if code == 1011:
            # move, scale, rotate and mirror
            yield dxftag(code, m.transform(Vec3(value)))
        elif code == 1012:
            # scale, rotate and mirror
            yield dxftag(code, m.transform_direction(Vec3(value)))
        elif code == 1013:
            # rotate and mirror
            vec = Vec3(value)
            length = vec.magnitude
            if length > 1e-12:
                vec = m.transform_direction(vec).normalize(length)
                yield dxftag(code, vec)
            else:
                yield tag
        elif code == 1041 or code == 1042:
            # scale distance and factor, works only for uniform scaling
            vec = m.transform_direction(Vec3(value, 0, 0))
            yield dxftag(code, vec.magnitude)
        else:
            yield tag
Beispiel #8
0
    def transform(self, m: Matrix44) -> None:
        """ Transform ellipse in place by transformation matrix `m`. """
        new_center = m.transform(self.center)
        # 2021-01-28 removed % math.tau
        old_start_param = start_param = self.start_param
        old_end_param = end_param = self.end_param
        old_minor_axis = minor_axis(self.major_axis, self.extrusion,
                                    self.ratio)
        new_major_axis, new_minor_axis = m.transform_directions(
            (self.major_axis, old_minor_axis))
        # Original ellipse parameters stay untouched until end of transformation
        dot_product = new_major_axis.normalize().dot(
            new_minor_axis.normalize())
        if abs(dot_product) > 1e-6:
            new_major_axis, new_minor_axis, new_ratio = rytz_axis_construction(
                new_major_axis, new_minor_axis)
            new_extrusion = new_major_axis.cross(new_minor_axis).normalize()
            adjust_params = True
        else:
            # New axis are nearly orthogonal:
            new_ratio = new_minor_axis.magnitude / new_major_axis.magnitude
            # New normal vector:
            new_extrusion = new_major_axis.cross(new_minor_axis).normalize()
            # Calculate exact minor axis:
            new_minor_axis = minor_axis(new_major_axis, new_extrusion,
                                        new_ratio)
            adjust_params = False

        if adjust_params and not math.isclose(
                start_param, end_param, abs_tol=1e-9):
            # open ellipse, adjusting start- and end parameter
            x_axis = new_major_axis.normalize()
            y_axis = new_minor_axis.normalize()
            # TODO: use ellipse_param_span()?
            #  2021-01-28 this is possibly the source of errors!
            old_param_span = (end_param - start_param) % math.tau

            def param(vec: 'Vec3') -> float:
                dy = y_axis.dot(vec) / new_ratio  # adjust to circle
                dx = x_axis.dot(vec)
                return math.atan2(dy, dx) % math.tau

            # transformed start- and end point of old ellipse
            start_point = m.transform(
                vertex(start_param, self.major_axis, old_minor_axis,
                       self.center, self.ratio))
            end_point = m.transform(
                vertex(end_param, self.major_axis, old_minor_axis, self.center,
                       self.ratio))

            start_param = param(start_point - new_center)
            end_param = param(end_point - new_center)

            # Test if drawing the correct side of the curve
            if not math.isclose(old_param_span, math.pi, abs_tol=1e-9):
                # Equal param span check works well, except for a span of exact
                # pi (180 deg).
                # TODO: use ellipse_param_span()?
                #  2021-01-28 this is possibly the source of errors!
                new_param_span = (end_param - start_param) % math.tau
                if not math.isclose(
                        old_param_span, new_param_span, abs_tol=1e-9):
                    start_param, end_param = end_param, start_param
            else:  # param span is exact pi (180 deg)
                # expensive but it seem to work:
                old_chk_point = m.transform(
                    vertex(
                        mid_param(old_start_param, old_end_param),
                        self.major_axis,
                        old_minor_axis,
                        self.center,
                        self.ratio,
                    ))
                new_chk_point = vertex(
                    mid_param(start_param, end_param),
                    new_major_axis,
                    new_minor_axis,
                    new_center,
                    new_ratio,
                )
                if not old_chk_point.isclose(new_chk_point, abs_tol=1e-9):
                    start_param, end_param = end_param, start_param

        if new_ratio > 1:
            new_major_axis = minor_axis(new_major_axis, new_extrusion,
                                        new_ratio)
            new_ratio = 1.0 / new_ratio
            new_minor_axis = minor_axis(new_major_axis, new_extrusion,
                                        new_ratio)
            if not (math.isclose(start_param, 0)
                    and math.isclose(end_param, math.tau)):
                start_param -= pi2
                end_param -= pi2

        # TODO: remove normalize start- and end params?
        #  2021-01-28 this is possibly the source of errors!
        start_param = start_param % math.tau
        end_param = end_param % math.tau
        if math.isclose(start_param, end_param):
            start_param = 0.0
            end_param = math.tau

        self.center = new_center
        self.major_axis = new_major_axis
        self.minor_axis = new_minor_axis
        self.extrusion = new_extrusion
        self.ratio = new_ratio
        self.start_param = start_param
        self.end_param = end_param
 def transform(self, mat: Matrix44):
     v0 = Vector(self.X, self.Y, self.Z)
     v1 = mat.transform(v0)
     self.X = v1.x
     self.Y = v1.y
     self.Z = v1.z