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')