Exemple #1
0
 def test_from_tknots(self):
     tknots = np.array([0, 5, 9, 14, 17.0]) / 17.0
     degree = 3
     knotvector = sv_knotvector.from_tknots(degree, tknots)
     u4 = 0.5490196078431373
     expected = np.array([0, 0, 0, 0, u4, 1, 1, 1, 1])
     self.assert_numpy_arrays_equal(knotvector, expected, precision=6)
Exemple #2
0
def interpolate_nurbs_curve(cls,
                            degree,
                            points,
                            metric='DISTANCE',
                            tknots=None):
    n = len(points)
    if points.ndim != 2:
        raise Exception(
            f"Array of points was expected, but got {points.shape}: {points}")
    ndim = points.shape[1]  # 3 or 4
    if ndim not in {3, 4}:
        raise Exception(
            f"Only 3D and 4D points are supported, but ndim={ndim}")
    #points3d = points[:,:3]
    #print("pts:", points)
    if tknots is None:
        tknots = Spline.create_knots(
            points, metric=metric)  # In 3D or in 4D, in general?
    knotvector = sv_knotvector.from_tknots(degree, tknots)
    functions = SvNurbsBasisFunctions(knotvector)
    coeffs_by_row = [
        functions.function(idx, degree)(tknots) for idx in range(n)
    ]
    A = np.zeros((ndim * n, ndim * n))
    for equation_idx, t in enumerate(tknots):
        for unknown_idx in range(n):
            coeff = coeffs_by_row[unknown_idx][equation_idx]
            row = ndim * equation_idx
            col = ndim * unknown_idx
            for d in range(ndim):
                A[row + d, col + d] = coeff
    B = np.zeros((ndim * n, 1))
    for point_idx, point in enumerate(points):
        row = ndim * point_idx
        B[row:row + ndim] = point[:, np.newaxis]

    x = np.linalg.solve(A, B)

    control_points = []
    for i in range(n):
        row = i * ndim
        control = x[row:row + ndim, 0].T
        control_points.append(control)
    control_points = np.array(control_points)
    if ndim == 3:
        weights = np.ones((n, ))
    else:  # 4
        control_points, weights = from_homogenous(control_points)

    if type(cls) == type:
        return cls.build(cls.get_nurbs_implementation(), degree, knotvector,
                         control_points, weights)
    elif isinstance(cls, str):
        return SvNurbsMaths.build_curve(cls, degree, knotvector,
                                        control_points, weights)
    else:
        raise TypeError(f"Unsupported type of `cls` parameter: {type(cls)}")
Exemple #3
0
    def interpolate_list(cls, degree, points, metric='DISTANCE'):
        n_curves, n_points, _ = points.shape
        tknots = [
            Spline.create_knots(points[i], metric=metric)
            for i in range(n_curves)
        ]
        knotvectors = [
            sv_knotvector.from_tknots(degree, tknots[i])
            for i in range(n_curves)
        ]
        functions = [
            SvNurbsBasisFunctions(knotvectors[i]) for i in range(n_curves)
        ]
        coeffs_by_row = [[
            functions[curve_idx].function(idx, degree)(tknots[curve_idx])
            for idx in range(n_points)
        ] for curve_idx in range(n_curves)]
        coeffs_by_row = np.array(coeffs_by_row)
        A = np.zeros((n_curves, 3 * n_points, 3 * n_points))
        for curve_idx in range(n_curves):
            for equation_idx, t in enumerate(tknots[curve_idx]):
                for unknown_idx in range(n_points):
                    coeff = coeffs_by_row[curve_idx][unknown_idx][equation_idx]
                    row = 3 * equation_idx
                    col = 3 * unknown_idx
                    A[curve_idx, row, col] = A[curve_idx, row + 1,
                                               col + 1] = A[curve_idx, row + 2,
                                                            col + 2] = coeff

        B = np.zeros((n_curves, 3 * n_points, 1))
        for curve_idx in range(n_curves):
            for point_idx, point in enumerate(points[curve_idx]):
                row = 3 * point_idx
                B[curve_idx, row:row + 3] = point[:, np.newaxis]

        x = np.linalg.solve(A, B)

        curves = []
        weights = np.ones((n_points, ))
        for curve_idx in range(n_curves):
            control_points = []
            for i in range(n_points):
                row = i * 3
                control = x[curve_idx][row:row + 3, 0].T
                control_points.append(control)
            control_points = np.array(control_points)

            curve = SvNurbsCurve.build(cls.get_nurbs_implementation(), degree,
                                       knotvectors[curve_idx], control_points,
                                       weights)
            curves.append(curve)

        return curves
Exemple #4
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