Error in element placement

Hi everyone,

I am using** ifc openshell to create an IFC model** from custom geometry data.
Everything works fine but one error occasionally appears randomly.

The two buildings are created in exactly the same manner but the placement of the one roof appears to be the other way round and it's hard to debug it. Does someone maybe know why?
Or what also might help: Would it be possible to set the top elevation of the element in the code using ifc openshell?
That's the only thing that is different from the two roofs when I open the model in BIM collab.


My code for making the roofs:

def make_roof(ifcfile, owner_history, context, storey, roof, index, height, roofThickness=0.001, z_pos=0.0):
    roof_curve = roof['data']['roofCurves'][index]
    rel_pts = roof['data']['options']['relativePts'][index]
    rel_pts = convert_points(rel_pts)
    inclination = roof['data']['options']['inclinations'][index]
    x_dir = roof['data']['options']['xDirs'][index]
    x_vec = mathutils.Vector((x_dir['data']['x'], x_dir['data']['y'], x_dir['data']['z']))
    z_rot = calculate_rotation_angle(mathutils.Vector((1.0, 0.0, 0.0)), x_vec)

    roof_placement = hf.create_ifclocalplacement(ifcfile, point=(0.,0.,0.))
    polyline = hf.create_ifcpolyline(ifcfile, rel_pts)
    axis_representation = ifcfile.createIfcShapeRepresentation(context, "Axis", "Curve2D", [polyline])

    rotation_matrix = Matrix.Rotation(np.radians(90 - inclination), 4, 'X')
    rotated_vector = rotation_matrix @ mathutils.Vector((0, 1, 0))
    extrusion_dir = (float(rotated_vector[0]), float(rotated_vector[1]), float(rotated_vector[2]))

    height = height * (-1)
    height = height * (-1)
    extrusion_placement = hf.create_ifcaxis2placement(ifcfile, (0.0, 0.0, float(height + z_pos)), (0., 0., 1.0), (1., 0., 0.))

    solid = hf.create_ifcextrudedareasolid(ifcfile, rel_pts, extrusion_placement, extrusion_dir, -roofThickness)
    body_representation = ifcfile.createIfcShapeRepresentation(context, "Body", "SweptSolid", [solid])
    product_shape = ifcfile.createIfcProductDefinitionShape(None, None, [axis_representation, body_representation])
    roof_element = ifcfile.createIfcSlab(hf.create_guid(), owner_history, "Slab", "Roof", None, roof_placement, product_shape, None)
    ifcopenshell.api.run("spatial.assign_container", ifcfile, relating_structure=storey, product=roof_element)

    # Rotation matrix around the X axis
    matrixRotX = np.eye(4)
    matrixRotX[1][1] = np.cos(inclination * np.pi / 180)
    matrixRotX[1][2] = -np.sin(inclination * np.pi / 180)
    matrixRotX[2][1] = np.sin(inclination * np.pi / 180)
    matrixRotX[2][2] = np.cos(inclination * np.pi / 180)

    # Rotation matrix around the Z axis
    matrixRotZ = np.eye(4)
    matrixRotZ[0][0] = np.cos(z_rot * np.pi / 180)
    matrixRotZ[0][1] = -np.sin(z_rot * np.pi / 180)
    matrixRotZ[1][0] = np.sin(z_rot * np.pi / 180)
    matrixRotZ[1][1] = np.cos(z_rot * np.pi / 180)

    roof_pt0 = convert_points(roof['data']['pts'], two_d=False)[0]
    roof_curve_pt0 = convert_points(roof_curve['data']['pts'], two_d=False)[0]
    z = roof_curve_pt0[2] -  roof_pt0[2]

    vec1 = mathutils.Vector((0.0, 0.0, 0.0))
    roof_pt0 = convert_points(roof_curve['data']['pts'], two_d=False)[0]
    # vec2 = mathutils.Vector((roof_pt0[0], roof_pt0[1], height))
    vec2 = mathutils.Vector((roof_pt0[0], roof_pt0[1], z))

    # Translation matrix
    matrixTransl = np.eye(4)
    matrixTransl[0][3] = vec2[0] - vec1[0]
    matrixTransl[1][3] = vec2[1] - vec1[1]
    matrixTransl[2][3] = vec2[2] - vec1[2]

    matrix_combined = np.matmul(np.matmul(matrixTransl, matrixRotZ), matrixRotX)

    ifcopenshell.api.run("geometry.edit_object_placement",
        ifcfile, product=roof_element, matrix=matrix_combined
    )

