OSArch Community

[IfcOpenShell-Python] How to calculate a distance between two IFC entities?

  1. M

    In the past, I used successfully PythonOCC to determine the volume from one IFC entity. So I thought, why not also use PythonOCC for this problem and got the following code:

    import ifcopenshell
    
    from ifcopenshell import geom
    
    import OCC.Core.BRepExtrema as BRepExtrema
    
    
    File = "two-cube-built-element.ifc"
    
    ifc_file = ifcopenshell.open(File)
    
    
    Units = ifc_file.by_type("IFCSIUNIT")
    
    for unit in Units:
    
        if unit.UnitType == "LENGTHUNIT":
    
            length_unit = unit.Name
    
            break
    
    
    # Define settings
    
    settings = geom.settings()
    
    settings.set(settings.USE_PYTHON_OPENCASCADE, True) # tells ifcopenshell to use pythonocc
    
    
    ifc_products = ifc_file.by_type("IfcBuiltElement")
    
    Shapes = [ ifcopenshell.geom.create_shape(settings, product) for product in ifc_products] 
    
    
    # Create the BRepExtrema_DistShapeShape object
    
    dist = BRepExtrema.BRepExtrema_DistShapeShape(Shapes[0].geometry, Shapes[1].geometry)
    
    
    
    # Perform the distance calculation
    
    dist.Perform()
    
    
    
    # Get the minimum distance
    
    min_distance = dist.Value()
    
    
    
    print("Minimum distance between the two IfcBuiltElement:", min_distance, length_unit.lower())

    For my test IFC file (attached see below), I got the right result! See image:

    And it is the same value as in BIMVision:

    My next step is to calculate the distance between the bottom faces of both cubes, like in the image below:

    My question is, before I go down deeper in this rabbit hole named PythonOCC, to solve my new problem: Are there other possibilities how I can solve this with a python script? Maybe other Python libraries?

  2. A
  3. M

    A little update, I got this script, which calculate the distance between the bottom faces of both cubes:

    import ifcopenshell
    
    from ifcopenshell import geom
    
    from OCC.Core import TopAbs
    
    from OCC.Core.TopExp import TopExp_Explorer
    
    from OCC.Core.BRepAdaptor import BRepAdaptor_Surface
    
    import OCC.Core.BRepExtrema as BRepExtrema
    
    import OCC.Core.gp as gp
    
    from OCC.Core.BRep import BRep_Tool
    
    
    
    File = "two-cube-built-element.ifc"
    
    ifc_file = ifcopenshell.open(File)
    
    
    
    Units = ifc_file.by_type("IFCSIUNIT")
    
    for unit in Units:
    
        if unit.UnitType == "LENGTHUNIT":
    
            length_unit = unit.Name
    
            break
    
    
    
    # Define settings
    
    settings = geom.settings()
    
    settings.set(settings.USE_PYTHON_OPENCASCADE, True) # tells ifcopenshell to use pythonocc
    
    
    
    ifc_products = ifc_file.by_type("IfcBuiltElement")
    
    
    
    Cube1, Cube2 = [ ifcopenshell.geom.create_shape(settings, product).geometry for product in ifc_products] 
    
    
    
    # Function to get the bottom face of a shape
    
    def get_bottom_face(compound):
    
        # Create a TopExp_Explorer to iterate over the faces in the compound
    
        explorer = TopExp_Explorer(compound, TopAbs.TopAbs_FACE)
    
    
    
        # Iterate over the faces in the compound
    
        while explorer.More():
    
            face = explorer.Current()
    
    
    
            # Check if the face is the bottom face
    
            # You can modify this condition based on your specific cube representation
    
            if is_bottom_face(face):
    
                return face
    
    
    
            # Move to the next face
    
            explorer.Next()
    
    
    
        return None
    
    
    
    # Function to check if a face is the bottom face
    
    def is_bottom_face(face):
    
        # You can implement your logic to identify the bottom face based on your specific cube representation
    
        # For example, you can check the normal of the face or its position in relation to the cube
    
    
    
        # Here's a simple example assuming the bottom face has a normal pointing downwards
    
        surface = BRepAdaptor_Surface(face)
    
        normal = surface.Plane().Axis().Direction()
    
        return normal.IsEqual(gp.gp_Dir(0, 0, -1), 1e-6)  # Tolerance is set to 1e-6
    
    
    
    # Get the bottom faces of Cube1 and Cube2
    
    bottom_face_cube1 = get_bottom_face(Cube1)
    
    bottom_face_cube2 = get_bottom_face(Cube2)
    
    
    
    # Calculate the minimal distance between the bottom faces
    
    dist = BRepExtrema.BRepExtrema_DistShapeShape(bottom_face_cube1, bottom_face_cube2)
    
    dist.Perform()
    
    min_distance = dist.Value()
    
    
    
    print("Minimum distance between the bottom faces of the two IfcBuiltElement:", min_distance, length_unit.lower())

    With this code, I got the right result:

    @Arv Thanks for the hint. Is there a way to specify that I want the distance between the bottom faces of the two cubes?

  4. M

    You can use ifcopenshell.util.shape.get_volume() to get the volume and not worry about OCC.

    I wouldn't recommend using BRepExtrema_DistShapeShape because it's actually extremely slow. We use an implementation in the geometry tree (typically for IfcClash) using an implementation from NVidia Omniverse's PhysX written by very clever people who invent these types of algos. It's got lots of toys I'd highly recommend investigating.

    It's exposed as a many-many but should work with two objects too: https://docs.ifcopenshell.org/ifcopenshell-python/geometry_tree.html#detecting-clearance-clashes-between-elements

  5. B

    @Moult said:

    You can use ifcopenshell.util.shape.get_volume() to get the volume and not worry about OCC.

    very useful, I did not know about this.

    BTW: I do use for all kind of geometry algos I need to do a FreeCAD shape and the methods of FreeCAD. It might not be the fastest, but it has hundreds of methods to evaluate geometry including geometry checking.

  6. M

    Indeed, another option is mathutils.geometry from Blender. However for distance checks, BVH trees are extremely useful so I'd highly recommend the IfcOpenShell geometry tree.

  7. G
  8. M

    While we're at it, I'd also like to shoutout to shapely which is awesome library for 2D geometry analysis. Great for cross sectional profiles, cut shapes, wall topology...

Login or Register to reply.