mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
New dumb column tool. Creates a parametric solid column from profile sets.
This commit is contained in:
@@ -58,6 +58,7 @@ class AddRepresentation(bpy.types.Operator):
|
||||
obj: bpy.props.StringProperty()
|
||||
context_id: bpy.props.IntProperty()
|
||||
ifc_representation_class: bpy.props.StringProperty()
|
||||
profile_set: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||
@@ -93,6 +94,7 @@ class AddRepresentation(bpy.types.Operator):
|
||||
"should_force_faceted_brep": context.scene.BIMGeometryProperties.should_force_faceted_brep,
|
||||
"should_force_triangulation": context.scene.BIMGeometryProperties.should_force_triangulation,
|
||||
"ifc_representation_class": self.ifc_representation_class,
|
||||
"profile_set": self.file.by_id(self.profile_set) if self.profile_set else None
|
||||
}
|
||||
|
||||
result = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import bpy
|
||||
import bmesh
|
||||
import math
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.type
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.element
|
||||
import mathutils.geometry
|
||||
import blenderbim.bim.handler
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from math import pi, degrees
|
||||
from mathutils import Vector, Matrix
|
||||
from ifcopenshell.api.pset.data import Data as PsetData
|
||||
from ifcopenshell.api.material.data import Data as MaterialData
|
||||
from blenderbim.bim.module.geometry.helper import Helper
|
||||
|
||||
|
||||
def element_listener(element, obj):
|
||||
blenderbim.bim.handler.subscribe_to(obj, "mode", mode_callback)
|
||||
|
||||
|
||||
def mode_callback(obj, data):
|
||||
for obj in bpy.context.selected_objects + [bpy.context.active_object]:
|
||||
if (
|
||||
obj.mode != "EDIT"
|
||||
or not obj.data
|
||||
or not isinstance(obj.data, (bpy.types.Mesh, bpy.types.Curve, bpy.types.TextCurve))
|
||||
or not obj.BIMObjectProperties.ifc_definition_id
|
||||
or not bpy.context.scene.BIMProjectProperties.is_authoring
|
||||
):
|
||||
return
|
||||
product = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric")
|
||||
if not parametric or parametric["Engine"] != "BlenderBIM.DumbColumn":
|
||||
return
|
||||
IfcStore.edited_objs.add(obj)
|
||||
bm = bmesh.from_edit_mesh(obj.data)
|
||||
bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 1, verts=bm.verts, edges=bm.edges)
|
||||
bmesh.update_edit_mesh(obj.data)
|
||||
bm.free()
|
||||
|
||||
|
||||
def ensure_solid(usecase_path, ifc_file, settings):
|
||||
product = ifc_file.by_id(settings["blender_object"].BIMObjectProperties.ifc_definition_id)
|
||||
parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric")
|
||||
if not parametric or parametric["Engine"] != "BlenderBIM.DumbColumn":
|
||||
return
|
||||
material = ifcopenshell.util.element.get_material(product)
|
||||
if material and material.is_a("IfcMaterialProfileSet"):
|
||||
settings["profile_set"] = material
|
||||
else:
|
||||
return
|
||||
settings["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcMaterialProfileSet"
|
||||
|
||||
|
||||
class DumbColumnGenerator:
|
||||
def __init__(self, relating_type):
|
||||
self.relating_type = relating_type
|
||||
|
||||
def generate(self):
|
||||
self.file = IfcStore.get_file()
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(IfcStore.get_file())
|
||||
material = ifcopenshell.util.element.get_material(self.relating_type)
|
||||
if material and material.is_a("IfcMaterialProfileSet"):
|
||||
self.profile_set = material
|
||||
else:
|
||||
return
|
||||
|
||||
self.collection = bpy.context.view_layer.active_layer_collection.collection
|
||||
self.collection_obj = bpy.data.objects.get(self.collection.name)
|
||||
self.length = 3
|
||||
self.rotation = 0
|
||||
self.location = Vector((0, 0, 0))
|
||||
return self.derive_from_cursor()
|
||||
|
||||
def derive_from_cursor(self):
|
||||
self.location = bpy.context.scene.cursor.location
|
||||
return self.create_column()
|
||||
|
||||
def create_column(self):
|
||||
# A cube
|
||||
verts = [
|
||||
Vector((-1, -1, -1)),
|
||||
Vector((-1, -1, 1)),
|
||||
Vector((-1, 1, -1)),
|
||||
Vector((-1, 1, 1)),
|
||||
Vector((1, -1, -1)),
|
||||
Vector((1, -1, 1)),
|
||||
Vector((1, 1, -1)),
|
||||
Vector((1, 1, 1)),
|
||||
]
|
||||
edges = []
|
||||
faces = [
|
||||
[0, 2, 3, 1],
|
||||
[2, 3, 7, 6],
|
||||
[4, 5, 7, 6],
|
||||
[0, 1, 5, 4],
|
||||
[1, 3, 7, 5],
|
||||
[0, 2, 6, 4],
|
||||
]
|
||||
|
||||
mesh = bpy.data.meshes.new(name="Dumb Column")
|
||||
mesh.from_pydata(verts, edges, faces)
|
||||
obj = bpy.data.objects.new("Column", mesh)
|
||||
obj.name = "Column"
|
||||
obj.location = self.location
|
||||
if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
|
||||
obj.location[2] = self.collection_obj.location[2]
|
||||
self.collection.objects.link(obj)
|
||||
bpy.ops.bim.assign_class(
|
||||
obj=obj.name, ifc_class="IfcColumn", predefined_type="COLUMN", should_add_representation=False
|
||||
)
|
||||
bpy.ops.bim.assign_type(relating_type=self.relating_type.id(), related_object=obj.name)
|
||||
bpy.ops.bim.add_representation(
|
||||
obj=obj.name,
|
||||
context_id=ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW").id(),
|
||||
ifc_representation_class="IfcExtrudedAreaSolid/IfcMaterialProfileSet",
|
||||
profile_set=self.profile_set.id(),
|
||||
)
|
||||
representation = ifcopenshell.util.representation.get_representation(
|
||||
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "Model", "Body", "MODEL_VIEW"
|
||||
)
|
||||
bpy.ops.bim.switch_representation(obj=obj.name, ifc_definition_id=representation.id(), should_reload=True)
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
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.DumbColumn"})
|
||||
MaterialData.load(self.file)
|
||||
obj.select_set(True)
|
||||
return obj
|
||||
@@ -1,7 +1,7 @@
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.module.model import product, wall, slab
|
||||
from blenderbim.bim.module.model import product, wall, slab, column
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from bpy.app.handlers import persistent
|
||||
|
||||
@@ -45,3 +45,8 @@ def load_post(*args):
|
||||
ifcopenshell.api.add_pre_listener(
|
||||
"type.assign_type", "BlenderBIM.DumbSlab.RegenerateFromType", slab.DumbSlabPlaner().regenerate_from_type
|
||||
)
|
||||
|
||||
IfcStore.add_element_listener(column.element_listener)
|
||||
ifcopenshell.api.add_pre_listener(
|
||||
"geometry.add_representation", "BlenderBIM.DumbColumn.EnsureSolid", column.ensure_solid
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
from . import wall, slab
|
||||
from . import wall, slab, column
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.pset.data import Data as PsetData
|
||||
from mathutils import Vector
|
||||
@@ -32,6 +32,10 @@ class AddTypeInstance(bpy.types.Operator):
|
||||
obj = slab.DumbSlabGenerator(self.file.by_id(int(relating_type))).generate()
|
||||
if obj:
|
||||
return {"FINISHED"}
|
||||
elif ifc_class == "IfcColumnType":
|
||||
obj = column.DumbColumnGenerator(self.file.by_id(int(relating_type))).generate()
|
||||
if obj:
|
||||
return {"FINISHED"}
|
||||
# A cube
|
||||
verts = [
|
||||
Vector((-1, -1, -1)),
|
||||
|
||||
@@ -83,6 +83,7 @@ class AssignClass(bpy.types.Operator):
|
||||
predefined_type: bpy.props.StringProperty()
|
||||
userdefined_type: bpy.props.StringProperty()
|
||||
context_id: bpy.props.IntProperty()
|
||||
should_add_representation: bpy.props.BoolProperty(default=True)
|
||||
ifc_representation_class: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
@@ -112,9 +113,10 @@ class AssignClass(bpy.types.Operator):
|
||||
obj.name = "{}/{}".format(product.is_a(), obj.name)
|
||||
IfcStore.link_element(product, obj)
|
||||
|
||||
bpy.ops.bim.add_representation(
|
||||
obj=obj.name, context_id=self.context_id, ifc_representation_class=self.ifc_representation_class
|
||||
)
|
||||
if self.should_add_representation:
|
||||
bpy.ops.bim.add_representation(
|
||||
obj=obj.name, context_id=self.context_id, ifc_representation_class=self.ifc_representation_class
|
||||
)
|
||||
|
||||
if product.is_a("IfcElementType"):
|
||||
self.place_in_types_collection(obj)
|
||||
|
||||
@@ -30,7 +30,9 @@ class Usecase:
|
||||
# IfcExtrudedAreaSolid/IfcCircleProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids
|
||||
# IfcExtrudedAreaSolid/IfcMaterialProfileSet
|
||||
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
||||
"profile_set": None, # The material profile set if the extrusion requires it
|
||||
}
|
||||
self.ifc_vertices = []
|
||||
for key, value in settings.items():
|
||||
@@ -217,6 +219,8 @@ class Usecase:
|
||||
return self.create_arbitrary_extrusion_representation()
|
||||
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids":
|
||||
return self.create_arbitrary_void_extrusion_representation()
|
||||
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcMaterialProfileSet":
|
||||
return self.create_material_profile_set_extrusion_representation()
|
||||
return self.create_mesh_representation()
|
||||
|
||||
def create_camera_block_representation(self):
|
||||
@@ -404,6 +408,31 @@ class Usecase:
|
||||
[item],
|
||||
)
|
||||
|
||||
def create_material_profile_set_extrusion_representation(self):
|
||||
profile_def = (
|
||||
self.settings["profile_set"].CompositeProfile
|
||||
or self.settings["profile_set"].MaterialProfiles[0].Profile
|
||||
)
|
||||
position = None
|
||||
if self.file.schema == "IFC2X3":
|
||||
position = self.file.createIfcAxis2Placement3D(
|
||||
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||
self.file.createIfcDirection((1.0, 0.0, 0.0)),
|
||||
)
|
||||
item = self.file.createIfcExtrudedAreaSolid(
|
||||
profile_def,
|
||||
position,
|
||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||
self.convert_si_to_unit(self.settings["blender_object"].dimensions[2]),
|
||||
)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"SweptSolid",
|
||||
[item],
|
||||
)
|
||||
|
||||
def create_mesh_representation(self):
|
||||
if self.file.schema == "IFC2X3" or self.settings["should_force_faceted_brep"]:
|
||||
return self.create_faceted_brep()
|
||||
|
||||
@@ -38,7 +38,15 @@ class Usecase:
|
||||
material_set = self.file.create_entity(self.settings["type"])
|
||||
self.create_material_association(material_set)
|
||||
elif self.settings["type"] == "IfcMaterialProfileSetUsage":
|
||||
material_set = self.file.create_entity("IfcMaterialProfileSet")
|
||||
element_type = ifcopenshell.util.element.get_type(self.settings["product"])
|
||||
if element_type:
|
||||
element_type_material = ifcopenshell.util.element.get_material(element_type)
|
||||
if element_type_material and element_type_material.is_a("IfcMaterialProfileSet"):
|
||||
material_set = element_type_material
|
||||
else:
|
||||
material_set = self.file.create_entity("IfcMaterialProfileSet")
|
||||
else:
|
||||
material_set = self.file.create_entity("IfcMaterialProfileSet")
|
||||
material_set_usage = self.create_profile_set_usage(material_set)
|
||||
self.create_material_association(material_set_usage)
|
||||
elif self.settings["type"] == "IfcMaterialList":
|
||||
|
||||
@@ -52,7 +52,9 @@ def get_properties(properties):
|
||||
|
||||
|
||||
def get_type(element):
|
||||
if hasattr(element, "IsTypedBy") and element.IsTypedBy:
|
||||
if element.is_a("IfcTypeObject"):
|
||||
return element
|
||||
elif hasattr(element, "IsTypedBy") and element.IsTypedBy:
|
||||
return element.IsTypedBy[0].RelatingType
|
||||
elif hasattr(element, "IsDefinedBy") and element.IsDefinedBy: # IFC2X3
|
||||
for relationship in element.IsDefinedBy:
|
||||
|
||||
Reference in New Issue
Block a user