def bilinear_surface(vtxs, overhang=0.0): """ Returns B-spline surface of a bilinear surface given by 4 corner points: uv coords: We retun also list of UV coordinates of the given points. :param vtxs: List of tuples (X,Y,Z) :return: ( Surface, vtxs_uv ) """ assert len(vtxs) == 4, "n vtx: {}".format(len(vtxs)) vtxs = np.array(vtxs) if overhang > 0.0: dv = np.roll(vtxs, -1, axis=0) - vtxs dv *= overhang vtxs += np.roll(dv, 1, axis=0) - dv def mid(*idx): return np.mean(vtxs[list(idx)], axis=0) # v - direction v0 -> v2 # u - direction v0 -> v1 poles = [[vtxs[0], mid(0, 3), vtxs[3]], [mid(0, 1), mid(0, 1, 2, 3), mid(2, 3)], [vtxs[1], mid(1, 2), vtxs[2]]] knots = 3 * [0.0 - overhang] + 3 * [1.0 + overhang] basis = bs.SplineBasis(2, knots) surface = bs.Surface((basis, basis), poles) #vtxs_uv = [ (0, 0), (1, 0), (1, 1), (0, 1) ] return surface
def test_eval(self): #self.plot_basis(bs.SplineBasis.make_equidistant(0, 4)) knots = np.array([ 0, 0, 0, 0.1880192, 0.24545785, 0.51219762, 0.82239001, 1., 1., 1. ]) basis = bs.SplineBasis(2, knots) #self.plot_basis(basis) eq_basis = bs.SplineBasis.make_equidistant(0, 2) assert eq_basis.eval(0, 0.0) == 1.0 assert eq_basis.eval(1, 0.0) == 0.0 assert eq_basis.eval(0, 0.5) == 0.0 assert eq_basis.eval(1, 0.5) == 1.0 assert eq_basis.eval(1, 1.0) == 1.0 eq_basis = bs.SplineBasis.make_equidistant(1, 4) assert eq_basis.eval(0, 0.0) == 1.0 assert eq_basis.eval(1, 0.0) == 0.0 assert eq_basis.eval(2, 0.0) == 0.0 assert eq_basis.eval(3, 0.0) == 0.0 assert eq_basis.eval(4, 0.0) == 0.0 assert eq_basis.eval(0, 0.125) == 0.5 assert eq_basis.eval(1, 0.125) == 0.5 assert eq_basis.eval(2, 1.0) == 0.0 # check summation to one: for deg in range(0, 10): basis = bs.SplineBasis.make_equidistant(deg, 2) for x in np.linspace(basis.domain[0], basis.domain[1], 10): s = sum([basis.eval(i, x) for i in range(basis.size)]) assert np.isclose(s, 1.0)
def curve_from_grid(points, **kwargs): """ Make a Curve (of degree 3) as an approximation of a sequence of points. :param points - N x D array, D is dimension :param nt Prescribed number of poles of the resulting spline. :return: Curve object. TODO: - Measure efficiency. Estimate how good we can be. Do it our self if we can do at leas 10 times better. - Find out which method is used. Hoschek (4.4.1) refers to several methods how to determine parametrization of the curve, i.e. Find parameters t_i to the given approximation points P_i. - Further on it is not clear what is the mening of the 's' parameter and how one cna influence tolerance and smoothness. - Some sort of adaptivity is used. """ deg = kwargs.get('degree', 3) tol = kwargs.get('tol', 0.01) weights = np.ones(points.shape[0]) weights[0] = weights[-1] = 1000.0 tck = scipy.interpolate.splprep(points.T, k=deg, s=tol, w=weights)[0] knots, poles, degree = tck curve_poles = np.array(poles).T curve_poles[0] = points[0] curve_poles[-1] = points[-1] basis = bs.SplineBasis(degree, knots) curve = bs.Curve(basis, curve_poles) return curve
def test_find_knot_interval(self): """ test methods: - make_equidistant - find_knot_interval """ eq_basis = bs.SplineBasis.make_equidistant(2, 100) assert eq_basis.find_knot_interval(0.0) == 0 assert eq_basis.find_knot_interval(0.001) == 0 assert eq_basis.find_knot_interval(0.01) == 1 assert eq_basis.find_knot_interval(0.011) == 1 assert eq_basis.find_knot_interval(0.5001) == 50 assert eq_basis.find_knot_interval(1.0 - 0.011) == 98 assert eq_basis.find_knot_interval(1.0 - 0.01) == 99 assert eq_basis.find_knot_interval(1.0 - 0.001) == 99 assert eq_basis.find_knot_interval(1.0) == 99 knots = np.array([ 0, 0, 0, 0.1880192, 0.24545785, 0.51219762, 0.82239001, 1., 1., 1. ]) basis = bs.SplineBasis(2, knots) for interval in range(2, 7): xx = np.linspace(knots[interval], knots[interval + 1], 10) for j, x in enumerate(xx[:-1]): i_found = basis.find_knot_interval(x) assert i_found == interval - 2, "i_found: {} i: {} j: {} x: {} ".format( i_found, interval - 2, j, x)
def line(vtxs, overhang=0.0): ''' Return B-spline approximation of a line from two points :param vtxs: [ X0, X1 ], Xn are point coordinates in arbitrary dimension D :return: Curve2D ''' assert len(vtxs) == 2 vtxs = np.array(vtxs) if overhang > 0.0: dv = overhang * (vtxs[1] - vtxs[0]) vtxs[0] -= dv vtxs[1] += dv mid = np.mean(vtxs, axis=0) poles = [vtxs[0], mid, vtxs[1]] knots = 3 * [0.0 - overhang] + 3 * [1.0 + overhang] basis = bs.SplineBasis(2, knots) return bs.Curve(basis, poles)