We’ve been working with Distance Grids which calculate how far a point is away from the closest surface point. They return a gradient that can be used in different calculations. A common use case is turning that gradient into some geometry. Let’s say you have a 3D model and you want to add some surface detail to it. You could calculate all the voxels within say 2mm of the surface. If you turn this into geometry then you can Intersect that with some volumetric function to create an interesting surface. We’ve created a new class called DistanceGridExtractor for that purpose. It will create a smooth grid that for the inside and outside distances you specify.
Below is a surface created by taking a torus as the main object. I calculated all voxels outside the torus for 2mm. I then turned that into geometry and intersected it with a SchwarzPrimitive volume. It’s cut in half to show the inside.
public void testTorusBumpy(){ int max_attribute = 127; int nx = 400; double sphereRadius = 16.0 * MM; AttributeGrid grid = makeTorus(nx, sphereRadius, 2 * MM, voxelSize, max_attribute, surfaceThickness); double[] bounds = new double[6]; grid.getGridBounds(bounds); double maxInDistance = 0*MM; double maxOutDistance = 2.1*MM + voxelSize; DistanceTransformExact dt_exact = new DistanceTransformExact(max_attribute, maxInDistance, maxOutDistance); AttributeGrid dg_exact = dt_exact.execute(grid); DensityGridExtractor dge = new DensityGridExtractor(0, maxOutDistance - voxelSize, dg_exact,maxInDistance,maxOutDistance, max_attribute); AttributeGrid supersurface = (AttributeGrid) grid.createEmpty(grid.getWidth(), grid.getHeight(), grid.getDepth(), grid.getSliceHeight(), grid.getVoxelSize()); supersurface.setGridBounds(bounds); supersurface = dge.execute(supersurface); AttributeGrid dest = (AttributeGrid) grid.createEmpty(grid.getWidth(), grid.getHeight(), grid.getDepth(), grid.getSliceHeight(), grid.getVoxelSize()); dest.setGridBounds(bounds); GridMaker gm = new GridMaker(); gm.setMaxAttributeValue(max_attribute); DataSourceGrid dsg1 = new DataSourceGrid(grid,max_attribute); DataSourceGrid dsg2 = new DataSourceGrid(supersurface, max_attribute); DataSource schwarz = new VolumePatterns.SchwarzPrimitive(2*MM,0.5*MM); Intersection pattern = new Intersection(dsg2, schwarz); Union result = new Union(); result.add(pattern); Subtraction subtract = new Subtraction(result, new Plane(new Vector3d(0,1,0), new Vector3d(0,0,0))); gm.setSource(subtract); gm.makeGrid(dest); try { writeGrid(dest, "bumpy_torus.stl", max_attribute); } catch(IOException ioe) { ioe.printStackTrace(); } }