Search in sources :

Example 6 with TriangularFacet

use of net.imagej.ops.geom.geom3d.mesh.TriangularFacet in project imagej-ops by imagej.

the class DefaultVoxelization3D method calculate.

@Override
public RandomAccessibleInterval<BitType> calculate(Mesh input) {
    Img<BitType> outImg = ops.create().img(new FinalInterval(width, height, depth), new BitType());
    DefaultMesh dMesh = (DefaultMesh) input;
    Set<RealLocalizable> verts = dMesh.getVertices();
    RealPoint minPoint = new RealPoint(verts.iterator().next());
    RealPoint maxPoint = new RealPoint(verts.iterator().next());
    for (RealLocalizable v : verts) {
        if (v.getDoublePosition(0) < minPoint.getDoublePosition(0))
            minPoint.setPosition(v.getDoublePosition(0), 0);
        if (v.getDoublePosition(1) < minPoint.getDoublePosition(1))
            minPoint.setPosition(v.getDoublePosition(1), 1);
        if (v.getDoublePosition(2) < minPoint.getDoublePosition(2))
            minPoint.setPosition(v.getDoublePosition(2), 2);
        if (v.getDoublePosition(0) > maxPoint.getDoublePosition(0))
            maxPoint.setPosition(v.getDoublePosition(0), 0);
        if (v.getDoublePosition(1) > maxPoint.getDoublePosition(1))
            maxPoint.setPosition(v.getDoublePosition(1), 1);
        if (v.getDoublePosition(2) > maxPoint.getDoublePosition(2))
            maxPoint.setPosition(v.getDoublePosition(2), 2);
    }
    RealPoint dimPoint = new RealPoint((maxPoint.getDoublePosition(0) - minPoint.getDoublePosition(0)), (maxPoint.getDoublePosition(1) - minPoint.getDoublePosition(1)), (maxPoint.getDoublePosition(2) - minPoint.getDoublePosition(2)));
    double[] stepSizes = new double[3];
    stepSizes[0] = dimPoint.getDoublePosition(0) / width;
    stepSizes[1] = dimPoint.getDoublePosition(1) / height;
    stepSizes[2] = dimPoint.getDoublePosition(2) / depth;
    double[] voxelHalfsize = new double[3];
    for (int k = 0; k < stepSizes.length; k++) voxelHalfsize[k] = stepSizes[k] / 2.0;
    for (Facet f : dMesh.getFacets()) {
        TriangularFacet tri = (TriangularFacet) f;
        Vector3D v1 = tri.getP0();
        Vector3D v2 = tri.getP1();
        Vector3D v3 = tri.getP2();
        double[] minSubBoundary = new double[] { Math.min(Math.min(v1.getX(), v2.getX()), v3.getX()) - minPoint.getDoublePosition(0), Math.min(Math.min(v1.getY(), v2.getY()), v3.getY()) - minPoint.getDoublePosition(1), Math.min(Math.min(v1.getZ(), v2.getZ()), v3.getZ()) - minPoint.getDoublePosition(2) };
        double[] maxSubBoundary = new double[] { Math.max(Math.max(v1.getX(), v2.getX()), v3.getX()) - minPoint.getDoublePosition(0), Math.max(Math.max(v1.getY(), v2.getY()), v3.getY()) - minPoint.getDoublePosition(1), Math.max(Math.max(v1.getZ(), v2.getZ()), v3.getZ()) - minPoint.getDoublePosition(2) };
        // Should use the
        RandomAccess<BitType> ra = outImg.randomAccess();
        // interval
        // implementation
        // for speed
        long[] indices = new long[3];
        for (indices[0] = (long) Math.floor(minSubBoundary[0] / stepSizes[0]); indices[0] < Math.floor(maxSubBoundary[0] / stepSizes[0]); indices[0]++) {
            for (indices[1] = (long) Math.floor(minSubBoundary[1] / stepSizes[1]); indices[1] < Math.floor(maxSubBoundary[1] / stepSizes[1]); indices[1]++) {
                for (indices[2] = (long) Math.floor(minSubBoundary[2] / stepSizes[2]); indices[2] < Math.floor(maxSubBoundary[2] / stepSizes[2]); indices[2]++) {
                    ra.setPosition(indices);
                    if (// Don't check if voxel is already
                    !ra.get().get()) // filled
                    {
                        double[] voxelCenter = new double[3];
                        for (int k = 0; k < 3; k++) voxelCenter[k] = indices[k] * stepSizes[k] + voxelHalfsize[k];
                        if (triBoxOverlap(voxelCenter, voxelHalfsize, v1, v2, v3) == 1) {
                            ra.get().set(true);
                        }
                    }
                }
            }
        }
    }
    return outImg;
}
Also used : RealLocalizable(net.imglib2.RealLocalizable) RealPoint(net.imglib2.RealPoint) TriangularFacet(net.imagej.ops.geom.geom3d.mesh.TriangularFacet) DefaultMesh(net.imagej.ops.geom.geom3d.mesh.DefaultMesh) BitType(net.imglib2.type.logic.BitType) Vector3D(org.apache.commons.math3.geometry.euclidean.threed.Vector3D) RealPoint(net.imglib2.RealPoint) FinalInterval(net.imglib2.FinalInterval) Facet(net.imagej.ops.geom.geom3d.mesh.Facet) TriangularFacet(net.imagej.ops.geom.geom3d.mesh.TriangularFacet)