Thank you in advance!

Comments

  • It's hard to tell without looking at your resultant IFC so we can see exactly what's causing the location to be down there.

    There's also no such thing as a "Top Elevation" or "Bottom Elevation" etc. Those values are dynamically computed by your IFC viewer and are not explicitly present at all in your IFC model so there is no way to "set" it.

  • Thanks for your answer @Moult
    Is there sth that I could provide to "see" it better?
    The IFC would be the attached one.

  • Cheers, I don't see any roof in that model. I was expecting to see one correct roof and one wrong roof, so I could compare them and know how to debug it.

    I'd recommend using the BlenderBIM Add-on along with the built-in BlenderBIM IFC Debug tools (imagine a web inspector for IFC objects).

  • Ah sorry for the inconvenience!
    Maybe that's a Blender BIM tolerance issue - I am extruding a very tiny amount to get a surface.
    In the attached model here, it's extruded more to get the roof slabs.

  • edited August 2023

    Still the same. I don't see any IfcRoof at all. Is there an element name / global ID I can use to select?

    Note your model has lots of validation problems, for example this issue where you have a negative extrusion. Have you considered using more IfcOpenShell utils / API which can help protect you against these problems?

    2023-08-15 18:58:56,253    ERROR rule_executor.py 176 On instance:
        #4270=IfcExtrudedAreaSolid(#4268,#4259,#4269,-0.2)
    Rule IfcPositiveLengthMeasure.WR1:
        (self > 0.0)
    Violated by:
        (-0.2 > 0.0)
    
  • I "modelled" it as an IFCSlab and gave the description roof.
    Can you see it as that?


    The GUID of the wrongly placed element is: 06kSv2EqGHxelJPDQQu67Q

    Thanks I will remeber that!
    I tried to use IfcOpenShell utils / API as much as possible but at least for me I found the **ifclocalplacement ** handy for move elements to origin, rotating / extruding it there and moving them back - I am just doing this for roofs and sloped walls.
    Didn't find another option for this ...

  • Ah thanks I found it. Yes indeed your extrusions are negative. This is not allowed. If other viewers display it, it's purely just "random behaviour" since it is invalid.

    You might consider using ifcopenshell.util.placement for easy rotation matrixes as well as ifcopenshell.util.shape_builder for easy extrusions, translations, mirroring, etc.

  • Ah, nice to know thanks!!

    But I still have this error for the incorrect placement of one of the roofs/ slabs
    I don't think it has to do with the negative extrusion. I changed it to be positive but still having the one roof placed differently

  • The negative extrusion is probably just a symptom of a deeper problem in the way your code deals with vectors. At a guess without looking too deeply, I'd say your calculated matrixRotX isn't what you want. See this screenshot of how the object placement differs between the two slabs.

  • A few more pretty critical mistakes you might like to fix too:

    axis_representation = ifcfile.createIfcShapeRepresentation(context, "Axis", "Curve2D", [polyline])
    

    You should not use the same context here, nor should a slab have an Axis. This may even cause your roofs to be invisible in some viewers. By the way this might be a good article if you haven't seen it: https://blenderbim.org/docs-python/ifcopenshell-python/geometry_creation.html

  • Yes the different, object placement is my main problem.
    If I log the x-rotation matrices there are the same and also fixed the negative extrusion directions but still getting the same result.

    Would there be a dirty way to fix it by just setting the roof at the correct position and not relative to the floor where it is contained.

    I also see this for the different last stories. Don't know if its a problem because global z is the same

  • From your screenshot the X rotation matrixes are not the same.

    Also ifcopenshell.api.run("geometry.edit_object_placement") is already in absolute coordinates, not relative coordinates.

Sign In or Register to comment.