mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 14:02:27 +00:00
Merge branch 'v0.6.0' of https://github.com/IfcOpenShell/IfcOpenShell into presentationlayer
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
c14f5eeca042232025797990396232e4feab53e7
|
||||||
|
d6881e833da0b6278313870d37d42ca6ece8686a
|
||||||
|
892be5444c5bd01a601c99243ac8d3e7b2f0e779
|
||||||
|
d169a964dd7e9ab5c98b35a82bcbc76dc6229a7a
|
||||||
|
4a6ec11f6f84a3d1fed2ee9b2f85d783ac3daa9d
|
||||||
|
2c9d6a47f4d24a923069775206bf734feeb14830
|
||||||
|
8f1743ed64a2a52c201a1ef5e312b4d3a7a922cf
|
||||||
|
ad7f030344c405e10cfa7d5cf06d82c121eeb825
|
||||||
@@ -38,10 +38,12 @@ endif
|
|||||||
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && rm -f geolocation.py
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && rm -f geolocation.py
|
||||||
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && rm -f selector.py
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && rm -f selector.py
|
||||||
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && rm -f unit.py
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && rm -f unit.py
|
||||||
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && rm -f pset.py
|
||||||
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/element.py
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/element.py
|
||||||
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/geolocation.py
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/geolocation.py
|
||||||
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/selector.py
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/selector.py
|
||||||
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/unit.py
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/unit.py
|
||||||
|
cd dist/blenderbim/libs/site/packages/ifcopenshell/util && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcopenshell-python/ifcopenshell/util/pset.py
|
||||||
|
|
||||||
# Provides Python OCC functionality for cutting IFC geometry for construction documentation
|
# Provides Python OCC functionality for cutting IFC geometry for construction documentation
|
||||||
mkdir dist/working
|
mkdir dist/working
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ if bpy is not None:
|
|||||||
from .module.model import opening as model_opening
|
from .module.model import opening as model_opening
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
|
operator.ReassignClass,
|
||||||
operator.AssignClass,
|
operator.AssignClass,
|
||||||
operator.UnassignClass,
|
operator.UnassignClass,
|
||||||
operator.SelectClass,
|
operator.SelectClass,
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import datetime
|
|||||||
import os
|
import os
|
||||||
import zipfile
|
import zipfile
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.pset
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from .helper import SIUnitHelper, get_representation_elements
|
from .helper import SIUnitHelper, get_representation_elements
|
||||||
from . import schema
|
from . import schema
|
||||||
from . import ifc
|
from . import ifc
|
||||||
import ifcopenshell
|
|
||||||
import addon_utils
|
import addon_utils
|
||||||
|
|
||||||
|
|
||||||
@@ -466,10 +467,10 @@ class IfcParser:
|
|||||||
return
|
return
|
||||||
qto_names = self.get_applicable_qtos(ifc_class)
|
qto_names = self.get_applicable_qtos(ifc_class)
|
||||||
for name in qto_names:
|
for name in qto_names:
|
||||||
if name not in schema.ifc.qtos:
|
if name not in ifcopenshell.util.pset.qtos:
|
||||||
continue
|
continue
|
||||||
has_automatic_value = False
|
has_automatic_value = False
|
||||||
props = schema.ifc.qtos[name]["HasPropertyTemplates"].keys()
|
props = ifcopenshell.util.pset.qtos[name]["HasPropertyTemplates"].keys()
|
||||||
guessed_values = {}
|
guessed_values = {}
|
||||||
for prop_name in props:
|
for prop_name in props:
|
||||||
value = self.qto_calculator.guess_quantity(prop_name, props, obj)
|
value = self.qto_calculator.guess_quantity(prop_name, props, obj)
|
||||||
@@ -1666,12 +1667,12 @@ class IfcExporter:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create_qto_properties(self, qto):
|
def create_qto_properties(self, qto):
|
||||||
if qto["attributes"]["Name"] in schema.ifc.qtos:
|
if qto["attributes"]["Name"] in ifcopenshell.util.pset.qtos:
|
||||||
return self.create_templated_qto_properties(qto)
|
return self.create_templated_qto_properties(qto)
|
||||||
return self.create_custom_qto_properties(qto)
|
return self.create_custom_qto_properties(qto)
|
||||||
|
|
||||||
def create_pset_properties(self, pset):
|
def create_pset_properties(self, pset):
|
||||||
if pset["attributes"]["Name"] in schema.ifc.psets:
|
if pset["attributes"]["Name"] in ifcopenshell.util.pset.psets:
|
||||||
return self.create_templated_pset_properties(pset)
|
return self.create_templated_pset_properties(pset)
|
||||||
return self.create_custom_pset_properties(pset)
|
return self.create_custom_pset_properties(pset)
|
||||||
|
|
||||||
@@ -1704,7 +1705,7 @@ class IfcExporter:
|
|||||||
|
|
||||||
def create_templated_pset_properties(self, pset):
|
def create_templated_pset_properties(self, pset):
|
||||||
properties = []
|
properties = []
|
||||||
templates = schema.ifc.psets[pset["attributes"]["Name"]]["HasPropertyTemplates"]
|
templates = ifcopenshell.util.pset.psets[pset["attributes"]["Name"]]["HasPropertyTemplates"]
|
||||||
for name, data in templates.items():
|
for name, data in templates.items():
|
||||||
if name not in pset["raw"]:
|
if name not in pset["raw"]:
|
||||||
continue
|
continue
|
||||||
@@ -1731,7 +1732,7 @@ class IfcExporter:
|
|||||||
|
|
||||||
def create_templated_qto_properties(self, qto):
|
def create_templated_qto_properties(self, qto):
|
||||||
properties = []
|
properties = []
|
||||||
templates = schema.ifc.qtos[qto["attributes"]["Name"]]["HasPropertyTemplates"]
|
templates = ifcopenshell.util.pset.qtos[qto["attributes"]["Name"]]["HasPropertyTemplates"]
|
||||||
for name, data in templates.items():
|
for name, data in templates.items():
|
||||||
if name not in qto["raw"]:
|
if name not in qto["raw"]:
|
||||||
continue
|
continue
|
||||||
@@ -3157,10 +3158,7 @@ class IfcExporter:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def relate_spaces_to_boundary_elements(self):
|
def relate_spaces_to_boundary_elements(self):
|
||||||
for (
|
for (relating_space_index, relationships,) in self.ifc_parser.rel_space_boundaries.items():
|
||||||
relating_space_index,
|
|
||||||
relationships,
|
|
||||||
) in self.ifc_parser.rel_space_boundaries.items():
|
|
||||||
for relationship in relationships:
|
for relationship in relationships:
|
||||||
relationship["attributes"]["GlobalId"] = ifcopenshell.guid.new()
|
relationship["attributes"]["GlobalId"] = ifcopenshell.guid.new()
|
||||||
relationship["attributes"]["RelatedBuildingElement"] = self.ifc_parser.products[
|
relationship["attributes"]["RelatedBuildingElement"] = self.ifc_parser.products[
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import ifcopenshell.geom
|
|||||||
import ifcopenshell.util.geolocation
|
import ifcopenshell.util.geolocation
|
||||||
import ifcopenshell.util.selector
|
import ifcopenshell.util.selector
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
import ifcopenshell.util.pset
|
||||||
import bpy
|
import bpy
|
||||||
import bmesh
|
import bmesh
|
||||||
import os
|
import os
|
||||||
@@ -206,8 +207,8 @@ class MaterialCreator:
|
|||||||
def add_pset(self, pset, obj):
|
def add_pset(self, pset, obj):
|
||||||
new_pset = obj.BIMMaterialProperties.psets.add()
|
new_pset = obj.BIMMaterialProperties.psets.add()
|
||||||
new_pset.name = pset.Name
|
new_pset.name = pset.Name
|
||||||
if new_pset.name in schema.ifc.psets:
|
if new_pset.name in ifcopenshell.util.pset.psets:
|
||||||
for prop_name in schema.ifc.psets[new_pset.name]["HasPropertyTemplates"].keys():
|
for prop_name in ifcopenshell.util.pset.psets[new_pset.name]["HasPropertyTemplates"].keys():
|
||||||
prop = new_pset.properties.add()
|
prop = new_pset.properties.add()
|
||||||
prop.name = prop_name
|
prop.name = prop_name
|
||||||
for prop in pset.Properties:
|
for prop in pset.Properties:
|
||||||
@@ -1338,8 +1339,8 @@ class IfcImporter:
|
|||||||
def add_pset(self, pset, obj):
|
def add_pset(self, pset, obj):
|
||||||
new_pset = obj.BIMObjectProperties.psets.add()
|
new_pset = obj.BIMObjectProperties.psets.add()
|
||||||
new_pset.name = pset.Name
|
new_pset.name = pset.Name
|
||||||
if new_pset.name in schema.ifc.psets:
|
if new_pset.name in ifcopenshell.util.pset.psets:
|
||||||
for prop_name in schema.ifc.psets[new_pset.name]["HasPropertyTemplates"].keys():
|
for prop_name in ifcopenshell.util.pset.psets[new_pset.name]["HasPropertyTemplates"].keys():
|
||||||
prop = new_pset.properties.add()
|
prop = new_pset.properties.add()
|
||||||
prop.name = prop_name
|
prop.name = prop_name
|
||||||
# Invalid IFC, but some vendors like Solidworks do this so we accomodate it
|
# Invalid IFC, but some vendors like Solidworks do this so we accomodate it
|
||||||
@@ -1358,8 +1359,8 @@ class IfcImporter:
|
|||||||
def add_qto(self, qto, obj):
|
def add_qto(self, qto, obj):
|
||||||
new_qto = obj.BIMObjectProperties.qtos.add()
|
new_qto = obj.BIMObjectProperties.qtos.add()
|
||||||
new_qto.name = str(qto.Name)
|
new_qto.name = str(qto.Name)
|
||||||
if new_qto.name in schema.ifc.qtos:
|
if new_qto.name in ifcopenshell.util.pset.qtos:
|
||||||
for prop_name in schema.ifc.qtos[new_qto.name]["HasPropertyTemplates"].keys():
|
for prop_name in ifcopenshell.util.pset.qtos[new_qto.name]["HasPropertyTemplates"].keys():
|
||||||
prop = new_qto.properties.add()
|
prop = new_qto.properties.add()
|
||||||
prop.name = prop_name
|
prop.name = prop_name
|
||||||
for prop in qto.Quantities:
|
for prop in qto.Quantities:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import subprocess
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.selector
|
import ifcopenshell.util.selector
|
||||||
import ifcopenshell.util.geolocation
|
import ifcopenshell.util.geolocation
|
||||||
|
import ifcopenshell.util.pset
|
||||||
import tempfile
|
import tempfile
|
||||||
from . import export_ifc
|
from . import export_ifc
|
||||||
from . import import_ifc
|
from . import import_ifc
|
||||||
@@ -213,6 +214,20 @@ class SelectPset(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class ReassignClass(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.reassign_class"
|
||||||
|
bl_label = "Reassign IFC Class"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
bpy.context.active_object.BIMObjectProperties.is_reassigning_class = True
|
||||||
|
bpy.context.scene.BIMProperties.ifc_class = obj.name.split("/")[0]
|
||||||
|
predefined_type = obj.BIMObjectProperties.attributes.get("PredefinedType")
|
||||||
|
if predefined_type:
|
||||||
|
bpy.context.scene.BIMProperties.ifc_predefined_type = predefined_type.string_value
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AssignClass(bpy.types.Operator):
|
class AssignClass(bpy.types.Operator):
|
||||||
bl_idname = "bim.assign_class"
|
bl_idname = "bim.assign_class"
|
||||||
bl_label = "Assign IFC Class"
|
bl_label = "Assign IFC Class"
|
||||||
@@ -221,6 +236,7 @@ class AssignClass(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
if self.object_name:
|
if self.object_name:
|
||||||
objects = [bpy.data.objects.get(self.object_name)]
|
objects = [bpy.data.objects.get(self.object_name)]
|
||||||
|
objects[0].BIMObjectProperties.is_reassigning_class = False
|
||||||
else:
|
else:
|
||||||
objects = bpy.context.selected_objects
|
objects = bpy.context.selected_objects
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
@@ -835,32 +851,60 @@ class AddQto(bpy.types.Operator):
|
|||||||
bl_label = "Add Qto"
|
bl_label = "Add Qto"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
self.applicable_qtos_cache = {}
|
||||||
name = bpy.context.active_object.BIMObjectProperties.qto_name
|
name = bpy.context.active_object.BIMObjectProperties.qto_name
|
||||||
if name not in schema.ifc.qtos:
|
if name not in ifcopenshell.util.pset.qtos:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
qto = bpy.context.active_object.BIMObjectProperties.qtos.add()
|
for obj in bpy.context.selected_objects:
|
||||||
qto.name = name
|
if "/" not in obj.name or obj.BIMObjectProperties.qtos.find(name) != -1:
|
||||||
for prop_name in schema.ifc.qtos[name]["HasPropertyTemplates"].keys():
|
continue
|
||||||
prop = qto.properties.add()
|
applicable_qtos = self.get_applicable_qtos(obj.name.split("/")[0])
|
||||||
prop.name = prop_name
|
if name not in applicable_qtos:
|
||||||
|
continue
|
||||||
|
qto = obj.BIMObjectProperties.qtos.add()
|
||||||
|
qto.name = name
|
||||||
|
for prop_name in ifcopenshell.util.pset.qtos[name]["HasPropertyTemplates"].keys():
|
||||||
|
prop = qto.properties.add()
|
||||||
|
prop.name = prop_name
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def get_applicable_qtos(self, ifc_class):
|
||||||
|
if ifc_class not in self.applicable_qtos_cache:
|
||||||
|
self.applicable_qtos_cache[ifc_class] = ifcopenshell.util.pset.get_applicable_psetqtos(
|
||||||
|
bpy.context.scene.BIMProperties.export_schema, ifc_class, is_qto=True
|
||||||
|
)
|
||||||
|
return self.applicable_qtos_cache[ifc_class]
|
||||||
|
|
||||||
|
|
||||||
class AddPset(bpy.types.Operator):
|
class AddPset(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_pset"
|
bl_idname = "bim.add_pset"
|
||||||
bl_label = "Add Pset"
|
bl_label = "Add Pset"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
pset_name = bpy.context.active_object.BIMObjectProperties.pset_name
|
self.applicable_psets_cache = {}
|
||||||
if pset_name not in schema.ifc.psets:
|
name = bpy.context.active_object.BIMObjectProperties.pset_name
|
||||||
|
if name not in ifcopenshell.util.pset.psets:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
pset = bpy.context.active_object.BIMObjectProperties.psets.add()
|
for obj in bpy.context.selected_objects:
|
||||||
pset.name = pset_name
|
if "/" not in obj.name or obj.BIMObjectProperties.psets.find(name) != -1:
|
||||||
for prop_name in schema.ifc.psets[pset_name]["HasPropertyTemplates"].keys():
|
continue
|
||||||
prop = pset.properties.add()
|
applicable_psets = self.get_applicable_psets(obj.name.split("/")[0])
|
||||||
prop.name = prop_name
|
if name not in applicable_psets:
|
||||||
|
continue
|
||||||
|
pset = obj.BIMObjectProperties.psets.add()
|
||||||
|
pset.name = name
|
||||||
|
for prop_name in ifcopenshell.util.pset.psets[name]["HasPropertyTemplates"].keys():
|
||||||
|
prop = pset.properties.add()
|
||||||
|
prop.name = prop_name
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def get_applicable_psets(self, ifc_class):
|
||||||
|
if ifc_class not in self.applicable_psets_cache:
|
||||||
|
self.applicable_psets_cache[ifc_class] = ifcopenshell.util.pset.get_applicable_psetqtos(
|
||||||
|
bpy.context.scene.BIMProperties.export_schema, ifc_class, is_pset=True
|
||||||
|
)
|
||||||
|
return self.applicable_psets_cache[ifc_class]
|
||||||
|
|
||||||
|
|
||||||
class RemovePset(bpy.types.Operator):
|
class RemovePset(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_pset"
|
bl_idname = "bim.remove_pset"
|
||||||
@@ -868,7 +912,13 @@ class RemovePset(bpy.types.Operator):
|
|||||||
pset_index: bpy.props.IntProperty()
|
pset_index: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
bpy.context.active_object.BIMObjectProperties.psets.remove(self.pset_index)
|
name = bpy.context.active_object.BIMObjectProperties.psets[self.pset_index].name
|
||||||
|
for obj in bpy.context.selected_objects:
|
||||||
|
if "/" not in obj.name:
|
||||||
|
continue
|
||||||
|
index = obj.BIMObjectProperties.psets.find(name)
|
||||||
|
if index != -1:
|
||||||
|
obj.BIMObjectProperties.psets.remove(index)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -878,7 +928,13 @@ class RemoveQto(bpy.types.Operator):
|
|||||||
index: bpy.props.IntProperty()
|
index: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
bpy.context.active_object.BIMObjectProperties.qtos.remove(self.index)
|
name = bpy.context.active_object.BIMObjectProperties.qtos[self.index].name
|
||||||
|
for obj in bpy.context.selected_objects:
|
||||||
|
if "/" not in obj.name:
|
||||||
|
continue
|
||||||
|
index = obj.BIMObjectProperties.qtos.find(name)
|
||||||
|
if index != -1:
|
||||||
|
obj.BIMObjectProperties.qtos.remove(index)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -1221,9 +1277,18 @@ class AddAttribute(bpy.types.Operator):
|
|||||||
bl_label = "Add Attribute"
|
bl_label = "Add Attribute"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
if bpy.context.active_object.BIMObjectProperties.applicable_attributes:
|
if not bpy.context.active_object.BIMObjectProperties.applicable_attributes:
|
||||||
attribute = bpy.context.active_object.BIMObjectProperties.attributes.add()
|
return {"FINISHED"}
|
||||||
attribute.name = bpy.context.active_object.BIMObjectProperties.applicable_attributes
|
name = bpy.context.active_object.BIMObjectProperties.applicable_attributes
|
||||||
|
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(bpy.context.scene.BIMProperties.export_schema)
|
||||||
|
for obj in bpy.context.selected_objects:
|
||||||
|
if "/" not in obj.name or obj.BIMObjectProperties.attributes.find(name) != -1:
|
||||||
|
continue
|
||||||
|
entity = schema.declaration_by_name(obj.name.split("/")[0])
|
||||||
|
if name not in [a.name() for a in entity.all_attributes()]:
|
||||||
|
continue
|
||||||
|
attribute = obj.BIMObjectProperties.attributes.add()
|
||||||
|
attribute.name = name
|
||||||
if attribute.name == "GlobalId":
|
if attribute.name == "GlobalId":
|
||||||
attribute.string_value = ifcopenshell.guid.new()
|
attribute.string_value = ifcopenshell.guid.new()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -1246,7 +1311,13 @@ class RemoveAttribute(bpy.types.Operator):
|
|||||||
attribute_index: bpy.props.IntProperty()
|
attribute_index: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
bpy.context.active_object.BIMObjectProperties.attributes.remove(self.attribute_index)
|
name = bpy.context.active_object.BIMObjectProperties.attributes[self.attribute_index].name
|
||||||
|
for obj in bpy.context.selected_objects:
|
||||||
|
if "/" not in obj.name:
|
||||||
|
continue
|
||||||
|
index = obj.BIMObjectProperties.attributes.find(name)
|
||||||
|
if index != -1:
|
||||||
|
obj.BIMObjectProperties.attributes.remove(index)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -2714,7 +2785,6 @@ class CopyPropertyToSelection(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.applicable_psets_cache = {}
|
self.applicable_psets_cache = {}
|
||||||
self.empty = ifcopenshell.file()
|
|
||||||
for obj in bpy.context.selected_objects:
|
for obj in bpy.context.selected_objects:
|
||||||
if "/" not in obj.name:
|
if "/" not in obj.name:
|
||||||
continue
|
continue
|
||||||
@@ -2725,7 +2795,7 @@ class CopyPropertyToSelection(bpy.types.Operator):
|
|||||||
continue
|
continue
|
||||||
pset = obj.BIMObjectProperties.psets.add()
|
pset = obj.BIMObjectProperties.psets.add()
|
||||||
pset.name = self.pset_name
|
pset.name = self.pset_name
|
||||||
for template_prop_name in schema.ifc.psets[self.pset_name]["HasPropertyTemplates"].keys():
|
for template_prop_name in ifcopenshell.util.pset.psets[self.pset_name]["HasPropertyTemplates"].keys():
|
||||||
prop = pset.properties.add()
|
prop = pset.properties.add()
|
||||||
prop.name = template_prop_name
|
prop.name = template_prop_name
|
||||||
prop = pset.properties.get(self.prop_name)
|
prop = pset.properties.get(self.prop_name)
|
||||||
@@ -2733,16 +2803,12 @@ class CopyPropertyToSelection(bpy.types.Operator):
|
|||||||
prop.string_value = self.prop_value
|
prop.string_value = self.prop_value
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
# TODO: move into util module. See bug #971
|
def get_applicable_psets(self, ifc_class):
|
||||||
def get_applicable_psets(self, element_class):
|
if ifc_class not in self.applicable_psets_cache:
|
||||||
if element_class not in self.applicable_psets_cache:
|
self.applicable_psets_cache[ifc_class] = ifcopenshell.util.pset.get_applicable_psetqtos(
|
||||||
element = self.empty.create_entity(element_class)
|
bpy.context.scene.BIMProperties.export_schema, ifc_class, is_pset=True
|
||||||
applicable_psets = []
|
)
|
||||||
for ifc_class, pset_names in schema.ifc.applicable_psets.items():
|
return self.applicable_psets_cache[ifc_class]
|
||||||
if element.is_a(ifc_class):
|
|
||||||
applicable_psets.extend(pset_names)
|
|
||||||
self.applicable_psets_cache[element_class] = applicable_psets
|
|
||||||
return self.applicable_psets_cache[element_class]
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_OT_ChangeClassificationLevel(bpy.types.Operator):
|
class BIM_OT_ChangeClassificationLevel(bpy.types.Operator):
|
||||||
@@ -3589,11 +3655,11 @@ class GuessQuantity(bpy.types.Operator):
|
|||||||
prop.string_value = str(round(quantity, 3))
|
prop.string_value = str(round(quantity, 3))
|
||||||
|
|
||||||
def add_qto(self, obj, name):
|
def add_qto(self, obj, name):
|
||||||
if name not in schema.ifc.qtos:
|
if name not in ifcopenshell.util.pset.qtos:
|
||||||
return
|
return
|
||||||
qto = obj.BIMObjectProperties.qtos.add()
|
qto = obj.BIMObjectProperties.qtos.add()
|
||||||
qto.name = name
|
qto.name = name
|
||||||
for prop_name in schema.ifc.qtos[name]["HasPropertyTemplates"].keys():
|
for prop_name in ifcopenshell.util.pset.qtos[name]["HasPropertyTemplates"].keys():
|
||||||
prop = qto.properties.add()
|
prop = qto.properties.add()
|
||||||
prop.name = prop_name
|
prop.name = prop_name
|
||||||
return qto
|
return qto
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.pset
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from . import export_ifc
|
from . import export_ifc
|
||||||
from . import schema
|
from . import schema
|
||||||
@@ -449,29 +450,25 @@ def refreshReferences(self, context):
|
|||||||
context.scene.BIMProperties.classification_references.root = ""
|
context.scene.BIMProperties.classification_references.root = ""
|
||||||
|
|
||||||
|
|
||||||
# TODO: move into util module. See bug #971
|
|
||||||
def getPsetNames(self, context):
|
def getPsetNames(self, context):
|
||||||
global psetnames_enum
|
global psetnames_enum
|
||||||
psetnames_enum.clear()
|
psetnames_enum.clear()
|
||||||
if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements:
|
if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements:
|
||||||
empty = ifcopenshell.file()
|
pset_names = ifcopenshell.util.pset.get_applicable_psetqtos(
|
||||||
element = empty.create_entity(context.active_object.name.split("/")[0])
|
bpy.context.scene.BIMProperties.export_schema, context.active_object.name.split("/")[0], is_pset=True
|
||||||
for ifc_class, pset_names in schema.ifc.applicable_psets.items():
|
)
|
||||||
if element.is_a(ifc_class):
|
psetnames_enum.extend([(p, p, "") for p in pset_names])
|
||||||
psetnames_enum.extend([(p, p, "") for p in pset_names])
|
|
||||||
return psetnames_enum
|
return psetnames_enum
|
||||||
|
|
||||||
|
|
||||||
# TODO: move into util module. See bug #971
|
|
||||||
def getQtoNames(self, context):
|
def getQtoNames(self, context):
|
||||||
global qtonames_enum
|
global qtonames_enum
|
||||||
qtonames_enum.clear()
|
qtonames_enum.clear()
|
||||||
if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements:
|
if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements:
|
||||||
empty = ifcopenshell.file()
|
qto_names = ifcopenshell.util.pset.get_applicable_psetqtos(
|
||||||
element = empty.create_entity(context.active_object.name.split("/")[0])
|
bpy.context.scene.BIMProperties.export_schema, context.active_object.name.split("/")[0], is_qto=True
|
||||||
for ifc_class, qto_names in schema.ifc.applicable_qtos.items():
|
)
|
||||||
if element.is_a(ifc_class):
|
qtonames_enum.extend([(q, q, "") for q in qto_names])
|
||||||
qtonames_enum.extend([(q, q, "") for q in qto_names])
|
|
||||||
return qtonames_enum
|
return qtonames_enum
|
||||||
|
|
||||||
|
|
||||||
@@ -1625,6 +1622,7 @@ class BoundaryCondition(PropertyGroup):
|
|||||||
|
|
||||||
|
|
||||||
class BIMObjectProperties(PropertyGroup):
|
class BIMObjectProperties(PropertyGroup):
|
||||||
|
is_reassigning_class: BoolProperty(name="Is Reassigning Class")
|
||||||
global_ids: CollectionProperty(name="GlobalIds", type=GlobalId)
|
global_ids: CollectionProperty(name="GlobalIds", type=GlobalId)
|
||||||
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
||||||
relating_type: PointerProperty(name="Type Product", type=bpy.types.Object)
|
relating_type: PointerProperty(name="Type Product", type=bpy.types.Object)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.pset
|
||||||
import bpy
|
import bpy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -30,14 +31,10 @@ class IfcSchema:
|
|||||||
self.property_files = []
|
self.property_files = []
|
||||||
property_paths = Path(os.path.join(self.data_dir, "pset")).glob("*.ifc")
|
property_paths = Path(os.path.join(self.data_dir, "pset")).glob("*.ifc")
|
||||||
for path in property_paths:
|
for path in property_paths:
|
||||||
self.property_files.append(ifcopenshell.open(path))
|
ifcopenshell.util.pset.load_property_set_template(path)
|
||||||
self.property_files.append(ifcopenshell.open(os.path.join(self.schema_dir, "Pset_IFC4_ADD2.ifc")))
|
ifcopenshell.util.pset.load_property_set_template(os.path.join(self.schema_dir, "Pset_IFC4_ADD2.ifc"))
|
||||||
|
|
||||||
self.classification_files = {}
|
self.classification_files = {}
|
||||||
self.psets = {}
|
|
||||||
self.qtos = {}
|
|
||||||
self.applicable_psets = {}
|
|
||||||
self.applicable_qtos = {}
|
|
||||||
self.classifications = {}
|
self.classifications = {}
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
@@ -50,17 +47,6 @@ class IfcSchema:
|
|||||||
with open(os.path.join(self.schema_dir, "ifc_types_IFC4.json")) as f:
|
with open(os.path.join(self.schema_dir, "ifc_types_IFC4.json")) as f:
|
||||||
self.type_map = json.load(f)
|
self.type_map = json.load(f)
|
||||||
|
|
||||||
for property_file in self.property_files:
|
|
||||||
for prop in property_file.by_type("IfcPropertySetTemplate"):
|
|
||||||
if prop.Name[0:4] == "Qto_":
|
|
||||||
self.qtos[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
|
|
||||||
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
|
|
||||||
self.applicable_qtos.setdefault(entity, []).append(prop.Name)
|
|
||||||
else:
|
|
||||||
self.psets[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
|
|
||||||
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
|
|
||||||
self.applicable_psets.setdefault(entity, []).append(prop.Name)
|
|
||||||
|
|
||||||
def load_classification(self, name, classification_index=None):
|
def load_classification(self, name, classification_index=None):
|
||||||
if name not in self.classifications:
|
if name not in self.classifications:
|
||||||
if classification_index is not None:
|
if classification_index is not None:
|
||||||
|
|||||||
@@ -21,24 +21,28 @@ class BIM_PT_object(Panel):
|
|||||||
props = context.active_object.BIMObjectProperties
|
props = context.active_object.BIMObjectProperties
|
||||||
bim_properties = context.scene.BIMProperties
|
bim_properties = context.scene.BIMProperties
|
||||||
|
|
||||||
row = layout.row()
|
if props.is_reassigning_class or "/" not in context.active_object.name:
|
||||||
row.prop(bim_properties, "ifc_product")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(bim_properties, "ifc_class")
|
|
||||||
if bim_properties.ifc_predefined_type:
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(bim_properties, "ifc_predefined_type")
|
row.prop(bim_properties, "ifc_product")
|
||||||
if bim_properties.ifc_predefined_type == "USERDEFINED":
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(bim_properties, "ifc_userdefined_type")
|
row.prop(bim_properties, "ifc_class")
|
||||||
row = layout.row(align=True)
|
if bim_properties.ifc_predefined_type:
|
||||||
if "Ifc" not in context.active_object.name:
|
row = layout.row()
|
||||||
op = row.operator("bim.assign_class")
|
row.prop(bim_properties, "ifc_predefined_type")
|
||||||
|
if bim_properties.ifc_predefined_type == "USERDEFINED":
|
||||||
|
row = layout.row()
|
||||||
|
row.prop(bim_properties, "ifc_userdefined_type")
|
||||||
|
row = layout.row(align=True)
|
||||||
|
if "Ifc" not in context.active_object.name:
|
||||||
|
op = row.operator("bim.assign_class")
|
||||||
|
else:
|
||||||
|
op = row.operator("bim.assign_class")
|
||||||
|
op.object_name = context.active_object.name
|
||||||
|
op = row.operator("bim.unassign_class", icon="X", text="")
|
||||||
|
op.object_name = context.active_object.name
|
||||||
else:
|
else:
|
||||||
op = row.operator("bim.assign_class", text="Reassign IFC Class")
|
row = layout.row()
|
||||||
op.object_name = context.active_object.name
|
row.operator("bim.reassign_class", text="Reassign IFC Class")
|
||||||
op = row.operator("bim.unassign_class", icon="X", text="")
|
|
||||||
op.object_name = context.active_object.name
|
|
||||||
|
|
||||||
if "Ifc" not in context.active_object.name:
|
if "Ifc" not in context.active_object.name:
|
||||||
return
|
return
|
||||||
@@ -1894,10 +1898,13 @@ class BIM_UL_classifications(bpy.types.UIList):
|
|||||||
|
|
||||||
class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
||||||
bl_idname = "blenderbim"
|
bl_idname = "blenderbim"
|
||||||
svg2pdf_command: StringProperty(name="SVG to PDF Command")
|
svg2pdf_command: StringProperty(name="SVG to PDF Command", description="E.g. [['inkscape', svg, '-o', pdf]]")
|
||||||
svg2dxf_command: StringProperty(name="SVG to DXF Command")
|
svg2dxf_command: StringProperty(
|
||||||
svg_command: StringProperty(name="SVG Command")
|
name="SVG to DXF Command",
|
||||||
pdf_command: StringProperty(name="PDF Command")
|
description="E.g. [['inkscape', svg, '-o', eps], ['pstoedit', '-dt', '-f', 'dxf:-polyaslines -mm', eps, dxf, '-psarg', '-dNOSAFER']]",
|
||||||
|
)
|
||||||
|
svg_command: StringProperty(name="SVG Command", description="E.g. [['firefox-bin', path]]")
|
||||||
|
pdf_command: StringProperty(name="PDF Command", description="E.g. [['firefox-bin', path]]")
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import ifcopenshell
|
||||||
|
|
||||||
|
property_set_template_files = []
|
||||||
|
psets = {}
|
||||||
|
qtos = {}
|
||||||
|
applicable_psets = {}
|
||||||
|
applicable_qtos = {}
|
||||||
|
|
||||||
|
|
||||||
|
def load_property_set_template(path):
|
||||||
|
property_set_template_files.append(ifcopenshell.open(path))
|
||||||
|
for prop in property_set_template_files[-1].by_type("IfcPropertySetTemplate"):
|
||||||
|
if prop.Name[0:4] == "Qto_":
|
||||||
|
qtos[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
|
||||||
|
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
|
||||||
|
applicable_qtos.setdefault(entity, []).append(prop.Name)
|
||||||
|
else:
|
||||||
|
psets[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
|
||||||
|
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
|
||||||
|
applicable_psets.setdefault(entity, []).append(prop.Name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_applicable_psetqtos(schema_version, ifc_class, is_pset=False, is_qto=False):
|
||||||
|
def is_a(entity, ifc_class):
|
||||||
|
if entity.name() == ifc_class:
|
||||||
|
return True
|
||||||
|
return is_a(entity.supertype(), ifc_class) if entity.supertype() else False
|
||||||
|
|
||||||
|
results = []
|
||||||
|
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(schema_version)
|
||||||
|
entity = schema.declaration_by_name(ifc_class)
|
||||||
|
if is_pset:
|
||||||
|
search_items = applicable_psets.items()
|
||||||
|
elif is_qto:
|
||||||
|
search_items = applicable_qtos.items()
|
||||||
|
for ifc_class, pset_names in search_items:
|
||||||
|
if is_a(entity, ifc_class):
|
||||||
|
results.extend(pset_names)
|
||||||
|
return results
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.selector
|
||||||
|
|
||||||
|
|
||||||
|
class Patcher:
|
||||||
|
def __init__(self, src, file, logger, args=None):
|
||||||
|
self.src = src
|
||||||
|
self.file = file
|
||||||
|
self.logger = logger
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def patch(self):
|
||||||
|
self.contained_ins = {}
|
||||||
|
self.aggregates = {}
|
||||||
|
self.new = ifcopenshell.file(schema=self.file.wrapped_data.schema)
|
||||||
|
self.owner_history = None
|
||||||
|
for owner_history in self.file.by_type("IfcOwnerHistory"):
|
||||||
|
self.owner_history = self.new.add(owner_history)
|
||||||
|
break
|
||||||
|
selector = ifcopenshell.util.selector.Selector()
|
||||||
|
for element in selector.parse(self.file, self.args[0]):
|
||||||
|
self.add_element(element)
|
||||||
|
self.create_spatial_tree()
|
||||||
|
self.file = self.new
|
||||||
|
|
||||||
|
def add_element(self, element):
|
||||||
|
new_element = self.new.add(element)
|
||||||
|
for rel in element.ContainedInStructure:
|
||||||
|
spatial_element = rel.RelatingStructure
|
||||||
|
new_spatial_element = self.new.add(spatial_element)
|
||||||
|
self.contained_ins.setdefault(spatial_element.GlobalId, set()).add(new_element)
|
||||||
|
self.add_spatial_tree(spatial_element, new_spatial_element)
|
||||||
|
|
||||||
|
def add_spatial_tree(self, spatial_element, new_spatial_element):
|
||||||
|
for rel in spatial_element.Decomposes:
|
||||||
|
new = self.new.add(rel.RelatingObject)
|
||||||
|
self.aggregates.setdefault(rel.RelatingObject.GlobalId, set()).add(new_spatial_element)
|
||||||
|
self.add_spatial_tree(rel.RelatingObject, new)
|
||||||
|
|
||||||
|
def create_spatial_tree(self):
|
||||||
|
for relating_structure, related_elements in self.contained_ins.items():
|
||||||
|
self.new.createIfcRelContainedInSpatialStructure(
|
||||||
|
ifcopenshell.guid.new(),
|
||||||
|
self.owner_history,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
list(related_elements),
|
||||||
|
self.new.by_guid(relating_structure),
|
||||||
|
)
|
||||||
|
for relating_object, related_objects in self.aggregates.items():
|
||||||
|
self.new.createIfcRelAggregates(
|
||||||
|
ifcopenshell.guid.new(),
|
||||||
|
self.owner_history,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
self.new.by_guid(relating_object),
|
||||||
|
list(related_objects),
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user