def test_force_rational(self): # more or less random 3D volume with p=[3,2,1] and n=[4,3,2] controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 2], [1, 0, 2], [1, 1, 2], [2, 1, 2], [2, 2, 2], [2, 3, 2], [3, 0, 0], [4, 1, 0], [3, 2, 0], [0, 0, 3], [-1, 1, 3], [0, 2, 3], [1, -1, 5], [1, 0, 5], [1, 1, 5], [2, 1, 4], [2, 2, 4], [2, 3, 4], [3, 0, 2], [4, 1, 2], [3, 2, 2]] basis1 = BSplineBasis(4, [0, 0, 0, 0, 2, 2, 2, 2]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints) evaluation_point1 = vol(0.23, .66, .32) control_point1 = vol[0] vol.force_rational() evaluation_point2 = vol(0.23, .66, .32) control_point2 = vol[0] # ensure that volume has not chcanged, by comparing evaluation of it self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2]) # ensure that we include rational weights of 1 self.assertEqual(len(control_point1), 3) self.assertEqual(len(control_point2), 4) self.assertEqual(control_point2[3], 1) self.assertEqual(vol.rational, True)
def test_edge_surfaces_six_sides_issue_141(self): # create the unit cube vol = Volume() # modify slightly one edge: umin(w=0) is now a parabola instead of a line vol.raise_order(0,1,0) vol.controlpoints[-1, 1, 0, 0] += 1 faces = vol.faces() # edge_surface should give back the same modified unit cube vol2 = vf.edge_surfaces(faces) # check discretization self.assertEqual(vol2.order(0),2) self.assertEqual(vol2.order(1),3) self.assertEqual(vol2.order(2),2) self.assertEqual(len(vol2.knots(0)),2) # [0, 1] self.assertEqual(len(vol2.knots(1)),2) self.assertEqual(len(vol2.knots(2)),2) # check a 5x5x5 evaluation grid u = np.linspace(0,1,5) v = np.linspace(0,1,5) w = np.linspace(0,1,5) pt = vol( u,v,w) pt2 = vol2(u,v,w) self.assertTrue(np.allclose(pt, pt2))
def test_evaluate(self): # creating the identity mapping by different size for all directions vol = Volume(BSplineBasis(7), BSplineBasis(6), BSplineBasis(5)) # call evaluation at a 2x3x4 grid of points u_val = np.linspace(0, 1, 2) v_val = np.linspace(0, 1, 3) w_val = np.linspace(0, 1, 4) value = vol(u_val, v_val, w_val) self.assertEqual(value.shape[0], 2) # 2 u-evaluation points self.assertEqual(value.shape[1], 3) # 3 v-evaluation points self.assertEqual(value.shape[2], 4) # 4 w-evaluation points self.assertEqual(value.shape[3], 3) # 3 dimensions (x,y,z) self.assertEqual(vol.order(), (7, 6, 5)) for i, u in enumerate(u_val): for j, v in enumerate(v_val): for k, w in enumerate(w_val): self.assertAlmostEqual(value[i, j, k, 0], u) # identity map x=u self.assertAlmostEqual(value[i, j, k, 1], v) # identity map y=v self.assertAlmostEqual(value[i, j, k, 2], w) # identity map z=w # test errors and exceptions with self.assertRaises(ValueError): val = vol(-10, .5, .5) # evalaute outside parametric domain with self.assertRaises(ValueError): val = vol(+10, .3, .3) # evalaute outside parametric domain with self.assertRaises(ValueError): val = vol(.5, -10, .123) # evalaute outside parametric domain with self.assertRaises(ValueError): val = vol(.5, +10, .123) # evalaute outside parametric domain with self.assertRaises(ValueError): val = vol(.5, .2, +10) # evalaute outside parametric domain with self.assertRaises(ValueError): val = vol(.5, .2, -10) # evalaute outside parametric domain
def cube(size=1, lower_left=(0, 0, 0)): """ Create a cube with parmetric origin at *(0,0,0)*. :param float size: Size(s), either a single scalar or a tuple of scalars per axis :param array-like lower_left: local origin, the lower bottom left corner of the cube :return: A linear parametrized box :rtype: Volume """ result = Volume() result.scale(size) result += lower_left return result
def test_controlpoint_access(self): v = Volume() v.refine(1) self.assertAlmostEqual(v[0,0,0, 0] , 0) self.assertAlmostEqual(v[0,0,0][0] , 0) self.assertAlmostEqual(v[0,1,0][0] , 0) self.assertAlmostEqual(v[0,1,0][1] , .5) self.assertAlmostEqual(v[0,1,0, 1] , .5) self.assertAlmostEqual(v[0,0,2][2] , 1) self.assertAlmostEqual(v[4][0] , .5) self.assertAlmostEqual(v[4][1] , .5) self.assertAlmostEqual(v[4][2] , 0) self.assertAlmostEqual(v[13][0] , .5) self.assertAlmostEqual(v[13][1] , .5) self.assertAlmostEqual(v[13][2] , .5) self.assertAlmostEqual(v[14][0] , 1) self.assertAlmostEqual(v[14][1] , .5) self.assertAlmostEqual(v[14][2] , .5) v[0] = [.1, .1, .1] v[1,1,1] = [.6, .6, .6] v[1,0,0][0] = .4 self.assertAlmostEqual(v[0,0,0][0], .1) self.assertAlmostEqual(v[0,0,0][1], .1) self.assertAlmostEqual(v[0,0,0][2], .1) self.assertAlmostEqual(v[13][0] , .6) self.assertAlmostEqual(v[13][1] , .6) self.assertAlmostEqual(v[13][2] , .6) self.assertAlmostEqual(v[1][0] , .4) self.assertAlmostEqual(v[1][1] , 0) self.assertAlmostEqual(v[1][2] , 0) v[:,0,0] = 13 v[0,1,0][:] = 12 # v[0,2,1] = [9,8,7] # v[0,2,0] = [9,8,7] v[0,2,1::-1] = [9,8,7] v[1,2,1::-1,:] = [[6,5,4],[3,2,1]] self.assertAlmostEqual(v[1,0,0,0], 13) self.assertAlmostEqual(v[1,0,0,1], 13) self.assertAlmostEqual(v[2,0,0,2], 13) self.assertAlmostEqual(v[0,1,0,0], 12) self.assertAlmostEqual(v[0,1,0,2], 12) self.assertAlmostEqual(v[0,2,2,1], 1) self.assertAlmostEqual(v[0,2,1,0], 9) self.assertAlmostEqual(v[0,2,1,1], 8) self.assertAlmostEqual(v[0,2,0,2], 7) self.assertAlmostEqual(v[1,2,1,0], 6) self.assertAlmostEqual(v[1,2,1,1], 5) self.assertAlmostEqual(v[1,2,1,2], 4) self.assertAlmostEqual(v[1,2,0,0], 3) self.assertAlmostEqual(v[1,2,0,1], 2) self.assertAlmostEqual(v[1,2,0,2], 1)
def test_controlpoint_access(self): v = Volume() v.refine(1) self.assertAlmostEqual(v[0, 0, 0, 0], 0) self.assertAlmostEqual(v[0, 0, 0][0], 0) self.assertAlmostEqual(v[0, 1, 0][0], 0) self.assertAlmostEqual(v[0, 1, 0][1], .5) self.assertAlmostEqual(v[0, 1, 0, 1], .5) self.assertAlmostEqual(v[0, 0, 2][2], 1) self.assertAlmostEqual(v[4][0], .5) self.assertAlmostEqual(v[4][1], .5) self.assertAlmostEqual(v[4][2], 0) self.assertAlmostEqual(v[13][0], .5) self.assertAlmostEqual(v[13][1], .5) self.assertAlmostEqual(v[13][2], .5) self.assertAlmostEqual(v[14][0], 1) self.assertAlmostEqual(v[14][1], .5) self.assertAlmostEqual(v[14][2], .5) v[0] = [.1, .1, .1] v[1, 1, 1] = [.6, .6, .6] v[1, 0, 0][0] = .4 self.assertAlmostEqual(v[0, 0, 0][0], .1) self.assertAlmostEqual(v[0, 0, 0][1], .1) self.assertAlmostEqual(v[0, 0, 0][2], .1) self.assertAlmostEqual(v[13][0], .6) self.assertAlmostEqual(v[13][1], .6) self.assertAlmostEqual(v[13][2], .6) self.assertAlmostEqual(v[1][0], .4) self.assertAlmostEqual(v[1][1], 0) self.assertAlmostEqual(v[1][2], 0) v[:, 0, 0] = 13 v[0, 1, 0][:] = 12 # v[0,2,1] = [9,8,7] # v[0,2,0] = [9,8,7] v[0, 2, 1::-1] = [9, 8, 7] v[1, 2, 1::-1, :] = [[6, 5, 4], [3, 2, 1]] self.assertAlmostEqual(v[1, 0, 0, 0], 13) self.assertAlmostEqual(v[1, 0, 0, 1], 13) self.assertAlmostEqual(v[2, 0, 0, 2], 13) self.assertAlmostEqual(v[0, 1, 0, 0], 12) self.assertAlmostEqual(v[0, 1, 0, 2], 12) self.assertAlmostEqual(v[0, 2, 2, 1], 1) self.assertAlmostEqual(v[0, 2, 1, 0], 9) self.assertAlmostEqual(v[0, 2, 1, 1], 8) self.assertAlmostEqual(v[0, 2, 0, 2], 7) self.assertAlmostEqual(v[1, 2, 1, 0], 6) self.assertAlmostEqual(v[1, 2, 1, 1], 5) self.assertAlmostEqual(v[1, 2, 1, 2], 4) self.assertAlmostEqual(v[1, 2, 0, 0], 3) self.assertAlmostEqual(v[1, 2, 0, 1], 2) self.assertAlmostEqual(v[1, 2, 0, 2], 1)
def cube(size=1, lower_left=(0,0,0)): """ Create a cube with parmetric origin at *(0,0,0)*. :param float size: Size(s), either a single scalar or a tuple of scalars per axis :param array-like lower_left: local origin, the lower bottom left corner of the cube :return: A linear parametrized box :rtype: Volume """ result = Volume() result.scale(size) result += lower_left return result
def test_permute_and_flip(self): v1 = Volume() v2 = Volume() v2.swap('u', 'v') v2.reverse('v') v2.swap('u', 'w') ori = Orientation.compute(v1, v2) self.assertEqual(ori.perm, (1, 2, 0)) self.assertEqual(ori.flip, (True, False, False))
def test_map_section(self): v1 = Volume() v2 = Volume() v2.swap('u', 'v') v2.reverse('v') v2.swap('u', 'w') ori = Orientation.compute(v1, v2) self.assertEqual(ori.map_section((-1, 0, -1)), (-1, -1, -1)) self.assertEqual(ori.map_section((0, 0, None)), (-1, None, 0))
def test_lookup(self): model = SplineModel(3, 3) v = Volume().refine(1, 1, 1) model.add(v) model.add(v + (1, 0, 0)) model.add(v + (0, 0, 1)) q = Volume().refine(1, 1, 1) self.assertIs(model[q].node, model[v].node) q = Volume().refine(1, 1, 1).reverse('u').swap('u', 'v') self.assertIs(model[q].node, model[v].node) self.assertIs(model[v.section(w=-1)].node, model[(v + (0, 0, 1)).section(w=0)].node)
def test_map_array(self): v1 = Volume() v2 = Volume() v2.swap('u', 'v') v2.reverse('v') v2.swap('u', 'w') ori = Orientation.compute(v1, v2) self.assertTrue((ori.map_array( np.reshape(np.arange(8, dtype=int), (2, 2, 2))) == np.reshape([2, 6, 3, 7, 0, 4, 1, 5], (2, 2, 2))).all())
def test_raise_order(self): # more or less random 3D volume with p=[2,2,1] and n=[4,3,2] controlpoints = [[0, 0, 0], [-1, 1, 0], [0, 2, 0], [1, -1, 0], [1, 0, 0], [1, 1, 0], [2, 1, 0], [2, 2, 0], [2, 3, 0], [3, 0, 0], [4, 1, 0], [3, 2, 0], [0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 2], [1, 0, 2], [1, 1, 2], [2, 1, 2], [2, 2, 2], [2, 3, 2], [3, 0, 1], [4, 1, 1], [3, 2, 1]] basis1 = BSplineBasis(3, [0, 0, 0, .4, 1, 1, 1]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints) self.assertEqual(vol.order(), (3, 3, 2)) evaluation_point1 = vol(0.23, 0.37, 0.44) # pick some evaluation point (could be anything) vol.raise_order(1, 2, 4) self.assertEqual(vol.order(), (4, 5, 6)) evaluation_point2 = vol(0.23, 0.37, 0.44) # evaluation before and after RaiseOrder should remain unchanged self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2]) # test a rational 3D volume controlpoints = [[0, 0, 1, 1], [-1, 1, .96, 1], [0, 2, 1, 1], [1, -1, 1, 1], [1, 0, .8, 1], [1, 1, 1, 1], [2, 1, .89, 1], [2, 2, .9, 1], [2, 3, 1, 1], [3, 0, 1, 1], [4, 1, 1, 1], [3, 2, 1, 1], [0, 0, 1, 2], [-1, 1, .7, 2], [0, 2, 1.3, 2], [1, -1, 1, 2], [1, 0, .77, 2], [1, 1, 1, 2], [2, 1, .89, 1], [2, 2, .8, 4], [2, 3, 1, 1], [3, 0, 1, 1], [4, 1, 1, 1], [3, 2, 1, 1]] basis1 = BSplineBasis(3, [0, 0, 0, .4, 1, 1, 1]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints, True) self.assertEqual(vol.order()[0], 3) self.assertEqual(vol.order()[1], 3) evaluation_point1 = vol(0.23, 0.37, 0.44) vol.raise_order(1, 2, 1) self.assertEqual(vol.order(), (4, 5, 3)) evaluation_point2 = vol(0.23, 0.37, 0.44) # evaluation before and after RaiseOrder should remain unchanged self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2])
def interpolate(x, bases, u=None): """ Interpolate a volume on a set of regular gridded interpolation points `x`. The points can be either a matrix (in which case the first index is interpreted as a flat row-first index of the interpolation grid) or a 4D tensor. In both cases the last index is the physical coordinates. :param numpy.ndarray x: Grid of interpolation points :param [BSplineBasis] bases: The basis to interpolate on :param [array-like] u: Parametric interpolation points, defaults to Greville points of the basis :return: Interpolated volume :rtype: Volume """ vol_shape = [b.num_functions() for b in bases] dim = x.shape[-1] if len(x.shape) == 2: x = x.reshape(vol_shape + [dim]) if u is None: u = [b.greville() for b in bases] N_all = [b(t) for b, t in zip(bases, u)] N_all.reverse() cp = x for N in N_all: cp = np.tensordot(np.linalg.inv(N), cp, axes=(1, 2)) return Volume(bases[0], bases[1], bases[2], cp.transpose(2, 1, 0, 3).reshape((np.prod(vol_shape), dim)))
def least_square_fit(x, bases, u): """ Perform a least-square fit of a point cloud `x` onto a spline basis. The points can be either a matrix (in which case the first index is interpreted as a flat row-first index of the interpolation grid) or a 4D tensor. In both cases the last index is the physical coordinates. There must be at least as many points as basis functions. :param numpy.ndarray x: Grid of evaluation points :param [BSplineBasis] bases: Basis on which to interpolate :param [array-like] u: Parametric values at evaluation points :return: Approximated volume :rtype: Volume """ vol_shape = [b.num_functions() for b in bases] dim = x.shape[-1] if len(x.shape) == 2: x = x.reshape(vol_shape + [dim]) N_all = [b(t) for b, t in zip(bases, u)] N_all.reverse() cp = x for N in N_all: cp = np.tensordot(N.T, cp, axes=(1, 2)) for N in N_all: cp = np.tensordot(np.linalg.inv(N.T * N), cp, axes=(1, 2)) return Volume(bases[0], bases[1], bases[2], cp.transpose(2, 1, 0, 3).reshape((np.prod(vol_shape), dim)))
def read(self): lines = self.lines() version = next(lines).split() assert version[0] == 'C' assert version[3] == '0' # No support for rational SPL yet pardim = int(version[1]) physdim = int(version[2]) orders = [int(k) for k in islice(lines, pardim)] ncoeffs = [int(k) for k in islice(lines, pardim)] totcoeffs = int(np.prod(ncoeffs)) nknots = [a + b for a, b in zip(orders, ncoeffs)] next(lines) # Skip spline accuracy knots = [[float(k) for k in islice(lines, nkts)] for nkts in nknots] bases = [BSplineBasis(p, kts, -1) for p, kts in zip(orders, knots)] cpts = np.array([float(k) for k in islice(lines, totcoeffs * physdim)]) cpts = cpts.reshape(physdim, *(ncoeffs[::-1])).transpose() if pardim == 1: patch = Curve(*bases, controlpoints=cpts, raw=True) elif pardim == 2: patch = Surface(*bases, controlpoints=cpts, raw=True) elif pardim == 3: patch = Volume(*bases, controlpoints=cpts, raw=True) else: patch = SplineObject(bases, controlpoints=cpts, raw=True) return [patch]
def test_indexing(self): v = Volume() self.assertEqual(v[0][0], 0.0) self.assertEqual(v[0][1], 0.0) self.assertEqual(v[0][2], 0.0) self.assertEqual(v[1][0], 1.0) self.assertEqual(v[1][1], 0.0) self.assertEqual(v[1][2], 0.0) self.assertEqual(v[-1][0], 1.0) self.assertEqual(v[-1][1], 1.0) self.assertEqual(v[-1][2], 1.0) self.assertEqual(v[:][0, 0], 0.0) self.assertEqual(v[:][1, 0], 1.0) self.assertEqual(v[:][1, 1], 0.0) self.assertEqual(v[:][2, 1], 1.0) self.assertEqual(v[:][2, 2], 0.0) self.assertEqual(v[:][5, 0], 1.0) self.assertEqual(v[:][5, 1], 0.0) self.assertEqual(v[:][5, 2], 1.0) self.assertEqual(v[0, 0, 0][0], 0.0) self.assertEqual(v[0, 0, 0][1], 0.0) self.assertEqual(v[0, 0, 0][2], 0.0) self.assertEqual(v[0, 1, 0][0], 0.0) self.assertEqual(v[0, 1, 0][1], 1.0) self.assertEqual(v[0, 1, 0][2], 0.0) self.assertEqual(v[0, :, 1][0, 0], 0.0) self.assertEqual(v[0, :, 1][0, 1], 0.0) self.assertEqual(v[0, :, 1][0, 2], 1.0) self.assertEqual(v[0, :, 1][1, 0], 0.0) self.assertEqual(v[0, :, 1][1, 1], 1.0) self.assertEqual(v[0, :, 1][1, 2], 1.0)
def test_edge_surfaces_six_sides(self): # create the unit cube vol = Volume() vol.raise_order(2,2,2) vol.refine(3) edges = vol.faces() # edge_surface should give back the same unit cube vol2 = vf.edge_surfaces(edges) # check discretization self.assertEqual(vol2.order(0), 4) self.assertEqual(vol2.order(1), 4) self.assertEqual(vol2.order(2), 4) self.assertEqual(len(vol2.knots(0)), 5) # [0,.25,.5,.75,1] self.assertEqual(len(vol2.knots(1)), 5) self.assertEqual(len(vol2.knots(2)), 5) # check a 5x5x5 evaluation grid u = np.linspace(0,1,5) v = np.linspace(0,1,5) w = np.linspace(0,1,5) pt = vol( u,v,w) pt2 = vol2(u,v,w) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
def get_mixed_cont_mesh(self): # Create mixed discontinuity mesh: C^0, C^0, C^{-1} nx, ny, nz = self.n Xz = self.raw.get_discontinuous_z() b1 = BSplineBasis(2, sorted(list(range(self.n[0]+1))+[0,self.n[0]])) b2 = BSplineBasis(2, sorted(list(range(self.n[1]+1))+[0,self.n[1]])) b3 = BSplineBasis(2, sorted(list(range(self.n[2]+1))*2)) true_vol = Volume(b1, b2, b3, Xz, raw=True) return true_vol
def get_spline(spline, n, p, rational=False): basis = BSplineBasis(p, [0]*(p-1) + list(range(n-p+2)) + [n-p+1]*(p-1)) if spline == 'curve': return Curve(basis, rational=rational) elif spline == 'surface': return Surface(basis, basis, rational=rational) elif spline == 'volume': return Volume(basis, basis, basis, rational=rational) return None
def test_make_identical(self): basis1 = BSplineBasis(4, [-1,-1,0,0,1,1,2,2], periodic=1) basis2 = BSplineBasis(3, [-1,0,0,1,1,2], periodic=0) basis3 = BSplineBasis(2) vol1 = Volume() vol2 = Volume(basis1, basis2, basis3) vol1.refine(1) Volume.make_splines_identical(vol1,vol2) for v in (vol1, vol2): self.assertEqual(v.periodic(0), False) self.assertEqual(v.periodic(1), False) self.assertEqual(v.periodic(2), False) self.assertEqual(v.order(), (4,3,2)) self.assertAlmostEqual(len(v.knots(0, True)), 11) self.assertAlmostEqual(len(v.knots(1, True)), 8) self.assertAlmostEqual(len(v.knots(2, True)), 5)
def get_cm1_mesh(self): # Create the C^{-1} mesh nx, ny, nz = self.n Xm1 = self.raw.get_discontinuous_all() b1 = BSplineBasis(2, sorted(list(range(self.n[0]+1))*2)) b2 = BSplineBasis(2, sorted(list(range(self.n[1]+1))*2)) b3 = BSplineBasis(2, sorted(list(range(self.n[2]+1))*2)) discont_vol = Volume(b1, b2, b3, Xm1) return discont_vol
def test_operators(self): v = Volume() v.raise_order(1,1,2) v.refine(3,2,1) # test translation operator v2 = v + [1,0,0] v3 = [1,0,0] + v v += [1,0,0] self.assertTrue(np.allclose(v2.controlpoints, v3.controlpoints)) self.assertTrue(np.allclose(v.controlpoints, v3.controlpoints)) # test scaling operator v2 = v * 3 v3 = 3 * v v *= 3 self.assertTrue(np.allclose(v2.controlpoints, v3.controlpoints)) self.assertTrue(np.allclose(v.controlpoints, v3.controlpoints))
def test_swap(self): # more or less random 3D volume with p=[3,2,1] and n=[4,3,2] controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 2], [1, 0, 2], [1, 1, 2], [2, 1, 2], [2, 2, 2], [2, 3, 2], [3, 0, 0], [4, 1, 0], [3, 2, 0], [0, 0, 3], [-1, 1, 3], [0, 2, 3], [1, -1, 5], [1, 0, 5], [1, 1, 5], [2, 1, 4], [2, 2, 4], [2, 3, 4], [3, 0, 2], [4, 1, 2], [3, 2, 2]] basis1 = BSplineBasis(4, [0, 0, 0, 0, 2, 2, 2, 2]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints) evaluation_point1 = vol(0.23, .56, .12) control_point1 = vol[ 1] # this is control point i=(1,0,0), when n=(4,3,2) self.assertEqual(vol.order(), (4, 3, 2)) vol.swap(0, 1) evaluation_point2 = vol(0.56, .23, .12) control_point2 = vol[ 3] # this is control point i=(0,1,0), when n=(3,4,2) self.assertEqual(vol.order(), (3, 4, 2)) # ensure that volume has not chcanged, by comparing evaluation of it self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2]) # check that the control points have re-ordered themselves self.assertEqual(control_point1[0], control_point2[0]) self.assertEqual(control_point1[1], control_point2[1]) self.assertEqual(control_point1[2], control_point2[2]) vol.swap(1, 2) evaluation_point3 = vol(.56, .12, .23) control_point3 = vol[ 6] # this is control point i=(0,0,1), when n=(3,2,4) self.assertEqual(vol.order(), (3, 2, 4)) # ensure that volume has not chcanged, by comparing evaluation of it self.assertAlmostEqual(evaluation_point1[0], evaluation_point3[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point3[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point3[2]) # check that the control points have re-ordered themselves self.assertEqual(control_point1[0], control_point3[0]) self.assertEqual(control_point1[1], control_point3[1]) self.assertEqual(control_point1[2], control_point3[2])
def test_edge_surfaces_six_sides(self): # create the unit cube vol = Volume() vol.raise_order(2,2,2) vol.refine(3) edges = vol.faces() # edge_surface should give back the same unit cube vol2 = VolumeFactory.edge_surfaces(edges) # check discretization self.assertEqual(vol2.order(0), 4) self.assertEqual(vol2.order(1), 4) self.assertEqual(vol2.order(2), 4) self.assertEqual(len(vol2.knots(0)), 5) # [0,.25,.5,.75,1] self.assertEqual(len(vol2.knots(1)), 5) self.assertEqual(len(vol2.knots(2)), 5) # check a 5x5x5 evaluation grid u = np.linspace(0,1,5) v = np.linspace(0,1,5) w = np.linspace(0,1,5) pt = vol( u,v,w) pt2 = vol2(u,v,w) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
def test_faces(self): vol1 = Volume() faces = vol1.faces() self.assertEqual(len(faces), 6) # check that it all comes out in the order umin, umax, vmin, vmax, wmin, wmax self.assertTrue(np.allclose(faces[0][0, 0], (0, 0, 0))) self.assertTrue(np.allclose(faces[0][1, 1], (0, 1, 1))) self.assertTrue(np.allclose(faces[1][0, 0], (1, 0, 0))) self.assertTrue(np.allclose(faces[1][1, 1], (1, 1, 1))) self.assertTrue(np.allclose(faces[2][0, 0], (0, 0, 0))) self.assertTrue(np.allclose(faces[2][1, 1], (1, 0, 1))) self.assertTrue(np.allclose(faces[3][0, 0], (0, 1, 0))) self.assertTrue(np.allclose(faces[3][1, 1], (1, 1, 1))) self.assertTrue(np.allclose(faces[4][0, 0], (0, 0, 0))) self.assertTrue(np.allclose(faces[4][1, 1], (1, 1, 0))) self.assertTrue(np.allclose(faces[5][0, 0], (0, 0, 1))) self.assertTrue(np.allclose(faces[5][1, 1], (1, 1, 1))) # one parametric direction is periodic, these indices should return None vol2 = vf.cylinder() faces = vol2.faces() self.assertEqual(len(faces), 6) self.assertIsNotNone(faces[0]) self.assertIsNotNone(faces[1]) self.assertIsNone(faces[2]) self.assertIsNone(faces[3]) self.assertIsNotNone(faces[4]) self.assertIsNotNone(faces[5]) # two parametric directions are periodic vol3 = vf.torus() faces = vol3.faces() self.assertEqual(len(faces), 6) self.assertIsNotNone(faces[0]) self.assertIsNotNone(faces[1]) self.assertIsNone(faces[2]) self.assertIsNone(faces[3]) self.assertIsNone(faces[4]) self.assertIsNone(faces[5])
def revolve(surf, theta=2 * pi, axis=(0,0,1)): """ Revolve a volume by sweeping a surface in a rotational fashion around an axis. :param Surface surf: Surface to revolve :param float theta: Angle to revolve, in radians :param array-like axis: Axis of rotation :return: The revolved surface :rtype: Volume """ surf = surf.clone() # clone input surface, throw away old reference surf.set_dimension(3) # add z-components (if not already present) surf.force_rational() # add weight (if not already present) # align axis with the z-axis normal_theta = atan2(axis[1], axis[0]) normal_phi = atan2(sqrt(axis[0]**2 + axis[1]**2), axis[2]) surf.rotate(-normal_theta, [0,0,1]) surf.rotate(-normal_phi, [0,1,0]) path = CurveFactory.circle_segment(theta=theta) n = len(surf) # number of control points of the surface m = len(path) # number of control points of the sweep cp = np.zeros((m * n, 4)) dt = np.sign(theta)*(path.knots(0)[1] - path.knots(0)[0]) / 2.0 for i in range(m): weight = path[i,-1] cp[i * n:(i + 1) * n, :] = np.reshape(surf.controlpoints.transpose(1, 0, 2), (n, 4)) cp[i * n:(i + 1) * n, 2] *= weight cp[i * n:(i + 1) * n, 3] *= weight surf.rotate(dt) result = Volume(surf.bases[0], surf.bases[1], path.bases[0], cp, True) # rotate it back again result.rotate(normal_phi, [0,1,0]) result.rotate(normal_theta, [0,0,1]) return result
def test_permute(self): v1 = Volume() v2 = Volume() v2.swap('u', 'v') ori = Orientation.compute(v1, v2) self.assertEqual(ori.perm, (1, 0, 2)) self.assertEqual(ori.flip, (False, False, False)) v2.swap('v', 'w') ori = Orientation.compute(v1, v2) self.assertEqual(ori.perm, (2, 0, 1)) self.assertEqual(ori.flip, (False, False, False))
def test_flip(self): v1 = Volume() v2 = Volume() v2.reverse('u') ori = Orientation.compute(v1, v2) self.assertEqual(ori.perm, (0, 1, 2)) self.assertEqual(ori.flip, (True, False, False)) v2.reverse('w') ori = Orientation.compute(v1, v2) self.assertEqual(ori.perm, (0, 1, 2)) self.assertEqual(ori.flip, (True, False, True))
def test_evaluate_nontensor(self): vol = Volume(BSplineBasis(7), BSplineBasis(7), BSplineBasis(5)) u_val = [0, 0.1, 0.9, 0.3] v_val = [0.2, 0.3, 0.9, 0.4] w_val = [0.3, 0.5, 0.5, 0.0] value = vol(u_val, v_val, w_val, tensor=False) self.assertEqual(value.shape[0], 4) self.assertEqual(value.shape[1], 3) for i, (u, v, w) in enumerate(zip(u_val, v_val, w_val)): self.assertAlmostEqual(value[i, 0], u) # identity map x=u self.assertAlmostEqual(value[i, 1], v) # identity map y=v self.assertAlmostEqual(value[i, 2], w) # identity map z=w
def test_reverse(self): # identity mapping, control points generated from knot vector basis1 = BSplineBasis(4, [2, 2, 2, 2, 3, 6, 12, 12, 12, 12]) basis2 = BSplineBasis(3, [-3, -3, -3, 20, 30, 33, 33, 33]) basis3 = BSplineBasis(5, [0, 0, 0, 0, 0, 8, 8, 8, 8, 8]) vol = Volume(basis1, basis2, basis3) u = np.linspace(2, 12, 5) v = np.linspace(-3, 33, 5) w = np.linspace(0, 8, 5) pt = vol(u, v, w) vol.reverse('v') pt2 = vol(u, v[::-1], w) self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0) self.assertAlmostEqual(vol.start('v'), -3) self.assertAlmostEqual(vol.end('v'), 33) vol.reverse(2) pt2 = vol(u, v[::-1], w[::-1]) self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0) self.assertAlmostEqual(vol.start('w'), 0) self.assertAlmostEqual(vol.end('w'), 8)
def test_cp_numbering(self): model = SplineModel(3, 3) v = Volume().refine(1, 1, 1) model.add(v) model.add(v + (1, 0, 0)) model.add(v + (0, 0, 1)) # Predictable numbering of control points model.generate_cp_numbers() cps = model.cps() self.assertEqual(cps.shape, (63, 3)) np.testing.assert_almost_equal(cps[:27], v.controlpoints.reshape(-1, 3)) np.testing.assert_almost_equal( cps[27:45], v.controlpoints[1:].reshape(-1, 3) + (1, 0, 0)) np.testing.assert_almost_equal( cps[45:], v.controlpoints[:, :, 1:].reshape(-1, 3) + (0, 0, 1))
def test_cell_numbering(self): model = SplineModel(3, 3) v = Volume().refine(1, 1, 1) model.add(v) model.add(v + (1, 0, 0)) model.add(v + (0, 0, 1)) # Predictable numbering of cells model.generate_cell_numbers() self.assertTrue((model[v].node.cell_numbers.flatten() == np.arange( 8, dtype=int)).all()) self.assertTrue( (model[v + (1, 0, 0)].node.cell_numbers.flatten() == np.arange( 8, 16, dtype=int)).all()) self.assertTrue( (model[v + (0, 0, 1)].node.cell_numbers.flatten() == np.arange( 16, 24, dtype=int)).all())
def test_swap(self): # more or less random 3D volume with p=[3,2,1] and n=[4,3,2] controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 2], [1, 0, 2], [1, 1, 2], [2, 1, 2], [2, 2, 2], [2, 3, 2], [3, 0, 0], [4, 1, 0], [3, 2, 0], [0, 0, 3], [-1, 1, 3], [0, 2, 3], [1, -1, 5], [1, 0, 5], [1, 1, 5], [2, 1, 4], [2, 2, 4], [2, 3, 4], [3, 0, 2], [4, 1, 2], [3, 2, 2]] basis1 = BSplineBasis(4, [0, 0, 0, 0, 2, 2, 2, 2]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints) evaluation_point1 = vol(0.23, .56, .12) control_point1 = vol[1] # this is control point i=(1,0,0), when n=(4,3,2) self.assertEqual(vol.order(), (4, 3, 2)) vol.swap(0, 1) evaluation_point2 = vol(0.56, .23, .12) control_point2 = vol[3] # this is control point i=(0,1,0), when n=(3,4,2) self.assertEqual(vol.order(), (3, 4, 2)) # ensure that volume has not chcanged, by comparing evaluation of it self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2]) # check that the control points have re-ordered themselves self.assertEqual(control_point1[0], control_point2[0]) self.assertEqual(control_point1[1], control_point2[1]) self.assertEqual(control_point1[2], control_point2[2]) vol.swap(1, 2) evaluation_point3 = vol(.56, .12, .23) control_point3 = vol[6] # this is control point i=(0,0,1), when n=(3,2,4) self.assertEqual(vol.order(), (3, 2, 4)) # ensure that volume has not chcanged, by comparing evaluation of it self.assertAlmostEqual(evaluation_point1[0], evaluation_point3[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point3[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point3[2]) # check that the control points have re-ordered themselves self.assertEqual(control_point1[0], control_point3[0]) self.assertEqual(control_point1[1], control_point3[1]) self.assertEqual(control_point1[2], control_point3[2])
def extrude(surf, amount): """ Extrude a surface by sweeping it to a given height. :param Surface surf: Surface to extrude :param array-like amount: 3-component vector of sweeping amount and direction :return: The extruded surface :rtype: Volume """ surf.set_dimension(3) # add z-components (if not already present) cp = [] for controlpoint in surf: cp.append(list(controlpoint)) surf += amount for controlpoint in surf: cp.append(list(controlpoint)) surf -= amount return Volume(surf.bases[0], surf.bases[1], BSplineBasis(2), cp, surf.rational)
def test_bounding_box(self): vol = Volume() bb = vol.bounding_box() self.assertAlmostEqual(bb[0][0], 0) self.assertAlmostEqual(bb[0][1], 1) self.assertAlmostEqual(bb[1][0], 0) self.assertAlmostEqual(bb[1][1], 1) self.assertAlmostEqual(bb[2][0], 0) self.assertAlmostEqual(bb[2][1], 1) vol.refine(2) vol.rotate(pi / 4, [1, 0, 0]) vol += (1, 0, 1) bb = vol.bounding_box() self.assertAlmostEqual(bb[0][0], 1) self.assertAlmostEqual(bb[0][1], 2) self.assertAlmostEqual(bb[1][0], -sqrt(2) / 2) self.assertAlmostEqual(bb[1][1], sqrt(2) / 2) self.assertAlmostEqual(bb[2][0], 1) self.assertAlmostEqual(bb[2][1], 1 + sqrt(2))
def test_reverse(self): # identity mapping, control points generated from knot vector basis1 = BSplineBasis(4, [2,2,2,2,3,6,12,12,12,12]) basis2 = BSplineBasis(3, [-3,-3,-3,20,30,33,33,33]) basis3 = BSplineBasis(5, [0,0,0,0,0,8,8,8,8,8]) vol = Volume(basis1, basis2, basis3) u = np.linspace( 2,12,5) v = np.linspace(-3,33,5) w = np.linspace( 0, 8,5) pt = vol(u,v,w) vol.reverse('v') pt2 = vol(u,v[::-1],w) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) self.assertAlmostEqual(vol.start('v'), -3) self.assertAlmostEqual(vol.end('v'), 33) vol.reverse(2) pt2 = vol(u,v[::-1],w[::-1]) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) self.assertAlmostEqual(vol.start('w'), 0) self.assertAlmostEqual(vol.end('w'), 8)
def test_make_identical(self): basis1 = BSplineBasis(4, [-1, -1, 0, 0, 1, 1, 2, 2], periodic=1) basis2 = BSplineBasis(3, [-1, 0, 0, 1, 1, 2], periodic=0) basis3 = BSplineBasis(2) vol1 = Volume() vol2 = Volume(basis1, basis2, basis3) vol1.refine(1) Volume.make_splines_identical(vol1, vol2) for v in (vol1, vol2): self.assertEqual(v.periodic(0), False) self.assertEqual(v.periodic(1), False) self.assertEqual(v.periodic(2), False) self.assertEqual(v.order(), (4, 3, 2)) self.assertAlmostEqual(len(v.knots(0, True)), 11) self.assertAlmostEqual(len(v.knots(1, True)), 8) self.assertAlmostEqual(len(v.knots(2, True)), 5)
def test_node_counts(self): model = SplineModel(3, 3) v = Volume().refine(1, 1, 1) model.add(v) model.add(v + (1, 0, 0)) model.add(v + (0, 0, 1)) # 3 volumes cat = model.catalogue self.assertEqual(len(cat.top_nodes()), 3) # 16 faces cat = cat.lower self.assertEqual(len(cat.top_nodes()), 16) # 28 edges cat = cat.lower self.assertEqual(len(cat.top_nodes()), 28) # 16 vertices cat = cat.lower self.assertEqual(len(cat.top_nodes()), 16)
def test_bounding_box(self): vol = Volume() bb = vol.bounding_box() self.assertAlmostEqual(bb[0][0], 0 ) self.assertAlmostEqual(bb[0][1], 1 ) self.assertAlmostEqual(bb[1][0], 0 ) self.assertAlmostEqual(bb[1][1], 1 ) self.assertAlmostEqual(bb[2][0], 0 ) self.assertAlmostEqual(bb[2][1], 1 ) vol.refine(2) vol.rotate(pi/4, [1,0,0]) vol += (1,0,1) bb = vol.bounding_box() self.assertAlmostEqual(bb[0][0], 1 ) self.assertAlmostEqual(bb[0][1], 2 ) self.assertAlmostEqual(bb[1][0], -sqrt(2)/2 ) self.assertAlmostEqual(bb[1][1], sqrt(2)/2 ) self.assertAlmostEqual(bb[2][0], 1 ) self.assertAlmostEqual(bb[2][1], 1+sqrt(2) )
def test_operators(self): v = Volume() v.raise_order(1, 1, 2) v.refine(3, 2, 1) # test translation operator v2 = v + [1, 0, 0] v3 = [1, 0, 0] + v v += [1, 0, 0] self.assertTrue(np.allclose(v2.controlpoints, v3.controlpoints)) self.assertTrue(np.allclose(v.controlpoints, v3.controlpoints)) # test scaling operator v2 = v * 3 v3 = 3 * v v *= 3 self.assertTrue(np.allclose(v2.controlpoints, v3.controlpoints)) self.assertTrue(np.allclose(v.controlpoints, v3.controlpoints))
def edge_surfaces(*surfaces): """ Create the volume defined by the region between the input surfaces. In case of six input surfaces, these must be given in the order: bottom, top, left, right, back, front. Opposing sides must be parametrized in the same directions. :param [Surface] surfaces: Two or six edge surfaces :return: The enclosed volume :rtype: Volume :raises ValueError: If the length of *surfaces* is not two or six """ if len(surfaces) == 1: # probably gives input as a list-like single variable surfaces = surfaces[0] if len(surfaces) == 2: surf1 = surfaces[0].clone() surf2 = surfaces[1].clone() Surface.make_splines_identical(surf1, surf2) (n1, n2, d) = surf1.controlpoints.shape # d = dimension + rational controlpoints = np.zeros((n1, n2, 2, d)) controlpoints[:, :, 0, :] = surf1.controlpoints controlpoints[:, :, 1, :] = surf2.controlpoints # Volume constructor orders control points in a different way, so we # create it from scratch here result = Volume(surf1.bases[0], surf1.bases[1], BSplineBasis(2), controlpoints, rational=surf1.rational, raw=True) return result elif len(surfaces) == 6: if any([surf.rational for surf in surfaces]): raise RuntimeError('edge_surfaces not supported for rational splines') # coons patch (https://en.wikipedia.org/wiki/Coons_patch) umin = surfaces[0] umax = surfaces[1] vmin = surfaces[2] vmax = surfaces[3] wmin = surfaces[4] wmax = surfaces[5] vol1 = edge_surfaces(umin,umax) vol2 = edge_surfaces(vmin,vmax) vol3 = edge_surfaces(wmin,wmax) vol4 = Volume(controlpoints=vol1.corners(order='F'), rational=vol1.rational) vol1.swap(0, 2) vol1.swap(1, 2) vol2.swap(1, 2) vol4.swap(1, 2) Volume.make_splines_identical(vol1, vol2) Volume.make_splines_identical(vol1, vol3) Volume.make_splines_identical(vol1, vol4) Volume.make_splines_identical(vol2, vol3) Volume.make_splines_identical(vol2, vol4) Volume.make_splines_identical(vol3, vol4) result = vol1.clone() result.controlpoints += vol2.controlpoints result.controlpoints += vol3.controlpoints result.controlpoints -= 2*vol4.controlpoints return result else: raise ValueError('Requires two or six input surfaces')
def test_insert_knot(self): # more or less random 3D volume with p=[2,2,1] and n=[4,3,2] controlpoints = [[0, 0, 0], [-1, 1, 0], [0, 2, 0], [1, -1, 0], [1, 0, 0], [1, 1, 0], [2, 1, 0], [2, 2, 0], [2, 3, 0], [3, 0, 0], [4, 1, 0], [3, 2, 0], [0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 2], [1, 0, 2], [1, 1, 2], [2, 1, 2], [2, 2, 2], [2, 3, 2], [3, 0, 1], [4, 1, 1], [3, 2, 1]] basis1 = BSplineBasis(3, [0, 0, 0, .4, 1, 1, 1]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints) evaluation_point1 = vol(0.23, 0.37, 0.44) # pick some evaluation point (could be anything) vol.insert_knot(.20, 0) vol.insert_knot( .5, 'u') vol.insert_knot( .7, 0) vol.insert_knot( .1, 1) vol.insert_knot( 1.0 / 3, 1) vol.insert_knot( .8, 2) vol.insert_knot( .9, 'W') knot1, knot2, knot3 = vol.knots(with_multiplicities=True) self.assertEqual(len(knot1), 10) # 7 to start with, 3 new ones self.assertEqual(len(knot2), 8) # 6 to start with, 2 new ones self.assertEqual(len(knot3), 6) # 4 to start with, 2 new ones self.assertEqual(vol.controlpoints.shape, (7, 5, 4, 3)) evaluation_point2 = vol(0.23, 0.37, 0.44) # evaluation before and after insert_knot should remain unchanged self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2]) # test a rational 3D volume controlpoints = [[0, 0, 1, 1], [-1, 1, .96, 1], [0, 2, 1, 1], [1, -1, 1, 1], [1, 0, .8, 1], [1, 1, 1, 1], [2, 1, .89, 1], [2, 2, .9, 1], [2, 3, 1, 1], [3, 0, 1, 1], [4, 1, 1, 1], [3, 2, 1, 1], [0, 0, 1, 2], [-1, 1, .7, 2], [0, 2, 1.3, 2], [1, -1, 1, 2], [1, 0, .77, 2], [1, 1, 1, 2], [2, 1, .89, 1], [2, 2, .8, 4], [2, 3, 1, 1], [3, 0, 1, 1], [4, 1, 1, 1], [3, 2, 1, 1]] basis1 = BSplineBasis(3, [0, 0, 0, .4, 1, 1, 1]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints, True) evaluation_point1 = vol(0.23, 0.37, 0.44) vol.insert_knot([.20, .5, .7], 0) vol.insert_knot([.1, 1.0 / 3], 1) vol.insert_knot([.8, .9], 2) knot1, knot2, knot3 = vol.knots(with_multiplicities=True) self.assertEqual(len(knot1), 10) # 7 to start with, 3 new ones self.assertEqual(len(knot2), 8) # 6 to start with, 2 new ones self.assertEqual(len(knot3), 6) # 4 to start with, 2 new ones self.assertEqual(vol.controlpoints.shape, (7, 5, 4, 4)) evaluation_point2 = vol(0.23, 0.37, 0.44) # evaluation before and after RaiseOrder should remain unchanged self.assertAlmostEqual(evaluation_point1[0], evaluation_point2[0]) self.assertAlmostEqual(evaluation_point1[1], evaluation_point2[1]) self.assertAlmostEqual(evaluation_point1[2], evaluation_point2[2])
def test_split(self): # more or less random 3D volume with p=[3,2,1] and n=[4,3,2] controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 2], [1, 0, 2], [1, 1, 2], [2, 1, 2], [2, 2, 2], [2, 3, 2], [3, 0, 0], [4, 1, 0], [3, 2, 0], [0, 0, 3], [-1, 1, 3], [0, 2, 3], [1, -1, 5], [1, 0, 5], [1, 1, 5], [2, 1, 4], [2, 2, 4], [2, 3, 4], [3, 0, 2], [4, 1, 2], [3, 2, 2]] basis1 = BSplineBasis(4, [0, 0, 0, 0, 2, 2, 2, 2]) basis2 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis3 = BSplineBasis(2, [0, 0, 1, 1]) vol = Volume(basis1, basis2, basis3, controlpoints) split_u_vol = vol.split([.1, .2, .3, .4, .5, .6], 0) split_v_vol = vol.split(.1, 1) split_w_vol = vol.split([.4, .5, .6], 2) self.assertEqual(len(split_u_vol), 7) self.assertEqual(len(split_v_vol), 2) self.assertEqual(len(split_w_vol), 4) # check that the u-vector is properly split self.assertAlmostEqual(split_u_vol[0].start(0), 0.0) self.assertAlmostEqual(split_u_vol[0].end(0), 0.1) self.assertAlmostEqual(split_u_vol[1].start(0), 0.1) self.assertAlmostEqual(split_u_vol[1].end(0), 0.2) self.assertAlmostEqual(split_u_vol[2].start(0), 0.2) self.assertAlmostEqual(split_u_vol[2].end(0), 0.3) self.assertAlmostEqual(split_u_vol[6].start(0), 0.6) self.assertAlmostEqual(split_u_vol[6].end(0), 2.0) # check that the other vectors remain unchanged self.assertAlmostEqual(split_u_vol[2].start(1), 0.0) self.assertAlmostEqual(split_u_vol[2].end(1), 1.0) self.assertAlmostEqual(split_u_vol[2].start(2), 0.0) self.assertAlmostEqual(split_u_vol[2].end(2), 1.0) # check that the v-vector is properly split self.assertAlmostEqual(split_v_vol[0].start(1), 0.0) self.assertAlmostEqual(split_v_vol[0].end(1), 0.1) self.assertAlmostEqual(split_v_vol[1].start(1), 0.1) self.assertAlmostEqual(split_v_vol[1].end(1), 1.0) # check that the others remain unchanged self.assertAlmostEqual(split_v_vol[1].start(0), 0.0) self.assertAlmostEqual(split_v_vol[1].end(0), 2.0) self.assertAlmostEqual(split_v_vol[1].start(2), 0.0) self.assertAlmostEqual(split_v_vol[1].end(2), 1.0) # check that the w-vector is properly split self.assertAlmostEqual(split_w_vol[1].start(2), 0.4) self.assertAlmostEqual(split_w_vol[1].end(2), 0.5) self.assertAlmostEqual(split_w_vol[2].start(2), 0.5) self.assertAlmostEqual(split_w_vol[2].end(2), 0.6) # check that the others remain unchanged self.assertAlmostEqual(split_w_vol[1].start(0), 0.0) self.assertAlmostEqual(split_w_vol[1].end(0), 2.0) self.assertAlmostEqual(split_w_vol[1].start(1), 0.0) self.assertAlmostEqual(split_w_vol[1].end(1), 1.0) # check that evaluations remain unchanged pt1 = vol(0.23, 0.12, 0.3) self.assertAlmostEqual(split_u_vol[2].evaluate(.23, .12, .3)[0], pt1[0]) self.assertAlmostEqual(split_u_vol[2].evaluate(.23, .12, .3)[1], pt1[1]) self.assertAlmostEqual(split_u_vol[2].evaluate(.23, .12, .3)[2], pt1[2]) self.assertAlmostEqual(split_v_vol[1].evaluate(.23, .12, .3)[0], pt1[0]) self.assertAlmostEqual(split_v_vol[1].evaluate(.23, .12, .3)[1], pt1[1]) self.assertAlmostEqual(split_v_vol[1].evaluate(.23, .12, .3)[2], pt1[2]) self.assertAlmostEqual(split_w_vol[0].evaluate(.23, .12, .3)[0], pt1[0]) self.assertAlmostEqual(split_w_vol[0].evaluate(.23, .12, .3)[1], pt1[1]) self.assertAlmostEqual(split_w_vol[0].evaluate(.23, .12, .3)[2], pt1[2])
def test_reparam(self): # identity mapping, control points generated from knot vector basis1 = BSplineBasis(4, [2,2,2,2,3,6,7,7,7,7]) basis2 = BSplineBasis(3, [-3,-3,-3,20,30,31,31,31]) basis3 = BSplineBasis(5, [0,0,0,0,0,8,8,8,8,8]) vol = Volume(basis1, basis2, basis3) self.assertAlmostEqual(vol.start(0), 2) self.assertAlmostEqual(vol.end(0), 7) self.assertAlmostEqual(vol.start(1), -3) self.assertAlmostEqual(vol.end(1), 31) self.assertAlmostEqual(vol.start(2), 0) self.assertAlmostEqual(vol.end(2), 8) vol.reparam((4,10), (0,9), (2,3)) self.assertAlmostEqual(vol.start(0), 4) self.assertAlmostEqual(vol.end(0), 10) self.assertAlmostEqual(vol.start(1), 0) self.assertAlmostEqual(vol.end(1), 9) self.assertAlmostEqual(vol.start(2), 2) self.assertAlmostEqual(vol.end(2), 3) vol.reparam((5,11), direction=0) self.assertAlmostEqual(vol.start(0), 5) self.assertAlmostEqual(vol.end(0), 11) self.assertAlmostEqual(vol.start(1), 0) self.assertAlmostEqual(vol.end(1), 9) self.assertAlmostEqual(vol.start(2), 2) self.assertAlmostEqual(vol.end(2), 3) vol.reparam((5,11), direction=1) self.assertAlmostEqual(vol.start(0), 5) self.assertAlmostEqual(vol.end(0), 11) self.assertAlmostEqual(vol.start(1), 5) self.assertAlmostEqual(vol.end(1), 11) self.assertAlmostEqual(vol.start(2), 2) self.assertAlmostEqual(vol.end(2), 3) vol.reparam((5,11), direction=2) self.assertAlmostEqual(vol.start(0), 5) self.assertAlmostEqual(vol.end(0), 11) self.assertAlmostEqual(vol.start(1), 5) self.assertAlmostEqual(vol.end(1), 11) self.assertAlmostEqual(vol.start(2), 5) self.assertAlmostEqual(vol.end(2), 11) vol.reparam((-9,9)) self.assertAlmostEqual(vol.start(0), -9) self.assertAlmostEqual(vol.end(0), 9) self.assertAlmostEqual(vol.start(1), 0) self.assertAlmostEqual(vol.end(1), 1) self.assertAlmostEqual(vol.start(2), 0) self.assertAlmostEqual(vol.end(2), 1) vol.reparam() self.assertAlmostEqual(vol.start(0), 0) self.assertAlmostEqual(vol.end(0), 1) self.assertAlmostEqual(vol.start(1), 0) self.assertAlmostEqual(vol.end(1), 1) self.assertAlmostEqual(vol.start(2), 0) self.assertAlmostEqual(vol.end(2), 1) vol.reparam((4,10), (0,9), (2,7)) vol.reparam(direction=1) self.assertAlmostEqual(vol.start(0), 4) self.assertAlmostEqual(vol.end(0), 10) self.assertAlmostEqual(vol.start(1), 0) self.assertAlmostEqual(vol.end(1), 1) self.assertAlmostEqual(vol.start(2), 2) self.assertAlmostEqual(vol.end(2), 7)
def test_volume(self): v = Volume() self.assertAlmostEqual(v.volume(), 1.0) v -= (.5, .5, 0) v[:,:,1,0:2] = 0.0 # squeeze top together, creating a pyramid self.assertAlmostEqual(v.volume(), 1.0/3)