Example 7 with TriangularFacet

use of net.imagej.ops.geom.geom3d.mesh.TriangularFacet in project imagej-ops by imagej.

the class DefaultConvexHull3D method assignPointsToFacets.

/**
 * Assigns all points which are not part of the convex hull to a facet. A
 * point is assigned to a facet if the point is in front of this facet. Every
 * point is assigned to only one facet. If a facet has a point in front the
 * facet is added to {@link DefaultConvexHull3D#facetsWithPointInFront}. After
 * this call {@link DefaultConvexHull3D#vertices} is empty. Points which are
 * behind all facets are removed because they are on the inside of the convex
 * hull.
 *
 * @param newFacets which could have a point in front
 * @param facetsWithPointInFront
 */
private void assignPointsToFacets(final double epsilon, final Set<Vertex> vertices, final List<TriangularFacet> newFacets, final List<TriangularFacet> facets, final List<TriangularFacet> facetsWithPointInFront) {
    Iterator<Vertex> vertexIt = vertices.iterator();
    while (vertexIt.hasNext()) {
        Vertex v = vertexIt.next();
        Iterator<TriangularFacet> facetIt = newFacets.iterator();
        TriangularFacet maxFacet = null;
        double maxdis = epsilon;
        while (facetIt.hasNext()) {
            TriangularFacet f = facetIt.next();
            double distanceToPlane = f.distanceToPlane(v);
            // point is assigned to the facet with maximum distance
            if (distanceToPlane > maxdis) {
                maxdis = distanceToPlane;
                maxFacet = f;
            }
        }
        // therefore on the inside of the convex hull.
        if (maxFacet != null) {
            maxFacet.setVertexInFront(v, maxdis);
            if (!facetsWithPointInFront.contains(maxFacet)) {
                facetsWithPointInFront.add(maxFacet);
            }
        }
    }
    facets.addAll(newFacets);
    // All vertices are reassigned or are inside of the convex hull.
    vertices.clear();
}
Also used : Vertex(net.imagej.ops.geom.geom3d.mesh.Vertex) TriangularFacet(net.imagej.ops.geom.geom3d.mesh.TriangularFacet)

Example 8 with TriangularFacet

use of net.imagej.ops.geom.geom3d.mesh.TriangularFacet in project imagej-ops by imagej.

the class DefaultConvexHull3D method createSimplex.

/**
 * Computes an initial simplex of four facets. The simplex consists of the
 * four points v0-v3. v0 and v1 have the largest possible distance in one
 * dimension. v2 is the point with the largest distance to v0----v1. v3 is the
 * point with the largest distance to the plane described by v0, v1, v2.
 */
private double createSimplex(final Set<Vertex> vertices, final List<TriangularFacet> facets, final List<TriangularFacet> facetsWithPointInFront) {
    final Pair<Double, Vertex[]> minMax = computeMinMax(vertices);
    final double epsilon = minMax.getA();
    int i = getMaxDistPointIndex(minMax.getB());
    Vertex v0 = minMax.getB()[i];
    Vertex v1 = minMax.getB()[i + 3];
    vertices.remove(v0);
    vertices.remove(v1);
    Vertex v2 = getV2(epsilon, vertices, v0, v1);
    vertices.remove(v2);
    Vertex v3 = getV3(epsilon, vertices, v0, v1, v2);
    vertices.remove(v3);
    TriangularFacet f0 = new TriangularFacet(v0, v1, v2);
    if (f0.distanceToPlane(v3) > epsilon) {
        // change triangle orientation to counter clockwise
        Vertex tmp = v1;
        v1 = v2;
        v2 = tmp;
        f0 = new TriangularFacet(v0, v1, v2);
    }
    // v3 is behind f0
    assert f0.distanceToPlane(v3) < epsilon;
    TriangularFacet f1 = new TriangularFacet(v1, v0, v3);
    TriangularFacet f2 = new TriangularFacet(v2, v1, v3);
    TriangularFacet f3 = new TriangularFacet(v0, v2, v3);
    f0.setNeighbor(0, f3);
    f0.setNeighbor(1, f1);
    f0.setNeighbor(2, f2);
    f1.setNeighbor(0, f2);
    f1.setNeighbor(1, f0);
    f1.setNeighbor(2, f3);
    f2.setNeighbor(0, f3);
    f2.setNeighbor(1, f0);
    f2.setNeighbor(2, f1);
    f3.setNeighbor(0, f1);
    f3.setNeighbor(1, f0);
    f3.setNeighbor(2, f2);
    assert f0.distanceToPlane(v3) < epsilon;
    assert f1.distanceToPlane(v2) < epsilon;
    assert f2.distanceToPlane(v0) < epsilon;
    assert f3.distanceToPlane(v1) < epsilon;
    List<TriangularFacet> newFacets = new ArrayList<>();
    newFacets.add(f0);
    newFacets.add(f1);
    newFacets.add(f2);
    newFacets.add(f3);
    assignPointsToFacets(epsilon, vertices, newFacets, facets, facetsWithPointInFront);
    return epsilon;
}
Also used : Vertex(net.imagej.ops.geom.geom3d.mesh.Vertex) TriangularFacet(net.imagej.ops.geom.geom3d.mesh.TriangularFacet) ArrayList(java.util.ArrayList)

