Beispiel #1
0
 def __init__(self,
              curve,
              algorithm,
              scale_all,
              axis,
              t_min,
              t_max,
              up_axis=None,
              resolution=50,
              length_mode='T'):
     self.curve = curve
     self.axis = axis
     self.t_min = t_min
     self.t_max = t_max
     self.algorithm = algorithm
     self.scale_all = scale_all
     self.up_axis = up_axis
     self.length_mode = length_mode
     if algorithm == SvBendAlongCurveField.ZERO:
         self.curve.pre_calc_torsion_integral(resolution)
     elif algorithm == SvBendAlongCurveField.TRACK_NORMAL:
         self.normal_tracker = SvNormalTrack(curve, resolution)
     if length_mode == 'L':
         self.length_solver = SvCurveLengthSolver(curve)
         self.length_solver.prepare('SPL', resolution)
     self.__description__ = "Bend along {}".format(curve)
Beispiel #2
0
 def set_length(self, base_curve, curve, t_ext, sign=1):
     if curve is None:
         return None
     if self.len_mode == 'T':
         curve.u_bounds = (0, t_ext)
         if isinstance(curve, SvLine) and sign < 0:
             unit = curve.direction / np.linalg.norm(curve.direction)
             t_target = t_ext / np.linalg.norm(curve.direction)
             start = curve.point + curve.direction - t_ext * unit
             curve.point = start
             curve.u_bounds = (0, t_target)
     elif self.len_mode == 'L':
         if isinstance(curve, SvLine):
             if sign > 0:
                 curve.direction = curve.direction
                 t_ext = t_ext / np.linalg.norm(curve.direction)
                 curve.u_bounds = (0, t_ext)
             else:
                 unit = curve.direction / np.linalg.norm(curve.direction)
                 t_target = t_ext / np.linalg.norm(curve.direction)
                 start = curve.point + curve.direction - t_ext * unit
                 curve.point = start
                 curve.u_bounds = (0, t_target)
         else:
             u_min, u_max = base_curve.get_u_bounds()
             base_length = base_curve.calc_length(u_min, u_max,
                                                  self.len_resolution)
             # base_length / (u_max - u_min) ~= t_ext / (t_target - 0)
             t_mid = t_ext * (u_max - u_min) / base_length
             #self.debug(f"Base curve len: {base_length}, range: {u_max - u_min}, T_ext {t_ext} => T_mid {t_mid}")
             curve.u_bounds = (0, t_mid)
             solver = SvCurveLengthSolver(curve)
             solver.prepare('SPL', self.len_resolution)
             t_target = solver.solve(np.array([t_ext]))[0]
             #self.debug(f"C: {type(curve)}: L = {t_mid} => T = {t_target}")
             curve.u_bounds = (0, t_target)
     return curve
Beispiel #3
0
    def process(self):

        if not any((s.is_linked for s in self.outputs)):
            return

        need_eval = self.outputs['Vertices'].is_linked

        curves_s = self.inputs['Curve'].sv_get()
        resolution_s = self.inputs['Resolution'].sv_get()
        length_s = self.inputs['Length'].sv_get()
        samples_s = self.inputs['Samples'].sv_get(default=[[]])

        length_s = ensure_nesting_level(length_s, 3)
        resolution_s = ensure_nesting_level(resolution_s, 2)
        samples_s = ensure_nesting_level(samples_s, 2)
        curves_s = ensure_nesting_level(curves_s, 2, data_types=(SvCurve,))

        ts_out = []
        verts_out = []
        for curves, resolutions, input_lengths_i, samples_i in zip_long_repeat(curves_s, resolution_s, length_s, samples_s):
            for curve, resolution, input_lengths, samples in zip_long_repeat(curves, resolutions, input_lengths_i, samples_i):

                mode = self.mode
                accuracy = self.accuracy
                if self.id_data.sv_draft:
                    mode = 'LIN'
                    accuracy = self.accuracy_draft

                if self.specify_accuracy:
                    tolerance = 10 ** (-accuracy)
                else:
                    tolerance = None

                solver = SvCurveLengthSolver(curve)
                solver.prepare(mode, resolution, tolerance=tolerance)

                if self.eval_mode == 'AUTO':
                    total_length = solver.get_total_length()
                    input_lengths = np.linspace(0.0, total_length, num = samples)
                else:
                    input_lengths = np.array(input_lengths)

                ts = solver.solve(input_lengths)

                ts_out.append(ts.tolist())
                if need_eval:
                    verts = curve.evaluate_array(ts).tolist()
                    verts_out.append(verts)

        self.outputs['T'].sv_set(ts_out)
        self.outputs['Vertices'].sv_set(verts_out)
    def process(self):

        if not any((s.is_linked for s in self.outputs)):
            return

        need_eval = self.outputs['Vertices'].is_linked

        curves = self.inputs['Curve'].sv_get()
        resolution_s = self.inputs['Resolution'].sv_get()
        length_s = self.inputs['Length'].sv_get()
        samples_s = self.inputs['Samples'].sv_get(default=[[]])

        length_s = ensure_nesting_level(length_s, 2)

        ts_out = []
        verts_out = []
        for curve, resolution, input_lengths, samples, in zip_long_repeat(
                curves, resolution_s, length_s, samples_s):
            if self.eval_mode == 'AUTO':
                if isinstance(samples, (list, tuple)):
                    samples = samples[0]

            if isinstance(resolution, (list, tuple)):
                resolution = resolution[0]

            mode = self.mode
            if self.id_data.sv_draft:
                mode = 'LIN'
            solver = SvCurveLengthSolver(curve)
            solver.prepare(mode, resolution)

            if self.eval_mode == 'AUTO':
                total_length = solver.get_total_length()
                input_lengths = np.linspace(0.0, total_length, num=samples)
            else:
                input_lengths = np.array(input_lengths)

            ts = solver.solve(input_lengths)

            ts_out.append(ts.tolist())
            if need_eval:
                verts = curve.evaluate_array(ts).tolist()
                verts_out.append(verts)

        self.outputs['T'].sv_set(ts_out)
        self.outputs['Vertices'].sv_set(verts_out)
