use of org.bimserver.shared.HashMapVirtualObject in project BIMserver by opensourceBIM.
the class SetReferenceChange method execute.
@Override
public void execute(Transaction transaction) throws UserException, BimserverLockConflictException, BimserverDatabaseException, IOException, QueryException {
PackageMetaData packageMetaData = transaction.getDatabaseSession().getMetaDataManager().getPackageMetaData(transaction.getProject().getSchema());
HashMapVirtualObject object = transaction.get(oid);
if (object == null) {
Query query = new Query(packageMetaData);
QueryPart queryPart = query.createQueryPart();
queryPart.addOid(oid);
QueryObjectProvider queryObjectProvider = new QueryObjectProvider(transaction.getDatabaseSession(), transaction.getBimServer(), query, Collections.singleton(transaction.getPreviousRevision().getOid()), packageMetaData);
object = queryObjectProvider.next();
transaction.updated(object);
}
EClass eClass = transaction.getDatabaseSession().getEClassForOid(oid);
if (!ChangeHelper.canBeChanged(eClass)) {
throw new UserException("Only objects from the following schemas are allowed to be changed: Ifc2x3tc1 and IFC4, this object (" + eClass.getName() + ") is from the \"" + eClass.getEPackage().getName() + "\" package");
}
if (object == null) {
throw new UserException("No object of type \"" + eClass.getName() + "\" with oid " + oid + " found in project with pid " + transaction.getProject().getId());
}
EReference eReference = packageMetaData.getEReference(eClass.getName(), referenceName);
if (eReference == null) {
throw new UserException("No reference with the name \"" + referenceName + "\" found in class \"" + eClass.getName() + "\"");
}
if (eReference.isMany()) {
throw new UserException("Reference " + referenceName + " is not of type 'single'");
}
object.setReference(eReference, referenceOid, 0);
EClass eClassForOid = transaction.getDatabaseSession().getEClassForOid(referenceOid);
EReference inverseOrOpposite = packageMetaData.getInverseOrOpposite(eClassForOid, eReference);
if (inverseOrOpposite != null) {
HashMapVirtualObject referencedObject = transaction.get(referenceOid);
if (referencedObject == null) {
Query query = new Query(packageMetaData);
QueryPart queryPart = query.createQueryPart();
queryPart.addOid(referenceOid);
QueryObjectProvider queryObjectProvider = new QueryObjectProvider(transaction.getDatabaseSession(), transaction.getBimServer(), query, Collections.singleton(transaction.getPreviousRevision().getOid()), packageMetaData);
referencedObject = queryObjectProvider.next();
}
if (inverseOrOpposite.isMany()) {
referencedObject.addReference(inverseOrOpposite, eClassForOid, oid);
} else {
referencedObject.setReference(inverseOrOpposite, oid);
}
transaction.updated(referencedObject);
}
}
use of org.bimserver.shared.HashMapVirtualObject in project BIMserver by opensourceBIM.
the class StreamingGeometryGenerator method generateGeometry.
@SuppressWarnings("unchecked")
public GenerateGeometryResult generateGeometry(long uoid, final DatabaseSession databaseSession, QueryContext queryContext, long nrObjects) throws BimserverDatabaseException, GeometryGeneratingException {
GenerateGeometryResult generateGeometryResult = new GenerateGeometryResult();
packageMetaData = queryContext.getPackageMetaData();
productClass = packageMetaData.getEClass("IfcProduct");
geometryFeature = (EReference) productClass.getEStructuralFeature("geometry");
representationFeature = productClass.getEStructuralFeature("Representation");
representationsFeature = packageMetaData.getEClass("IfcProductDefinitionShape").getEStructuralFeature("Representations");
itemsFeature = packageMetaData.getEClass("IfcShapeRepresentation").getEStructuralFeature("Items");
mappingSourceFeature = packageMetaData.getEClass("IfcMappedItem").getEStructuralFeature("MappingSource");
GregorianCalendar now = new GregorianCalendar();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
debugIdentifier = dateFormat.format(now.getTime()) + " (" + report.getOriginalIfcFileName() + ")";
long start = System.nanoTime();
String pluginName = "";
if (queryContext.getPackageMetaData().getSchema() == Schema.IFC4) {
pluginName = "org.bimserver.ifc.step.serializer.Ifc4StepStreamingSerializerPlugin";
} else if (queryContext.getPackageMetaData().getSchema() == Schema.IFC2X3TC1) {
pluginName = "org.bimserver.ifc.step.serializer.Ifc2x3tc1StepStreamingSerializerPlugin";
} else {
throw new GeometryGeneratingException("Unknown schema " + queryContext.getPackageMetaData().getSchema());
}
reuseGeometry = bimServer.getServerSettingsCache().getServerSettings().isReuseGeometry();
optimizeMappedItems = bimServer.getServerSettingsCache().getServerSettings().isOptimizeMappedItems();
report.setStart(new GregorianCalendar());
report.setIfcSchema(queryContext.getPackageMetaData().getSchema());
report.setUseMappingOptimization(optimizeMappedItems);
report.setReuseGeometry(reuseGeometry);
try {
final StreamingSerializerPlugin ifcSerializerPlugin = (StreamingSerializerPlugin) bimServer.getPluginManager().getPlugin(pluginName, true);
if (ifcSerializerPlugin == null) {
throw new UserException("No IFC serializer found");
}
User user = (User) databaseSession.get(uoid, org.bimserver.database.OldQuery.getDefault());
UserSettings userSettings = user.getUserSettings();
report.setUserName(user.getName());
report.setUserUserName(user.getUsername());
RenderEnginePluginConfiguration renderEngine = null;
if (eoid != -1) {
renderEngine = databaseSession.get(eoid, OldQuery.getDefault());
} else {
renderEngine = userSettings.getDefaultRenderEngine();
}
if (renderEngine == null) {
throw new UserException("No default render engine has been selected for this user");
}
renderEngineName = renderEngine.getName();
int availableProcessors = Runtime.getRuntime().availableProcessors();
report.setAvailableProcessors(availableProcessors);
int maxSimultanousThreads = Math.min(bimServer.getServerSettingsCache().getServerSettings().getRenderEngineProcesses(), availableProcessors);
if (maxSimultanousThreads < 1) {
maxSimultanousThreads = 1;
}
final RenderEngineSettings settings = new RenderEngineSettings();
settings.setPrecision(Precision.SINGLE);
settings.setIndexFormat(IndexFormat.AUTO_DETECT);
settings.setGenerateNormals(true);
settings.setGenerateTriangles(true);
settings.setGenerateWireFrame(false);
final RenderEngineFilter renderEngineFilter = new RenderEngineFilter();
RenderEnginePool renderEnginePool = bimServer.getRenderEnginePools().getRenderEnginePool(packageMetaData.getSchema(), renderEngine.getPluginDescriptor().getPluginClassName(), bimServer.getPluginSettingsCache().getPluginSettings(renderEngine.getOid()));
report.setRenderEngineName(renderEngine.getName());
report.setRenderEnginePluginVersion(renderEngine.getPluginDescriptor().getPluginBundleVersion().getVersion());
VersionInfo versionInfo = renderEnginePool.getRenderEngineFactory().getVersionInfo();
report.setRenderEngineVersion(versionInfo);
// TODO there must be a cleaner way of getting this info, since it's in the database...
RenderEngine engine = renderEnginePool.borrowObject();
try {
applyLayerSets = engine.isApplyLayerSets();
report.setApplyLayersets(applyLayerSets);
calculateQuantities = engine.isCalculateQuantities();
report.setCalculateQuantities(calculateQuantities);
} finally {
renderEnginePool.returnObject(engine);
}
// TODO reuse, pool the pools :) Or something smarter
// TODO reuse queue, or try to determine a realistic size, or don't use a fixed-size queue
ThreadPoolExecutor executor = new ThreadPoolExecutor(maxSimultanousThreads, maxSimultanousThreads, 24, TimeUnit.HOURS, new ArrayBlockingQueue<Runnable>(10000000));
JsonQueryObjectModelConverter jsonQueryObjectModelConverter = new JsonQueryObjectModelConverter(packageMetaData);
String queryNameSpace = packageMetaData.getSchema().name().toLowerCase() + "-stdlib";
// All references should already be direct, since this is now done in BimServer on startup, quite the hack...
Include objectPlacement = jsonQueryObjectModelConverter.getDefineFromFile(queryNameSpace + ":ObjectPlacement", true);
Set<EClass> classes = null;
if (queryContext.getOidCounters() != null) {
classes = queryContext.getOidCounters().keySet();
} else {
classes = packageMetaData.getEClasses();
}
float multiplierToMm = processUnits(databaseSession, queryContext);
generateGeometryResult.setMultiplierToMm(multiplierToMm);
// Phase 1 (mapped item detection) sometimes detects that mapped items have invalid (unsupported) RepresentationIdentifier values, this set keeps track of objects to skip in Phase 2 because of that
Set<Long> toSkip = new HashSet<>();
// Less than 100 objects -> Use 1 object per process (so we have progress indication per 1%)
// More than 100 objects -> Use # objects / 100 objects per process
// Unless the amount of objects becomes > 100 / process, than cap it on 100
int regularObjectCount = 0;
Set<EClass> typesToDo = new HashSet<>();
Set<Long> done = new HashSet<>();
for (EClass eClass : classes) {
if (packageMetaData.getEClass("IfcProduct").isSuperTypeOf(eClass)) {
Query query2 = new Query(eClass.getName() + "Main query", packageMetaData);
QueryPart queryPart2 = query2.createQueryPart();
queryPart2.addType(eClass, false);
Include representationInclude = queryPart2.createInclude();
representationInclude.addType(eClass, false);
representationInclude.addFieldDirect("Representation");
Include representationsInclude = representationInclude.createInclude();
representationsInclude.addType(packageMetaData.getEClass("IfcProductRepresentation"), true);
representationsInclude.addFieldDirect("Representations");
Include itemsInclude = representationsInclude.createInclude();
itemsInclude.addType(packageMetaData.getEClass("IfcShapeRepresentation"), false);
itemsInclude.addFieldDirect("Items");
itemsInclude.addFieldDirect("ContextOfItems");
Include mappingSourceInclude = itemsInclude.createInclude();
mappingSourceInclude.addType(packageMetaData.getEClass("IfcMappedItem"), false);
mappingSourceInclude.addFieldDirect("MappingSource");
mappingSourceInclude.addFieldDirect("MappingTarget");
Include representationMap = mappingSourceInclude.createInclude();
representationMap.addType(packageMetaData.getEClass("IfcRepresentationMap"), false);
representationMap.addFieldDirect("MappedRepresentation");
Include createInclude = representationMap.createInclude();
createInclude.addType(packageMetaData.getEClass("IfcShapeRepresentation"), true);
Include targetInclude = mappingSourceInclude.createInclude();
targetInclude.addType(packageMetaData.getEClass("IfcCartesianTransformationOperator3D"), false);
targetInclude.addFieldDirect("Axis1");
targetInclude.addFieldDirect("Axis2");
targetInclude.addFieldDirect("Axis3");
targetInclude.addFieldDirect("LocalOrigin");
queryPart2.addInclude(objectPlacement);
Map<Long, Map<Long, ProductDef>> representationMapToProduct = new HashMap<>();
QueryObjectProvider queryObjectProvider2 = new QueryObjectProvider(databaseSession, bimServer, query2, Collections.singleton(queryContext.getRoid()), packageMetaData);
HashMapVirtualObject next = queryObjectProvider2.next();
while (next != null) {
if (next.eClass() == eClass) {
AbstractHashMapVirtualObject representation = next.getDirectFeature(representationFeature);
if (representation != null) {
Set<HashMapVirtualObject> representations = representation.getDirectListFeature(representationsFeature);
if (representations != null) {
boolean foundValidContext = false;
for (HashMapVirtualObject representationItem : representations) {
if (usableContext(representationItem)) {
foundValidContext = true;
break;
}
}
boolean stop = false;
Set<String> counts = new HashSet<>();
for (HashMapVirtualObject representationItem : representations) {
String representationIdentifier = (String) representationItem.get("RepresentationIdentifier");
if (counts.contains(representationIdentifier)) {
stop = true;
} else {
counts.add(representationIdentifier);
}
}
if (stop) {
next = queryObjectProvider2.next();
continue;
}
for (HashMapVirtualObject representationItem : representations) {
if (!usableContext(representationItem) && foundValidContext) {
continue;
}
if (hasValidRepresentationIdentifier(representationItem)) {
Set<HashMapVirtualObject> items = representationItem.getDirectListFeature(itemsFeature);
if (items == null || items.size() > 1) {
// Only if there is just one item, we'll store this for reuse
// TODO actually we could store them for > 1 as well, only they should only be used (2nd stage) for products that use the exact same items, for now
regularObjectCount++;
continue;
}
// So this next loop always results in 1 (or no) loops
for (HashMapVirtualObject item : items) {
report.addRepresentationItem(item.eClass().getName());
if (!packageMetaData.getEClass("IfcMappedItem").isSuperTypeOf(item.eClass())) {
regularObjectCount++;
// All non IfcMappedItem objects will be done in phase 2
continue;
}
AbstractHashMapVirtualObject mappingTarget = item.getDirectFeature(packageMetaData.getEReference("IfcMappedItem", "MappingTarget"));
AbstractHashMapVirtualObject mappingSourceOfMappedItem = item.getDirectFeature(packageMetaData.getEReference("IfcMappedItem", "MappingSource"));
if (mappingSourceOfMappedItem == null) {
LOGGER.info("No mapping source");
continue;
}
AbstractHashMapVirtualObject mappedRepresentation = mappingSourceOfMappedItem.getDirectFeature(packageMetaData.getEReference("IfcRepresentationMap", "MappedRepresentation"));
if (!hasValidRepresentationIdentifier(mappedRepresentation)) {
// Skip this mapping, we should store somewhere that this object should also be skipped in the normal way
String identifier = (String) mappedRepresentation.get("RepresentationIdentifier");
report.addSkippedBecauseOfInvalidRepresentationIdentifier(identifier);
toSkip.add(next.getOid());
continue;
}
double[] mappingMatrix = Matrix.identity();
double[] productMatrix = Matrix.identity();
if (mappingTarget != null) {
AbstractHashMapVirtualObject axis1 = mappingTarget.getDirectFeature(packageMetaData.getEReference("IfcCartesianTransformationOperator", "Axis1"));
AbstractHashMapVirtualObject axis2 = mappingTarget.getDirectFeature(packageMetaData.getEReference("IfcCartesianTransformationOperator", "Axis2"));
AbstractHashMapVirtualObject axis3 = mappingTarget.getDirectFeature(packageMetaData.getEReference("IfcCartesianTransformationOperator3D", "Axis3"));
AbstractHashMapVirtualObject localOrigin = mappingTarget.getDirectFeature(packageMetaData.getEReference("IfcCartesianTransformationOperator", "LocalOrigin"));
double[] a1 = null;
double[] a2 = null;
double[] a3 = null;
if (axis3 != null) {
List<Double> list = (List<Double>) axis3.get("DirectionRatios");
a3 = new double[] { list.get(0), list.get(1), list.get(2) };
Vector.normalize(a3);
} else {
a3 = new double[] { 0, 0, 1 };
}
if (axis1 != null) {
List<Double> list = (List<Double>) axis1.get("DirectionRatios");
a1 = new double[] { list.get(0), list.get(1), list.get(2) };
Vector.normalize(a1);
} else {
if (a3[0] == 1 && a3[1] == 0 && a3[2] == 0) {
a1 = new double[] { 0, 1, 0 };
} else {
a1 = new double[] { 1, 0, 0 };
}
}
double[] xVec = Vector.scalarProduct(Vector.dot(a1, a3), a3);
double[] xAxis = Vector.subtract(a1, xVec);
Vector.normalize(xAxis);
if (axis2 != null) {
List<Double> list = (List<Double>) axis2.get("DirectionRatios");
a2 = new double[] { list.get(0), list.get(1), list.get(2) };
Vector.normalize(a2);
} else {
a2 = new double[] { 0, 1, 0 };
}
double[] tmp = Vector.scalarProduct(Vector.dot(a2, a3), a3);
double[] yAxis = Vector.subtract(a2, tmp);
tmp = Vector.scalarProduct(Vector.dot(a2, xAxis), xAxis);
yAxis = Vector.subtract(yAxis, tmp);
Vector.normalize(yAxis);
a2 = yAxis;
a1 = xAxis;
List<Double> t = (List<Double>) localOrigin.get("Coordinates");
mappingMatrix = new double[] { a1[0], a1[1], a1[2], 0, a2[0], a2[1], a2[2], 0, a3[0], a3[1], a3[2], 0, t.get(0).doubleValue(), t.get(1).doubleValue(), t.get(2).doubleValue(), 1 };
}
AbstractHashMapVirtualObject placement = next.getDirectFeature(packageMetaData.getEReference("IfcProduct", "ObjectPlacement"));
if (placement != null) {
productMatrix = placementToMatrix(placement);
}
AbstractHashMapVirtualObject mappingSource = item.getDirectFeature(mappingSourceFeature);
if (mappingSource != null) {
Map<Long, ProductDef> map = representationMapToProduct.get(((HashMapVirtualObject) mappingSource).getOid());
if (map == null) {
map = new LinkedHashMap<>();
representationMapToProduct.put(((HashMapVirtualObject) mappingSource).getOid(), map);
}
ProductDef pd = new ProductDef(next.getOid());
pd.setMappedItemOid(item.getOid());
pd.setObject(next);
pd.setProductMatrix(productMatrix);
pd.setMappingMatrix(mappingMatrix);
pd.setRepresentationOid(representationItem.getOid());
map.put(next.getOid(), pd);
}
}
} else {
report.addSkippedBecauseOfInvalidRepresentationIdentifier((String) representationItem.get("RepresentationIdentifier"));
}
}
}
}
}
next = queryObjectProvider2.next();
}
for (Long repMapId : representationMapToProduct.keySet()) {
Map<Long, ProductDef> map = representationMapToProduct.get(repMapId);
// When there is more than one instance using this mapping
if (map.size() > 1) {
Query query = new Query("Reuse query " + eClass.getName(), packageMetaData);
query.setDoubleBuffer(true);
QueryPart queryPart = query.createQueryPart();
// QueryPart queryPart3 = query.createQueryPart();
queryPart.addType(eClass, false);
// queryPart3.addType(packageMetaData.getEClass("IfcMappedItem"), false);
long masterOid = map.values().iterator().next().getOid();
double[] inverted = Matrix.identity();
ProductDef masterProductDef = map.get(masterOid);
if (!Matrix.invertM(inverted, 0, masterProductDef.getMappingMatrix(), 0)) {
LOGGER.debug("No inverse, this mapping will be skipped and processed as normal");
// TODO we should however be able to squeeze out a little more reuse by finding another master...
continue;
}
Set<Long> representationOids = new HashSet<>();
for (ProductDef pd : map.values()) {
done.add(pd.getOid());
if (!optimizeMappedItems) {
queryPart.addOid(pd.getOid());
representationOids.add(pd.getRepresentationOid());
// In theory these should be fused together during querying
// queryPart3.addOid(pd.getMappedItemOid());
} else {
pd.setMasterOid(masterOid);
}
}
if (optimizeMappedItems) {
queryPart.addOid(masterOid);
representationOids.add(masterProductDef.getRepresentationOid());
}
LOGGER.debug("Running " + map.size() + " objects in one batch because of reused geometry " + (eClass.getName()));
// queryPart3.addInclude(jsonQueryObjectModelConverter.getDefineFromFile("ifc2x3tc1-stdlib:IfcMappedItem"));
processQuery(databaseSession, queryContext, generateGeometryResult, ifcSerializerPlugin, settings, renderEngineFilter, renderEnginePool, executor, eClass, query, queryPart, true, map, map.size(), representationOids);
}
}
typesToDo.add(eClass);
}
}
// LOGGER.info("Regular object count: " + regularObjectCount);
int maxObjectsPerFile = regularObjectCount / 100;
if (regularObjectCount < 100) {
maxObjectsPerFile = 1;
}
if (maxObjectsPerFile > 100) {
maxObjectsPerFile = 100;
}
// maxObjectsPerFile = 1;
report.setMaxPerFile(maxObjectsPerFile);
for (EClass eClass : typesToDo) {
Query query3 = new Query("Remaining " + eClass.getName(), packageMetaData);
QueryPart queryPart3 = query3.createQueryPart();
queryPart3.addType(eClass, false);
Include include3 = queryPart3.createInclude();
include3.addType(eClass, false);
include3.addFieldDirect("Representation");
Include rInclude = include3.createInclude();
rInclude.addType(packageMetaData.getEClass("IfcProductRepresentation"), true);
rInclude.addFieldDirect("Representations");
Include representationsInclude2 = rInclude.createInclude();
representationsInclude2.addType(packageMetaData.getEClass("IfcShapeModel"), true);
representationsInclude2.addFieldDirect("ContextOfItems");
Query query = new Query("Main " + eClass.getName(), packageMetaData);
query.setDoubleBuffer(true);
QueryPart queryPart = query.createQueryPart();
int written = 0;
QueryObjectProvider queryObjectProvider2 = new QueryObjectProvider(databaseSession, bimServer, query3, Collections.singleton(queryContext.getRoid()), packageMetaData);
HashMapVirtualObject next = queryObjectProvider2.next();
Set<Long> representationOids = new HashSet<>();
while (next != null) {
// Not sure why the duplicate code in the next 20 lines
if (next.eClass() == eClass && !done.contains(next.getOid()) && !toSkip.contains(next.getOid())) {
AbstractHashMapVirtualObject representation = next.getDirectFeature(representationFeature);
if (representation != null) {
Set<HashMapVirtualObject> list = representation.getDirectListFeature(packageMetaData.getEReference("IfcProductRepresentation", "Representations"));
Set<Long> goForIt = goForIt(list);
if (!goForIt.isEmpty()) {
if (next.eClass() == eClass && !done.contains(next.getOid())) {
representation = next.getDirectFeature(representationFeature);
if (representation != null) {
list = representation.getDirectListFeature(packageMetaData.getEReference("IfcProductRepresentation", "Representations"));
Set<Long> goForIt2 = goForIt(list);
if (!goForIt2.isEmpty()) {
queryPart.addOid(next.getOid());
representationOids.addAll(goForIt2);
written++;
if (written >= maxObjectsPerFile) {
processQuery(databaseSession, queryContext, generateGeometryResult, ifcSerializerPlugin, settings, renderEngineFilter, renderEnginePool, executor, eClass, query, queryPart, false, null, written, representationOids);
query = new Query("Main " + eClass.getName(), packageMetaData);
query.setDoubleBuffer(true);
queryPart = query.createQueryPart();
written = 0;
representationOids.clear();
}
}
}
}
}
}
}
next = queryObjectProvider2.next();
}
if (written > 0) {
processQuery(databaseSession, queryContext, generateGeometryResult, ifcSerializerPlugin, settings, renderEngineFilter, renderEnginePool, executor, eClass, query, queryPart, false, null, written, representationOids);
}
}
allJobsPushed = true;
executor.shutdown();
executor.awaitTermination(24, TimeUnit.HOURS);
// TODO, disable?
if (true) {
LOGGER.debug("Generating quantized vertices");
double[] quantizationMatrix = createQuantizationMatrixFromBounds(generateGeometryResult.getBoundsUntransformed(), multiplierToMm);
for (Long id : geometryDataMap.keySet()) {
Tuple<HashMapVirtualObject, ByteBuffer> tuple = geometryDataMap.get(id);
HashMapVirtualObject buffer = new HashMapVirtualObject(queryContext, GeometryPackage.eINSTANCE.getBuffer());
// Buffer buffer = databaseSession.create(Buffer.class);
buffer.set("data", quantizeVertices(tuple.getB().asDoubleBuffer(), quantizationMatrix, multiplierToMm).array());
// buffer.setData(quantizeVertices(tuple.getB(), quantizationMatrix, multiplierToMm).array());
// databaseSession.store(buffer);
buffer.save();
HashMapVirtualObject geometryData = tuple.getA();
geometryData.set("verticesQuantized", buffer.getOid());
int reused = (int) geometryData.eGet(GeometryPackage.eINSTANCE.getGeometryData_Reused());
int nrTriangles = (int) geometryData.eGet(GeometryPackage.eINSTANCE.getGeometryData_NrIndices()) / 3;
int saveableTriangles = Math.max(0, (reused - 1)) * nrTriangles;
geometryData.set("saveableTriangles", saveableTriangles);
// if (saveableTriangles > 0) {
// System.out.println("Saveable triangles: " + saveableTriangles);
// }
geometryData.saveOverwrite();
}
}
long end = System.nanoTime();
long total = totalBytes.get() - (bytesSavedByHash.get() + bytesSavedByTransformation.get() + bytesSavedByMapping.get());
LOGGER.info("Rendertime: " + Formatters.nanosToString(end - start) + ", " + "Reused (by hash): " + Formatters.bytesToString(bytesSavedByHash.get()) + ", Reused (by transformation): " + Formatters.bytesToString(bytesSavedByTransformation.get()) + ", Reused (by mapping): " + Formatters.bytesToString(bytesSavedByMapping.get()) + ", Total: " + Formatters.bytesToString(totalBytes.get()) + ", Final: " + Formatters.bytesToString(total));
if (report.getNumberOfDebugFiles() > 0) {
LOGGER.error("[" + report.getOriginalIfcFileName() + "] Number of erroneous files: " + report.getNumberOfDebugFiles());
}
SkippedBecauseOfInvalidRepresentation skipped = report.getSkippedBecauseOfInvalidRepresentationIdentifier();
if (skipped.hasImportant()) {
LOGGER.warn("[" + report.getOriginalIfcFileName() + "] Number of representations skipped:");
for (String identifier : skipped.getImportantSet()) {
LOGGER.warn("\t" + identifier + ": " + skipped.get(identifier));
}
}
String dump = geometryGenerationDebugger.dump();
if (dump != null) {
LOGGER.info(dump);
}
} catch (Exception e) {
running = false;
LOGGER.error("", e);
report.setEnd(new GregorianCalendar());
throw new GeometryGeneratingException(e);
}
report.setEnd(new GregorianCalendar());
try {
if (report.getNumberOfDebugFiles() > 0) {
writeDebugFile();
}
} catch (IOException e) {
LOGGER.debug("", e);
}
return generateGeometryResult;
}
use of org.bimserver.shared.HashMapVirtualObject in project BIMserver by opensourceBIM.
the class StreamingGeometryGenerator method usableContext.
private boolean usableContext(HashMapVirtualObject representationItem) {
AbstractHashMapVirtualObject context = representationItem.getDirectFeature(representationItem.eClass().getEStructuralFeature("ContextOfItems"));
if (context == null) {
LOGGER.debug("No context: " + representationItem);
return false;
}
Object contextType = context.get("ContextType");
if (contextType == null) {
LOGGER.debug("No ContextType: " + representationItem);
return false;
}
if (!contextType.equals("Model") && !contextType.equals("Design")) {
LOGGER.debug("No Model/Design context: " + contextType);
return false;
}
return true;
}
use of org.bimserver.shared.HashMapVirtualObject 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);
}
use of org.bimserver.shared.HashMapVirtualObject in project BIMserver by opensourceBIM.
the class GeometryAccellerator method generateOctree.
private Octree generateOctree(OctreeKey key) {
LOGGER.info("Generating octree: " + key);
Long start = System.nanoTime();
try (DatabaseSession databaseSession = bimServer.getDatabase().createSession(OperationType.READ_ONLY)) {
Bounds totalBounds = new Bounds();
for (long roid : key.getRoids()) {
Revision revision = databaseSession.get(roid, OldQuery.getDefault());
totalBounds.integrate(revision.getBoundsMm());
}
Octree octree = new Octree(totalBounds, 9);
// Assuming all given roids are of projects that all have the same
// schema
Revision revision = databaseSession.get(key.getRoids().iterator().next(), OldQuery.getDefault());
PackageMetaData packageMetaData = bimServer.getMetaDataManager().getPackageMetaData(revision.getProject().getSchema());
Set<EClass> excluded = new HashSet<>();
if (key.getExcludedClasses() != null) {
for (String exclude : key.getExcludedClasses()) {
excluded.add(packageMetaData.getEClass(exclude));
}
}
Query query = new Query(packageMetaData);
QueryPart queryPart = query.createQueryPart();
queryPart.addType(packageMetaData.getEClass("IfcProduct"), true, excluded);
Include product = queryPart.createInclude();
product.addType(packageMetaData.getEClass("IfcProduct"), true);
product.addFieldDirect("geometry");
Include geometryInfo = product.createInclude();
geometryInfo.addType(GeometryPackage.eINSTANCE.getGeometryInfo(), false);
geometryInfo.addFieldDirect("data");
geometryInfo.addFieldDirect("boundsMm");
Include boundsInclude = geometryInfo.createInclude();
boundsInclude.addType(GeometryPackage.eINSTANCE.getBounds(), false);
boundsInclude.addFieldDirect("min");
boundsInclude.addFieldDirect("max");
Include dataInclude = geometryInfo.createInclude();
dataInclude.addType(GeometryPackage.eINSTANCE.getGeometryData(), false);
dataInclude.addFieldDirect("boundsMm");
Include dataBoundsInclude = dataInclude.createInclude();
dataBoundsInclude.addType(GeometryPackage.eINSTANCE.getBounds(), false);
dataBoundsInclude.addFieldDirect("min");
dataBoundsInclude.addFieldDirect("max");
QueryObjectProvider queryObjectProvider = new QueryObjectProvider(databaseSession, bimServer, query, key.getRoids(), packageMetaData);
HashMapVirtualObject next = queryObjectProvider.next();
Map<Long, GeometryDataObject> map = new HashMap<>();
while (next != null) {
AbstractHashMapVirtualObject geometry = next.getDirectFeature(packageMetaData.getEReference("IfcProduct", "geometry"));
if (geometry != null) {
float density = (float) geometry.get("density");
long geometryDataId = (long) geometry.get("data");
AbstractHashMapVirtualObject boundsMm = geometry.getDirectFeature(GeometryPackage.eINSTANCE.getGeometryInfo_BoundsMm());
GeometryDataObject geometryDataObject = null;
if (key.getGeometryIdsToReuse().contains(geometryDataId)) {
// Special case, we now have to use the complete
// bounding box of all reused objects, instead of using
// the object's aabb
HashMapVirtualObject geometryData = (HashMapVirtualObject) geometry.getDirectFeature(GeometryPackage.eINSTANCE.getGeometryInfo_Data());
boundsMm = geometryData.getDirectFeature(GeometryPackage.eINSTANCE.getGeometryData_BoundsMm());
geometryDataObject = map.get(geometryData.getOid());
if (geometryDataObject == null) {
geometryDataObject = new GeometryDataObject(geometryData);
map.put(geometryData.getOid(), geometryDataObject);
}
}
if (boundsMm != null) {
AbstractHashMapVirtualObject min = boundsMm.getDirectFeature(GeometryPackage.eINSTANCE.getBounds_Min());
AbstractHashMapVirtualObject max = boundsMm.getDirectFeature(GeometryPackage.eINSTANCE.getBounds_Max());
HashMapVirtualObject geometryData = (HashMapVirtualObject) geometry.getDirectFeature(GeometryPackage.eINSTANCE.getGeometryInfo_Data());
int saveableTriangles = (int) geometryData.get("saveableTriangles");
int reused = (int) geometryData.get("reused");
int triangles = (int) geometryData.get("nrIndices") / 3;
org.bimserver.database.queries.Bounds objectBounds = new org.bimserver.database.queries.Bounds((double) min.get("x"), (double) min.get("y"), (double) min.get("z"), (double) max.get("x"), (double) max.get("y"), (double) max.get("z"));
GeometryObject geometryObject = new GeometryObject(next.getOid(), next.eClass(), next.getCroid(), saveableTriangles, reused, triangles, density, objectBounds);
Node node = octree.add(geometryObject);
geometryObject.setTileId(node.getId());
geometryObject.setTileLevel(node.getLevel());
geometryObject.setGeometryDataObject(geometryDataObject);
}
}
next = queryObjectProvider.next();
}
AtomicLong totalTriangles = new AtomicLong();
octree.traverseBreathFirst(new Traverser() {
@Override
public void traverse(Node node) {
for (GeometryObject geometryObject : node.getValues()) {
totalTriangles.addAndGet(geometryObject.getTriangles());
}
}
});
LOGGER.info("Total triangles: " + totalTriangles);
octree.moveGeometryDown(new MoveGeometryDownDecider() {
@Override
public boolean shouldMoveDown(GeometryObject geometryObject) {
GeometryDataObject geometryDataObject = geometryObject.getGeometryDataObject();
if (geometryDataObject == null) {
// It's not reused at all
return false;
}
return false;
}
});
octree.moveUp(new MoveUpDecider() {
@Override
public boolean moveUp(Node node) {
// TODO use more heuristics
int totalTriangles = 0;
for (GeometryObject geometryObject : node.getValues()) {
totalTriangles += geometryObject.getTriangles();
}
if (totalTriangles < 1200) {
return true;
}
return false;
}
});
long end = System.nanoTime();
LOGGER.info("Octree generated in " + ((end - start) / 1000000) + " ms");
return octree;
} catch (BimserverDatabaseException e) {
LOGGER.error("", e);
} catch (IOException e) {
LOGGER.error("", e);
} catch (QueryException e) {
LOGGER.error("", e);
}
return null;
}
Aggregations