Example 9 with TriangularFacet

use of net.imagej.ops.geom.geom3d.mesh.TriangularFacet in project imagej-ops by imagej.

the class DefaultMarchingCubes method calculate.

@SuppressWarnings({ "unchecked" })
@Override
public DefaultMesh calculate(final RandomAccessibleInterval<T> input) {
    DefaultMesh output = new DefaultMesh();
    ExtendedRandomAccessibleInterval<T, RandomAccessibleInterval<T>> extended = Views.extendValue(input, (T) new BoolType(false));
    Cursor<T> c = Views.interval(extended, new FinalInterval(new long[] { input.min(0) - 1, input.min(1) - 1, input.min(2) - 1 }, new long[] { input.max(0) + 1, input.max(1) + 1, input.max(2) + 1 })).localizingCursor();
    while (c.hasNext()) {
        c.next();
        int cursorX = c.getIntPosition(0);
        int cursorY = c.getIntPosition(1);
        int cursorZ = c.getIntPosition(2);
        Cursor<T> cu = getCube(extended, cursorX, cursorY, cursorZ);
        int i = 0;
        double[] vertex_values = new double[8];
        while (cu.hasNext()) {
            vertex_values[i++] = (cu.next().get()) ? 1 : 0;
        }
        // 6------7
        // /| /|
        // 2-----3 |
        // | 4---|-5
        // |/ |/
        // 0-----1
        vertex_values = mapFlatIterableToLookUpCube(vertex_values);
        // 4------5
        // /| /|
        // 7-----6 |
        // | 0---|-1
        // |/ |/
        // 3-----2
        int cubeindex = getCubeIndex(vertex_values);
        if (EDGE_TABLE[cubeindex] != 0) {
            int[] p0 = new int[] { 0 + cursorX, 0 + cursorY, 1 + cursorZ };
            int[] p1 = new int[] { 1 + cursorX, 0 + cursorY, 1 + cursorZ };
            int[] p2 = new int[] { 1 + cursorX, 0 + cursorY, 0 + cursorZ };
            int[] p3 = new int[] { 0 + cursorX, 0 + cursorY, 0 + cursorZ };
            int[] p4 = new int[] { 0 + cursorX, 1 + cursorY, 1 + cursorZ };
            int[] p5 = new int[] { 1 + cursorX, 1 + cursorY, 1 + cursorZ };
            int[] p6 = new int[] { 1 + cursorX, 1 + cursorY, 0 + cursorZ };
            int[] p7 = new int[] { 0 + cursorX, 1 + cursorY, 0 + cursorZ };
            double[][] vertlist = new double[12][];
            /* Find the vertices where the surface intersects the cube */
            if (0 != (EDGE_TABLE[cubeindex] & 1)) {
                vertlist[0] = interpolatePoint(p0, p1, vertex_values[0], vertex_values[1]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 2)) {
                vertlist[1] = interpolatePoint(p1, p2, vertex_values[1], vertex_values[2]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 4)) {
                vertlist[2] = interpolatePoint(p2, p3, vertex_values[2], vertex_values[3]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 8)) {
                vertlist[3] = interpolatePoint(p3, p0, vertex_values[3], vertex_values[0]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 16)) {
                vertlist[4] = interpolatePoint(p4, p5, vertex_values[4], vertex_values[5]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 32)) {
                vertlist[5] = interpolatePoint(p5, p6, vertex_values[5], vertex_values[6]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 64)) {
                vertlist[6] = interpolatePoint(p6, p7, vertex_values[6], vertex_values[7]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 128)) {
                vertlist[7] = interpolatePoint(p7, p4, vertex_values[7], vertex_values[4]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 256)) {
                vertlist[8] = interpolatePoint(p0, p4, vertex_values[0], vertex_values[4]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 512)) {
                vertlist[9] = interpolatePoint(p1, p5, vertex_values[1], vertex_values[5]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 1024)) {
                vertlist[10] = interpolatePoint(p2, p6, vertex_values[2], vertex_values[6]);
            }
            if (0 != (EDGE_TABLE[cubeindex] & 2048)) {
                vertlist[11] = interpolatePoint(p3, p7, vertex_values[3], vertex_values[7]);
            }
            /* Create the triangle */
            for (i = 0; TRIANGLE_TABLE[cubeindex][i] != -1; i += 3) {
                TriangularFacet face = new TriangularFacet(new Vertex(vertlist[TRIANGLE_TABLE[cubeindex][i + 2]][0], vertlist[TRIANGLE_TABLE[cubeindex][i + 2]][1], vertlist[TRIANGLE_TABLE[cubeindex][i + 2]][2]), new Vertex(vertlist[TRIANGLE_TABLE[cubeindex][i + 1]][0], vertlist[TRIANGLE_TABLE[cubeindex][i + 1]][1], vertlist[TRIANGLE_TABLE[cubeindex][i + 1]][2]), new Vertex(vertlist[TRIANGLE_TABLE[cubeindex][i]][0], vertlist[TRIANGLE_TABLE[cubeindex][i]][1], vertlist[TRIANGLE_TABLE[cubeindex][i]][2]));
                face.getArea();
                output.addFace(face);
            }
        }
    }
    return output;
}
Also used : BoolType(net.imglib2.type.logic.BoolType) Vertex(net.imagej.ops.geom.geom3d.mesh.Vertex) TriangularFacet(net.imagej.ops.geom.geom3d.mesh.TriangularFacet) DefaultMesh(net.imagej.ops.geom.geom3d.mesh.DefaultMesh) RandomAccessibleInterval(net.imglib2.RandomAccessibleInterval) ExtendedRandomAccessibleInterval(net.imglib2.view.ExtendedRandomAccessibleInterval) FinalInterval(net.imglib2.FinalInterval)

