mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-24 10:46:55 +00:00
Fix #4139. Bulk purge orphaned classes and move advanced operators to debug panel.
This commit is contained in:
@@ -510,8 +510,116 @@ class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
"Will find all elements of class that have no inverse refernces and will remove them, use very carefully"
|
"Will find all elements of class that have no inverse refernces and will remove them, use very carefully"
|
||||||
)
|
)
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||||
|
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
context.window_manager.fileselect_add(self)
|
||||||
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMDebugProperties
|
props = context.scene.BIMDebugProperties
|
||||||
purged_elements = core.purge_unused_elements(tool.Ifc, tool.Debug, props.ifc_class_purge)
|
if props.ifc_class_purge:
|
||||||
self.report({"INFO"}, f"{purged_elements} unused elements found and removed.")
|
purged_elements = core.purge_unused_elements(tool.Ifc, tool.Debug, props.ifc_class_purge)
|
||||||
|
self.report({"INFO"}, f"{purged_elements} unused elements found and removed.")
|
||||||
|
tool.Ifc.get().write(self.filepath)
|
||||||
|
return
|
||||||
|
|
||||||
|
# A whitelisted class is a class that only contains simple data that
|
||||||
|
# has no meaning by itself (only has meaning when combined with other
|
||||||
|
# data). E.g. a colour by itself has no meaning so is whitelisted, but
|
||||||
|
# a material by itself may be part of your materials library.
|
||||||
|
|
||||||
|
# There are classes I don't know enough about to decide. Not whitelisting in case.
|
||||||
|
# IfcAlignmentParameterSegment
|
||||||
|
# IfcBoundaryCondition
|
||||||
|
# IfcStructuralConnectionCondition
|
||||||
|
# IfcStructuralLoad
|
||||||
|
|
||||||
|
whitelisted_classes = [
|
||||||
|
"IfcActorRole",
|
||||||
|
"IfcAddress",
|
||||||
|
"IfcApplication",
|
||||||
|
"IfcAppliedValue",
|
||||||
|
"IfcConnectionGeometry",
|
||||||
|
"IfcCoordinateReferenceSystem",
|
||||||
|
"IfcDerivedUnit",
|
||||||
|
"IfcDerivedUnitElement",
|
||||||
|
"IfcDimensionalExponents",
|
||||||
|
"IfcExternalReference",
|
||||||
|
"IfcGridAxis",
|
||||||
|
"IfcIrregularTimeSeriesValue",
|
||||||
|
"IfcLightDistributionData",
|
||||||
|
"IfcLightIntensityDistribution",
|
||||||
|
"IfcMeasureWithUnit",
|
||||||
|
"IfcMonetaryUnit",
|
||||||
|
"IfcNamedUnit",
|
||||||
|
"IfcObjectPlacement",
|
||||||
|
"IfcOrganization", # Should be referenced as part of an actor
|
||||||
|
"IfcOwnerHistory",
|
||||||
|
"IfcPerson", # Should be referenced as part of an actor
|
||||||
|
"IfcPersonAndOrganization", # Should be referenced as part of an actor
|
||||||
|
"IfcPhysicalQuantity",
|
||||||
|
"IfcPresentationItem",
|
||||||
|
"IfcProductDefinitionShape",
|
||||||
|
"IfcPropertyAbstraction",
|
||||||
|
"IfcRecurrencePattern",
|
||||||
|
"IfcReference",
|
||||||
|
"IfcRepresentation",
|
||||||
|
"IfcRepresentationContext",
|
||||||
|
"IfcRepresentationItem",
|
||||||
|
"IfcRepresentationMap",
|
||||||
|
"IfcPropertyDefinition", # A bit of a questionable one, and the odd one out from IfcRoot.
|
||||||
|
"IfcSchedulingTime",
|
||||||
|
"IfcShapeAspect",
|
||||||
|
"IfcTable",
|
||||||
|
"IfcTableColumn",
|
||||||
|
"IfcTableRow",
|
||||||
|
"IfcTextureCoordinateIndices",
|
||||||
|
"IfcTimePeriod",
|
||||||
|
"IfcTimeSeries",
|
||||||
|
"IfcTimeSeriesValue",
|
||||||
|
"IfcUnitAssignment",
|
||||||
|
"IfcVirtualGridIntersection",
|
||||||
|
]
|
||||||
|
|
||||||
|
total_purged = 0
|
||||||
|
while True:
|
||||||
|
total_batches = 0
|
||||||
|
print("*" * 100)
|
||||||
|
total_batch_purged = 0
|
||||||
|
for ifc_class in whitelisted_classes:
|
||||||
|
total_class_purged = 0
|
||||||
|
try:
|
||||||
|
elements = tool.Ifc.get().by_type(ifc_class)
|
||||||
|
except:
|
||||||
|
continue # Probably not in this schema?
|
||||||
|
to_purge = set()
|
||||||
|
for element in elements:
|
||||||
|
try:
|
||||||
|
if ifc_class == "IfcRepresentationItem" and element.is_a("IfcStyledItem") and element.Item:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
to_purge.add(element.id()) # It's invalid, definitely purge it.
|
||||||
|
if tool.Ifc.get().get_total_inverses(element) == 0:
|
||||||
|
to_purge.add(element.id())
|
||||||
|
for element_id in to_purge:
|
||||||
|
try:
|
||||||
|
element = tool.Ifc.get().by_id(element_id)
|
||||||
|
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), element)
|
||||||
|
total_class_purged += 1
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
if total_class_purged > 0:
|
||||||
|
total_batch_purged += total_class_purged
|
||||||
|
print(f"Auto purged {total_class_purged} {ifc_class}")
|
||||||
|
if total_batch_purged > 0:
|
||||||
|
total_purged += total_batch_purged
|
||||||
|
print(f"Auto purged in batch: {total_batch_purged}")
|
||||||
|
total_batches += 1
|
||||||
|
if total_batch_purged == 0:
|
||||||
|
break
|
||||||
|
elif total_batches > 20:
|
||||||
|
print("Finished 20 batches. Manually stopping in case of infinite loop.")
|
||||||
|
self.report({"INFO"}, f"Auto purged {total_purged} orphaned elements")
|
||||||
|
tool.Ifc.get().write(self.filepath)
|
||||||
|
|||||||
@@ -87,6 +87,13 @@ class BIM_PT_debug(Panel):
|
|||||||
row.prop(props, "display_type", text="")
|
row.prop(props, "display_type", text="")
|
||||||
row.operator("bim.override_display_type").display = context.scene.BIMDebugProperties.display_type
|
row.operator("bim.override_display_type").display = context.scene.BIMDebugProperties.display_type
|
||||||
|
|
||||||
|
layout.operator("bim.purge_unused_representations")
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(context.scene.BIMDebugProperties, "ifc_class_purge", text="")
|
||||||
|
row.operator("bim.purge_unused_elements_by_class", text="Purge Orphaned", icon="TRASH")
|
||||||
|
row.operator("bim.print_unused_elements_stats", text="", icon="INFO")
|
||||||
|
|
||||||
if context.active_object and context.active_object.data:
|
if context.active_object and context.active_object.data:
|
||||||
mprops = context.active_object.data.BIMMeshProperties
|
mprops = context.active_object.data.BIMMeshProperties
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
|||||||
@@ -399,11 +399,3 @@ class BIM_PT_purge(Panel):
|
|||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.operator("bim.purge_unused_profiles")
|
layout.operator("bim.purge_unused_profiles")
|
||||||
layout.operator("bim.purge_unused_types")
|
layout.operator("bim.purge_unused_types")
|
||||||
layout.operator("bim.purge_unused_representations")
|
|
||||||
layout.separator()
|
|
||||||
|
|
||||||
layout.label(text="Purge unused elements by class:")
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.prop(context.scene.BIMDebugProperties, "ifc_class_purge", text="")
|
|
||||||
row.operator("bim.purge_unused_elements_by_class", text="", icon="TRASH")
|
|
||||||
row.operator("bim.print_unused_elements_stats", text="", icon="INFO")
|
|
||||||
|
|||||||
Reference in New Issue
Block a user