Search in sources :

Example 1 with TemporaryGeometryData

use of org.bimserver.TemporaryGeometryData in project BIMserver by opensourceBIM.

the class GeometryRunner method run.

@Override
public void run() {
    Thread.currentThread().setName("GeometryRunner");
    long start = System.nanoTime();
    job.setStartNanos(start);
    // For all objects "hitchhiking" on this GeometryRunner, we also want to couple them to the job
    if (map != null) {
        for (long oid : map.keySet()) {
            if (map.get(oid).getMasterOid() != oid) {
                try {
                    job.addObject(oid, databaseSession.getEClassForOid(oid).getName());
                } catch (BimserverDatabaseException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    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())) {
                for (QueryPart qp : originalQuery.getQueryParts()) {
                    if (qp.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) {
                            for (QueryPart qp : originalQuery.getQueryParts()) {
                                if (qp.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<Long, 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, Long> oidToEid = oidConvertingSerializer.getOidToEid();
                        Map<Long, DebuggingInfo> debuggingInfo = new HashMap<>();
                        for (HashMapVirtualObject ifcProduct : objects) {
                            if (!this.streamingGeometryGenerator.running) {
                                return;
                            }
                            Long expressId = oidToEid.get(ifcProduct.getOid());
                            try {
                                RenderEngineInstance renderEngineInstance = renderEngineModel.getInstanceFromExpressId(expressId);
                                RenderEngineGeometry geometry = renderEngineInstance.generateGeometry();
                                boolean translate = true;
                                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_IfcProductUuid(), UuidUtils.toByteArray(ifcProduct.getUuid()));
                                    geometryInfo.setAttribute(GeometryPackage.eINSTANCE.getGeometryInfo_IfcProductRid(), ifcProduct.getRid());
                                    geometryInfo.setReference(GeometryPackage.eINSTANCE.getGeometryInfo_Bounds(), bounds);
                                    bounds.setReference(GeometryPackage.eINSTANCE.getBounds_Min(), minBounds);
                                    bounds.setReference(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.setReference(GeometryPackage.eINSTANCE.getBounds_Min(), minBoundsUntranslated);
                                    boundsUntransformed.setReference(GeometryPackage.eINSTANCE.getBounds_Max(), maxBoundsUntranslated);
                                    geometryInfo.setReference(GeometryPackage.eINSTANCE.getGeometryInfo_BoundsUntransformed(), boundsUntransformed);
                                    double volume = 0;
                                    volume = setCalculatedQuantities(renderEngineInstance, geometryInfo, volume);
                                    HashMapVirtualObject geometryData = new HashMapVirtualObject(queryContext, GeometryPackage.eINSTANCE.getGeometryData());
                                    geometryData.set("type", databaseSession.getCid(eClass));
                                    ByteBuffer indices = geometry.getIndices();
                                    ByteBuffer vertices = geometry.getVertices();
                                    ByteBuffer normals = geometry.getNormals();
                                    ByteBuffer colorByteBuffer = geometry.getMaterialIndices();
                                    IntBuffer indicesAsInt = indices.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
                                    DoubleBuffer verticesAsDouble = vertices.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
                                    FloatBuffer normalsAsFloat = normals.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
                                    IntBuffer materialIndices = colorByteBuffer.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
                                    if (detectTwoFaceTriangles(ifcProduct, indicesAsInt, verticesAsDouble, 0.001f)) {
                                        BufferSet bufferSet = appendInvertedGeometry(indicesAsInt, verticesAsDouble, normalsAsFloat, materialIndices);
                                        indices = bufferSet.getIndicesByteBuffer();
                                        vertices = bufferSet.getVerticesByteBuffer();
                                        normals = bufferSet.getNormalsByteBuffer();
                                        colorByteBuffer = bufferSet.getColorsByteBuffer();
                                        indicesAsInt = indices.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
                                        verticesAsDouble = vertices.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
                                        normalsAsFloat = normals.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
                                        materialIndices = colorByteBuffer.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
                                    }
                                    geometryData.setAttribute(GeometryPackage.eINSTANCE.getGeometryData_Reused(), 1);
                                    geometryData.setReference(GeometryPackage.eINSTANCE.getGeometryData_Indices(), createBuffer(queryContext, indices));
                                    geometryData.setReference(GeometryPackage.eINSTANCE.getGeometryData_Vertices(), createBuffer(queryContext, vertices));
                                    geometryData.setReference(GeometryPackage.eINSTANCE.getGeometryData_Normals(), createBuffer(queryContext, normals));
                                    geometryData.set("nrIndices", indicesAsInt.capacity());
                                    geometryData.set("nrVertices", verticesAsDouble.capacity());
                                    geometryData.set("nrNormals", normalsAsFloat.capacity());
                                    ByteBuffer lineIndices = generateLineRendering(ifcProduct, indicesAsInt, verticesAsDouble, normalsAsFloat, 0.001f);
                                    geometryData.set("nrLineIndices", lineIndices.capacity() / 4);
                                    geometryData.setReference(GeometryPackage.eINSTANCE.getGeometryData_LineIndices(), createBuffer(queryContext, lineIndices));
                                    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]);
                                    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);
                                                }
                                                if (color.isBlack()) {
                                                    continue;
                                                }
                                                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.setAttribute(GeometryPackage.eINSTANCE.getColorPack_Data(), colorMap2.toByteArray());
                                            colorPack.save();
                                            geometryData.setReference(GeometryPackage.eINSTANCE.getGeometryData_ColorPack(), colorPack.getOid(), 0);
                                        }
                                        if (colorMap.usedColors() == 0) {
                                            if (eClass.getName().contentEquals("IfcWindow") || eClass.getName().contentEquals("IfcOpeningElement") || eClass.getName().contentEquals("IfcSpace")) {
                                                // To make sure the viewer will but this object in the right buffer (transparent), we override the transparency here
                                                // This only happens for objects with no color, maybe there are more types that are usually transparent?
                                                colorMap.setHasTransparency(true);
                                            // } else {
                                            // LOGGER.info(ifcProduct.eClass().getName());
                                            }
                                        } 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.setReference(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.setReference(GeometryPackage.eINSTANCE.getGeometryData_MostUsedColor(), color);
                                        }
                                        if (hasMaterial) {
                                            geometryData.set("nrColors", colors.capacity());
                                            geometryData.setReference(GeometryPackage.eINSTANCE.getGeometryData_ColorsQuantized(), createBuffer(queryContext, colors), -1);
                                        } 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.setReference(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.setReference(GeometryPackage.eINSTANCE.getBounds_Min(), geometryDataBoundsMin);
                                    geometryDataBounds.setReference(GeometryPackage.eINSTANCE.getBounds_Max(), geometryDataBoundsMax);
                                    geometryData.setReference(GeometryPackage.eINSTANCE.getGeometryData_BoundsMm(), geometryDataBounds);
                                    if (volume == 0) {
                                        volume = getVolumeFromBounds(boundsUntransformed);
                                    }
                                    float nrTriangles = indicesAsInt.capacity() / 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;
                                            // }
                                            if (!found) {
                                                range.setGeometryDataOid(geometryData.getOid());
                                                reusableGeometryData.add(range);
                                                volume = setCalculatedQuantities(renderEngineInstance, geometryInfo, volume);
                                                geometryInfo.setAttribute(GeometryPackage.eINSTANCE.getGeometryInfo_PrimitiveCount(), indicesAsInt.capacity() / 3);
                                                productToData.put(ifcProduct.getOid(), new TemporaryGeometryData(geometryData.getOid(), renderEngineInstance.getAdditionalData(), 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
                                            // TODO Why??
                                            geometryData.save();
                                            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");
                                // }
                                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.setReference(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());
                                        geometryInfo.setAttribute(GeometryPackage.eINSTANCE.getGeometryInfo_IfcProductUuid(), UuidUtils.toByteArray(ifcProduct.getUuid()));
                                        geometryInfo.setAttribute(GeometryPackage.eINSTANCE.getGeometryInfo_IfcProductRid(), ifcProduct.getRid());
                                        boundsUntransformed.setReference(GeometryPackage.eINSTANCE.getBounds_Min(), minBoundsUntransformed);
                                        boundsUntransformed.setReference(GeometryPackage.eINSTANCE.getBounds_Max(), maxBoundsUntransformed);
                                        geometryInfo.setReference(GeometryPackage.eINSTANCE.getGeometryInfo_BoundsUntransformed(), boundsUntransformed);
                                        double volume = 0;
                                        if (streamingGeometryGenerator.isCalculateQuantities()) {
                                            ObjectNode additionalData = masterGeometryData.getAdditionalData();
                                            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);
                                                }
                                            }
                                        }
                                        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) {
                    Metrics metrics = renderEngine.getMetrics();
                    if (metrics != null) {
                        job.setCpuTimeMs(metrics.getCpuTimeMs());
                        job.setMaxMemoryBytes(metrics.getMaxMemoryBytes());
                    }
                    renderEnginePool.returnObject(renderEngine);
                }
                try {
                    if (!notFoundObjects.isEmpty()) {
                        writeDebugFile(bytes, false, notFoundObjects);
                        StringBuilder sb = new StringBuilder();
                        for (Long 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);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Query(org.bimserver.database.queries.om.Query) HashMapWrappedVirtualObject(org.bimserver.shared.HashMapWrappedVirtualObject) HashMap(java.util.HashMap) QueryPart(org.bimserver.database.queries.om.QueryPart) FloatBuffer(java.nio.FloatBuffer) RenderEngineGeometry(org.bimserver.plugins.renderengine.RenderEngineGeometry) RenderEngineModel(org.bimserver.plugins.renderengine.RenderEngineModel) Metrics(org.bimserver.plugins.renderengine.Metrics) QueryObjectProvider(org.bimserver.database.queries.QueryObjectProvider) RenderEngineException(org.bimserver.plugins.renderengine.RenderEngineException) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) DoubleBuffer(java.nio.DoubleBuffer) OidConvertingSerializer(org.bimserver.plugins.serializers.OidConvertingSerializer) StreamingSerializer(org.bimserver.plugins.serializers.StreamingSerializer) EntityNotFoundException(org.bimserver.plugins.renderengine.EntityNotFoundException) Range(org.bimserver.Range) HashMapVirtualObject(org.bimserver.shared.HashMapVirtualObject) ByteArrayInputStream(java.io.ByteArrayInputStream) IntBuffer(java.nio.IntBuffer) BimserverDatabaseException(org.bimserver.BimserverDatabaseException) ObjectListener(org.bimserver.ObjectListener) PluginConfiguration(org.bimserver.plugins.PluginConfiguration) RenderEngine(org.bimserver.plugins.renderengine.RenderEngine) TemporaryGeometryData(org.bimserver.TemporaryGeometryData) HashMapWrappedVirtualObject(org.bimserver.shared.HashMapWrappedVirtualObject) WrappedVirtualObject(org.bimserver.shared.WrappedVirtualObject) Color4f(org.bimserver.Color4f) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ObjectProviderProxy(org.bimserver.ObjectProviderProxy) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ByteBuffer(java.nio.ByteBuffer) FileNotFoundException(java.io.FileNotFoundException) GeometryGeneratingException(org.bimserver.GeometryGeneratingException) EntityNotFoundException(org.bimserver.plugins.renderengine.EntityNotFoundException) IOException(java.io.IOException) BimserverDatabaseException(org.bimserver.BimserverDatabaseException) RenderEngineException(org.bimserver.plugins.renderengine.RenderEngineException) RenderEngineInstance(org.bimserver.plugins.renderengine.RenderEngineInstance) ProductDef(org.bimserver.ProductDef)

Aggregations

ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 FileNotFoundException (java.io.FileNotFoundException)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 ByteBuffer (java.nio.ByteBuffer)1 DoubleBuffer (java.nio.DoubleBuffer)1 FloatBuffer (java.nio.FloatBuffer)1 IntBuffer (java.nio.IntBuffer)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1 BimserverDatabaseException (org.bimserver.BimserverDatabaseException)1 Color4f (org.bimserver.Color4f)1 GeometryGeneratingException (org.bimserver.GeometryGeneratingException)1 ObjectListener (org.bimserver.ObjectListener)1 ObjectProviderProxy (org.bimserver.ObjectProviderProxy)1 ProductDef (org.bimserver.ProductDef)1 Range (org.bimserver.Range)1