def test_edge_surfaces(self): # test 3D surface vs 2D rational surface # more or less random 3D surface with p=[2,2] and n=[3,4] controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 1], [1, 0, .5], [1, 1, 1], [2, 1, 1], [2, 2, .5], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]] basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis2 = BSplineBasis(3, [0, 0, 0, .64, 2, 2, 2]) top = Surface(basis1, basis2, controlpoints) # more or less random 2D rational surface with p=[1,2] and n=[3,4] controlpoints = [[0, 0, 1], [-1, 1, .96], [0, 2, 1], [1, -1, 1], [1, 0, .8], [1, 1, 1], [2, 1, .89], [2, 2, .9], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]] basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1]) bottom = Surface(basis1, basis2, controlpoints, True) vol = VolumeFactory.edge_surfaces(bottom, top) # set parametric domain to [0,1]^2 for easier comparison top.reparam() bottom.reparam() # verify on 7x7x2 evaluation grid for u in np.linspace(0, 1, 7): for v in np.linspace(0, 1, 7): for w in np.linspace(0, 1, 2): # rational basis, not linear in w-direction self.assertAlmostEqual( vol(u, v, w)[0], bottom(u, v)[0] * (1 - w) + top(u, v)[0] * w) # x-coordinate self.assertAlmostEqual( vol(u, v, w)[1], bottom(u, v)[1] * (1 - w) + top(u, v)[1] * w) # y-coordinate self.assertAlmostEqual( vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w) # z-coordinate # test 3D surface vs 2D surface controlpoints = [[0, 0], [-1, 1], [0, 2], [1, -1], [1, 0], [1, 1], [2, 1], [2, 2], [2, 3], [3, 0], [4, 1], [3, 2]] basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1]) bottom = Surface(basis1, basis2, controlpoints) # non-rational! vol = VolumeFactory.edge_surfaces(bottom, top) # also non-rational! # verify on 5x5x7 evaluation grid for u in np.linspace(0, 1, 5): for v in np.linspace(0, 1, 5): for w in np.linspace(0, 1, 7): # include inner evaluation points self.assertAlmostEqual( vol(u, v, w)[0], bottom(u, v)[0] * (1 - w) + top(u, v)[0] * w) # x-coordinate self.assertAlmostEqual( vol(u, v, w)[1], bottom(u, v)[1] * (1 - w) + top(u, v)[1] * w) # y-coordinate self.assertAlmostEqual( vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w) # z-coordinate
def test_edge_surfaces(self): # test 3D surface vs 2D rational surface # more or less random 3D surface with p=[2,2] and n=[3,4] controlpoints = [[0, 0, 1], [-1, 1, 1], [0, 2, 1], [1, -1, 1], [1, 0, .5], [1, 1, 1], [2, 1, 1], [2, 2, .5], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]] basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis2 = BSplineBasis(3, [0, 0, 0, .64, 2, 2, 2]) top = Surface(basis1, basis2, controlpoints) # more or less random 2D rational surface with p=[1,2] and n=[3,4] controlpoints = [[0, 0, 1], [-1, 1, .96], [0, 2, 1], [1, -1, 1], [1, 0, .8], [1, 1, 1], [2, 1, .89], [2, 2, .9], [2, 3, 1], [3, 0, 1], [4, 1, 1], [3, 2, 1]] basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1]) bottom = Surface(basis1, basis2, controlpoints, True) vol = vf.edge_surfaces(bottom, top) # set parametric domain to [0,1]^2 for easier comparison top.reparam() bottom.reparam() # verify on 7x7x2 evaluation grid for u in np.linspace(0, 1, 7): for v in np.linspace(0, 1, 7): for w in np.linspace(0, 1, 2): # rational basis, not linear in w-direction self.assertAlmostEqual( vol(u, v, w)[0], bottom(u, v)[0] * (1 - w) + top(u, v)[0] * w) # x-coordinate self.assertAlmostEqual( vol(u, v, w)[1], bottom(u, v)[1] * (1 - w) + top(u, v)[1] * w) # y-coordinate self.assertAlmostEqual( vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w) # z-coordinate # test 3D surface vs 2D surface controlpoints = [[0, 0], [-1, 1], [0, 2], [1, -1], [1, 0], [1, 1], [2, 1], [2, 2], [2, 3], [3, 0], [4, 1], [3, 2]] basis1 = BSplineBasis(3, [0, 0, 0, 1, 1, 1]) basis2 = BSplineBasis(2, [0, 0, .4, .44, 1, 1]) bottom = Surface(basis1, basis2, controlpoints) # non-rational! vol = vf.edge_surfaces(bottom, top) # also non-rational! # verify on 5x5x7 evaluation grid for u in np.linspace(0, 1, 5): for v in np.linspace(0, 1, 5): for w in np.linspace(0, 1, 7): # include inner evaluation points self.assertAlmostEqual( vol(u, v, w)[0], bottom(u, v)[0] * (1 - w) + top(u, v)[0] * w) # x-coordinate self.assertAlmostEqual( vol(u, v, w)[1], bottom(u, v)[1] * (1 - w) + top(u, v)[1] * w) # y-coordinate self.assertAlmostEqual( vol(u, v, w)[2], 0 * (1 - w) + top(u, v)[2] * w) # z-coordinate
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_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_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 texture(self, p, ngeom, ntexture, method='full', irange=[None,None], jrange=[None,None]): # Set the dimensions of geometry and texture map # ngeom = np.floor(self.n / (p-1)) # ntexture = np.floor(self.n * n) # ngeom = ngeom.astype(np.int32) # ntexture = ntexture.astype(np.int32) ngeom = ensure_listlike(ngeom, 3) ntexture = ensure_listlike(ntexture, 3) p = ensure_listlike(p, 3) # Create the geometry ngx, ngy, ngz = ngeom b1 = BSplineBasis(p[0], [0]*(p[0]-1) + [i/ngx for i in range(ngx+1)] + [1]*(p[0]-1)) b2 = BSplineBasis(p[1], [0]*(p[1]-1) + [i/ngy for i in range(ngy+1)] + [1]*(p[1]-1)) b3 = BSplineBasis(p[2], [0]*(p[2]-1) + [i/ngz for i in range(ngz+1)] + [1]*(p[2]-1)) l2_fit = surface_factory.least_square_fit vol = self.get_c0_mesh() i = slice(irange[0], irange[1], None) j = slice(jrange[0], jrange[1], None) # special case number of evaluation points for full domain if irange[1] == None: irange[1] = vol.shape[0] if jrange[1] == None: jrange[1] = vol.shape[1] if irange[0] == None: irange[0] = 0 if jrange[0] == None: jrange[0] = 0 nu = np.diff(irange) nv = np.diff(jrange) nw = vol.shape[2] u = np.linspace(0, 1, nu) v = np.linspace(0, 1, nv) w = np.linspace(0, 1, nw) crvs = [] crvs.append(curve_factory.polygon(vol[i ,jrange[0] , 0,:].squeeze())) crvs.append(curve_factory.polygon(vol[i ,jrange[0] ,-1,:].squeeze())) crvs.append(curve_factory.polygon(vol[i ,jrange[1]-1, 0,:].squeeze())) crvs.append(curve_factory.polygon(vol[i ,jrange[1]-1,-1,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[0] ,j , 0,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[0] ,j ,-1,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[1]-1,j , 0,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[1]-1,j ,-1,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[0] ,jrange[0] , :,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[0] ,jrange[1]-1, :,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[1]-1,jrange[0] , :,:].squeeze())) crvs.append(curve_factory.polygon(vol[irange[1]-1,jrange[1]-1, :,:].squeeze())) # with G2('curves.g2') as myfile: # myfile.write(crvs) # print('Written curve.g2') if method == 'full': bottom = l2_fit(vol[i, j, 0,:].squeeze(), [b1, b2], [u, v]) top = l2_fit(vol[i, j, -1,:].squeeze(), [b1, b2], [u, v]) left = l2_fit(vol[irange[0] ,j, :,:].squeeze(), [b2, b3], [v, w]) right = l2_fit(vol[irange[1]-1,j, :,:].squeeze(), [b2, b3], [v, w]) front = l2_fit(vol[i, jrange[0], :,:].squeeze(), [b1, b3], [u, w]) back = l2_fit(vol[i, jrange[1]-1,:,:].squeeze(), [b1, b3], [u, w]) volume = volume_factory.edge_surfaces([left, right, front, back, bottom, top]) elif method == 'z': bottom = l2_fit(vol[i,j, 0,:].squeeze(), [b1, b2], [u, v]) top = l2_fit(vol[i,j,-1,:].squeeze(), [b1, b2], [u, v]) volume = volume_factory.edge_surfaces([bottom, top]) volume.set_order(*p) volume.refine(ngz - 1, direction='w') volume.reverse(direction=2) # Point-to-cell mapping # TODO: Optimize more eps = 1e-2 u = [np.linspace(eps, 1-eps, n) for n in ntexture] points = volume(*u).reshape(-1, 3) cellids = np.zeros(points.shape[:-1], dtype=int) cell = None nx, ny, nz = self.n for ptid, point in enumerate(tqdm(points, desc='Inverse mapping')): i, j, k = cell = self.raw.cell_at(point) # , guess=cell) cellid = i*ny*nz + j*nz + k cellids[ptid] = cellid cellids = cellids.reshape(tuple(ntexture)) all_textures = {} for name in self.attribute: data = self.attribute[name][cellids] # TODO: This flattens the image if it happens to be 3D (or higher...) # do we need a way to communicate the structure back to the caller? # data = data.reshape(-1, data.shape[-1]) # TODO: This normalizes the image, # but we need a way to communicate the ranges back to the caller # a, b = min(data.flat), max(data.flat) # data = ((data - a) / (b - a) * 255).astype(np.uint8) all_textures[name] = data all_textures['cellids'] = cellids return volume, all_textures