mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-30 16:43:00 +00:00
Revert "Squashed commit of the following:"
This reverts commit f07cf1d1ef.
This commit is contained in:
@@ -160,8 +160,7 @@ def register():
|
||||
bpy.types.Camera.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.PointLight.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
|
||||
if hasattr(bpy.types, "UI_MT_button_context_menu"):
|
||||
bpy.types.UI_MT_button_context_menu.append(ui.draw_custom_context_menu)
|
||||
bpy.types.UI_MT_button_context_menu.append(ui.draw_custom_context_menu)
|
||||
|
||||
for mod in modules.values():
|
||||
mod.register()
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -26,7 +26,6 @@ from blenderbim.bim.module.drawing.prop import RasterStyleProperty
|
||||
from bpy.app.handlers import persistent
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.owner.prop import get_user_person, get_user_organisation
|
||||
from blenderbim.bim.module.model.data import AuthoringData
|
||||
from ifcopenshell.api.material.data import Data as MaterialData
|
||||
from ifcopenshell.api.type.data import Data as TypeData
|
||||
|
||||
@@ -302,4 +301,3 @@ def setDefaultProperties(scene):
|
||||
drawing_style.name = "Blender Default"
|
||||
drawing_style.render_type = "DEFAULT"
|
||||
bpy.ops.bim.save_drawing_style(index="2")
|
||||
AuthoringData.type_thumbnails = {}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.module.type.prop as type_prop
|
||||
from bpy.types import WorkSpaceTool
|
||||
from blenderbim.bim.module.model.data import AuthoringData
|
||||
@@ -52,14 +51,9 @@ class CadTool(WorkSpaceTool):
|
||||
row = layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_Q")
|
||||
if obj.BIMObjectProperties.ifc_definition_id:
|
||||
row.operator("bim.edit_extrusion_profile", text="Save Profile")
|
||||
row.operator("bim.align_view_to_profile", text="", icon="AXIS_FRONT")
|
||||
row.operator("bim.disable_editing_extrusion_profile", text="", icon="CANCEL")
|
||||
else:
|
||||
row.operator("bim.edit_arbitrary_profile", text="Save Profile")
|
||||
row.operator("bim.align_view_to_profile", text="", icon="AXIS_FRONT")
|
||||
row.operator("bim.disable_editing_arbitrary_profile", text="", icon="CANCEL")
|
||||
row.operator("bim.edit_extrusion_profile", text="Save Profile")
|
||||
row.operator("bim.align_view_to_profile", text="", icon="AXIS_FRONT")
|
||||
row.operator("bim.disable_editing_extrusion_profile", text="", icon="CANCEL")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
@@ -186,10 +180,7 @@ class CadHotkey(bpy.types.Operator):
|
||||
bpy.ops.bim.cad_offset(distance=self.props.distance)
|
||||
|
||||
def hotkey_S_Q(self):
|
||||
if tool.Ifc.get_entity(bpy.context.active_object):
|
||||
bpy.ops.bim.edit_extrusion_profile()
|
||||
else:
|
||||
bpy.ops.bim.edit_arbitrary_profile()
|
||||
bpy.ops.bim.edit_extrusion_profile()
|
||||
|
||||
def hotkey_S_R(self):
|
||||
if self.is_profile():
|
||||
|
||||
@@ -503,7 +503,6 @@ class DisableEditingAssignedMaterial(bpy.types.Operator):
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.bim.disable_editing_material_set_item()
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
props = obj.BIMObjectMaterialProperties
|
||||
props.is_editing = False
|
||||
@@ -527,9 +526,6 @@ class EditAssignedMaterial(bpy.types.Operator):
|
||||
props = obj.BIMObjectMaterialProperties
|
||||
product_data = Data.products[obj.BIMObjectProperties.ifc_definition_id]
|
||||
|
||||
if props.active_material_set_item_id != 0: # We were editing a material layer set item
|
||||
bpy.ops.bim.edit_material_set_item(material_set_item=props.active_material_set_item_id)
|
||||
|
||||
if product_data["type"] == "IfcMaterial":
|
||||
bpy.ops.bim.unassign_material(obj=obj.name)
|
||||
bpy.ops.bim.assign_material(obj=obj.name, material_type="IfcMaterial")
|
||||
|
||||
@@ -189,17 +189,14 @@ class AuthoringData:
|
||||
if not ifc_class and ifc_classes:
|
||||
ifc_class = ifc_classes[0][0]
|
||||
if ifc_class:
|
||||
elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda s: s.Name or "Unnamed")
|
||||
elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda s: s.Name)
|
||||
results.extend(elements)
|
||||
return results
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def relating_types(cls, ifc_class=None):
|
||||
return [
|
||||
(str(e.id()), e.Name or "Unnamed", e.Description or "")
|
||||
for e in cls.constr_class_entities(ifc_class=ifc_class)
|
||||
]
|
||||
return [(str(e.id()), e.Name, e.Description or "") for e in cls.constr_class_entities(ifc_class=ifc_class)]
|
||||
|
||||
@classmethod
|
||||
def relating_types_browser(cls):
|
||||
@@ -335,7 +332,7 @@ class ArrayData:
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.is_loaded = True
|
||||
cls.data = {"parameters": cls.parameters()}
|
||||
cls.data = { "parameters": cls.parameters() }
|
||||
|
||||
@classmethod
|
||||
def parameters(cls):
|
||||
|
||||
@@ -201,9 +201,7 @@ class ChangeTypePage(bpy.types.Operator, tool.Ifc.Operator):
|
||||
page: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMModelProperties
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=props.type_class, offset=9 * (self.page - 1), limit=9)
|
||||
props.type_page = self.page
|
||||
context.scene.BIMModelProperties.type_page = self.page
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -318,24 +316,14 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_label = "Load Type Thumbnails"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
ifc_class: bpy.props.StringProperty()
|
||||
limit: bpy.props.IntProperty()
|
||||
offset: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
props = bpy.context.scene.BIMModelProperties
|
||||
processing = set()
|
||||
# Only process at most one paginated class at a time.
|
||||
# Only process at most one class at a time.
|
||||
# Large projects have hundreds of types which can lead to unnecessary lag.
|
||||
queue = sorted(tool.Ifc.get().by_type(self.ifc_class), key=lambda e: e.Name or "Unnamed")
|
||||
if self.limit:
|
||||
queue = queue[self.offset:self.offset + self.limit]
|
||||
else:
|
||||
offset = 9 * (props.type_page - 1)
|
||||
if offset < 0:
|
||||
offset = 0
|
||||
queue = queue[offset:offset + 9]
|
||||
queue = tool.Ifc.get().by_type(self.ifc_class)
|
||||
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
|
||||
|
||||
@@ -173,9 +173,10 @@ class DumbSlabGenerator:
|
||||
matrix_world[2][3] = self.collection_obj.location[2] - self.depth
|
||||
else:
|
||||
matrix_world[2][3] -= self.depth
|
||||
obj.matrix_world = Matrix.Rotation(self.x_angle, 4, 'X') @ matrix_world
|
||||
obj.matrix_world = matrix_world
|
||||
bpy.context.view_layer.update()
|
||||
self.collection.objects.link(obj)
|
||||
obj.matrix_world = Matrix.Rotation(self.x_angle, 4, 'X')
|
||||
|
||||
element = blenderbim.core.root.assign_class(
|
||||
tool.Ifc,
|
||||
@@ -617,13 +618,122 @@ class EnableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
position = Matrix()
|
||||
|
||||
tool.Model.import_profile(extrusion.SweptArea, obj=obj, position=position)
|
||||
self.vertices = []
|
||||
self.edges = []
|
||||
self.arcs = []
|
||||
self.circles = []
|
||||
|
||||
profile = extrusion.SweptArea
|
||||
if profile.is_a("IfcArbitraryClosedProfileDef"):
|
||||
self.process_curve(obj, position, profile.OuterCurve)
|
||||
if profile.is_a("IfcArbitraryProfileDefWithVoids"):
|
||||
for inner_curve in profile.InnerCurves:
|
||||
self.process_curve(obj, position, inner_curve)
|
||||
elif profile.is_a() == "IfcRectangleProfileDef":
|
||||
self.process_rectangle(obj, position, profile)
|
||||
|
||||
mesh = bpy.data.meshes.new("Profile")
|
||||
mesh.from_pydata(self.vertices, self.edges, [])
|
||||
mesh.BIMMeshProperties.is_profile = True
|
||||
obj.data = mesh
|
||||
|
||||
for arc in self.arcs:
|
||||
group = obj.vertex_groups.new(name="IFCARCINDEX")
|
||||
group.add(arc, 1, "REPLACE")
|
||||
|
||||
for circle in self.circles:
|
||||
group = obj.vertex_groups.new(name="IFCCIRCLE")
|
||||
group.add(circle, 1, "REPLACE")
|
||||
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
DecorationsHandler.install(context)
|
||||
bpy.ops.wm.tool_set_by_id(name="bim.cad_tool")
|
||||
return {"FINISHED"}
|
||||
|
||||
def process_curve(self, obj, position, curve):
|
||||
offset = len(self.vertices)
|
||||
|
||||
if curve.is_a("IfcPolyline"):
|
||||
total_points = len(curve.Points)
|
||||
last_index = len(curve.Points) - 1
|
||||
for i, point in enumerate(curve.Points):
|
||||
if i == last_index:
|
||||
continue
|
||||
global_point = position @ Vector(self.convert_unit_to_si(point.Coordinates)).to_3d()
|
||||
self.vertices.append(global_point)
|
||||
self.edges.extend([(i, i + 1) for i in range(offset, len(self.vertices))])
|
||||
self.edges[-1] = (len(self.vertices) - 1, offset) # Close the loop
|
||||
elif curve.is_a("IfcIndexedPolyCurve"):
|
||||
is_arc = False
|
||||
if curve.Segments:
|
||||
for segment in curve.Segments:
|
||||
if len(segment[0]) == 3: # IfcArcIndex
|
||||
is_arc = True
|
||||
local_point = self.convert_unit_to_si(curve.Points.CoordList[segment[0][0] - 1])
|
||||
global_point = position @ Vector(local_point).to_3d()
|
||||
self.vertices.append(global_point)
|
||||
local_point = self.convert_unit_to_si(curve.Points.CoordList[segment[0][1] - 1])
|
||||
global_point = position @ Vector(local_point).to_3d()
|
||||
self.vertices.append(global_point)
|
||||
self.arcs.append([len(self.vertices) - 2, len(self.vertices) - 1])
|
||||
else:
|
||||
local_point = self.convert_unit_to_si(curve.Points.CoordList[segment[0][0] - 1])
|
||||
global_point = position @ Vector(local_point).to_3d()
|
||||
self.vertices.append(global_point)
|
||||
if is_arc:
|
||||
self.arcs[-1].append(len(self.vertices) - 1)
|
||||
is_arc = False
|
||||
else:
|
||||
for local_point in curve.Points.CoordList:
|
||||
global_point = position @ Vector(self.convert_unit_to_si(local_point)).to_3d()
|
||||
self.vertices.append(global_point)
|
||||
# Curves without segments are self closing
|
||||
del self.vertices[-1]
|
||||
|
||||
self.edges.extend([(i, i + 1) for i in range(offset, len(self.vertices))])
|
||||
self.edges[-1] = (len(self.vertices) - 1, offset) # Close the loop
|
||||
elif curve.is_a("IfcCircle"):
|
||||
center = self.convert_unit_to_si(
|
||||
Matrix(ifcopenshell.util.placement.get_axis2placement(curve.Position).tolist()).col[3].to_3d()
|
||||
)
|
||||
radius = self.convert_unit_to_si(curve.Radius)
|
||||
self.vertices.extend(
|
||||
[
|
||||
position @ Vector((center[0], center[1] - curve.Radius, 0.0)),
|
||||
position @ Vector((center[0], center[1] + curve.Radius, 0.0)),
|
||||
]
|
||||
)
|
||||
self.circles.append([offset, offset + 1])
|
||||
self.edges.append((offset, offset + 1))
|
||||
|
||||
def process_rectangle(self, obj, position, profile):
|
||||
if profile.Position:
|
||||
p_position = Matrix(ifcopenshell.util.placement.get_axis2placement(profile.Position).tolist())
|
||||
p_position[0][3] *= self.unit_scale
|
||||
p_position[1][3] *= self.unit_scale
|
||||
p_position[2][3] *= self.unit_scale
|
||||
else:
|
||||
p_position = Matrix()
|
||||
|
||||
x = self.convert_unit_to_si(profile.XDim)
|
||||
y = self.convert_unit_to_si(profile.YDim)
|
||||
|
||||
self.vertices.extend(
|
||||
[
|
||||
position @ p_position @ Vector((-x / 2, -y / 2, 0.0)),
|
||||
position @ p_position @ Vector((x / 2, -y / 2, 0.0)),
|
||||
position @ p_position @ Vector((x / 2, y / 2, 0.0)),
|
||||
position @ p_position @ Vector((-x / 2, y / 2, 0.0)),
|
||||
]
|
||||
)
|
||||
self.edges.extend([(i, i + 1) for i in range(0, len(self.vertices))])
|
||||
self.edges[-1] = (len(self.vertices) - 1, 0) # Close the loop
|
||||
|
||||
def convert_unit_to_si(self, value):
|
||||
if isinstance(value, (tuple, list)):
|
||||
return [v * self.unit_scale for v in value]
|
||||
return value * self.unit_scale
|
||||
|
||||
|
||||
class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_extrusion_profile"
|
||||
@@ -648,16 +758,40 @@ class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
position = Matrix()
|
||||
|
||||
profile = tool.Model.export_profile(obj, position=position)
|
||||
helper = Helper(tool.Ifc.get())
|
||||
indices = helper.auto_detect_arbitrary_profile_with_voids(obj, obj.data)
|
||||
|
||||
if isinstance(indices, tuple) and indices[0] is False: # Ugly
|
||||
|
||||
if not profile:
|
||||
def msg(self, context):
|
||||
self.layout.label(text="INVALID PROFILE: " + indices[1])
|
||||
|
||||
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
|
||||
DecorationsHandler.install(context)
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
return
|
||||
return {"FINISHED"}
|
||||
|
||||
self.bm = bmesh.new()
|
||||
self.bm.from_mesh(obj.data)
|
||||
self.bm.verts.ensure_lookup_table()
|
||||
self.bm.edges.ensure_lookup_table()
|
||||
|
||||
if indices["inner_curves"]:
|
||||
profile = tool.Ifc.get().createIfcArbitraryProfileDefWithVoids("AREA")
|
||||
else:
|
||||
profile = tool.Ifc.get().createIfcArbitraryClosedProfileDef("AREA")
|
||||
|
||||
if tool.Ifc.get().schema != "IFC2X3":
|
||||
self.points = self.create_points(position, indices["points"])
|
||||
|
||||
profile.OuterCurve = self.create_curve(position, indices["profile"])
|
||||
if indices["inner_curves"]:
|
||||
results = []
|
||||
for inner_curve in indices["inner_curves"]:
|
||||
results.append(self.create_curve(position, inner_curve))
|
||||
profile.InnerCurves = results
|
||||
|
||||
self.bm.free()
|
||||
|
||||
old_profile = extrusion.SweptArea
|
||||
extrusion.SweptArea = profile
|
||||
@@ -697,6 +831,45 @@ class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
def create_points(self, position, indices):
|
||||
position_i = position.inverted()
|
||||
points = []
|
||||
for point in indices:
|
||||
local_point = (position_i @ point).to_2d()
|
||||
points.append(self.convert_si_to_unit(list(local_point)))
|
||||
return tool.Ifc.get().createIfcCartesianPointList2D(points)
|
||||
|
||||
def create_curve(self, position, edge_indices, points=None):
|
||||
position_i = position.inverted()
|
||||
if len(edge_indices) == 2:
|
||||
diameter = edge_indices[0]
|
||||
p1 = self.bm.verts[diameter[0]].co
|
||||
p2 = self.bm.verts[diameter[1]].co
|
||||
center = self.convert_si_to_unit(list(position_i @ p1.lerp(p2, 0.5)))
|
||||
radius = self.convert_si_to_unit((p1 - p2).length / 2)
|
||||
return tool.Ifc.get().createIfcCircle(
|
||||
tool.Ifc.get().createIfcAxis2Placement2D(tool.Ifc.get().createIfcCartesianPoint(center[0:2])), radius
|
||||
)
|
||||
if tool.Ifc.get().schema == "IFC2X3":
|
||||
points = []
|
||||
for edge in edge_indices:
|
||||
local_point = (position_i @ Vector(self.bm.verts[edge[0]].co)).to_2d()
|
||||
points.append(tool.Ifc.get().createIfcCartesianPoint(self.convert_si_to_unit(local_point)))
|
||||
points.append(points[0])
|
||||
return tool.Ifc.get().createIfcPolyline(points)
|
||||
segments = []
|
||||
for segment in edge_indices:
|
||||
if len(segment) == 2:
|
||||
segments.append(tool.Ifc.get().createIfcLineIndex([i + 1 for i in segment]))
|
||||
elif len(segment) == 3:
|
||||
segments.append(tool.Ifc.get().createIfcArcIndex([i + 1 for i in segment]))
|
||||
return tool.Ifc.get().createIfcIndexedPolyCurve(self.points, segments, False)
|
||||
|
||||
def convert_si_to_unit(self, value):
|
||||
if isinstance(value, (tuple, list)):
|
||||
return [v / self.unit_scale for v in value]
|
||||
return value / self.unit_scale
|
||||
|
||||
|
||||
class ResetVertex(bpy.types.Operator):
|
||||
bl_idname = "bim.reset_vertex"
|
||||
|
||||
@@ -38,7 +38,7 @@ class LaunchTypeManager(bpy.types.Operator):
|
||||
props.type_page = 1
|
||||
if props.ifc_class:
|
||||
props.type_class = props.ifc_class
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class, offset=0, limit=9)
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class)
|
||||
if not AuthoringData.is_loaded:
|
||||
AuthoringData.load()
|
||||
return context.window_manager.invoke_popup(self, width=550)
|
||||
|
||||
@@ -413,9 +413,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bpy.ops.bim.align_product(align_type="CENTERLINE")
|
||||
|
||||
def hotkey_S_E(self):
|
||||
if not bpy.context.selected_objects:
|
||||
return
|
||||
elif self.active_class in ("IfcWall", "IfcWallStandardCase"):
|
||||
if self.active_class in ("IfcWall", "IfcWallStandardCase"):
|
||||
bpy.ops.bim.join_wall(join_type="T")
|
||||
elif self.active_class in ("IfcSlab", "IfcSlabStandardCase", "IfcRamp", "IfcRoof"):
|
||||
if not bpy.context.active_object:
|
||||
|
||||
@@ -20,16 +20,12 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddProfileDef,
|
||||
operator.DisableEditingArbitraryProfile,
|
||||
operator.DisableEditingProfile,
|
||||
operator.DisableProfileEditingUI,
|
||||
operator.EditArbitraryProfile,
|
||||
operator.EditProfile,
|
||||
operator.EnableEditingArbitraryProfile,
|
||||
operator.EnableEditingProfile,
|
||||
operator.LoadProfiles,
|
||||
operator.DisableProfileEditingUI,
|
||||
operator.RemoveProfileDef,
|
||||
operator.EnableEditingProfile,
|
||||
operator.DisableEditingProfile,
|
||||
operator.EditProfile,
|
||||
prop.Profile,
|
||||
prop.BIMProfileProperties,
|
||||
ui.BIM_PT_profiles,
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.util.doc
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
def refresh():
|
||||
ProfileData.is_loaded = False
|
||||
|
||||
|
||||
class ProfileData:
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {
|
||||
"total_profiles": cls.total_profiles(),
|
||||
"profile_classes": cls.profile_classes(),
|
||||
"is_arbitrary_profile": cls.is_arbitrary_profile(),
|
||||
"is_editing_arbitrary_profile": cls.is_editing_arbitrary_profile(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def total_profiles(cls):
|
||||
return len(tool.Ifc.get().by_type("IfcProfileDef"))
|
||||
|
||||
@classmethod
|
||||
def profile_classes(cls):
|
||||
classes = ["IfcArbitraryClosedProfileDef"]
|
||||
queue = ["IfcParameterizedProfileDef"]
|
||||
while queue:
|
||||
item = queue.pop()
|
||||
subtypes = [s.name() for s in tool.Ifc.schema().declaration_by_name(item).subtypes()]
|
||||
classes.extend(subtypes)
|
||||
queue.extend(subtypes)
|
||||
schema_identifier = tool.Ifc.get_schema()
|
||||
return [
|
||||
(c, c, ifcopenshell.util.doc.get_entity_doc(schema_identifier, c)["description"] or "")
|
||||
for c in sorted(classes)
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def is_arbitrary_profile(cls):
|
||||
props = bpy.context.scene.BIMProfileProperties
|
||||
if props.active_profile_id:
|
||||
profile = tool.Ifc.get().by_id(props.active_profile_id)
|
||||
if profile.is_a("IfcArbitraryClosedProfileDef"):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def is_editing_arbitrary_profile(cls):
|
||||
obj = bpy.context.active_object
|
||||
return obj and obj.data and hasattr(obj.data, "BIMMeshProperties") and obj.data.BIMMeshProperties.is_profile
|
||||
@@ -1,5 +1,5 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021, 2022 Dion Moult <dion@thinkmoult.com>
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
@@ -19,8 +19,8 @@
|
||||
import bpy
|
||||
import ifcopenshell.api
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.module.model.slab import DecorationsHandler
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.profile.data import Data
|
||||
|
||||
|
||||
class LoadProfiles(bpy.types.Operator):
|
||||
@@ -32,11 +32,10 @@ class LoadProfiles(bpy.types.Operator):
|
||||
props = context.scene.BIMProfileProperties
|
||||
props.profiles.clear()
|
||||
|
||||
for profile in tool.Ifc.get().by_type("IfcProfileDef"):
|
||||
for ifc_definition_id, profile in Data.profiles.items():
|
||||
new = props.profiles.add()
|
||||
new.ifc_definition_id = profile.id()
|
||||
new.name = profile.ProfileName or "Unnamed"
|
||||
new.ifc_class = profile.is_a()
|
||||
new.ifc_definition_id = ifc_definition_id
|
||||
new.name = profile.get("ProfileName", "") or "Unnamed"
|
||||
|
||||
props.is_editing = True
|
||||
bpy.ops.bim.disable_editing_profile()
|
||||
@@ -53,28 +52,39 @@ class DisableProfileEditingUI(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveProfileDef(bpy.types.Operator, tool.Ifc.Operator):
|
||||
class RemoveProfileDef(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_profile_def"
|
||||
bl_label = "Remove Profile Definition"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
profile: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
ifcopenshell.api.run("profile.remove_profile", tool.Ifc.get(), profile=tool.Ifc.get().by_id(self.profile))
|
||||
props = context.scene.BIMProfileProperties
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run("profile.remove_profile", self.file, **{"profile": self.file.by_id(self.profile)})
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_profiles()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
class EnableEditingProfile(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_profile"
|
||||
bl_label = "Enable Editing Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
profile: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMProfileProperties
|
||||
props.profile_attributes.clear()
|
||||
blenderbim.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.profile), props.profile_attributes)
|
||||
|
||||
data = Data.profiles[self.profile]
|
||||
|
||||
blenderbim.bim.helper.import_attributes(data["type"], props.profile_attributes, data)
|
||||
props.active_profile_id = self.profile
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingProfile(bpy.types.Operator):
|
||||
@@ -87,91 +97,20 @@ class DisableEditingProfile(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
class EditProfile(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_profile"
|
||||
bl_label = "Edit Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMProfileProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.profile_attributes)
|
||||
profile = tool.Ifc.get().by_id(props.active_profile_id)
|
||||
ifcopenshell.api.run("profile.edit_profile", tool.Ifc.get(), profile=profile, attributes=attributes)
|
||||
self.file = IfcStore.get_file()
|
||||
profile = self.file.by_id(props.active_profile_id)
|
||||
ifcopenshell.api.run("profile.edit_profile", self.file, **{"profile": profile, "attributes": attributes})
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_profiles()
|
||||
|
||||
|
||||
class AddProfileDef(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_profile_def"
|
||||
bl_label = "Add Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMProfileProperties
|
||||
profile_class = props.profile_classes
|
||||
if profile_class == "IfcArbitraryClosedProfileDef":
|
||||
points = [(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]
|
||||
profile = ifcopenshell.api.run("profile.add_arbitrary_profile", tool.Ifc.get(), profile=points)
|
||||
else:
|
||||
profile = ifcopenshell.api.run("profile.add_parameterized_profile", tool.Ifc.get(), ifc_class=profile_class)
|
||||
profile.ProfileName = "New Profile"
|
||||
bpy.ops.bim.load_profiles()
|
||||
|
||||
|
||||
class EnableEditingArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.enable_editing_arbitrary_profile"
|
||||
bl_label = "Enable Editing Arbitrary Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMProfileProperties
|
||||
profile = tool.Ifc.get().by_id(props.active_profile_id)
|
||||
obj = tool.Model.import_profile(profile)
|
||||
bpy.context.scene.collection.objects.link(obj)
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
DecorationsHandler.install(context)
|
||||
bpy.ops.wm.tool_set_by_id(name="bim.cad_tool")
|
||||
|
||||
|
||||
class DisableEditingArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.disable_editing_arbitrary_profile"
|
||||
bl_label = "Disable Editing Arbitrary Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
DecorationsHandler.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
bpy.data.objects.remove(obj)
|
||||
|
||||
|
||||
class EditArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_arbitrary_profile"
|
||||
bl_label = "Edit Arbitrary Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMProfileProperties
|
||||
old_profile = tool.Ifc.get().by_id(props.active_profile_id)
|
||||
|
||||
obj = context.active_object
|
||||
|
||||
DecorationsHandler.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
|
||||
profile = tool.Model.export_profile(obj)
|
||||
if not profile:
|
||||
def msg(self, context):
|
||||
self.layout.label(text="INVALID PROFILE: " + indices[1])
|
||||
|
||||
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
|
||||
DecorationsHandler.install(context)
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
return
|
||||
|
||||
bpy.data.objects.remove(obj)
|
||||
profile.ProfileType = old_profile.ProfileType
|
||||
profile.ProfileName = old_profile.ProfileName
|
||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_profile)
|
||||
bpy.ops.bim.load_profiles()
|
||||
props.active_profile_id = profile.id()
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -22,7 +22,6 @@ import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.attribute
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.profile.data import ProfileData
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -36,15 +35,8 @@ from bpy.props import (
|
||||
)
|
||||
|
||||
|
||||
def get_profile_classes(self, context):
|
||||
if not ProfileData.is_loaded:
|
||||
ProfileData.load()
|
||||
return ProfileData.data["profile_classes"]
|
||||
|
||||
|
||||
class Profile(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_class: StringProperty(name="IFC Class")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
|
||||
@@ -54,4 +46,3 @@ class BIMProfileProperties(PropertyGroup):
|
||||
active_profile_index: IntProperty(name="Active Profile Index")
|
||||
active_profile_id: IntProperty(name="Active Profile Id")
|
||||
profile_attributes: CollectionProperty(name="Profile Attributes", type=Attribute)
|
||||
profile_classes: EnumProperty(items=get_profile_classes, name="Profile Classes")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021, 2022 Dion Moult <dion@thinkmoult.com>
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
@@ -17,9 +17,9 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.module.profile.data import ProfileData
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.profile.data import Data
|
||||
|
||||
|
||||
class BIM_PT_profiles(Panel):
|
||||
@@ -33,15 +33,17 @@ class BIM_PT_profiles(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Ifc.get()
|
||||
file = IfcStore.get_file()
|
||||
return file
|
||||
|
||||
def draw(self, context):
|
||||
if not ProfileData.is_loaded:
|
||||
ProfileData.load()
|
||||
self.file = IfcStore.get_file()
|
||||
if not Data.is_loaded:
|
||||
Data.load(self.file)
|
||||
self.props = context.scene.BIMProfileProperties
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="{} Profiles Found".format(ProfileData.data["total_profiles"]), icon="SNAP_GRID")
|
||||
row.label(text="{} Profiles Found".format(len(Data.profiles)), icon="SNAP_GRID")
|
||||
if self.props.is_editing:
|
||||
row.operator("bim.disable_profile_editing_ui", text="", icon="CANCEL")
|
||||
else:
|
||||
@@ -50,10 +52,6 @@ class BIM_PT_profiles(Panel):
|
||||
if not self.props.is_editing:
|
||||
return
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.props, "profile_classes", text="")
|
||||
row.operator("bim.add_profile_def", text="", icon="ADD")
|
||||
|
||||
self.layout.template_list(
|
||||
"BIM_UL_profiles",
|
||||
"",
|
||||
@@ -67,14 +65,6 @@ class BIM_PT_profiles(Panel):
|
||||
self.draw_editable_ui(context)
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
if ProfileData.data["is_arbitrary_profile"]:
|
||||
if ProfileData.data["is_editing_arbitrary_profile"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.edit_arbitrary_profile", text="Save Profile", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_arbitrary_profile", text="", icon="CANCEL")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.operator("bim.enable_editing_arbitrary_profile", text="Edit Profile", icon="GREASEPENCIL")
|
||||
blenderbim.bim.helper.draw_attributes(self.props.profile_attributes, self.layout)
|
||||
|
||||
|
||||
@@ -84,7 +74,6 @@ class BIM_UL_profiles(UIList):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.label(text=item.name or "Unnamed")
|
||||
row.label(text=item.ifc_class)
|
||||
|
||||
if props.active_profile_id == item.ifc_definition_id:
|
||||
row.operator("bim.edit_profile", text="", icon="CHECKMARK")
|
||||
|
||||
@@ -1,578 +1,10 @@
|
||||
mapper = {
|
||||
'Qto_AudioVisualApplianceBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
"Qto_WallBaseQuantities" : {
|
||||
"Length" : "get_length",
|
||||
"Width" : "get_width",
|
||||
"Height" : "get_height",
|
||||
},
|
||||
'Qto_PlateBaseQuantities' : {
|
||||
'Width' : None,
|
||||
'Perimeter' : None,
|
||||
'GrossArea' : None,
|
||||
'NetArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_OpeningElementBaseQuantities' : {
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
'Depth' : None,
|
||||
'Area' : None,
|
||||
'Volume' : None,
|
||||
},
|
||||
'Qto_MarineFacilityBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
'Area' : None,
|
||||
'Volume' : None,
|
||||
},
|
||||
'Qto_ChillerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_PileBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'CrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossSurfaceArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_VibrationIsolatorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_LampBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_VehicleBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
},
|
||||
'Qto_PipeFittingBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'GrossCrossSectionArea' : None,
|
||||
'NetCrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_CableCarrierFittingBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_HeatExchangerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_DoorBaseQuantities' : {
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
'Perimeter' : None,
|
||||
'Area' : None,
|
||||
},
|
||||
'Qto_DuctSegmentBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'GrossCrossSectionArea' : None,
|
||||
'NetCrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_TransformerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_FacilityPartBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
'Area' : None,
|
||||
'Volume' : None,
|
||||
},
|
||||
'Qto_ProjectionElementBaseQuantities' : {
|
||||
'Area' : None,
|
||||
'Volume' : None,
|
||||
},
|
||||
'Qto_SignBaseQuantities' : {
|
||||
'Height' : None,
|
||||
'Width' : None,
|
||||
'Thickness' : None,
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_CableSegmentBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'Length' : None,
|
||||
'CrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
},
|
||||
'Qto_BuildingBaseQuantities' : {
|
||||
'Height' : None,
|
||||
'EavesHeight' : None,
|
||||
'FootPrintArea' : None,
|
||||
'GrossFloorArea' : None,
|
||||
'NetFloorArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
},
|
||||
'Qto_ElectricFlowStorageDeviceBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_CommunicationsApplianceBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_RailBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Volume' : None,
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_PictorialSignQuantities' : {
|
||||
'Area' : None,
|
||||
'SignArea' : None,
|
||||
},
|
||||
'Qto_SpaceHeaterBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_CoveringBaseQuantities' : {
|
||||
'Width' : None,
|
||||
'GrossArea' : None,
|
||||
'NetArea' : None,
|
||||
},
|
||||
'Qto_PipeSegmentBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'GrossCrossSectionArea' : None,
|
||||
'NetCrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
'FootPrintArea' : None,
|
||||
},
|
||||
'Qto_HumidifierBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_ConstructionEquipmentResourceBaseQuantities' : {
|
||||
'UsageTime' : None,
|
||||
'OperatingTime' : None,
|
||||
},
|
||||
'Qto_AlarmBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_JunctionBoxBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'NumberOfGangs' : None,
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
},
|
||||
'Qto_ArealStratumBaseQuantities' : {
|
||||
'Area' : None,
|
||||
'Length' : None,
|
||||
'PlanLength' : None,
|
||||
},
|
||||
'Qto_SiteBaseQuantities' : {
|
||||
'GrossPerimeter' : None,
|
||||
'GrossArea' : None,
|
||||
},
|
||||
'Qto_MotorConnectionBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_RoofBaseQuantities' : {
|
||||
'GrossArea' : None,
|
||||
'NetArea' : None,
|
||||
'ProjectedArea' : None,
|
||||
},
|
||||
'Qto_ChimneyBaseQuantities' : {
|
||||
'Length' : None,
|
||||
},
|
||||
'Qto_ElectricTimeControlBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_ElectricMotorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_EarthworksFillBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Depth' : None,
|
||||
'CompactedVolume' : None,
|
||||
'LooseVolume' : None,
|
||||
},
|
||||
'Qto_ConduitSegmentBaseQuantities' : {
|
||||
'InnerDiameter' : None,
|
||||
'OuterDiameter' : None,
|
||||
},
|
||||
'Qto_SignalBaseQuantities' : {
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_DuctFittingBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'GrossCrossSectionArea' : None,
|
||||
'NetCrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_UnitaryControlElementBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_ActuatorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_CurtainWallQuantities' : {
|
||||
'Length' : None,
|
||||
'Height' : None,
|
||||
'Width' : None,
|
||||
'GrossSideArea' : None,
|
||||
'NetSideArea' : None,
|
||||
},
|
||||
'Qto_BoilerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
'TotalSurfaceArea' : None,
|
||||
},
|
||||
'Qto_FlowMeterBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_AirTerminalBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'Perimeter' : None,
|
||||
'TotalSurfaceArea' : None,
|
||||
},
|
||||
'Qto_DuctSilencerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_WasteTerminalBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_SlabBaseQuantities' : {
|
||||
'Width' : None,
|
||||
'Length' : None,
|
||||
'Depth' : "get_height",
|
||||
'Perimeter' : None,
|
||||
'GrossArea' : None,
|
||||
'NetArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_ImpactProtectionDeviceBaseQuantities' : {
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_LightFixtureBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_FlowInstrumentBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_BuildingStoreyBaseQuantities' : {
|
||||
'GrossHeight' : None,
|
||||
'NetHeight' : None,
|
||||
'GrossPerimeter' : None,
|
||||
'GrossFloorArea' : None,
|
||||
'NetFloorArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
},
|
||||
'Qto_ReinforcedSoilBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Depth' : None,
|
||||
'Area' : None,
|
||||
'Volume' : None,
|
||||
},
|
||||
'Qto_DistributionBoardBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'NumberOfCircuits' : None,
|
||||
},
|
||||
'Qto_FootingBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
'CrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossSurfaceArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_PumpBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_CableCarrierSegmentBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'Length' : None,
|
||||
'CrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
},
|
||||
'Qto_InterceptorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_ColumnBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'CrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossSurfaceArea' : None,
|
||||
'NetSurfaceArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_EarthworksCutBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Depth' : None,
|
||||
'UndisturbedVolume' : None,
|
||||
'LooseVolume' : None,
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_StackTerminalBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_CoilBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_KerbBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
'Depth' : None,
|
||||
'Volume' : None,
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_PavementBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Depth' : None,
|
||||
'GrossArea' : None,
|
||||
'NetArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
},
|
||||
'Qto_ControllerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_SolarDeviceBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'GrossArea' : None,
|
||||
},
|
||||
'Qto_RampFlightBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'GrossArea' : None,
|
||||
'NetArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
},
|
||||
'Qto_ElectricApplianceBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_ValveBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_DamperBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_SurfaceFeatureBaseQuantities' : {
|
||||
'Area' : None,
|
||||
'Length' : None,
|
||||
},
|
||||
'Qto_WallBaseQuantities' : {
|
||||
'Length' : "get_length",
|
||||
'Width' : "get_width",
|
||||
'Height' : None,
|
||||
'GrossFootPrintArea' : None,
|
||||
'NetFootPrintArea' : None,
|
||||
'GrossSideArea' : None,
|
||||
'NetSideArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_StairFlightBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
},
|
||||
'Qto_SwitchingDeviceBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_BurnerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_ConstructionMaterialResourceBaseQuantities' : {
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_ElectricGeneratorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_LinearStratumBaseQuantities' : {
|
||||
'Diameter' : None,
|
||||
'Length' : None,
|
||||
},
|
||||
'Qto_CableFittingBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_DistributionChamberElementBaseQuantities' : {
|
||||
'GrossSurfaceArea' : None,
|
||||
'NetSurfaceArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'Depth' : None,
|
||||
},
|
||||
'Qto_CompressorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_ProtectiveDeviceTrippingUnitBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_EvaporatorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_SpaceBaseQuantities' : {
|
||||
'Height' : None,
|
||||
'FinishCeilingHeight' : None,
|
||||
'FinishFloorHeight' : None,
|
||||
'GrossPerimeter' : None,
|
||||
'NetPerimeter' : None,
|
||||
'GrossFloorArea' : None,
|
||||
'NetFloorArea' : None,
|
||||
'GrossWallArea' : None,
|
||||
'NetWallArea' : None,
|
||||
'GrossCeilingArea' : None,
|
||||
'NetCeilingArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
},
|
||||
'Qto_CourseBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Thickness' : None,
|
||||
'Volume' : None,
|
||||
'GrossVolume' : None,
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_CondenserBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_FireSuppressionTerminalBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_RailingBaseQuantities' : {
|
||||
'Length' : None,
|
||||
},
|
||||
'Qto_TubeBundleBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_BeamBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'CrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossSurfaceArea' : None,
|
||||
'NetSurfaceArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_SleeperBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
},
|
||||
'Qto_ProtectiveDeviceBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_CooledBeamBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_TankBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
'TotalSurfaceArea' : None,
|
||||
},
|
||||
'Qto_AirToAirHeatRecoveryBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_CoolingTowerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_SensorBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_WindowBaseQuantities' : {
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
'Perimeter' : None,
|
||||
'Area' : None,
|
||||
},
|
||||
'Qto_SanitaryTerminalBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_BuildingElementProxyQuantities' : {
|
||||
'NetSurfaceArea' : None,
|
||||
'NetVolume' : None,
|
||||
},
|
||||
'Qto_FanBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_OutletBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_UnitaryEquipmentBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_FilterBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_MemberBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'CrossSectionArea' : None,
|
||||
'OuterSurfaceArea' : None,
|
||||
'GrossSurfaceArea' : None,
|
||||
'NetSurfaceArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'GrossWeight' : None,
|
||||
'NetWeight' : None,
|
||||
},
|
||||
'Qto_BodyGeometryValidation' : {
|
||||
'GrossSurfaceArea' : None,
|
||||
'NetSurfaceArea' : None,
|
||||
'GrossVolume' : None,
|
||||
'NetVolume' : None,
|
||||
'SurfaceGenusBeforeFeatures' : None,
|
||||
'SurfaceGenusAfterFeatures' : None,
|
||||
},
|
||||
'Qto_VolumetricStratumBaseQuantities' : {
|
||||
'Area' : None,
|
||||
'Mass' : None,
|
||||
'PlanArea' : None,
|
||||
'Volume' : None,
|
||||
},
|
||||
'Qto_SpatialZoneBaseQuantities' : {
|
||||
'Length' : None,
|
||||
'Width' : None,
|
||||
'Height' : None,
|
||||
},
|
||||
'Qto_ReinforcingElementBaseQuantities' : {
|
||||
'Count' : None,
|
||||
'Length' : None,
|
||||
'Weight' : None,
|
||||
},
|
||||
'Qto_EvaporativeCoolerBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_AirTerminalBoxTypeBaseQuantities' : {
|
||||
'GrossWeight' : None,
|
||||
},
|
||||
'Qto_LaborResourceBaseQuantities' : {
|
||||
'StandardWork' : None,
|
||||
'OvertimeWork' : None,
|
||||
"Qto_SlabBaseQuantities" : {
|
||||
"Depth" : "get_height",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -37,10 +37,7 @@ class QtoCalculator:
|
||||
|
||||
for key in self.mapping_dict.keys():
|
||||
for item in self.mapping_dict[key].keys():
|
||||
if self.mapping_dict[key][item]:
|
||||
self.mapping_dict[key][item] = eval("self." + self.mapping_dict[key][item])
|
||||
else:
|
||||
self.mapping_dict[key][item] = None
|
||||
self.mapping_dict[key][item] = eval("self." + self.mapping_dict[key][item])
|
||||
|
||||
def calculate_quantity(self, qto_name, quantity_name, obj):
|
||||
return self.mapping_dict[qto_name][quantity_name](obj)
|
||||
|
||||
@@ -215,7 +215,7 @@ class Attribute(PropertyGroup):
|
||||
has_calculator: BoolProperty(name="Has Calculator", default=False)
|
||||
|
||||
def get_value(self):
|
||||
if self.is_optional and self.is_null:
|
||||
if self.is_null:
|
||||
return None
|
||||
return getattr(self, str(self.get_value_name()), None)
|
||||
|
||||
|
||||
@@ -392,12 +392,6 @@ class BIM_PT_misc_object(Panel):
|
||||
|
||||
def draw_custom_context_menu(self, context):
|
||||
# https://blender.stackexchange.com/a/275555/86891
|
||||
if (
|
||||
not hasattr(context, "button_pointer")
|
||||
or not hasattr(context, "button_prop")
|
||||
or not hasattr(context.button_prop, "identifier")
|
||||
):
|
||||
return
|
||||
prop = context.button_pointer
|
||||
prop_name = context.button_prop.identifier
|
||||
prop_value = getattr(prop, prop_name, None)
|
||||
|
||||
@@ -92,19 +92,14 @@ class Model(blenderbim.core.tool.Model):
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
offset = 0.0
|
||||
thickness = 0.0
|
||||
direction_sense = "POSITIVE"
|
||||
material = ifcopenshell.util.element.get_material(element)
|
||||
if material:
|
||||
if material.is_a("IfcMaterialLayerSetUsage"):
|
||||
offset = material.OffsetFromReferenceLine * unit_scale
|
||||
direction_sense = material.DirectionSense
|
||||
material = material.ForLayerSet
|
||||
if material.is_a("IfcMaterialLayerSet"):
|
||||
thickness = sum([l.LayerThickness for l in material.MaterialLayers]) * unit_scale
|
||||
if direction_sense == "NEGATIVE":
|
||||
thickness *= -1
|
||||
offset *= -1
|
||||
return {"thickness": thickness, "offset": offset, "direction_sense": direction_sense}
|
||||
return {"thickness": thickness, "offset": offset}
|
||||
|
||||
@classmethod
|
||||
def get_manual_booleans(cls, element):
|
||||
|
||||
@@ -42,7 +42,7 @@ class Project(blenderbim.core.tool.Project):
|
||||
def load_default_thumbnails(cls):
|
||||
if tool.Ifc.get().by_type("IfcElementType"):
|
||||
ifc_class = sorted(tool.Ifc.get().by_type("IfcElementType"), key=lambda e: e.is_a())[0].is_a()
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=ifc_class, offset=0, limit=9)
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=ifc_class)
|
||||
|
||||
@classmethod
|
||||
def run_aggregate_assign_object(cls, relating_obj=None, related_obj=None):
|
||||
|
||||
@@ -42,8 +42,8 @@ IfcOpenShell (using an IfcOpenBot build) for convenience. Instructions on how to
|
||||
compile IfcOpenShell is out of scope of this document.
|
||||
|
||||
You can create your own package by using the Makefile as shown below. You can
|
||||
choose between a ``PLATFORM`` of ``linux``, ``macos``, ``macosm1``, and ``win``.
|
||||
You can choose between a ``PYVERSION`` of ``py39``, ``py37``, or ``py310``.
|
||||
choose between a ``PLATFORM`` of ``linux``, ``macos``, and ``win``. You can
|
||||
choose between a ``PYVERSION`` of ``py39``, ``py37``, or ``py310``.
|
||||
::
|
||||
|
||||
$ cd src/blenderbim
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2022 @Andrej730
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# fmt: off
|
||||
# pylint: skip-file
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import boltspy as bolts
|
||||
|
||||
|
||||
class LibraryGenerator:
|
||||
def generate(self, parse_profiles_type="EU", output_filename="IFC4 EU Steel.ifc"):
|
||||
ifcopenshell.api.pre_listeners = {}
|
||||
ifcopenshell.api.post_listeners = {}
|
||||
|
||||
self.materials = {}
|
||||
|
||||
self.file = ifcopenshell.api.run("project.create_file")
|
||||
self.project = ifcopenshell.api.run(
|
||||
"root.create_entity", self.file, ifc_class="IfcProject", name=f"{parse_profiles_type} Steel Profiles Library"
|
||||
)
|
||||
self.library = ifcopenshell.api.run(
|
||||
"root.create_entity", self.file, ifc_class="IfcProjectLibrary", name=f"{parse_profiles_type} Steel Profiles Library"
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"project.assign_declaration", self.file, definition=self.library, relating_context=self.project
|
||||
)
|
||||
unit = ifcopenshell.api.run("unit.add_si_unit", self.file, unit_type="LENGTHUNIT", name="METRE", prefix="MILLI")
|
||||
ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit])
|
||||
|
||||
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
|
||||
plan = ifcopenshell.api.run("context.add_context", self.file, context_type="Plan")
|
||||
self.representations = {
|
||||
"body": ifcopenshell.api.run(
|
||||
"context.add_context",
|
||||
self.file,
|
||||
context_type="Model",
|
||||
context_identifier="Body",
|
||||
target_view="MODEL_VIEW",
|
||||
parent=model,
|
||||
),
|
||||
"annotation": ifcopenshell.api.run(
|
||||
"context.add_context",
|
||||
self.file,
|
||||
context_type="Plan",
|
||||
context_identifier="Annotation",
|
||||
target_view="PLAN_VIEW",
|
||||
parent=plan,
|
||||
),
|
||||
}
|
||||
|
||||
self.material = ifcopenshell.api.run("material.add_material", self.file, name="Unknown")
|
||||
|
||||
profiles_translation = {
|
||||
"profile_i": ("IfcIShapeProfileDef", {"tw": "WebThickness", "tf": "FlangeThickness", "h": "OverallDepth", "b": "OverallWidth"}),
|
||||
"profile_z": ("IfcZShapeProfileDef", {"tw": "WebThickness", "tf": "FlangeThickness", "h": "Depth", "c1": "FlangeWidth"}),
|
||||
"profile_c": ("IfcUShapeProfileDef", {"tw": "WebThickness", "tf": "FlangeThickness", "h": "Depth", "b": "FlangeWidth"}),
|
||||
"profile_l*_equal": ("IfcLShapeProfileDef", {"a": "Depth", "t": "Thickness"}),
|
||||
"profile_l*_unequal": ("IfcLShapeProfileDef", {"a": "Depth", "b": "Width", "t": "Thickness"}),
|
||||
"profile_hollow*_circle": ("IfcCircleHollowProfileDef", {"t": "WallThickness", "D": "Radius"}),
|
||||
"profile_hollow*_square": ("IfcRectangleHollowProfileDef", {"t": "WallThickness", "b": "XDim"}),
|
||||
"profile_hollow*_rectangular": ("IfcRectangleHollowProfileDef", {"t": "WallThickness", "b": "XDim", "h": "YDim"}),
|
||||
}
|
||||
|
||||
if parse_profiles_type == "AU":
|
||||
bolt_class_filter = lambda x: "bluescope" in x.id
|
||||
elif parse_profiles_type == "EU":
|
||||
bolt_class_filter = lambda x: "bluescope" not in x.id
|
||||
else:
|
||||
bolt_class_filter = lambda x: True
|
||||
|
||||
for prof_type in profiles_translation:
|
||||
ifc_profile_name, ifc_params_translation = profiles_translation[prof_type]
|
||||
col_name, _, prof_keyword = prof_type.partition("*")
|
||||
bolt_col = bolts.repo.collections[col_name]
|
||||
|
||||
for bolt_class in bolts.repo.collection_classes.get_dsts(bolt_col):
|
||||
if not bolt_class_filter(bolt_class):
|
||||
continue
|
||||
|
||||
if prof_keyword and prof_keyword not in bolt_class.id:
|
||||
continue
|
||||
|
||||
if not bolt_class.parameters.tables:
|
||||
# some bolt classes have no data attached
|
||||
# like hollow_generic_square
|
||||
continue
|
||||
|
||||
bolts_cols = bolt_class.parameters.tables[0].columns
|
||||
bolts_cols = [ifc_params_translation.get(c, "unused") for c in bolts_cols]
|
||||
bolts_data = bolt_class.parameters.tables[0].data
|
||||
|
||||
for prof_name in bolts_data.keys():
|
||||
ifc_params = dict(zip(bolts_cols, bolts_data[prof_name]))
|
||||
if "unused" in ifc_params:
|
||||
del ifc_params["unused"]
|
||||
|
||||
if prof_type == "profile_hollow*_square":
|
||||
ifc_params["YDim"] = ifc_params["XDim"]
|
||||
elif prof_type == "profile_hollow*_circle":
|
||||
# by default bolts provides diameter, so we need to convert it to radius
|
||||
ifc_params["Radius"] /= 2
|
||||
|
||||
# profile is setup by type of profile and by supplying it's parameters
|
||||
# ProfileType stays AREA
|
||||
profile = self.file.create_entity(ifc_profile_name, ProfileType="AREA", **ifc_params)
|
||||
|
||||
# building profiles for each of 3 types
|
||||
self.create_profile_type("IfcBeamType", prof_name, profile)
|
||||
self.create_profile_type("IfcMemberType", prof_name, profile)
|
||||
self.create_profile_type("IfcColumnType", prof_name, profile)
|
||||
|
||||
self.file.write(output_filename)
|
||||
|
||||
def create_layer_set_type(self, name, data):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=data["type"], name=name)
|
||||
element.Description = data["Description"]
|
||||
rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet")
|
||||
layer_set = rel.RelatingMaterial
|
||||
for layer_data in data["Layers"]:
|
||||
layer = ifcopenshell.api.run(
|
||||
"material.add_layer", self.file, layer_set=layer_set, material=self.materials[layer_data[1]]["ifc"]
|
||||
)
|
||||
layer.Name = layer_data[0]
|
||||
layer.LayerThickness = layer_data[2]
|
||||
ifcopenshell.api.run("project.assign_declaration", self.file, definition=element, relating_context=self.library)
|
||||
return element
|
||||
|
||||
def create_layer_type(self, ifc_class, name, thickness):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
|
||||
rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet")
|
||||
layer_set = rel.RelatingMaterial
|
||||
layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=layer_set, material=self.materials["TBD"]["ifc"])
|
||||
layer.LayerThickness = thickness
|
||||
ifcopenshell.api.run("project.assign_declaration", self.file, definition=element, relating_context=self.library)
|
||||
return element
|
||||
|
||||
def create_profile_type(self, ifc_class, name, profile):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
|
||||
rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet")
|
||||
profile_set = rel.RelatingMaterial
|
||||
material_profile = ifcopenshell.api.run(
|
||||
"material.add_profile", self.file, profile_set=profile_set, material=self.material
|
||||
# material=self.materials["TBD"]["ifc"]
|
||||
)
|
||||
ifcopenshell.api.run("material.assign_profile", self.file, material_profile=material_profile, profile=profile)
|
||||
ifcopenshell.api.run("project.assign_declaration", self.file, definition=element, relating_context=self.library)
|
||||
|
||||
def create_type(self, ifc_class, name, representations):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
|
||||
for rep_name, obj_name in representations.items():
|
||||
obj = bpy.data.objects.get(obj_name)
|
||||
representation = ifcopenshell.api.run(
|
||||
"geometry.add_representation",
|
||||
self.file,
|
||||
context=self.representations[rep_name],
|
||||
blender_object=obj,
|
||||
geometry=obj.data,
|
||||
total_items=max(1, len(obj.material_slots)),
|
||||
)
|
||||
styles = []
|
||||
for slot in obj.material_slots:
|
||||
style = ifcopenshell.api.run("style.add_style", self.file, name=slot.material.name)
|
||||
ifcopenshell.api.run(
|
||||
"style.add_surface_style",
|
||||
self.file,
|
||||
style=style,
|
||||
ifc_class="IfcSurfaceStyleRendering",
|
||||
attributes=tool.Style.get_surface_rendering_attributes(slot.material),
|
||||
)
|
||||
styles.append(style)
|
||||
if styles:
|
||||
ifcopenshell.api.run(
|
||||
"style.assign_representation_styles", self.file, shape_representation=representation, styles=styles
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"geometry.assign_representation", self.file, product=element, representation=representation
|
||||
)
|
||||
ifcopenshell.api.run("project.assign_declaration", self.file, definition=element, relating_context=self.library)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
LibraryGenerator().generate(parse_profiles_type="EU", output_filename="IFC4 EU Steel.ifc")
|
||||
LibraryGenerator().generate(parse_profiles_type="AU", output_filename="IFC4 AU Steel.ifc")
|
||||
Reference in New Issue
Block a user