Beispiel #5
0
class SvBendAlongCurveField(SvVectorField):

    ZERO = 'ZERO'
    FRENET = 'FRENET'
    HOUSEHOLDER = 'householder'
    TRACK = 'track'
    DIFF = 'diff'
    TRACK_NORMAL = 'track_normal'

    def __init__(self, curve, algorithm, scale_all, axis, t_min, t_max, up_axis=None, resolution=50, length_mode='T'):
        self.curve = curve
        self.axis = axis
        self.t_min = t_min
        self.t_max = t_max
        self.algorithm = algorithm
        self.scale_all = scale_all
        self.up_axis = up_axis
        self.length_mode = length_mode
        if algorithm == SvBendAlongCurveField.ZERO:
            self.curve.pre_calc_torsion_integral(resolution)
        elif algorithm == SvBendAlongCurveField.TRACK_NORMAL:
            self.normal_tracker = SvNormalTrack(curve, resolution)
        if length_mode == 'L':
            self.length_solver = SvCurveLengthSolver(curve)
            self.length_solver.prepare('SPL', resolution)
        self.__description__ = "Bend along {}".format(curve)

    def get_matrix(self, tangent, scale):
        return MathutilsRotationCalculator.get_matrix(tangent, scale, self.axis,
                    self.algorithm, self.scale_all, self.up_axis)

    def get_matrices(self, ts, scale):
        n = len(ts)
        if self.scale_all:
            scale_matrix = np.array([
                [scale, 0, 0],
                [0, scale, 0],
                [0, 0, 1/scale]
            ])
        else:
            scale_matrix = np.array([
                [1, 0, 0],
                [0, 1, 0],
                [0, 0, 1/scale]
            ])
        if self.algorithm == SvBendAlongCurveField.FRENET:
            frenet, _ , _ = self.curve.frame_array(ts)
            return frenet @ scale_matrix
        elif self.algorithm == SvBendAlongCurveField.ZERO:
            frenet, _ , _ = self.curve.frame_array(ts)
            angles = - self.curve.torsion_integral(ts)
            zeros = np.zeros((n,))
            ones = np.ones((n,))
            row1 = np.stack((np.cos(angles), np.sin(angles), zeros)).T # (n, 3)
            row2 = np.stack((-np.sin(angles), np.cos(angles), zeros)).T # (n, 3)
            row3 = np.stack((zeros, zeros, ones)).T # (n, 3)
            rotation_matrices = np.dstack((row1, row2, row3))
            return frenet @ rotation_matrices @ scale_matrix
        elif self.algorithm == SvBendAlongCurveField.TRACK_NORMAL:
            matrices = self.normal_tracker.evaluate_array(ts)
            return matrices @ scale_matrix
        else:
            raise Exception("Unsupported algorithm")

    def get_t_value(self, x, y, z):
        curve_t_min, curve_t_max = self.curve.get_u_bounds()
        t = [x, y, z][self.axis]
        if self.length_mode == 'T':
            t = (curve_t_max - curve_t_min) * (t - self.t_min) / (self.t_max - self.t_min) + curve_t_min
        else:
            t = (t - self.t_min) / (self.t_max - self.t_min) # 0 .. 1
            t = t * self.length_solver.get_total_length()
            t = self.length_solver.solve(np.array([t]))[0]
        return t

    def get_t_values(self, xs, ys, zs):
        curve_t_min, curve_t_max = self.curve.get_u_bounds()
        ts = [xs, ys, zs][self.axis]
        if self.length_mode == 'T':
            ts = (curve_t_max - curve_t_min) * (ts - self.t_min) / (self.t_max - self.t_min) + curve_t_min
        else:
            ts = (ts - self.t_min) / (self.t_max - self.t_min) # 0 .. 1
            ts = ts * self.length_solver.get_total_length()
            ts = self.length_solver.solve(ts)
        return ts

    def get_scale(self):
        if self.length_mode == 'T':
            curve_t_min, curve_t_max = self.curve.get_u_bounds()
            t_range = curve_t_max - curve_t_min
        else:
            t_range = self.length_solver.get_total_length()
        return (self.t_max - self.t_min) / t_range

    def evaluate(self, x, y, z):
        t = self.get_t_value(x, y, z)
        spline_tangent = self.curve.tangent(t)
        spline_vertex = self.curve.evaluate(t)
        scale = self.get_scale()
        if self.algorithm in {SvBendAlongCurveField.ZERO, SvBendAlongCurveField.FRENET, SvBendAlongCurveField.TRACK_NORMAL}:
            matrix = self.get_matrices(np.array([t]), scale)
        else:
            matrix = self.get_matrix(spline_tangent, scale)
        src_vector_projection = np.array([x, y, z])
        src_vector_projection[self.axis] = 0
        new_vertex = np.matmul(matrix, src_vector_projection) + spline_vertex
        vector = new_vertex - np.array([x, y, z])
        return vector

    def evaluate_grid(self, xs, ys, zs):
        def multiply(matrices, vectors):
            vectors = vectors[np.newaxis]
            vectors = np.transpose(vectors, axes=(1,2,0))
            r = matrices @ vectors
            return r[:,:,0]

        ts = self.get_t_values(xs, ys, zs).flatten()
        spline_tangents = self.curve.tangent_array(ts)
        spline_vertices = self.curve.evaluate_array(ts)
        scale = self.get_scale()
        if self.algorithm in {SvBendAlongCurveField.ZERO, SvBendAlongCurveField.FRENET, SvBendAlongCurveField.TRACK_NORMAL}:
            matrices = self.get_matrices(ts, scale)
        else:
            matrices = np.vectorize(lambda t : self.get_matrix(t, scale), signature='(3)->(3,3)')(spline_tangents)
        src_vectors = np.stack((xs, ys, zs)).T
        src_vector_projections = src_vectors.copy()
        src_vector_projections[:,self.axis] = 0
        #multiply = np.vectorize(lambda m, v: m @ v, signature='(3,3),(3)->(3)')
        new_vertices = multiply(matrices, src_vector_projections) + spline_vertices
        R = (new_vertices - src_vectors).T
        return R[0], R[1], R[2]
