[IfcOpenShell][BlenderBIM] Creating an IfcGrid,IfcBuildingStorey,IfcSlab,IfcWall and youtube demo.

edited August 2022 in General

After reading this thread and seeing this post on a Freecad forum from 2016.

It made me wonder if I could create an .ifc with Python starting from the basics with a grid.
Conclusion, it seems I can, I barely changed the script and loaded the .ifc in BlenderBIM


Here is the python code:


See the python code
import os
import sys
import time
import uuid
import math

import ifcopenshell

O = 0., 0., 0.
X = 1., 0., 0.
Y = 0., 1., 0.
Z = 0., 0., 1.

create_guid = lambda: ifcopenshell.guid.compress(uuid.uuid1().hex)


file_name = 'grid.ifc'
timestamp = time.time()
timestring = time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(timestamp))
creator = "C. Claus"
organization = "Claus aannemingsmaatschappij"
application, application_version = "IfcOpenShell", "0.5"
project_globalid, project_name = create_guid(), "Grid"


# open for Blank
ifc_file = ifcopenshell.file()


#=============================================

org = ifc_file.createIfcOrganization()
org.Name = organization

app = ifc_file.createIfcApplication()
app.ApplicationDeveloper = org
app.Version = "3.2"
app.ApplicationFullName = "BlenderBIM"

person = ifc_file.createIfcPerson()
person.FamilyName="C. Claus"


person_org= ifc_file.createIfcPersonAndOrganization()
person_org.ThePerson=person
person_org.TheOrganization=org

owner_hist= ifc_file.createIfcOwnerHistory()
owner_hist.OwningUser = person_org
owner_hist.OwningApplication = app
owner_hist.ChangeAction= "NOCHANGE"
owner_hist.CreationDate= int(time.time())

#  Global unit definitions
LengthUnit = ifc_file.createIfcSIUnit()
LengthUnit.UnitType = "LENGTHUNIT"
LengthUnit.Prefix = "MILLI"
LengthUnit.Name="METRE"

#AreaUnit = ifc_file.createIfcSIUnit("AREAUNIT" , None, "SQUARE_METRE")
AreaUnit = ifc_file.createIfcSIUnit()
AreaUnit.UnitType = "AREAUNIT"
AreaUnit.Name="SQUARE_METRE"


VolumeUnit = ifc_file.createIfcSIUnit()
VolumeUnit.UnitType = "VOLUMEUNIT"
VolumeUnit.Name="CUBIC_METRE"


PlaneAngleUnit = ifc_file.createIfcSIUnit()
PlaneAngleUnit.UnitType = "PLANEANGLEUNIT"
PlaneAngleUnit.Name  ="RADIAN"

AngleUnit = ifc_file.createIfcMeasureWithUnit()
AngleUnit.UnitComponent =PlaneAngleUnit 
AngleUnit.ValueComponent = ifc_file.createIfcPlaneAngleMeasure(math.pi/180)


DimExp = ifc_file.createIfcDimensionalExponents(0,0,0,0,0,0,0)


ConvertBaseUnit = ifc_file.createIfcConversionBasedUnit()
ConvertBaseUnit.Dimensions = DimExp
ConvertBaseUnit.UnitType="PLANEANGLEUNIT"
ConvertBaseUnit.Name="DEGREE"
ConvertBaseUnit.ConversionFactor = AngleUnit


UnitAssignment=ifc_file.createIfcUnitAssignment([LengthUnit , AreaUnit , VolumeUnit ,ConvertBaseUnit])

axis_X = ifc_file.createIfcDirection(X)
axis_Y = ifc_file.createIfcDirection(Y)
axis_Z = ifc_file.createIfcDirection(Z)
Pnt_O = ifc_file.createIfcCartesianPoint(O)


# Defining project and representation contexts 
WorldCoordinateSystem = ifc_file.createIfcAxis2Placement3D()
WorldCoordinateSystem.Location=Pnt_O
WorldCoordinateSystem.Axis = axis_Z
WorldCoordinateSystem.RefDirection = axis_X

context = ifc_file.createIfcGeometricRepresentationContext()
context.ContextType = "Model"
context.CoordinateSpaceDimension = 3
context.Precision = 1.e-05
context.WorldCoordinateSystem = WorldCoordinateSystem


