diff --git a/src/blenderbim/blenderbim/bim/export_ifc.py b/src/blenderbim/blenderbim/bim/export_ifc.py index 5290b1215f..c0b52e7ce6 100644 --- a/src/blenderbim/blenderbim/bim/export_ifc.py +++ b/src/blenderbim/blenderbim/bim/export_ifc.py @@ -46,9 +46,6 @@ class IfcExporter: jsonData = ifcjson.IFC2JSON5a(self.file, self.ifc_export_settings.json_compact).spf2Json() with open(self.ifc_export_settings.output_file, "w") as outfile: json.dump(jsonData, outfile, indent=None if self.ifc_export_settings.json_compact else 4) - if bpy.context.scene.BIMProjectProperties.is_authoring: - if bpy.data.filepath: - bpy.ops.wm.save_mainfile() def set_header(self): # TODO: add all metadata, pending bug #747 diff --git a/src/blenderbim/blenderbim/bim/handler.py b/src/blenderbim/blenderbim/bim/handler.py index 7d7d5b6bfc..2626d5335d 100644 --- a/src/blenderbim/blenderbim/bim/handler.py +++ b/src/blenderbim/blenderbim/bim/handler.py @@ -9,17 +9,18 @@ from ifcopenshell.api.attribute.data import Data as AttributeData def mode_callback(obj, data): - if ( - obj.mode != "OBJECT" - or not obj.data - or not isinstance(obj.data, bpy.types.Mesh) - or not obj.data.BIMMeshProperties.ifc_definition_id - or not bpy.context.scene.BIMProjectProperties.is_authoring - ): - return - representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id) - if representation.RepresentationType == "Tessellation" or representation.RepresentationType == "Brep": - IfcStore.edited_objs.add(obj.name) + for obj in bpy.context.selected_objects: + if ( + obj.mode != "OBJECT" + or not obj.data + or not isinstance(obj.data, bpy.types.Mesh) + or not obj.data.BIMMeshProperties.ifc_definition_id + or not bpy.context.scene.BIMProjectProperties.is_authoring + ): + return + representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id) + if representation.RepresentationType == "Tessellation" or representation.RepresentationType == "Brep": + IfcStore.edited_objs.add(obj.name) def name_callback(obj, data): @@ -81,9 +82,7 @@ def loadIfcStore(scene): @persistent def ensureIfcExported(scene): if IfcStore.get_file() and not bpy.context.scene.BIMProperties.ifc_file: - # The invocation pops up a file select window. - # This is non-blocking, therefore the Blend file is saved before we export. - bpy.ops.export_ifc.bim("INVOKE_DEFAULT", should_force_resave=True) + bpy.ops.export_ifc.bim("INVOKE_DEFAULT") @persistent diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index eb7a298c4f..f98f0f5082 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -780,9 +780,6 @@ class IfcImporter: if element is None: return - if not self.ifc_import_settings.should_import_spaces and element.is_a("IfcSpace"): - return - self.ifc_import_settings.logger.info("Creating object %s", element) if mesh: @@ -1084,8 +1081,6 @@ class IfcImporter: def add_related_objects(self, parent, related_objects): for element in related_objects: - if element.is_a("IfcSpace"): - continue global_id = element.GlobalId collection = bpy.data.collections.new(self.get_name(element)) self.spatial_structure_elements[global_id] = {"blender": collection} @@ -1129,8 +1124,6 @@ class IfcImporter: container = element.ContainedInStructure[0].RelatingStructure elif hasattr(element, "Decomposes") and element.Decomposes: container = element.Decomposes[0].RelatingObject - if container.is_a("IfcSpace"): - return self.get_aggregate_container(container) return container def create_openings_collection(self): @@ -1179,9 +1172,7 @@ class IfcImporter: and element.ContainedInStructure[0].RelatingStructure ): container = element.ContainedInStructure[0].RelatingStructure - if container.is_a("IfcSpace"): - return self.place_object_in_spatial_tree(container, obj) - elif element.is_a("IfcGrid"): + if element.is_a("IfcGrid"): grid_collection = bpy.data.collections.get(obj.name) if grid_collection: # Just in case we ran into invalid grids from Revit self.spatial_structure_elements[container.GlobalId]["blender"].children.link(grid_collection) @@ -1193,22 +1184,15 @@ class IfcImporter: if element.Decomposes[0].RelatingObject.is_a("IfcProject"): collection = self.project["blender"] elif element.Decomposes[0].RelatingObject.is_a("IfcSpatialStructureElement"): - if element.is_a("IfcSpatialStructureElement") and not element.is_a("IfcSpace"): + if element.is_a("IfcSpatialStructureElement"): global_id = element.GlobalId - else: - global_id = element.Decomposes[0].RelatingObject.GlobalId if global_id in self.spatial_structure_elements: if ( element.is_a("IfcSpatialStructureElement") - and not element.is_a("IfcSpace") and "blender_obj" in self.spatial_structure_elements[global_id] ): bpy.data.objects.remove(self.spatial_structure_elements[global_id]["blender_obj"]) collection = self.spatial_structure_elements[global_id]["blender"] - # This may occur if we are nesting an IfcSpace (which is special - # since it does not have a collection within an IfcSpace - if not collection: - return self.place_object_in_spatial_tree(element.Decomposes[0].RelatingObject, obj) else: collection = self.aggregates[element.Decomposes[0].RelatingObject.GlobalId]["blender"] if collection: @@ -1432,7 +1416,6 @@ class IfcImportSettings: self.logger = None self.input_file = None self.diff_file = None - self.should_import_spaces = False self.should_auto_set_workarounds = True self.should_use_cpu_multiprocessing = True self.should_merge_by_class = False diff --git a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py index 5d366d5191..27a62fd4d2 100644 --- a/src/blenderbim/blenderbim/bim/module/aggregate/operator.py +++ b/src/blenderbim/blenderbim/bim/module/aggregate/operator.py @@ -39,7 +39,8 @@ class AssignObject(bpy.types.Operator): self.remove_collection(bpy.context.scene.collection, spatial_collection) for collection in bpy.data.collections: if collection == relating_collection: - collection.children.link(spatial_collection) + if not collection.children.get(spatial_collection.name): + collection.children.link(spatial_collection) continue self.remove_collection(collection, spatial_collection) else: diff --git a/src/blenderbim/blenderbim/bim/module/cost/__init__.py b/src/blenderbim/blenderbim/bim/module/cost/__init__.py index ce2d98dc85..7a8a31b1d3 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/cost/__init__.py @@ -8,8 +8,10 @@ classes = ( operator.EnableEditingCostSchedule, operator.DisableEditingCostSchedule, operator.AddCostItem, + operator.AddSummaryCostItem, operator.ExpandCostItem, operator.ContractCostItem, + operator.RemoveCostItem, prop.CostItem, prop.BIMCostProperties, ui.BIM_PT_cost_schedules, diff --git a/src/blenderbim/blenderbim/bim/module/cost/operator.py b/src/blenderbim/blenderbim/bim/module/cost/operator.py index afc937ea78..86e0cf03df 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/operator.py +++ b/src/blenderbim/blenderbim/bim/module/cost/operator.py @@ -120,24 +120,37 @@ class EditCostSchedule(bpy.types.Operator): return {"FINISHED"} -class AddCostItem(bpy.types.Operator): - bl_idname = "bim.add_cost_item" +class AddSummaryCostItem(bpy.types.Operator): + bl_idname = "bim.add_summary_cost_item" bl_label = "Add Cost Item" cost_schedule: bpy.props.IntProperty() def execute(self, context): props = context.scene.BIMCostProperties self.file = IfcStore.get_file() - if len(props.cost_items): - data = {"cost_item": self.file.by_id(props.cost_items[props.active_cost_item_index].ifc_definition_id)} - else: - data = {"cost_schedule": self.file.by_id(self.cost_schedule)} - ifcopenshell.api.run("cost.add_cost_item", self.file, **data) + ifcopenshell.api.run("cost.add_cost_item", self.file, **{ + "cost_schedule": self.file.by_id(self.cost_schedule) + }) Data.load(self.file) bpy.ops.bim.enable_editing_cost_schedule(cost_schedule = self.cost_schedule) return {"FINISHED"} +class AddCostItem(bpy.types.Operator): + bl_idname = "bim.add_cost_item" + bl_label = "Add Cost Item" + cost_item: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() + data = {"cost_item": self.file.by_id(self.cost_item)} + ifcopenshell.api.run("cost.add_cost_item", self.file, **data) + Data.load(self.file) + bpy.ops.bim.enable_editing_cost_schedule(cost_schedule = props.active_cost_schedule_id) + return {"FINISHED"} + + class ExpandCostItem(bpy.types.Operator): bl_idname = "bim.expand_cost_item" bl_label = "Expand Cost Item" @@ -145,9 +158,11 @@ class ExpandCostItem(bpy.types.Operator): def execute(self, context): props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() contracted_cost_items = json.loads(props.contracted_cost_items) contracted_cost_items.remove(self.cost_item) props.contracted_cost_items = json.dumps(contracted_cost_items) + Data.load(self.file) bpy.ops.bim.enable_editing_cost_schedule(cost_schedule = props.active_cost_schedule_id) return {"FINISHED"} @@ -159,8 +174,31 @@ class ContractCostItem(bpy.types.Operator): def execute(self, context): props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() contracted_cost_items = json.loads(props.contracted_cost_items) contracted_cost_items.append(self.cost_item) props.contracted_cost_items = json.dumps(contracted_cost_items) + Data.load(self.file) + bpy.ops.bim.enable_editing_cost_schedule(cost_schedule = props.active_cost_schedule_id) + return {"FINISHED"} + + +class RemoveCostItem(bpy.types.Operator): + bl_idname = "bim.remove_cost_item" + bl_label = "Remove Cost item" + cost_item: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMCostProperties + self.file = IfcStore.get_file() + ifcopenshell.api.run( + "cost.remove_cost_item", + self.file, + cost_item=IfcStore.get_file().by_id(self.cost_item), + ) + Data.load(self.file) + # contracted_cost_items = json.loads(props.contracted_cost_items) + # contracted_cost_items.remove(props.active_cost_item_index) + # props.contracted_cost_items = json.dumps(contracted_cost_items) bpy.ops.bim.enable_editing_cost_schedule(cost_schedule = props.active_cost_schedule_id) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/cost/ui.py b/src/blenderbim/blenderbim/bim/module/cost/ui.py index abfc20074b..7c9edc329e 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/ui.py +++ b/src/blenderbim/blenderbim/bim/module/cost/ui.py @@ -51,9 +51,8 @@ class BIM_PT_cost_schedules(Panel): 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="X Cost Items") - row.operator("bim.add_cost_item", text="", icon="ADD").cost_schedule = cost_schedule_id - + row.label(text="X Summary Cost Items") + row.operator("bim.add_summary_cost_item", text="", icon="ADD").cost_schedule = cost_schedule_id self.layout.template_list( "BIM_UL_cost_items", "", @@ -72,10 +71,12 @@ class BIM_UL_cost_items(UIList): row.label(text="", icon="BLANK1") if item.has_children: if item.is_expanded: - op = row.operator("bim.contract_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN") + row.operator("bim.contract_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN").cost_item = item.ifc_definition_id else: - op = row.operator("bim.expand_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT") - op.cost_item = item.ifc_definition_id + row.operator("bim.expand_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").cost_item = item.ifc_definition_id else: row.label(text="", icon="DOT") row.label(text=item.name) + row.operator("bim.add_cost_item", text="", icon="ADD").cost_item = item.ifc_definition_id + op = row.operator("bim.remove_cost_item", text="", icon="X") + op.cost_item = item.ifc_definition_id diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 19f86fa5d5..0047d012eb 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -104,18 +104,27 @@ class AddRepresentation(bpy.types.Operator): return {"FINISHED"} box_context_id = get_context_id("Model", "Box", "MODEL_VIEW") + old_box = ifcopenshell.util.element.get_representation(product, "Model", "Box", "MODEL_VIEW") if ( box_context_id and context_of_items.ContextType == "Model" and context_of_items.ContextIdentifier and context_of_items.ContextIdentifier == "Body" ): + if old_box: + bpy.ops.bim.remove_representation(representation_id=old_box.id(), obj=obj.name) representation_data["context"] = self.file.by_id(box_context_id) new_box = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data) ifcopenshell.api.run( "geometry.assign_representation", self.file, **{"product": product, "representation": new_box} ) + [ + bpy.ops.bim.add_style(material=s.material.name) + for s in obj.material_slots + if not s.material.BIMMaterialProperties.ifc_style_id + ] + ifcopenshell.api.run( "geometry.assign_styles", self.file, diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index e2e9919551..11745bdf7a 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -318,6 +318,10 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): material_set_class = "IfcMaterialLayerSet" elif product_data["type"] == "IfcMaterialProfileSet": material_set_data = Data.profile_sets[product_data["id"]] + elif product_data["type"] == "IfcMaterialProfileSetUsage": + profile_set_usage = Data.profile_set_usages[product_data["id"]] + material_set_data = Data.profile_sets[profile_set_usage["ForProfileSet"]] + material_set_class = "IfcMaterialProfileSet" elif product_data["type"] == "IfcMaterialList": material_set_data = Data.lists[product_data["id"]] else: @@ -409,7 +413,7 @@ class EnableEditingMaterialSetItem(bpy.types.Operator): material_set_item_data = Data.constituents[self.material_set_item] elif product_data["type"] == "IfcMaterialLayerSet" or product_data["type"] == "IfcMaterialLayerSetUsage": material_set_item_data = Data.layers[self.material_set_item] - elif product_data["type"] == "IfcMaterialProfileSet": + elif product_data["type"] == "IfcMaterialProfileSet" or product_data["type"] == "IfcMaterialProfileSetUsage": material_set_item_data = Data.profiles[self.material_set_item] else: material_set_item_data = {} @@ -542,7 +546,7 @@ class EditMaterialSetItem(bpy.types.Operator): }, ) Data.load_layers() - elif product_data["type"] == "IfcMaterialProfileSet": + elif product_data["type"] == "IfcMaterialProfileSet" or product_data["type"] == "IfcMaterialProfileSetUsage": profile_attributes = {} for attribute in props.material_set_item_profile_attributes: if attribute.data_type == "string": diff --git a/src/blenderbim/blenderbim/bim/module/material/prop.py b/src/blenderbim/blenderbim/bim/module/material/prop.py index 6b39d95691..4bd7093d69 100644 --- a/src/blenderbim/blenderbim/bim/module/material/prop.py +++ b/src/blenderbim/blenderbim/bim/module/material/prop.py @@ -70,6 +70,7 @@ def getMaterialTypes(self, context): "IfcMaterialLayerSet", "IfcMaterialLayerSetUsage", "IfcMaterialProfileSet", + "IfcMaterialProfileSetUsage", "IfcMaterialList", ] if IfcStore.get_file().schema == "IFC2X3": diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index 591fa8ccb3..262a920ef3 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -82,6 +82,13 @@ class BIM_PT_object_material(Panel): self.set_items = self.material_set_data["MaterialProfiles"] or [] self.set_data = Data.profiles self.set_item_name = "profile" + elif self.product_data["type"] == "IfcMaterialProfileSetUsage": + self.material_set_usage = Data.profile_set_usages[self.product_data["id"]] + self.material_set_id = self.material_set_usage["ForProfileSet"] + self.material_set_data = Data.profile_sets[self.material_set_id] + self.set_items = self.material_set_data["MaterialProfiles"] or [] + self.set_data = Data.profiles + self.set_item_name = "profile" elif self.product_data["type"] == "IfcMaterialList": self.material_set_id = self.product_data["id"] self.material_set_data = Data.lists[self.material_set_id] diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/prop.py b/src/blenderbim/blenderbim/bim/module/pset_template/prop.py index 36b8bc8c05..83b134c399 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/prop.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/prop.py @@ -65,7 +65,7 @@ def getPsetTemplates(self, context): IfcStore.pset_template_file = ifcopenshell.open(IfcStore.pset_template_path) templates = IfcStore.pset_template_file.by_type("IfcPropertySetTemplate") psettemplates_enum.extend([(str(t.id()), t.Name, "") for t in templates]) - Data.load(IfcStore.get_file()) + Data.load(IfcStore.pset_template_file) return psettemplates_enum diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/ui.py b/src/blenderbim/blenderbim/bim/module/pset_template/ui.py index 49813c0c96..b252e4e496 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/ui.py @@ -35,10 +35,8 @@ class BIM_PT_pset_template(Panel): row.operator("bim.enable_editing_pset_template", text="", icon="GREASEPENCIL") row.operator("bim.remove_pset_template", text="", icon="X") - # row.operator("bim.save_pset_template", text="", icon="EXPORT") - if not Data.is_loaded and props.pset_template_files: - Data.load(IfcStore.get_file()) + Data.load(IfcStore.pset_template_file) if not Data.pset_templates: return diff --git a/src/blenderbim/blenderbim/bim/module/root/operator.py b/src/blenderbim/blenderbim/bim/module/root/operator.py index 0af5b8bddb..a785741d60 100644 --- a/src/blenderbim/blenderbim/bim/module/root/operator.py +++ b/src/blenderbim/blenderbim/bim/module/root/operator.py @@ -153,6 +153,7 @@ class AssignClass(bpy.types.Operator): collection.objects.link(obj) if parent_collection: parent_collection.children.link(collection) + bpy.ops.bim.assign_object(related_object=obj.name, relating_object=parent_collection.name) else: bpy.context.scene.collection.children.link(collection) diff --git a/src/blenderbim/blenderbim/bim/module/root/ui.py b/src/blenderbim/blenderbim/bim/module/root/ui.py index d30a7ffe40..6991dbca58 100644 --- a/src/blenderbim/blenderbim/bim/module/root/ui.py +++ b/src/blenderbim/blenderbim/bim/module/root/ui.py @@ -39,7 +39,7 @@ class BIM_PT_class(Panel): name += "[{}]".format(data["PredefinedType"]) row = self.layout.row(align=True) row.label(text=name) - row.operator("bim.copy_class", icon="DUPLICATE", text="").obj = context.active_object.name + row.operator("bim.copy_class", icon="DUPLICATE", text="") row.operator("bim.unlink_object", icon="UNLINKED", text="") row.operator("bim.enable_reassign_class", icon="GREASEPENCIL", text="") if context.selected_objects: diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index 27102da316..9f57dc8d18 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -9,7 +9,6 @@ classes = ( operator.RemoveWorkPlan, operator.EnableEditingWorkPlan, operator.DisableEditingWorkPlan, - operator.LoadWorkSchedules, operator.DisableWorkScheduleEditingUI, operator.AddWorkSchedule, operator.EditWorkSchedule, @@ -26,17 +25,19 @@ classes = ( operator.EnableEditingWorkCalendar, operator.DisableEditingWorkCalendar, operator.AddTask, + operator.AddSummaryTask, + operator.ExpandTask, + operator.ContractTask, + operator.RemoveTask, prop.WorkPlan, prop.BIMWorkPlanProperties, prop.Task, - prop.WorkSchedule, prop.BIMWorkScheduleProperties, prop.WorkCalendar, prop.BIMWorkCalendarProperties, 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_UL_tasks, diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 1b0ecad74a..b344b7ab3d 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -123,23 +123,6 @@ class DisableEditingWorkPlan(bpy.types.Operator): 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" @@ -156,7 +139,6 @@ class AddWorkSchedule(bpy.types.Operator): 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"} @@ -182,7 +164,7 @@ class EditWorkSchedule(bpy.types.Operator): **{"work_schedule": self.file.by_id(props.active_work_schedule_id), "attributes": attributes} ) Data.load(IfcStore.get_file()) - bpy.ops.bim.load_work_schedules() + bpy.ops.bim.disable_editing_work_schedule() return {"FINISHED"} @@ -194,10 +176,11 @@ class RemoveWorkSchedule(bpy.types.Operator): 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)} + "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"} @@ -207,9 +190,10 @@ class EnableEditingWorkSchedule(bpy.types.Operator): 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) + self.props = context.scene.BIMWorkScheduleProperties + self.props.active_work_schedule_id = self.work_schedule + while len(self.props.work_schedule_attributes) > 0: + self.props.work_schedule_attributes.remove(0) data = Data.work_schedules[self.work_schedule] @@ -217,7 +201,7 @@ class EnableEditingWorkSchedule(bpy.types.Operator): data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) if data_type == "entity": continue - new = props.work_schedule_attributes.add() + new = self.props.work_schedule_attributes.add() new.name = attribute.name() new.is_null = data[attribute.name()] is None new.is_optional = attribute.optional() @@ -230,10 +214,30 @@ class EnableEditingWorkSchedule(bpy.types.Operator): 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 - bpy.ops.bim.load_tasks(work_schedule=self.work_schedule) + self.props.active_work_schedule_id = self.work_schedule + + while len(self.props.tasks) > 0: + self.props.tasks.remove(0) + + self.contracted_tasks = json.loads(self.props.contracted_tasks) + for related_object_id in Data.work_schedules[self.work_schedule]["RelatedObjects"]: + self.create_new_task_li(related_object_id, 0) return {"FINISHED"} + def create_new_task_li(self, related_object_id, level_index): + task = Data.tasks[related_object_id] + new = self.props.tasks.add() + new.name = task["Name"] or "Unnamed" + new.ifc_definition_id = related_object_id + new.is_expanded = related_object_id not in self.contracted_tasks + new.level_index = level_index + if task["RelatedObjects"]: + new.has_children = True + if new.is_expanded: + for related_object_id in task["RelatedObjects"]: + self.create_new_task_li(related_object_id, level_index + 1) + # return {"FINISHED"} + class DisableEditingWorkSchedule(bpy.types.Operator): bl_idname = "bim.disable_editing_work_schedule" @@ -392,13 +396,80 @@ class DisableTaskEditingUI(bpy.types.Operator): class AddTask(bpy.types.Operator): bl_idname = "bim.add_task" bl_label = "Add Task" + task: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMWorkScheduleProperties + self.file = IfcStore.get_file() + ifcopenshell.api.run("sequence.add_task", self.file, **{ + "parent_task": self.file.by_id(self.task) + }) + Data.load(self.file) + bpy.ops.bim.enable_editing_work_schedule(work_schedule = props.active_work_schedule_id) + return {"FINISHED"} + + +class AddSummaryTask(bpy.types.Operator): + bl_idname = "bim.add_summary_task" + bl_label = "Add Task" work_schedule: bpy.props.IntProperty() def execute(self, context): + props = context.scene.BIMWorkScheduleProperties self.file = IfcStore.get_file() - task = ifcopenshell.api.run("sequence.add_task", self.file) - control = self.file.by_id(self.work_schedule) - ifcopenshell.api.run("control.assign_control", self.file, related_object=task, relating_control=control) + ifcopenshell.api.run("sequence.add_task", self.file, **{ + "work_schedule": self.file.by_id(self.work_schedule) + }) Data.load(self.file) - bpy.ops.bim.enable_editing_work_schedule(work_schedule = self.work_schedule) + bpy.ops.bim.enable_editing_work_schedule(work_schedule = props.active_work_schedule_id) + return {"FINISHED"} + + +class ExpandTask(bpy.types.Operator): + bl_idname = "bim.expand_task" + bl_label = "Expand Task" + task: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMWorkScheduleProperties + self.file = IfcStore.get_file() + contracted_tasks = json.loads(props.contracted_tasks) + contracted_tasks.remove(self.task) + props.contracted_tasks = json.dumps(contracted_tasks) + Data.load(self.file) + bpy.ops.bim.enable_editing_work_schedule(work_schedule = props.active_work_schedule_id) + return {"FINISHED"} + + +class ContractTask(bpy.types.Operator): + bl_idname = "bim.contract_task" + bl_label = "Contract Task" + task: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMWorkScheduleProperties + self.file = IfcStore.get_file() + contracted_tasks = json.loads(props.contracted_tasks) + contracted_tasks.append(self.task) + props.contracted_tasks = json.dumps(contracted_tasks) + Data.load(self.file) + bpy.ops.bim.enable_editing_work_schedule(work_schedule = props.active_work_schedule_id) + return {"FINISHED"} + + +class RemoveTask(bpy.types.Operator): + bl_idname = "bim.remove_task" + bl_label = "Remove Task" + task: bpy.props.IntProperty() + + def execute(self, context): + props = context.scene.BIMWorkScheduleProperties + self.file = IfcStore.get_file() + ifcopenshell.api.run( + "sequence.remove_task", + self.file, + task=IfcStore.get_file().by_id(self.task), + ) + Data.load(self.file) + bpy.ops.bim.enable_editing_work_schedule(work_schedule = props.active_work_schedule_id) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index a21ec53a48..6d1d089537 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -17,7 +17,9 @@ class Task(PropertyGroup): name: StringProperty(name="Name") identification: StringProperty(name="Identification") ifc_definition_id: IntProperty(name="IFC Definition ID") - + has_children: BoolProperty(name="Has Children") + is_expanded: BoolProperty(name="Is Expanded") + level_index: IntProperty(name="Level Index") class WorkPlan(PropertyGroup): name: StringProperty(name="Name") @@ -32,19 +34,15 @@ class BIMWorkPlanProperties(PropertyGroup): 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") tasks: CollectionProperty(name="Tasks", type=Task) active_task_index: IntProperty(name="Active Task Index") + contracted_tasks: StringProperty(name="Contracted Task Items", default="[]") + class WorkCalendar(PropertyGroup): diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index d0eba710f5..54710c9621 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -80,31 +80,33 @@ class BIM_PT_work_schedules(Panel): return IfcStore.get_file() def draw(self, context): + self.props = context.scene.BIMWorkScheduleProperties + 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") + row = self.layout.row() + row.operator("bim.add_work_schedule", icon="ADD") - if self.props.is_editing: - self.layout.template_list( - "BIM_UL_work_schedules", - "", - self.props, - "work_schedules", - self.props, - "active_work_schedule_index", - ) + for work_schedule_id, work_schedule in Data.work_schedules.items(): + row = self.layout.row(align=True) + row.label(text=work_schedule["Name"] or "Unnamed", icon="LINENUMBERS_ON") - if self.props.active_work_schedule_id: - self.draw_editable_ui(context) + if self.props.active_work_schedule_id and self.props.active_work_schedule_id == work_schedule_id: + row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK") + row.operator("bim.disable_editing_work_schedule", text="", icon="X") + elif self.props.active_work_schedule_id: + row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = work_schedule_id + else: + row.operator("bim.enable_editing_work_schedule", text="", icon="GREASEPENCIL").work_schedule = work_schedule_id + row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = work_schedule_id - def draw_editable_ui(self, context): + if self.props.active_work_schedule_id == work_schedule_id: + self.draw_editable_work_schedule_ui(work_schedule_id, work_schedule) + + def draw_editable_work_schedule_ui(self, work_schedule_id, work_schedule): for attribute in self.props.work_schedule_attributes: row = self.layout.row(align=True) if attribute.data_type == "string": @@ -114,13 +116,9 @@ class BIM_PT_work_schedules(Panel): if attribute.is_optional: row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") - self.draw_task_ui(context) - - def draw_task_ui(self, context): row = self.layout.row(align=True) - row.label(text="{} Tasks Found".format(len(Data.tasks)), icon="ACTION") - row.operator("bim.add_task", text="", icon="ADD").work_schedule = self.props.active_work_schedule_id - + row.label(text="X Summary Tasks") + row.operator("bim.add_summary_task", text="", icon="ADD").work_schedule = work_schedule_id self.layout.template_list( "BIM_UL_tasks", "", @@ -130,21 +128,23 @@ class BIM_PT_work_schedules(Panel): "active_task_index", ) - -class BIM_UL_work_schedules(UIList): +class BIM_UL_tasks(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 + for i in range(0, item.level_index): + row.label(text="", icon="BLANK1") + if item.has_children: + if item.is_expanded: + row.operator("bim.contract_task", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN").task = item.ifc_definition_id + else: + row.operator("bim.expand_task", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").task = 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 + row.label(text="", icon="DOT") + row.label(text=item.name) + op = row.operator("bim.add_task", text="", icon="ADD") + op.task = item.ifc_definition_id + row.operator("bim.remove_task", text="", icon="X").task = item.ifc_definition_id class BIM_PT_work_calendars(Panel): @@ -209,12 +209,3 @@ class BIM_UL_work_calendars(UIList): 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_UL_tasks(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): - if item: - row = layout.row(align=True) - if item.identification: - layout.label(text=item.identification) - layout.label(text=item.name) diff --git a/src/blenderbim/blenderbim/bim/operator.py b/src/blenderbim/blenderbim/bim/operator.py index 3851f1aff2..51eb123f52 100644 --- a/src/blenderbim/blenderbim/bim/operator.py +++ b/src/blenderbim/blenderbim/bim/operator.py @@ -67,9 +67,11 @@ class ExportIFC(bpy.types.Operator): filepath: bpy.props.StringProperty(subtype="FILE_PATH") json_version: bpy.props.EnumProperty(items=[("4", "4", ""), ("5a", "5a", "")], name="IFC JSON Version") json_compact: bpy.props.BoolProperty(name="Export Compact IFCJSON", default=False) - should_force_resave: bpy.props.BoolProperty(name="Resave .blend", default=False) def invoke(self, context, event): + if bpy.context.scene.BIMProperties.ifc_file: + self.filepath = bpy.context.scene.BIMProperties.ifc_file + return self.execute(context) if not self.filepath: self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".ifc") WindowManager = context.window_manager @@ -104,8 +106,8 @@ class ExportIFC(bpy.types.Operator): new.name = output_file if not bpy.context.scene.BIMProperties.ifc_file: bpy.context.scene.BIMProperties.ifc_file = output_file - if self.should_force_resave: - bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath) + if bpy.data.is_saved and bpy.data.is_dirty and bpy.data.filepath: + bpy.ops.wm.save_mainfile(filepath=bpy.data.filepath) return {"FINISHED"} @@ -115,7 +117,6 @@ class ImportIFC(bpy.types.Operator, ImportHelper): filename_ext = ".ifc" filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) - should_import_spaces: bpy.props.BoolProperty(name="Import Spaces", default=False) should_auto_set_workarounds: bpy.props.BoolProperty(name="Automatically Set Vendor Workarounds", default=True) should_use_cpu_multiprocessing: bpy.props.BoolProperty(name="Import with CPU Multiprocessing", default=True) should_merge_by_class: bpy.props.BoolProperty(name="Import and Merge by Class", default=False) @@ -140,7 +141,6 @@ class ImportIFC(bpy.types.Operator, ImportHelper): ) settings = import_ifc.IfcImportSettings.factory(context, self.filepath, logger) - settings.should_import_spaces = self.should_import_spaces settings.should_auto_set_workarounds = self.should_auto_set_workarounds settings.should_use_cpu_multiprocessing = self.should_use_cpu_multiprocessing settings.should_merge_by_class = self.should_merge_by_class diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py new file mode 100644 index 0000000000..003cf31931 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py @@ -0,0 +1,10 @@ +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = {"cost_item": None} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + # TODO: do a deep purge + self.file.remove(self.settings["cost_item"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py b/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py index f7fc4be564..8e7147ee67 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py @@ -24,18 +24,28 @@ class Usecase: elif self.settings["type"] == "IfcMaterialProfileSet": material_set = self.file.create_entity(self.settings["type"]) self.create_material_association(material_set) + elif self.settings["type"] == "IfcMaterialProfileSetUsage": + material_set = self.file.create_entity("IfcMaterialProfileSet") + material_set_usage = self.create_profile_set_usage(material_set) + self.create_material_association(material_set_usage) elif self.settings["type"] == "IfcMaterialList": material_set = self.file.create_entity(self.settings["type"]) material_set.Materials = [self.settings["material"]] self.create_material_association(material_set) def create_layer_set_usage(self, material_set): - return self.file.create_entity("IfcMaterialLayerSetUsage", **{ - "ForLayerSet": material_set, - "LayerSetDirection": "AXIS2" if self.settings["product"].is_a("IfcWall") else "AXIS3", - "DirectionSense": "POSITIVE", - "OffsetFromReferenceLine": 0 - }) + return self.file.create_entity( + "IfcMaterialLayerSetUsage", + **{ + "ForLayerSet": material_set, + "LayerSetDirection": "AXIS2" if self.settings["product"].is_a("IfcWall") else "AXIS3", + "DirectionSense": "POSITIVE", + "OffsetFromReferenceLine": 0, + } + ) + + def create_profile_set_usage(self, material_set): + return self.file.create_entity("IfcMaterialProfileSetUsage", **{"ForProfileSet": material_set}) def assign_ifc_material(self): rel = self.get_rel_associates_material(self.settings["material"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/data.py b/src/ifcopenshell-python/ifcopenshell/api/material/data.py index 1c39d5b20f..6d1c68e5da 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/data.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/data.py @@ -6,8 +6,10 @@ class Data: materials = {} constituent_sets = {} constituents = {} + layer_sets_usages = {} layer_sets = {} layers = {} + profile_set_usages = {} profile_sets = {} profiles = {} lists = {} @@ -23,6 +25,7 @@ class Data: cls.layer_set_usages = {} cls.layer_sets = {} cls.layers = {} + cls.profile_set_usages = {} cls.profile_sets = {} cls.profiles = {} cls.lists = {} @@ -41,6 +44,7 @@ class Data: cls.load_layers() cls.load_layer_usages() cls.load_profiles() + cls.load_profile_usages() cls.load_lists() cls.is_loaded = True @@ -68,6 +72,11 @@ class Data: cls.layer_set_usages = {} cls.load_element("IfcMaterialLayerSetUsage", cls.layer_set_usages) + @classmethod + def load_profile_usages(cls): + cls.profile_set_usages = {} + cls.load_element("IfcMaterialProfileSetUsage", cls.profile_set_usages) + @classmethod def load_profiles(cls): cls.profile_sets = {} @@ -109,6 +118,4 @@ class Data: @classmethod def load_association(cls, association, product_id): material_select = association.RelatingMaterial - if material_select.is_a("IfcMaterialProfileSetUsage"): # TODO: implement usages - material_select = material_select.ForProfileSet cls.products[product_id] = {"type": material_select.is_a(), "id": material_select.id()} diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py index e27acee45a..1102606064 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py @@ -1,16 +1,12 @@ import ifcopenshell.api - +import ifcopenshell class Usecase: def __init__(self, file, **settings): self.file = file self.settings = { - "name": None, - "predefined_type": "NOTDEFINED", - "is_milestone": False, - "identification": "none", - "predecessor_to": None, - "successor_from": None, + "work_schedule": None, + "parent_task": None, } for key, value in settings.items(): self.settings[key] = value @@ -20,8 +16,23 @@ class Usecase: "root.create_entity", self.file, ifc_class="IfcTask", - predefined_type=self.settings["predefined_type"], - name=self.settings["name"], + name= None, + predefined_type= "NOTDEFINED", + identification= "none", ) - task.IsMilestone = self.settings["is_milestone"] + task.IsMilestone = False + if self.settings["work_schedule"]: + self.file.create_entity( + "IfcRelAssignsToControl", + **{ + "GlobalId": ifcopenshell.guid.new(), + "OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file), + "RelatedObjects": [task], + "RelatingControl": self.settings["work_schedule"], + } + ) + elif self.settings["parent_task"]: + ifcopenshell.api.run( + "nest.assign_object", self.file, object=task, relating_object=self.settings["parent_task"] + ) return task diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py index edfa8cbe45..04ba1e7a63 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/data.py @@ -61,6 +61,7 @@ class Data: @classmethod def load_work_calendars(cls): + cls.work_calendars = {} for work_calendar in cls._file.by_type("IfcWorkCalendar"): data = work_calendar.get_info() del data["OwnerHistory"] @@ -72,4 +73,9 @@ class Data: def load_tasks(cls): cls.tasks = {} for task in cls._file.by_type("IfcTask"): - cls.tasks[task.id()] = {"Name": task.Name, "Identification": task.Identification or ""} + data = task.get_info() + del data["OwnerHistory"] + data["RelatedObjects"] = [] + for rel in task.IsNestedBy: + [data["RelatedObjects"].append(o.id()) for o in rel.RelatedObjects if o.is_a("IfcTask")] + cls.tasks[task.id()] = data diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py new file mode 100644 index 0000000000..941a335663 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py @@ -0,0 +1,19 @@ +import ifcopenshell.api + + +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = {"task": None} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + # TODO: do a deep purge + ifcopenshell.api.run( + "project.unassign_declaration", + self.file, + definition=self.settings["task"], + relating_context=self.file.by_type("IfcContext")[0], + ) + self.file.remove(self.settings["task"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py index c0af69b25d..2fd21d975f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py @@ -1,3 +1,6 @@ +import ifcopenshell.api + + class Usecase: def __init__(self, file, **settings): self.file = file diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index 788acf7f34..1c90f3d391 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -119,17 +119,13 @@ def is_representation_of_context(representation, context, subcontext=None, targe def remove_deep(ifc_file, element): + # @todo maybe some sort of try-finally mechanism. + ifc_file.batch() subgraph = list(ifc_file.traverse(element)) subgraph_set = set(subgraph) for ref in subgraph[::-1]: if ref.id() and len(set(ifc_file.get_inverse(ref)) - subgraph_set) == 0: ifc_file.remove(ref) - - -def remove_deep_batched(ifc_file, element): - # @todo maybe some sort of try-finally mechanism. - ifc_file.batch() - remove_deep(ifc_file, element) ifc_file.unbatch() diff --git a/src/ifcparse/IfcCharacterDecoder.cpp b/src/ifcparse/IfcCharacterDecoder.cpp index 1c2fd38228..0ad9cc787d 100644 --- a/src/ifcparse/IfcCharacterDecoder.cpp +++ b/src/ifcparse/IfcCharacterDecoder.cpp @@ -317,7 +317,7 @@ IfcCharacterEncoder::operator std::string() { // Either 2 or 4 to uses \X2 or \X4 respectively. // Currently hardcoded to 4, but \X2 might be // sufficient for nearly all purposes. - const int num_bytes = *std::max_element(str.begin(), str.end()) > 0xffff ? 4 : 2; + const int num_bytes = (str.empty() || *std::max_element(str.begin(), str.end())) > 0xffff ? 4 : 2; const std::string num_bytes_str = std::string(1,num_bytes + 0x30); bool in_extended = false; diff --git a/src/ifcparse/IfcEntityInstanceData.h b/src/ifcparse/IfcEntityInstanceData.h index 7d2c4ee8ca..6fb0386f38 100644 --- a/src/ifcparse/IfcEntityInstanceData.h +++ b/src/ifcparse/IfcEntityInstanceData.h @@ -48,17 +48,13 @@ public: : file(file_), id_(id), type_(type), attributes_(0), offset_in_file_(offset_in_file) {} - IfcEntityInstanceData(IfcParse::IfcFile* file_, size_t size) - : file(file_), id_(0), type_(0), attributes_(new Argument*[size]), offset_in_file_(0) + IfcEntityInstanceData(IfcParse::IfcFile* file_, size_t size) + : file(file_), id_(0), type_(0), attributes_(new Argument*[size] {0}), offset_in_file_(0) {} - IfcEntityInstanceData(const IfcParse::declaration* type) - : file(0), id_(0), type_(type), attributes_(new Argument*[getArgumentCount()]) - { - for (size_t i = 0; i < getArgumentCount(); ++i) { - attributes_[i] = 0; - } - } + IfcEntityInstanceData(const IfcParse::declaration* type) + : file(0), id_(0), type_(type), attributes_(new Argument*[getArgumentCount()]{ 0 }), offset_in_file_(0) + {} void load() const; diff --git a/src/ifcparse/IfcSpfHeader.cpp b/src/ifcparse/IfcSpfHeader.cpp index 5b95e68dcf..779b717152 100644 --- a/src/ifcparse/IfcSpfHeader.cpp +++ b/src/ifcparse/IfcSpfHeader.cpp @@ -43,11 +43,6 @@ HeaderEntity::HeaderEntity(const char * const datatype, size_t size, IfcFile* fi if (file) { offset_in_file_ = file->stream->Tell(); load(); - } else { - // attributes_ = new Argument*[size]; - for (size_t i = 0; i < size; ++i) { - attributes_[i] = 0; - } } }