Beispiel #6
0
class SvBendAlongCurveField(SvVectorField):
    def __init__(self,
                 curve,
                 algorithm,
                 scale_all,
                 axis,
                 t_min,
                 t_max,
                 up_axis=None,
                 resolution=50,
                 length_mode='T'):
        self.curve = curve
        self.axis = axis
        self.t_min = t_min
        self.t_max = t_max
        self.algorithm = algorithm
        self.scale_all = scale_all
        self.up_axis = up_axis
        self.length_mode = length_mode
        if algorithm == 'ZERO':
            self.curve.pre_calc_torsion_integral(resolution)
        if length_mode == 'L':
            self.length_solver = SvCurveLengthSolver(curve)
            self.length_solver.prepare('SPL', resolution)
        self.__description__ = "Bend along {}".format(curve)

    def get_matrix(self, tangent, scale):
        x = Vector((1.0, 0.0, 0.0))
        y = Vector((0.0, 1.0, 0.0))
        z = Vector((0.0, 0.0, 1.0))

        if self.axis == 0:
            ax1, ax2, ax3 = x, y, z
        elif self.axis == 1:
            ax1, ax2, ax3 = y, x, z
        else:
            ax1, ax2, ax3 = z, x, y

        if self.scale_all:
            scale_matrix = Matrix.Scale(1 / scale, 4, ax1) @ Matrix.Scale(
                scale, 4, ax2) @ Matrix.Scale(scale, 4, ax3)
        else:
            scale_matrix = Matrix.Scale(1 / scale, 4, ax1)
        scale_matrix = np.array(scale_matrix.to_3x3())

        tangent = Vector(tangent)
        if self.algorithm == 'householder':
            rot = autorotate_householder(ax1, tangent).inverted()
        elif self.algorithm == 'track':
            axis = "XYZ"[self.axis]
            rot = autorotate_track(axis, tangent, self.up_axis)
        elif self.algorithm == 'diff':
            rot = autorotate_diff(tangent, ax1)
        else:
            raise Exception("Unsupported algorithm")
        rot = np.array(rot.to_3x3())

        return np.matmul(rot, scale_matrix)

    def get_matrices(self, ts, scale):
        frenet, _, _ = self.curve.frame_array(ts)
        if self.scale_all:
            scale_matrix = np.array([[scale, 0, 0], [0, scale, 0],
                                     [0, 0, 1 / scale]])
        else:
            scale_matrix = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1 / scale]])
        n = len(ts)
        if self.algorithm == 'FRENET':
            return frenet @ scale_matrix
        elif self.algorithm == 'ZERO':
            angles = -self.curve.torsion_integral(ts)
            zeros = np.zeros((n, ))
            ones = np.ones((n, ))
            row1 = np.stack(
                (np.cos(angles), np.sin(angles), zeros)).T  # (n, 3)
            row2 = np.stack(
                (-np.sin(angles), np.cos(angles), zeros)).T  # (n, 3)
            row3 = np.stack((zeros, zeros, ones)).T  # (n, 3)
            rotation_matrices = np.dstack((row1, row2, row3))
            return frenet @ rotation_matrices @ scale_matrix
        else:
            raise Exception("Unsupported algorithm")

    def get_t_value(self, x, y, z):
        curve_t_min, curve_t_max = self.curve.get_u_bounds()
        t = [x, y, z][self.axis]
        if self.length_mode == 'T':
            t = (curve_t_max - curve_t_min) * (t - self.t_min) / (
                self.t_max - self.t_min) + curve_t_min
        else:
            t = (t - self.t_min) / (self.t_max - self.t_min)  # 0 .. 1
            t = t * self.length_solver.get_total_length()
            t = self.length_solver.solve(np.array([t]))[0]
        return t

    def get_t_values(self, xs, ys, zs):
        curve_t_min, curve_t_max = self.curve.get_u_bounds()
        ts = [xs, ys, zs][self.axis]
        if self.length_mode == 'T':
            ts = (curve_t_max - curve_t_min) * (ts - self.t_min) / (
                self.t_max - self.t_min) + curve_t_min
        else:
            ts = (ts - self.t_min) / (self.t_max - self.t_min)  # 0 .. 1
            ts = ts * self.length_solver.get_total_length()
            ts = self.length_solver.solve(ts)
        return ts

    def get_scale(self):
        if self.length_mode == 'T':
            curve_t_min, curve_t_max = self.curve.get_u_bounds()
            t_range = curve_t_max - curve_t_min
        else:
            t_range = self.length_solver.get_total_length()
        return (self.t_max - self.t_min) / t_range

    def evaluate(self, x, y, z):
        t = self.get_t_value(x, y, z)
        spline_tangent = self.curve.tangent(t)
        spline_vertex = self.curve.evaluate(t)
        scale = self.get_scale()
        if self.algorithm in {'ZERO', 'FRENET'}:
            matrix = self.get_matrices(np.array([t]), scale)
        else:
            matrix = self.get_matrix(spline_tangent, scale)
        src_vector_projection = np.array([x, y, z])
        src_vector_projection[self.axis] = 0
        new_vertex = np.matmul(matrix, src_vector_projection) + spline_vertex
        vector = new_vertex - np.array([x, y, z])
        return vector

    def evaluate_grid(self, xs, ys, zs):
        ts = self.get_t_values(xs, ys, zs).flatten()
        spline_tangents = self.curve.tangent_array(ts)
        spline_vertices = self.curve.evaluate_array(ts)
        scale = self.get_scale()
        if self.algorithm in {'ZERO', 'FRENET'}:
            matrices = self.get_matrices(ts, scale)
        else:
            matrices = np.vectorize(lambda t: self.get_matrix(t, scale),
                                    signature='(3)->(3,3)')(spline_tangents)
        src_vectors = np.stack((xs, ys, zs)).T
        src_vector_projections = src_vectors.copy()
        src_vector_projections[:, self.axis] = 0
        #matrices = matrices[np.newaxis][np.newaxis]
        multiply = np.vectorize(lambda m, v: m @ v, signature='(3,3),(3)->(3)')
        new_vertices = multiply(matrices,
                                src_vector_projections) + spline_vertices
        R = (new_vertices - src_vectors).T
        return R[0], R[1], R[2]