mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-23 14:46:22 +00:00
WIP refactor of geometry for stabilisation and optimisation. Switch representation now done.
This commit is contained in:
@@ -92,7 +92,7 @@ class AddRepresentation(bpy.types.Operator, Operator):
|
|||||||
Data.load(tool.Ifc.get(), element.id())
|
Data.load(tool.Ifc.get(), element.id())
|
||||||
|
|
||||||
|
|
||||||
class SwitchRepresentation(bpy.types.Operator):
|
class SwitchRepresentation(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.switch_representation"
|
bl_idname = "bim.switch_representation"
|
||||||
bl_label = "Switch Representation"
|
bl_label = "Switch Representation"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
@@ -102,77 +102,15 @@ class SwitchRepresentation(bpy.types.Operator):
|
|||||||
disable_opening_subtractions: bpy.props.BoolProperty()
|
disable_opening_subtractions: bpy.props.BoolProperty()
|
||||||
should_switch_all_meshes: bpy.props.BoolProperty()
|
should_switch_all_meshes: bpy.props.BoolProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
self.element_obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
core.switch_representation(
|
||||||
self.oprops = self.element_obj.BIMObjectProperties
|
tool.Geometry,
|
||||||
|
obj=bpy.data.objects.get(self.obj) if self.obj else context.active_object,
|
||||||
self.file = IfcStore.get_file()
|
representation=tool.Ifc.get().by_id(self.ifc_definition_id),
|
||||||
self.context_of_items = self.file.by_id(self.ifc_definition_id).ContextOfItems
|
should_reload=self.should_reload,
|
||||||
self.mesh_name = self.get_mesh_name()
|
enable_dynamic_voids=self.disable_opening_subtractions,
|
||||||
|
is_global=self.should_switch_all_meshes,
|
||||||
mesh = bpy.data.meshes.get(self.mesh_name)
|
)
|
||||||
if mesh:
|
|
||||||
self.switch_mesh(mesh)
|
|
||||||
if not mesh or self.should_reload:
|
|
||||||
self.pull_mesh_from_ifc(context)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
def switch_mesh(self, mesh):
|
|
||||||
if self.should_switch_all_meshes or self.file.by_id(self.oprops.ifc_definition_id).is_a("IfcTypeProduct"):
|
|
||||||
self.element_obj.data.user_remap(mesh)
|
|
||||||
else:
|
|
||||||
self.element_obj.data = mesh
|
|
||||||
|
|
||||||
def get_mesh_name(self):
|
|
||||||
representation = self.resolve_mapped_representation(self.file.by_id(self.ifc_definition_id))
|
|
||||||
return "{}/{}".format(self.context_of_items.id(), representation.id())
|
|
||||||
|
|
||||||
def resolve_mapped_representation(self, representation):
|
|
||||||
if representation.RepresentationType == "MappedRepresentation":
|
|
||||||
return self.resolve_mapped_representation(representation.Items[0].MappingSource.MappedRepresentation)
|
|
||||||
return representation
|
|
||||||
|
|
||||||
def pull_mesh_from_ifc(self, context):
|
|
||||||
logger = logging.getLogger("ImportIFC")
|
|
||||||
ifc_import_settings = import_ifc.IfcImportSettings.factory(context, IfcStore.path, logger)
|
|
||||||
element = self.file.by_id(self.oprops.ifc_definition_id)
|
|
||||||
settings = ifcopenshell.geom.settings()
|
|
||||||
|
|
||||||
if self.context_of_items.ContextIdentifier == "Body":
|
|
||||||
if element.is_a("IfcTypeProduct") or self.disable_opening_subtractions:
|
|
||||||
shape = ifcopenshell.geom.create_shape(settings, self.file.by_id(self.ifc_definition_id))
|
|
||||||
else:
|
|
||||||
shape = ifcopenshell.geom.create_shape(settings, self.file.by_id(self.oprops.ifc_definition_id))
|
|
||||||
else:
|
|
||||||
settings.set(settings.INCLUDE_CURVES, True)
|
|
||||||
shape = ifcopenshell.geom.create_shape(settings, self.file.by_id(self.ifc_definition_id))
|
|
||||||
|
|
||||||
ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
|
||||||
ifc_importer.file = self.file
|
|
||||||
mesh = ifc_importer.create_mesh(element, shape)
|
|
||||||
mesh.name = self.mesh_name
|
|
||||||
mesh.BIMMeshProperties.ifc_definition_id = self.ifc_definition_id
|
|
||||||
self.switch_mesh(mesh)
|
|
||||||
material_creator = import_ifc.MaterialCreator(ifc_import_settings, ifc_importer)
|
|
||||||
material_creator.load_existing_materials()
|
|
||||||
material_creator.create(element, self.element_obj, mesh)
|
|
||||||
|
|
||||||
if self.disable_opening_subtractions and self.context_of_items.ContextIdentifier == "Body":
|
|
||||||
if self.oprops.ifc_definition_id not in VoidData.products:
|
|
||||||
VoidData.load(self.file, self.oprops.ifc_definition_id)
|
|
||||||
for opening_id in VoidData.products[self.oprops.ifc_definition_id]:
|
|
||||||
opening = IfcStore.get_element(opening_id)
|
|
||||||
if not opening:
|
|
||||||
continue
|
|
||||||
modifier = self.element_obj.modifiers.new("IfcOpeningElement", "BOOLEAN")
|
|
||||||
modifier.operation = "DIFFERENCE"
|
|
||||||
modifier.object = opening
|
|
||||||
modifier.solver = "EXACT"
|
|
||||||
modifier.use_self = True
|
|
||||||
else:
|
|
||||||
for modifier in self.element_obj.modifiers:
|
|
||||||
if modifier.type == "BOOLEAN" and "IfcOpeningElement" in modifier.name:
|
|
||||||
self.element_obj.modifiers.remove(modifier)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveRepresentation(bpy.types.Operator, Operator):
|
class RemoveRepresentation(bpy.types.Operator, Operator):
|
||||||
@@ -324,8 +262,13 @@ class UpdateParametricRepresentation(bpy.types.Operator):
|
|||||||
parameter = props.ifc_parameters[self.index]
|
parameter = props.ifc_parameters[self.index]
|
||||||
self.file.by_id(parameter.step_id)[parameter.index] = parameter.value
|
self.file.by_id(parameter.step_id)[parameter.index] = parameter.value
|
||||||
show_representation_parameters = bool(props.ifc_parameters)
|
show_representation_parameters = bool(props.ifc_parameters)
|
||||||
bpy.ops.bim.switch_representation(
|
core.switch_representation(
|
||||||
ifc_definition_id=props.ifc_definition_id, should_reload=True, should_switch_all_meshes=True
|
tool.Geometry,
|
||||||
|
obj=obj,
|
||||||
|
representation=tool.Ifc.get().by_id(props.ifc_definition_id),
|
||||||
|
should_reload=True,
|
||||||
|
enable_dynamic_voids=False,
|
||||||
|
is_global=True,
|
||||||
)
|
)
|
||||||
if show_representation_parameters:
|
if show_representation_parameters:
|
||||||
bpy.ops.bim.get_representation_ifc_parameters()
|
bpy.ops.bim.get_representation_ifc_parameters()
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import bmesh
|
|||||||
import blenderbim.bim.handler
|
import blenderbim.bim.handler
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.geometry
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from math import pi
|
from math import pi
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
@@ -57,12 +59,13 @@ def mode_callback(obj, data):
|
|||||||
)
|
)
|
||||||
if not representation:
|
if not representation:
|
||||||
continue
|
continue
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
obj=building_element_obj.name,
|
tool.Geometry,
|
||||||
should_switch_all_meshes=True,
|
obj=building_element_obj,
|
||||||
|
representation=representation,
|
||||||
should_reload=True,
|
should_reload=True,
|
||||||
ifc_definition_id=representation.id(),
|
enable_dynamic_voids=True,
|
||||||
disable_opening_subtractions=True,
|
is_global=True,
|
||||||
)
|
)
|
||||||
IfcStore.edited_objs.add(obj)
|
IfcStore.edited_objs.add(obj)
|
||||||
bm = bmesh.from_edit_mesh(obj.data)
|
bm = bmesh.from_edit_mesh(obj.data)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import ifcopenshell
|
|||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.geometry
|
||||||
from . import wall, slab, profile
|
from . import wall, slab, profile
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.pset.data import Data as PsetData
|
from ifcopenshell.api.pset.data import Data as PsetData
|
||||||
@@ -229,12 +231,13 @@ class DynamicallyVoidProduct(bpy.types.Operator):
|
|||||||
was_edit_mode = obj.mode == "EDIT"
|
was_edit_mode = obj.mode == "EDIT"
|
||||||
if was_edit_mode:
|
if was_edit_mode:
|
||||||
bpy.ops.object.mode_set(mode="OBJECT")
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
obj=obj.name,
|
tool.Geometry,
|
||||||
should_switch_all_meshes=True,
|
obj=obj,
|
||||||
|
representation=representation,
|
||||||
should_reload=True,
|
should_reload=True,
|
||||||
ifc_definition_id=representation.id(),
|
enable_dynamic_voids=True,
|
||||||
disable_opening_subtractions=True,
|
is_global=True,
|
||||||
)
|
)
|
||||||
if was_edit_mode:
|
if was_edit_mode:
|
||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
@@ -286,8 +289,13 @@ def regenerate_profile_usage(usecase_path, ifc_file, settings):
|
|||||||
continue
|
continue
|
||||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
if representation:
|
if representation:
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
obj=obj.name, ifc_definition_id=representation.id(), should_reload=True, should_switch_all_meshes=True
|
tool.Geometry,
|
||||||
|
obj=obj,
|
||||||
|
representation=representation,
|
||||||
|
should_reload=True,
|
||||||
|
enable_dynamic_voids=True,
|
||||||
|
is_global=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -182,8 +182,13 @@ class DumbProfileGenerator:
|
|||||||
profile_set_usage=profile_set_usage,
|
profile_set_usage=profile_set_usage,
|
||||||
)
|
)
|
||||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
obj=obj.name, ifc_definition_id=representation.id(), should_reload=True, should_switch_all_meshes=True
|
tool.Geometry,
|
||||||
|
obj=obj,
|
||||||
|
representation=representation,
|
||||||
|
should_reload=True,
|
||||||
|
enable_dynamic_voids=True,
|
||||||
|
is_global=True,
|
||||||
)
|
)
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric")
|
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric")
|
||||||
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbProfile"})
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbProfile"})
|
||||||
@@ -239,8 +244,13 @@ class DumbProfileRegenerator:
|
|||||||
return
|
return
|
||||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
if representation:
|
if representation:
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
obj=obj.name, ifc_definition_id=representation.id(), should_reload=True, should_switch_all_meshes=True
|
tool.Geometry,
|
||||||
|
obj=obj,
|
||||||
|
representation=representation,
|
||||||
|
should_reload=True,
|
||||||
|
enable_dynamic_voids=True,
|
||||||
|
is_global=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def sync_object(self, element):
|
def sync_object(self, element):
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import bpy
|
|||||||
import ifcopenshell.util.schema
|
import ifcopenshell.util.schema
|
||||||
import ifcopenshell.util.type
|
import ifcopenshell.util.type
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.geometry
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.type.data import Data
|
from ifcopenshell.api.type.data import Data
|
||||||
from ifcopenshell.api.geometry.data import Data as GeometryData
|
from ifcopenshell.api.geometry.data import Data as GeometryData
|
||||||
@@ -64,13 +66,23 @@ class AssignType(bpy.types.Operator):
|
|||||||
for representation_id in representation_ids:
|
for representation_id in representation_ids:
|
||||||
representation = GeometryData.representations[representation_id]
|
representation = GeometryData.representations[representation_id]
|
||||||
if representation["ContextOfItems"]["ContextIdentifier"] == "Body":
|
if representation["ContextOfItems"]["ContextIdentifier"] == "Body":
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
obj=related_object.name, ifc_definition_id=representation_id, should_switch_all_meshes=False
|
tool.Geometry,
|
||||||
|
obj=related_object,
|
||||||
|
representation=tool.Ifc.get().by_id(representation_id),
|
||||||
|
should_reload=False,
|
||||||
|
enable_dynamic_voids=False,
|
||||||
|
is_global=False,
|
||||||
)
|
)
|
||||||
has_switched = True
|
has_switched = True
|
||||||
if not has_switched and representation_ids:
|
if not has_switched and representation_ids:
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
obj=related_object.name, ifc_definition_id=representation_id, should_switch_all_meshes=False
|
tool.Geometry,
|
||||||
|
obj=related_object,
|
||||||
|
representation=tool.Ifc.get().by_id(representation_id),
|
||||||
|
should_reload=False,
|
||||||
|
enable_dynamic_voids=False,
|
||||||
|
is_global=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
bpy.ops.bim.disable_editing_type(obj=related_object.name)
|
bpy.ops.bim.disable_editing_type(obj=related_object.name)
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.geometry
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.void.data import Data
|
from ifcopenshell.api.void.data import Data
|
||||||
|
|
||||||
@@ -120,10 +122,13 @@ class RemoveOpening(bpy.types.Operator):
|
|||||||
ifcopenshell.api.run("void.remove_opening", self.file, **{"opening": self.file.by_id(self.opening_id)})
|
ifcopenshell.api.run("void.remove_opening", self.file, **{"opening": self.file.by_id(self.opening_id)})
|
||||||
|
|
||||||
if not is_modifier_removed:
|
if not is_modifier_removed:
|
||||||
bpy.ops.bim.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
ifc_definition_id=obj.data.BIMMeshProperties.ifc_definition_id,
|
tool.Geometry,
|
||||||
|
obj=obj,
|
||||||
|
representation=tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id),
|
||||||
should_reload=True,
|
should_reload=True,
|
||||||
should_switch_all_meshes=True,
|
enable_dynamic_voids=False,
|
||||||
|
is_global=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||||
|
|||||||
@@ -66,8 +66,32 @@ def add_representation(
|
|||||||
ifc.run("geometry.assign_representation", product=element, representation=representation)
|
ifc.run("geometry.assign_representation", product=element, representation=representation)
|
||||||
|
|
||||||
data = geometry.duplicate_object_data(obj)
|
data = geometry.duplicate_object_data(obj)
|
||||||
name = geometry.get_representation_name(context, representation)
|
name = geometry.get_representation_name(representation)
|
||||||
geometry.rename_object_data(data, name)
|
geometry.rename_object(data, name)
|
||||||
geometry.link(representation, data)
|
geometry.link(representation, data)
|
||||||
|
|
||||||
return representation
|
return representation
|
||||||
|
|
||||||
|
|
||||||
|
def switch_representation(
|
||||||
|
geometry,
|
||||||
|
obj=None,
|
||||||
|
representation=None,
|
||||||
|
should_reload=True,
|
||||||
|
enable_dynamic_voids=True,
|
||||||
|
is_global=True,
|
||||||
|
):
|
||||||
|
representation = geometry.resolve_mapped_representation(representation)
|
||||||
|
data = geometry.get_representation_data(representation)
|
||||||
|
|
||||||
|
if not data or should_reload:
|
||||||
|
data = geometry.import_representation(obj, representation, enable_dynamic_voids=enable_dynamic_voids)
|
||||||
|
geometry.rename_object(data, geometry.get_representation_name(representation))
|
||||||
|
geometry.link(representation, data)
|
||||||
|
|
||||||
|
geometry.change_object_data(obj, data, is_global=is_global)
|
||||||
|
|
||||||
|
if enable_dynamic_voids and geometry.is_body_representation(representation):
|
||||||
|
geometry.create_dynamic_voids(obj)
|
||||||
|
else:
|
||||||
|
geometry.clear_dynamic_voids(obj)
|
||||||
|
|||||||
@@ -65,15 +65,22 @@ class Context:
|
|||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Geometry:
|
class Geometry:
|
||||||
|
def change_object_data(cls, obj, data, is_global=False): pass
|
||||||
|
def clear_dynamic_voids(cls, obj): pass
|
||||||
|
def create_dynamic_voids(cls, obj): pass
|
||||||
def does_object_have_mesh_with_faces(cls, obj): pass
|
def does_object_have_mesh_with_faces(cls, obj): pass
|
||||||
def duplicate_object_data(cls, obj): pass
|
def duplicate_object_data(cls, obj): pass
|
||||||
|
def get_cartesian_point_coordinate_offset(cls, obj): pass
|
||||||
def get_object_data(cls, obj): pass
|
def get_object_data(cls, obj): pass
|
||||||
def get_object_materials_without_styles(cls, obj): pass
|
def get_object_materials_without_styles(cls, obj): pass
|
||||||
def get_representation_name(cls, context, representation): pass
|
def get_representation_data(cls, representation): pass
|
||||||
def get_cartesian_point_coordinate_offset(cls, obj): pass
|
def get_representation_name(cls, representation): pass
|
||||||
def get_total_representation_items(cls, obj): pass
|
def get_total_representation_items(cls, obj): pass
|
||||||
|
def import_representation(cls, obj, representation, enable_dynamic_voids=False): pass
|
||||||
|
def is_body_representation(cls, representation): pass
|
||||||
def link(cls, element, obj): pass
|
def link(cls, element, obj): pass
|
||||||
def rename_object_data(cls, data, name): pass
|
def rename_object(cls, obj, name): pass
|
||||||
|
def resolve_mapped_representation(cls, representation): pass
|
||||||
def should_force_faceted_brep(cls): pass
|
def should_force_faceted_brep(cls): pass
|
||||||
def should_force_triangulation(cls): pass
|
def should_force_triangulation(cls): pass
|
||||||
def should_use_presentation_style_assignment(cls): pass
|
def should_use_presentation_style_assignment(cls): pass
|
||||||
|
|||||||
@@ -17,13 +17,42 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import logging
|
||||||
|
import ifcopenshell
|
||||||
import blenderbim.core.tool
|
import blenderbim.core.tool
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.bim.import_ifc
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
|
|
||||||
class Geometry(blenderbim.core.tool.Geometry):
|
class Geometry(blenderbim.core.tool.Geometry):
|
||||||
|
@classmethod
|
||||||
|
def change_object_data(cls, obj, data, is_global=False):
|
||||||
|
if is_global:
|
||||||
|
obj.data.user_remap(data)
|
||||||
|
else:
|
||||||
|
obj.data = data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_dynamic_voids(cls, obj):
|
||||||
|
for modifier in obj.modifiers:
|
||||||
|
if modifier.type == "BOOLEAN" and "IfcOpeningElement" in modifier.name:
|
||||||
|
obj.modifiers.remove(modifier)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_dynamic_voids(cls, obj):
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
for rel in element.HasOpenings:
|
||||||
|
opening_obj = tool.Ifc.get_object(rel.RelatedOpeningElement)
|
||||||
|
if not opening_obj:
|
||||||
|
continue
|
||||||
|
modifier = obj.modifiers.new("IfcOpeningElement", "BOOLEAN")
|
||||||
|
modifier.operation = "DIFFERENCE"
|
||||||
|
modifier.object = opening_obj
|
||||||
|
modifier.solver = "EXACT"
|
||||||
|
modifier.use_self = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def does_object_have_mesh_with_faces(cls, obj):
|
def does_object_have_mesh_with_faces(cls, obj):
|
||||||
return bool(isinstance(obj.data, bpy.types.Mesh) and len(obj.data.polygons))
|
return bool(isinstance(obj.data, bpy.types.Mesh) and len(obj.data.polygons))
|
||||||
@@ -44,8 +73,12 @@ class Geometry(blenderbim.core.tool.Geometry):
|
|||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_representation_name(cls, context, representation):
|
def get_representation_data(cls, representation):
|
||||||
return f"{context.id()}/{representation.id()}"
|
return bpy.data.meshes.get(cls.get_representation_name(representation))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_representation_name(cls, representation):
|
||||||
|
return f"{representation.ContextOfItems.id()}/{representation.id()}"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_cartesian_point_coordinate_offset(cls, obj):
|
def get_cartesian_point_coordinate_offset(cls, obj):
|
||||||
@@ -63,13 +96,46 @@ class Geometry(blenderbim.core.tool.Geometry):
|
|||||||
def get_total_representation_items(cls, obj):
|
def get_total_representation_items(cls, obj):
|
||||||
return max(1, len(obj.material_slots))
|
return max(1, len(obj.material_slots))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def import_representation(cls, obj, representation, enable_dynamic_voids=False):
|
||||||
|
logger = logging.getLogger("ImportIFC")
|
||||||
|
ifc_import_settings = blenderbim.bim.import_ifc.IfcImportSettings.factory(bpy.context, None, logger)
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
settings = ifcopenshell.geom.settings()
|
||||||
|
|
||||||
|
if representation.ContextOfItems.ContextIdentifier == "Body":
|
||||||
|
if element.is_a("IfcTypeProduct") or enable_dynamic_voids:
|
||||||
|
shape = ifcopenshell.geom.create_shape(settings, representation)
|
||||||
|
else:
|
||||||
|
shape = ifcopenshell.geom.create_shape(settings, element)
|
||||||
|
else:
|
||||||
|
settings.set(settings.INCLUDE_CURVES, True)
|
||||||
|
shape = ifcopenshell.geom.create_shape(settings, representation)
|
||||||
|
|
||||||
|
ifc_importer = blenderbim.bim.import_ifc.IfcImporter(ifc_import_settings)
|
||||||
|
ifc_importer.file = tool.Ifc.get()
|
||||||
|
mesh = ifc_importer.create_mesh(element, shape)
|
||||||
|
ifc_importer.material_creator.load_existing_materials()
|
||||||
|
ifc_importer.material_creator.create(element, obj, mesh)
|
||||||
|
return mesh
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_body_representation(cls, representation):
|
||||||
|
return representation.ContextOfItems.ContextIdentifier == "Body"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def link(cls, element, obj):
|
def link(cls, element, obj):
|
||||||
obj.BIMMeshProperties.ifc_definition_id = element.id()
|
obj.BIMMeshProperties.ifc_definition_id = element.id()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def rename_object_data(cls, data, name):
|
def rename_object(cls, obj, name):
|
||||||
data.name = name
|
obj.name = name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve_mapped_representation(cls, representation):
|
||||||
|
if representation.RepresentationType == "MappedRepresentation":
|
||||||
|
return cls.resolve_mapped_representation(representation.Items[0].MappingSource.MappedRepresentation)
|
||||||
|
return representation
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def should_force_faceted_brep(cls):
|
def should_force_faceted_brep(cls):
|
||||||
|
|||||||
@@ -23,6 +23,16 @@ Scenario: Add representation
|
|||||||
And I press "bim.add_representation"
|
And I press "bim.add_representation"
|
||||||
Then nothing happens
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Switch representation
|
||||||
|
Given an empty IFC project
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
When the variable "representation" is "{ifc}.by_type('IfcShapeRepresentation')[0].id()"
|
||||||
|
And I press "bim.switch_representation(obj='IfcWall/Cube', ifc_definition_id={representation})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
Scenario: Copy representation
|
Scenario: Copy representation
|
||||||
Given an empty IFC project
|
Given an empty IFC project
|
||||||
And I add a cube
|
And I add a cube
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ class TestAddRepresentation:
|
|||||||
|
|
||||||
# Update mesh
|
# Update mesh
|
||||||
geometry.duplicate_object_data("obj").should_be_called().will_return("data")
|
geometry.duplicate_object_data("obj").should_be_called().will_return("data")
|
||||||
geometry.get_representation_name("context", "representation").should_be_called().will_return("name")
|
geometry.get_representation_name("representation").should_be_called().will_return("name")
|
||||||
geometry.rename_object_data("data", "name").should_be_called()
|
geometry.rename_object("data", "name").should_be_called()
|
||||||
geometry.link("representation", "data").should_be_called()
|
geometry.link("representation", "data").should_be_called()
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@@ -124,8 +124,8 @@ class TestAddRepresentation:
|
|||||||
|
|
||||||
# Update mesh
|
# Update mesh
|
||||||
geometry.duplicate_object_data("obj").should_be_called().will_return("data")
|
geometry.duplicate_object_data("obj").should_be_called().will_return("data")
|
||||||
geometry.get_representation_name("context", "representation").should_be_called().will_return("name")
|
geometry.get_representation_name("representation").should_be_called().will_return("name")
|
||||||
geometry.rename_object_data("data", "name").should_be_called()
|
geometry.rename_object("data", "name").should_be_called()
|
||||||
geometry.link("representation", "data").should_be_called()
|
geometry.link("representation", "data").should_be_called()
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@@ -176,3 +176,26 @@ class TestAddRepresentation:
|
|||||||
)
|
)
|
||||||
is None
|
is None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSwitchRepresentation:
|
||||||
|
def test_run(self, ifc, geometry, style, surveyor):
|
||||||
|
geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation")
|
||||||
|
geometry.get_representation_data("representation").should_be_called().will_return("data")
|
||||||
|
geometry.import_representation(
|
||||||
|
"obj", "representation", enable_dynamic_voids=True
|
||||||
|
).should_be_called().will_return("new_data")
|
||||||
|
geometry.get_representation_name("representation").should_be_called().will_return("name")
|
||||||
|
geometry.rename_object("new_data", "name").should_be_called()
|
||||||
|
geometry.link("representation", "new_data").should_be_called()
|
||||||
|
geometry.change_object_data("obj", "new_data", is_global=True).should_be_called()
|
||||||
|
geometry.is_body_representation("representation").should_be_called().will_return(True)
|
||||||
|
geometry.create_dynamic_voids("obj").should_be_called()
|
||||||
|
subject.switch_representation(
|
||||||
|
geometry,
|
||||||
|
obj="obj",
|
||||||
|
representation="mapped_rep",
|
||||||
|
should_reload=True,
|
||||||
|
enable_dynamic_voids=True,
|
||||||
|
is_global=True,
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
ISO-10303-21;
|
||||||
|
HEADER;
|
||||||
|
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
|
||||||
|
FILE_NAME('annotation.ifc','2021-10-19T11:50:01+11:00',(),(),'IfcOpenShell v0.7.0-6cc7d796','BlenderBIM 0.0.999999','Nobody');
|
||||||
|
FILE_SCHEMA(('IFC4'));
|
||||||
|
ENDSEC;
|
||||||
|
DATA;
|
||||||
|
#1=IFCPERSON('HSeldon','Seldon','Hari',$,$,$,$,$);
|
||||||
|
#2=IFCORGANIZATION('APTR','Aperture Science',$,$,$);
|
||||||
|
#3=IFCPERSONANDORGANIZATION(#1,#2,$);
|
||||||
|
#4=IFCACTORROLE(.USERDEFINED.,'CONTRIBUTOR',$);
|
||||||
|
#5=IFCTELECOMADDRESS(.USERDEFINED.,$,'WEBPAGE',$,$,$,$,'https://ifcopenshell.org',$);
|
||||||
|
#6=IFCORGANIZATION('IfcOpenShell','IfcOpenShell','IfcOpenShell is an open source software library that helps users and software developers to work with IFC data.',(#4),(#5));
|
||||||
|
#7=IFCAPPLICATION(#6,'0.0.999999','BlenderBIM Add-on','BlenderBIM');
|
||||||
|
#8=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
|
||||||
|
#9=IFCPROJECT('0NqkoFmWPBxvsDLeGa5rDc',#8,'My Project',$,$,$,$,(#18,#24),#13);
|
||||||
|
#10=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
|
||||||
|
#11=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
|
||||||
|
#12=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
|
||||||
|
#13=IFCUNITASSIGNMENT((#11,#12,#10));
|
||||||
|
#14=IFCCARTESIANPOINT((0.,0.,0.));
|
||||||
|
#15=IFCDIRECTION((0.,0.,1.));
|
||||||
|
#16=IFCDIRECTION((1.,0.,0.));
|
||||||
|
#17=IFCAXIS2PLACEMENT3D(#14,#15,#16);
|
||||||
|
#18=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#17,$);
|
||||||
|
#19=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#18,$,.MODEL_VIEW.,$);
|
||||||
|
#20=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Box','Model',*,*,*,*,#18,$,.MODEL_VIEW.,$);
|
||||||
|
#21=IFCCARTESIANPOINT((0.,0.,0.));
|
||||||
|
#22=IFCDIRECTION((1.,0.,0.));
|
||||||
|
#23=IFCAXIS2PLACEMENT2D(#21,#22);
|
||||||
|
#24=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#23,$);
|
||||||
|
#25=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#24,$,.PLAN_VIEW.,$);
|
||||||
|
#26=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604558,#3,#7,1634604558);
|
||||||
|
#27=IFCSITE('3kJImD6Rr4NfpxM218DNpq',#26,'My Site',$,$,#53,$,$,$,$,$,$,$,$);
|
||||||
|
#33=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604558,#3,#7,1634604558);
|
||||||
|
#34=IFCBUILDING('3afq36fJb80A_bTAB9RB0f',#33,'My Building',$,$,#60,$,$,$,$,$,$);
|
||||||
|
#40=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604558,#3,#7,1634604558);
|
||||||
|
#41=IFCBUILDINGSTOREY('2vQTqYOy13G8THztmBknz3',#40,'My Storey',$,$,#67,$,$,$,$);
|
||||||
|
#47=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
|
||||||
|
#48=IFCRELAGGREGATES('22R8p4a0z4jAFLUof7ha5H',#47,$,$,#9,(#27));
|
||||||
|
#49=IFCCARTESIANPOINT((0.,0.,0.));
|
||||||
|
#50=IFCDIRECTION((0.,0.,1.));
|
||||||
|
#51=IFCDIRECTION((1.,0.,0.));
|
||||||
|
#52=IFCAXIS2PLACEMENT3D(#49,#50,#51);
|
||||||
|
#53=IFCLOCALPLACEMENT($,#52);
|
||||||
|
#54=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
|
||||||
|
#55=IFCRELAGGREGATES('1ty5GrCRX0vPrGpg4F_2JL',#54,$,$,#27,(#34));
|
||||||
|
#56=IFCCARTESIANPOINT((0.,0.,0.));
|
||||||
|
#57=IFCDIRECTION((0.,0.,1.));
|
||||||
|
#58=IFCDIRECTION((1.,0.,0.));
|
||||||
|
#59=IFCAXIS2PLACEMENT3D(#56,#57,#58);
|
||||||
|
#60=IFCLOCALPLACEMENT(#53,#59);
|
||||||
|
#61=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604558,#3,#7,1634604558);
|
||||||
|
#62=IFCRELAGGREGATES('1Lbqbq3O56pg1ouvCD5WR9',#61,$,$,#34,(#41));
|
||||||
|
#63=IFCCARTESIANPOINT((0.,0.,0.));
|
||||||
|
#64=IFCDIRECTION((0.,0.,1.));
|
||||||
|
#65=IFCDIRECTION((1.,0.,0.));
|
||||||
|
#66=IFCAXIS2PLACEMENT3D(#63,#64,#65);
|
||||||
|
#67=IFCLOCALPLACEMENT(#60,#66);
|
||||||
|
#68=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1634604586,#3,#7,1634604586);
|
||||||
|
#69=IFCWALL('2iJrnC5QfEH8KDFgXqLR5J',#68,'Square',$,$,#88,#81,$,.ELEMENTEDWALL.);
|
||||||
|
#75=IFCCARTESIANPOINTLIST2D(((1.,1.),(1.,-1.),(-1.,1.),(-1.,-1.)));
|
||||||
|
#76=IFCINDEXEDPOLYCURVE(#75,(IFCLINEINDEX((3,4))),$);
|
||||||
|
#77=IFCINDEXEDPOLYCURVE(#75,(IFCLINEINDEX((1,3))),$);
|
||||||
|
#78=IFCINDEXEDPOLYCURVE(#75,(IFCLINEINDEX((4,2)),IFCLINEINDEX((2,1))),$);
|
||||||
|
#79=IFCGEOMETRICCURVESET((#76,#77,#78));
|
||||||
|
#80=IFCSHAPEREPRESENTATION(#25,'Annotation','Annotation2D',(#79));
|
||||||
|
#81=IFCPRODUCTDEFINITIONSHAPE($,$,(#80));
|
||||||
|
#82=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1634604586,#3,#7,1634604586);
|
||||||
|
#83=IFCRELCONTAINEDINSPATIALSTRUCTURE('1AG29wImP3hgw6L3xSIacB',#82,$,$,(#69),#41);
|
||||||
|
#84=IFCCARTESIANPOINT((0.,0.,0.));
|
||||||
|
#85=IFCDIRECTION((0.,0.,1.));
|
||||||
|
#86=IFCDIRECTION((1.,0.,0.));
|
||||||
|
#87=IFCAXIS2PLACEMENT3D(#84,#85,#86);
|
||||||
|
#88=IFCLOCALPLACEMENT(#67,#87);
|
||||||
|
ENDSEC;
|
||||||
|
END-ISO-10303-21;
|
||||||
@@ -33,6 +33,55 @@ class TestImplementsTool(test.bim.bootstrap.NewFile):
|
|||||||
assert isinstance(subject(), blenderbim.core.tool.Geometry)
|
assert isinstance(subject(), blenderbim.core.tool.Geometry)
|
||||||
|
|
||||||
|
|
||||||
|
class TestChangeObjectData(test.bim.bootstrap.NewFile):
|
||||||
|
def test_change_single_object_data(self):
|
||||||
|
data1 = bpy.data.meshes.new("Mesh")
|
||||||
|
data2 = bpy.data.meshes.new("Mesh")
|
||||||
|
obj1 = bpy.data.objects.new("Object", data1)
|
||||||
|
obj2 = bpy.data.objects.new("Object", data1)
|
||||||
|
subject.change_object_data(obj1, data2, is_global=False)
|
||||||
|
assert obj1.data == data2
|
||||||
|
assert obj2.data == data1
|
||||||
|
|
||||||
|
def test_change_object_data_globally(self):
|
||||||
|
data1 = bpy.data.meshes.new("Mesh")
|
||||||
|
data2 = bpy.data.meshes.new("Mesh")
|
||||||
|
obj1 = bpy.data.objects.new("Object", data1)
|
||||||
|
obj2 = bpy.data.objects.new("Object", data1)
|
||||||
|
subject.change_object_data(obj1, data2, is_global=True)
|
||||||
|
assert obj1.data == data2
|
||||||
|
assert obj2.data == data2
|
||||||
|
|
||||||
|
|
||||||
|
class TestClearDynamicVoids(test.bim.bootstrap.NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||||
|
obj.modifiers.new("IfcOpeningElement", "BOOLEAN")
|
||||||
|
subject.clear_dynamic_voids(obj)
|
||||||
|
assert len(obj.modifiers) == 0
|
||||||
|
|
||||||
|
|
||||||
|
class TestCreateDynamicVoids(test.bim.bootstrap.NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
wall = ifc.createIfcWall()
|
||||||
|
opening = ifc.createIfcOpeningElement()
|
||||||
|
ifcopenshell.api.run("void.add_opening", ifc, opening=opening, element=wall)
|
||||||
|
wall_obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||||
|
opening_obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||||
|
tool.Ifc.link(wall, wall_obj)
|
||||||
|
tool.Ifc.link(opening, opening_obj)
|
||||||
|
subject.create_dynamic_voids(wall_obj)
|
||||||
|
modifier = wall_obj.modifiers[0]
|
||||||
|
assert modifier.type == "BOOLEAN"
|
||||||
|
assert modifier.name == "IfcOpeningElement"
|
||||||
|
assert modifier.operation == "DIFFERENCE"
|
||||||
|
assert modifier.object == opening_obj
|
||||||
|
assert modifier.solver == "EXACT"
|
||||||
|
assert modifier.use_self is True
|
||||||
|
|
||||||
|
|
||||||
class TestDoesObjectHaveMeshWithFaces(test.bim.bootstrap.NewFile):
|
class TestDoesObjectHaveMeshWithFaces(test.bim.bootstrap.NewFile):
|
||||||
def test_empties_return_false(self):
|
def test_empties_return_false(self):
|
||||||
obj = bpy.data.objects.new("Object", None)
|
obj = bpy.data.objects.new("Object", None)
|
||||||
@@ -81,12 +130,23 @@ class TestGetObjectMaterialsWithoutStyles(test.bim.bootstrap.NewFile):
|
|||||||
assert subject.get_object_materials_without_styles(obj) == [material1, material2]
|
assert subject.get_object_materials_without_styles(obj) == [material1, material2]
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetRepresentationData(test.bim.bootstrap.NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
context = ifc.createIfcGeometricRepresentationContext()
|
||||||
|
representation = ifc.createIfcShapeRepresentation()
|
||||||
|
representation.ContextOfItems = context
|
||||||
|
data = bpy.data.meshes.new("1/2")
|
||||||
|
assert subject.get_representation_data(representation) == data
|
||||||
|
|
||||||
|
|
||||||
class TestGetRepresentationName(test.bim.bootstrap.NewFile):
|
class TestGetRepresentationName(test.bim.bootstrap.NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
context = ifc.createIfcGeometricRepresentationContext()
|
context = ifc.createIfcGeometricRepresentationContext()
|
||||||
representation = ifc.createIfcShapeRepresentation()
|
representation = ifc.createIfcShapeRepresentation()
|
||||||
assert subject.get_representation_name(context, representation) == f"{context.id()}/{representation.id()}"
|
representation.ContextOfItems = context
|
||||||
|
assert subject.get_representation_name(representation) == f"{context.id()}/{representation.id()}"
|
||||||
|
|
||||||
|
|
||||||
class TestGetCartesianPointCoordinateOffset(test.bim.bootstrap.NewFile):
|
class TestGetCartesianPointCoordinateOffset(test.bim.bootstrap.NewFile):
|
||||||
@@ -127,6 +187,44 @@ class TestGetTotalRepresentationItems(test.bim.bootstrap.NewFile):
|
|||||||
assert subject.get_total_representation_items(obj) == 2
|
assert subject.get_total_representation_items(obj) == 2
|
||||||
|
|
||||||
|
|
||||||
|
class TestImportRepresentation(test.bim.bootstrap.NewFile):
|
||||||
|
def test_importing_a_normal_shape(self):
|
||||||
|
ifc = ifcopenshell.open("test/files/basic.ifc")
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||||
|
material = bpy.data.materials.new("Material")
|
||||||
|
material.BIMMaterialProperties.ifc_style_id = 101
|
||||||
|
element = ifc.by_type("IfcWall")[0]
|
||||||
|
tool.Ifc.link(element, obj)
|
||||||
|
representation = element.Representation.Representations[0]
|
||||||
|
mesh = subject.import_representation(obj, representation, enable_dynamic_voids=False)
|
||||||
|
assert len(mesh.polygons) == 12
|
||||||
|
assert mesh.materials[0] == material
|
||||||
|
|
||||||
|
def test_importing_non_body_curves(self):
|
||||||
|
ifc = ifcopenshell.open("test/files/annotation.ifc")
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||||
|
element = ifc.by_type("IfcWall")[0]
|
||||||
|
tool.Ifc.link(element, obj)
|
||||||
|
representation = element.Representation.Representations[0]
|
||||||
|
mesh = subject.import_representation(obj, representation, enable_dynamic_voids=False)
|
||||||
|
assert len(mesh.polygons) == 0
|
||||||
|
assert len(mesh.edges) == 4
|
||||||
|
|
||||||
|
|
||||||
|
class TestIsBodyRepresentation(test.bim.bootstrap.NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
context = ifc.createIfcGeometricRepresentationContext()
|
||||||
|
representation = ifc.createIfcShapeRepresentation()
|
||||||
|
representation.ContextOfItems = context
|
||||||
|
context.ContextIdentifier = "Body"
|
||||||
|
assert subject.is_body_representation(representation) is True
|
||||||
|
context.ContextIdentifier = "Clearance"
|
||||||
|
assert subject.is_body_representation(representation) is False
|
||||||
|
|
||||||
|
|
||||||
class TestLink(test.bim.bootstrap.NewFile):
|
class TestLink(test.bim.bootstrap.NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -139,10 +237,27 @@ class TestLink(test.bim.bootstrap.NewFile):
|
|||||||
class TestRenameObjectData(test.bim.bootstrap.NewFile):
|
class TestRenameObjectData(test.bim.bootstrap.NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
obj = bpy.data.meshes.new("Mesh")
|
obj = bpy.data.meshes.new("Mesh")
|
||||||
subject.rename_object_data(obj, "name")
|
subject.rename_object(obj, "name")
|
||||||
assert obj.name == "name"
|
assert obj.name == "name"
|
||||||
|
|
||||||
|
|
||||||
|
class TestResolveMappedRepresentation(test.bim.bootstrap.NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
mapped_representation = ifc.createIfcShapeRepresentation()
|
||||||
|
representation = ifc.createIfcShapeRepresentation()
|
||||||
|
mapped_representation.RepresentationType = "MappedRepresentation"
|
||||||
|
mapped_representation.Items = [
|
||||||
|
ifc.createIfcMappedItem(MappingSource=ifc.createIfcRepresentationMap(MappedRepresentation=representation))
|
||||||
|
]
|
||||||
|
assert subject.resolve_mapped_representation(mapped_representation) == representation
|
||||||
|
|
||||||
|
def test_return_a_representation_if_not_mapped(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
representation = ifc.createIfcShapeRepresentation()
|
||||||
|
assert subject.resolve_mapped_representation(representation) == representation
|
||||||
|
|
||||||
|
|
||||||
class TestShouldForceFacetedBrep(test.bim.bootstrap.NewFile):
|
class TestShouldForceFacetedBrep(test.bim.bootstrap.NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
result = bpy.context.scene.BIMGeometryProperties.should_force_faceted_brep
|
result = bpy.context.scene.BIMGeometryProperties.should_force_faceted_brep
|
||||||
|
|||||||
Reference in New Issue
Block a user