Reputation: 11
I am developing a small Java API that manipulates IFC (Industry Foundation Class) objects. For that, I am using external tools, like BIMserver.
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. Therefore, the referential for each object is the entity where it is contained.
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 an IfcSpace
and an IfcDistributionControlElement
.
Does anyone know how to get the absolute coordinates (not the relative coordinates) of each IFC object? If you know some APIs or libraries that could help me, you can send them too.
Upvotes: 1
Views: 2715
Reputation: 1001
Below is the function that would recursively get you the absolute coordinates of the coordinate system origin for local placement, which is used for any class extending IfcProduct. However, this only works if none of the intermediate coordinate systems is rotated, because this function does not take into account the placement "directions", only its "location".
public double[] getAbsolutePosition(IfcObjectPlacement ifcObjectPlacement) throws Exception {
if (ifcObjectPlacement instanceof IfcGridPlacement) {
throw new Exception("IfcGridPlacement has not been implemented");
} else if (ifcObjectPlacement instanceof IfcLocalPlacement) {
IfcLocalPlacement ifcLocalPlacement = (IfcLocalPlacement) ifcObjectPlacement;
IfcAxis2Placement relativePlacement = ifcLocalPlacement.getRelativePlacement();
if (relativePlacement instanceof IfcAxis2Placement2D) {
throw new Exception("IfcAxis2Placement2D has not been implemented");
} else if (relativePlacement instanceof IfcAxis2Placement3D) {
IfcAxis2Placement3D ifcAxis2Placement3D = (IfcAxis2Placement3D) relativePlacement;
IfcObjectPlacement placementRelativeTo = ifcLocalPlacement.getPlacementRelTo();
if (placementRelativeTo == null) {
IfcCartesianPoint ifcCartesianPoint = ifcAxis2Placement3D.getLocation();
return new double[] { ifcCartesianPoint.getCoordinates().get(0).getValue(), ifcCartesianPoint.getCoordinates().get(1).getValue(), ifcCartesianPoint.getCoordinates().get(2).getValue() };
} else {
double[] relative = getAbsolutePosition(placementRelativeTo);
IfcCartesianPoint ifcCartesianPoint = ifcAxis2Placement3D.getLocation();
return new double[] { relative[0] + ifcCartesianPoint.getCoordinates().get(0).getValue(), relative[1] + ifcCartesianPoint.getCoordinates().get(1).getValue(), relative[2] + ifcCartesianPoint.getCoordinates().get(2).getValue() };
}
}
}
return new double[] { 0d, 0d, 0d };
}
Upvotes: 0
Reputation: 1331
To resolve IfcLocalPlacement
, you basically need to traverse its placementRelativeTo
attribute recursively until it is null or not a local placement anymore. For every recursively specified local placement you factor its IfcAxis2Placement
(attribute relativePlacement
) into your final transformation matrix. The placement may be 2D or 3D and defines the position and orientation of the coordinate system relative to its "parent" CS. Note that the orientation of the 3D axis placement is given by the vector of its z-axis and any vector in the xz-plane that is different from the z-axis, but does not need to be perpendicular to the z-axis. Here is an implementation in Java: PlacementResolver.java
, with test cases for illustration: PlacementResolverTest.java
.
You may also find useful code in the BIMserver repository in GeometryGenerator.java and Matrix.java.
If you are using BIMserver, you can also use the transformation matrizes created during geometry generation (by the render engine, e.g. IfcOpenShell). For this to work, you need to have geometry generation enabled (usually enabled by default if you have the IfcOpenShell plugin installed). If you use a client, you need to load the model with geometry (via the respective parameter during model load). Finally you can access the matrix by calling getGeometry().getTransformation()
on an IfcProduct
instance that has geometry. The transformation matrix is a double matrix but stored as a byte[]
in little endian system. You can convert, for example, following the explanation in this comment.
Upvotes: 0
Reputation: 44422
You need to apply/stack all the different IfcLocalPlacement
in the tree until you reach IfcProject
container. You can find also explanation here in the docs for IFC2X3 and here in the docs for IFC4 (the specs for IfcLocalPlacement
have not changed as far as I can see):
The following conventions shall apply as default relative positions if the relative placement is used. The conventions are given for all five direct subtypes of IfcProduct, the IfcSpatialStructureElement, IfcElement, IfcAnnotation, IfcGrid, IfcPort. More detailed placement information is given at the level of subtypes of those five types mentioned.
- For the subtypes of
IfcSpatialStructureElement
the following conventions apply
IfcSite
shall be placed absolutely within the world coordinate system established by the geometric representation context of theIfcProject
IfcBuilding
shall be placed relative to the local placement ofIfcSite
IfcBuildingStorey
shall be placed relative to the local placement ofIfcBuilding
- For
IfcGrid
andIfcAnnotation
the convention applies that it shall be placed relative
- to the local placement of its container (
IfcSite
,IfcBuilding
,IfcBuildingStorey
)
- it should be the same container element that is referenced by the
IfcRelContainedInSpatialStructure
containment relationship,- For
IfcPort
the convention applies that it shall be placed relative
- to the local placement of the element it belongs to (
IfcElement
)
- it should be the same element that is referenced by the
IfcRelConnectsPortToElement
connection relationship,- For
IfcElement
the convention applies that it shall be placed relative:
- to the local placement of its container (
IfcSite
,IfcBuilding
,IfcBuildingStorey
)
- it should be the same container element that is referenced by the
IfcRelContainedInSpatialStructure
containment relationship,- to the local placement of the
IfcElement
to which it is tied by an element composition relationship
- for features that are located relative to the main component (such as openings), as expressed by
IfcRelVoidsElement
andIfcRelProjectsElement
,- for elements that fill an opening (such as doors or windows), as expressed by
IfcRelFillsElement
,- for coverings that cover the element, as expressed by
IfcRelCoversBldgElements
,- for sub components that are aggregated to the main component, as expressed by
IfcRelAggregates
andIfcRelNests
)
Upvotes: 3