Search in sources :

Example 1 with SpatialHashTable

use of maspack.geometry.SpatialHashTable in project artisynth_core by artisynth.

the class StlReader method readBinary.

public static PolygonalMesh readBinary(PolygonalMesh mesh, InputStream is, double tol) throws IOException {
    boolean _printDebug = false;
    // Byte ordering is assumed to be Little Endian (see wikipedia on STL format).
    // Format of binary STL is
    // 80 byte header (skip)
    // 4 byte int indicating num facets to follow
    is.skip(80);
    byte[] bbuf = new byte[4];
    is.read(bbuf, 0, 4);
    // This is a simple way to read unsigned long from 4 bytes (LittleEndian)
    // There is no other method for reading unsigned 4-byte Int with ByteBuffer!
    long numFacets = 0;
    numFacets |= bbuf[3] & 0xFF;
    numFacets <<= 8;
    numFacets |= bbuf[2] & 0xFF;
    numFacets <<= 8;
    numFacets |= bbuf[1] & 0xFF;
    numFacets <<= 8;
    numFacets |= bbuf[0] & 0xFF;
    if (_printDebug) {
        System.out.println("Num facets: " + numFacets);
    }
    ArrayList<Point3d> nodeList = new ArrayList<Point3d>();
    ArrayList<ArrayList<Integer>> faceList = new ArrayList<ArrayList<Integer>>();
    if (_printDebug) {
        System.out.print("Reading file... ");
    }
    // For big files, it is slightly faster to read one facet
    // at a time than the whole file at once (for some reason).
    long start = System.nanoTime();
    int facetSize = 50;
    bbuf = new byte[facetSize];
    List<Point3d> allPoints = new ArrayList<Point3d>(3 * (int) numFacets);
    List<Point3d[]> allFaces = new ArrayList<Point3d[]>((int) numFacets);
    for (long i = 0; i < numFacets; i++) {
        int nBytesRead = is.read(bbuf, 0, facetSize);
        if (nBytesRead < facetSize) {
            throw new IOException("Invalid STL file detected! (non-matching size)");
        }
        ByteBuffer bb = ByteBuffer.wrap(bbuf);
        bb.order(ByteOrder.LITTLE_ENDIAN);
        // Ignore normal
        bb.getFloat();
        bb.getFloat();
        bb.getFloat();
        Point3d[] face = new Point3d[3];
        // Read all 3 vertices
        double[] vals = new double[3];
        for (int j = 0; j < 3; j++) {
            vals[0] = bb.getFloat();
            vals[1] = bb.getFloat();
            vals[2] = bb.getFloat();
            Point3d pnt;
            pnt = new Point3d(vals);
            allPoints.add(pnt);
            face[j] = pnt;
        }
        allFaces.add(face);
        // Attribute byte count should = 0
        bb.getShort();
    }
    if (_printDebug) {
        System.out.println("(" + 1.e-9 * (System.nanoTime() - start) + ")");
        System.out.print("Building spatial hash table... ");
        start = System.nanoTime();
    }
    SpatialHashTable<Point3d> table = new SpatialHashTable<Point3d>(tol);
    table.setup(allPoints, allPoints);
    if (_printDebug) {
        System.out.println("(" + 1.e-9 * (System.nanoTime() - start) + ")");
        System.out.print("Scanning for unique verts... ");
        start = System.nanoTime();
    }
    HashMap<Point3d, Integer> allToUniqueMap = new HashMap<Point3d, Integer>(allPoints.size());
    double tolSq = tol * tol;
    for (Point3d pnt : allPoints) {
        if (allToUniqueMap.containsKey(pnt)) {
            continue;
        }
        // Find all points within tol of pnt
        List<Point3d> results = new ArrayList<Point3d>();
        // table.getCellsNearOld (pnt);
        List<Point3d> cell = table.getElsNear(pnt);
        // continue;
        if (cell != null) {
            for (Point3d neighbour : cell) {
                if (neighbour.distanceSquared(pnt) < tolSq) {
                    results.add(neighbour);
                }
            }
        }
        int idx = nodeList.size();
        nodeList.add(pnt);
        for (Point3d neighbour : results) {
            allToUniqueMap.put(neighbour, idx);
        }
    }
    if (_printDebug) {
        System.out.println("(" + 1.e-9 * (System.nanoTime() - start) + ")");
        System.out.print("Building faceList... ");
        start = System.nanoTime();
    }
    // Build face list by looking up the index of the Unique vert through hashmap.
    for (Point3d[] face : allFaces) {
        ArrayList<Integer> faceNodes = new ArrayList<Integer>(3);
        for (int i = 0; i < 3; i++) {
            int idx = allToUniqueMap.get(face[i]);
            faceNodes.add(idx);
        }
        faceList.add(faceNodes);
    }
    if (_printDebug) {
        System.out.println("(" + 1.e-9 * (System.nanoTime() - start) + ")");
        System.out.print("building mesh... ");
        start = System.nanoTime();
    }
    mesh = buildMesh(mesh, nodeList, faceList);
    if (_printDebug) {
        System.out.println("(" + 1.e-9 * (System.nanoTime() - start) + ")");
        System.out.println("Done!");
        System.out.println("Unique verts: " + nodeList.size());
        System.out.println("Unique faces: " + allFaces.size());
    }
    return mesh;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) SpatialHashTable(maspack.geometry.SpatialHashTable) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) Point3d(maspack.matrix.Point3d)

Aggregations

IOException (java.io.IOException)1 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 SpatialHashTable (maspack.geometry.SpatialHashTable)1 Point3d (maspack.matrix.Point3d)1