footprint_context = ifc_file.createIfcGeometricRepresentationSubContext()
footprint_context.ContextIdentifier = 'FootPrint'
footprint_context.ContextType = "Model"
footprint_context.ParentContext = context
footprint_context.TargetView = 'MODEL_VIEW'

myProject = ifc_file.createIfcProject(create_guid())
myProject.OwnerHistory = owner_hist
myProject.Name = "Test Grid"
myProject.RepresentationContexts = [context]
myProject.UnitsInContext = UnitAssignment


# Defining site, building and first story ------------
site_placement = ifc_file.createIfcLocalPlacement()
site_placement.RelativePlacement=WorldCoordinateSystem
mySite = ifc_file.createIfcSite( create_guid() )
mySite.OwnerHistory = owner_hist
mySite.Name = "My Site"
mySite.ObjectPlacement = site_placement
mySite.CompositionType="ELEMENT"

building_placement = ifc_file.createIfcLocalPlacement()
building_placement.PlacementRelTo = site_placement
building_placement.RelativePlacement = WorldCoordinateSystem

myBuilding = ifc_file.createIfcBuilding( create_guid(), owner_hist )
myBuilding.Name = "Test Building"
myBuilding.ObjectPlacement = building_placement
myBuilding.CompositionType="ELEMENT"

floor1_placement = ifc_file.createIfcLocalPlacement()
floor1_placement.PlacementRelTo = building_placement
floor1_placement.RelativePlacement = WorldCoordinateSystem

floor1 = ifc_file.createIfcBuildingStorey( create_guid(), owner_hist )
floor1.Name = "Floor 1"
floor1.ObjectPlacement = floor1_placement
floor1.CompositionType="ELEMENT"
floor1.Elevation = 1000


container_project = ifc_file.createIfcRelAggregates(create_guid() , owner_hist)
container_project.Name="Project Container"
container_project.RelatingObject = myProject 
container_project.RelatedObjects = [mySite]

container_site = ifc_file.createIfcRelAggregates(create_guid() , owner_hist)
container_site.Name = "Site Container"
container_site.RelatingObject = mySite
container_site.RelatedObjects = [myBuilding] 

container_storey = ifc_file.createIfcRelAggregates(create_guid() , owner_hist)
container_storey.Name = "Building Container"
container_storey.RelatingObject = myBuilding
container_storey.RelatedObjects = [floor1] 


#####################################################
###       Defining the grid axes geometry         ###
#####################################################
GridXList = [   {'id':'1' , 'distance':0.0 } ,
                {'id':'2' , 'distance':4000.0}  ]

GridYList = [   {'id':'A' , 'distance':0.0 } ,
                {'id':'B' , 'distance':4000.0}  ]

xMin = GridXList[0]['distance']-2000.0 ; xMax =  GridXList[-1]['distance']+2000.0 
yMin =  GridYList[0]['distance']-2000.0 ; yMax =  GridYList[-1]['distance']+2000.0 


polylineSet = []
gridX = []
for iGrid in GridXList:
    pnt1 = ifc_file.createIfcCartesianPoint( (iGrid['distance'],yMin) )
    pnt2 = ifc_file.createIfcCartesianPoint( (iGrid['distance'],yMax) )
    Line = ifc_file.createIfcPolyline( [pnt1 , pnt2] )
    polylineSet.append(Line)
    grid = ifc_file.createIfcGridAxis()
    grid.AxisTag = iGrid['id']
    grid.AxisCurve = Line
    grid.SameSense = True
    gridX.append(grid)

gridY = []
for iGrid in GridYList:
    pnt1 = ifc_file.createIfcCartesianPoint( (xMin ,iGrid['distance']) )
    pnt2 = ifc_file.createIfcCartesianPoint( (xMax,iGrid['distance']) )
    Line = ifc_file.createIfcPolyline( [pnt1 , pnt2] )
    polylineSet.append(Line)
    grid = ifc_file.createIfcGridAxis()
    grid.AxisTag = iGrid['id']
    grid.AxisCurve = Line
    grid.SameSense = True
    gridY.append(grid)

# Defining the grid 
PntGrid = ifc_file.createIfcCartesianPoint( O )

