Lateral Area or Vertical Faces in the Ifc Structure

Hello,
I am having some issues and I hope that someone could help me. I have a wall, basically I can go through the entities and reach the faces (IfcFace) of the wall. But what I need are only the "lateral area" faces or the vertical faces of the wall. Does anyone know if or how I could filter my faces of the wall I have, so it shows me only the vertical faces or lateral area faces? On this way I would like to exclude the faces that are placed horizontal.
I am also adding a screenshot of my IfcFaces I've gotten.

I hope someone can help me in this case.
Best regards

Comments

  • Have you considered using create shape from ifcopenshell.geom (or the iterator if you are processing a lot of geometry) then checking the normals of each face? If the normal has a z component greater than a threshold it's horizontal.

  • Thank you for your response. No I didn't consider using create shape from ifcopenshell.geom. I am not really advanced in this area, cold you please give me some advice or links where I could look into it?

  • @Alexanderchocks sure thing! Here you go: https://wiki.osarch.org/index.php?title=IfcOpenShell_code_examples#Geometry_processing

    Note this simply talks about how to get geometry as a soup of faces. Doing the math to calculate face normals is your own homework :)

    Coen
  • @Moult thank you very much for your help. Also what I wanted to ask, is there any information inside the IFC structure that could give me the direction (or horizontal oder vertical orientation) of a face? So based on this information I could exclude faces I don't need. Based on my research I could not find anything inside the IFC structure, do you have any idea which information in this case would be helpful in the IFC structure?

    Also regarding the "create shape from ifcopenshell.geom", I have done it but my problem is that I do not understand if it is really necessary in this case. Since I can get the faces with IfcFace in the Ifc structure of my model and also have the IfcCartesianPoints, why would I need to create a shape to get the verts with which I could calculate the normals? I could also just look into the IfcFace in the IFC structure and at the cartesian points and based on them calculating the normals? Am I understanding something wrong? Do you have any thoughts on this you could share with me?

  • @Alexanderchocks sure, if you already have IfcFaces, you can do all the math yourself. However, keep in mind that those IfcFaces are in local coordinates, so to know which direction they actually are pointing in absolute coordinates, there's a bit of math you need to do - you'll need to consider any mapped instances and object placement orientation. Just like in all 3D programs you have local coordinates and global coordinates.

    The create_shape does all this work for you, and also handles geometries that don't use IfcFace, such as parametrically extruded profiles (very common in steel modeling, walls, slabs, etc).

    IFC does not store face normals so you won't find it in the schema. What are you after? Is there precalculated side areas in your quantity take off data? Maybe that's a shortcut.

  • @Moult the problem is, I would like to have something that could give me the information of a vertical face in an object. For example if I have a wall that needs to be painted. Since I would like to paint only the vertical faces of this wall, I would like to get only the vertical faces of the ifc file I have. I was thinking if maybe the ifc stores somewhere this kind of information.

    There is no precalculated side areas, it is just basically a simple wall model as an ifc file.

    I have this information. What I am a little bit cofused about is, what are this numbers from 0 to 9 represent when I print the faces? Does it say something about the amount of faces I have? Or which verts belong to which face? Is it possible to see the face with the associated verts? It is not difficult to calculate the normals, but I somehow don't understand how to organize this information here to do the actual calculation of the normals.

    element = ifc_file.by_type('IfcWall')[0]
    settings = ifcopenshell.geom.settings()
    shape = ifcopenshell.geom.create_shape(settings, element)
    faces = shape.geometry.faces
    verts = shape.geometry.verts
    print (faces)

    (2, 1, 0, 2, 3, 1, 7, 5, 4, 7, 4, 6, 5, 7, 8, 0, 8, 2, 0, 5, 8, 2, 8, 9, 2, 9, 3, 9, 1, 3, 4, 1, 9, 6, 4, 9, 6, 9, 8, 6, 8, 7, 4, 0, 1, 5, 0, 4)

    print (verts)

    (3.40561318397522, -0.5, 2.22044604925031e-16, 3.40561318397522, 0.5, -8.88178419700125e-16, 5.32907051820075e-15, -0.5, -2.22044604925031e-16, 5.32907051820075e-15, 0.5, -2.22044604925031e-16, 6.0, 0.5, 4.49360990524292, 6.0, -0.5, 4.49360990524292, 6.0, 0.5, 4.5, 6.0, -0.5, 4.5, 5.32907051820075e-15, -0.5, 4.5, 5.32907051820075e-15, 0.5, 4.5)

  • edited February 2022

    This is a standard 1D array definition of triangulated geometry. As you know a triangle is made of 3 vertices. So, given an array of all the vertices in the mesh, you can define a triangle by the indices of its three vertices in the mesh vertex array.
    Your first list is a flattened list of 3-uples defining triangles. Here's how to get the unflattened list :

    tris_1d = (2, 1, 0, 2, 3, 1, 7, 5, 4, 7, 4, 6, 5, 7, 8, 0, 8, 2, 0, 5, 8, 2, 8, 9, 2, 9, 3, 9, 1, 3, 4, 1, 9, 6, 4, 9, 6, 9, 8, 6, 8, 7, 4, 0, 1, 5, 0, 4)
    tris = [(tris_1d[i], tris_1d[i + 1], tris_1d[i + 2]) for i in range(0, len(tris_1d), 3)]
    print(tris)
    print(len(tris))
    

    [(2, 1, 0), (2, 3, 1), (7, 5, 4), (7, 4, 6), (5, 7, 8), (0, 8, 2), (0, 5, 8), (2, 8, 9), (2, 9, 3), (9, 1, 3), (4, 1, 9), (6, 4, 9), (6, 9, 8), (6, 8, 7), (4, 0, 1), (5, 0, 4)]
    16

    So this is an array defining exactly 16 triangles.
    The second list is a flattened 3-uple array of vertex coordinates.

    verts_1d = (3.40561318397522, -0.5, 2.22044604925031e-16, 3.40561318397522, 0.5, -8.88178419700125e-16, 5.32907051820075e-15, -0.5, -2.22044604925031e-16, 5.32907051820075e-15, 0.5, -2.22044604925031e-16, 6.0, 0.5, 4.49360990524292, 6.0, -0.5, 4.49360990524292, 6.0, 0.5, 4.5, 6.0, -0.5, 4.5, 5.32907051820075e-15, -0.5, 4.5, 5.32907051820075e-15, 0.5, 4.5)
    verts = [(verts_1d[i], verts_1d[i + 1], verts_1d[i + 2]) for i in range(0, len(verts_1d), 3)]
    print(verts)
    print(len(verts))
    

    [(3.40561318397522, -0.5, 2.22044604925031e-16), (3.40561318397522, 0.5, -8.88178419700125e-16), (5.32907051820075e-15, -0.5, -2.22044604925031e-16), (5.32907051820075e-15, 0.5, -2.22044604925031e-16), (6.0, 0.5, 4.49360990524292), (6.0, -0.5, 4.49360990524292), (6.0, 0.5, 4.5), (6.0, -0.5, 4.5), (5.32907051820075e-15, -0.5, 4.5), (5.32907051820075e-15, 0.5, 4.5)]
    10

    Here are your 10 vertices. They are accessed from index 0 to 9.

    tris_coords = [(verts[i], verts[j], verts[k]) for i, j, k in tris]
    print(tris_coords)
    

    [((5.32907051820075e-15, -0.5, -2.22044604925031e-16), ... , (3.40561318397522, 0.5, -8.88178419700125e-16))]

    And a face can be considered vertical if it's normal z component is equal to 0.

    I found a pretty straightforward way of getting a triangle normal there : https://blenderartists.org/t/getting-face-normals-from-python/309648/3

    def vecsub(a, b):
        return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
    
    def veccross(x, y):
        v = [0, 0, 0]
        v[0] = x[1]*y[2] - x[2]*y[1]
        v[1] = x[2]*y[0] - x[0]*y[2]
        v[2] = x[0]*y[1] - x[1]*y[0]
        return v
    
    def normal(v0, v1, v2):
        return veccross(vecsub(v0, v1),vecsub(v0, v2))
    
    
    for i, (v0, v1, v2) in enumerate(tris_coords):
        n_z = normal(v0, v1, v2)[2]
        if n_z < 10e-6:
            print(f"Triangle {i} is vertical")
    

    Triangle 0 is vertical
    Triangle 1 is vertical
    Triangle 2 is vertical
    Triangle 3 is vertical
    Triangle 4 is vertical
    Triangle 5 is vertical
    Triangle 6 is vertical
    Triangle 7 is vertical
    Triangle 11 is vertical
    Triangle 12 is vertical
    Triangle 14 is vertical
    Triangle 15 is vertical

    Now you just have to find a way to calculate the area of a 3D triangle :)
    BTW this would be easier if you tried to do it using Blender, even if headless from the command line. It has a bunch of builtin math modules to do theses calculations for you. Or even straight from the Blenderbim addon.

    Cheers

    vpajic
Sign In or Register to comment.