
org.bimserver.serializers.binarygeometry.BinaryGeometryMessagingSerializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of binaryserializers Show documentation
Show all versions of binaryserializers Show documentation
BIMserver plugins that provides binary serializers
The newest version!
package org.bimserver.serializers.binarygeometry;
/******************************************************************************
* Copyright (C) 2009-2019 BIMserver.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {@literal }.
*****************************************************************************/
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.bimserver.emf.IdEObject;
import org.bimserver.emf.IfcModelInterface;
import org.bimserver.emf.PackageMetaData;
import org.bimserver.models.geometry.GeometryData;
import org.bimserver.models.geometry.GeometryInfo;
import org.bimserver.plugins.PluginManagerInterface;
import org.bimserver.plugins.serializers.MessagingSerializer;
import org.bimserver.plugins.serializers.ProgressReporter;
import org.bimserver.plugins.serializers.ProjectInfo;
import org.bimserver.plugins.serializers.SerializerException;
import org.eclipse.emf.ecore.EClass;
import com.google.common.base.Charsets;
import com.google.common.io.LittleEndianDataOutputStream;
/**
* @author Ruben de Laat
*
* Use the more efficient BinaryGeometryMessagingStreamingSerializer
*/
@Deprecated
public class BinaryGeometryMessagingSerializer implements MessagingSerializer {
private static final byte FORMAT_VERSION = 6;
private IfcModelInterface model;
private enum Mode {
START,
DATA,
END
}
private enum MessageType {
INIT((byte)0),
GEOMETRY_TRIANGLES((byte)1),
GEOMETRY_INSTANCE((byte)2),
GEOMETRY_TRIANGLES_PARTED((byte)3),
GEOMETRY_INSTANCE_PARTED((byte)4);
private byte id;
private MessageType(byte id) {
this.id = id;
}
public byte getId() {
return id;
}
}
private Mode mode = Mode.START;
private Map concreteGeometrySent;
private Iterator iterator;
private PackageMetaData packageMetaData;
private long splitCounter = -1;
@Override
public void init(IfcModelInterface model, ProjectInfo projectInfo, PluginManagerInterface pluginManager, PackageMetaData packageMetaData, boolean normalizeOids) throws SerializerException {
this.model = model;
this.packageMetaData = packageMetaData;
}
@Override
public boolean writeMessage(OutputStream outputStream, ProgressReporter progressReporter) throws IOException {
switch (mode) {
case START:
if (!writeStart(outputStream)) {
mode = Mode.END;
return false;
}
mode = Mode.DATA;
break;
case DATA:
if (!writeData(outputStream)) {
mode = Mode.END;
return false;
}
break;
case END:
return false;
default:
break;
}
return true;
}
private boolean writeStart(OutputStream outputStream) throws IOException {
LittleEndianDataOutputStream dataOutputStream = new LittleEndianDataOutputStream(outputStream);
// Identifier for clients to determine if this server is even serving binary geometry
dataOutputStream.writeByte(MessageType.INIT.getId());
dataOutputStream.writeUTF("BGS");
// Version of the current format being outputted, should be changed for every (released) change in protocol
dataOutputStream.writeByte(FORMAT_VERSION);
Bounds modelBounds = new Bounds();
int nrObjects = 0;
// All access to EClass is being done generically to support multiple IFC schema's with 1 serializer
EClass productClass = model.getPackageMetaData().getEClass("IfcProduct");
List products = model.getAllWithSubTypes(productClass);
// First iteration, to determine number of objects with geometry and calculate model bounds
for (IdEObject ifcProduct : products) {
GeometryInfo geometryInfo = (GeometryInfo) ifcProduct.eGet(ifcProduct.eClass().getEStructuralFeature("geometry"));
if (geometryInfo != null && geometryInfo.getTransformation() != null) {
Bounds objectBounds = new Bounds(geometryInfo.getBounds());
modelBounds.integrate(objectBounds);
nrObjects++;
}
}
int skip = 4 - (7 % 4);
if(skip != 0 && skip != 4) {
dataOutputStream.write(new byte[skip]);
}
modelBounds.writeTo(dataOutputStream);
dataOutputStream.writeInt(nrObjects);
concreteGeometrySent = new HashMap();
EClass productEClass = packageMetaData.getEClass("IfcProduct");
iterator = model.getAllWithSubTypes(productEClass).iterator();
return nrObjects > 0;
}
@SuppressWarnings("unchecked")
private boolean writeData(OutputStream outputStream) throws IOException {
IdEObject ifcProduct = iterator.next();
LittleEndianDataOutputStream dataOutputStream = new LittleEndianDataOutputStream(outputStream);
GeometryInfo geometryInfo = (GeometryInfo) ifcProduct.eGet(ifcProduct.eClass().getEStructuralFeature("geometry"));
if (geometryInfo != null && geometryInfo.getTransformation() != null) {
GeometryData geometryData = geometryInfo.getData();
int totalNrIndices = geometryData.getIndices().getData().length / 4;
int maxIndexValues = 16389;
Object reuse = concreteGeometrySent.get(geometryData.getOid());
MessageType messageType = null;
if (reuse == null) {
if (totalNrIndices > maxIndexValues) {
messageType = MessageType.GEOMETRY_TRIANGLES_PARTED;
} else {
messageType = MessageType.GEOMETRY_TRIANGLES;
}
} else {
if (reuse instanceof List) {
messageType = MessageType.GEOMETRY_INSTANCE_PARTED;
} else {
messageType = MessageType.GEOMETRY_INSTANCE;
}
}
dataOutputStream.writeByte(messageType.getId());
dataOutputStream.writeUTF(ifcProduct.eClass().getName());
Long roid = model.getPidRoidMap().get(ifcProduct.getPid());
dataOutputStream.writeLong(roid);
dataOutputStream.writeLong(ifcProduct.getOid());
// BEWARE, ByteOrder is always LITTLE_ENDIAN, because that's what GPU's seem to prefer, Java's ByteBuffer default is BIG_ENDIAN though!
int skip = 8 - ((3 + ifcProduct.eClass().getName().getBytes(Charsets.UTF_8).length) % 8);
if(skip != 0 && skip != 8) {
dataOutputStream.write(new byte[skip]);
}
dataOutputStream.write(geometryInfo.getTransformation());
if (reuse != null && reuse instanceof Long) {
// Reused geometry, only send the id of the reused geometry data
dataOutputStream.writeLong(geometryData.getOid());
} else if (reuse != null && reuse instanceof List) {
List list = (List)reuse;
dataOutputStream.writeInt(list.size());
for (long coreId : list) {
dataOutputStream.writeLong(coreId);
}
} else {
if (totalNrIndices > maxIndexValues) {
// Split geometry, this algorithm - for now - just throws away all the reuse of vertices that might be there
// Also, although usually the vertices buffers are too large, this algorithm is based on the indices, so we
// probably are not cramming as much data as we can in each "part", but that's not really a problem I think
int nrParts = (totalNrIndices + maxIndexValues - 1) / maxIndexValues;
dataOutputStream.writeInt(nrParts);
Bounds objectBounds = new Bounds(geometryInfo.getBounds().getMin(), geometryInfo.getBounds().getMax());
objectBounds.writeTo(dataOutputStream);
ByteBuffer indicesBuffer = ByteBuffer.wrap(geometryData.getIndices().getData());
indicesBuffer.order(ByteOrder.LITTLE_ENDIAN);
IntBuffer indicesIntBuffer = indicesBuffer.asIntBuffer();
ByteBuffer vertexBuffer = ByteBuffer.wrap(geometryData.getVertices().getData());
vertexBuffer.order(ByteOrder.LITTLE_ENDIAN);
FloatBuffer verticesFloatBuffer = vertexBuffer.asFloatBuffer();
ByteBuffer normalsBuffer = ByteBuffer.wrap(geometryData.getNormals().getData());
normalsBuffer.order(ByteOrder.LITTLE_ENDIAN);
FloatBuffer normalsFloatBuffer = normalsBuffer.asFloatBuffer();
for (int part=0; part arrayList = new ArrayList();
arrayList.add(geometryData.getOid());
concreteGeometrySent.put(geometryData.getOid(), arrayList);
}
}
}
return iterator.hasNext();
}
@Override
public void close() throws IOException {
// TODO Auto-generated method stub
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy