IfcOpenShell : Create openings in walls with arbitrary shapes

edited November 2022 in General

I'm hitting sort of a roadblock here in one of my export endeavours. I'm trying to explore how to carve openings in walls using the API.
I'd like to put openings in walls and achieve roundtripping but I can't.
I'm basically converting wall geometry and booleans from blender to ifc. I can't use the blenderbim addon interface to do it because I want to be agnostic of Blender as much as possible and I have hundreds of walls to export.

Here's a simple example.
with a typed wall and a boolean opening (All blender stuff, there is no ifc involved in the blend file yet) :

So as pseudo code here's where I'm at :

material = add_material()
wall_type = add_wall_type(thickness = 0.30)
wall_occurence = add_wall_occurence(blender_obj, wall_type)

Roundtrippin works up until then.

Now I add a regular blender boolean to my wall to create an opening. (It doesn't have to be added as a modifier but that's how I know this opening belongs to this wall in code)

I export it to an opening element, and use it as an opening to the IfcWall occurrence.

            opening_ifc = run(
                "root.create_entity", wrapper.file, ifc_class="IfcOpeningElement", name=opening_blend.name
            )
            items = create_ifc_mesh(wrapper, opening_blend)  # Similar to the dxf2ifc.py example script
            representation = wrapper.file.createIfcShapeRepresentation(
                wrapper.body,
                wrapper.body.ContextIdentifier,
                "Tesselation",
                items,
            )
            run("geometry.assign_representation", wrapper.file, product=opening_ifc, representation=representation)
            run("void.add_opening", wrapper.file, opening=opening_ifc, element=wall_ifc)

Then when I try to import the ifc file back to Blender, there is no opening. However the weird thing is that the opening does display when I go into the BIM tool and click on the Void tool, but it isn't registered as an opening.

And it does display in BimVision
and Revit

Surely I'm missing something but can't really figure what...
I'll share the ifc if anyone wants to take a look or has some insight into this.

Cheers

Comments

  • Hi @Gorgious , haven't tested, but here's a quick idea. Could it be that some magic steps are missing by just creating an IfcShapeRepresentation instead of calling the api on "geometry.add_representation"?

  • Hehe that may very well be it :) The usecase is a 800 lines behemoth and it seems it covers all edge cases so that might be mildly headache-inducing >< I'll also dig into the blenderbim core functions like this one.

    I have to say the faceted brep representation seems to be the one that plays the nicest with other softwares. No luck on the blenderbim roundtripping so far. I'll keep digging !

    I have a feeling I might also be doing something forbidden regarding geometric representation contexts. I still have a lot to learn about that, it's still a foggy area for me.

    cvillagrasa
  • @Gorgious this is what I know:

    IfcOpenings are applied to walls and slabs, ie. They are applied to Building Elements rather than the Representation.

    Representations can be a Boolean result of other representations, but in this case the RepresentationType must be 'CSG', otherwise IfcOpenShell won't show it.

    cvillagrasa
  • edited November 2022

    Thank you both for your input :)
    It seems I have made a bit of progress. So as you said @brunopostle IfcOpenings are applied to an Element rather than a Representation.
    Here's how I define my wall :

            wall_occurrence_ifc = run("root.create_entity", wrapper.file, ifc_class="IfcWall", name=wall_blend.name)
            representation = run(
                "geometry.add_wall_representation",
                wrapper.file,
                context=wrapper.body,
                length=wall_blend.dimensions[0],
                height=wall_blend.dimensions[2],
                thickness=wall_blend.dimensions[1],
            )
            run("geometry.assign_representation", wrapper.file, product=wall_occurrence_ifc, representation=representation)
            run("type.assign_type", wrapper.file, related_object=wall_occurrence_ifc, relating_type=wall_type)
    

    And then I create the opening :

                opening_ifc = run(
                    "root.create_entity", wrapper.file, ifc_class="IfcOpeningElement", name=opening_blend.name
                )
                representation = create_faceted_brep(wrapper, opening_blend)
                run("geometry.assign_representation", wrapper.file, product=opening_ifc, representation=representation)
                run("void.add_opening", wrapper.file, opening=opening_ifc, element=wall_ifc)
    

    So as far as I can tell the representation shouldn't have to be updated once the opening has been setup ? It kinda works but I think it only works with very basic shapes, like elongated cubes. Cylinders work, too.

    I'd like to export more elaborate shapes like this one

    But no luck. And still, the walls are not cut when roundtripping in blenderbim.

    I've explored using IfcBooleans, adding booleans to the base wall representation.

                for opening_set in get_openings_in_wall_as_arguments(wrapper, wall_blend, wall_occurrence):
                    run(
                    "geometry.add_boolean", wrapper.file, representation=wall_representation, operator="DIFFERENCE", **opening_set
                    )
                run("geometry.assign_representation", wrapper.file, product=wall_occurrence, representation=wall_representation)
    

    It kinda works, when I roundtrip the file the booleans are recognized and the holes are there.

    But I have three gripes with this method :

    • Booleans shouldn't be used to cut window and doors voids into walls, in this case openings should be used as per the schema.
    • There is a booleans argument to "geometry.add_wall_representation" but I can't seem to find how to generate these objects.
    • Revit doesn't like it. Walls with booleans don't import. Archicad does import the walls but does not cut the booleans out. :(
    AceCoentheoryshaw
  • @Gorgious IfcOpenShell should cope with complex geometry for an IfcOpening, though I have only experimented with breps, no true curves.

    There are a couple of downloadable examples in this thread: https://github.com/IfcOpenShell/IfcOpenShell/issues/2474

  • @brunopostle Ooh nice I'll dig into homemaker's code to learn more about this, it looks like a gold mine of information for my purpose. :)
    FWIW I've managed to get more reliable results by using the local matrix of IfcOpenings for defining geometry and placing them with "geometry.edit_object_placement" with the world matrix. Previously I set all the openings' origins at world origin and offset the vertices accordingly which was unreliable.

    I think next I'll try to define the IfcOpening placement in the local matrix of the wall, seems like it is expected in the schema.

  • @Gorgious the wall.py code in the Homemaker add-on was auto-converted from perl and my File::IFC module, so it is a bit funky. It does things like setting out windows in the wall axis direction, then rotating them to world coordinates, then assigning them to the wall using ifcopenshell.api, which maps them back to axis coordinates. I need to clean this stuff up.

    Gorgious
  • edited November 2022

    After a bit of work I have sorted out a few of the possible problems I've experienced when using custom geometry ("Brep") as an IfcOpeningElement :

    • Non-uniform object scale -> Apply Scale to (1,1,1) before export
    • Double vertices -> Merge vertices by distance
    • Non-coplanar faces -> Here I don't think there is a one-click solution. When modeling, you should take care of only modeling coplanar faces (ie all the vertices of each face are located on the same 3D plane (Consistent with the docs). I tried triangulating the mesh which ensures all faces are coplanar but it didn't work out that well.
    • Quads : It seems N-Gons are not a problem with Brep representation so I elected to using them as much as possible. In fact, in some places using quads prevented correct mesh export.
    • Complexity : When possible rather use several more simple meshes (Elongated Cube, cylinder, etc.) rather than one complex mesh. Co-planar booleans didn't seem that bothersome so a complex mesh is easily separated into other, more simple meshes.
    • Use local coordinates (preferably using the same local axis as the wall - but I didn't manage to work that out and I exported openings OK)
    • Take care of not having opening elements that do not intersect with the wall they are associated with. It will make Revit complain. I don't know if it's okay in the schema though. I don't see how that would be useful.

    I'm out for more adventures !

    CoentheoryshawAce
  • Just a small update to my last post : Don't use opening elements with coplanar faces.

    This particular wall section had roundtripping import on BlenderBIM infinitely stuck (at least for a few dozen minutes), because one of the faces of the openings was smack down coplanar to one of the faces of another one. Although it opens fine on other softs. It may be worth a bug report ? Or is it a limitation of ifcopenshell ?

    Here in BIMvision the two culprit openings :

    After I made the opening slightly bigger in Blender the file imported back in a second or two. (still a lot for a simple wall but I guess they are complex boolean operations).

    I'll share the file for posterity or if I need to get back to it at some point.

    Cheers

    CoentheoryshawCadGiruAce
Sign In or Register to comment.