/* * __ .__ .__ ._____. * _/ |_ _______ __|__| ____ | | |__\_ |__ ______ * \ __\/ _ \ \/ / |/ ___\| | | || __ \ / ___/ * | | ( <_> > <| \ \___| |_| || \_\ \\___ \ * |__| \____/__/\_ \__|\___ >____/__||___ /____ > * \/ \/ \/ \/ * * Copyright (c) 2006-2011 Karsten Schmidt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * http://creativecommons.org/licenses/LGPL/2.1/ * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ package toxi.volume; import toxi.geom.AABB; import toxi.geom.Triangle3D; import toxi.geom.Vec3D; import toxi.geom.mesh.Mesh3D; import toxi.math.MathUtils; import toxi.math.ScaleMap; /** * * @author tux */ public class MeshVoxelizer { /** * */ protected VolumetricSpace volume; /** * */ protected int wallThickness = 0; /** * * @param res */ public MeshVoxelizer(int res) { this(res, res, res); } /** * * @param resX * @param resY * @param resZ */ public MeshVoxelizer(int resX, int resY, int resZ) { volume = new VolumetricHashMap(new Vec3D(1, 1, 1), resX, resY, resZ, 0.1f); } /** * * @return */ public MeshVoxelizer clear() { volume.clear(); return this; } /** * @return the volume */ public VolumetricSpace getVolume() { return volume; } /** * @return the wallThickness */ public int getWallThickness() { return wallThickness; } /** * * @param x * @param y * @param z * @param iso */ protected void setVoxelAt(int x, int y, int z, float iso) { int mix = MathUtils.max(x - wallThickness, 0); int miy = MathUtils.max(y - wallThickness, 0); int miz = MathUtils.max(z - wallThickness, 0); int max = MathUtils.min(x + wallThickness, volume.resX1); int may = MathUtils.min(y + wallThickness, volume.resY1); int maz = MathUtils.min(z + wallThickness, volume.resZ1); for (z = miz; z <= maz; z++) { for (y = miy; y <= may; y++) { for (x = mix; x <= max; x++) { volume.setVoxelAt(x, y, z, iso); } } } } /** * @param wallThickness * the wallThickness to set * @return */ public MeshVoxelizer setWallThickness(int wallThickness) { this.wallThickness = wallThickness; return this; } private VolumetricSpace solidifyVolume(VolumetricSpaceArray volume) { for (int z = 0; z < volume.resZ; z++) { for (int y = 0; y < volume.resY; y++) { boolean isFilled = false; int startX = 0; for (int x = 0; x < volume.resX; x++) { float val = volume.getVoxelAt(x, y, z); if (val > 0) { if (!isFilled) { startX = x; isFilled = true; } else { for (int i = startX; i <= x; i++) { volume.setVoxelAt(i, y, z, 1); } isFilled = false; } } } } } return volume; } /** * * @param mesh * @return */ public VolumetricSpace voxelizeMesh(Mesh3D mesh) { return voxelizeMesh(mesh, 1f); } /** * * @param mesh * @param iso * @return */ public VolumetricSpace voxelizeMesh(Mesh3D mesh, float iso) { AABB box = mesh.getBoundingBox(); Vec3D bmin = box.getMin(); Vec3D bmax = box.getMax(); ScaleMap wx = new ScaleMap(bmin.x, bmax.x, 1, volume.resX - 2); ScaleMap wy = new ScaleMap(bmin.y, bmax.y, 1, volume.resY - 2); ScaleMap wz = new ScaleMap(bmin.z, bmax.z, 1, volume.resZ - 2); ScaleMap gx = new ScaleMap(1, volume.resX - 2, bmin.x, bmax.x); ScaleMap gy = new ScaleMap(1, volume.resY - 2, bmin.y, bmax.y); ScaleMap gz = new ScaleMap(1, volume.resZ - 2, bmin.z, bmax.z); volume.setScale(box.getExtent().scale(2f)); Triangle3D tri = new Triangle3D(); AABB voxel = new AABB(new Vec3D(), volume.voxelSize.scale(0.5f)); mesh.getFaces().stream().map((f) -> { tri.a = f.a; return f; }).map((f) -> { tri.b = f.b; return f; }).map((f) -> { tri.c = f.c; return f; }).map((_item) -> tri.getBoundingBox()).forEach((bounds) -> { Vec3D min = bounds.getMin(); Vec3D max = bounds.getMax(); min = new Vec3D((int) wx.getClippedValueFor(min.x), (int) wy.getClippedValueFor(min.y), (int) wz.getClippedValueFor(min.z)); max = new Vec3D((int) wx.getClippedValueFor(max.x), (int) wy.getClippedValueFor(max.y), (int) wz.getClippedValueFor(max.z)); for (int z = (int) min.z; z <= max.z; z++) { for (int y = (int) min.y; y <= max.y; y++) { for (int x = (int) min.x; x <= max.x; x++) { if (x < volume.resX1 && y < volume.resY1 && z < volume.resZ1) { voxel.set((float) gx.getClippedValueFor(x), (float) gy.getClippedValueFor(y), (float) gz.getClippedValueFor(z)); if (voxel.intersectsTriangle(tri)) { setVoxelAt(x, y, z, iso); } } } } } }); return volume; } }