Beispiel #1
0
def transform_extrusion(extrusion: 'Vertex', m: Matrix44) -> Tuple[Vec3, bool]:
    """
    Transforms the old `extrusion` vector into a new extrusion vector. Returns the new extrusion vector and a
    boolean value: ``True`` if the new OCS established by the new extrusion vector has a uniform scaled xy-plane,
    else ``False``.

    The new extrusion vector is perpendicular to plane defined by the transformed x- and y-axis.

    Args:
        extrusion: extrusion vector of the old OCS
        m: transformation matrix

    Returns:

    """
    ocs = OCS(extrusion)
    ocs_x_axis_in_wcs = ocs.to_wcs(X_AXIS)
    ocs_y_axis_in_wcs = ocs.to_wcs(Y_AXIS)
    x_axis, y_axis = m.transform_directions(
        (ocs_x_axis_in_wcs, ocs_y_axis_in_wcs))

    # Not sure if this is the correct test for a uniform scaled xy-plane
    is_uniform = math.isclose(x_axis.magnitude_square,
                              y_axis.magnitude_square,
                              abs_tol=1e-9)
    new_extrusion = x_axis.cross(y_axis).normalize()
    return new_extrusion, is_uniform
Beispiel #2
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