def test_normal(self): surf = sf.sphere(1) surf.swap() u = np.linspace(surf.start(0) + 1e-3, surf.end(0) - 1e-3, 9) v = np.linspace(surf.start(1) + 1e-3, surf.end(1) - 1e-3, 9) xpts = surf(u, v, tensor=False) npts = surf.normal(u, v, tensor=False) self.assertEqual(npts.shape, (9, 3)) # check that the normal is pointing out of the unit ball on a 9x9 evaluation grid for (x, n) in zip(xpts, npts): self.assertAlmostEqual(n[0], x[0]) self.assertAlmostEqual(n[1], x[1]) self.assertAlmostEqual(n[2], x[2]) xpts = surf(u, v) npts = surf.normal(u, v) self.assertEqual(npts.shape, (9, 9, 3)) # check that the normal is pointing out of the unit ball on a 9x9 evaluation grid for (i, j) in zip(xpts, npts): for (x, n) in zip(i, j): self.assertAlmostEqual(n[0], x[0]) self.assertAlmostEqual(n[1], x[1]) self.assertAlmostEqual(n[2], x[2]) # check single value input n = surf.normal(0, 0) self.assertEqual(len(n), 3) # test 2D surface s = Surface() n = s.normal(.5, .5) self.assertEqual(len(n), 3) self.assertAlmostEqual(n[0], 0.0) self.assertAlmostEqual(n[1], 0.0) self.assertAlmostEqual(n[2], 1.0) n = s.normal([.25, .5], [.1, .2, .3, .4, .5, .6, .7, .8, .9]) self.assertEqual(n.shape[0], 2) self.assertEqual(n.shape[1], 9) self.assertEqual(n.shape[2], 3) self.assertAlmostEqual(n[1, 4, 0], 0.0) self.assertAlmostEqual(n[1, 4, 1], 0.0) self.assertAlmostEqual(n[1, 4, 2], 1.0) n = s.normal([.25, .5, .75], [.3, .5, .9], tensor=False) self.assertEqual(n.shape, (3, 3)) for i in range(3): for j in range(2): self.assertAlmostEqual(n[i, j], 0.0) self.assertAlmostEqual(n[i, 2], 1.0) # test errors s = Surface(BSplineBasis(3), BSplineBasis(3), [[0]] * 9) # 1D-surface with self.assertRaises(RuntimeError): s.normal(.5, .5)
def test_sphere(self): # unit ball surf = SurfaceFactory.sphere() # test 7x7 grid for radius = 1 for u in np.linspace(surf.start()[0], surf.end()[0], 7): for v in np.linspace(surf.start()[1], surf.end()[1], 7): self.assertAlmostEqual(np.linalg.norm(surf(u, v), 2), 1.0) self.assertAlmostEqual(surf.area(), 4*pi, places=3)
def test_sphere(self): # unit ball surf = sf.sphere() # test 7x7 grid for radius = 1 for u in np.linspace(surf.start()[0], surf.end()[0], 7): for v in np.linspace(surf.start()[1], surf.end()[1], 7): self.assertAlmostEqual(np.linalg.norm(surf(u, v), 2), 1.0) self.assertAlmostEqual(surf.area(), 4 * pi, places=3)
def sphere(self): dim = int( self.read_next_non_whitespace().strip()) r = float( next(self.fstream).strip()) center = np.array(next(self.fstream).split(), dtype=float) z_axis = np.array(next(self.fstream).split(), dtype=float) x_axis = np.array(next(self.fstream).split(), dtype=float) param_u = np.array(next(self.fstream).split(), dtype=float) param_v = np.array(next(self.fstream).split(), dtype=float) swap = next(self.fstream).strip() != '0' result = SurfaceFactory.sphere(r=r, center=center, xaxis=x_axis, zaxis=z_axis).swap() if swap: result.swap() result.reparam(param_u, param_v) return result
def sphere(r=1, center=(0, 0, 0), type='radial'): """ Create a solid sphere :param float r: Radius :param array-like center: Local origin of the sphere :param string type: The type of parametrization ('radial' or 'square') :return: A solid ball :rtype: Volume """ if type == 'radial': shell = SurfaceFactory.sphere(r, center) midpoint = shell * 0 + center return edge_surfaces(shell, midpoint) elif type == 'square': # based on the work of James E.Cobb: "Tiling the Sphere with Rational Bezier Patches" # University of Utah, July 11, 1988. UUCS-88-009 b = BSplineBasis(order=5) sr2 = sqrt(2) sr3 = sqrt(3) sr6 = sqrt(6) cp = [ [-4 * (sr3 - 1), 4 * (1 - sr3), 4 * (1 - sr3), 4 * (3 - sr3)], # row 0 [-sr2, sr2 * (sr3 - 4), sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], [ 0, 4. / 3 * (1 - 2 * sr3), 4. / 3 * (1 - 2 * sr3), 4. / 3 * (5 - sr3) ], [sr2, sr2 * (sr3 - 4), sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], [4 * (sr3 - 1), 4 * (1 - sr3), 4 * (1 - sr3), 4 * (3 - sr3)], [-sr2 * (4 - sr3), -sr2, sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], # row 1 [ -(3 * sr3 - 2) / 2, (2 - 3 * sr3) / 2, -(sr3 + 6) / 2, (sr3 + 6) / 2 ], [0, sr2 * (2 * sr3 - 7) / 3, -5 * sr6 / 3, sr2 * (sr3 + 6) / 3], [(3 * sr3 - 2) / 2, (2 - 3 * sr3) / 2, -(sr3 + 6) / 2, (sr3 + 6) / 2], [sr2 * (4 - sr3), -sr2, sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], [ -4. / 3 * (2 * sr3 - 1), 0, 4. / 3 * (1 - 2 * sr3), 4 * (5 - sr3) / 3 ], # row 2 [-sr2 / 3 * (7 - 2 * sr3), 0, -5 * sr6 / 3, sr2 * (sr3 + 6) / 3], [0, 0, 4 * (sr3 - 5) / 3, 4 * (5 * sr3 - 1) / 9], [sr2 / 3 * (7 - 2 * sr3), 0, -5 * sr6 / 3, sr2 * (sr3 + 6) / 3], [ 4. / 3 * (2 * sr3 - 1), 0, 4. / 3 * (1 - 2 * sr3), 4 * (5 - sr3) / 3 ], [-sr2 * (4 - sr3), sr2, sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], # row 3 [ -(3 * sr3 - 2) / 2, -(2 - 3 * sr3) / 2, -(sr3 + 6) / 2, (sr3 + 6) / 2 ], [0, -sr2 * (2 * sr3 - 7) / 3, -5 * sr6 / 3, sr2 * (sr3 + 6) / 3], [(3 * sr3 - 2) / 2, -(2 - 3 * sr3) / 2, -(sr3 + 6) / 2, (sr3 + 6) / 2], [sr2 * (4 - sr3), sr2, sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], [-4 * (sr3 - 1), -4 * (1 - sr3), 4 * (1 - sr3), 4 * (3 - sr3)], # row 4 [-sr2, -sr2 * (sr3 - 4), sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], [ 0, -4. / 3 * (1 - 2 * sr3), 4. / 3 * (1 - 2 * sr3), 4. / 3 * (5 - sr3) ], [sr2, -sr2 * (sr3 - 4), sr2 * (sr3 - 4), sr2 * (3 * sr3 - 2)], [4 * (sr3 - 1), -4 * (1 - sr3), 4 * (1 - sr3), 4 * (3 - sr3)] ] wmin = Surface(b, b, cp, rational=True) wmax = wmin.clone().mirror([0, 0, 1]) vmax = wmin.clone().rotate(pi / 2, [1, 0, 0]) vmin = vmax.clone().mirror([0, 1, 0]) umax = vmin.clone().rotate(pi / 2, [0, 0, 1]) umin = umax.clone().mirror([1, 0, 0]) # ideally I would like to call edge_surfaces() now, but that function # does not work with rational surfaces, so we'll just manually try # and add some inner controlpoints cp = np.zeros((5, 5, 5, 4)) cp[:, :, 0, :] = wmin[:, :, :] cp[:, :, -1, :] = wmax[:, :, :] cp[:, 0, :, :] = vmin[:, :, :] cp[:, -1, :, :] = vmax[:, :, :] cp[0, :, :, :] = umin[:, :, :] cp[-1, :, :, :] = umax[:, :, :] inner = np.linspace(-.5, .5, 3) Y, X, Z = np.meshgrid(inner, inner, inner) cp[1:4, 1:4, 1:4, 0] = X cp[1:4, 1:4, 1:4, 1] = Y cp[1:4, 1:4, 1:4, 2] = Z cp[1:4, 1:4, 1:4, 3] = 1 ball = Volume(b, b, b, cp, rational=True, raw=True) return r * ball + center else: raise ValueError('invalid type argument')
def sphere(r=1, center=(0,0,0), type='radial'): """ Create a solid sphere :param float r: Radius :param array-like center: Local origin of the sphere :param string type: The type of parametrization ('radial' or 'square') :return: A solid ball :rtype: Volume """ if type == 'radial': shell = SurfaceFactory.sphere(r, center) midpoint = shell*0 + center return edge_surfaces(shell, midpoint) elif type == 'square': # based on the work of James E.Cobb: "Tiling the Sphere with Rational Bezier Patches" # University of Utah, July 11, 1988. UUCS-88-009 b = BSplineBasis(order=5) sr2 = sqrt(2) sr3 = sqrt(3) sr6 = sqrt(6) cp = [[ -4*(sr3-1), 4*(1-sr3), 4*(1-sr3), 4*(3-sr3) ], # row 0 [ -sr2 , sr2*(sr3-4), sr2*(sr3-4), sr2*(3*sr3-2)], [ 0 , 4./3*(1-2*sr3), 4./3*(1-2*sr3),4./3*(5-sr3) ], [ sr2 , sr2*(sr3-4), sr2*(sr3-4), sr2*(3*sr3-2)], [ 4*(sr3-1), 4*(1-sr3), 4*(1-sr3), 4*(3-sr3) ], [ -sr2*(4-sr3), -sr2, sr2*(sr3-4), sr2*(3*sr3-2)], # row 1 [ -(3*sr3-2)/2, (2-3*sr3)/2, -(sr3+6)/2, (sr3+6)/2], [ 0 , sr2*(2*sr3-7)/3, -5*sr6/3, sr2*(sr3+6)/3], [ (3*sr3-2)/2, (2-3*sr3)/2, -(sr3+6)/2, (sr3+6)/2], [ sr2*(4-sr3), -sr2, sr2*(sr3-4), sr2*(3*sr3-2)], [ -4./3*(2*sr3-1), 0, 4./3*(1-2*sr3), 4*(5-sr3)/3], # row 2 [-sr2/3*(7-2*sr3), 0, -5*sr6/3, sr2*(sr3+6)/3], [ 0 , 0, 4*(sr3-5)/3, 4*(5*sr3-1)/9], [ sr2/3*(7-2*sr3), 0, -5*sr6/3, sr2*(sr3+6)/3], [ 4./3*(2*sr3-1), 0, 4./3*(1-2*sr3), 4*(5-sr3)/3], [ -sr2*(4-sr3), sr2, sr2*(sr3-4), sr2*(3*sr3-2)], # row 3 [ -(3*sr3-2)/2, -(2-3*sr3)/2, -(sr3+6)/2, (sr3+6)/2], [ 0 ,-sr2*(2*sr3-7)/3, -5*sr6/3, sr2*(sr3+6)/3], [ (3*sr3-2)/2, -(2-3*sr3)/2, -(sr3+6)/2, (sr3+6)/2], [ sr2*(4-sr3), sr2, sr2*(sr3-4), sr2*(3*sr3-2)], [ -4*(sr3-1), -4*(1-sr3), 4*(1-sr3), 4*(3-sr3) ], # row 4 [ -sr2 , -sr2*(sr3-4), sr2*(sr3-4), sr2*(3*sr3-2)], [ 0 , -4./3*(1-2*sr3), 4./3*(1-2*sr3),4./3*(5-sr3) ], [ sr2 , -sr2*(sr3-4), sr2*(sr3-4), sr2*(3*sr3-2)], [ 4*(sr3-1), -4*(1-sr3), 4*(1-sr3), 4*(3-sr3) ]] wmin = Surface(b,b,cp, rational=True) wmax = wmin.clone().mirror([0,0,1]) vmax = wmin.clone().rotate(pi/2, [1,0,0]) vmin = vmax.clone().mirror([0,1,0]) umax = vmin.clone().rotate(pi/2, [0,0,1]) umin = umax.clone().mirror([1,0,0]) # ideally I would like to call edge_surfaces() now, but that function # does not work with rational surfaces, so we'll just manually try # and add some inner controlpoints cp = np.zeros((5,5,5,4)) cp[ :, :, 0,:] = wmin[:,:,:] cp[ :, :,-1,:] = wmax[:,:,:] cp[ :, 0, :,:] = vmin[:,:,:] cp[ :,-1, :,:] = vmax[:,:,:] cp[ 0, :, :,:] = umin[:,:,:] cp[-1, :, :,:] = umax[:,:,:] inner = np.linspace(-.5,.5, 3) Y, X, Z = np.meshgrid(inner,inner,inner) cp[1:4,1:4,1:4,0] = X cp[1:4,1:4,1:4,1] = Y cp[1:4,1:4,1:4,2] = Z cp[1:4,1:4,1:4,3] = 1 ball = Volume(b,b,b,cp,rational=True, raw=True) return r*ball + center else: raise ValueError('invalid type argument')