ifcopenshell scripting on IFC file loaded in BlenderBIM
Hi!
I just started to explore BlenderBIM and since I already have some scripting experience with IfcOpenShell in Python, I was looking if I could directly access the IFC file(s) loaded in Blender through BlenderBIM. I'm able to load any IFC file from my drive using IfcOpenShell in the Blender scripting environment, but I want to access the currently loaded IFC file(s) in Blender to be able to combine the UI from BlenderBIM and scripting whenever needed.
Best regards,
Mathias
Tagged:
Comments
This should get you started. BTW, you may be interested in the brand new
ifcopenshell.api
namespace - everything you can do in the BlenderBIM Add-on is now part of IfcOpenShell itself.thanks! I'm now able to read and write the IFC data directly from the file loaded with BlenderBIM :)
When I changed a property for testing, I could not see the change being propagated into the BlenderBIM GUI (but it's there when I export to IFC using the GUI). I believe I need to perform some kind of syncing between BlenderBIM and Blender? Is this the "authoring" mode from https://github.com/IfcOpenShell/IfcOpenShell/issues/1360#issuecomment-793351042? If so, how can I activate it? :)
The authoring mode handles syncing of visual operations only, but not when you're changing stuff via scripts.
When you're changing stuff via scripts, you need to decide for yourself when to refresh data for the BlenderBIM Add-on GUI. The data is cached in data classes (currently refactored into
ifcopenshell.api
namespace). You can either refresh data, or just purge the existing data cache, and the UI will detect the lack of a cache and fetch anew. If you're not running master, the data classes are something likeblenderbim.bim.module.foo.data
. They haveload()
andpurge()
functions which you can call.hmm, I not able to track down the correct data cache (BlenderBIM v210221). Can you provide an example? I loaded the IFC in the script from Blender and used IfcOpenShell to change a property:
Note: the namespace changes in the master to
ifcopenshell.api
. Hopefully this helps:You may also prefer to use the data loader to get data instead of writing lower level ifcopenshell. It may also be useful to use the usecases directly for editing. For example:
Benefits of doing it this way is:
The API is pretty fresh so it needs time to mature, but I highly recommend checking it out. The more people using it, the more we can polish it into a really slick interface and iron out the bugs so that future devs can write less code with more features, faster.
thanks, will check this out!
@Moult following is a test of this new ifcopenshell api. Let me know if I'm on the right track.
I'm not using any blender specific code yet, I'm hoping that there is some magic to conjure up blender geometry from this ifc data (or maybe it is the other way around, I'm clueless!). IfcOwnerHistory doesn't seem to work for me, though I haven't really dug into this. I think I can work with numpy matrices for transforms, is this recommended? There doesn't seem to be an api for assembling geometry, so I'm constructing a SweptSolid the old fashioned way, is this ok?
@brunopostle correct, the geometry.add_representation usecase is currently tightly coupled to Blender. The process, I would imagine, is to define multiple "adaptors" of the add_representation usecase that follow a defined interface, but cater to Blender, FreeCAD, Trimesh, etc. This work has not yet been done.
Adding a person and organisation is good, but you should in general never call the
owner.create_owner_history
usecase directly unless you're doing custom magic. Instead, it is simply used internally by the API for other usecases to call. Your responsibility, should you wish to use ownership histories (in IFC4, it is optional), is to overload or monkey-patch the functions inifcopenshell.api.owner.settings
. This way, you can determine yourself which owner is making which API call. Here's a simple case for you:This code looks unnecessary to me:
I think the issue is that you are first editing the placement, and then assigning the spatial container. The assign container usecase currently isn't clever enough to recalculate the placement to be relative. This is a bug. I will fix it. If you first assigned the container, and then edited the placement, then the PlacementRelTo will be correct.
Hope it helps.
@Moult thanks, very useful. Although I'm targeting blenderbim, I can see how in the short term I can just write code that generates an IFC file, as in the example - or are there any considerations I need to make? Is generating an IFC file or a blenderbim model (or a freecad model) just a matter of calling a different function at the end? I'm currently writing a temporary IFC file and importing it with blenderbim, but this is slow
@brunopostle the IFC model is the BlenderBIM Add-on model :) There is no difference anymore. Not sure what different function you might be referring to.
That's my understanding too! It is only that if I run the above script in the blender console I don't get a nice model in blenderbim, or IFC structure in the outliner, so I'm assuming there is a function to update the GUI.
@brunopostle correct. The
ifcopenshell.api
as the namespace suggests is agnostic of Blender. It allows anybody to author IFCs with a high-level API. The BlenderBIM Add-on then adds a graphical interface on top of theifcopenshell.api
functions, so that you can easily view results and interact with it graphically. You can also call the BlenderBIM Add-on's operators via script, so if you wanted to see your results created step-by-step in the Blender interface, you could call those instead, for examplebpy.ops.bim.create_project()
.Right now, there is no easy way to say "hey I've updated the underlying IFC, can you refresh what you have in the Blender scene?" via code as a general process. In the future, there will be, but I haven't built that yet. For specific changes, in particular non-geometric changes, you can indeed refresh the Blender UI by calling the load() function on the various Data classes. However, for geometric changes, it can be a bit more tricky. I can show you how if you're interested.
@Moult ok, it suits me to write everything outside of blender (as I can write tests, and restarting blender after every change is a real drag). For the time-being I'll continue using a temporary IFC file with ifc.write() and import_ifc.IfcImporter(), and I'll worry about doing it without a temporary file when I have this working.
@brunopostle agreed, it is desirable to do that. One of the main drivers to split the code outside Blender was to make sure it was testable and maintainable.
Hi @Moult ! related to this thread, I am trying to understand the new ifcopenshell.api after the refactor, but am struggling a little.
If I try to set up a property set for a dummy IfcSlab/Cube, I do get the pset on BlenderBIM after updating the UI, but not its property from the second api.run (life of 100 years in this case):
Would this be more or less the preferred way to add property sets programatically or am I messing something up?
Thanks in advance,
@cvillagrasa you've almost got it! Two mistakes:
properties
should beProperties
with a capitalP
.100 years
is not a valid duration. Durations are a special data type in IFC. See https://en.wikipedia.org/wiki/ISO_8601#Durations - the correct value would beP100Y
. Note that very soon it is likely we will build some utility functions for managing ISO8601 durations to make things like this simpler.Thanks a lot for the answer!
#1 would have definitely entertained me for a while, and it's good to learn about #2.
As a last step, I've also tried to update the UI with a tag_redraw, although I've desisted for now. I've tried as follows but it does not work:
Once in the window region of the properties area, I don't really know how to navigate down to the actual BIM_PT_object_psets panel, and the general tag_redraw seems to have no effect. But in any case, this is a very minor issue for now. Adding (to then delete) an additional pset does trigger the update.
@cvillagrasa the UI basically relies on IFC data cached in the relevant API data class. There is no need to navigate to any Blender UI region and do any fancy redraw function. Try this:
When using
How do I access the absolute file path of the IFC file?
Nevermind, found it. It's