Example 10 with TriangularFacet

use of net.imagej.ops.geom.geom3d.mesh.TriangularFacet in project imagej-ops by imagej.

the class DefaultVolumeMesh method calculate.

@Override
public DoubleType calculate(final Mesh input) {
    double volume = 0;
    for (Facet f : input.getFacets()) {
        TriangularFacet tf = (TriangularFacet) f;
        volume += signedVolumeOfTriangle(tf.getP0(), tf.getP1(), tf.getP2());
    }
    return new DoubleType(Math.abs(volume));
}
Also used : TriangularFacet(net.imagej.ops.geom.geom3d.mesh.TriangularFacet) DoubleType(net.imglib2.type.numeric.real.DoubleType) Facet(net.imagej.ops.geom.geom3d.mesh.Facet) TriangularFacet(net.imagej.ops.geom.geom3d.mesh.TriangularFacet)

Aggregations

TriangularFacet (net.imagej.ops.geom.geom3d.mesh.TriangularFacet)13 Vertex (net.imagej.ops.geom.geom3d.mesh.Vertex)8 DefaultMesh (net.imagej.ops.geom.geom3d.mesh.DefaultMesh)5 ArrayList (java.util.ArrayList)4 Facet (net.imagej.ops.geom.geom3d.mesh.Facet)4 RealLocalizable (net.imglib2.RealLocalizable)3 RealPoint (net.imglib2.RealPoint)3 FinalInterval (net.imglib2.FinalInterval)2 Vector3D (org.apache.commons.math3.geometry.euclidean.threed.Vector3D)2 IOException (java.io.IOException)1 URISyntaxException (java.net.URISyntaxException)1 LinkedHashSet (java.util.LinkedHashSet)1 AbstractFeatureTest (net.imagej.ops.features.AbstractFeatureTest)1 DefaultMarchingCubes (net.imagej.ops.geom.geom3d.DefaultMarchingCubes)1 Horizon (net.imagej.ops.geom.geom3d.mesh.Horizon)1 RandomAccessibleInterval (net.imglib2.RandomAccessibleInterval)1 BitType (net.imglib2.type.logic.BitType)1 BoolType (net.imglib2.type.logic.BoolType)1 DoubleType (net.imglib2.type.numeric.real.DoubleType)1 ExtendedRandomAccessibleInterval (net.imglib2.view.ExtendedRandomAccessibleInterval)1