IfcOpenShell: create face with interior holes
Hi all,
I have some problems with creating geometry in IfcOpenShell & thought maybe some of you could help me. Here's the problem:
I have a face with one or more interior holes (as a python list of lists, where the first list corresponds to the outer boundary and the others are all interior holes). In the case of the figure, it looks like: [[1,2,3,4],[5,6,7,8],[9,10,11,12]]. I'd like to convert that to a IfcFace.
The code now looks like this. IFC_vertices is a dictionary of IfcCartesianPoints based on the vertex index.
IFC_model = ifcopenshell.open("ifcmodel.ifc")
face = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
cartesian_points = []
for vertex in face[0]:
cartesian_points.append(IFC_vertices[vertex])
polyloop = IFC_model.create_entity("IfcPolyLoop", Polygon=cartesian_points)
outerbound = IFC_model.create_entity("IfcFaceOuterBound", Bound=polyloop, Orientation=True) # orientation of vertices is CCW
innerbounds = []
for interior_face in face[1:]:
for vertex in interior_face:
cartesian_points.append(IFC_vertices[vertex])
polyloop = IFC_model.create_entity("IfcPolyLoop", Polygon=cartesian_points)
innerbounds.append(IFC_model.create_entity("IfcFaceBound", Bound=polyloop, Orientation=False)) # orientation of vertices is CW
IFC_model.create_entity("IfcFace", Bounds=[outerbound] + innerbounds)
I thought it was pretty straightforward this way, as it is explained in the BuildingSMART documentation. But there is definitely something wrong with the IfcFaceBounds / IfcOuterFaceBounds. Here's an output of such a case in BlenderBIM (likely not a bug there because in Solibri it looks similar):
Is there any IFC/IfcOpenShell hero that knows what went wrong in the code?
Comments
Output of this building can be found in following file
Blender's mesh system does not allow holes in geometry polygons. A face must have at most one continuous edge ring. See https://blender.stackexchange.com/a/33325/86891 Solibri might work the same way. The solution is to add edges to cut the face so there is at most one continuous edge ring.
Note that using a 2D curve with multiple loops does the job quite well as hinted in the BSE question.
There might be a case here to automatically tidy up the mesh when translating from ifc to bmesh ? but the result may not be consistent so I don't know if we'd be able to ensure no data is lost or modified when importing / exporting.
@LaurensJN I only quickly skimmed through but can you confirm
cartesian_points.append(IFC_vertices[vertex])
? Note that face indices start from 1 (which it looks like you have) but python indices start from 0.@Moult indices here are for simplicity & visualisation. The cartesian_points are actually built using CJIO indexing. Faces are also correctly displayed if there are no holes, so I don't think there are problems there.
@Gorgious that might be the problem. The solution there is blender-based, but I need a solution for IFC files, because I just use BlenderBIM to import the faces. @Moult do you know if BlenderBIM could possibly have problems with handling IfcFaces with holes?
I will check if I could easily add the closest vertex on the boundary to each polyloop, maybe that could solve the problem (in the easy example 4/6 and 2/12).
I found the mistake... I didn't empty cartesian_points each loop in the interior_face, so that produces some weird outputs. Bad news: I wasted my whole sunday on this single line. Good news: cityjson files converted to IFC can now have their accurate representation :)
