Esempio n. 1
0
def concatenate_nurbs_curves(curves):
    if not curves:
        raise Exception("List of curves must be not empty")
    curves = unify_curves_degree(curves)
    result = curves[0]
    for curve in curves[1:]:
        result = result.concatenate(curve)
    return result
Esempio n. 2
0
def concatenate_nurbs_curves(curves):
    if not curves:
        raise Exception("List of curves must be not empty")
    curves = unify_curves_degree(curves)
    result = curves[0]
    for i, curve in enumerate(curves[1:]):
        try:
            result = result.concatenate(curve)
        except Exception as e:
            raise Exception(f"Can't append curve #{i+1}: {e}")
    return result
Esempio n. 3
0
    def make_ruled_surface(self, curve2, vmin, vmax):
        curve = self
        curve2 = SvNurbsCurve.to_nurbs(curve2)
        if curve2 is None:
            raise UnsupportedCurveTypeException("second curve is not NURBS")
        curve, curve2 = unify_curves_degree([curve, curve2])
        if curve.get_degree() != curve2.get_degree():
            raise UnsupportedCurveTypeException(
                f"curves have different degrees: {curve.get_degree()} != {curve2.get_degree()}"
            )

        #print(f"kv1: {curve.get_knotvector().shape}, kv2: {curve2.get_knotvector().shape}")
        kv1, kv2 = curve.get_knotvector(), curve2.get_knotvector()
        if kv1.shape != kv2.shape or (kv1 != kv2).any():
            curve, curve2 = unify_two_curves(curve, curve2)
            #raise UnsupportedCurveTypeException("curves have different knot vectors")

        my_control_points = curve.get_control_points()
        other_control_points = curve2.get_control_points()
        if len(my_control_points) != len(other_control_points):
            raise UnsupportedCurveTypeException(
                "curves have different number of control points")

        if vmin != 0:
            my_control_points = (
                1 - vmin) * my_control_points + vmin * other_control_points
        if vmax != 0:
            other_control_points = (
                1 - vmax) * my_control_points + vmax * other_control_points

        control_points = np.stack((my_control_points, other_control_points))
        control_points = np.transpose(control_points, axes=(1, 0, 2))

        weights = np.stack((curve.get_weights(), curve2.get_weights())).T
        knotvector_v = sv_knotvector.generate(1, 2, clamped=True)

        surface = SvNurbsMaths.build_surface(
            self.get_nurbs_implementation(),
            degree_u=curve.get_degree(),
            degree_v=1,
            knotvector_u=curve.get_knotvector(),
            knotvector_v=knotvector_v,
            control_points=control_points,
            weights=weights)
        return surface
Esempio n. 4
0
    def lerp_to(self, curve2, coefficient):
        curve1 = self
        curve2 = SvNurbsCurve.to_nurbs(curve2)
        if curve2 is None:
            raise UnsupportedCurveTypeException("second curve is not NURBS")
        curve1, curve2 = unify_curves_degree([curve1, curve2])
        curve1, curve2 = unify_two_curves(curve1, curve2)

        #c1cp = curve1.get_homogenous_control_points()
        #c2cp = curve2.get_homogenous_control_points()
        c1cp = curve1.get_control_points()
        c2cp = curve2.get_control_points()
        ws1 = curve1.get_weights()
        ws2 = curve2.get_weights()

        points = c1cp * (1 - coefficient) + coefficient * c2cp

        weights = ws1 * (1 - coefficient) + coefficient * ws2

        return SvNurbsCurve.build(curve1.get_nurbs_implementation(),
                                  curve1.get_degree(), curve1.get_knotvector(),
                                  points, weights)
Esempio n. 5
0
    def process(self):

        # upgrades older versions of ProfileMK3 to the version that has self.file_pointer
        if self.filename and not self.file_pointer:
            text = self.get_bpy_data_from_name(self.filename, bpy.data.texts)
            if text:
                self.file_pointer = text

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

        sync_pointer_and_stored_name(self, "file_pointer", "filename")

        profile = self.load_profile()
        optional_inputs = self.get_optional_inputs(profile)

        var_names = self.get_variables()
        self.debug("Var_names: %s; optional: %s", var_names, optional_inputs)
        inputs = self.get_input()

        result_vertices = []
        result_edges = []
        result_knots = []
        result_names = []
        result_curves = []

        if var_names:
            input_values = []
            for name in var_names:
                try:
                    input_values.append(inputs[name])
                except KeyError as e:
                    name = e.args[0]
                    if name not in optional_inputs:
                        if name in self.inputs:
                            raise SvNoDataError(self.inputs[name])
                        else:
                            self.adjust_sockets()
                            raise SvNoDataError(self.inputs[name])
                    else:
                        input_values.append([None])
            parameters = match_long_repeat(input_values)
        else:
            parameters = [[[]]]

        input_names = [
            socket.name for socket in self.inputs if socket.is_linked
        ]

        for values in zip(*parameters):
            variables = dict(zip(var_names, values))
            curves_form = Interpreter.NURBS if self.nurbs_out else None
            interpreter = Interpreter(self,
                                      input_names,
                                      curves_form=curves_form,
                                      z_axis=self.selected_axis)
            interpreter.interpret(profile, variables)
            verts = self.extend_out_verts(interpreter.vertices)
            result_vertices.append(verts)
            result_edges.append(interpreter.edges)
            knots = self.extend_out_verts(interpreter.knots)
            result_knots.append(knots)
            result_names.append([[name] for name in interpreter.knotnames])
            all_curves = interpreter.curves
            if self.concat_curves:
                new_curves = []
                for curves in self.group_curves(all_curves):
                    if self.nurbs_out:
                        curves = unify_curves_degree(curves)
                    curve = concatenate_curves(curves)
                    new_curves.append(curve)
                result_curves.append(new_curves)
            else:
                result_curves.append(all_curves)

        self.outputs['Vertices'].sv_set(result_vertices)
        self.outputs['Edges'].sv_set(result_edges)
        self.outputs['Knots'].sv_set(result_knots)
        self.outputs['KnotNames'].sv_set(result_names)
        if 'Curve' in self.outputs:
            self.outputs['Curve'].sv_set(result_curves)
Esempio n. 6
0
def gordon_surface(u_curves,
                   v_curves,
                   intersections,
                   metric='POINTS',
                   u_knots=None,
                   v_knots=None,
                   knotvector_accuracy=6,
                   reparametrize_tolerance=1e-2):
    """
    Generate a NURBS surface from a net of NURBS curves, by use of Gordon's algorithm.

    :param u_curves - list of NURBS curves along U direciton (length N)
    :param v_curves - list of NURBS curves along V direcion (length M)
    :param intersections - np.array of shape (N, M, 3): points of curves intersection
    :param metric - metric function that can be used to calculate T values of curves
                    intersections from their positions.
    :param u_knots - np.array, T values of curves intersection for each curve from u_curves
    :param v_knots - np.array, T values of curves intersection for each curve from v_curves

    return value: a NURBS surface.

    See also: The NURBS Book, 2nd ed., p.10.5.
    """

    if not u_curves or not v_curves:
        raise Exception("U or V curves are not provided")

    if (u_knots is None) != (v_knots is None):
        raise Exception(
            "u_knots and v_knots must be either both provided or both omited")

    if any(c.is_rational() for c in u_curves):
        raise Exception(
            "Some of U-curves are rational. Rational curves are not supported for Gordon surface."
        )
    if any(c.is_rational() for c in v_curves):
        raise Exception(
            "Some of V-curves are rational. Rational curves are not supported for Gordon surface."
        )

    intersections = np.array(intersections)

    if u_knots is not None:
        loft_u_kwargs = loft_v_kwargs = interpolate_kwargs = {
            'metric': 'POINTS'
        }

        u_curves = [
            reparametrize_by_segments(c, knots, reparametrize_tolerance)
            for c, knots in zip(u_curves, u_knots)
        ]
        v_curves = [
            reparametrize_by_segments(c, knots, reparametrize_tolerance)
            for c, knots in zip(v_curves, v_knots)
        ]
        #print("U", u_curves)
        #print("V", v_curves)

    else:
        loft_u_kwargs = loft_v_kwargs = interpolate_kwargs = {'metric': metric}

    u_curves = unify_curves_degree(u_curves)
    u_curves = unify_curves(u_curves,
                            accuracy=knotvector_accuracy)  #, method='AVERAGE')
    v_curves = unify_curves_degree(v_curves)
    v_curves = unify_curves(v_curves,
                            accuracy=knotvector_accuracy)  #, method='AVERAGE')

    u_curves_degree = u_curves[0].get_degree()
    v_curves_degree = v_curves[0].get_degree()
    n = len(intersections)
    m = len(intersections[0])

    loft_v_degree = min(len(u_curves) - 1, v_curves_degree)
    loft_u_degree = min(len(v_curves) - 1, u_curves_degree)

    _, _, lofted_v = simple_loft(u_curves,
                                 degree_v=loft_v_degree,
                                 knotvector_accuracy=knotvector_accuracy,
                                 **loft_v_kwargs)
    _, _, lofted_u = simple_loft(v_curves,
                                 degree_v=loft_u_degree,
                                 knotvector_accuracy=knotvector_accuracy,
                                 **loft_u_kwargs)
    lofted_u = lofted_u.swap_uv()

    int_degree_u = min(m - 1, u_curves_degree)
    int_degree_v = min(n - 1, v_curves_degree)
    interpolated = interpolate_nurbs_surface(int_degree_u, int_degree_v,
                                             intersections,
                                             **interpolate_kwargs)
    interpolated = interpolated.swap_uv()
    #print(f"Loft.U: {lofted_u}")
    #print(f"Loft.V: {lofted_v}")
    #print(f"Interp: {interpolated}")
    #print(f"        {interpolated.get_knotvector_u()}")
    #print(f"        {interpolated.get_knotvector_v()}")

    lofted_u, lofted_v, interpolated = unify_nurbs_surfaces(
        [lofted_u, lofted_v, interpolated],
        knotvector_accuracy=knotvector_accuracy)

    control_points = lofted_u.get_control_points() + \
                        lofted_v.get_control_points() - \
                        interpolated.get_control_points()

    surface = SvNurbsSurface.build(SvNurbsSurface.NATIVE,
                                   interpolated.get_degree_u(),
                                   interpolated.get_degree_v(),
                                   interpolated.get_knotvector_u(),
                                   interpolated.get_knotvector_v(),
                                   control_points,
                                   weights=None)
    #print(f"Result: {surface}")

    return lofted_u, lofted_v, interpolated, surface
