Package toxi.volume

Source Code of toxi.volume.ArrayIsoSurface

/*
*   __               .__       .__  ._____.          
* _/  |_  _______  __|__| ____ |  | |__\_ |__   ______
* \   __\/  _ \  \/  /  |/ ___\|  | |  || __ \ /  ___/
*  |  | (  <_> >    <|  \  \___|  |_|  || \_\ \\___ \
*  |__|  \____/__/\_ \__|\___  >____/__||___  /____  >
*                   \/       \/             \/     \/
*
* 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 java.util.logging.Logger;

import toxi.geom.Vec3D;
import toxi.geom.mesh.Mesh3D;
import toxi.geom.mesh.TriangleMesh;

/**
* IsoSurface class based on C version by Paul Bourke and Lingo version by
* myself.
*/
public class ArrayIsoSurface implements IsoSurface {

    protected static final Logger logger = Logger
            .getLogger(ArrayIsoSurface.class.getName());

    protected Vec3D cellSize;
    protected Vec3D centreOffset;
    protected VolumetricSpace volume;

    public float isoValue;

    protected int resX, resY, resZ;
    protected int resX1, resY1, resZ1;

    protected int sliceRes;
    protected int nextXY;

    protected Vec3D[] edgeVertices;

    public ArrayIsoSurface(VolumetricSpace volume) {
        this.volume = volume;
        cellSize = new Vec3D(volume.scale.x / volume.resX1, volume.scale.y
                / volume.resY1, volume.scale.z / volume.resZ1);

        resX = volume.resX;
        resY = volume.resY;
        resZ = volume.resZ;
        resX1 = volume.resX1;
        resY1 = volume.resY1;
        resZ1 = volume.resZ1;

        sliceRes = volume.sliceRes;
        nextXY = resX + sliceRes;

        centreOffset = volume.halfScale.getInverted();

        edgeVertices = new Vec3D[3 * volume.numCells];
    }

    /**
     * Computes the surface mesh for the given volumetric data and iso value.
     */
    public Mesh3D computeSurfaceMesh(Mesh3D mesh, final float iso) {
        if (mesh == null) {
            mesh = new TriangleMesh("isosurface-" + iso);
        } else {
            mesh.clear();
        }
        isoValue = iso;
        float offsetZ = centreOffset.z;
        for (int z = 0; z < resZ1; z++) {
            int sliceOffset = sliceRes * z;
            float offsetY = centreOffset.y;
            for (int y = 0; y < resY1; y++) {
                float offsetX = centreOffset.x;
                int offset = resX * y + sliceOffset;
                for (int x = 0; x < resX1; x++) {
                    final int cellIndex = getCellIndex(x, y, z);
                    if (cellIndex > 0 && cellIndex < 255) {
                        final int edgeFlags = MarchingCubesIndex.edgesToCompute[cellIndex];
                        if (edgeFlags > 0 && edgeFlags < 255) {
                            int edgeOffsetIndex = offset * 3;
                            float offsetData = volume.getVoxelAt(offset);
                            float isoDiff = isoValue - offsetData;
                            if ((edgeFlags & 1) > 0) {
                                if (edgeVertices[edgeOffsetIndex] == null) {
                                    float t = isoDiff
                                            / (volume.getVoxelAt(offset + 1) - offsetData);
                                    edgeVertices[edgeOffsetIndex] = new Vec3D(
                                            offsetX + t * cellSize.x, y
                                                    * cellSize.y
                                                    + centreOffset.y, z
                                                    * cellSize.z
                                                    + centreOffset.z);
                                }
                            }
                            if ((edgeFlags & 2) > 0) {
                                if (edgeVertices[edgeOffsetIndex + 1] == null) {
                                    float t = isoDiff
                                            / (volume.getVoxelAt(offset + resX) - offsetData);
                                    edgeVertices[edgeOffsetIndex + 1] = new Vec3D(
                                            x * cellSize.x + centreOffset.x,
                                            offsetY + t * cellSize.y, z
                                                    * cellSize.z
                                                    + centreOffset.z);
                                }
                            }
                            if ((edgeFlags & 4) > 0) {
                                if (edgeVertices[edgeOffsetIndex + 2] == null) {
                                    float t = isoDiff
                                            / (volume.getVoxelAt(offset
                                                    + sliceRes) - offsetData);
                                    edgeVertices[edgeOffsetIndex + 2] = new Vec3D(
                                            x * cellSize.x + centreOffset.x, y
                                                    * cellSize.y
                                                    + centreOffset.y, offsetZ
                                                    + t * cellSize.z);
                                }
                            }
                        }
                    }
                    offsetX += cellSize.x;
                    offset++;
                }
                offsetY += cellSize.y;
            }
            offsetZ += cellSize.z;
        }

        final int[] face = new int[16];
        for (int z = 0; z < resZ1; z++) {
            int sliceOffset = sliceRes * z;
            for (int y = 0; y < resY1; y++) {
                int offset = resX * y + sliceOffset;
                for (int x = 0; x < resX1; x++) {
                    final int cellIndex = getCellIndex(x, y, z);
                    if (cellIndex > 0 && cellIndex < 255) {
                        int n = 0;
                        int edgeIndex;
                        final int[] cellTriangles = MarchingCubesIndex.cellTriangles[cellIndex];
                        while ((edgeIndex = cellTriangles[n]) != -1) {
                            int[] edgeOffsetInfo = MarchingCubesIndex.edgeOffsets[edgeIndex];
                            face[n] = ((x + edgeOffsetInfo[0]) + resX
                                    * (y + edgeOffsetInfo[1]) + sliceRes
                                    * (z + edgeOffsetInfo[2]))
                                    * 3 + edgeOffsetInfo[3];
                            n++;
                        }
                        for (int i = 0; i < n; i += 3) {
                            final Vec3D va = edgeVertices[face[i + 1]];
                            final Vec3D vb = edgeVertices[face[i + 2]];
                            final Vec3D vc = edgeVertices[face[i]];
                            if (va != null && vb != null && vc != null) {
                                mesh.addFace(va, vb, vc);
                            }
                        }
                    }
                    offset++;
                }
            }
        }
        return mesh;
    }

    protected final int getCellIndex(int x, int y, int z) {
        int cellIndex = 0;
        int idx = x + y * resX + z * sliceRes;
        if (volume.getVoxelAt(idx) < isoValue) {
            cellIndex |= 0x01;
        }
        if (volume.getVoxelAt(idx + sliceRes) < isoValue) {
            cellIndex |= 0x08;
        }
        if (volume.getVoxelAt(idx + resX) < isoValue) {
            cellIndex |= 0x10;
        }
        if (volume.getVoxelAt(idx + resX + sliceRes) < isoValue) {
            cellIndex |= 0x80;
        }
        idx++;
        if (volume.getVoxelAt(idx) < isoValue) {
            cellIndex |= 0x02;
        }
        if (volume.getVoxelAt(idx + sliceRes) < isoValue) {
            cellIndex |= 0x04;
        }
        if (volume.getVoxelAt(idx + resX) < isoValue) {
            cellIndex |= 0x20;
        }
        if (volume.getVoxelAt(idx + resX + sliceRes) < isoValue) {
            cellIndex |= 0x40;
        }
        return cellIndex;
    }

    /**
     * Resets mesh vertices to default positions and clears face index. Needs to
     * be called inbetween successive calls to
     * {@link #computeSurfaceMesh(Mesh3D, float)}
     */
    public void reset() {
        for (int i = 0; i < edgeVertices.length; i++) {
            edgeVertices[i] = null;
        }
    }
}
TOP

Related Classes of toxi.volume.ArrayIsoSurface

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.