mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 23:31:00 +00:00
merage
This commit is contained in:
@@ -1,153 +1,64 @@
|
|||||||
|
import bpy
|
||||||
|
import json
|
||||||
import math
|
import math
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.attribute
|
||||||
from mathutils import geometry
|
from mathutils import geometry
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
import bpy
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
|
|
||||||
# TODO: Deprecate this in favour of ifcopenshell.util.unit
|
def import_attributes(ifc_class, props, data, callback=None):
|
||||||
|
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
|
||||||
|
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||||
|
if data_type == "entity" or (isinstance(data_type, tuple) and "entity" in ".".join(data_type)):
|
||||||
|
continue
|
||||||
|
new = props.add()
|
||||||
|
new.name = attribute.name()
|
||||||
|
new.is_null = data[attribute.name()] is None
|
||||||
|
new.is_optional = attribute.optional()
|
||||||
|
new.data_type = data_type if isinstance(data_type, str) else ""
|
||||||
|
is_handled_by_callback = callback(attribute.name(), new, data) if callback else False
|
||||||
|
if is_handled_by_callback:
|
||||||
|
pass # Our job is done
|
||||||
|
elif is_handled_by_callback is False:
|
||||||
|
props.remove(len(props) - 1)
|
||||||
|
elif data_type == "string":
|
||||||
|
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||||
|
elif data_type == "boolean":
|
||||||
|
new.bool_value = False if new.is_null else data[attribute.name()]
|
||||||
|
elif data_type == "integer":
|
||||||
|
new.int_value = 0 if new.is_null else data[attribute.name()]
|
||||||
|
elif data_type == "float":
|
||||||
|
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
||||||
|
elif data_type == "enum":
|
||||||
|
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
||||||
|
if data[attribute.name()]:
|
||||||
|
new.enum_value = data[attribute.name()]
|
||||||
|
|
||||||
|
|
||||||
class SIUnitHelper:
|
def export_attributes(props, callback=None):
|
||||||
prefixes = {
|
attributes = {}
|
||||||
"EXA": 1e18,
|
for attribute in props:
|
||||||
"PETA": 1e15,
|
is_handled_by_callback = callback(attributes, attribute) if callback else False
|
||||||
"TERA": 1e12,
|
if attribute.is_null:
|
||||||
"GIGA": 1e9,
|
attributes[attribute.name] = None
|
||||||
"MEGA": 1e6,
|
elif is_handled_by_callback:
|
||||||
"KILO": 1e3,
|
pass # Our job is done
|
||||||
"HECTO": 1e2,
|
elif attribute.data_type == "string":
|
||||||
"DECA": 1e1,
|
attributes[attribute.name] = attribute.string_value
|
||||||
"DECI": 1e-1,
|
elif attribute.data_type == "boolean":
|
||||||
"CENTI": 1e-2,
|
attributes[attribute.name] = attribute.bool_value
|
||||||
"MILLI": 1e-3,
|
elif attribute.data_type == "integer":
|
||||||
"MICRO": 1e-6,
|
attributes[attribute.name] = attribute.int_value
|
||||||
"NANO": 1e-9,
|
elif attribute.data_type == "float":
|
||||||
"PICO": 1e-12,
|
attributes[attribute.name] = attribute.float_value
|
||||||
"FEMTO": 1e-15,
|
elif attribute.data_type == "enum":
|
||||||
"ATTO": 1e-18,
|
attributes[attribute.name] = attribute.enum_value
|
||||||
}
|
return attributes
|
||||||
unit_names = [
|
|
||||||
"AMPERE",
|
|
||||||
"BECQUEREL",
|
|
||||||
"CANDELA",
|
|
||||||
"COULOMB",
|
|
||||||
"CUBIC_METRE",
|
|
||||||
"DEGREE CELSIUS",
|
|
||||||
"FARAD",
|
|
||||||
"GRAM",
|
|
||||||
"GRAY",
|
|
||||||
"HENRY",
|
|
||||||
"HERTZ",
|
|
||||||
"JOULE",
|
|
||||||
"KELVIN",
|
|
||||||
"LUMEN",
|
|
||||||
"LUX",
|
|
||||||
"MOLE",
|
|
||||||
"NEWTON",
|
|
||||||
"OHM",
|
|
||||||
"PASCAL",
|
|
||||||
"RADIAN",
|
|
||||||
"SECOND",
|
|
||||||
"SIEMENS",
|
|
||||||
"SIEVERT",
|
|
||||||
"SQUARE METRE",
|
|
||||||
"METRE",
|
|
||||||
"STERADIAN",
|
|
||||||
"TESLA",
|
|
||||||
"VOLT",
|
|
||||||
"WATT",
|
|
||||||
"WEBER",
|
|
||||||
]
|
|
||||||
si_conversions = {
|
|
||||||
"inch": 0.0254,
|
|
||||||
"foot": 0.3048,
|
|
||||||
"yard": 0.914,
|
|
||||||
"mile": 1609,
|
|
||||||
"square inch": 0.0006452,
|
|
||||||
"square foot": 0.09290304,
|
|
||||||
"square yard": 0.83612736,
|
|
||||||
"acre": 4046.86,
|
|
||||||
"square mile": 2588881,
|
|
||||||
"cubic inch": 0.00001639,
|
|
||||||
"cubic foot": 0.02831684671168849,
|
|
||||||
"cubic yard": 0.7636,
|
|
||||||
"litre": 0.001,
|
|
||||||
"fluid ounce UK": 0.0000284130625,
|
|
||||||
"fluid ounce US": 0.00002957353,
|
|
||||||
"pint UK": 0.000568,
|
|
||||||
"pint US": 0.000473,
|
|
||||||
"gallon UK": 0.004546,
|
|
||||||
"gallon US": 0.003785,
|
|
||||||
"degree": math.pi / 180,
|
|
||||||
"ounce": 0.02835,
|
|
||||||
"pound": 0.454,
|
|
||||||
"ton UK": 1016.0469088,
|
|
||||||
"ton US": 907.18474,
|
|
||||||
"lbf": 4.4482216153,
|
|
||||||
"kip": 4448.2216153,
|
|
||||||
"psi": 6894.7572932,
|
|
||||||
"ksi": 6894757.2932,
|
|
||||||
"minute": 60,
|
|
||||||
"hour": 3600,
|
|
||||||
"day": 86400,
|
|
||||||
"btu": 1055.056,
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_prefix(text):
|
|
||||||
for prefix in SIUnitHelper.prefixes.keys():
|
|
||||||
if prefix in text.upper():
|
|
||||||
return prefix
|
|
||||||
|
|
||||||
@staticmethod
|
# TODO: migrate the below helper functions into the drawing module, since it is specific to that module
|
||||||
def get_prefix_multiplier(text):
|
|
||||||
if not text:
|
|
||||||
return 1
|
|
||||||
prefix = SIUnitHelper.get_prefix(text)
|
|
||||||
if prefix:
|
|
||||||
return SIUnitHelper.prefixes[prefix]
|
|
||||||
return 1
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_unit_name(text):
|
|
||||||
for name in SIUnitHelper.unit_names:
|
|
||||||
if name in text.upper().replace("METER", "METRE"):
|
|
||||||
return name
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def convert(value, from_prefix, from_unit, to_prefix, to_unit):
|
|
||||||
"""Converts between length, area, and volume units
|
|
||||||
|
|
||||||
:param value: The numeric value you want to convert
|
|
||||||
:type value: float
|
|
||||||
:param from_prefix: A prefix from IfcSIPrefix. Can be None.
|
|
||||||
:type from_prefix: string
|
|
||||||
:param from_unit: IfcSIUnitName or IfcConversionBasedUnit.Name
|
|
||||||
:type from_unit: string
|
|
||||||
:param to_prefix: A prefix from IfcSIPrefix. Can be None.
|
|
||||||
:type to_prefix: string
|
|
||||||
:param to_unit: IfcSIUnitName or IfcConversionBasedUnit.Name
|
|
||||||
:type to_unit: string
|
|
||||||
"""
|
|
||||||
if from_unit in SIUnitHelper.si_conversions:
|
|
||||||
value *= SIUnitHelper.si_conversions[from_unit]
|
|
||||||
elif from_prefix:
|
|
||||||
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
|
|
||||||
if "SQUARE" in from_unit:
|
|
||||||
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
|
|
||||||
elif "CUBIC" in from_unit:
|
|
||||||
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
|
|
||||||
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
|
|
||||||
if to_unit in SIUnitHelper.si_conversions:
|
|
||||||
return value * (1 / SIUnitHelper.si_conversions[to_unit])
|
|
||||||
elif to_prefix:
|
|
||||||
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
|
|
||||||
if "SQUARE" in from_unit:
|
|
||||||
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
|
|
||||||
elif "CUBIC" in from_unit:
|
|
||||||
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
|
|
||||||
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py
|
# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py
|
||||||
@@ -302,7 +213,7 @@ def parse_diagram_scale(camera):
|
|||||||
def get_project_collection(scene):
|
def get_project_collection(scene):
|
||||||
"""Get main project collection"""
|
"""Get main project collection"""
|
||||||
|
|
||||||
colls = [c for c in scene.collection.children if c.name.startswith('IfcProject')]
|
colls = [c for c in scene.collection.children if c.name.startswith("IfcProject")]
|
||||||
if len(colls) != 1:
|
if len(colls) != 1:
|
||||||
raise RuntimeError("project collection missing or not unique")
|
raise RuntimeError("project collection missing or not unique")
|
||||||
return colls[0]
|
return colls[0]
|
||||||
@@ -315,7 +226,7 @@ def get_active_drawing(scene):
|
|||||||
return None, None
|
return None, None
|
||||||
try:
|
try:
|
||||||
drawing = props.drawings[props.active_drawing_index]
|
drawing = props.drawings[props.active_drawing_index]
|
||||||
return scene.collection.children['Views'].children[f"IfcGroup/{drawing.name}"], drawing.camera
|
return scene.collection.children["Views"].children[f"IfcGroup/{drawing.name}"], drawing.camera
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
raise RuntimeError("missing drawing collection")
|
raise RuntimeError("missing drawing collection")
|
||||||
|
|
||||||
@@ -333,8 +244,8 @@ def ortho_view_frame(camera, margin=0.015):
|
|||||||
"""
|
"""
|
||||||
aspect = camera.BIMCameraProperties.raster_y / camera.BIMCameraProperties.raster_x
|
aspect = camera.BIMCameraProperties.raster_y / camera.BIMCameraProperties.raster_x
|
||||||
size = camera.ortho_scale
|
size = camera.ortho_scale
|
||||||
hwidth = size * .5
|
hwidth = size * 0.5
|
||||||
hheight = size * .5 * aspect
|
hheight = size * 0.5 * aspect
|
||||||
scale = parse_diagram_scale(camera)
|
scale = parse_diagram_scale(camera)
|
||||||
xmarg = margin * scale
|
xmarg = margin * scale
|
||||||
ymarg = margin * scale * aspect
|
ymarg = margin * scale * aspect
|
||||||
|
|||||||
@@ -718,7 +718,7 @@ class IfcImporter:
|
|||||||
# Create structural collections
|
# Create structural collections
|
||||||
self.structural_member_collection = bpy.data.collections.new("Members")
|
self.structural_member_collection = bpy.data.collections.new("Members")
|
||||||
self.structural_connection_collection = bpy.data.collections.new("Connections")
|
self.structural_connection_collection = bpy.data.collections.new("Connections")
|
||||||
self.structural_collection = bpy.data.collections.new("StructuralEntities")
|
self.structural_collection = bpy.data.collections.new("StructuralItems")
|
||||||
self.structural_collection.children.link(self.structural_member_collection)
|
self.structural_collection.children.link(self.structural_member_collection)
|
||||||
self.structural_collection.children.link(self.structural_connection_collection)
|
self.structural_collection.children.link(self.structural_connection_collection)
|
||||||
self.project["blender"].children.link(self.structural_collection)
|
self.project["blender"].children.link(self.structural_collection)
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class AddRepresentation(bpy.types.Operator):
|
|||||||
[
|
[
|
||||||
bpy.ops.bim.add_style(material=s.material.name)
|
bpy.ops.bim.add_style(material=s.material.name)
|
||||||
for s in obj.material_slots
|
for s in obj.material_slots
|
||||||
if not s.material.BIMMaterialProperties.ifc_style_id
|
if s.material and not s.material.BIMMaterialProperties.ifc_style_id
|
||||||
]
|
]
|
||||||
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class ReassignClass(bpy.types.Operator):
|
|||||||
class AssignClass(bpy.types.Operator):
|
class AssignClass(bpy.types.Operator):
|
||||||
bl_idname = "bim.assign_class"
|
bl_idname = "bim.assign_class"
|
||||||
bl_label = "Assign IFC Class"
|
bl_label = "Assign IFC Class"
|
||||||
bl_options = {'REGISTER', 'UNDO'}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
obj: bpy.props.StringProperty()
|
obj: bpy.props.StringProperty()
|
||||||
ifc_class: bpy.props.StringProperty()
|
ifc_class: bpy.props.StringProperty()
|
||||||
predefined_type: bpy.props.StringProperty()
|
predefined_type: bpy.props.StringProperty()
|
||||||
@@ -92,10 +92,6 @@ class AssignClass(bpy.types.Operator):
|
|||||||
elif self.predefined_type == "":
|
elif self.predefined_type == "":
|
||||||
predefined_type = None
|
predefined_type = None
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
if obj.data and hasattr(obj.data, "materials"):
|
|
||||||
for material in obj.data.materials:
|
|
||||||
if not material.BIMMaterialProperties.ifc_style_id:
|
|
||||||
bpy.ops.bim.add_style(material=material.name)
|
|
||||||
self.assign_class(context, obj)
|
self.assign_class(context, obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ classes = (
|
|||||||
operator.UnassignProduct,
|
operator.UnassignProduct,
|
||||||
operator.GenerateGanttChart,
|
operator.GenerateGanttChart,
|
||||||
operator.ImportP6,
|
operator.ImportP6,
|
||||||
|
operator.ImportMSP,
|
||||||
operator.LoadTaskProperties,
|
operator.LoadTaskProperties,
|
||||||
operator.SelectTaskRelatedProducts,
|
operator.SelectTaskRelatedProducts,
|
||||||
operator.VisualiseWorkScheduleDate,
|
operator.VisualiseWorkScheduleDate,
|
||||||
@@ -82,6 +83,7 @@ classes = (
|
|||||||
|
|
||||||
def menu_func_import(self, context):
|
def menu_func_import(self, context):
|
||||||
self.layout.operator(operator.ImportP6.bl_idname, text="P6 (.xml)")
|
self.layout.operator(operator.ImportP6.bl_idname, text="P6 (.xml)")
|
||||||
|
self.layout.operator(operator.ImportMSP.bl_idname, text="Microsoft Project (.xml)")
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
import os
|
import os
|
||||||
import bpy
|
import bpy
|
||||||
import json
|
import json
|
||||||
@@ -7,6 +8,7 @@ import pystache
|
|||||||
import webbrowser
|
import webbrowser
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.date
|
import ifcopenshell.util.date
|
||||||
|
import blenderbim.bim.helper
|
||||||
import blenderbim.bim.module.sequence.helper as helper
|
import blenderbim.bim.module.sequence.helper as helper
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@@ -32,15 +34,7 @@ class EditWorkPlan(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkPlanProperties
|
props = context.scene.BIMWorkPlanProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.work_plan_attributes, self.export_attributes)
|
||||||
for attribute in props.work_plan_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_plan",
|
"sequence.edit_work_plan",
|
||||||
@@ -51,6 +45,14 @@ class EditWorkPlan(bpy.types.Operator):
|
|||||||
bpy.ops.bim.disable_editing_work_plan()
|
bpy.ops.bim.disable_editing_work_plan()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def export_attributes(self, attributes, prop):
|
||||||
|
if "Date" in prop.name or "Time" in prop.name:
|
||||||
|
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
||||||
|
return True
|
||||||
|
elif prop.name == "Duration" or prop.name == "TotalFloat":
|
||||||
|
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class RemoveWorkPlan(bpy.types.Operator):
|
class RemoveWorkPlan(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_work_plan"
|
bl_idname = "bim.remove_work_plan"
|
||||||
@@ -76,27 +78,17 @@ class EnableEditingWorkPlan(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.work_plans[self.work_plan]
|
data = Data.work_plans[self.work_plan]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkPlan").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcWorkPlan", props.work_plan_attributes, data, self.import_attributes)
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
|
||||||
if data_type == "entity":
|
|
||||||
continue
|
|
||||||
new = props.work_plan_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = data_type
|
|
||||||
if attribute.name() in ["CreationDate", "StartTime", "FinishTime"]:
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
|
||||||
elif data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
props.active_work_plan_id = self.work_plan
|
props.active_work_plan_id = self.work_plan
|
||||||
props.editing_type = "ATTRIBUTES"
|
props.editing_type = "ATTRIBUTES"
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def import_attributes(self, name, prop, data):
|
||||||
|
if name in ["CreationDate", "StartTime", "FinishTime"]:
|
||||||
|
prop.string_value = "" if prop.is_null else data[name].isoformat()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class DisableEditingWorkPlan(bpy.types.Operator):
|
class DisableEditingWorkPlan(bpy.types.Operator):
|
||||||
bl_idname = "bim.disable_editing_work_plan"
|
bl_idname = "bim.disable_editing_work_plan"
|
||||||
@@ -175,15 +167,7 @@ class EditWorkSchedule(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.work_schedule_attributes, self.export_attributes)
|
||||||
for attribute in props.work_schedule_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_schedule",
|
"sequence.edit_work_schedule",
|
||||||
@@ -194,6 +178,14 @@ class EditWorkSchedule(bpy.types.Operator):
|
|||||||
bpy.ops.bim.disable_editing_work_schedule()
|
bpy.ops.bim.disable_editing_work_schedule()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def export_attributes(self, attributes, prop):
|
||||||
|
if "Date" in prop.name or "Time" in prop.name:
|
||||||
|
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
||||||
|
return True
|
||||||
|
elif prop.name == "Duration" or prop.name == "TotalFloat":
|
||||||
|
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class RemoveWorkSchedule(bpy.types.Operator):
|
class RemoveWorkSchedule(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_work_schedule"
|
bl_idname = "bim.remove_work_schedule"
|
||||||
@@ -226,23 +218,14 @@ class EnableEditingWorkSchedule(bpy.types.Operator):
|
|||||||
def enable_editing_work_schedule(self):
|
def enable_editing_work_schedule(self):
|
||||||
data = Data.work_schedules[self.work_schedule]
|
data = Data.work_schedules[self.work_schedule]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkSchedule").all_attributes():
|
blenderbim.bim.helper.import_attributes(
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
"IfcWorkSchedule", self.props.work_schedule_attributes, data, self.import_attributes
|
||||||
if data_type == "entity":
|
)
|
||||||
continue
|
|
||||||
new = self.props.work_schedule_attributes.add()
|
def import_attributes(self, name, prop, data):
|
||||||
new.name = attribute.name()
|
if name in ["CreationDate", "StartTime", "FinishTime"]:
|
||||||
new.is_null = data[attribute.name()] is None
|
prop.string_value = "" if prop.is_null else data[name].isoformat()
|
||||||
new.is_optional = attribute.optional()
|
return True
|
||||||
new.data_type = data_type
|
|
||||||
if attribute.name() in ["CreationDate", "StartTime", "FinishTime"]:
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
|
||||||
elif data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingTasks(bpy.types.Operator):
|
class EnableEditingTasks(bpy.types.Operator):
|
||||||
@@ -258,10 +241,11 @@ class EnableEditingTasks(bpy.types.Operator):
|
|||||||
self.tprops.tasks.remove(0)
|
self.tprops.tasks.remove(0)
|
||||||
|
|
||||||
self.contracted_tasks = json.loads(self.props.contracted_tasks)
|
self.contracted_tasks = json.loads(self.props.contracted_tasks)
|
||||||
sort_keys = {
|
self.sort_keys = {
|
||||||
i: Data.tasks[i]["Identification"] for i in Data.work_schedules[self.work_schedule]["RelatedObjects"]
|
i: Data.tasks[i]["Identification"] or "" for i in Data.work_schedules[self.work_schedule]["RelatedObjects"]
|
||||||
}
|
}
|
||||||
for related_object_id in sorted(sort_keys, key=sort_keys.__getitem__):
|
|
||||||
|
for related_object_id in sorted(self.sort_keys, key=self.natural_sort_key):
|
||||||
self.create_new_task_li(related_object_id, 0)
|
self.create_new_task_li(related_object_id, 0)
|
||||||
bpy.ops.bim.load_task_properties()
|
bpy.ops.bim.load_task_properties()
|
||||||
self.props.editing_type = "TASKS"
|
self.props.editing_type = "TASKS"
|
||||||
@@ -276,10 +260,13 @@ class EnableEditingTasks(bpy.types.Operator):
|
|||||||
if task["RelatedObjects"]:
|
if task["RelatedObjects"]:
|
||||||
new.has_children = True
|
new.has_children = True
|
||||||
if new.is_expanded:
|
if new.is_expanded:
|
||||||
sort_keys = {i: Data.tasks[i]["Identification"] for i in task["RelatedObjects"]}
|
self.sort_keys = {i: Data.tasks[i]["Identification"] or "" for i in task["RelatedObjects"]}
|
||||||
for related_object_id in sorted(sort_keys, key=sort_keys.__getitem__):
|
for related_object_id in sorted(self.sort_keys, key=self.natural_sort_key):
|
||||||
self.create_new_task_li(related_object_id, level_index + 1)
|
self.create_new_task_li(related_object_id, level_index + 1)
|
||||||
return {"FINISHED"}
|
|
||||||
|
def natural_sort_key(self, i, _nsre=re.compile("([0-9]+)")):
|
||||||
|
s = self.sort_keys[i]
|
||||||
|
return [int(text) if text.isdigit() else text.lower() for text in _nsre.split(s)]
|
||||||
|
|
||||||
|
|
||||||
class LoadTaskProperties(bpy.types.Operator):
|
class LoadTaskProperties(bpy.types.Operator):
|
||||||
@@ -322,6 +309,10 @@ class LoadTaskProperties(bpy.types.Operator):
|
|||||||
item.start = "-"
|
item.start = "-"
|
||||||
item.finish = "-"
|
item.finish = "-"
|
||||||
item.duration = "-"
|
item.duration = "-"
|
||||||
|
if task["HasAssignmentsWorkCalendar"]:
|
||||||
|
item.calendar = Data.work_calendars[task["HasAssignmentsWorkCalendar"][0]]["Name"] or "Unnamed"
|
||||||
|
else:
|
||||||
|
item.calendar = ""
|
||||||
self.props.is_task_update_enabled = True
|
self.props.is_task_update_enabled = True
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -434,39 +425,23 @@ class EnableEditingTaskTime(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.task_times[task_time_id]
|
data = Data.task_times[task_time_id]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcTaskTime").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcTaskTime", props.task_time_attributes, data, self.import_attributes)
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
|
||||||
if data_type == "entity":
|
|
||||||
continue
|
|
||||||
new = props.task_time_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = data_type
|
|
||||||
if data_type == "string":
|
|
||||||
if isinstance(data[attribute.name()], datetime):
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
|
||||||
elif isinstance(data[attribute.name()], isodate.Duration):
|
|
||||||
new.string_value = (
|
|
||||||
""
|
|
||||||
if new.is_null
|
|
||||||
else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "boolean":
|
|
||||||
new.bool_value = False if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "float":
|
|
||||||
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
props.active_task_time_id = task_time_id
|
props.active_task_time_id = task_time_id
|
||||||
props.active_task_id = self.task
|
props.active_task_id = self.task
|
||||||
props.editing_task_type = "TASKTIME"
|
props.editing_task_type = "TASKTIME"
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def import_attributes(self, name, prop, data):
|
||||||
|
if prop.data_type == "string":
|
||||||
|
if isinstance(data[name], datetime):
|
||||||
|
prop.string_value = "" if prop.is_null else data[name].isoformat()
|
||||||
|
return True
|
||||||
|
elif isinstance(data[name], isodate.Duration):
|
||||||
|
prop.string_value = (
|
||||||
|
"" if prop.is_null else ifcopenshell.util.date.datetime2ifc(data[name], "IfcDuration")
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
def add_task_time(self):
|
def add_task_time(self):
|
||||||
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=self.file.by_id(self.task))
|
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=self.file.by_id(self.task))
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
@@ -479,20 +454,7 @@ class EditTaskTime(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.task_time_attributes, self.export_attributes)
|
||||||
for attribute in props.task_time_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "boolean":
|
|
||||||
attributes[attribute.name] = attribute.bool_value
|
|
||||||
elif attribute.data_type == "float":
|
|
||||||
attributes[attribute.name] = attribute.float_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
|
|
||||||
attributes = self.convert_strings_to_date_times(attributes)
|
attributes = self.convert_strings_to_date_times(attributes)
|
||||||
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
@@ -506,21 +468,13 @@ class EditTaskTime(bpy.types.Operator):
|
|||||||
bpy.ops.bim.load_task_properties(task=props.active_task_id)
|
bpy.ops.bim.load_task_properties(task=props.active_task_id)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def convert_strings_to_date_times(self, attributes):
|
def export_attributes(self, attributes, prop):
|
||||||
for key, value in attributes.items():
|
if "Start" in prop.name or "Finish" in prop.name or prop.name == "StatusTime":
|
||||||
if not value:
|
attributes[prop.name] = helper.parse_datetime(value)
|
||||||
continue
|
return True
|
||||||
if "Start" in key or "Finish" in key or key == "StatusTime":
|
elif prop.name == "ScheduleDuration":
|
||||||
try:
|
attributes[prop.name] = helper.parse_duration(value)
|
||||||
attributes[key] = parser.isoparse(value)
|
return True
|
||||||
except:
|
|
||||||
try:
|
|
||||||
attributes[key] = parser.parse(value, dayfirst=True, fuzzy=True)
|
|
||||||
except:
|
|
||||||
attributes[key] = None
|
|
||||||
elif key == "ScheduleDuration":
|
|
||||||
attributes[key] = isodate.parse_duration(value)
|
|
||||||
return attributes
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingTask(bpy.types.Operator):
|
class EnableEditingTask(bpy.types.Operator):
|
||||||
@@ -535,25 +489,7 @@ class EnableEditingTask(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.tasks[self.task]
|
data = Data.tasks[self.task]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcTask").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcTask", props.task_attributes, data)
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
|
||||||
if data_type == "entity":
|
|
||||||
continue
|
|
||||||
new = props.task_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = data_type
|
|
||||||
if data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "boolean":
|
|
||||||
new.bool_value = False if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "integer":
|
|
||||||
new.int_value = 0 if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
props.active_task_id = self.task
|
props.active_task_id = self.task
|
||||||
props.editing_task_type = "ATTRIBUTES"
|
props.editing_task_type = "ATTRIBUTES"
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -575,19 +511,7 @@ class EditTask(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.export_attributes(props.task_attributes)
|
||||||
for attribute in props.task_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "boolean":
|
|
||||||
attributes[attribute.name] = attribute.bool_value
|
|
||||||
elif attribute.data_type == "integer":
|
|
||||||
attributes[attribute.name] = attribute.int_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_task", self.file, **{"task": self.file.by_id(props.active_task_id), "attributes": attributes}
|
"sequence.edit_task", self.file, **{"task": self.file.by_id(props.active_task_id), "attributes": attributes}
|
||||||
@@ -773,15 +697,7 @@ class EditWorkCalendar(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkCalendarProperties
|
props = context.scene.BIMWorkCalendarProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.work_calendar_attributes)
|
||||||
for attribute in props.work_calendar_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_calendar",
|
"sequence.edit_work_calendar",
|
||||||
@@ -819,21 +735,7 @@ class EnableEditingWorkCalendar(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.work_calendars[self.work_calendar]
|
data = Data.work_calendars[self.work_calendar]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkCalendar").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcWorkCalendar", self.props.work_calendar_attributes, data)
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
|
||||||
if data_type == "entity":
|
|
||||||
continue
|
|
||||||
new = self.props.work_calendar_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = data_type
|
|
||||||
if data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
self.props.active_work_calendar_id = self.work_calendar
|
self.props.active_work_calendar_id = self.work_calendar
|
||||||
self.props.editing_type = "ATTRIBUTES"
|
self.props.editing_type = "ATTRIBUTES"
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -869,6 +771,27 @@ class ImportP6(bpy.types.Operator, ImportHelper):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class ImportMSP(bpy.types.Operator, ImportHelper):
|
||||||
|
bl_idname = "import_msp.bim"
|
||||||
|
bl_label = "Import MSP"
|
||||||
|
filename_ext = ".xml"
|
||||||
|
filter_glob: bpy.props.StringProperty(default="*.xml", options={"HIDDEN"})
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
from ifcp6.msp2ifc import MSP2Ifc
|
||||||
|
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
start = time.time()
|
||||||
|
msp2ifc = MSP2Ifc()
|
||||||
|
msp2ifc.xml = self.filepath
|
||||||
|
msp2ifc.file = self.file
|
||||||
|
msp2ifc.work_plan = self.file.by_type("IfcWorkPlan")[0] if self.file.by_type("IfcWorkPlan") else None
|
||||||
|
msp2ifc.execute()
|
||||||
|
Data.load(IfcStore.get_file())
|
||||||
|
print("Import finished in {:.2f} seconds".format(time.time() - start))
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingWorkCalendarTimes(bpy.types.Operator):
|
class EnableEditingWorkCalendarTimes(bpy.types.Operator):
|
||||||
bl_idname = "bim.enable_editing_work_calendar_times"
|
bl_idname = "bim.enable_editing_work_calendar_times"
|
||||||
bl_label = "Enable Editing Work Calendar Times"
|
bl_label = "Enable Editing Work Calendar Times"
|
||||||
@@ -910,29 +833,20 @@ class EnableEditingWorkTime(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.work_times[self.work_time]
|
data = Data.work_times[self.work_time]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkTime").all_attributes():
|
blenderbim.bim.helper.import_attributes(
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
"IfcWorkTime", self.props.work_time_attributes, data, self.import_attributes
|
||||||
if data_type == "entity":
|
)
|
||||||
continue
|
|
||||||
new = self.props.work_time_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = data_type
|
|
||||||
if attribute.name() in ["Start", "Finish"]:
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
|
||||||
elif data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
|
|
||||||
self.initialise_recurrence_components()
|
self.initialise_recurrence_components()
|
||||||
self.load_recurrence_pattern_data(data)
|
self.load_recurrence_pattern_data(data)
|
||||||
self.props.active_work_time_id = self.work_time
|
self.props.active_work_time_id = self.work_time
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def import_attributes(self, name, prop, data):
|
||||||
|
if name in ["Start", "Finish"]:
|
||||||
|
prop.string_value = "" if prop.is_null else data[name].isoformat()
|
||||||
|
return True
|
||||||
|
|
||||||
def initialise_recurrence_components(self):
|
def initialise_recurrence_components(self):
|
||||||
if len(self.props.day_components) == 0:
|
if len(self.props.day_components) == 0:
|
||||||
for i in range(0, 31):
|
for i in range(0, 31):
|
||||||
@@ -988,15 +902,7 @@ class EditWorkTime(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.props = context.scene.BIMWorkCalendarProperties
|
self.props = context.scene.BIMWorkCalendarProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(self.props.work_time_attributes)
|
||||||
for attribute in self.props.work_time_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_time",
|
"sequence.edit_work_time",
|
||||||
@@ -1163,6 +1069,7 @@ class EditTaskCalendar(bpy.types.Operator):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
|
bpy.ops.bim.load_task_properties(task=self.task)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -1183,6 +1090,7 @@ class RemoveTaskCalendar(bpy.types.Operator):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
|
bpy.ops.bim.load_task_properties(task=self.task)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -1225,21 +1133,7 @@ class EnableEditingSequenceAttributes(bpy.types.Operator):
|
|||||||
|
|
||||||
def enable_editing_sequence_attributes(self):
|
def enable_editing_sequence_attributes(self):
|
||||||
data = Data.sequences[self.sequence]
|
data = Data.sequences[self.sequence]
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcRelSequence").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcRelSequence", self.props.sequence_attributes, data)
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
|
||||||
if data_type == "entity":
|
|
||||||
continue
|
|
||||||
new = self.props.sequence_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
new.data_type = data_type
|
|
||||||
if data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingSequenceTimeLag(bpy.types.Operator):
|
class EnableEditingSequenceTimeLag(bpy.types.Operator):
|
||||||
@@ -1259,34 +1153,22 @@ class EnableEditingSequenceTimeLag(bpy.types.Operator):
|
|||||||
|
|
||||||
def enable_editing_attributes(self):
|
def enable_editing_attributes(self):
|
||||||
data = Data.lag_times[self.lag_time]
|
data = Data.lag_times[self.lag_time]
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcLagTime").all_attributes():
|
blenderbim.bim.helper.import_attributes(
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
"IfcLagTime", self.props.time_lag_attributes, data, self.import_attributes
|
||||||
if data_type == "entity":
|
)
|
||||||
continue
|
|
||||||
new = self.props.time_lag_attributes.add()
|
def import_attributes(self, name, prop, data):
|
||||||
new.name = attribute.name()
|
if name == "LagValue":
|
||||||
new.is_null = data[attribute.name()] is None
|
if isinstance(data[name], isodate.Duration):
|
||||||
new.is_optional = attribute.optional()
|
prop.data_type = "string"
|
||||||
new.data_type = data_type
|
prop.string_value = (
|
||||||
if attribute.name() == "LagValue":
|
"" if prop.is_null else ifcopenshell.util.date.datetime2ifc(data[name], "IfcDuration")
|
||||||
if isinstance(data[attribute.name()], isodate.Duration):
|
)
|
||||||
new.data_type = "string"
|
return True
|
||||||
new.string_value = (
|
else:
|
||||||
""
|
prop.data_type = "float"
|
||||||
if new.is_null
|
prop.float_value = 0.0 if prop.is_null else data[name]
|
||||||
else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
|
return True
|
||||||
)
|
|
||||||
else:
|
|
||||||
new.data_type = "float"
|
|
||||||
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "float":
|
|
||||||
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
|
|
||||||
|
|
||||||
class UnassignLagTime(bpy.types.Operator):
|
class UnassignLagTime(bpy.types.Operator):
|
||||||
@@ -1325,15 +1207,7 @@ class EditSequenceAttributes(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.sequence_attributes)
|
||||||
for attribute in props.sequence_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_sequence",
|
"sequence.edit_sequence",
|
||||||
@@ -1352,17 +1226,7 @@ class EditSequenceTimeLag(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.time_lag_attributes)
|
||||||
for attribute in props.time_lag_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "float":
|
|
||||||
attributes[attribute.name] = attribute.float_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_lag_time",
|
"sequence.edit_lag_time",
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ class Task(PropertyGroup):
|
|||||||
derived_start: StringProperty(name="Derived Start")
|
derived_start: StringProperty(name="Derived Start")
|
||||||
derived_finish: StringProperty(name="Derived Finish")
|
derived_finish: StringProperty(name="Derived Finish")
|
||||||
derived_duration: StringProperty(name="Derived Duration")
|
derived_duration: StringProperty(name="Derived Duration")
|
||||||
|
calendar: StringProperty(name="Calendar")
|
||||||
is_predecessor: BoolProperty(name="Is Predecessor")
|
is_predecessor: BoolProperty(name="Is Predecessor")
|
||||||
is_successor: BoolProperty(name="Is Successor")
|
is_successor: BoolProperty(name="Is Successor")
|
||||||
|
|
||||||
@@ -189,6 +190,7 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
|||||||
task_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
task_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
||||||
should_show_visualisation_ui: BoolProperty(name="Should Show Visualisation UI", default=False)
|
should_show_visualisation_ui: BoolProperty(name="Should Show Visualisation UI", default=False)
|
||||||
should_show_times: BoolProperty(name="Should Show Times", default=False)
|
should_show_times: BoolProperty(name="Should Show Times", default=False)
|
||||||
|
should_show_calendars: BoolProperty(name="Should Show Calendars", default=False)
|
||||||
active_task_time_id: IntProperty(name="Active Task Id")
|
active_task_time_id: IntProperty(name="Active Task Id")
|
||||||
task_time_attributes: CollectionProperty(name="Task Time Attributes", type=Attribute)
|
task_time_attributes: CollectionProperty(name="Task Time Attributes", type=Attribute)
|
||||||
contracted_tasks: StringProperty(name="Contracted Task Items", default="[]")
|
contracted_tasks: StringProperty(name="Contracted Task Items", default="[]")
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ class BIM_PT_work_schedules(Panel):
|
|||||||
row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK")
|
row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK")
|
||||||
elif self.props.editing_type == "TASKS":
|
elif self.props.editing_type == "TASKS":
|
||||||
row.prop(self.props, "should_show_times", text="", icon="TIME")
|
row.prop(self.props, "should_show_times", text="", icon="TIME")
|
||||||
|
row.prop(self.props, "should_show_calendars", text="", icon="VIEW_ORTHO")
|
||||||
row.prop(self.props, "should_show_visualisation_ui", text="", icon="CAMERA_STEREO")
|
row.prop(self.props, "should_show_visualisation_ui", text="", icon="CAMERA_STEREO")
|
||||||
row.operator("bim.generate_gantt_chart", text="", icon="NLA").work_schedule = work_schedule_id
|
row.operator("bim.generate_gantt_chart", text="", icon="NLA").work_schedule = work_schedule_id
|
||||||
row.operator("bim.add_summary_task", text="", icon="ADD").work_schedule = work_schedule_id
|
row.operator("bim.add_summary_task", text="", icon="ADD").work_schedule = work_schedule_id
|
||||||
@@ -336,6 +337,9 @@ class BIM_UL_tasks(UIList):
|
|||||||
else:
|
else:
|
||||||
row.prop(item, "duration", emboss=False, text="")
|
row.prop(item, "duration", emboss=False, text="")
|
||||||
|
|
||||||
|
if props.should_show_calendars:
|
||||||
|
row.label(text=item.calendar)
|
||||||
|
|
||||||
if context.active_object:
|
if context.active_object:
|
||||||
oprops = context.active_object.BIMObjectProperties
|
oprops = context.active_object.BIMObjectProperties
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
@@ -349,10 +353,6 @@ class BIM_UL_tasks(UIList):
|
|||||||
if props.active_task_id == item.ifc_definition_id:
|
if props.active_task_id == item.ifc_definition_id:
|
||||||
if props.editing_task_type == "TASKTIME":
|
if props.editing_task_type == "TASKTIME":
|
||||||
row.operator("bim.edit_task_time", text="", icon="CHECKMARK")
|
row.operator("bim.edit_task_time", text="", icon="CHECKMARK")
|
||||||
elif props.editing_task_type == "CALENDAR":
|
|
||||||
row.operator("bim.disable_editing_task", text="", icon="CHECKMARK")
|
|
||||||
elif props.editing_task_type == "SEQUENCE":
|
|
||||||
row.operator("bim.disable_editing_task", text="", icon="CHECKMARK")
|
|
||||||
elif props.editing_task_type == "ATTRIBUTES":
|
elif props.editing_task_type == "ATTRIBUTES":
|
||||||
row.operator("bim.edit_task", text="", icon="CHECKMARK")
|
row.operator("bim.edit_task", text="", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_editing_task", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_task", text="", icon="CANCEL")
|
||||||
|
|||||||
@@ -20,22 +20,33 @@ classes = (
|
|||||||
operator.EnableEditingStructuralConnectionCondition,
|
operator.EnableEditingStructuralConnectionCondition,
|
||||||
operator.DisableEditingStructuralConnectionCondition,
|
operator.DisableEditingStructuralConnectionCondition,
|
||||||
operator.RemoveStructuralConnectionCondition,
|
operator.RemoveStructuralConnectionCondition,
|
||||||
operator.EnableEditingStructuralMemberAxis,
|
operator.EnableEditingStructuralItemAxis,
|
||||||
operator.DisableEditingStructuralMemberAxis,
|
operator.DisableEditingStructuralItemAxis,
|
||||||
operator.EditStructuralMemberAxis,
|
operator.EditStructuralItemAxis,
|
||||||
|
operator.EnableEditingStructuralItemConnectionCS,
|
||||||
|
operator.DisableEditingStructuralItemConnectionCS,
|
||||||
|
operator.EditStructuralItemConnectionCS,
|
||||||
operator.AddStructuralLoadCase,
|
operator.AddStructuralLoadCase,
|
||||||
operator.EditStructuralLoadCase,
|
operator.EditStructuralLoadCase,
|
||||||
operator.RemoveStructuralLoadCase,
|
operator.RemoveStructuralLoadCase,
|
||||||
|
operator.AddStructuralLoadGroup,
|
||||||
|
operator.RemoveStructuralLoadGroup,
|
||||||
|
operator.AddStructuralActivity,
|
||||||
operator.EnableEditingStructuralLoadCase,
|
operator.EnableEditingStructuralLoadCase,
|
||||||
|
operator.EnableEditingStructuralLoadCaseGroups,
|
||||||
operator.DisableEditingStructuralLoadCase,
|
operator.DisableEditingStructuralLoadCase,
|
||||||
|
operator.EnableEditingStructuralLoadGroupActivities,
|
||||||
prop.StructuralAnalysisModel,
|
prop.StructuralAnalysisModel,
|
||||||
|
prop.StructuralActivity,
|
||||||
prop.BIMStructuralProperties,
|
prop.BIMStructuralProperties,
|
||||||
prop.BIMObjectStructuralProperties,
|
prop.BIMObjectStructuralProperties,
|
||||||
ui.BIM_PT_structural_analysis_models,
|
ui.BIM_PT_structural_analysis_models,
|
||||||
ui.BIM_PT_structural_boundary_conditions,
|
ui.BIM_PT_structural_boundary_conditions,
|
||||||
ui.BIM_PT_connected_structural_members,
|
ui.BIM_PT_connected_structural_members,
|
||||||
ui.BIM_PT_structural_member,
|
ui.BIM_PT_structural_member,
|
||||||
|
ui.BIM_PT_structural_connection,
|
||||||
ui.BIM_UL_structural_analysis_models,
|
ui.BIM_UL_structural_analysis_models,
|
||||||
|
ui.BIM_UL_structural_activities,
|
||||||
ui.BIM_PT_structural_load_cases,
|
ui.BIM_PT_structural_load_cases,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import bpy
|
|||||||
import json
|
import json
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import blenderbim.bim.helper
|
||||||
from math import degrees
|
from math import degrees
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
@@ -259,7 +260,7 @@ class EditStructuralAnalysisModel(bpy.types.Operator):
|
|||||||
**{
|
**{
|
||||||
"structural_analysis_model": self.file.by_id(props.active_structural_analysis_model_id),
|
"structural_analysis_model": self.file.by_id(props.active_structural_analysis_model_id),
|
||||||
"attributes": attributes,
|
"attributes": attributes,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
bpy.ops.bim.load_structural_analysis_models()
|
bpy.ops.bim.load_structural_analysis_models()
|
||||||
@@ -277,7 +278,7 @@ class RemoveStructuralAnalysisModel(bpy.types.Operator):
|
|||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"structural.remove_structural_analysis_model",
|
"structural.remove_structural_analysis_model",
|
||||||
self.file,
|
self.file,
|
||||||
**{"structural_analysis_model": self.file.by_id(self.structural_analysis_model)}
|
**{"structural_analysis_model": self.file.by_id(self.structural_analysis_model)},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
bpy.ops.bim.load_structural_analysis_models()
|
bpy.ops.bim.load_structural_analysis_models()
|
||||||
@@ -340,7 +341,7 @@ class AssignStructuralAnalysisModel(bpy.types.Operator):
|
|||||||
**{
|
**{
|
||||||
"product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id),
|
"product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id),
|
||||||
"structural_analysis_model": self.file.by_id(self.structural_analysis_model),
|
"structural_analysis_model": self.file.by_id(self.structural_analysis_model),
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -361,15 +362,15 @@ class UnassignStructuralAnalysisModel(bpy.types.Operator):
|
|||||||
**{
|
**{
|
||||||
"product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id),
|
"product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id),
|
||||||
"structural_analysis_model": self.file.by_id(self.structural_analysis_model),
|
"structural_analysis_model": self.file.by_id(self.structural_analysis_model),
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingStructuralMemberAxis(bpy.types.Operator):
|
class EnableEditingStructuralItemAxis(bpy.types.Operator):
|
||||||
bl_idname = "bim.enable_editing_structural_member_axis"
|
bl_idname = "bim.enable_editing_structural_item_axis"
|
||||||
bl_label = "Enable Editing Structural Member Axis"
|
bl_label = "Enable Editing Structural Item Axis"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
obj = bpy.context.active_object
|
obj = bpy.context.active_object
|
||||||
@@ -377,20 +378,22 @@ class EnableEditingStructuralMemberAxis(bpy.types.Operator):
|
|||||||
props = obj.BIMStructuralProperties
|
props = obj.BIMStructuralProperties
|
||||||
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
member = self.file.by_id(oprops.ifc_definition_id)
|
item = self.file.by_id(oprops.ifc_definition_id)
|
||||||
z_axis = Vector(member.Axis.DirectionRatios).normalized() @ obj.matrix_world if member.Axis else None
|
z_axis = Vector(item.Axis.DirectionRatios).normalized() @ obj.matrix_world if item.Axis else None
|
||||||
x_axis = (obj.data.vertices[1].co - obj.data.vertices[0].co).normalized()
|
x_axis = (obj.data.vertices[1].co - obj.data.vertices[0].co).normalized()
|
||||||
location = obj.data.vertices[0].co
|
location = obj.data.vertices[0].co
|
||||||
empty = bpy.data.objects.new("Member Axis", None)
|
empty = bpy.data.objects.new("Item Axis", None)
|
||||||
empty.empty_display_type = "ARROWS"
|
empty.empty_display_type = "ARROWS"
|
||||||
if z_axis:
|
if z_axis:
|
||||||
y_axis = (z_axis.cross(x_axis)).normalized()
|
y_axis = (z_axis.cross(x_axis)).normalized()
|
||||||
empty.matrix_world = Matrix((
|
empty.matrix_world = Matrix(
|
||||||
(x_axis[0], y_axis[0], z_axis[0], location[0]),
|
(
|
||||||
(x_axis[1], y_axis[1], z_axis[1], location[1]),
|
(x_axis[0], y_axis[0], z_axis[0], location[0]),
|
||||||
(x_axis[2], y_axis[2], z_axis[2], location[2]),
|
(x_axis[1], y_axis[1], z_axis[1], location[1]),
|
||||||
(0, 0, 0, 1),
|
(x_axis[2], y_axis[2], z_axis[2], location[2]),
|
||||||
))
|
(0, 0, 0, 1),
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
empty.location = location
|
empty.location = location
|
||||||
empty.rotation_mode = "QUATERNION"
|
empty.rotation_mode = "QUATERNION"
|
||||||
@@ -404,9 +407,9 @@ class EnableEditingStructuralMemberAxis(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class DisableEditingStructuralMemberAxis(bpy.types.Operator):
|
class DisableEditingStructuralItemAxis(bpy.types.Operator):
|
||||||
bl_idname = "bim.disable_editing_structural_member_axis"
|
bl_idname = "bim.disable_editing_structural_item_axis"
|
||||||
bl_label = "Disable Editing Structural Member Axis"
|
bl_label = "Disable Editing Structural Item Axis"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
obj = bpy.context.active_object
|
obj = bpy.context.active_object
|
||||||
@@ -417,9 +420,9 @@ class DisableEditingStructuralMemberAxis(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class EditStructuralMemberAxis(bpy.types.Operator):
|
class EditStructuralItemAxis(bpy.types.Operator):
|
||||||
bl_idname = "bim.edit_structural_member_axis"
|
bl_idname = "bim.edit_structural_item_axis"
|
||||||
bl_label = "Edit Structural Member Axis"
|
bl_label = "Edit Structural Item Axis"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
obj = bpy.context.active_object
|
obj = bpy.context.active_object
|
||||||
@@ -429,12 +432,85 @@ class EditStructuralMemberAxis(bpy.types.Operator):
|
|||||||
z_axis = relative_matrix.col[2][0:3]
|
z_axis = relative_matrix.col[2][0:3]
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"structural.edit_structural_member_axis",
|
"structural.edit_structural_item_axis",
|
||||||
self.file,
|
self.file,
|
||||||
structural_member=self.file.by_id(oprops.ifc_definition_id),
|
structural_item=self.file.by_id(oprops.ifc_definition_id),
|
||||||
axis=z_axis,
|
axis=z_axis,
|
||||||
)
|
)
|
||||||
bpy.ops.bim.disable_editing_structural_member_axis()
|
bpy.ops.bim.disable_editing_structural_item_axis()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingStructuralItemConnectionCS(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_structural_item_connection_cs"
|
||||||
|
bl_label = "Enable Editing Structural Item Connection CS"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
oprops = obj.BIMObjectProperties
|
||||||
|
props = obj.BIMStructuralProperties
|
||||||
|
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
item = self.file.by_id(oprops.ifc_definition_id)
|
||||||
|
z_axis = Vector(item.Axis.DirectionRatios).normalized() @ obj.matrix_world if item.Axis else None
|
||||||
|
x_axis = (obj.data.vertices[1].co - obj.data.vertices[0].co).normalized()
|
||||||
|
location = obj.data.vertices[0].co
|
||||||
|
empty = bpy.data.objects.new("Item Connection CS", None)
|
||||||
|
empty.empty_display_type = "ARROWS"
|
||||||
|
if z_axis:
|
||||||
|
y_axis = (z_axis.cross(x_axis)).normalized()
|
||||||
|
empty.matrix_world = Matrix(
|
||||||
|
(
|
||||||
|
(x_axis[0], y_axis[0], z_axis[0], location[0]),
|
||||||
|
(x_axis[1], y_axis[1], z_axis[1], location[1]),
|
||||||
|
(x_axis[2], y_axis[2], z_axis[2], location[2]),
|
||||||
|
(0, 0, 0, 1),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
empty.location = location
|
||||||
|
empty.rotation_mode = "QUATERNION"
|
||||||
|
empty.rotation_quaternion = x_axis.to_track_quat("X", "Z")
|
||||||
|
|
||||||
|
props.axis_angle = degrees(empty.rotation_euler[0])
|
||||||
|
props.axis_empty = empty
|
||||||
|
context.scene.collection.objects.link(empty)
|
||||||
|
|
||||||
|
props.is_editing_axis = True
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class DisableEditingStructuralItemConnectionCS(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.disable_editing_structural_item_connection_cs"
|
||||||
|
bl_label = "Disable Editing Structural Item Connection CS"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
props = obj.BIMStructuralProperties
|
||||||
|
props.is_editing_axis = False
|
||||||
|
if props.axis_empty:
|
||||||
|
bpy.data.objects.remove(props.axis_empty)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class EditStructuralItemConnectionCS(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.edit_structural_item_connection_cs"
|
||||||
|
bl_label = "Edit Structural Item Connection CS"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
oprops = obj.BIMObjectProperties
|
||||||
|
props = obj.BIMStructuralProperties
|
||||||
|
relative_matrix = props.axis_empty.matrix_world @ obj.matrix_world.inverted()
|
||||||
|
z_axis = relative_matrix.col[2][0:3]
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"structural.edit_structural_item_connection_cs",
|
||||||
|
self.file,
|
||||||
|
structural_item=self.file.by_id(oprops.ifc_definition_id),
|
||||||
|
axis=z_axis,
|
||||||
|
)
|
||||||
|
bpy.ops.bim.disable_editing_structural_item_axis()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -494,15 +570,7 @@ class EditStructuralLoadCase(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMStructuralProperties
|
props = context.scene.BIMStructuralProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.load_case_attributes)
|
||||||
for attribute in props.load_case_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
if attribute.data_type == "string":
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
elif attribute.data_type == "enum":
|
|
||||||
attributes[attribute.name] = attribute.enum_value
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"structural.edit_structural_load_case",
|
"structural.edit_structural_load_case",
|
||||||
@@ -536,33 +604,18 @@ class EnableEditingStructuralLoadCase(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.props = context.scene.BIMStructuralProperties
|
self.props = context.scene.BIMStructuralProperties
|
||||||
self.props.active_load_case_id = self.load_case
|
self.props.active_load_case_id = self.load_case
|
||||||
|
self.props.load_case_editing_type = "ATTRIBUTES"
|
||||||
while len(self.props.load_case_attributes) > 0:
|
while len(self.props.load_case_attributes) > 0:
|
||||||
self.props.load_case_attributes.remove(0)
|
self.props.load_case_attributes.remove(0)
|
||||||
self.enable_editing_structural_load_case()
|
data = Data.load_cases[self.load_case]
|
||||||
|
blenderbim.bim.helper.import_attributes(
|
||||||
|
"IfcStructuralLoadCase", self.props.load_case_attributes, data, self.import_attributes
|
||||||
|
)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def enable_editing_structural_load_case(self):
|
def import_attributes(self, name, prop, data):
|
||||||
data = Data.load_cases[self.load_case]
|
if name in ["SelfWeightCoefficients"]:
|
||||||
print(data)
|
return False
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcStructuralLoadCase").all_attributes():
|
|
||||||
if attribute.name() in ["SelfWeightCoefficients", "Coefficient"]:
|
|
||||||
continue
|
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
|
||||||
if data_type == "entity":
|
|
||||||
continue
|
|
||||||
new = self.props.load_case_attributes.add()
|
|
||||||
new.name = attribute.name()
|
|
||||||
new.is_null = data[attribute.name()] is None
|
|
||||||
new.is_optional = attribute.optional()
|
|
||||||
print(data_type)
|
|
||||||
new.data_type = data_type
|
|
||||||
if data_type == "string":
|
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
|
||||||
elif data_type == "enum":
|
|
||||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
|
||||||
if data[attribute.name()]:
|
|
||||||
new.enum_value = data[attribute.name()]
|
|
||||||
|
|
||||||
|
|
||||||
class DisableEditingStructuralLoadCase(bpy.types.Operator):
|
class DisableEditingStructuralLoadCase(bpy.types.Operator):
|
||||||
@@ -571,4 +624,109 @@ class DisableEditingStructuralLoadCase(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
context.scene.BIMStructuralProperties.active_load_case_id = 0
|
context.scene.BIMStructuralProperties.active_load_case_id = 0
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingStructuralLoadCaseGroups(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_structural_load_case_groups"
|
||||||
|
bl_label = "Enable Editing Structural Load Case Groups"
|
||||||
|
load_case: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.props = context.scene.BIMStructuralProperties
|
||||||
|
self.props.active_load_case_id = self.load_case
|
||||||
|
self.props.load_case_editing_type = "GROUPS"
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class AddStructuralLoadGroup(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.add_structural_load_group"
|
||||||
|
bl_label = "Add Structural Load Group"
|
||||||
|
load_case: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
load_group = ifcopenshell.api.run("structural.add_structural_load_group", self.file)
|
||||||
|
ifcopenshell.api.run("group.assign_group", self.file, product=load_group, group=self.file.by_id(self.load_case))
|
||||||
|
Data.load(IfcStore.get_file())
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveStructuralLoadGroup(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.remove_structural_load_group"
|
||||||
|
bl_label = "Remove Structural Load Group"
|
||||||
|
load_group: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"structural.remove_structural_load_group", self.file, load_group=self.file.by_id(self.load_group)
|
||||||
|
)
|
||||||
|
Data.load(self.file)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingStructuralLoadGroupActivities(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_structural_load_group_activities"
|
||||||
|
bl_label = "Enable Editing Structural Load Group Activities"
|
||||||
|
load_group: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
self.props = context.scene.BIMStructuralProperties
|
||||||
|
self.props.active_load_group_id = self.load_group
|
||||||
|
self.props.load_group_editing_type = "ACTIVITY"
|
||||||
|
self.load_structural_activities()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def load_structural_activities(self):
|
||||||
|
while len(self.props.load_group_activities) > 0:
|
||||||
|
self.props.load_group_activities.remove(0)
|
||||||
|
for activity_id in Data.load_groups[self.load_group]["IsGroupedBy"]:
|
||||||
|
activity = Data.structural_activities[activity_id]
|
||||||
|
new = self.props.load_group_activities.add()
|
||||||
|
new.ifc_definition_id = activity_id
|
||||||
|
new.name = self.file.by_id(activity["AssignedToStructuralItem"]).Name or "Unnamed"
|
||||||
|
new.applied_load_class = self.file.by_id(activity["AppliedLoad"]).is_a()
|
||||||
|
|
||||||
|
|
||||||
|
class AddStructuralActivity(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.add_structural_activity"
|
||||||
|
bl_label = "Add Structural Activity"
|
||||||
|
load_group: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.props = context.scene.BIMStructuralProperties
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
for obj in context.selected_objects:
|
||||||
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||||
|
continue
|
||||||
|
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||||
|
applied_load_class = self.props.applicable_structural_activity_types
|
||||||
|
|
||||||
|
if element.is_a("IfcStructuralPointConnection"):
|
||||||
|
if applied_load_class not in ["IfcStructuralLoadSingleForce", "IfcStructuralLoadSingleDisplacement"]:
|
||||||
|
continue
|
||||||
|
ifc_class = "IfcStructuralPointAction"
|
||||||
|
elif element.is_a("IfcStructuralCurveMember"):
|
||||||
|
if applied_load_class != "IfcStructuralLoadLinearForce":
|
||||||
|
continue
|
||||||
|
ifc_class = "IfcStructuralLinearAction"
|
||||||
|
elif element.is_a("IfcStructuralSurfaceMember"):
|
||||||
|
if applied_load_class != "IfcStructuralLoadPlanarForce":
|
||||||
|
continue
|
||||||
|
ifc_class = "IfcStructuralPlanarAction"
|
||||||
|
|
||||||
|
activity = ifcopenshell.api.run(
|
||||||
|
"structural.add_structural_activity",
|
||||||
|
self.file,
|
||||||
|
ifc_class=ifc_class,
|
||||||
|
applied_load=None, # TODO
|
||||||
|
structural_member=element
|
||||||
|
)
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"group.assign_group", self.file, product=activity, group=self.file.by_id(self.load_group)
|
||||||
|
)
|
||||||
|
Data.load(IfcStore.get_file())
|
||||||
|
bpy.ops.bim.enable_editing_structural_load_group_activities(load_group=self.load_group)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import bpy
|
import bpy
|
||||||
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from math import radians
|
from math import radians
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
@@ -14,6 +15,28 @@ from bpy.props import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def getApplicableStructuralActivityTypes(self, context):
|
||||||
|
ifc_file = IfcStore.get_file()
|
||||||
|
element_classes = set(
|
||||||
|
[
|
||||||
|
ifc_file.by_id(o.BIMObjectProperties.ifc_definition_id).is_a()
|
||||||
|
for o in bpy.context.selected_objects
|
||||||
|
if o.BIMObjectProperties.ifc_definition_id
|
||||||
|
]
|
||||||
|
)
|
||||||
|
types = [("IfcStructuralLoadTemperature", "IfcStructuralLoadTemperature", "")]
|
||||||
|
if "IfcStructuralPointConnection" in element_classes:
|
||||||
|
types.extend([
|
||||||
|
("IfcStructuralLoadSingleForce", "IfcStructuralLoadSingleForce", ""),
|
||||||
|
("IfcStructuralLoadSingleDisplacement", "IfcStructuralLoadSingleDisplacement", "")
|
||||||
|
])
|
||||||
|
if "IfcStructuralCurveMember" in element_classes:
|
||||||
|
types.append(("IfcStructuralLoadLinearForce", "IfcStructuralLoadLinearForce", ""))
|
||||||
|
if "IfcStructuralSurfaceMember" in element_classes:
|
||||||
|
types.append(("IfcStructuralLoadPlanarForce", "IfcStructuralLoadPlanarForce", ""))
|
||||||
|
return types
|
||||||
|
|
||||||
|
|
||||||
def updateAxisAngle(self, context):
|
def updateAxisAngle(self, context):
|
||||||
if not self.axis_empty:
|
if not self.axis_empty:
|
||||||
return
|
return
|
||||||
@@ -27,11 +50,29 @@ def updateAxisAngle(self, context):
|
|||||||
empty.rotation_euler[0] = radians(self.axis_angle)
|
empty.rotation_euler[0] = radians(self.axis_angle)
|
||||||
|
|
||||||
|
|
||||||
|
def updateConnectionCS(self, context):
|
||||||
|
if not self.ccs_empty:
|
||||||
|
return
|
||||||
|
obj = context.active_object
|
||||||
|
empty = self.ccs_empty
|
||||||
|
empty.location = obj.data.vertices[0].co
|
||||||
|
empty.rotation_mode = "XYZ"
|
||||||
|
empty.rotation_euler[0] = radians(self.ccs_x_angle)
|
||||||
|
empty.rotation_euler[1] = radians(self.ccs_y_angle)
|
||||||
|
empty.rotation_euler[2] = radians(self.ccs_z_angle)
|
||||||
|
|
||||||
|
|
||||||
class StructuralAnalysisModel(PropertyGroup):
|
class StructuralAnalysisModel(PropertyGroup):
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
|
|
||||||
|
|
||||||
|
class StructuralActivity(PropertyGroup):
|
||||||
|
name: StringProperty(name="Name")
|
||||||
|
applied_load_class: StringProperty(name="Applied Load Class")
|
||||||
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
|
|
||||||
|
|
||||||
class BIMStructuralProperties(PropertyGroup):
|
class BIMStructuralProperties(PropertyGroup):
|
||||||
structural_analysis_model_attributes: CollectionProperty(
|
structural_analysis_model_attributes: CollectionProperty(
|
||||||
name="Structural Analysis Model Attributes", type=Attribute
|
name="Structural Analysis Model Attributes", type=Attribute
|
||||||
@@ -40,12 +81,17 @@ class BIMStructuralProperties(PropertyGroup):
|
|||||||
structural_analysis_models: CollectionProperty(name="Structural Analysis Models", type=StructuralAnalysisModel)
|
structural_analysis_models: CollectionProperty(name="Structural Analysis Models", type=StructuralAnalysisModel)
|
||||||
active_structural_analysis_model_index: IntProperty(name="Active Structural Analysis Model Index")
|
active_structural_analysis_model_index: IntProperty(name="Active Structural Analysis Model Index")
|
||||||
active_structural_analysis_model_id: IntProperty(name="Active Structural Analysis Model Id")
|
active_structural_analysis_model_id: IntProperty(name="Active Structural Analysis Model Id")
|
||||||
|
load_case_editing_type: StringProperty(name="Load Case Editing Type")
|
||||||
# editing_type: StringProperty(name="Editing Type")
|
|
||||||
# active_load_case_index: IntProperty(name="Active Work Schedules Index")
|
|
||||||
|
|
||||||
load_case_attributes: CollectionProperty(name="Load Case Attributes", type=Attribute)
|
load_case_attributes: CollectionProperty(name="Load Case Attributes", type=Attribute)
|
||||||
active_load_case_id: IntProperty(name="Active Load Case Id")
|
active_load_case_id: IntProperty(name="Active Load Case Id")
|
||||||
|
load_group_editing_type: StringProperty(name="Load Group Editing Type")
|
||||||
|
# load_group_attributes: CollectionProperty(name="Load Group Attributes", type=Attribute)
|
||||||
|
active_load_group_id: IntProperty(name="Active Load Group Id")
|
||||||
|
applicable_structural_activity_types: EnumProperty(
|
||||||
|
items=getApplicableStructuralActivityTypes, name="Applicable Structural Activity Types"
|
||||||
|
)
|
||||||
|
load_group_activities: CollectionProperty(name="Load Group Activities", type=StructuralActivity)
|
||||||
|
active_load_group_activity_index: IntProperty(name="Active Load Group Activity Index")
|
||||||
|
|
||||||
|
|
||||||
class BIMObjectStructuralProperties(PropertyGroup):
|
class BIMObjectStructuralProperties(PropertyGroup):
|
||||||
@@ -58,3 +104,8 @@ class BIMObjectStructuralProperties(PropertyGroup):
|
|||||||
axis_empty: PointerProperty(name="Axis Empty", type=bpy.types.Object)
|
axis_empty: PointerProperty(name="Axis Empty", type=bpy.types.Object)
|
||||||
|
|
||||||
# relating_structural_activity: PointerProperty(name="Relating Structural Activity", type=bpy.types.Object)
|
# relating_structural_activity: PointerProperty(name="Relating Structural Activity", type=bpy.types.Object)
|
||||||
|
is_editing_connection_cs: BoolProperty(name="Is Editing Connection CS", default=False)
|
||||||
|
ccs_x_angle: FloatProperty(name="Connection CS X Angle", update=updateConnectionCS)
|
||||||
|
ccs_y_angle: FloatProperty(name="Connection CS Y Angle", update=updateConnectionCS)
|
||||||
|
ccs_z_angle: FloatProperty(name="Connection CS Z Angle", update=updateConnectionCS)
|
||||||
|
ccs_empty: PointerProperty(name="CCS Empty", type=bpy.types.Object)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import bpy
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.structural.data import Data
|
from ifcopenshell.api.structural.data import Data
|
||||||
@@ -169,11 +170,63 @@ class BIM_PT_structural_member(Panel):
|
|||||||
if self.props.is_editing_axis:
|
if self.props.is_editing_axis:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(self.props, "axis_angle")
|
row.prop(self.props, "axis_angle")
|
||||||
row.operator("bim.edit_structural_member_axis", text="", icon="CHECKMARK")
|
row.operator("bim.edit_structural_item_axis", text="", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_editing_structural_member_axis", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_structural_item_axis", text="", icon="CANCEL")
|
||||||
else:
|
else:
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.operator("bim.enable_editing_structural_member_axis", text="Edit Axis", icon="GREASEPENCIL")
|
row.operator("bim.enable_editing_structural_item_axis", text="Edit Axis", icon="GREASEPENCIL")
|
||||||
|
else:
|
||||||
|
row = self.layout.row()
|
||||||
|
row.label(text="TODO")
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_PT_structural_connection(Panel):
|
||||||
|
bl_label = "IFC Structural Connection"
|
||||||
|
bl_idname = "BIM_PT_structural_connection"
|
||||||
|
bl_options = {"DEFAULT_CLOSED"}
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "object"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
if not context.active_object:
|
||||||
|
return False
|
||||||
|
props = context.active_object.BIMObjectProperties
|
||||||
|
if not props.ifc_definition_id:
|
||||||
|
return False
|
||||||
|
if not IfcStore.get_file().by_id(props.ifc_definition_id).is_a("IfcStructuralConnection"):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
self.oprops = context.active_object.BIMObjectProperties
|
||||||
|
self.props = context.active_object.BIMStructuralProperties
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
|
||||||
|
if self.file.by_id(self.oprops.ifc_definition_id).is_a("IfcStructuralCurveConnection"):
|
||||||
|
if self.props.is_editing_axis:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(self.props, "axis_angle")
|
||||||
|
row.operator("bim.edit_structural_item_axis", text="", icon="CHECKMARK")
|
||||||
|
row.operator("bim.disable_editing_structural_item_axis", text="", icon="CANCEL")
|
||||||
|
else:
|
||||||
|
row = self.layout.row()
|
||||||
|
row.operator("bim.enable_editing_structural_item_axis", text="Edit Axis", icon="GREASEPENCIL")
|
||||||
|
|
||||||
|
elif self.file.by_id(self.oprops.ifc_definition_id).is_a("IfcStructuralPointConnection"):
|
||||||
|
if self.props.is_editing_connection_cs:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text="Editing Connection CS")
|
||||||
|
row.operator("bim.edit_structural_item_connection_cs", text="", icon="CHECKMARK")
|
||||||
|
row.operator("bim.disable_editing_structural_item_connection_cs", text="", icon="CANCEL")
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(self.props, "ccs_x_angle")
|
||||||
|
row.prop(self.props, "ccs_y_angle")
|
||||||
|
row.prop(self.props, "ccs_z_angle")
|
||||||
|
else:
|
||||||
|
row = self.layout.row()
|
||||||
|
row.operator("bim.enable_editing_structural_item_connection_cs", text="Edit Connection CS", icon="GREASEPENCIL")
|
||||||
else:
|
else:
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.label(text="TODO")
|
row.label(text="TODO")
|
||||||
@@ -292,25 +345,76 @@ class BIM_PT_structural_load_cases(Panel):
|
|||||||
row.label(text=load_case["Name"] or "Unnamed", icon="CON_CLAMPTO")
|
row.label(text=load_case["Name"] or "Unnamed", icon="CON_CLAMPTO")
|
||||||
|
|
||||||
if self.props.active_load_case_id and self.props.active_load_case_id == load_case_id:
|
if self.props.active_load_case_id and self.props.active_load_case_id == load_case_id:
|
||||||
row.operator("bim.edit_structural_load_case", text="", icon="CHECKMARK")
|
if self.props.load_case_editing_type == "ATTRIBUTES":
|
||||||
|
row.operator("bim.edit_structural_load_case", text="", icon="CHECKMARK")
|
||||||
|
elif self.props.load_case_editing_type == "GROUPS":
|
||||||
|
row.operator("bim.add_structural_load_group", text="", icon="ADD").load_case = load_case_id
|
||||||
row.operator("bim.disable_editing_structural_load_case", text="", icon="CANCEL")
|
row.operator("bim.disable_editing_structural_load_case", text="", icon="CANCEL")
|
||||||
elif self.props.active_load_case_id:
|
elif self.props.active_load_case_id:
|
||||||
row.operator("bim.remove_structural_load_case", text="", icon="X").load_case = load_case_id
|
row.operator("bim.remove_structural_load_case", text="", icon="X").load_case = load_case_id
|
||||||
else:
|
else:
|
||||||
|
row.operator(
|
||||||
|
"bim.enable_editing_structural_load_case_groups", text="", icon="GHOST_ENABLED"
|
||||||
|
).load_case = load_case_id
|
||||||
row.operator(
|
row.operator(
|
||||||
"bim.enable_editing_structural_load_case", text="", icon="GREASEPENCIL"
|
"bim.enable_editing_structural_load_case", text="", icon="GREASEPENCIL"
|
||||||
).load_case = load_case_id
|
).load_case = load_case_id
|
||||||
row.operator("bim.remove_structural_load_case", text="", icon="X").load_case = load_case_id
|
row.operator("bim.remove_structural_load_case", text="", icon="X").load_case = load_case_id
|
||||||
|
|
||||||
if self.props.active_load_case_id == load_case_id:
|
if self.props.active_load_case_id == load_case_id:
|
||||||
self.draw_editable_load_case_ui()
|
if self.props.load_case_editing_type == "ATTRIBUTES":
|
||||||
|
self.draw_editable_load_case_ui()
|
||||||
|
elif self.props.load_case_editing_type == "GROUPS":
|
||||||
|
self.draw_editable_load_case_group_ui(load_case)
|
||||||
|
|
||||||
def draw_editable_load_case_ui(self):
|
def draw_editable_load_case_ui(self):
|
||||||
for attribute in self.props.load_case_attributes:
|
for attribute in self.props.load_case_attributes:
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
if attribute.data_type == "string":
|
if attribute.data_type == "string":
|
||||||
row.prop(attribute, "string_value", text=attribute.name)
|
row.prop(attribute, "string_value", text=attribute.name)
|
||||||
|
elif attribute.data_type == "float":
|
||||||
|
row.prop(attribute, "float_value", text=attribute.name)
|
||||||
elif attribute.data_type == "enum":
|
elif attribute.data_type == "enum":
|
||||||
row.prop(attribute, "enum_value", text=attribute.name)
|
row.prop(attribute, "enum_value", text=attribute.name)
|
||||||
if attribute.is_optional:
|
if attribute.is_optional:
|
||||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||||
|
|
||||||
|
def draw_editable_load_case_group_ui(self, load_case):
|
||||||
|
box = self.layout.box()
|
||||||
|
if not len(load_case["IsGroupedBy"]):
|
||||||
|
row = box.row(align=True)
|
||||||
|
row.label(text="No Load Groups Found")
|
||||||
|
for load_group_id in load_case["IsGroupedBy"]:
|
||||||
|
load_group = Data.load_groups[load_group_id]
|
||||||
|
row = box.row(align=True)
|
||||||
|
row.label(text=load_group["Name"] or "Unnamed", icon="GHOST_ENABLED")
|
||||||
|
op = row.operator("bim.enable_editing_structural_load_group_activities", text="", icon="GHOST_ENABLED")
|
||||||
|
op.load_group = load_group_id
|
||||||
|
row.operator("bim.remove_structural_load_group", text="", icon="X").load_group = load_group_id
|
||||||
|
|
||||||
|
if self.props.active_load_group_id == load_group_id:
|
||||||
|
if self.props.load_group_editing_type == "ACTIVITY":
|
||||||
|
self.draw_editable_load_group_activities_ui(box, load_group)
|
||||||
|
|
||||||
|
def draw_editable_load_group_activities_ui(self, layout, load_group):
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(self.props, "applicable_structural_activity_types", text="")
|
||||||
|
op = row.operator("bim.add_structural_activity", text="", icon="ADD")
|
||||||
|
op.load_group = load_group["id"]
|
||||||
|
layout.template_list(
|
||||||
|
"BIM_UL_structural_activities",
|
||||||
|
"",
|
||||||
|
self.props,
|
||||||
|
"load_group_activities",
|
||||||
|
self.props,
|
||||||
|
"active_load_group_activity_index",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_UL_structural_activities(UIList):
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
if item:
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.label(text=item.name)
|
||||||
|
row.label(text=item.applied_load_class)
|
||||||
|
|||||||
@@ -166,8 +166,11 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
std::vector<T> ts;
|
std::vector<T> ts;
|
||||||
|
|
||||||
if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) {
|
if (extend < 0.) {
|
||||||
return ts;
|
// Shell are only required when we do the boolean based intersection check
|
||||||
|
if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) {
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ts = select_box(bb, completely_within);
|
ts = select_box(bb, completely_within);
|
||||||
@@ -288,7 +291,9 @@ namespace IfcGeom {
|
|||||||
if (it.initialize()) {
|
if (it.initialize()) {
|
||||||
do {
|
do {
|
||||||
IfcGeom::BRepElement<double>* elem = (IfcGeom::BRepElement<double>*)it.get();
|
IfcGeom::BRepElement<double>* elem = (IfcGeom::BRepElement<double>*)it.get();
|
||||||
add((IfcUtil::IfcBaseEntity*)it.file()->instance_by_id(elem->id()), elem->geometry().as_compound());
|
auto compound = elem->geometry().as_compound();
|
||||||
|
compound.Move(elem->transformation().data());
|
||||||
|
add((IfcUtil::IfcBaseEntity*)it.file()->instance_by_id(elem->id()), compound);
|
||||||
} while (it.next());
|
} while (it.next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user