mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 10:51:13 +00:00
merage master v6.0.0
This commit is contained in:
@@ -52,10 +52,10 @@ endif
|
||||
|
||||
# Provides IfcOpenShell Python functionality
|
||||
ifeq ($(PYVERSION), py37)
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-37-v0.6.0-517b819-$(PLATFORM)64.zip
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-37-v0.6.0-ff7219b-$(PLATFORM)64.zip
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-39-v0.6.0-517b819-$(PLATFORM)64.zip
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-39-v0.6.0-ff7219b-$(PLATFORM)64.zip
|
||||
endif
|
||||
cd dist/working && unzip ifcblender*
|
||||
cp -r dist/working/io_import_scene_ifc/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||
@@ -142,7 +142,7 @@ endif
|
||||
cd dist/working && unzip v0.6.0.zip
|
||||
# IfcOpenBot sometimes lags behind, so we hotfix the Python utilities
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/util/* dist/blenderbim/libs/site/packages/ifcopenshell/util/
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/api dist/blenderbim/libs/site/packages/ifcopenshell/api
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/api/* dist/blenderbim/libs/site/packages/ifcopenshell/api/
|
||||
# Provides bcf functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/bcf/bcf dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCClash functionality
|
||||
|
||||
@@ -25,6 +25,7 @@ if bpy is not None:
|
||||
"geometry": None,
|
||||
"cobie": None,
|
||||
"sequence": None,
|
||||
"cost": None,
|
||||
"group": None,
|
||||
"structural": None,
|
||||
"material": None,
|
||||
|
||||
@@ -90,7 +90,7 @@ class IfcExporter:
|
||||
for guid in to_delete:
|
||||
product = self.file.by_id(guid)
|
||||
IfcStore.unlink_element(product)
|
||||
ifcopenshell.api.run("remove_product", self.file, **{"product": product})
|
||||
ifcopenshell.api.run("root.remove_product", self.file, **{"product": product})
|
||||
|
||||
def sync_edited_objects(self):
|
||||
for obj_name in IfcStore.edited_objs.copy():
|
||||
|
||||
@@ -414,7 +414,11 @@ class IfcImporter:
|
||||
self.exclude_elements |= self.native_elements
|
||||
|
||||
def is_native(self, element):
|
||||
if not element.Representation or not element.Representation.Representations or element.HasOpenings:
|
||||
if (
|
||||
not element.Representation
|
||||
or not element.Representation.Representations
|
||||
or getattr(element, "HasOpenings", None)
|
||||
):
|
||||
return
|
||||
representations = self.get_transformed_body_representations(element.Representation.Representations)
|
||||
|
||||
|
||||
@@ -205,7 +205,8 @@ class Helper:
|
||||
for edge in bm.edges:
|
||||
edge_vector = edge.verts[1].co - edge.verts[0].co
|
||||
unshared_verts = set(edge.verts) - face_verts_set
|
||||
if len(unshared_verts) == 1 and not (edge_vector.angle(profile_face.normal) - pi / 2 < 0.001):
|
||||
angle_to_normal = edge_vector.angle(profile_face.normal)
|
||||
if len(unshared_verts) == 1 and (angle_to_normal < 0.001 or angle_to_normal - pi < 0.001):
|
||||
if unshared_verts.pop() == edge.verts[1]:
|
||||
return [edge.verts[0].index, edge.verts[1].index]
|
||||
return [edge.verts[1].index, edge.verts[0].index]
|
||||
|
||||
@@ -398,7 +398,7 @@ class UpdateMeshRepresentation(bpy.types.Operator):
|
||||
|
||||
obj.data.BIMMeshProperties.ifc_definition_id = int(new_representation.id())
|
||||
obj.data.name = f"{old_representation.ContextOfItems.id()}/{new_representation.id()}"
|
||||
bpy.ops.bim.remove_representation(representation_id=old_representation.id())
|
||||
bpy.ops.bim.remove_representation(representation_id=old_representation.id(), obj=obj.name)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ classes = (
|
||||
operator.EnableEditingGeoreferencing,
|
||||
operator.DisableEditingGeoreferencing,
|
||||
operator.EditGeoreferencing,
|
||||
operator.SetNorthOffset,
|
||||
operator.GetNorthOffset,
|
||||
operator.SetIfcGridNorth,
|
||||
operator.SetBlenderGridNorth,
|
||||
operator.SetIfcTrueNorth,
|
||||
operator.SetBlenderTrueNorth,
|
||||
operator.RemoveGeoreferencing,
|
||||
operator.AddGeoreferencing,
|
||||
operator.ConvertLocalToGlobal,
|
||||
|
||||
@@ -17,27 +17,6 @@ class EnableEditingGeoreferencing(bpy.types.Operator):
|
||||
self.file = IfcStore.get_file()
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
while len(props.map_conversion) > 0:
|
||||
props.map_conversion.remove(0)
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
new = props.map_conversion.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = Data.map_conversion[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.map_conversion[attribute.name()]
|
||||
elif data_type == "float":
|
||||
new.float_value = 0.0 if new.is_null else Data.map_conversion[attribute.name()]
|
||||
elif data_type == "integer":
|
||||
new.int_value = 0 if new.is_null else Data.map_conversion[attribute.name()]
|
||||
elif data_type == "boolean":
|
||||
new.bool_value = False if new.is_null else Data.map_conversion[attribute.name()]
|
||||
|
||||
while len(props.projected_crs) > 0:
|
||||
props.projected_crs.remove(0)
|
||||
|
||||
@@ -69,6 +48,27 @@ class EnableEditingGeoreferencing(bpy.types.Operator):
|
||||
elif props.map_unit_type == "IfcConversionBasedUnit":
|
||||
props.map_unit_imperial = Data.projected_crs["MapUnit"]["Name"]
|
||||
|
||||
while len(props.map_conversion) > 0:
|
||||
props.map_conversion.remove(0)
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity" or data_type == "select":
|
||||
continue
|
||||
print(attribute.name(), data_type)
|
||||
new = props.map_conversion.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = Data.map_conversion[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
# Enforce a string data type to prevent data loss in singpe-precision Blender props
|
||||
new.data_type = "string"
|
||||
new.string_value = "" if new.is_null else str(Data.map_conversion[attribute.name()])
|
||||
|
||||
props.has_true_north = bool(Data.true_north)
|
||||
if Data.true_north:
|
||||
props.true_north_abscissa = str(Data.true_north[0])
|
||||
props.true_north_ordinate = str(Data.true_north[1])
|
||||
|
||||
props.is_editing = True
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -91,23 +91,6 @@ class EditGeoreferencing(bpy.types.Operator):
|
||||
self.file = IfcStore.get_file()
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
map_conversion = {}
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
blender_attribute = props.map_conversion.get(attribute.name())
|
||||
if blender_attribute.is_null:
|
||||
map_conversion[attribute.name()] = None
|
||||
elif blender_attribute.data_type == "string":
|
||||
map_conversion[attribute.name()] = blender_attribute.string_value
|
||||
elif blender_attribute.data_type == "float":
|
||||
map_conversion[attribute.name()] = blender_attribute.float_value
|
||||
elif blender_attribute.data_type == "integer":
|
||||
map_conversion[attribute.name()] = blender_attribute.int_value
|
||||
elif blender_attribute.data_type == "boolean":
|
||||
map_conversion[attribute.name()] = blender_attribute.bool_value
|
||||
|
||||
projected_crs = {}
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
@@ -129,38 +112,87 @@ class EditGeoreferencing(bpy.types.Operator):
|
||||
if not props.is_map_unit_null:
|
||||
map_unit = props.map_unit_si if props.map_unit_type == "IfcSIUnit" else props.map_unit_imperial
|
||||
|
||||
map_conversion = {}
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity" or data_type == "select":
|
||||
continue
|
||||
blender_attribute = props.map_conversion.get(attribute.name())
|
||||
if blender_attribute.is_null:
|
||||
map_conversion[attribute.name()] = None
|
||||
elif blender_attribute.data_type == "string":
|
||||
# We store our floats as string to prevent single precision data loss
|
||||
map_conversion[attribute.name()] = float(blender_attribute.string_value)
|
||||
|
||||
true_north = None
|
||||
if props.has_true_north:
|
||||
try:
|
||||
true_north = [float(props.true_north_abscissa), float(props.true_north_ordinate)]
|
||||
except:
|
||||
pass
|
||||
|
||||
ifcopenshell.api.run(
|
||||
"georeference.edit_georeferencing",
|
||||
self.file,
|
||||
**{"map_conversion": map_conversion, "projected_crs": projected_crs, "map_unit": map_unit}
|
||||
**{
|
||||
"map_conversion": map_conversion,
|
||||
"projected_crs": projected_crs,
|
||||
"map_unit": map_unit,
|
||||
"true_north": true_north,
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_georeferencing()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetNorthOffset(bpy.types.Operator):
|
||||
bl_idname = "bim.set_north_offset"
|
||||
bl_label = "Set North Offset"
|
||||
class SetBlenderGridNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_blender_grid_north"
|
||||
bl_label = "Set Blender Grid North"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.sun_pos_properties.north_offset = -radians(
|
||||
ifcopenshell.util.geolocation.xy2angle(
|
||||
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisAbscissa").float_value,
|
||||
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisOrdinate").float_value,
|
||||
ifcopenshell.util.geolocation.xaxis2angle(
|
||||
float(context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisAbscissa").string_value),
|
||||
float(context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisOrdinate").string_value),
|
||||
)
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class GetNorthOffset(bpy.types.Operator):
|
||||
bl_idname = "bim.get_north_offset"
|
||||
bl_label = "Get North Offset"
|
||||
class SetIfcGridNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_ifc_grid_north"
|
||||
bl_label = "Set IFC Grid North"
|
||||
|
||||
def execute(self, context):
|
||||
x_angle = -context.scene.sun_pos_properties.north_offset
|
||||
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisAbscissa").float_value = cos(x_angle)
|
||||
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisOrdinate").float_value = sin(x_angle)
|
||||
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisAbscissa").string_value = str(cos(x_angle))
|
||||
context.scene.BIMGeoreferenceProperties.map_conversion.get("XAxisOrdinate").string_value = str(sin(x_angle))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetBlenderTrueNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_blender_true_north"
|
||||
bl_label = "Set Blender True North"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.sun_pos_properties.north_offset = -radians(
|
||||
ifcopenshell.util.geolocation.yaxis2angle(
|
||||
float(context.scene.BIMGeoreferenceProperties.true_north_abscissa),
|
||||
float(context.scene.BIMGeoreferenceProperties.true_north_ordinate),
|
||||
)
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetIfcTrueNorth(bpy.types.Operator):
|
||||
bl_idname = "bim.set_ifc_true_north"
|
||||
bl_label = "Set IFC True North"
|
||||
|
||||
def execute(self, context):
|
||||
y_angle = -context.scene.sun_pos_properties.north_offset + radians(90)
|
||||
context.scene.BIMGeoreferenceProperties.true_north_abscissa = str(cos(y_angle))
|
||||
context.scene.BIMGeoreferenceProperties.true_north_ordinate = str(sin(y_angle))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -46,3 +46,6 @@ class BIMGeoreferenceProperties(PropertyGroup):
|
||||
blender_orthogonal_height: StringProperty(name="Blender Orthogonal Height", default="0")
|
||||
blender_x_axis_abscissa: StringProperty(name="Blender X Axis Abscissa", default="1")
|
||||
blender_x_axis_ordinate: StringProperty(name="Blender X Axis Ordinate", default="0")
|
||||
has_true_north: BoolProperty(name="Has True North", default=True)
|
||||
true_north_abscissa: StringProperty(name="True North Abscissa")
|
||||
true_north_ordinate: StringProperty(name="True North Ordinate")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import ifcopenshell.util.geolocation
|
||||
from bpy.types import Panel
|
||||
from ifcopenshell.api.georeference.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class BIM_PT_gis(Panel):
|
||||
bl_label = "IFC Georeferencing"
|
||||
bl_idname = "BIM_PT_gis"
|
||||
@@ -15,6 +17,8 @@ class BIM_PT_gis(Panel):
|
||||
return IfcStore.get_file()
|
||||
|
||||
def draw(self, context):
|
||||
self.layout.use_property_split = True
|
||||
self.layout.use_property_decorate = False
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
@@ -26,30 +30,10 @@ class BIM_PT_gis(Panel):
|
||||
def draw_editable_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Map Conversion", icon="GRID")
|
||||
row.label(text="Projected CRS", icon="WORLD")
|
||||
row.operator("bim.edit_georeferencing", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_georeferencing", icon="X", text="")
|
||||
|
||||
for attribute in props.map_conversion:
|
||||
if attribute.name == "XAxisAbscissa" and hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.get_north_offset", text="Set IFC North")
|
||||
row.operator("bim.set_north_offset", text="Set Blender North")
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "integer":
|
||||
row.prop(attribute, "int_value", text=attribute.name)
|
||||
elif attribute.data_type == "float":
|
||||
row.prop(attribute, "float_value", text=attribute.name)
|
||||
elif attribute.data_type == "boolean":
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Projected CRS", icon="WORLD")
|
||||
|
||||
for attribute in props.projected_crs:
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
@@ -70,10 +54,43 @@ class BIM_PT_gis(Panel):
|
||||
row.prop(props, "map_unit_imperial", text="")
|
||||
row.prop(props, "is_map_unit_null", icon="RADIOBUT_OFF" if props.is_map_unit_null else "RADIOBUT_ON", text="")
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text="Map Conversion", icon="GRID")
|
||||
|
||||
for attribute in props.map_conversion:
|
||||
if attribute.name == "Scale" and hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.set_ifc_grid_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_grid_north", text="Set Blender North")
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "integer":
|
||||
row.prop(attribute, "int_value", text=attribute.name)
|
||||
elif attribute.data_type == "float":
|
||||
row.prop(attribute, "float_value", text=attribute.name)
|
||||
elif attribute.data_type == "boolean":
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text="True North", icon="LIGHT_SUN")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "has_true_north")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "true_north_abscissa")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "true_north_ordinate")
|
||||
if hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.set_ifc_true_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_true_north", text="Set Blender North")
|
||||
|
||||
def draw_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
if not Data.map_conversion and IfcStore.get_file().schema != "IFC2X3":
|
||||
if not Data.projected_crs and IfcStore.get_file().schema != "IFC2X3":
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Not Georeferenced")
|
||||
row.operator("bim.add_georeferencing", icon="ADD", text="")
|
||||
@@ -100,26 +117,26 @@ class BIM_PT_gis(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="XAxisOrdinate")
|
||||
row.label(text=props.blender_x_axis_ordinate)
|
||||
row.label(text="Derived Grid North")
|
||||
row.label(
|
||||
text=str(
|
||||
round(
|
||||
ifcopenshell.util.geolocation.xaxis2angle(
|
||||
float(props.blender_x_axis_abscissa), float(props.blender_x_axis_ordinate)
|
||||
),
|
||||
3,
|
||||
)
|
||||
)
|
||||
)
|
||||
elif IfcStore.get_file().schema == "IFC2X3":
|
||||
row = self.layout.row()
|
||||
row.label(text="Not Georeferenced")
|
||||
|
||||
if Data.map_conversion:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Map Conversion", icon="GRID")
|
||||
row.operator("bim.enable_editing_georeferencing", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.remove_georeferencing", icon="X", text="")
|
||||
|
||||
for key, value in Data.map_conversion.items():
|
||||
if key == "id" or key == "type" or key == "SourceCRS" or key == "TargetCRS" or not value:
|
||||
continue
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=key)
|
||||
row.label(text=str(value))
|
||||
|
||||
if Data.projected_crs:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Projected CRS", icon="WORLD")
|
||||
row.operator("bim.enable_editing_georeferencing", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.remove_georeferencing", icon="X", text="")
|
||||
|
||||
for key, value in Data.projected_crs.items():
|
||||
if key == "id" or key == "type" or not value:
|
||||
@@ -132,6 +149,40 @@ class BIM_PT_gis(Panel):
|
||||
row.label(text=key)
|
||||
row.label(text=str(value))
|
||||
|
||||
if Data.map_conversion:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Map Conversion", icon="GRID")
|
||||
|
||||
for key, value in Data.map_conversion.items():
|
||||
if key == "id" or key == "type" or key == "SourceCRS" or key == "TargetCRS" or value is None:
|
||||
continue
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=key)
|
||||
row.label(text=str(value))
|
||||
if key == "XAxisOrdinate":
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Derived Angle")
|
||||
row.label(
|
||||
text=str(
|
||||
round(
|
||||
ifcopenshell.util.geolocation.xaxis2angle(
|
||||
Data.map_conversion["XAxisAbscissa"], Data.map_conversion["XAxisOrdinate"]
|
||||
),
|
||||
3,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if Data.true_north:
|
||||
row = self.layout.row()
|
||||
row.label(text="True North", icon="LIGHT_SUN")
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Vector")
|
||||
row.label(text=str(Data.true_north[0:2])[1:-1])
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Derived Angle")
|
||||
row.label(text=str(round(ifcopenshell.util.geolocation.yaxis2angle(*Data.true_north[0:2]), 3)))
|
||||
|
||||
|
||||
class BIM_PT_gis_utilities(Panel):
|
||||
bl_idname = "BIM_PT_gis_utilities"
|
||||
|
||||
@@ -47,7 +47,7 @@ class EnableEditingLayer(bpy.types.Operator):
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcPresentationLayerAssignment").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
if data_type == "entity" or data_type == "select":
|
||||
continue
|
||||
new = props.layer_attributes.add()
|
||||
new.name = attribute.name()
|
||||
|
||||
@@ -8,6 +8,9 @@ classes = (
|
||||
operator.UnassignMaterial,
|
||||
operator.AddConstituent,
|
||||
operator.RemoveConstituent,
|
||||
operator.AddProfile,
|
||||
operator.RemoveProfile,
|
||||
operator.AssignParameterizedProfile,
|
||||
operator.AddLayer,
|
||||
operator.RemoveLayer,
|
||||
operator.ReorderMaterialSetItem,
|
||||
|
||||
@@ -1,8 +1,36 @@
|
||||
import bpy
|
||||
import json
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.attribute
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.material.data import Data
|
||||
from ifcopenshell.api.profile.data import Data as ProfileData
|
||||
|
||||
|
||||
class AssignParameterizedProfile(bpy.types.Operator):
|
||||
bl_idname = "bim.assign_parameterized_profile"
|
||||
bl_label = "Assign Parameterized Profile"
|
||||
ifc_class: bpy.props.StringProperty()
|
||||
material_profile: bpy.props.IntProperty()
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
profile = ifcopenshell.api.run(
|
||||
"profile.add_parameterized_profile",
|
||||
self.file,
|
||||
**{"ifc_class": self.ifc_class},
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"material.assign_profile",
|
||||
self.file,
|
||||
**{"material_profile": self.file.by_id(self.material_profile), "profile": profile}
|
||||
)
|
||||
Data.load_profiles()
|
||||
ProfileData.load(self.file)
|
||||
bpy.ops.bim.enable_editing_material_set_item(obj=obj.name, material_set_item=self.material_profile)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddMaterial(bpy.types.Operator):
|
||||
@@ -115,6 +143,43 @@ class RemoveConstituent(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddProfile(bpy.types.Operator):
|
||||
bl_idname = "bim.add_profile"
|
||||
bl_label = "Add Profile"
|
||||
obj: bpy.props.StringProperty()
|
||||
profile_set: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"material.add_profile",
|
||||
self.file,
|
||||
**{
|
||||
"profile_set": self.file.by_id(self.profile_set),
|
||||
"material": self.file.by_id(int(obj.BIMObjectMaterialProperties.material)),
|
||||
},
|
||||
)
|
||||
Data.load_profiles()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveProfile(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_profile"
|
||||
bl_label = "Remove Profile"
|
||||
obj: bpy.props.StringProperty()
|
||||
profile: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"material.remove_profile", self.file, **{"profile": self.file.by_id(self.profile)}
|
||||
)
|
||||
Data.load_profiles()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddLayer(bpy.types.Operator):
|
||||
bl_idname = "bim.add_layer"
|
||||
bl_label = "Add Layer"
|
||||
@@ -333,8 +398,8 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||
props = obj.BIMObjectMaterialProperties
|
||||
props.active_material_set_item_id = self.material_set_item
|
||||
self.props = obj.BIMObjectMaterialProperties
|
||||
self.props.active_material_set_item_id = self.material_set_item
|
||||
product_data = Data.products[obj.BIMObjectProperties.ifc_definition_id]
|
||||
material_set_item = self.file.by_id(self.material_set_item)
|
||||
|
||||
@@ -347,17 +412,24 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
|
||||
else:
|
||||
material_set_item_data = {}
|
||||
|
||||
props.material_set_item_material = str(material_set_item_data["Material"])
|
||||
self.props.material_set_item_material = str(material_set_item_data["Material"])
|
||||
|
||||
while len(props.material_set_item_attributes) > 0:
|
||||
props.material_set_item_attributes.remove(0)
|
||||
self.load_set_item_attributes(material_set_item, material_set_item_data)
|
||||
if material_set_item.is_a("IfcMaterialProfile"):
|
||||
self.load_profile_attributes(material_set_item, material_set_item_data)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
def load_set_item_attributes(self, material_set_item, material_set_item_data):
|
||||
while len(self.props.material_set_item_attributes) > 0:
|
||||
self.props.material_set_item_attributes.remove(0)
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name(material_set_item.is_a()).all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
if attribute.name() in material_set_item_data:
|
||||
new = props.material_set_item_attributes.add()
|
||||
new = self.props.material_set_item_attributes.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = material_set_item_data[attribute.name()] is None
|
||||
new.data_type = data_type
|
||||
@@ -369,7 +441,45 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
|
||||
new.int_value = 0 if new.is_null else material_set_item_data[attribute.name()]
|
||||
elif data_type == "boolean":
|
||||
new.bool_value = False if new.is_null else material_set_item_data[attribute.name()]
|
||||
return {"FINISHED"}
|
||||
|
||||
def load_profile_attributes(self, material_set_item, material_set_item_data):
|
||||
while len(self.props.material_set_item_profile_attributes) > 0:
|
||||
self.props.material_set_item_profile_attributes.remove(0)
|
||||
|
||||
if not material_set_item_data["Profile"]:
|
||||
return
|
||||
|
||||
profile = self.file.by_id(material_set_item_data["Profile"])
|
||||
profile_data = ProfileData.profiles[material_set_item_data["Profile"]]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name(profile.is_a()).all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
if attribute.name() in profile_data:
|
||||
new = self.props.material_set_item_profile_attributes.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = profile_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 profile_data[attribute.name()]
|
||||
elif data_type == "float":
|
||||
new.float_value = 0.0 if new.is_null else profile_data[attribute.name()]
|
||||
elif data_type == "integer":
|
||||
new.int_value = 0 if new.is_null else profile_data[attribute.name()]
|
||||
elif data_type == "boolean":
|
||||
new.bool_value = False if new.is_null else profile_data[attribute.name()]
|
||||
elif data_type == "enum":
|
||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
||||
if profile_data[attribute.name()]:
|
||||
new.enum_value = profile_data[attribute.name()]
|
||||
|
||||
# Force null to be false if the attribute is mandatory because when we first assign a profile, all of
|
||||
# its fields are null (which is illegal).
|
||||
# TODO: find a better solution.
|
||||
if not new.is_optional:
|
||||
new.is_null = False
|
||||
|
||||
|
||||
class DisableEditingMaterialSetItem(bpy.types.Operator):
|
||||
@@ -431,16 +541,31 @@ class EditMaterialSetItem(bpy.types.Operator):
|
||||
)
|
||||
Data.load_layers()
|
||||
elif product_data["type"] == "IfcMaterialProfileSet":
|
||||
profile_attributes = {}
|
||||
for attribute in props.material_set_item_profile_attributes:
|
||||
if attribute.data_type == "string":
|
||||
value = attribute.string_value
|
||||
elif attribute.data_type == "float":
|
||||
value = attribute.float_value
|
||||
elif attribute.data_type == "integer":
|
||||
value = attribute.int_value
|
||||
elif attribute.data_type == "boolean":
|
||||
value = attribute.bool_value
|
||||
elif attribute.data_type == "enum":
|
||||
value = attribute.enum_value
|
||||
profile_attributes[attribute.name] = None if attribute.is_null else value
|
||||
ifcopenshell.api.run(
|
||||
"material.edit_profile",
|
||||
self.file,
|
||||
**{
|
||||
"profile": self.file.by_id(self.material_set_item),
|
||||
"attributes": attributes,
|
||||
"profile_attributes": profile_attributes,
|
||||
"material": self.file.by_id(int(obj.BIMObjectMaterialProperties.material_set_item_material)),
|
||||
},
|
||||
)
|
||||
Data.load_profiles()
|
||||
ProfileData.load(self.file)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
import blenderbim.bim.schema # refactor
|
||||
import blenderbim.bim.schema # refactor
|
||||
from ifcopenshell.api.material.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
@@ -17,6 +17,29 @@ from bpy.props import (
|
||||
|
||||
materials_enum = []
|
||||
materialtypes_enum = []
|
||||
profileclasses_enum = []
|
||||
parameterizedprofileclasses_enum = []
|
||||
|
||||
|
||||
def getProfileClasses(self, context):
|
||||
global profileclasses_enum
|
||||
if len(profileclasses_enum) == 0 and IfcStore.get_schema():
|
||||
profileclasses_enum.clear()
|
||||
profileclasses_enum = [
|
||||
(t.name(), t.name(), "") for t in IfcStore.get_schema().declaration_by_name("IfcProfileDef").subtypes()
|
||||
]
|
||||
return profileclasses_enum
|
||||
|
||||
|
||||
def getParameterizedProfileClasses(self, context):
|
||||
global parameterizedprofileclasses_enum
|
||||
if len(parameterizedprofileclasses_enum) == 0 and IfcStore.get_schema():
|
||||
parameterizedprofileclasses_enum.clear()
|
||||
parameterizedprofileclasses_enum = [
|
||||
(t.name(), t.name(), "")
|
||||
for t in IfcStore.get_schema().declaration_by_name("IfcParameterizedProfileDef").subtypes()
|
||||
]
|
||||
return parameterizedprofileclasses_enum
|
||||
|
||||
|
||||
def getMaterials(self, context):
|
||||
@@ -52,4 +75,9 @@ class BIMObjectMaterialProperties(PropertyGroup):
|
||||
material_set_attributes: CollectionProperty(name="Material Set Attributes", type=Attribute)
|
||||
active_material_set_item_id: IntProperty(name="Active Material Set ID")
|
||||
material_set_item_attributes: CollectionProperty(name="Material Set Item Attributes", type=Attribute)
|
||||
material_set_item_profile_attributes: CollectionProperty(name="Material Set Item Profile Attributes", type=Attribute)
|
||||
material_set_item_material: EnumProperty(items=getMaterials, name="Material")
|
||||
profile_classes: EnumProperty(items=getProfileClasses, name="Profile Classes")
|
||||
parameterized_profile_classes: EnumProperty(
|
||||
items=getParameterizedProfileClasses, name="Parameterized Profile Classes"
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from bpy.types import Panel
|
||||
from ifcopenshell.api.material.data import Data
|
||||
from ifcopenshell.api.profile.data import Data as ProfileData
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
@@ -46,6 +47,8 @@ class BIM_PT_object_material(Panel):
|
||||
Data.load(IfcStore.get_file())
|
||||
if self.oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), self.oprops.ifc_definition_id)
|
||||
if not ProfileData.is_loaded:
|
||||
ProfileData.load(self.file)
|
||||
self.product_data = Data.products[self.oprops.ifc_definition_id]
|
||||
|
||||
if not Data.materials:
|
||||
@@ -172,6 +175,39 @@ class BIM_PT_object_material(Panel):
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
if self.set_item_name == "profile":
|
||||
self.draw_assign_profile_ui(box, item)
|
||||
self.draw_editable_profile_ui(box, item)
|
||||
|
||||
def draw_assign_profile_ui(self, layout, item):
|
||||
row = layout.row(align=True)
|
||||
row.prop(self.props, "profile_classes", text="")
|
||||
if self.props.profile_classes == "IfcParameterizedProfileDef":
|
||||
row.prop(self.props, "parameterized_profile_classes", text="")
|
||||
op = row.operator("bim.assign_parameterized_profile", icon="GREASEPENCIL" if item["Profile"] else "ADD", text="")
|
||||
op.ifc_class = self.props.parameterized_profile_classes
|
||||
op.material_profile = item["id"]
|
||||
else:
|
||||
# TODO: support non parametric profiles by showing a list of named profiles to select from, or an
|
||||
# eyedropper to pick profile geometry from the scene
|
||||
row.operator("bim.disable_editing_material_set_item", icon="X", text="")
|
||||
|
||||
def draw_editable_profile_ui(self, layout, item):
|
||||
for attribute in self.props.material_set_item_profile_attributes:
|
||||
row = layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "integer":
|
||||
row.prop(attribute, "int_value", text=attribute.name)
|
||||
elif attribute.data_type == "float":
|
||||
row.prop(attribute, "float_value", text=attribute.name)
|
||||
elif attribute.data_type == "boolean":
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
def draw_read_only_set_item_ui(self, set_item_id, index, is_first=False, is_last=False):
|
||||
if self.product_data["type"] == "IfcMaterialList":
|
||||
item = Data.materials[set_item_id]
|
||||
|
||||
@@ -84,6 +84,8 @@ class PieAddOpening(bpy.types.Operator):
|
||||
for obj in context.selected_objects:
|
||||
if "IfcOpeningElement" in obj.name or not obj.BIMObjectProperties.ifc_definition_id:
|
||||
opening_name = obj.name
|
||||
elif len(obj.children) == 1 and not obj.children[0].BIMObjectProperties.ifc_definition_id:
|
||||
opening_name = obj.children[0].name
|
||||
else:
|
||||
opj_name = obj.name
|
||||
bpy.ops.bim.add_opening(obj=opj_name, opening=opening_name)
|
||||
|
||||
@@ -3,6 +3,7 @@ from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.CreateProject,
|
||||
operator.CreateProjectLibrary,
|
||||
operator.ValidateIfcFile,
|
||||
prop.BIMProjectProperties,
|
||||
ui.BIM_PT_project,
|
||||
|
||||
@@ -53,6 +53,30 @@ class CreateProject(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CreateProjectLibrary(bpy.types.Operator):
|
||||
bl_idname = "bim.create_project_library"
|
||||
bl_label = "Create Project Library"
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
if self.file:
|
||||
return {"FINISHED"}
|
||||
|
||||
IfcStore.file = ifcopenshell.api.run(
|
||||
"project.create_file", **{"version": bpy.context.scene.BIMProperties.export_schema}
|
||||
)
|
||||
self.file = IfcStore.get_file()
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
bpy.ops.bim.add_person()
|
||||
bpy.ops.bim.add_organisation()
|
||||
|
||||
project_library = bpy.data.objects.new("My Project Library", None)
|
||||
bpy.ops.bim.assign_class(obj=project_library.name, ifc_class="IfcProjectLibrary")
|
||||
bpy.ops.bim.assign_unit()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ValidateIfcFile(bpy.types.Operator):
|
||||
bl_idname = "bim.validate_ifc_file"
|
||||
bl_label = "Validate IFC File"
|
||||
|
||||
@@ -63,3 +63,6 @@ class BIM_PT_project(Panel):
|
||||
row.prop(props, "volume_unit", text="Volume Unit")
|
||||
row = self.layout.row()
|
||||
row.operator("bim.create_project")
|
||||
if props.export_schema != "IFC2X3":
|
||||
row = self.layout.row()
|
||||
row.operator("bim.create_project_library")
|
||||
|
||||
@@ -2,21 +2,55 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.LoadWorkPlans,
|
||||
operator.DisableWorkPlanEditingUI,
|
||||
operator.AddWorkPlan,
|
||||
operator.EditWorkPlan,
|
||||
operator.RemoveWorkPlan,
|
||||
operator.EnableEditingWorkPlan,
|
||||
operator.DisableEditingWorkPlan,
|
||||
operator.LoadWorkSchedules,
|
||||
operator.DisableWorkScheduleEditingUI,
|
||||
operator.AddWorkSchedule,
|
||||
operator.EditWorkSchedule,
|
||||
operator.RemoveWorkSchedule,
|
||||
operator.EnableEditingWorkSchedule,
|
||||
operator.DisableEditingWorkSchedule,
|
||||
operator.LoadTasks,
|
||||
operator.DisableTaskEditingUI,
|
||||
operator.AddWorkPlan,
|
||||
operator.RemoveWorkPlan,
|
||||
operator.LoadWorkCalendars,
|
||||
operator.DisableWorkCalendarEditingUI,
|
||||
operator.AddWorkCalendar,
|
||||
operator.EditWorkCalendar,
|
||||
operator.RemoveWorkCalendar,
|
||||
operator.EnableEditingWorkCalendar,
|
||||
operator.DisableEditingWorkCalendar,
|
||||
prop.WorkPlan,
|
||||
prop.BIMWorkPlanProperties,
|
||||
prop.WorkSchedule,
|
||||
prop.BIMWorkScheduleProperties,
|
||||
prop.WorkCalendar,
|
||||
prop.BIMWorkCalendarProperties,
|
||||
prop.Task,
|
||||
prop.BIMTaskProperties,
|
||||
ui.BIM_PT_work_plans,
|
||||
ui.BIM_UL_work_plans,
|
||||
ui.BIM_PT_work_schedules,
|
||||
ui.BIM_UL_work_schedules,
|
||||
ui.BIM_PT_work_calendars,
|
||||
ui.BIM_UL_work_calendars,
|
||||
ui.BIM_PT_tasks,
|
||||
ui.BIM_UL_tasks,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BIMTaskProperties = bpy.props.PointerProperty(type=prop.BIMTaskProperties)
|
||||
|
||||
bpy.types.Scene.BIMWorkPlanProperties = bpy.props.PointerProperty(type=prop.BIMWorkPlanProperties)
|
||||
bpy.types.Scene.BIMWorkScheduleProperties = bpy.props.PointerProperty(type=prop.BIMWorkScheduleProperties)
|
||||
bpy.types.Scene.BIMWorkCalendarProperties = bpy.props.PointerProperty(type=prop.BIMWorkCalendarProperties)
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.BIMTaskProperties
|
||||
del bpy.types.Scene.BIMWorkPlanProperties
|
||||
del bpy.types.Scene.BIMWorkScheduleProperties
|
||||
del bpy.types.Scene.BIMWorkCalendarProperties
|
||||
|
||||
@@ -1,9 +1,36 @@
|
||||
import bpy
|
||||
import json
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.sequence.data import Data
|
||||
|
||||
|
||||
class LoadWorkPlans(bpy.types.Operator):
|
||||
bl_idname = "bim.load_work_plans"
|
||||
bl_label = "Load Work Plans"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkPlanProperties
|
||||
while len(props.work_plans) > 0:
|
||||
props.work_plans.remove(0)
|
||||
for ifc_definition_id, work_plan in Data.work_plans.items():
|
||||
new = props.work_plans.add()
|
||||
new.ifc_definition_id = ifc_definition_id
|
||||
new.name = work_plan["Name"] or "Unnamed"
|
||||
props.is_editing = True
|
||||
bpy.ops.bim.disable_editing_work_plan()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableWorkPlanEditingUI(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_work_plan_editing_ui"
|
||||
bl_label = "Disable WorkPlan Editing UI"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMWorkPlanProperties.is_editing = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddWorkPlan(bpy.types.Operator):
|
||||
bl_idname = "bim.add_work_plan"
|
||||
bl_label = "Add Work Plan"
|
||||
@@ -11,6 +38,33 @@ class AddWorkPlan(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
ifcopenshell.api.run("sequence.add_work_plan", IfcStore.get_file())
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_work_plans()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditWorkPlan(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_work_plan"
|
||||
bl_label = "Edit Work Plan"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkPlanProperties
|
||||
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()
|
||||
ifcopenshell.api.run(
|
||||
"sequence.edit_work_plan",
|
||||
self.file,
|
||||
**{"work_plan": self.file.by_id(props.active_work_plan_id), "attributes": attributes}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_work_plans()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -20,10 +74,290 @@ class RemoveWorkPlan(bpy.types.Operator):
|
||||
work_plan: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run("sequence.remove_work_plan", self.file, **{"work_plan": self.file.by_id(self.work_plan)})
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_work_plans()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingWorkPlan(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_work_plan"
|
||||
bl_label = "Enable Editing Work Plan"
|
||||
work_plan: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkPlanProperties
|
||||
while len(props.work_plan_attributes) > 0:
|
||||
props.work_plan_attributes.remove(0)
|
||||
|
||||
data = Data.work_plans[self.work_plan]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkPlan").all_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
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingWorkPlan(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_work_plan"
|
||||
bl_label = "Disable Editing Work Plan"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMWorkPlanProperties.active_work_plan_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class LoadWorkSchedules(bpy.types.Operator):
|
||||
bl_idname = "bim.load_work_schedules"
|
||||
bl_label = "Load Work Schedules"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
while len(props.work_schedules) > 0:
|
||||
props.work_schedules.remove(0)
|
||||
for ifc_definition_id, work_schedule in Data.work_schedules.items():
|
||||
new = props.work_schedules.add()
|
||||
new.ifc_definition_id = ifc_definition_id
|
||||
new.name = work_schedule["Name"] or "Unnamed"
|
||||
props.is_editing = True
|
||||
bpy.ops.bim.disable_editing_work_schedule()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableWorkScheduleEditingUI(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_work_schedule_editing_ui"
|
||||
bl_label = "Disable WorkSchedule Editing UI"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMWorkScheduleProperties.is_editing = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddWorkSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.add_work_schedule"
|
||||
bl_label = "Add Work Schedule"
|
||||
|
||||
def execute(self, context):
|
||||
ifcopenshell.api.run("sequence.add_work_schedule", IfcStore.get_file())
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_work_schedules()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditWorkSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_work_schedule"
|
||||
bl_label = "Edit Work Schedule"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
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()
|
||||
ifcopenshell.api.run(
|
||||
"sequence.remove_work_plan", IfcStore.get_file(), work_plan=IfcStore.get_file().by_id(self.work_plan)
|
||||
"sequence.edit_work_schedule",
|
||||
self.file,
|
||||
**{"work_schedule": self.file.by_id(props.active_work_schedule_id), "attributes": attributes}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_work_schedules()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveWorkSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_work_schedule"
|
||||
bl_label = "Remove Work Schedule"
|
||||
work_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"sequence.remove_work_schedule", self.file, **{"work_schedule": self.file.by_id(self.work_schedule)}
|
||||
)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_work_schedules()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingWorkSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_work_schedule"
|
||||
bl_label = "Enable Editing Work Schedule"
|
||||
work_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
while len(props.work_schedule_attributes) > 0:
|
||||
props.work_schedule_attributes.remove(0)
|
||||
|
||||
data = Data.work_schedules[self.work_schedule]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkSchedule").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
new = props.work_schedule_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_schedule_id = self.work_schedule
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingWorkSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_work_schedule"
|
||||
bl_label = "Disable Editing Work Schedule"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMWorkScheduleProperties.active_work_schedule_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class LoadWorkCalendars(bpy.types.Operator):
|
||||
bl_idname = "bim.load_work_calendars"
|
||||
bl_label = "Load Work Calendars"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkCalendarProperties
|
||||
while len(props.work_calendars) > 0:
|
||||
props.work_calendars.remove(0)
|
||||
for ifc_definition_id, work_calendar in Data.work_calendars.items():
|
||||
new = props.work_calendars.add()
|
||||
new.ifc_definition_id = ifc_definition_id
|
||||
new.name = work_calendar["Name"] or "Unnamed"
|
||||
props.is_editing = True
|
||||
bpy.ops.bim.disable_editing_work_calendar()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableWorkCalendarEditingUI(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_work_calendar_editing_ui"
|
||||
bl_label = "Disable WorkCalendar Editing UI"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMWorkCalendarProperties.is_editing = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddWorkCalendar(bpy.types.Operator):
|
||||
bl_idname = "bim.add_work_calendar"
|
||||
bl_label = "Add Work Calendar"
|
||||
|
||||
def execute(self, context):
|
||||
ifcopenshell.api.run("sequence.add_work_calendar", IfcStore.get_file())
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_work_calendars()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditWorkCalendar(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_work_calendar"
|
||||
bl_label = "Edit Work Calendar"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkCalendarProperties
|
||||
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()
|
||||
ifcopenshell.api.run(
|
||||
"sequence.edit_work_calendar",
|
||||
self.file,
|
||||
**{"work_calendar": self.file.by_id(props.active_work_calendar_id), "attributes": attributes}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_work_calendars()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveWorkCalendar(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_work_calendar"
|
||||
bl_label = "Remove Work Plan"
|
||||
work_calendar: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"sequence.remove_work_calendar", self.file, **{"work_calendar": self.file.by_id(self.work_calendar)}
|
||||
)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_work_calendars()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingWorkCalendar(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_work_calendar"
|
||||
bl_label = "Enable Editing Work Plan"
|
||||
work_calendar: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMWorkCalendarProperties
|
||||
while len(props.work_calendar_attributes) > 0:
|
||||
props.work_calendar_attributes.remove(0)
|
||||
|
||||
data = Data.work_calendars[self.work_calendar]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkCalendar").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
new = 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()]
|
||||
props.active_work_calendar_id = self.work_calendar
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingWorkCalendar(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_work_calendar"
|
||||
bl_label = "Disable Editing Work Calendar"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMWorkCalendarProperties.active_work_calendar_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -23,3 +23,42 @@ class BIMTaskProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||
tasks: CollectionProperty(name="Tasks", type=Task)
|
||||
active_task_index: IntProperty(name="Active Task Index")
|
||||
|
||||
|
||||
class WorkPlan(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
|
||||
class BIMWorkPlanProperties(PropertyGroup):
|
||||
work_plan_attributes: CollectionProperty(name="Work Plan Attributes", type=Attribute)
|
||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||
work_plans: CollectionProperty(name="Work Plans", type=WorkPlan)
|
||||
active_work_plan_index: IntProperty(name="Active Work Plan Index")
|
||||
active_work_plan_id: IntProperty(name="Active Work Plan Id")
|
||||
|
||||
|
||||
class WorkSchedule(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
|
||||
class BIMWorkScheduleProperties(PropertyGroup):
|
||||
work_schedule_attributes: CollectionProperty(name="Work Schedule Attributes", type=Attribute)
|
||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||
work_schedules: CollectionProperty(name="Work Schedules", type=WorkSchedule)
|
||||
active_work_schedule_index: IntProperty(name="Active Work Schedules Index")
|
||||
active_work_schedule_id: IntProperty(name="Active Work Schedules Id")
|
||||
|
||||
|
||||
class WorkCalendar(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
|
||||
|
||||
class BIMWorkCalendarProperties(PropertyGroup):
|
||||
work_calendar_attributes: CollectionProperty(name="Work Calendar Attributes", type=Attribute)
|
||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||
work_calendars: CollectionProperty(name="Work Calendar", type=WorkCalendar)
|
||||
active_work_calendar_index: IntProperty(name="Active Work Calendar Index")
|
||||
active_work_calendar_id: IntProperty(name="Active Work Calendar Id")
|
||||
|
||||
@@ -18,15 +18,181 @@ class BIM_PT_work_plans(Panel):
|
||||
def draw(self, context):
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
self.props = context.scene.BIMWorkPlanProperties
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="{} Work Plans Found".format(len(Data.work_plans)), icon="TEXT")
|
||||
if self.props.is_editing:
|
||||
row.operator("bim.add_work_plan", text="", icon="ADD")
|
||||
row.operator("bim.disable_work_plan_editing_ui", text="", icon="CHECKMARK")
|
||||
else:
|
||||
row.operator("bim.load_work_plans", text="", icon="GREASEPENCIL")
|
||||
|
||||
row = self.layout.row()
|
||||
row.operator("bim.add_work_plan", icon="ADD")
|
||||
if self.props.is_editing:
|
||||
self.layout.template_list(
|
||||
"BIM_UL_work_plans",
|
||||
"",
|
||||
self.props,
|
||||
"work_plans",
|
||||
self.props,
|
||||
"active_work_plan_index",
|
||||
)
|
||||
|
||||
for work_plan_id, work_plan in Data.work_plans.items():
|
||||
if self.props.active_work_plan_id:
|
||||
self.draw_editable_ui(context)
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
for attribute in self.props.work_plan_attributes:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=work_plan["Name"] or "Unnamed", icon="TEXT")
|
||||
row.operator("bim.add_work_plan", text="", icon="GREASEPENCIL")
|
||||
row.operator("bim.remove_work_plan", text="", icon="X").work_plan = work_plan_id
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
|
||||
class BIM_UL_work_plans(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)
|
||||
if context.scene.BIMWorkPlanProperties.active_work_plan_id == item.ifc_definition_id:
|
||||
row.operator("bim.edit_work_plan", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_work_plan", text="", icon="X")
|
||||
elif context.scene.BIMWorkPlanProperties.active_work_plan_id:
|
||||
row.operator("bim.remove_work_plan", text="", icon="X").work_plan = item.ifc_definition_id
|
||||
else:
|
||||
op = row.operator("bim.enable_editing_work_plan", text="", icon="GREASEPENCIL")
|
||||
op.work_plan = item.ifc_definition_id
|
||||
row.operator("bim.remove_work_plan", text="", icon="X").work_plan = item.ifc_definition_id
|
||||
|
||||
|
||||
class BIM_PT_work_schedules(Panel):
|
||||
bl_label = "IFC Work Schedules"
|
||||
bl_idname = "BIM_PT_work_schedules"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return IfcStore.get_file()
|
||||
|
||||
def draw(self, context):
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
self.props = context.scene.BIMWorkScheduleProperties
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="{} Work Schedules Found".format(len(Data.work_schedules)), icon="TEXT")
|
||||
if self.props.is_editing:
|
||||
row.operator("bim.add_work_schedule", text="", icon="ADD")
|
||||
row.operator("bim.disable_work_schedule_editing_ui", text="", icon="CHECKMARK")
|
||||
else:
|
||||
row.operator("bim.load_work_schedules", text="", icon="GREASEPENCIL")
|
||||
|
||||
if self.props.is_editing:
|
||||
self.layout.template_list(
|
||||
"BIM_UL_work_schedules",
|
||||
"",
|
||||
self.props,
|
||||
"work_schedules",
|
||||
self.props,
|
||||
"active_work_schedule_index",
|
||||
)
|
||||
|
||||
if self.props.active_work_schedule_id:
|
||||
self.draw_editable_ui(context)
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
for attribute in self.props.work_schedule_attributes:
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
|
||||
class BIM_UL_work_schedules(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)
|
||||
if context.scene.BIMWorkScheduleProperties.active_work_schedule_id == item.ifc_definition_id:
|
||||
row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_work_schedule", text="", icon="X")
|
||||
elif context.scene.BIMWorkScheduleProperties.active_work_schedule_id:
|
||||
row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = item.ifc_definition_id
|
||||
else:
|
||||
op = row.operator("bim.enable_editing_work_schedule", text="", icon="GREASEPENCIL")
|
||||
op.work_schedule = item.ifc_definition_id
|
||||
row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = item.ifc_definition_id
|
||||
|
||||
|
||||
class BIM_PT_work_calendars(Panel):
|
||||
bl_label = "IFC Work Calendars"
|
||||
bl_idname = "BIM_PT_work_calendars"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return IfcStore.get_file()
|
||||
|
||||
def draw(self, context):
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
self.props = context.scene.BIMWorkCalendarProperties
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="{} Work Calendar Found".format(len(Data.work_calendars)), icon="TEXT")
|
||||
if self.props.is_editing:
|
||||
row.operator("bim.add_work_calendar", text="", icon="ADD")
|
||||
row.operator("bim.disable_work_calendar_editing_ui", text="", icon="CHECKMARK")
|
||||
else:
|
||||
row.operator("bim.load_work_calendars", text="", icon="GREASEPENCIL")
|
||||
|
||||
if self.props.is_editing:
|
||||
self.layout.template_list(
|
||||
"BIM_UL_work_calendars",
|
||||
"",
|
||||
self.props,
|
||||
"work_calendars",
|
||||
self.props,
|
||||
"active_work_calendar_index",
|
||||
)
|
||||
|
||||
if self.props.active_work_calendar_id:
|
||||
self.draw_editable_ui(context)
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
for attribute in self.props.work_calendar_attributes:
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
|
||||
class BIM_UL_work_calendars(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)
|
||||
if context.scene.BIMWorkCalendarProperties.active_work_calendar_id == item.ifc_definition_id:
|
||||
row.operator("bim.edit_work_calendar", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_work_calendar", text="", icon="X")
|
||||
elif context.scene.BIMWorkCalendarProperties.active_work_calendar_id:
|
||||
row.operator("bim.remove_work_calendar", text="", icon="X").work_calendar = item.ifc_definition_id
|
||||
else:
|
||||
op = row.operator("bim.enable_editing_work_calendar", text="", icon="GREASEPENCIL")
|
||||
op.work_calendar = item.ifc_definition_id
|
||||
row.operator("bim.remove_work_calendar", text="", icon="X").work_calendar = item.ifc_definition_id
|
||||
|
||||
|
||||
class BIM_PT_tasks(Panel):
|
||||
|
||||
@@ -27,6 +27,8 @@ class BIM_PT_voids(Panel):
|
||||
for obj in context.selected_objects:
|
||||
if "IfcOpeningElement" in obj.name or not obj.BIMObjectProperties.ifc_definition_id:
|
||||
op.opening = obj.name
|
||||
elif len(obj.children) == 1 and not obj.children[0].BIMObjectProperties.ifc_definition_id:
|
||||
op.opening = obj.children[0].name
|
||||
else:
|
||||
op.obj = obj.name
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import ifcopenshell
|
||||
import ezdxf
|
||||
|
||||
class Dxf2Ifc:
|
||||
def execute(self):
|
||||
self.create_ifc_file()
|
||||
@@ -14,7 +17,7 @@ class Dxf2Ifc:
|
||||
[
|
||||
self.file.createIfcFaceOuterBound(
|
||||
self.file.createIfcPolyLoop(
|
||||
[self.file.createIfcCartesianPoint((v.dxf.location)) for v in face[0:3]]
|
||||
[self.file.createIfcCartesianPoint((face[index].dxf.location)) for index in range(len(face) -1)]
|
||||
),
|
||||
True,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user