Skip to content
This repository was archived by the owner on Nov 24, 2024. It is now read-only.

Commit 3104743

Browse files
authored
Merge pull request #1 from IfcOpenShell/v0.6.0
Upstream update
2 parents 70fcbfa + 18d7193 commit 3104743

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+3057
-564
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# Dependency and build folders created by the build scripts
2+
/_build-vs2017-x64/
3+
/_deps-vs2017-x64-installed/
4+
/_deps/
25
/deps*/
36
/build*/
47
/install*/
@@ -23,3 +26,5 @@ __pycache__
2326
*.mo
2427
# Vim
2528
*.swp
29+
30+

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Prerequisites
1919
Dependencies
2020
-------------
2121
* [Boost](http://www.boost.org/)
22-
* [Open Cascade](http://opencascade.org) - *optional*, but required for building IfcGeom
23-
([official](http://www.opencascade.org/getocc/download/loadocc/), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
22+
* [Open Cascade](https://dev.opencascade.org/) - *optional*, but required for building IfcGeom
23+
([official](https://dev.opencascade.org/release), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
2424
For converting IFC representation items into BRep solids and tesselated meshes
2525
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
2626
For IfcConvert to be able to write tessellated Collada (.dae) files
@@ -101,7 +101,7 @@ Note: where `make -j` is written, add a number roughly equal to the amount of CP
101101
$ make -j
102102
$ sudo make install
103103

104-
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
104+
**2c)** or obtain and compile OCCT from https://dev.opencascade.org/release
105105

106106
**3)** For building IfcConvert with COLLADA (.dae) support (on by default), OpenCOLLADA is needed:
107107

src/blenderbim/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,20 @@ endif
177177
cp -r dist/working/svgwrite-1.3.1/svgwrite dist/blenderbim/libs/site/packages/
178178
rm -rf dist/working
179179

180+
# Provides fuzzy date parsing for construction sequencing
181+
mkdir dist/working
182+
cd dist/working && wget https://files.pythonhosted.org/packages/be/ed/5bbc91f03fa4c839c4c7360375da77f9659af5f7086b7a7bdda65771c8e0/python-dateutil-2.8.1.tar.gz
183+
cd dist/working && tar -xzvf python-dateutil*
184+
cp -r dist/working/python-dateutil-2.8.1/dateutil dist/blenderbim/libs/site/packages/
185+
rm -rf dist/working
186+
187+
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
188+
mkdir dist/working
189+
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
190+
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
191+
cp dist/working/jsgantt* dist/blenderbim/bim/data/gantt/
192+
rm -rf dist/working
193+
180194
# Required by IFCDiff
181195
mkdir dist/working
182196
cd dist/working && wget https://github.com/Moult/deepdiff/archive/master.zip

src/blenderbim/blenderbim/bim/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ def register():
173173
bpy.app.handlers.load_post.append(handler.setDefaultProperties)
174174
bpy.app.handlers.load_post.append(handler.loadIfcStore)
175175
bpy.app.handlers.save_pre.append(handler.ensureIfcExported)
176-
bpy.app.handlers.save_pre.append(handler.storeIdMap)
177176
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
178177
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
179178
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
@@ -200,7 +199,6 @@ def unregister():
200199
bpy.utils.unregister_class(cls)
201200
bpy.app.handlers.load_post.remove(handler.setDefaultProperties)
202201
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
203-
bpy.app.handlers.save_pre.remove(handler.storeIdMap)
204202
bpy.app.handlers.save_pre.remove(handler.ensureIfcExported)
205203
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
206204
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<link href="jsgantt.css" rel="stylesheet" type="text/css"/>
2+
<script src="jsgantt.js" type="text/javascript"></script>
3+
<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
4+
<script type="text/javascript">
5+
var g = new JSGantt.GanttChart(document.getElementById('GanttChartDIV'), 'day');
6+
var json_data = `
7+
{{{json_data}}}
8+
`;
9+
JSGantt.parseJSONString(json_data, g);
10+
g.Draw();
11+
</script>

src/blenderbim/blenderbim/bim/export_ifc.py

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import ifcopenshell
99
import ifcopenshell.util.placement
1010
import ifcopenshell.api
11+
from ifcopenshell.api.spatial.data import Data as SpatialData
1112
from blenderbim.bim.ifc import IfcStore
1213
import addon_utils
1314

@@ -46,9 +47,6 @@ def export(self):
4647
jsonData = ifcjson.IFC2JSON5a(self.file, self.ifc_export_settings.json_compact).spf2Json()
4748
with open(self.ifc_export_settings.output_file, "w") as outfile:
4849
json.dump(jsonData, outfile, indent=None if self.ifc_export_settings.json_compact else 4)
49-
if bpy.context.scene.BIMProjectProperties.is_authoring:
50-
if bpy.data.filepath:
51-
bpy.ops.wm.save_mainfile()
5250

5351
def set_header(self):
5452
# TODO: add all metadata, pending bug #747
@@ -79,16 +77,19 @@ def sync_object_placements_and_deletions(self):
7977
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
8078
to_delete = []
8179

82-
for guid, obj in IfcStore.guid_map.items():
80+
for ifc_definition_id, obj in IfcStore.id_map.items():
8381
try:
8482
self.sync_object_placement(obj)
85-
except:
86-
pass
87-
if self.should_delete(guid, obj):
88-
to_delete.append(guid)
83+
self.sync_object_container(ifc_definition_id, obj)
84+
except ReferenceError:
85+
pass # The object is likely deleted
86+
if self.should_delete(obj):
87+
to_delete.append(ifc_definition_id)
8988

90-
for guid in to_delete:
91-
product = self.file.by_id(guid)
89+
SpatialData.purge()
90+
91+
for ifc_definition_id in to_delete:
92+
product = self.file.by_id(ifc_definition_id)
9293
IfcStore.unlink_element(product)
9394
ifcopenshell.api.run("root.remove_product", self.file, **{"product": product})
9495

@@ -104,9 +105,10 @@ def sync_edited_objects(self):
104105

105106
def sync_object_placement(self, obj):
106107
blender_matrix = np.matrix(obj.matrix_world)
107-
ifc_matrix = ifcopenshell.util.placement.get_local_placement(
108-
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).ObjectPlacement
109-
)
108+
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
109+
if not hasattr(element, "ObjectPlacement"):
110+
return
111+
ifc_matrix = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
110112
ifc_matrix[0][3] *= self.unit_scale
111113
ifc_matrix[1][3] *= self.unit_scale
112114
ifc_matrix[2][3] *= self.unit_scale
@@ -124,7 +126,36 @@ def sync_object_placement(self, obj):
124126
if not np.allclose(ifc_matrix, blender_matrix, atol=0.0001):
125127
bpy.ops.bim.edit_object_placement(obj=obj.name)
126128

127-
def should_delete(self, guid, obj):
129+
def sync_object_container(self, guid, obj):
130+
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
131+
element_collection = bpy.data.collections.get(obj.name)
132+
133+
if self.file.schema == "IFC2X3":
134+
if element.is_a("IfcProject"):
135+
return
136+
elif element.is_a("IfcContext"):
137+
return
138+
139+
if (element.is_a("IfcElement") and element_collection) or element.is_a("IfcSpatialStructureElement"):
140+
try:
141+
parent_collection = [c for c in bpy.data.collections if c.children.get(element_collection.name)][0]
142+
except:
143+
return # Out of the spatial tree
144+
else:
145+
parent_collection = obj.users_collection[0]
146+
147+
parent_obj = bpy.data.objects.get(parent_collection.name)
148+
if not parent_obj or not parent_obj.BIMObjectProperties.ifc_definition_id:
149+
return
150+
parent = self.file.by_id(parent_obj.BIMObjectProperties.ifc_definition_id)
151+
152+
if parent.is_a("IfcSpatialStructureElement") and not element.is_a("IfcSpatialStructureElement"):
153+
if parent != ifcopenshell.util.element.get_container(element):
154+
bpy.ops.bim.assign_container(relating_structure=parent.id(), related_element=obj.name)
155+
elif parent != ifcopenshell.util.element.get_aggregate(element):
156+
bpy.ops.bim.assign_object(relating_object=parent_obj.name, related_object=obj.name)
157+
158+
def should_delete(self, obj):
128159
try:
129160
# This will throw an exception if the Blender object no longer exists
130161
foo = obj.name

src/blenderbim/blenderbim/bim/handler.py

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@
99

1010

1111
def mode_callback(obj, data):
12-
if (
13-
obj.mode != "OBJECT"
14-
or not obj.data
15-
or not isinstance(obj.data, bpy.types.Mesh)
16-
or not obj.data.BIMMeshProperties.ifc_definition_id
17-
or not bpy.context.scene.BIMProjectProperties.is_authoring
18-
):
19-
return
20-
representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
21-
if representation.RepresentationType == "Tessellation" or representation.RepresentationType == "Brep":
22-
IfcStore.edited_objs.add(obj.name)
12+
for obj in bpy.context.selected_objects:
13+
if (
14+
obj.mode != "EDIT"
15+
or not obj.data
16+
or not isinstance(obj.data, bpy.types.Mesh)
17+
or not obj.data.BIMMeshProperties.ifc_definition_id
18+
or not bpy.context.scene.BIMProjectProperties.is_authoring
19+
):
20+
return
21+
representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
22+
if representation.RepresentationType == "Tessellation" or representation.RepresentationType == "Brep":
23+
IfcStore.edited_objs.add(obj.name)
2324

2425

2526
def name_callback(obj, data):
@@ -29,6 +30,9 @@ def name_callback(obj, data):
2930
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
3031
if not element.is_a("IfcRoot"):
3132
return
33+
if element.is_a("IfcSpatialStructureElement") or (hasattr(element, "IsDecomposedBy") and element.IsDecomposedBy):
34+
collection = obj.users_collection[0]
35+
collection.name = obj.name
3236
element.Name = "/".join(obj.name.split("/")[1:])
3337
AttributeData.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
3438

@@ -52,52 +56,35 @@ def subscribe_to(object, data_path, callback):
5256
def purge_module_data():
5357
from blenderbim.bim import modules
5458

55-
for name in modules.keys():
59+
for name, value in modules.items():
5660
try:
5761
getattr(getattr(getattr(ifcopenshell.api, name), "data"), "Data").purge()
5862
except AttributeError:
5963
pass
6064

65+
try:
66+
getattr(value, "prop").purge()
67+
except AttributeError:
68+
pass
69+
6170

6271
@persistent
6372
def loadIfcStore(scene):
64-
IfcStore.file = None
65-
IfcStore.schema = None
66-
props = bpy.context.scene.BIMProperties
67-
IfcStore.id_map = (
68-
{int(k): bpy.data.objects.get(v) for k, v in json.loads(props.id_map).items()} if props.id_map else {}
69-
)
70-
IfcStore.guid_map = (
71-
{k: bpy.data.objects.get(v) for k, v in json.loads(props.guid_map).items()} if props.id_map else {}
72-
)
73+
IfcStore.purge()
74+
ifc_file = IfcStore.get_file()
75+
IfcStore.get_schema()
76+
[
77+
IfcStore.link_element(ifc_file.by_id(o.BIMObjectProperties.ifc_definition_id), o)
78+
for o in bpy.data.objects
79+
if o.BIMObjectProperties.ifc_definition_id
80+
]
7381
purge_module_data()
7482

7583

7684
@persistent
7785
def ensureIfcExported(scene):
7886
if IfcStore.get_file() and not bpy.context.scene.BIMProperties.ifc_file:
79-
# The invocation pops up a file select window.
80-
# This is non-blocking, therefore the Blend file is saved before we export.
81-
bpy.ops.export_ifc.bim("INVOKE_DEFAULT", should_force_resave=True)
82-
83-
84-
@persistent
85-
def storeIdMap(scene):
86-
try:
87-
bpy.context.scene.BIMProperties.id_map = json.dumps({k: v.name for k, v in IfcStore.id_map.items()})
88-
bpy.context.scene.BIMProperties.guid_map = json.dumps({k: v.name for k, v in IfcStore.guid_map.items()})
89-
except:
90-
# Regenerate maps. Is there a better solution for this? It seems fragile.
91-
file = IfcStore.get_file()
92-
IfcStore.id_map = {
93-
o.ifc_definition_id: o.name for o in bpy.data.objects if o.BIMObjectProperties.ifc_definition_id
94-
}
95-
IfcStore.guid_map = {
96-
file.by_id(i).GlobalId: n for i, n in IfcStore.id_map.items() if file.by_id(i).is_a("IfcRoot")
97-
}
98-
# Then attempt to store it again
99-
bpy.context.scene.BIMProperties.id_map = json.dumps({k: v.name for k, v in IfcStore.id_map.items()})
100-
bpy.context.scene.BIMProperties.guid_map = json.dumps({k: v.name for k, v in IfcStore.guid_map.items()})
87+
bpy.ops.export_ifc.bim("INVOKE_DEFAULT")
10188

10289

10390
def get_application(ifc):
@@ -172,12 +159,12 @@ def create_application_organisation(ifc):
172159
@persistent
173160
def setDefaultProperties(scene):
174161
ifcopenshell.api.owner.settings.get_person = (
175-
lambda ifc : ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person))
162+
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person))
176163
if bpy.context.scene.BIMOwnerProperties.user_person
177164
else None
178165
)
179166
ifcopenshell.api.owner.settings.get_organisation = (
180-
lambda ifc : ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation))
167+
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation))
181168
if bpy.context.scene.BIMOwnerProperties.user_organisation
182169
else None
183170
)

src/blenderbim/blenderbim/bim/ifc.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ class IfcStore:
1212
edited_objs = set()
1313
pset_template_path = ""
1414
pset_template_file = None
15+
library_path = ""
16+
library_file = None
17+
18+
@staticmethod
19+
def purge():
20+
IfcStore.path = ""
21+
IfcStore.file = None
22+
IfcStore.schema = None
23+
IfcStore.id_map = {}
24+
IfcStore.guid_map = {}
25+
IfcStore.edited_objs = set()
26+
IfcStore.pset_template_path = ""
27+
IfcStore.pset_template_file = None
28+
IfcStore.library_path = ""
29+
IfcStore.library_file = None
1530

1631
@staticmethod
1732
def get_file():

0 commit comments

Comments
 (0)