Esempio n. 7
0
def simple_loft(curves,
                degree_v=None,
                knots_u='UNIFY',
                metric='DISTANCE',
                tknots=None,
                implementation=SvNurbsSurface.NATIVE):
    """
    Loft between given NURBS curves (a.k.a skinning).

    inputs:
    * degree_v - degree of resulting surface along V parameter; by default - use the same degree as provided curves
    * knots_u - one of:
        - 'UNIFY' - unify knotvectors of given curves by inserting additional knots
        - 'AVERAGE' - average knotvectors of given curves; this will work only if all curves have the same number of control points
    * metric - metric for interpolation; most useful are 'DISTANCE' and 'CENTRIPETAL'
    * implementation - NURBS maths implementation

    output: tuple:
        * list of curves - input curves after unification
        * list of NURBS curves along V direction
        * generated NURBS surface.
    """
    if knots_u not in {'UNIFY', 'AVERAGE'}:
        raise Exception(f"Unsupported knots_u option: {knots_u}")
    curve_class = type(curves[0])
    curves = unify_curves_degree(curves)
    if knots_u == 'UNIFY':
        curves = unify_curves(curves)
    else:
        kvs = [len(curve.get_control_points()) for curve in curves]
        max_kv, min_kv = max(kvs), min(kvs)
        if max_kv != min_kv:
            raise Exception(
                f"U knotvector averaging is not applicable: Curves have different number of control points: {kvs}"
            )

    degree_u = curves[0].get_degree()
    if degree_v is None:
        degree_v = degree_u

    if degree_v > len(curves):
        raise Exception(
            f"V degree ({degree_v}) must be not greater than number of curves ({len(curves)}) minus 1"
        )

    src_points = [curve.get_homogenous_control_points() for curve in curves]
    #     lens = [len(pts) for pts in src_points]
    #     max_len, min_len = max(lens), min(lens)
    #     if max_len != min_len:
    #         raise Exception(f"Unify error: curves have different number of control points: {lens}")

    src_points = np.array(src_points)
    #print("Src:", src_points)
    src_points = np.transpose(src_points, axes=(1, 0, 2))

    v_curves = [
        interpolate_nurbs_curve(curve_class,
                                degree_v,
                                points,
                                metric=metric,
                                tknots=tknots) for points in src_points
    ]
    control_points = [
        curve.get_homogenous_control_points() for curve in v_curves
    ]
    control_points = np.array(control_points)
    #weights = [curve.get_weights() for curve in v_curves]
    #weights = np.array([curve.get_weights() for curve in curves]).T
    n, m, ndim = control_points.shape
    control_points = control_points.reshape((n * m, ndim))
    control_points, weights = from_homogenous(control_points)
    control_points = control_points.reshape((n, m, 3))
    weights = weights.reshape((n, m))

    mean_v_vector = control_points.mean(axis=0)
    tknots_v = Spline.create_knots(mean_v_vector, metric=metric)
    knotvector_v = sv_knotvector.from_tknots(degree_v, tknots_v)
    if knots_u == 'UNIFY':
        knotvector_u = curves[0].get_knotvector()
    else:
        knotvectors = np.array([curve.get_knotvector() for curve in curves])
        knotvector_u = knotvectors.mean(axis=0)

    surface = SvNurbsSurface.build(implementation, degree_u, degree_v,
                                   knotvector_u, knotvector_v, control_points,
                                   weights)
    surface.u_bounds = curves[0].get_u_bounds()
    return curves, v_curves, surface