myGridCoordinateSystem = ifc_file.createIfcAxis2Placement3D()
myGridCoordinateSystem.Location= PntGrid
myGridCoordinateSystem.Axis = axis_Z
myGridCoordinateSystem.RefDirection = axis_X

grid_placement = ifc_file.createIfcLocalPlacement()
grid_placement.PlacementRelTo = floor1_placement
grid_placement.RelativePlacement = myGridCoordinateSystem

grid_curvedSet =  ifc_file.createIfcGeometricCurveSet(polylineSet)

gridShape_Reppresentation = ifc_file.createIfcShapeRepresentation()
gridShape_Reppresentation.ContextOfItems = footprint_context
gridShape_Reppresentation.RepresentationIdentifier = 'FootPrint'
gridShape_Reppresentation.RepresentationType = 'GeometricCurveSet'
gridShape_Reppresentation.Items = [grid_curvedSet]

grid_Reppresentation = ifc_file.createIfcProductDefinitionShape()
grid_Reppresentation.Representations  = [gridShape_Reppresentation]

myGrid = ifc_file.createIfcGrid(create_guid() , owner_hist)
myGrid.ObjectPlacement = grid_placement
myGrid.Representation = grid_Reppresentation
myGrid.UAxes=gridX
myGrid.VAxes=gridY

# assignment to spatial structure ------------------------------------------ 
container_SpatialStructure= ifc_file.createIfcRelContainedInSpatialStructure(create_guid() , owner_hist)
container_SpatialStructure.Name='BuildingStoreyContainer'
container_SpatialStructure.Description = 'BuildingStoreyContainer for Elements'
container_SpatialStructure.RelatingStructure = floor1
container_SpatialStructure.RelatedElements = [myGrid]


file_path = "C:\\Algemeen\\07_prive\\08_ifc_bestanden\\"
file_ifc = file_path  + file_name
print (file_ifc)
ifc_file.write(file_ifc)

How would I add the grid letter and number visibility in BlenderBIM? Like it is in BIMVision

theoryshaw

Comments

  • @Coen Is it an idea to start putting Snippets found here on the wiki?

  • @CadGiru said:
    @Coen Is it an idea to start putting Snippets found here on the wiki?

    i like that idea. Posting them to our https://gitlab.com/osarch/Example_Files repo, i think would be a better idea.
    ...
    @Coen noob question, is there anyway to run a script like this in BB... and have the results show 'live' in the 3D viewport? That is, instead of running the script, creating the IFC file, and then importing the IFC into BB.

  • @CadGiru said:
    @Coen Is it an idea to start putting Snippets found here on the wiki?

    That is probably a good idea,

    @theoryshaw said:
    @Coen noob question, is there anyway to run a script like this in BB... and have the results show 'live' in the 3D viewport? That is, instead of running the script, creating the IFC file, and then importing the IFC into BB.

    Live interaction with BlenderBIM would be great. BIMVision has this feature when a change is detected in IFC it prompts you to load the new version. Would be cool if BlenderBIM could do the same. I don't know if this is hard thing to do. I should look into it, I vaguely remember someone already made this before....? Or I dreamt it.

  • How would I add the grid letter and number visibility in BlenderBIM? Like it is in BIMVision

    How to do it via the UI... https://www.dropbox.com/s/ypcbn6nvxg5wmz3/2022-07-28_08-25-59_Blender_blender.mp4?dl=0

    Coen
  • @theoryshaw

    @Coen noob question, is there anyway to run a script like this in BB... and have the results show 'live' in the 3D viewport? That is, instead of running the script, creating the IFC file, and then importing the IFC into BB.

    I was thinking about this, I think I'm almost there.

    You could just put this line at the end of your script:

    bpy.ops.bim.load_project(filepath=file_ifc)
    

    And then then store the timestamp in a temporary variable, I need to do some more research on where it's stored usally in IFC and catch the exceptions, I now do relatively dumb string parsing, which is not really fool proof...

    def get_timestamp():
        ifc_file = ifcopenshell.open(IfcStore.path)
    
        with open(IfcStore.path) as ifc_text:
            for line_no, line_file in enumerate(ifc_text):
                if line_no  == 3:
                    if line_file.startswith("FILE_NAME"):
                        time_stamp = (line_file.split(',')[1])
    
        print (time_stamp)
    
    
    
    get_timestamp()   
    
    bpy.ops.bim.reload_ifc_file()
    

    If the user clicks save project, or somehow it detects the ifc file is being overwritten. It should start comparing the time stamps, if a difference in time stampts is detected it should unload the old ifc and load the the new ifc.

    theoryshaw
  • Just created a little workaround, this works, but be very careful! it throws an entire blender collection away where the IFC is located. Only store things in IFC and don't save the Blender file.

    project = ifc_file.by_type('IfcProject')
    
    for i in project:
        collection_name = 'IfcProject/' + i.Name
    
    collection = bpy.data.collections.get(str(collection_name))
    
    for obj in collection.objects:
        bpy.data.objects.remove(obj, do_unlink=True)
    
    bpy.data.collections.remove(collection)
    bpy.ops.bim.load_project(filepath=file_ifc)
    

    If you copy paste this at the end of your IfcOpenShell python scripts it automatically load the IFC file in BlenderBIM (Taking it you're coding in BlenderBIM ofcourse)..

  • nice.. this noob will play around. :)


  • Seems to work... 😁

    theoryshawvpajic
  • edited August 2022

    Did some refactoring of creating an IfcGrid, now you can change the grid amount and grid distance through a function:

    Code to be found here:
    https://github.com/C-Claus/BlenderScripts/blob/master/BlenderBIMGrid/create_grid_refactored_clean.py
    Some-auto generated results:


    vpajictheoryshaw
  • Next step, trying to create an IfcSlab through IfcOpenShell and add it to certain grid points. Probably worth another thread.

  • edited August 2022

    @Coen said:
    Next step, trying to create an IfcSlab through IfcOpenShell and add it to certain grid points. Probably worth another thread.

    i'm curious how this could be codified in the IFC, to survive an IFC roundtrip.
    Could it be through entitles like the following?

  • @Coen a few suggestions here
    I removed IFCPRODUCTDEFINITIONSHAPE and IFCGEOMETRICCURVESET, since the native gridlines in BB don't have these entities associated with them.
    You might have had a good reason to include them, if so, please disregard. I'm mostly doing this for practice. :)
    Best, Ryan

    Coen
  • It also looks like the IFCLOCALPLACEMENT is different. Not sure which one's right... local placement confuses me a little.

    In the create_grid_refactored_clean.py script...

      /*#101=IFCGRID('2dgA7o4TeHxRPiIF5$qabM',#5,$,$,$,#97,#100,(#46,#50,#54,#58),(#62,#66,#70,#74,#78,#82,#86,#90,#94),$,$);*/
        /*#97=IFCLOCALPLACEMENT(#38,#96);*/
          /*#38=IFCLOCALPLACEMENT(#32,#37);*/
            /*#32=IFCLOCALPLACEMENT(#26,#31);*/
              /*#26=IFCLOCALPLACEMENT($,#25);*/
                /*#25=IFCAXIS2PLACEMENT3D(#22,#23,#24);*/
                  /*#22=IFCCARTESIANPOINT((0.,0.,0.));*/
                  /*#23=IFCDIRECTION((0.,0.,1.));*/
                  /*#24=IFCDIRECTION((1.,0.,0.));*/
              /*#31=IFCAXIS2PLACEMENT3D(#28,#29,#30);*/
                /*#28=IFCCARTESIANPOINT((0.,0.,0.));*/
                /*#29=IFCDIRECTION((0.,0.,1.));*/
                /*#30=IFCDIRECTION((1.,0.,0.));*/
            /*#37=IFCAXIS2PLACEMENT3D(#34,#35,#36);*/
              /*#34=IFCCARTESIANPOINT((0.,0.,0.));*/
              /*#35=IFCDIRECTION((0.,0.,1.));*/
              /*#36=IFCDIRECTION((1.,0.,0.));*/
          /*#96=IFCAXIS2PLACEMENT3D(#95,#16,#14);*/
            /*#95=IFCCARTESIANPOINT((0.,0.,0.));*/
            /*#16=IFCDIRECTION((0.,0.,1.));*/
            /*#14=IFCDIRECTION((1.,0.,0.));*/
    
    

    In native BB....

    #60=IFCGRID('1FWhmuU9jB0u2KIDhbgjcq',$,'Grid',$,$,#71,$,(#72,#76,#80),(#84,#88,#92),$,$);
      /*#71=IFCLOCALPLACEMENT(#47,#70);*/
        /*#47=IFCLOCALPLACEMENT($,#46);*/
          /*#46=IFCAXIS2PLACEMENT3D(#43,#44,#45);*/
            /*#43=IFCCARTESIANPOINT((0.,0.,0.));*/
            /*#44=IFCDIRECTION((0.,0.,1.));*/
            /*#45=IFCDIRECTION((1.,0.,0.));*/
        /*#70=IFCAXIS2PLACEMENT3D(#67,#68,#69);*/
          /*#67=IFCCARTESIANPOINT((0.,0.,0.));*/
          /*#68=IFCDIRECTION((0.,0.,1.));*/
          /*#69=IFCDIRECTION((1.,0.,0.));*/
    
    Coen
  • edited August 2022

    @theoryshaw
    Thanks for the info, I thought BlenderBIM had no curve support? But it seem to export succesfully.
    I am now placing beams on the grid as I seen in the code from @BIMrookie92

    Some screenshots of auto generated results:

    BlenderBIM is so insanely fast with creating an entire IFC model and loading it....When I click run script it almost creates the geometry instantly.

    Also make it easy to place columns along a grid,

    Ace
  • @theoryshaw

    i'm curious how this could be codified in the IFC, to survive an IFC roundtrip.

    Me as well, the method I'm using now is just removing and rewriting the entire IFC in BlenderBIM. (seems to work, because BlenderBIM is insanely fast with loading an IFC).

    I made some little experiments with a IfcWall and IfcSlab, but I barely can't find any good Python documentation on how to create geometry with IfcOpenShell... Or maybe I am looking in the wrong places?. The only sources I used are the FreeCAD Forum, snippets from this forum and ifcopenshell academy. It's a lot of trial and error... and reading BuildingSmart documentation and logically trying to translate it to python code.

    Anyway some results:

    IfcWall placement moves if you change the slab thickness.

    theoryshawNigel
  • edited August 2022

    Imagine if IFC allowed us to do this?! :)

    Coen
  • I managed to get a slab and beam system to move along with the grid, probaly in a stupid way but it works.
    Still don't know how to create a IfcWall from a curve2D in ifcopenshell. 😥


  • Managed to create 1000 storey slabs. 😁

    Just amazing how fast BlenderBIM is with creating and loading...

  • For now I finished playing around with ifcopenshell and python :-)

    Here is the refactored code:
    https://github.com/C-Claus/BlenderScripts/blob/master/BlenderBIMGrid/create_grid_with_slabs_and_building_stories.py

    Removed a lot of stupid mistakes and unnecessary variables. Tried to keep it as simple as possible
    Scripts allow for creation of grids/building storeys and IfcSlabs created in IfcOpenShell and loaded in BlenderBIM. I think it could maybe serve as a basis for other things? . I highly appreciate feedback :-).

    And a screenshot:

    Don't know if this is worth a youtube demo?

    theoryshawvpajicGorgiousrogerioantoniomotaChamma
  • @Coen you do a lot of cool work, do the YouTube please. It helps people like me and closes off your mini project nicely

    vpajicCoen

  • It's kind of a challenge to create as much geometry as possible with as little config parameters as possible

    AceNigeltheoryshawbruno_perdigaoJesusbill
  • Hi @Coen this is cool, I downloaded the earlier code that makes the grids and builds the floors, thank you. Now I'm really interested in how the walls get built

    theoryshaw
  • @Nigel

    @Coen you do a lot of cool work, do the YouTube please. It helps people like me and closes off your mini project nicely

    Thanks, I made a youtube video.
    The code is to be found here.
    I tested it thoroughly, everything in this image should be easily adjustable through the python script, with the following parameters:

    filename                    = "demo.ifc"
    folder_path                 = "C:\\Algemeen\\07_prive\\08_ifc_bestanden\\"
    
    building_storeys_amount     = 2         # is the n number of building storeys, can't be 0 or less than 0
    elevation                   = 0.0       # is where the first of the building storeys start
    building_storey_height      = 3000      # is the equal distance between the building storeys
    
    grids_x_direction_amount    = 5        # is the n number of grids in x direction
    grids_y_direction_amount    = 5         # is the n number of grids in y direction
    grids_x_distance_between    = 1000.0     # is the distance between the x grids, always should be a float
    grids_y_distance_between    = 1000.0    # is the distance between the y grids, always should be a float
    grid_extends                = 2000.0    # is the distance on how much the grid extends
    
    slab_thickness              = 200.0  
    wall_interior_thickness     = 200.0
    wall_exterior_thickness     = 100.0
    wall_covering_thickness     = 150.0
    cavity_thickness            = 200.0
    slab_covering_thickness     = 150.0
    foundation_beam_height      = 1000.0
    

    I made this script because I wanted to learn ifcopenshell, the idea was it to keep it as simple as possible so end users could maybe one day make a parametric grid, building storey, walls, which are modular. Everything is referenced from the (0,0,0) point.
    I don't know where to take it from here, I could start coding an entire building with ifcopenshell, but the practicality of it seem to get lost.

    Plus the homemaker add-on from @brunopostle already does this way better :-).
    All the sources for the ifcopenshell code I uses were relatively old, forum posts from 2015 and such.
    But this code could serve to make a structural basis for modeling, or for people who want to learn ifcopenshell as I did myself.

    AceMartin156131theoryshawMoultcvillagrasaNigelCadGirurogerioantoniomota
  • This would be great to share on social media! By the way, IfcGridPlacement would be how to link objects to a grid's placement. However, it is not supported in IfcOpenShell.

    Coen
  • edited November 2022

    @Moult said:
    This would be great to share on social media! By the way, IfcGridPlacement would be how to link objects to a grid's placement. However, it is not supported in IfcOpenShell.

    Any news on it? I believe, I can create IfcGridPlacement instead of IfcLocalPlacement and use it for IfcBuilding placement in ifcopenshell. But BlenderBIM couldn't load such IFC:

    Coen
  • Well, I think I’ve found solution for myself. Just threw some middle-school equations in and now finding axes intersections explicitly:

    def find_axes_intersection(a1, a2):
        p11 = a1.AxisCurve.Points[0]
        p12 = a1.AxisCurve.Points[1]
        p21 = a2.AxisCurve.Points[0]
        p22 = a2.AxisCurve.Points[1]
        z0 = p11.Coordinates[2]
        x11 = p11.Coordinates[0]
        x12 = p12.Coordinates[0]
        y11 = p11.Coordinates[1]
        y12 = p12.Coordinates[1]
        x21 = p21.Coordinates[0]
        x22 = p22.Coordinates[0]
        y21 = p21.Coordinates[1]
        y22 = p22.Coordinates[1]
        A1 = y12 - y11
        B1 = x12 - x11
        C1 = y11 * (x12 - x11) - x11 * (y12 - y11)
        A2 = y22 - y21
        B2 = x22 - x21
        C2 = y21 * (x22 - x21) - x21 * (y22 - y21)
        x0 = (B1 * C2 - B2 * C1) / (A1 * B2 - A2 * B1)
        y0 = (C1 * A2 - C2 * A1) / (A1 * B2 - A2 * B1)
        return [x0,y0,z0]
    
    def create_customgridplacement(axis1, axis2, dir1=globalAxisZ, dir2=globalAxisX):
        point = ifc.createIfcCartesianPoint(find_axes_intersection(axis1, axis2))
        axis2Placement = ifc.createIfcAxis2Placement3D(point, dir1, dir2)
        localPlacement = ifc.createIfcLocalPlacement(None, axis2Placement)
        return localPlacement
    
    Coen
  • When opening the IFC the Grids are contained to the site, from models exported from different sources I always see them related to the building storey, is there a reason why you've chosen to relate it to the site?

  • @Pahlawan

    is there a reason why you've chosen to relate it to the site?

    No specific reason, intuivitely seemed to be the most logic place.

  • @Coen said:
    @Pahlawan

    is there a reason why you've chosen to relate it to the site?

    No specific reason, intuivitely seemed to be the most logic place.

    Yeah also seems to work good if you add other models in for example Solibri the grids will be there on multiple floors if that model has elements on that floor. Strangely does not work when there are only slabs in the model, it’ll only project on the first floor. Don’t know if that’s a feature or a bug though.

  • Python code for create ifcGrid direct on BlenderBIM

     """
      #bpy.ops.bim.new_project(preset="metric_mm")
      Test_Create_Grid_01.py
    
    """
    
    import bpy
    import blenderbim.tool as tool
    import ifcopenshell
    
    from mathutils import Vector
    
    site = tool.Ifc.get().by_type("IfcSite")
    site = site[0]
    site_obj = tool.Ifc.get_object(site)
    
    obj = bpy.data.objects.new("Grid", None)
    obj.name = "Grid"
    
    collection = site_obj.BIMObjectProperties.collection
    collection.objects.link(obj)
    
    bpy.ops.bim.assign_class(obj=obj.name, ifc_class="IfcGrid")
    grid = tool.Ifc.get_entity(obj)
    
    collection = obj.BIMObjectProperties.collection
    
    
    GridXList = [   {'id':'1' , 'distance':0.0 } ,
                    {'id':'2' , 'distance':4   },  
                    {'id':'3' , 'distance':7   },  ]
    
    GridYList = [   {'id':'A' , 'distance':0.0 } ,
                    {'id':'B' , 'distance':3.5 },
                    {'id':'C' , 'distance':5.5 },
                    {'id':'D' , 'distance':9.5},]
    
    common_keys = set.intersection(*map(set, GridXList))
    v = {k: [dic[k] for dic in GridXList] for k in common_keys}
    maxX = max(v['distance'])
    minX = min(v['distance'])
    
    common_keys = set.intersection(*map(set, GridYList))
    v = {k: [dic[k] for dic in GridYList] for k in common_keys}
    maxY = max(v['distance'])
    minY = min(v['distance'])
    
    
    axes_collection1 = bpy.data.collections.new("UAxes")
    collection.children.link(axes_collection1)
    
    
    for iGrid in GridYList:
        id = iGrid['id']
        y = iGrid['distance']
        verts = [
            Vector(( minX-2, y ,0)),
            Vector(( maxX+2, y ,0)),
        ]
        print(verts)
        edges = [[0, 1]]
        faces = []
        mesh = bpy.data.meshes.new(name="Grid Axis")
        mesh.from_pydata(verts, edges, faces)
        tag = id
        obj = bpy.data.objects.new(f"IfcGridAxis/{tag}", mesh)
        axes_collection1.objects.link(obj)
        result = ifcopenshell.api.run(
            "grid.create_grid_axis",
            tool.Ifc.get(),
            **{"axis_tag": tag, "uvw_axes": "UAxes", "grid": grid},
        )
        tool.Ifc.link(result, obj)
        ifcopenshell.api.run("grid.create_axis_curve", tool.Ifc.get(), **{"axis_curve": obj, "grid_axis": result})
        obj.BIMObjectProperties.ifc_definition_id = result.id()
    
    axes_collection2 = bpy.data.collections.new("VAxes")
    collection.children.link(axes_collection2)
    
    for iGrid in GridXList:
        id = iGrid['id']
        x = iGrid['distance']
        verts = [
            Vector(( x , minY-2, 0)),
            Vector(( x , maxY+2, 0)),
        ]
        print(verts)
        edges = [[0, 1]]
        faces = []
        mesh = bpy.data.meshes.new(name="Grid Axis")
        mesh.from_pydata(verts, edges, faces)
        tag = id
        obj = bpy.data.objects.new(f"IfcGridAxis/{tag}", mesh)
        axes_collection2.objects.link(obj)
        result = ifcopenshell.api.run(
            "grid.create_grid_axis",
            tool.Ifc.get(),
            **{"axis_tag": tag, "uvw_axes": "VAxes", "grid": grid},
        )
        tool.Ifc.link(result, obj)
        ifcopenshell.api.run("grid.create_axis_curve", tool.Ifc.get(), **{"axis_curve": obj, "grid_axis": result})
        obj.BIMObjectProperties.ifc_definition_id = result.id()
    
    
    steverugiCoenArv
Sign In or Register to comment.