Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get the absolute coordinates of an IfcProduct using BIMserver? #387

Closed
taylorjeremy opened this issue Jul 16, 2016 · 8 comments
Closed

Comments

@taylorjeremy
Copy link

Hello.

I am using BIMserver in a small Java API that I am developing. Right now, I am trying to get the coordinates of each object that is an instance of IfcProduct. However, I am just getting the relative coordinates to another IfcProduct, through IfcLocalPlacement, and not the absolute coordinates of the object.

My goal is to calculate the distance between IFC objects (just to show the information to the user, I am not trying to render objects and so). For example, the distance between a IfcSpace and a IfcDistributionControlElement.

Is it possible to get the absolute coordinates of each object using BIMserver? If so, can anyone spare some indicator on how to do that?

Thanks in advance,

Jeremy.

@rubendel
Copy link
Member

BIMserver has no built-in functionality for that. But if you are using the Java client API (or JavaScript API for that matter) it will help you to traverse the model.

"IfcLocalPlacement" has a reference "PlacementRelTo". Keep following that (recusively) until there are no PlacementRelTo references anymore and incorporate all the RelativePlacement you find along the way into one transformation matrix.

@aothms
Copy link
Member

aothms commented Jul 18, 2016

I guess it would also be possible to use the triangulated geometry that the BIMserver might have for those products.

@taylorjeremy
Copy link
Author

I'm using BimServerClientLib. In a past attempt, I tried to use GeometryInfo through getGeometry method, of IfcProduct class. But for all IfcProduct objects in the model, that object (GeometryInfo) is null. Maybe I'm forgetting to initialize something?

Regarding the transformation matrix, is it possible to reuse some of the operations performed in GeometryGenerator and Matrix classes and apply them to the relative coordinates returned by IfcLocalPlacement? Can these classes help me getting the absolute coordinates?

Thank you.

@rubendel
Copy link
Member

When you call getModel, there is an implementation that takes yet another boolean argument. That argument (called "includeGeometry") will tell the client to also fetch the geometry information. After that the getGeometry calls should return geometry (for the objects that have any). I agree it's not the most intuitive implementation at the moment.

GeometryGenerator and Matrix certainly provide methods to help you with this. But BIMserver does not use these methods to come to the final transformation matrices. BIMserver simply gets those matrices from IfcOpenShell and in some cases applies them to the geometry (for example to calculate absolute bounding boxes).

@rubendel
Copy link
Member

Thinking about that a bit more, in your use case it might actually be enough to just get the transformation matrices from BIMserver. You can call getGeometry().getTransformation() to get the transformation matrix. For efficient storage purposes those are stored as byte[]. The following code will convert to a double[].

double[] matrix = new double[16];
ByteBuffer transformationBuffer = ByteBuffer.wrap(geometryInfo.getTransformation());
transformationBuffer.order(ByteOrder.LITTLE_ENDIAN);
DoubleBuffer transformation = transformationBuffer.asDoubleBuffer();
transformation.get(matrix);

@taylorjeremy
Copy link
Author

Thank you for your answers, they were very helpful!

Just to make sure I'm following the right path:

ByteBuffer transformation = ByteBuffer.wrap(product.getGeometry().getTransformation());
transformation.order(ByteOrder.LITTLE_ENDIAN);
float[] matrix = new float[16];
FloatBuffer floatBuffer = transformation.asFloatBuffer();
for (int i=0; i< matrix.length; i++) {
      matrix[i] = floatBuffer.get();
}           
matrix = Matrix.changeOrientation(matrix);
Transform3D transform = new Transform3D(matrix);
Point3f pt = new Point3f(x, y, z); // Coordinates of an IfcCartesianPoint returned by the relative placement of the product
transform.transform(pt);

The double matrix returned had only 8 elements for each object, and not 16 for some reason, so I tried using floats and it worked. I apply the transformation matrix to some specific point (using Transform3D), and that might give me the global coordinates, right?

Thank you!

@rubendel
Copy link
Member

Which version of BIMserver are you using? In older versions that array was indeed an array of float.

I assume you verified that the change of orientation is necessary.

In theory I think you should not start out with the coordinates of the relative placement, some of the transformation might be applied two times that way. It's probably better to use the point [0, 0, 0] and transform that via the matrix.

For your usecase it might actually be better to iterate through all vertices in the object, transform them all according to the corresponding matrix and then calculate the (axis aligned) bounding box. With the bounding boxes you can then calculate the distances between the objects.

@taylorjeremy
Copy link
Author

I was using the version 'bimserver-1.4.0-FINAL-2015-09-29'. I was having some problems using recent versions. Anyway, I had it solved by transforming the point [0,0,0] using the matrix for the object, like you said.

Thank you for your answers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants