Example usage for java.nio IntBuffer get

List of usage examples for java.nio IntBuffer get

Introduction

In this page you can find the example usage for java.nio IntBuffer get.

Prototype

public abstract int get(int index);

Source Link

Document

Returns an int at the specified index; the position is not changed.

Usage

From source file:org.rifidi.designer.rcp.game.DesignerGame.java

@Override
public void simpleRender() {
    if (sceneData != null && !getCanvas().isDisposed() && sceneData.getRootNode().getParent() != null) {
        GameStateManager.getInstance().render(0);
        if (GlobalProperties.physicsDebugging) {
            PhysicsDebugger.drawPhysics(sceneData.getPhysicsSpace(), getRenderer());
        }//w w  w  .  j  a  v a2  s. c  o m
        if (GlobalProperties.boundingDebugging) {
            if (bu == null) {
                bu = ((EntitiesServiceImpl) sceneDataService).getRoomOctree().getTreeAsNode();
            }
            Debugger.drawBounds(bu, getRenderer());
            Debugger.drawBounds(sceneData.getRootNode(), getRenderer());
        }
        getRenderer().displayBackBuffer();
        // getCanvas().swapBuffers();
        if (miniMapView == null) {
            miniMapView = (MiniMapView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
                    .findView(MiniMapView.ID);
        }
        if (offy.isSupported() && miniMapView != null && minimapCounter == 10) {
            miniMapView.setMapCamera(offy.getCamera());
            minimapCounter = 0;
            sceneLOD = 3;
            for (Entity entity : sceneDataService.getCurrentSceneData().getEntities()) {
                if (entity instanceof VisualEntity) {
                    ((VisualEntity) entity).setLOD(sceneLOD);
                }
            }
            offscreenRenderSpatials.clear();
            offy.render(sceneData.getRootNode());
            IntBuffer buffer = offy.getImageData();
            if (imgData == null) {
                imgData = new ImageData(200, 200, 32, new PaletteData(0xFF0000, 0x00FF00, 0x0000FF));
            }
            for (int y = 0; y < 200; y++) {
                for (int x = 0; x < 200; x++) {
                    imgData.setPixel(x, y, buffer.get((199 - y) * 200 + x));
                }
            }
            miniMapView.setImage(imgData, 20);
        }
        minimapCounter++;

    }

}

From source file:org.geotools.imageio.unidata.UnidataImageReader.java

/**
 * @see javax.imageio.ImageReader#read(int, javax.imageio.ImageReadParam)
 *//*from   w w w  . j a  va 2s  .  c om*/
@Override
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
    clearAbortRequest();

    final UnidataSlice2DIndex slice2DIndex = getSlice2DIndex(imageIndex);
    final String variableName = slice2DIndex.getVariableName();
    final UnidataVariableAdapter wrapper = getCoverageDescriptor(new NameImpl(variableName));

    /*
     * Fetches the parameters that are not already processed by utility
     * methods like 'getDestination' or 'computeRegions' (invoked below).
     */
    final int strideX, strideY;
    // final int[] srcBands;
    final int[] dstBands;
    if (param != null) {
        strideX = param.getSourceXSubsampling();
        strideY = param.getSourceYSubsampling();
        // srcBands = param.getSourceBands();
        dstBands = param.getDestinationBands();
    } else {
        strideX = 1;
        strideY = 1;
        // srcBands = null;
        dstBands = null;
    }

    /*
     * Gets the destination image of appropriate size. We create it now
     * since it is a convenient way to get the number of destination bands.
     */
    final int width = wrapper.getWidth();
    final int height = wrapper.getHeight();
    /*
     * Computes the source region (in the NetCDF file) and the destination
     * region (in the buffered image). Copies those informations into UCAR
     * Range structure.
     */
    final Rectangle srcRegion = new Rectangle();
    final Rectangle destRegion = new Rectangle();
    computeRegions(param, width, height, null, srcRegion, destRegion);
    flipVertically(param, height, srcRegion);
    int destWidth = destRegion.x + destRegion.width;
    int destHeight = destRegion.y + destRegion.height;

    /*
     * build the ranges that need to be read from each 
     * dimension based on the source region
     */
    final List<Range> ranges = new LinkedList<Range>();
    try {
        // add the ranges the COARDS way: T, Z, Y, X
        // T
        int first = slice2DIndex.getTIndex();
        int length = 1;
        int stride = 1;
        if (first != -1) {
            ranges.add(new Range(first, first + length - 1, stride));
        }
        // Z
        first = slice2DIndex.getZIndex();
        if (first != -1) {
            ranges.add(new Range(first, first + length - 1, stride));
        }
        // Y
        first = srcRegion.y;
        length = srcRegion.height;
        stride = strideY;
        ranges.add(new Range(first, first + length - 1, stride));
        // X
        first = srcRegion.x;
        length = srcRegion.width;
        stride = strideX;
        ranges.add(new Range(first, first + length - 1, stride));
    } catch (InvalidRangeException e) {
        throw netcdfFailure(e);
    }

    /*
     * create the section of multidimensional array indices
     * that defines the exact data that need to be read 
     * for this image index and parameters 
     */
    final Section section = new Section(ranges);

    /*
     * Setting SampleModel and ColorModel.
     */
    final SampleModel sampleModel = wrapper.getSampleModel().createCompatibleSampleModel(destWidth, destHeight);
    final ColorModel colorModel = ImageIOUtilities.createColorModel(sampleModel);

    final WritableRaster raster = Raster.createWritableRaster(sampleModel, new Point(0, 0));
    final BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);

    CoordinateAxis axis = wrapper.variableDS.getCoordinateSystems().get(0).getLatAxis();
    boolean flipYAxis = false;
    try {
        Array yAxisStart = axis.read(new Section().appendRange(2));
        float y1 = yAxisStart.getFloat(0);
        float y2 = yAxisStart.getFloat(1);
        if (y2 > y1) {
            flipYAxis = true;
        }
    } catch (InvalidRangeException e) {
        throw new RuntimeException(e);
    }
    /*
     * Reads the requested sub-region only.
     */
    processImageStarted(imageIndex);
    final int numDstBands = 1;
    final float toPercent = 100f / numDstBands;
    final int type = raster.getSampleModel().getDataType();
    final int xmin = destRegion.x;
    final int ymin = destRegion.y;
    final int xmax = destRegion.width + xmin;
    final int ymax = destRegion.height + ymin;
    for (int zi = 0; zi < numDstBands; zi++) {
        // final int srcBand = (srcBands == null) ? zi : srcBands[zi];
        final int dstBand = (dstBands == null) ? zi : dstBands[zi];
        final Array array;
        try {
            // TODO leak through
            array = wrapper.variableDS.read(section);
        } catch (InvalidRangeException e) {
            throw netcdfFailure(e);
        }
        if (flipYAxis) {
            final IndexIterator it = array.getIndexIterator();
            for (int y = ymax; --y >= ymin;) {
                for (int x = xmin; x < xmax; x++) {
                    switch (type) {
                    case DataBuffer.TYPE_DOUBLE: {
                        raster.setSample(x, y, dstBand, it.getDoubleNext());
                        break;
                    }
                    case DataBuffer.TYPE_FLOAT: {
                        raster.setSample(x, y, dstBand, it.getFloatNext());
                        break;
                    }
                    case DataBuffer.TYPE_BYTE: {
                        byte b = it.getByteNext();
                        // int myByte = (0x000000FF & ((int) b));
                        // short anUnsignedByte = (short) myByte;
                        // raster.setSample(x, y, dstBand, anUnsignedByte);
                        raster.setSample(x, y, dstBand, b);
                        break;
                    }
                    default: {
                        raster.setSample(x, y, dstBand, it.getIntNext());
                        break;
                    }
                    }
                }
            }
        } else {
            switch (type) {
            case DataBuffer.TYPE_DOUBLE: {
                DoubleBuffer doubleBuffer = array.getDataAsByteBuffer().asDoubleBuffer();
                double[] samples = new double[destRegion.width * destRegion.height];
                doubleBuffer.get(samples);
                raster.setSamples(xmin, ymin, destRegion.width, destRegion.height, dstBand, samples);
                break;
            }
            case DataBuffer.TYPE_FLOAT:
                float[] samples = new float[destRegion.width * destRegion.height];
                FloatBuffer floatBuffer = array.getDataAsByteBuffer().asFloatBuffer();
                floatBuffer.get(samples);
                raster.setSamples(xmin, ymin, destRegion.width, destRegion.height, dstBand, samples);
                break;
            case DataBuffer.TYPE_BYTE:
                //THIS ONLY WORKS FOR ONE BAND!!
                raster.setDataElements(xmin, ymin, destRegion.width, destRegion.height,
                        array.getDataAsByteBuffer().array());
                break;
            case DataBuffer.TYPE_INT:
                IntBuffer intBuffer = array.getDataAsByteBuffer().asIntBuffer();
                int[] intSamples = new int[destRegion.width * destRegion.height];
                intBuffer.get(intSamples);
                raster.setSamples(xmin, ymin, destRegion.width, destRegion.height, dstBand, intSamples);
                break;
            default: {
                final IndexIterator it = array.getIndexIterator();
                for (int y = ymin; y < ymax; y++) {
                    for (int x = xmin; x < xmax; x++) {
                        raster.setSample(x, y, dstBand, it.getIntNext());
                    }
                }
                break;
            }

            }

        }
        /*
         * Checks for abort requests after reading. It would be a waste of a
         * potentially good image (maybe the abort request occurred after we
         * just finished the reading) if we didn't implemented the
         * 'isCancel()' method. But because of the later, which is checked
         * by the NetCDF library, we can't assume that the image is
         * complete.
         */
        if (abortRequested()) {
            processReadAborted();
            return image;
        }
        /*
         * Reports progress here, not in the deeper loop, because the costly
         * part is the call to 'variable.read(...)' which can't report
         * progress. The loop that copy pixel values is fast, so reporting
         * progress there would be pointless.
         */
        processImageProgress(zi * toPercent);
    }
    processImageComplete();
    return image;
}

From source file:org.geotools.imageio.netcdf.NetCDFImageReader.java

/**
 * @see javax.imageio.ImageReader#read(int, javax.imageio.ImageReadParam)
 */// ww  w .j a  v  a 2 s  .  c  o m
@Override
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
    clearAbortRequest();

    final Slice2DIndex slice2DIndex = getSlice2DIndex(imageIndex);
    final String variableName = slice2DIndex.getVariableName();
    final VariableAdapter wrapper = getCoverageDescriptor(new NameImpl(variableName));

    /*
     * Fetches the parameters that are not already processed by utility
     * methods like 'getDestination' or 'computeRegions' (invoked below).
     */
    final int strideX, strideY;
    // final int[] srcBands;
    final int[] dstBands;
    if (param != null) {
        strideX = param.getSourceXSubsampling();
        strideY = param.getSourceYSubsampling();
        // srcBands = param.getSourceBands();
        dstBands = param.getDestinationBands();
    } else {
        strideX = 1;
        strideY = 1;
        // srcBands = null;
        dstBands = null;
    }

    /*
     * Gets the destination image of appropriate size. We create it now
     * since it is a convenient way to get the number of destination bands.
     */
    final int width = wrapper.getWidth();
    final int height = wrapper.getHeight();
    /*
     * Computes the source region (in the NetCDF file) and the destination
     * region (in the buffered image). Copies those informations into UCAR
     * Range structure.
     */
    final Rectangle srcRegion = new Rectangle();
    final Rectangle destRegion = new Rectangle();
    computeRegions(param, width, height, null, srcRegion, destRegion);

    // Flipping is needed only when the input latitude coordinate is ordered
    // from min to max
    if (needsFlipping) {
        flipVertically(param, height, srcRegion);
    }
    int destWidth = destRegion.x + destRegion.width;
    int destHeight = destRegion.y + destRegion.height;

    /*
     * build the ranges that need to be read from each 
     * dimension based on the source region
     */
    final List<Range> ranges = new LinkedList<Range>();
    try {
        // add the ranges the COARDS way: T, Z, Y, X
        // T
        int first = slice2DIndex.getTIndex();
        int length = 1;
        int stride = 1;
        if (first != -1) {
            ranges.add(new Range(first, first + length - 1, stride));
        }
        // Z
        first = slice2DIndex.getZIndex();
        if (first != -1) {
            ranges.add(new Range(first, first + length - 1, stride));
        }
        // Y
        first = srcRegion.y;
        length = srcRegion.height;
        stride = strideY;
        ranges.add(new Range(first, first + length - 1, stride));
        // X
        first = srcRegion.x;
        length = srcRegion.width;
        stride = strideX;
        ranges.add(new Range(first, first + length - 1, stride));
    } catch (InvalidRangeException e) {
        throw netcdfFailure(e);
    }

    /*
     * create the section of multidimensional array indices
     * that defines the exact data that need to be read 
     * for this image index and parameters 
     */
    final Section section = new Section(ranges);

    /*
     * Setting SampleModel and ColorModel.
     */
    final SampleModel sampleModel = wrapper.getSampleModel().createCompatibleSampleModel(destWidth, destHeight);
    final ColorModel colorModel = ImageIOUtilities.createColorModel(sampleModel);

    final WritableRaster raster = Raster.createWritableRaster(sampleModel, new Point(0, 0));
    final BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);

    CoordinateAxis axis = wrapper.variableDS.getCoordinateSystems().get(0).getLatAxis();
    boolean flipYAxis = false;
    try {
        Array yAxisStart = axis.read(new Section().appendRange(2));
        float y1 = yAxisStart.getFloat(0);
        float y2 = yAxisStart.getFloat(1);
        if (y2 > y1) {
            flipYAxis = true;
        }
    } catch (InvalidRangeException e) {
        throw new RuntimeException(e);
    }
    /*
     * Reads the requested sub-region only.
     */
    processImageStarted(imageIndex);
    final int numDstBands = 1;
    final float toPercent = 100f / numDstBands;
    final int type = raster.getSampleModel().getDataType();
    final int xmin = destRegion.x;
    final int ymin = destRegion.y;
    final int xmax = destRegion.width + xmin;
    final int ymax = destRegion.height + ymin;
    for (int zi = 0; zi < numDstBands; zi++) {
        // final int srcBand = (srcBands == null) ? zi : srcBands[zi];
        final int dstBand = (dstBands == null) ? zi : dstBands[zi];
        final Array array;
        try {
            // TODO leak through
            array = wrapper.variableDS.read(section);
        } catch (InvalidRangeException e) {
            throw netcdfFailure(e);
        }
        if (flipYAxis) {
            final IndexIterator it = array.getIndexIterator();
            for (int y = ymax; --y >= ymin;) {
                for (int x = xmin; x < xmax; x++) {
                    switch (type) {
                    case DataBuffer.TYPE_DOUBLE: {
                        raster.setSample(x, y, dstBand, it.getDoubleNext());
                        break;
                    }
                    case DataBuffer.TYPE_FLOAT: {
                        raster.setSample(x, y, dstBand, it.getFloatNext());
                        break;
                    }
                    case DataBuffer.TYPE_BYTE: {
                        byte b = it.getByteNext();
                        // int myByte = (0x000000FF & ((int) b));
                        // short anUnsignedByte = (short) myByte;
                        // raster.setSample(x, y, dstBand, anUnsignedByte);
                        raster.setSample(x, y, dstBand, b);
                        break;
                    }
                    default: {
                        raster.setSample(x, y, dstBand, it.getIntNext());
                        break;
                    }
                    }
                }
            }
        } else {
            switch (type) {
            case DataBuffer.TYPE_DOUBLE: {
                DoubleBuffer doubleBuffer = array.getDataAsByteBuffer().asDoubleBuffer();
                double[] samples = new double[destRegion.width * destRegion.height];
                doubleBuffer.get(samples);
                raster.setSamples(xmin, ymin, destRegion.width, destRegion.height, dstBand, samples);
                break;
            }
            case DataBuffer.TYPE_FLOAT:
                float[] samples = new float[destRegion.width * destRegion.height];
                FloatBuffer floatBuffer = array.getDataAsByteBuffer().asFloatBuffer();
                floatBuffer.get(samples);
                raster.setSamples(xmin, ymin, destRegion.width, destRegion.height, dstBand, samples);
                break;
            case DataBuffer.TYPE_BYTE:
                //THIS ONLY WORKS FOR ONE BAND!!
                raster.setDataElements(xmin, ymin, destRegion.width, destRegion.height,
                        array.getDataAsByteBuffer().array());
                break;
            case DataBuffer.TYPE_INT:
                IntBuffer intBuffer = array.getDataAsByteBuffer().asIntBuffer();
                int[] intSamples = new int[destRegion.width * destRegion.height];
                intBuffer.get(intSamples);
                raster.setSamples(xmin, ymin, destRegion.width, destRegion.height, dstBand, intSamples);
                break;
            default: {
                final IndexIterator it = array.getIndexIterator();
                for (int y = ymin; y < ymax; y++) {
                    for (int x = xmin; x < xmax; x++) {
                        raster.setSample(x, y, dstBand, it.getIntNext());
                    }
                }
                break;
            }

            }

        }
        /*
         * Checks for abort requests after reading. It would be a waste of a
         * potentially good image (maybe the abort request occurred after we
         * just finished the reading) if we didn't implemented the
         * 'isCancel()' method. But because of the later, which is checked
         * by the NetCDF library, we can't assume that the image is
         * complete.
         */
        if (abortRequested()) {
            processReadAborted();
            return image;
        }
        /*
         * Reports progress here, not in the deeper loop, because the costly
         * part is the call to 'variable.read(...)' which can't report
         * progress. The loop that copy pixel values is fast, so reporting
         * progress there would be pointless.
         */
        processImageProgress(zi * toPercent);
    }
    processImageComplete();
    return image;
}

From source file:edu.cmu.graphchi.shards.QueryShard.java

private void queryIn(Long queryId, QueryCallback callback, byte edgeType, boolean ignoreType) {
    if (queryCache != null && callback.immediateReceive()) {
        long[] cached = (long[]) queryCache.get(incacheKey(queryId, edgeType));
        if (cached != null && callback.immediateReceive()) {
            for (int j = 0; j < cached.length; j++) {
                long ptr = cached[j];
                callback.receiveEdge(VertexIdTranslate.getVertexId(ptr), queryId, edgeType,
                        PointerUtil.encodePointer(shardNum, (int) VertexIdTranslate.getAux(ptr)));
            }//w  ww. ja v  a  2  s .co  m
            // cacheHitCounter.inc();
            return;
        } else {
            cacheMissCounter.inc();
        }
    }

    if (queryId < interval.getFirstVertex() || queryId > interval.getLastVertex()) {
        throw new IllegalArgumentException("Vertex " + queryId + " not part of interval:" + interval);
    }
    final LongBuffer tmpBuffer = adjBuffer.duplicate();

    try {
        /* Step 1: collect adj file offsets for the in-edges */
        final Timer.Context _timer1 = inEdgePhase1Timer.time();
        ArrayList<Integer> offsets = new ArrayList<Integer>();
        int END = (1 << 26) - 1;

        final IntBuffer startBufferTmp = inEdgeStartBuffer.duplicate();

        // Binary search to find the start of the vertex
        int n = inEdgeStartBuffer.capacity() / 2;
        int low = 0;
        int high = n - 1;
        int off = -1;
        int queryRelative = (int) (queryId - interval.getFirstVertex());
        while (low <= high) {
            int idx = ((high + low) / 2);
            int v = startBufferTmp.get(idx * 2);
            if (v == queryRelative) {
                off = startBufferTmp.get(idx * 2 + 1);
                break;
            }
            if (v < queryRelative) {
                low = idx + 1;
            } else {
                high = idx - 1;
            }
        }

        if (off == (-1)) {
            if (queryCache != null && queryCacheSize > queryCache.size()) {
                queryCache.put(incacheKey(queryId, edgeType), new long[0]);
            }
            return;
        }

        while (off != END) {
            tmpBuffer.position(off);
            long edge = tmpBuffer.get();

            if (VertexIdTranslate.getVertexId(edge) != queryId) {
                System.out.println(
                        "Mismatch in edge linkage: " + VertexIdTranslate.getVertexId(edge) + " !=" + queryId);
                throw new RuntimeException(
                        "Mismatch in edge linkage: " + VertexIdTranslate.getVertexId(edge) + " !=" + queryId);
            }
            if (ignoreType || VertexIdTranslate.getType(edge) == edgeType) {
                offsets.add(off);
            }

            off = (int) VertexIdTranslate.getAux(edge);

            if (off > END) {
                throw new RuntimeException("Encoding error: " + edge + " --> "
                        + VertexIdTranslate.getVertexId(edge) + " off : " + VertexIdTranslate.getAux(edge));
            }
            if (off != END && (off < 0 || off > tmpBuffer.capacity())) {
                System.err.println("Illegal off when looking for inedges: " + off + ", capacity:"
                        + tmpBuffer.capacity() + ", shardNum=" + shardNum);
            }
        }
        _timer1.stop();

        /* Step 2: collect the vertex ids that contain the offsets by passing over the pointer data */
        /* Find beginning */

        ArrayList<Long> inNeighbors = (callback.immediateReceive() ? null
                : new ArrayList<Long>(offsets.size()));
        ArrayList<Long> inNeighborsPtrs = (callback.immediateReceive() ? null
                : new ArrayList<Long>(offsets.size()));
        ArrayList<Byte> edgeTypes = (callback.immediateReceive() ? null : new ArrayList<Byte>(offsets.size()));

        ArrayList<Long> cached = (queryCache == null || queryCache.size() >= queryCacheSize || freezeCache
                ? null
                : new ArrayList<Long>());

        final LongBuffer tmpPointerIdxBuffer = (pinIndexToMemory ? null : pointerIdxBuffer.duplicate());

        Iterator<Integer> offsetIterator = offsets.iterator();
        if (!offsets.isEmpty()) {
            final Timer.Context _timer2 = inEdgePhase2Timer.time();

            int firstOff = offsets.get(0);
            if (tmpPointerIdxBuffer != null) {
                final Timer.Context _timer3 = inEdgeIndexLookupTimer.time();
                ShardIndex.IndexEntry startIndex = index.lookupByOffset(firstOff * 8);
                _timer3.stop();
                tmpPointerIdxBuffer.position(startIndex.vertexSeq);
            }

            int lastOff = firstOff;

            while (offsetIterator.hasNext()) {
                off = offsetIterator.next();

                if (off - lastOff > 8196 && tmpPointerIdxBuffer != null) {
                    // magic threshold when to consult the index
                    ShardIndex.IndexEntry skipIdx = index.lookupByOffset(off * 8);
                    if (skipIdx.fileOffset > lastOff) {
                        tmpPointerIdxBuffer.position(skipIdx.vertexSeq);
                    }
                }

                long vert = findVertexForOff(off, tmpPointerIdxBuffer);
                if (!callback.immediateReceive()) {
                    inNeighbors.add(vert);
                    inNeighborsPtrs.add(PointerUtil.encodePointer(shardNum, off));
                    edgeTypes.add(edgeType); // TODO with wild card
                } else {
                    callback.receiveEdge(vert, queryId, edgeType, PointerUtil.encodePointer(shardNum, off));
                }
                if (cached != null) {
                    cached.add(VertexIdTranslate.encodeVertexPacket(edgeType, vert, off));
                }
                lastOff = off;
            }
            _timer2.stop();

            if (cached != null) {
                long[] cachedArr = new long[cached.size()];
                for (int j = 0; j < cached.size(); j++)
                    cachedArr[j] = cached.get(j);
                queryCache.put(incacheKey(queryId, edgeType), cachedArr);
            }
        }
        if (!callback.immediateReceive()) {
            callback.receiveInNeighbors(queryId, inNeighbors, edgeTypes, inNeighborsPtrs);
        }

    } catch (Exception err) {
        throw new RuntimeException(err);
    }
}

From source file:org.bimserver.geometry.GeometryRunner.java

@Override
public void run() {
    Thread.currentThread().setName("GeometryRunner");
    long start = System.nanoTime();
    job.setStartNanos(start);/*from  w  w w  .  ja  v  a 2 s. c o m*/
    try {
        HashMapVirtualObject next = objectProvider.next();
        Query query = new Query("Double buffer query " + eClass.getName(),
                this.streamingGeometryGenerator.packageMetaData);
        QueryPart queryPart = query.createQueryPart();
        while (next != null) {
            long oid = next.getOid();
            queryPart.addOid(oid);
            if (eClass.isSuperTypeOf(next.eClass())) {
                if (originalQuery.getQueryParts().get(0).getOids().contains(oid)) {
                    job.addObject(next.getOid(), next.eClass().getName());
                }
            }
            next = objectProvider.next();
        }

        objectProvider = new QueryObjectProvider(databaseSession, this.streamingGeometryGenerator.bimServer,
                query, Collections.singleton(queryContext.getRoid()),
                this.streamingGeometryGenerator.packageMetaData);

        StreamingSerializer serializer = ifcSerializerPlugin.createSerializer(new PluginConfiguration());
        RenderEngine renderEngine = null;
        byte[] bytes = null;
        try {
            final Set<HashMapVirtualObject> objects = new LinkedHashSet<>();
            ObjectProviderProxy proxy = new ObjectProviderProxy(objectProvider, new ObjectListener() {
                @Override
                public void newObject(HashMapVirtualObject next) {
                    if (eClass.isSuperTypeOf(next.eClass())) {
                        if (next.eGet(
                                GeometryRunner.this.streamingGeometryGenerator.representationFeature) != null) {
                            if (originalQuery.getQueryParts().get(0).getOids().contains(next.getOid())) {
                                objects.add(next);
                            }
                        }
                    }
                }
            });
            serializer.init(proxy, null, null, this.streamingGeometryGenerator.bimServer.getPluginManager(),
                    this.streamingGeometryGenerator.packageMetaData);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            IOUtils.copy(serializer.getInputStream(), baos);
            bytes = baos.toByteArray();
            InputStream in = new ByteArrayInputStream(bytes);
            Map<Integer, HashMapVirtualObject> notFoundObjects = new HashMap<>();

            Set<Range> reusableGeometryData = new HashSet<>();

            Map<Long, TemporaryGeometryData> productToData = new HashMap<>();
            try {
                if (!objects.isEmpty()) {
                    renderEngine = renderEnginePool.borrowObject();
                    try (RenderEngineModel renderEngineModel = renderEngine.openModel(in, bytes.length)) {
                        renderEngineModel.setSettings(renderEngineSettings);
                        renderEngineModel.setFilter(renderEngineFilter);

                        try {
                            renderEngineModel.generateGeneralGeometry();
                        } catch (RenderEngineException e) {
                            if (e.getCause() instanceof java.io.EOFException) {
                                if (objects.isEmpty() || eClass.getName().equals("IfcAnnotation")) {
                                    // SKIP
                                } else {
                                    StreamingGeometryGenerator.LOGGER.error("Error in " + eClass.getName(), e);
                                }
                            }
                        }

                        OidConvertingSerializer oidConvertingSerializer = (OidConvertingSerializer) serializer;
                        Map<Long, Integer> oidToEid = oidConvertingSerializer.getOidToEid();
                        Map<Long, DebuggingInfo> debuggingInfo = new HashMap<>();

                        for (HashMapVirtualObject ifcProduct : objects) {
                            if (!this.streamingGeometryGenerator.running) {
                                return;
                            }
                            Integer expressId = oidToEid.get(ifcProduct.getOid());
                            try {
                                RenderEngineInstance renderEngineInstance = renderEngineModel
                                        .getInstanceFromExpressId(expressId);
                                RenderEngineGeometry geometry = renderEngineInstance.generateGeometry();
                                boolean translate = true;
                                // if (geometry == null ||
                                // geometry.getIndices().length == 0) {
                                // LOGGER.info("Running again...");
                                // renderEngineModel.setFilter(renderEngineFilterTransformed);
                                // geometry =
                                // renderEngineInstance.generateGeometry();
                                // if (geometry != null) {
                                // translate = false;
                                // }
                                // renderEngineModel.setFilter(renderEngineFilter);
                                // }

                                if (geometry != null && geometry.getNrIndices() > 0) {
                                    HashMapVirtualObject geometryInfo = new HashMapVirtualObject(queryContext,
                                            GeometryPackage.eINSTANCE.getGeometryInfo());

                                    HashMapWrappedVirtualObject bounds = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getBounds());
                                    HashMapWrappedVirtualObject minBounds = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getVector3f());
                                    HashMapWrappedVirtualObject maxBounds = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getVector3f());

                                    minBounds.set("x", Double.POSITIVE_INFINITY);
                                    minBounds.set("y", Double.POSITIVE_INFINITY);
                                    minBounds.set("z", Double.POSITIVE_INFINITY);

                                    maxBounds.set("x", -Double.POSITIVE_INFINITY);
                                    maxBounds.set("y", -Double.POSITIVE_INFINITY);
                                    maxBounds.set("z", -Double.POSITIVE_INFINITY);

                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_IfcProductOid(),
                                            ifcProduct.getOid());
                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_Bounds(), bounds);
                                    bounds.setAttribute(GeometryPackage.eINSTANCE.getBounds_Min(), minBounds);
                                    bounds.setAttribute(GeometryPackage.eINSTANCE.getBounds_Max(), maxBounds);

                                    HashMapWrappedVirtualObject boundsUntransformed = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getBounds());
                                    WrappedVirtualObject minBoundsUntranslated = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getVector3f());
                                    WrappedVirtualObject maxBoundsUntranslated = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getVector3f());

                                    minBoundsUntranslated.set("x", Double.POSITIVE_INFINITY);
                                    minBoundsUntranslated.set("y", Double.POSITIVE_INFINITY);
                                    minBoundsUntranslated.set("z", Double.POSITIVE_INFINITY);

                                    maxBoundsUntranslated.set("x", -Double.POSITIVE_INFINITY);
                                    maxBoundsUntranslated.set("y", -Double.POSITIVE_INFINITY);
                                    maxBoundsUntranslated.set("z", -Double.POSITIVE_INFINITY);

                                    boundsUntransformed.setAttribute(GeometryPackage.eINSTANCE.getBounds_Min(),
                                            minBoundsUntranslated);
                                    boundsUntransformed.setAttribute(GeometryPackage.eINSTANCE.getBounds_Max(),
                                            maxBoundsUntranslated);

                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_BoundsUntransformed(),
                                            boundsUntransformed);

                                    double volume = 0;
                                    ObjectNode additionalData = renderEngineInstance.getAdditionalData();
                                    if (streamingGeometryGenerator.isCalculateQuantities()) {
                                        if (additionalData != null) {
                                            geometryInfo.setAttribute(
                                                    GeometryPackage.eINSTANCE.getGeometryInfo_AdditionalData(),
                                                    additionalData.toString());
                                            if (additionalData.has("TOTAL_SURFACE_AREA")) {
                                                geometryInfo.setAttribute(
                                                        GeometryPackage.eINSTANCE.getGeometryInfo_Area(),
                                                        additionalData.get("TOTAL_SURFACE_AREA").asDouble());
                                            }
                                            if (additionalData.has("TOTAL_SHAPE_VOLUME")) {
                                                volume = additionalData.get("TOTAL_SHAPE_VOLUME").asDouble();
                                                geometryInfo.setAttribute(
                                                        GeometryPackage.eINSTANCE.getGeometryInfo_Volume(),
                                                        volume);
                                            }
                                        }
                                    }

                                    HashMapVirtualObject geometryData = new HashMapVirtualObject(queryContext,
                                            GeometryPackage.eINSTANCE.getGeometryData());

                                    geometryData.set("type", databaseSession.getCid(eClass));
                                    ByteBuffer indices = geometry.getIndices();
                                    IntBuffer indicesAsInt = indices.order(ByteOrder.LITTLE_ENDIAN)
                                            .asIntBuffer();
                                    geometryData.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryData_Reused(), 1);
                                    geometryData.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryData_Indices(),
                                            createBuffer(queryContext, indices));
                                    geometryData.set("nrIndices", indicesAsInt.capacity());
                                    ByteBuffer vertices = geometry.getVertices();
                                    DoubleBuffer verticesAsDouble = vertices.order(ByteOrder.LITTLE_ENDIAN)
                                            .asDoubleBuffer();
                                    geometryData.set("nrVertices", verticesAsDouble.capacity());
                                    geometryData.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryData_Vertices(),
                                            createBuffer(queryContext, vertices));
                                    ByteBuffer normals = geometry.getNormals();
                                    FloatBuffer normalsAsFloat = normals.order(ByteOrder.LITTLE_ENDIAN)
                                            .asFloatBuffer();
                                    geometryData.set("nrNormals", normalsAsFloat.capacity());
                                    geometryData.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryData_Normals(),
                                            createBuffer(queryContext, normals));

                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_PrimitiveCount(),
                                            indicesAsInt.capacity() / 3);

                                    job.setTrianglesGenerated(indicesAsInt.capacity() / 3);
                                    job.getReport().incrementTriangles(indicesAsInt.capacity() / 3);

                                    streamingGeometryGenerator.cacheGeometryData(geometryData, vertices);

                                    ColorMap colorMap = new ColorMap();

                                    ByteBuffer colors = ByteBuffer.wrap(new byte[0]);
                                    IntBuffer materialIndices = geometry.getMaterialIndices()
                                            .order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
                                    if (materialIndices != null && materialIndices.capacity() > 0) {
                                        FloatBuffer materialsAsFloat = geometry.getMaterials()
                                                .order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
                                        boolean hasMaterial = false;
                                        colors = ByteBuffer.allocate((verticesAsDouble.capacity() / 3) * 4);
                                        double[] triangle = new double[9];
                                        for (int i = 0; i < materialIndices.capacity(); ++i) {
                                            int c = materialIndices.get(i);
                                            if (c > -1) {
                                                Color4f color = new Color4f();
                                                for (int l = 0; l < 4; ++l) {
                                                    float val = fixColor(materialsAsFloat.get(4 * c + l));
                                                    color.set(l, val);
                                                }
                                                for (int j = 0; j < 3; ++j) {
                                                    int k = indicesAsInt.get(i * 3 + j);
                                                    triangle[j * 3 + 0] = verticesAsDouble.get(3 * k);
                                                    triangle[j * 3 + 1] = verticesAsDouble.get(3 * k + 1);
                                                    triangle[j * 3 + 2] = verticesAsDouble.get(3 * k + 2);
                                                    hasMaterial = true;
                                                    for (int l = 0; l < 4; ++l) {
                                                        float val = fixColor(materialsAsFloat.get(4 * c + l));
                                                        colors.put(4 * k + l,
                                                                UnsignedBytes.checkedCast((int) (val * 255)));
                                                    }
                                                }
                                                colorMap.addTriangle(triangle, color);
                                            }
                                        }
                                        if (hasMaterial) {
                                            ColorMap2 colorMap2 = new ColorMap2();
                                            byte[] colorB = new byte[4];
                                            for (int i = 0; i < colors.capacity(); i += 4) {
                                                colors.get(colorB);
                                                colorMap2.addColor(colorB);
                                            }

                                            HashMapVirtualObject colorPack = new HashMapVirtualObject(
                                                    queryContext, GeometryPackage.eINSTANCE.getColorPack());
                                            colorPack.set(GeometryPackage.eINSTANCE.getColorPack_Data(),
                                                    colorMap2.toByteArray());
                                            colorPack.save();
                                            geometryData.setReference(
                                                    GeometryPackage.eINSTANCE.getGeometryData_ColorPack(),
                                                    colorPack.getOid(), 0);
                                        }
                                        if (colorMap.usedColors() == 0) {
                                        } else if (colorMap.usedColors() == 1) {
                                            WrappedVirtualObject color = new HashMapWrappedVirtualObject(
                                                    GeometryPackage.eINSTANCE.getVector4f());
                                            Color4f firstColor = colorMap.getFirstColor();
                                            color.set("x", firstColor.getR());
                                            color.set("y", firstColor.getG());
                                            color.set("z", firstColor.getB());
                                            color.set("w", firstColor.getA());
                                            geometryData.setAttribute(
                                                    GeometryPackage.eINSTANCE.getGeometryData_Color(), color);

                                            // This tells the code further on to not store this geometry, as it can be easily generated
                                            hasMaterial = false;
                                        } else {
                                            Color4f mostUsed = colorMap.getMostUsedColor();

                                            WrappedVirtualObject color = new HashMapWrappedVirtualObject(
                                                    GeometryPackage.eINSTANCE.getVector4f());
                                            color.set("x", mostUsed.getR());
                                            color.set("y", mostUsed.getG());
                                            color.set("z", mostUsed.getB());
                                            color.set("w", mostUsed.getA());
                                            geometryData.setAttribute(
                                                    GeometryPackage.eINSTANCE.getGeometryData_MostUsedColor(),
                                                    color);
                                        }
                                        if (hasMaterial) {
                                            geometryData.set("nrColors", colors.capacity());
                                            geometryData.set(
                                                    GeometryPackage.eINSTANCE.getGeometryData_ColorsQuantized(),
                                                    createBuffer(queryContext, colors));
                                        } else {
                                            geometryData.set("nrColors", 0);
                                        }
                                    } else {
                                        geometryData.set("nrColors", 0);
                                    }

                                    boolean hasTransparency = colorMap.hasTransparency();

                                    double[] productTranformationMatrix = new double[16];
                                    if (translate && renderEngineInstance.getTransformationMatrix() != null) {
                                        productTranformationMatrix = renderEngineInstance
                                                .getTransformationMatrix();
                                    } else {
                                        Matrix.setIdentityM(productTranformationMatrix, 0);
                                    }

                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_NrColors(),
                                            colors.capacity());
                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_NrVertices(),
                                            verticesAsDouble.capacity());
                                    geometryInfo.setReference(GeometryPackage.eINSTANCE.getGeometryInfo_Data(),
                                            geometryData.getOid(), 0);
                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_HasTransparency(),
                                            hasTransparency);
                                    geometryData.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryData_HasTransparency(),
                                            hasTransparency);

                                    long size = this.streamingGeometryGenerator.getSize(geometryData);

                                    for (int i = 0; i < indicesAsInt.capacity(); i++) {
                                        this.streamingGeometryGenerator.processExtends(minBounds, maxBounds,
                                                productTranformationMatrix, verticesAsDouble,
                                                indicesAsInt.get(i) * 3, generateGeometryResult);
                                        this.streamingGeometryGenerator.processExtendsUntranslated(geometryInfo,
                                                verticesAsDouble, indicesAsInt.get(i) * 3,
                                                generateGeometryResult);
                                    }

                                    HashMapWrappedVirtualObject boundsUntransformedMm = createMmBounds(
                                            geometryInfo, boundsUntransformed,
                                            generateGeometryResult.getMultiplierToMm());
                                    geometryInfo.set("boundsUntransformedMm", boundsUntransformedMm);
                                    HashMapWrappedVirtualObject boundsMm = createMmBounds(geometryInfo, bounds,
                                            generateGeometryResult.getMultiplierToMm());
                                    geometryInfo.set("boundsMm", boundsMm);

                                    ByteBuffer normalsQuantized = quantizeNormals(normalsAsFloat);
                                    geometryData.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryData_NormalsQuantized(),
                                            createBuffer(queryContext, normalsQuantized));

                                    HashMapWrappedVirtualObject geometryDataBounds = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getBounds());
                                    WrappedVirtualObject geometryDataBoundsMin = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getVector3f());
                                    WrappedVirtualObject geometryDataBoundsMax = new HashMapWrappedVirtualObject(
                                            GeometryPackage.eINSTANCE.getVector3f());

                                    geometryDataBoundsMin.set("x",
                                            ((HashMapWrappedVirtualObject) boundsMm.get("min")).get("x"));
                                    geometryDataBoundsMin.set("y",
                                            ((HashMapWrappedVirtualObject) boundsMm.get("min")).get("y"));
                                    geometryDataBoundsMin.set("z",
                                            ((HashMapWrappedVirtualObject) boundsMm.get("min")).get("z"));

                                    geometryDataBoundsMax.set("x",
                                            ((HashMapWrappedVirtualObject) boundsMm.get("max")).get("x"));
                                    geometryDataBoundsMax.set("y",
                                            ((HashMapWrappedVirtualObject) boundsMm.get("max")).get("y"));
                                    geometryDataBoundsMax.set("z",
                                            ((HashMapWrappedVirtualObject) boundsMm.get("max")).get("z"));

                                    geometryDataBounds.setAttribute(GeometryPackage.eINSTANCE.getBounds_Min(),
                                            geometryDataBoundsMin);
                                    geometryDataBounds.setAttribute(GeometryPackage.eINSTANCE.getBounds_Max(),
                                            geometryDataBoundsMax);
                                    geometryData.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryData_BoundsMm(),
                                            geometryDataBounds);

                                    if (volume == 0) {
                                        volume = getVolumeFromBounds(boundsUntransformed);
                                    }
                                    float nrTriangles = geometry.getNrIndices() / 3;

                                    Density density = new Density(eClass.getName(), (float) volume,
                                            getBiggestFaceFromBounds(boundsUntransformedMm), (long) nrTriangles,
                                            geometryInfo.getOid());

                                    geometryInfo.setAttribute(
                                            GeometryPackage.eINSTANCE.getGeometryInfo_Density(),
                                            density.getDensityValue());

                                    generateGeometryResult.addDensity(density);

                                    double[] mibu = new double[] {
                                            (double) minBoundsUntranslated
                                                    .eGet(GeometryPackage.eINSTANCE.getVector3f_X()),
                                            (double) minBoundsUntranslated
                                                    .eGet(GeometryPackage.eINSTANCE.getVector3f_Y()),
                                            (double) minBoundsUntranslated
                                                    .eGet(GeometryPackage.eINSTANCE.getVector3f_Z()),
                                            1d };
                                    double[] mabu = new double[] {
                                            (double) maxBoundsUntranslated
                                                    .eGet(GeometryPackage.eINSTANCE.getVector3f_X()),
                                            (double) maxBoundsUntranslated
                                                    .eGet(GeometryPackage.eINSTANCE.getVector3f_Y()),
                                            (double) maxBoundsUntranslated
                                                    .eGet(GeometryPackage.eINSTANCE.getVector3f_Z()),
                                            1d };

                                    if (reuseGeometry) {
                                        /* TODO It still happens that geometry that should be reused is not reused, one of the reasons is still concurrency:
                                         *    - When the same geometry is processed concurrently they could both do the hash check at a time when there is no cached version, then they both think it's non-reused geometry
                                        */
                                        int hash = this.streamingGeometryGenerator.hash(indices, vertices,
                                                normals, colors);
                                        int firstIndex = indicesAsInt.get(0);
                                        int lastIndex = indicesAsInt.get(indicesAsInt.capacity() - 1);
                                        double[] firstVertex = new double[] { verticesAsDouble.get(firstIndex),
                                                verticesAsDouble.get(firstIndex + 1),
                                                verticesAsDouble.get(firstIndex + 2) };
                                        double[] lastVertex = new double[] {
                                                verticesAsDouble.get(lastIndex * 3),
                                                verticesAsDouble.get(lastIndex * 3 + 1),
                                                verticesAsDouble.get(lastIndex * 3 + 2) };
                                        Range range = new Range(firstVertex, lastVertex);
                                        Long referenceOid = this.streamingGeometryGenerator.hashes.get(hash);
                                        if (referenceOid != null) {
                                            HashMapVirtualObject referencedData = databaseSession
                                                    .getFromCache(referenceOid);
                                            if (referencedData == null) {
                                                LOGGER.error("Object not found in cache: " + referenceOid
                                                        + " (hash: " + hash + ")");
                                            }
                                            synchronized (referencedData) {
                                                Integer currentValue = (Integer) referencedData.get("reused");
                                                referencedData.set("reused", currentValue + 1);
                                            }
                                            HashMapWrappedVirtualObject dataBounds = (HashMapWrappedVirtualObject) referencedData
                                                    .get("boundsMm");
                                            extendBounds(boundsMm, dataBounds);
                                            referencedData.saveOverwrite();
                                            geometryInfo.setReference(
                                                    GeometryPackage.eINSTANCE.getGeometryInfo_Data(),
                                                    referenceOid, 0);
                                            this.streamingGeometryGenerator.bytesSavedByHash.addAndGet(size);
                                        } else if (geometryReused) {
                                            // This is true when this geometry is part of a mapped item mapping (and used more than once)

                                            boolean found = false;
                                            // for (Range r :
                                            // reusableGeometryData) {
                                            // if (r.isSimilar(range)) {
                                            // geometryInfo.setReference(GeometryPackage.eINSTANCE.getGeometryInfo_Data(),
                                            // r.getGeometryDataOid(), 0);
                                            // float[] offset =
                                            // r.getOffset(range);
                                            // ProductDef productDef =
                                            // map.get(ifcProduct.getOid());
                                            // double[] mappedItemMatrix =
                                            // null;
                                            // if (productDef != null &&
                                            // productDef.getMatrix() !=
                                            // null) {
                                            // mappedItemMatrix =
                                            // productDef.getMatrix();
                                            // } else {
                                            // Matrix.translateM(mappedItemMatrix,
                                            // 0, offset[0], offset[1],
                                            // offset[2]);
                                            // }
                                            // double[] result = new
                                            // double[16];
                                            // Matrix.multiplyMM(result, 0,
                                            // mappedItemMatrix, 0,
                                            // productTranformationMatrix,
                                            // 0);
                                            // setTransformationMatrix(geometryInfo,
                                            // result); // Overwritten?
                                            // bytesSavedByTransformation.addAndGet(size);
                                            // found = true;
                                            // break;
                                            // }
                                            // }
                                            if (!found) {
                                                range.setGeometryDataOid(geometryData.getOid());
                                                reusableGeometryData.add(range);

                                                if (streamingGeometryGenerator.isCalculateQuantities()) {
                                                    if (additionalData != null) {
                                                        geometryInfo.setAttribute(
                                                                GeometryPackage.eINSTANCE
                                                                        .getGeometryInfo_AdditionalData(),
                                                                additionalData.toString());
                                                        if (additionalData.has("SURFACE_AREA_ALONG_Z")) {
                                                            geometryInfo.setAttribute(
                                                                    GeometryPackage.eINSTANCE
                                                                            .getGeometryInfo_Area(),
                                                                    additionalData.get("SURFACE_AREA_ALONG_Z")
                                                                            .asDouble());
                                                        }
                                                        if (additionalData.has("TOTAL_SHAPE_VOLUME")) {
                                                            geometryInfo.setAttribute(
                                                                    GeometryPackage.eINSTANCE
                                                                            .getGeometryInfo_Volume(),
                                                                    additionalData.get("TOTAL_SHAPE_VOLUME")
                                                                            .asDouble());
                                                        }
                                                    }
                                                }

                                                geometryInfo.setAttribute(
                                                        GeometryPackage.eINSTANCE
                                                                .getGeometryInfo_PrimitiveCount(),
                                                        indicesAsInt.capacity() / 3);

                                                productToData.put(ifcProduct.getOid(),
                                                        new TemporaryGeometryData(geometryData.getOid(),
                                                                additionalData, indicesAsInt.capacity() / 3,
                                                                size, mibu, mabu, indicesAsInt,
                                                                verticesAsDouble, hasTransparency,
                                                                colors.capacity()));
                                                geometryData.save();
                                                databaseSession.cache((HashMapVirtualObject) geometryData);
                                            }
                                        } else {
                                            // if (sizes.containsKey(size)
                                            // && sizes.get(size).eClass()
                                            // == ifcProduct.eClass()) {
                                            // LOGGER.info("More reuse might
                                            // be possible " + size + " " +
                                            // ifcProduct.eClass().getName()
                                            // + ":" + ifcProduct.getOid() +
                                            // " / " +
                                            // sizes.get(size).eClass().getName()
                                            // + ":" +
                                            // sizes.get(size).getOid());
                                            // }
                                            //                                    if (geometryReused) {
                                            //                                       range.setGeometryDataOid(geometryData.getOid());
                                            //                                       reusableGeometryData.add(range);
                                            //                                       productToData.put(ifcProduct.getOid(), new TemporaryGeometryData(geometryData.getOid(), renderEngineInstance.getArea(), renderEngineInstance.getVolume(), indices.length / 3, size, mibu, mabu, indices, vertices));
                                            //                                    } // TODO else??

                                            // So reuse is on, the data was not found by hash, and this item is not in a mapped item

                                            // By saving it before putting it in the cache/hashmap, we make sure we won't get a BimserverConcurrentModificationException
                                            geometryData.save(); // TODO Why??

                                            databaseSession.cache((HashMapVirtualObject) geometryData);
                                            this.streamingGeometryGenerator.hashes.put(hash,
                                                    geometryData.getOid());
                                            // sizes.put(size, ifcProduct);
                                        }
                                    } else {
                                        geometryData.save();
                                        databaseSession.cache((HashMapVirtualObject) geometryData);
                                    }

                                    this.streamingGeometryGenerator.setTransformationMatrix(geometryInfo,
                                            productTranformationMatrix);
                                    debuggingInfo.put(ifcProduct.getOid(),
                                            new DebuggingInfo(productTranformationMatrix, indices.asIntBuffer(),
                                                    vertices.asFloatBuffer()));

                                    geometryInfo.save();
                                    this.streamingGeometryGenerator.totalBytes.addAndGet(size);

                                    ifcProduct.setReference(this.streamingGeometryGenerator.geometryFeature,
                                            geometryInfo.getOid(), 0);
                                    ifcProduct.saveOverwrite();

                                    // Doing a sync here because probably
                                    // writing large amounts of data, and db
                                    // only syncs every 100.000 writes by
                                    // default
                                    // databaseSession.getKeyValueStore().sync();
                                } else {
                                    // TODO
                                }
                            } catch (EntityNotFoundException e) {
                                // e.printStackTrace();
                                // As soon as we find a representation that
                                // is not Curve2D, then we should show a
                                // "INFO" message in the log to indicate
                                // there could be something wrong
                                boolean ignoreNotFound = eClass.getName().equals("IfcAnnotation");

                                // for (Object rep : representations) {
                                // if (rep instanceof
                                // IfcShapeRepresentation) {
                                // IfcShapeRepresentation
                                // ifcShapeRepresentation =
                                // (IfcShapeRepresentation)rep;
                                // if
                                // (!"Curve2D".equals(ifcShapeRepresentation.getRepresentationType()))
                                // {
                                // ignoreNotFound = false;
                                // }
                                // }
                                // }
                                if (!ignoreNotFound) {
                                    // LOGGER.warn("Entity not found " +
                                    // ifcProduct.eClass().getName() + " " +
                                    // (expressId) + "/" +
                                    // ifcProduct.getOid());
                                    notFoundObjects.put(expressId, ifcProduct);
                                }
                            } catch (BimserverDatabaseException | RenderEngineException e) {
                                StreamingGeometryGenerator.LOGGER.error("", e);
                            }
                        }

                        if (geometryReused && map != null) {
                            // We pick the first product and use that product to try and get the original data
                            long firstKey = map.keySet().iterator().next();
                            ProductDef masterProductDef = map.get(firstKey);
                            for (long key : map.keySet()) {
                                if (key != firstKey) {
                                    ProductDef productDef = map.get(key);
                                    HashMapVirtualObject ifcProduct = productDef.getObject();

                                    TemporaryGeometryData masterGeometryData = productToData
                                            .get(productDef.getMasterOid());
                                    if (masterGeometryData != null) {
                                        HashMapVirtualObject geometryInfo = new HashMapVirtualObject(
                                                queryContext, GeometryPackage.eINSTANCE.getGeometryInfo());

                                        HashMapWrappedVirtualObject bounds = new HashMapWrappedVirtualObject(
                                                GeometryPackage.eINSTANCE.getBounds());
                                        HashMapWrappedVirtualObject minBounds = new HashMapWrappedVirtualObject(
                                                GeometryPackage.eINSTANCE.getVector3f());
                                        HashMapWrappedVirtualObject maxBounds = new HashMapWrappedVirtualObject(
                                                GeometryPackage.eINSTANCE.getVector3f());

                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_Bounds(), bounds);
                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_HasTransparency(),
                                                masterGeometryData.hasTransparancy());

                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_NrColors(),
                                                masterGeometryData.getNrColors());
                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_NrVertices(),
                                                masterGeometryData.getNrVertices());

                                        bounds.set("min", minBounds);
                                        bounds.set("max", maxBounds);

                                        minBounds.set("x", Double.POSITIVE_INFINITY);
                                        minBounds.set("y", Double.POSITIVE_INFINITY);
                                        minBounds.set("z", Double.POSITIVE_INFINITY);

                                        maxBounds.set("x", -Double.POSITIVE_INFINITY);
                                        maxBounds.set("y", -Double.POSITIVE_INFINITY);
                                        maxBounds.set("z", -Double.POSITIVE_INFINITY);

                                        double[] mibu = masterGeometryData.getMibu();
                                        double[] mabu = masterGeometryData.getMabu();

                                        HashMapWrappedVirtualObject boundsUntransformed = new HashMapWrappedVirtualObject(
                                                GeometryPackage.eINSTANCE.getBounds());
                                        WrappedVirtualObject minBoundsUntransformed = new HashMapWrappedVirtualObject(
                                                GeometryPackage.eINSTANCE.getVector3f());
                                        WrappedVirtualObject maxBoundsUntransformed = new HashMapWrappedVirtualObject(
                                                GeometryPackage.eINSTANCE.getVector3f());

                                        minBoundsUntransformed.set("x", mibu[0]);
                                        minBoundsUntransformed.set("y", mibu[1]);
                                        minBoundsUntransformed.set("z", mibu[2]);

                                        maxBoundsUntransformed.set("x", mabu[0]);
                                        maxBoundsUntransformed.set("y", mabu[1]);
                                        maxBoundsUntransformed.set("z", mabu[2]);

                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_IfcProductOid(),
                                                ifcProduct.getOid());

                                        boundsUntransformed.setAttribute(
                                                GeometryPackage.eINSTANCE.getBounds_Min(),
                                                minBoundsUntransformed);
                                        boundsUntransformed.setAttribute(
                                                GeometryPackage.eINSTANCE.getBounds_Max(),
                                                maxBoundsUntransformed);
                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_BoundsUntransformed(),
                                                boundsUntransformed);

                                        ObjectNode additionalData = masterGeometryData.getAdditionalData();
                                        double volume = 0;
                                        if (additionalData != null) {
                                            geometryInfo.setAttribute(
                                                    GeometryPackage.eINSTANCE.getGeometryInfo_AdditionalData(),
                                                    additionalData.toString());
                                            if (additionalData.has("SURFACE_AREA_ALONG_Z")) {
                                                geometryInfo.setAttribute(
                                                        GeometryPackage.eINSTANCE.getGeometryInfo_Area(),
                                                        additionalData.get("SURFACE_AREA_ALONG_Z").asDouble());
                                            }
                                            if (additionalData.has("TOTAL_SHAPE_VOLUME")) {
                                                volume = additionalData.get("TOTAL_SHAPE_VOLUME").asDouble();
                                                geometryInfo.setAttribute(
                                                        GeometryPackage.eINSTANCE.getGeometryInfo_Volume(),
                                                        volume);
                                            }
                                        }

                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_PrimitiveCount(),
                                                masterGeometryData.getNrPrimitives());

                                        job.getReport()
                                                .incrementTriangles(masterGeometryData.getNrPrimitives());

                                        this.streamingGeometryGenerator.bytesSavedByMapping
                                                .addAndGet(masterGeometryData.getSize());
                                        this.streamingGeometryGenerator.totalBytes
                                                .addAndGet(masterGeometryData.getSize());

                                        // First, invert the master's mapping matrix
                                        double[] inverted = Matrix.identity();
                                        if (!Matrix.invertM(inverted, 0, masterProductDef.getMappingMatrix(),
                                                0)) {
                                            LOGGER.info(
                                                    "No inverse, this should not be able to happen at this time, please report");
                                            continue;
                                        }

                                        double[] finalMatrix = Matrix.identity();
                                        double[] totalTranformationMatrix = Matrix.identity();
                                        // Apply the mapping matrix of the product
                                        Matrix.multiplyMM(finalMatrix, 0, productDef.getMappingMatrix(), 0,
                                                inverted, 0);
                                        // Apply the product matrix of the product
                                        Matrix.multiplyMM(totalTranformationMatrix, 0,
                                                productDef.getProductMatrix(), 0, finalMatrix, 0);

                                        if (geometryGenerationDebugger != null) {
                                            //                                    if (debuggingInfo.containsKey(ifcProduct.getOid())) {
                                            //                                       DebuggingInfo debuggingInfo2 = debuggingInfo.get(ifcProduct.getOid());
                                            //                                       DebuggingInfo debuggingInfo3 = debuggingInfo.get(productDef.getMasterOid());
                                            //                                       
                                            //                                       if (debuggingInfo2.getIndices().length != debuggingInfo3.getIndices().length) {
                                            //                                          LOGGER.error("Different sizes for indices, weird...");
                                            //                                          LOGGER.error(ifcProduct.getOid() + " / " + productDef.getMasterOid());
                                            //                                       } else {
                                            //                                          for (int i=0; i<debuggingInfo2.getIndices().length; i++) {
                                            //                                             int index = debuggingInfo2.getIndices()[i];
                                            //                                             float[] vertex = new float[]{debuggingInfo2.getVertices()[index * 3], debuggingInfo2.getVertices()[index * 3 + 1], debuggingInfo2.getVertices()[index * 3 + 2], 1};
                                            //                                             float[] transformedOriginal = new float[4];
                                            //                                             Matrix.multiplyMV(transformedOriginal, 0, debuggingInfo2.getProductTranformationMatrix(), 0, vertex, 0);
                                            //                                             float[] transformedNew = new float[4];
                                            //                                             int index2 = debuggingInfo3.getIndices()[i];
                                            //                                             float[] vertex2 = new float[]{debuggingInfo3.getVertices()[index2 * 3], debuggingInfo3.getVertices()[index2 * 3 + 1], debuggingInfo3.getVertices()[index2 * 3 + 2], 1};
                                            //                                             Matrix.multiplyMV(transformedNew, 0, totalTranformationMatrix, 0, vertex2, 0);
                                            //                                             
                                            //                                             // TODO margin should depend on bb of complete model
                                            //                                             if (!almostTheSame((String)ifcProduct.get("GlobalId"), transformedNew, transformedOriginal, 0.05F)) {
                                            //                                                geometryGenerationDebugger.transformedVertexNotMatching(ifcProduct, transformedOriginal, transformedNew, debuggingInfo2.getProductTranformationMatrix(), totalTranformationMatrix);
                                            //                                             }
                                            //                                          }
                                            //                                       }

                                            //                                    almostTheSame((String)ifcProduct.get("GlobalId"), debuggingInfo2.getProductTranformationMatrix(), totalTranformationMatrix, 0.01D);
                                            //                                    }
                                        }

                                        IntBuffer indices = masterGeometryData.getIndices();
                                        for (int i = 0; i < indices.capacity(); i++) {
                                            this.streamingGeometryGenerator.processExtends(minBounds, maxBounds,
                                                    totalTranformationMatrix, masterGeometryData.getVertices(),
                                                    indices.get(i) * 3, generateGeometryResult);
                                        }

                                        HashMapWrappedVirtualObject boundsUntransformedMm = createMmBounds(
                                                geometryInfo, boundsUntransformed,
                                                generateGeometryResult.getMultiplierToMm());
                                        geometryInfo.set("boundsUntransformedMm", boundsUntransformedMm);
                                        HashMapWrappedVirtualObject boundsMm = createMmBounds(geometryInfo,
                                                bounds, generateGeometryResult.getMultiplierToMm());
                                        geometryInfo.set("boundsMm", boundsMm);

                                        float nrTriangles = masterGeometryData.getNrPrimitives();

                                        Density density = new Density(eClass.getName(), (float) volume,
                                                getBiggestFaceFromBounds(boundsUntransformedMm),
                                                (long) nrTriangles, geometryInfo.getOid());

                                        geometryInfo.setAttribute(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_Density(),
                                                density.getDensityValue());

                                        generateGeometryResult.addDensity(density);

                                        HashMapVirtualObject referencedData = databaseSession
                                                .getFromCache(masterGeometryData.getOid());
                                        Integer currentValue = (Integer) referencedData.get("reused");
                                        referencedData.set("reused", currentValue + 1);
                                        HashMapWrappedVirtualObject dataBounds = (HashMapWrappedVirtualObject) referencedData
                                                .get("boundsMm");
                                        extendBounds(boundsMm, dataBounds);

                                        // TODO this keeping track of the amount of reuse, takes it's toll on memory usage. Basically all geometry ends up in memory by the time the Geometry generation is done
                                        // We should try to see whether we can use BDB's mechanism to do partial retrievals/updates of a records here, because we only need to update just one value
                                        // Another, simpler option would be to introduce another layer between GeometryInfo and GeometryData, so we don't have to cache the actual data (vertices etc... the bulk)
                                        // In that case however the BinarySerializer would increase in complexity

                                        // This seems to have been partially solved now since GeometryData does not contain the bulk of the data anymore (the byte[]s are now in "Buffer").

                                        referencedData.saveOverwrite();
                                        geometryInfo.setReference(
                                                GeometryPackage.eINSTANCE.getGeometryInfo_Data(),
                                                masterGeometryData.getOid(), 0);

                                        // for (int i = 0; i <
                                        // indices.length; i++) {
                                        // processExtends(geometryInfo,
                                        // productTranformationMatrix,
                                        // vertices, indices[i] * 3,
                                        // generateGeometryResult);
                                        // processExtendsUntranslated(geometryInfo,
                                        // vertices, indices[i] * 3,
                                        // generateGeometryResult);
                                        // }

                                        // calculateObb(geometryInfo,
                                        // productTranformationMatrix,
                                        // indices, vertices,
                                        // generateGeometryResult);
                                        this.streamingGeometryGenerator.setTransformationMatrix(geometryInfo,
                                                totalTranformationMatrix);

                                        geometryInfo.save();
                                        // totalBytes.addAndGet(size);

                                        ifcProduct.setReference(this.streamingGeometryGenerator.geometryFeature,
                                                geometryInfo.getOid(), 0);
                                        ifcProduct.saveOverwrite();
                                    }
                                }
                            }
                        }
                    }
                }
            } finally {
                if (renderEngine != null) {
                    renderEnginePool.returnObject(renderEngine);
                }
                try {
                    if (!notFoundObjects.isEmpty()) {
                        writeDebugFile(bytes, false, notFoundObjects);
                        StringBuilder sb = new StringBuilder();
                        for (Integer key : notFoundObjects.keySet()) {
                            sb.append(key + " (" + notFoundObjects.get(key).getOid() + ")");
                            sb.append(", ");
                        }
                        sb.delete(sb.length() - 2, sb.length());
                        job.setException(new Exception("Missing objects in model (" + sb.toString() + ")"));
                    } else if (writeOutputFiles) {
                        writeDebugFile(bytes, false, null);
                    }
                    in.close();
                } catch (Throwable e) {

                } finally {

                }
                this.streamingGeometryGenerator.jobsDone.incrementAndGet();
                this.streamingGeometryGenerator.updateProgress();
            }
        } catch (Exception e) {
            StreamingGeometryGenerator.LOGGER.error("", e);
            writeDebugFile(bytes, true, null);
            job.setException(e);
            // LOGGER.error("Original query: " + originalQuery, e);
        }
    } catch (Exception e) {
        StreamingGeometryGenerator.LOGGER.error("", e);
        // LOGGER.error("Original query: " + originalQuery, e);
    }
    long end = System.nanoTime();
    job.setEndNanos(end);
}