[BlenderBIM] Rebar Geometry - annotations

edited October 2022 in General

Hello friends and fellow nerds.
Out on the building sites our rebar crew needs to get some information about the rebar when they fix them. I want to make, and place 3d mark-up annotations witch displays properties about the rebars. Alot like Solibris mark-up tool, but i need it to be an Ifc Annotation Object and a part of the Ifc.
I am pretty sure this can be done with blenderBIM.
But i have noe idea where to even start. I would really really appreciate som guidance :)

Not sure if the picture works, but it is a solibri mark-up

Comments

  • Are you OK with writing code to script this?

  • I have what i would call novice python skills. But i would love to give it a shot :D
    I am thinking it should be scripted as i would want it to be automated, it would be a pain placing all of these in all of our projects.

  • Essentially you'd loop through all rebar elements, and for each, fetch psets using ifcopenshell.util.element.get_psets() and create a new IfcAnnotation, and either just put whatever you wanted to label as a description in the IfcAnnotation, or if you really wanted a text representation, an IfcTextLiteral representation. Then relate the IfcAnnotation to the rebar with the drawing.assign_product API.

    See how many steps you can work out, and feel free to ask for more help if the description is too sparse. This might help https://blenderbim.org/docs-python/ifcopenshell-python/hello_world.html

    BalThorsGate
  • Thank you for the response! I'll give it a go, but don't be surprised if you hear from me again :)

  • Hello again good sir! I think i'm pretty close. The rebar loop and the entity creation works, but the realtion part i dont understand how to write.
    Could i bother you with an example on how to use it?

  • This part
    Then relate the IfcAnnotation to the rebar with the drawing.assign_product API.

  • for bar in rebar:
        barPsets = Element.get_psets(bar, psets_only= True)
        annotationData = {
        'GlobalId': ifcopenshell.guid.new(),
        'Name': bar.Name[:13],
        'Description' : barPsets['Pset_Prosjekt_Armering']['Shapecode']
        }
        ifcFile.create_entity('IfcAnnotation', **annotationData)``
    
  • Update!
    import ifcopenshell
    import ifcopenshell.util.element as Element
    import ifcopenshell.api.drawing.assign_product as Assign

    directory = ('C:\\Users\\johtho\\OneDrive - Backe\\04 Git_repos\\IFC_PARSER\\')
    
    ifcFile = ifcopenshell.open(r"C:\\Users\\johtho\\OneDrive - Backe\\04 Git_repos\\Ifc Rebar Annotation\\Ifc Rebar Annotations\\Liten ARMERINGSKLOSS.ifc")
    rebar = ifcFile.by_type('IfcReinforcingBar')
    annotations = ifcFile.by_type('IfcAnnotation')
    
    for bar in rebar:
        barPsets = Element.get_psets(bar, psets_only= True)
        annotationData = {
    
        'GlobalId': ifcopenshell.guid.new(),
        'Name': bar.Name[:13],
        'Description' : str(barPsets['Pset_Prosjekt_Armering']['Shapecode']) #this is just for testing
        }
        label = ifcFile.create_entity('IfcAnnotation', **annotationData)
        ifcopenshell.api.run("drawing.assign_product", ifcFile, relating_product=bar, related_object=label)
    

    I think i got the relationship to work, but i cant figure out how to add geometry to it (or make it visible)

    theoryshaw
  • I would also like to know, I also simpliefd your script a bit for sake of clarity and tested it on an IFC file with one single wall.

    @BalThorsGate
    You could also use IfcStore.path instead of using an absolute path:

    import ifcopenshell
    import ifcopenshell.util.element as Element
    import ifcopenshell.api.drawing.assign_product as Assign
    
    import blenderbim.bim.import_ifc
    from blenderbim.bim.ifc import IfcStore
    import blenderbim.tool as tool
    
    ifc_file = ifcopenshell.open(IfcStore.path)    
    walls = ifc_file.by_type('IfcWall')
    annotations = ifc_file.by_type('IfcAnnotation')
    
    for wall in walls:
    
        wall_psets = Element.get_psets(covering, psets_only= True)
    
        annotationData = { 'GlobalId': ifcopenshell.guid.new(),
                           'Name': wall.Name,
                           }
    
        label = ifc_file.create_entity('IfcAnnotation', **annotationData)
    
    
        ifcopenshell.api.run("drawing.assign_product", ifc_file, relating_product=wall, related_object=label)
    

    the label variable contains #1105=IfcAnnotation('0712T4SSX00w6QizK65_yx',$,'Wall',$,$,$,$) . But I can't manage to add it to the IFC file. I looked in the IFC file and can't find it.

    theoryshawBalThorsGate
  • geee..imagine a svg, where you can click on the rebar, and a html menu pops up with info about the rebar. I feel that is very doable.

    AceBalThorsGate
  • @theoryshaw said:
    geee..imagine a svg, where you can click on the rebar, and a html menu pops up with info about the rebar. I feel that is very doable.

    Now that would be something else! And i think our people in the pits would love it!

  • I'm not quite sure what i am looking at here. Sounds interesting though. Could you explain a bit more?

  • Great! So you've got the annotation and a relationship, now comes the text adding part. How do you want to do the text? The simplest approach is just to store it in the description attribute of the IfcAnnotation, but there's nothing that will show up in 3D.

    If you do want something to show up in 3D, then there's a lot of questions, like do you want 3D text? What viewer will you use? Which direction should the 3D text face? What size is the text? Or is it a non-scale specific size?

  • @Moult said:
    Great! So you've got the annotation and a relationship, now comes the text adding part. How do you want to do the text? The simplest approach is just to store it in the description attribute of the IfcAnnotation, but there's nothing that will show up in 3D.

    If you do want something to show up in 3D, then there's a lot of questions, like do you want 3D text? What viewer will you use? Which direction should the 3D text face? What size is the text? Or is it a non-scale specific size?

    Theses are the questions :D I do not have any good answers to this i am afraid. As to which direction to face the text. I could say toward you, but that is a pretty stupid answer.
    I got some screenshots from trimble connect on how i would like it to look. Theres a short video clip from trimple in the we transfer link.



    https://we.tl/t-rBKlkBmqEq

  • As for the viewer question, ill use whatever gets the job done :D We use Solibri for the most part. But the people on site uses trimble or 2d drawings on ipads.

  • @BalThorsGate

    ill use whatever gets the job done :D

    Is using Blender functionality an option? I was just experimenting with Blender to add text and then add the text to IFC. Might be a very stupid appraoch, but fun :-D

    import bpy
    import ifcopenshell
    import ifcopenshell.util.element as Element
    import ifcopenshell.api.drawing.assign_product as Assign
    
    import blenderbim.bim.import_ifc
    from blenderbim.bim.ifc import IfcStore
    import blenderbim.tool as tool
    
    import math
    from mathutils import Vector
    
    ifc_file = ifcopenshell.open(IfcStore.path)    
    walls = ifc_file.by_type('IfcWall')
    annotations = ifc_file.by_type('IfcAnnotation')
    
    for obj in bpy.context.view_layer.objects:
        if obj.name.startswith('IfcWall/'):
    
    
            x = obj.location.x
            y = obj.location.y
            z = obj.location.z
    
            for wall in walls:
                print (wall.Name)
    
                font_curve = bpy.data.curves.new(type="FONT", name="Font Curve")
                font_curve.body = wall.Name
                font_obj = bpy.data.objects.new(name=wall.Name, object_data=font_curve)
                bpy.context.scene.collection.objects.link(font_obj)
    
    
                bpy.data.objects[font_obj.name].location = Vector((x,y,z))
    


    BalThorsGate
  • @Coen said:
    @BalThorsGate

    ill use whatever gets the job done :D

    Is using Blender functionality an option? I was just experimenting with Blender to add text and then add the text to IFC. Might be a very stupid appraoch, but fun :-D

    import bpy
    import ifcopenshell
    import ifcopenshell.util.element as Element
    import ifcopenshell.api.drawing.assign_product as Assign
    
    import blenderbim.bim.import_ifc
    from blenderbim.bim.ifc import IfcStore
    import blenderbim.tool as tool
    
    import math
    from mathutils import Vector
    
    ifc_file = ifcopenshell.open(IfcStore.path)    
    walls = ifc_file.by_type('IfcWall')
    annotations = ifc_file.by_type('IfcAnnotation')
    
    for obj in bpy.context.view_layer.objects:
        if obj.name.startswith('IfcWall/'):
    
            
            x = obj.location.x
            y = obj.location.y
            z = obj.location.z
            
            for wall in walls:
                print (wall.Name)
                
                font_curve = bpy.data.curves.new(type="FONT", name="Font Curve")
                font_curve.body = wall.Name
                font_obj = bpy.data.objects.new(name=wall.Name, object_data=font_curve)
                bpy.context.scene.collection.objects.link(font_obj)
                
    
                bpy.data.objects[font_obj.name].location = Vector((x,y,z))
    


    Damn! That looks pretty good! Thank you so much! Ill give it a shot!

    Coen
  • If you want to export the fonts to IFC you will have to convert them to a mesh first I believe.

    BalThorsGate
  • edited October 2022

    Hoooooly crap! It worked! At least something popped up here :D

    But as you can see, there are some placement issues, and some size issues. All expected issues, but your annotations got placed right?
    And yes, i should figure out the ifcstore.path thing, but these other things are way to much fun :D
    `import bpy
    import ifcopenshell
    import ifcopenshell.util.element as Element
    import ifcopenshell.api.drawing.assign_product as Assign

    import blenderbim.bim.import_ifc
    from blenderbim.bim.ifc import IfcStore
    import blenderbim.tool as tool

    import math
    from mathutils import Vector

    ifcFile = ifcopenshell.open('C:\Users\johtho\OneDrive - Backe\04 Git_repos\Ifc Rebar Annotation\Ifc Rebar Annotations\Liten ARMERINGSKLOSS.ifc')
    rebars = ifcFile.by_type('IfcReinforcingBar')
    annotations = ifcFile.by_type('IfcAnnotation')

    for obj in bpy.context.view_layer.objects:
    if obj.name.startswith('IfcReinforcingBar/'):

        x = obj.location.x
        y = obj.location.y
        z = obj.location.z
    
        for rebar in rebars:
            print (rebar.Name)
    
            font_curve = bpy.data.curves.new(type="FONT", name="Font Curve")
            font_curve.body = rebar.Name
            font_obj = bpy.data.objects.new(name=rebar.Name, object_data=font_curve)
            bpy.context.scene.collection.objects.link(font_obj)
    
            bpy.data.objects[font_obj.name].location = Vector((x,y,z))`
    
    Coen
  • edited October 2022

    But as you can see, there are some placement issues, and some size issues. All expected issues, but your annotations got placed right?

    Yes, placement is quite hard for me. I think you would like to place/resize the labels perpendicualr to the normals of their objects. quite complex. I don't know where the origin points are of your rebar meshes. I have no experience with rebar modelling at all.
    I use the XYZ coordinates of these little orange dots (origin points) from the meshes to place the font objects.

    It's get quite messy as you can see

    But I'm doubting if this is the way to go, it "pollutes" the ifc a lot. unless you find a way to also easly remove/manage/maintain the labels

    Maybe @Gorgious has any ideas?

  • edited October 2022

    @BalThorsGate

    I've been experimenting a bit, I now get the center of each mesh and place the text there, if the mesh has a certain normal/rotation I like to place the text correspondingly, here's my WIP:

    import bpy
    import ifcopenshell
    import ifcopenshell.util.element as Element
    import ifcopenshell.api.drawing.assign_product as Assign
    
    import blenderbim.bim.import_ifc
    from blenderbim.bim.ifc import IfcStore
    import blenderbim.tool as tool
    
    import math
    import mathutils
    from mathutils import Vector
    
    #https://blender.stackexchange.com/questions/62040/get-center-of-geometry-of-an-object
    #https://blender.stackexchange.com/questions/129473/typeerror-element-wise-multiplication-not-supported-between-matrix-and-vect
    
    #get centre coordinates of mesh through bounding box
    obj = bpy.context.object
    local_bbox_center = 0.125 * sum((Vector(b) for b in obj.bound_box), Vector())
    global_bbox_center = obj.matrix_world @ local_bbox_center
    
    #get normals
    p = obj.data.polygons[0]
    
    #add the text
    font_curve = bpy.data.curves.new(type="FONT", name="Font Curve")
    font_curve.body = "wall.Name"
    font_obj = bpy.data.objects.new(name="wall.Name", object_data=font_curve)
    font_obj.data.size = 0.5
    
    bpy.context.scene.collection.objects.link(font_obj)
    
    #set text object
    bpy.data.objects[font_obj.name].location = Vector((global_bbox_center.x,global_bbox_center.y,global_bbox_center.z))
    
    #rotate text object through normal
    #https://blender.stackexchange.com/questions/19533/align-object-to-vector-using-python
    DirectionVector = mathutils.Vector(p.normal) 
    bpy.data.objects[font_obj.name].rotation_mode = 'QUATERNION'
    bpy.data.objects[font_obj.name].rotation_quaternion = DirectionVector.to_track_quat('X','Y')
    

    There's no implementation of IFC labeling yet.

    If you select a mesh and run this script it will add a font object which says "wall.Name"

    BalThorsGate
  • Wow! This is so amazing! It works! I am so grateful for all your help here, i am learning alot! But im also starting to see the challenges. Even so, i will keep on messing around with this when i get some freetime :D

    Coen
Sign In or Register to comment.