mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
See #4699. Potentially fix crashes by only loading IFC data once and caching in decorator.
This commit is contained in:
@@ -34,9 +34,7 @@ def refresh():
|
||||
DrawingsData.is_loaded = False
|
||||
ElementFiltersData.is_loaded = False
|
||||
AnnotationData.is_loaded = False
|
||||
DecoratorData.data = {}
|
||||
DecoratorData.cut_cache = {}
|
||||
DecoratorData.layerset_cache = {}
|
||||
DecoratorData.is_loaded = False
|
||||
|
||||
|
||||
class ProductAssignmentsData:
|
||||
@@ -239,6 +237,25 @@ class DecoratorData:
|
||||
slice_cache = {}
|
||||
fill_cache = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.is_loaded = True
|
||||
cls.cut_cache = {}
|
||||
cls.layerset_cache = {}
|
||||
|
||||
text = {}
|
||||
dimension = {}
|
||||
for obj in bpy.context.visible_objects:
|
||||
if not (element := tool.Ifc.get_entity(obj)):
|
||||
continue
|
||||
if tool.Drawing.is_annotation_object_type(element, ["TEXT", "TEXT_LEADER"]):
|
||||
text[obj.name] = cls.get_ifc_text_data(obj)
|
||||
elif tool.Drawing.is_annotation_object_type(
|
||||
element, ("DIMENSION", "DIAMETER", "SECTION_LEVEL", "PLAN_LEVEL", "RADIUS")
|
||||
):
|
||||
dimension[obj.name] = cls.get_dimension_data(obj)
|
||||
cls.data = {"text": text, "dimension": dimension}
|
||||
|
||||
@classmethod
|
||||
def get_batting_thickness(cls, obj):
|
||||
"""used by IfcAnnotations with ObjectType = "BATTING" """
|
||||
@@ -296,17 +313,10 @@ class DecoratorData:
|
||||
return display_data
|
||||
|
||||
@classmethod
|
||||
def get_ifc_text_data(cls, obj: bpy.types.Object) -> dict[str, Any]:
|
||||
def get_ifc_text_data(cls, obj: bpy.types.Object) -> dict:
|
||||
"""used by Ifc Annotations with ObjectType = "TEXT" / "TEXT_LEADER"\n
|
||||
returns font size in mm for current ifc text object"""
|
||||
result = cls.data.get(obj.name, None)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not tool.Drawing.is_annotation_object_type(element, ["TEXT", "TEXT_LEADER"]):
|
||||
return None
|
||||
|
||||
props = tool.Drawing.get_text_props(obj)
|
||||
# getting font size
|
||||
pset_data = ifcopenshell.util.element.get_pset(element, "EPset_Annotation") or {}
|
||||
@@ -344,9 +354,7 @@ class DecoratorData:
|
||||
|
||||
literals_data.append(literal_data)
|
||||
|
||||
text_data = {"Literals": literals_data, "FontSize": font_size, "Symbol": symbol, "Newline_At": newline_at}
|
||||
cls.data[obj.name] = text_data
|
||||
return text_data
|
||||
return {"Literals": literals_data, "FontSize": font_size, "Symbol": symbol, "Newline_At": newline_at}
|
||||
|
||||
@classmethod
|
||||
def get_symbol(cls, obj: bpy.types.Object) -> Union[str, None]:
|
||||
@@ -359,19 +367,7 @@ class DecoratorData:
|
||||
|
||||
DIMENSION / DIAMETER / SECTION_LEVEL / PLAN_LEVEL / RADIUS
|
||||
"""
|
||||
result = cls.data.get(obj.name, None)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
supported_object_types = ("DIMENSION", "DIAMETER", "SECTION_LEVEL", "PLAN_LEVEL", "RADIUS")
|
||||
if (
|
||||
not element
|
||||
or not element.is_a("IfcAnnotation")
|
||||
or ifcopenshell.util.element.get_predefined_type(element) not in supported_object_types
|
||||
):
|
||||
return None
|
||||
|
||||
dimension_style = "arrow"
|
||||
fill_bg = False
|
||||
classes = ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Classes")
|
||||
@@ -390,7 +386,7 @@ class DecoratorData:
|
||||
custom_unit_list = pset_data.get("CustomUnit", None) or ""
|
||||
custom_unit = custom_unit_list[0] if custom_unit_list else ""
|
||||
|
||||
dimension_data = {
|
||||
return {
|
||||
"dimension_style": dimension_style,
|
||||
"show_description_only": show_description_only,
|
||||
"suppress_zero_inches": suppress_zero_inches,
|
||||
@@ -399,8 +395,6 @@ class DecoratorData:
|
||||
"fill_bg": fill_bg,
|
||||
"custom_unit": custom_unit,
|
||||
}
|
||||
cls.data[obj.name] = dimension_data
|
||||
return dimension_data
|
||||
|
||||
|
||||
class AnnotationData:
|
||||
|
||||
@@ -599,7 +599,7 @@ class BaseDecorator:
|
||||
if not (pos := location_3d_to_region_2d(region, region3d, text_world_position)):
|
||||
return
|
||||
props = tool.Drawing.get_text_props(obj)
|
||||
text_data = DecoratorData.get_ifc_text_data(obj)
|
||||
text_data = DecoratorData.data["text"].get(obj.name, None)
|
||||
if props.is_editing:
|
||||
text_data = text_data | props.get_text_edited_data()
|
||||
literals_data = text_data["Literals"]
|
||||
@@ -656,7 +656,10 @@ class DimensionDecorator(BaseDecorator):
|
||||
viewportDrawingScale = self.get_viewport_drawing_scale(context)
|
||||
|
||||
# setup geometry parameters
|
||||
dimension_style = DecoratorData.get_dimension_data(obj)["dimension_style"]
|
||||
dimension_data = DecoratorData.data["dimension"].get(obj.name, None)
|
||||
if not dimension_data:
|
||||
return
|
||||
dimension_style = dimension_data["dimension_style"]
|
||||
if dimension_style == "oblique":
|
||||
size = viewportDrawingScale * 10 # OLBIQUE_SYMBOL_SIZE
|
||||
angle = radians(45)
|
||||
@@ -718,7 +721,9 @@ class DimensionDecorator(BaseDecorator):
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
description = element.Description
|
||||
dimension_data = DecoratorData.get_dimension_data(obj)
|
||||
dimension_data = DecoratorData.data["dimension"].get(obj.name, None)
|
||||
if not dimension_data:
|
||||
return
|
||||
show_description_only = dimension_data["show_description_only"]
|
||||
text_prefix = dimension_data["text_prefix"]
|
||||
text_suffix = dimension_data["text_suffix"]
|
||||
@@ -952,7 +957,9 @@ class RadiusDecorator(BaseDecorator):
|
||||
return
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
description = element.Description
|
||||
dimension_data = DecoratorData.get_dimension_data(obj)
|
||||
dimension_data = DecoratorData.data["dimension"].get(obj.name, None)
|
||||
if not dimension_data:
|
||||
return
|
||||
viewportDrawingScale = self.get_viewport_drawing_scale(context)
|
||||
text_offset = 20 * viewportDrawingScale
|
||||
|
||||
@@ -1179,7 +1186,9 @@ class PlanLevelDecorator(BaseDecorator):
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
description = element.Description
|
||||
dimension_data = DecoratorData.get_dimension_data(obj)
|
||||
dimension_data = DecoratorData.data["dimension"].get(obj.name, None)
|
||||
if not dimension_data:
|
||||
return
|
||||
|
||||
for verts in splines:
|
||||
p0, p1 = [location_3d_to_region_2d(region, region3d, v) for v in verts[:2]]
|
||||
@@ -1262,7 +1271,9 @@ class SectionLevelDecorator(BaseDecorator):
|
||||
storey = tool.Drawing.get_annotation_element(element)
|
||||
tag = storey.Name if storey else element.Description
|
||||
|
||||
dimension_data = DecoratorData.get_dimension_data(obj)
|
||||
dimension_data = DecoratorData.data["dimension"].get(obj.name, None)
|
||||
if not dimension_data:
|
||||
return
|
||||
|
||||
for verts in splines:
|
||||
|
||||
@@ -1721,11 +1732,11 @@ class CutDecorator:
|
||||
self.recalculate_fill(context, obj, element)
|
||||
|
||||
def recalculate_cut(self, context, obj: bpy.types.Object, element: ifcopenshell.entity_instance) -> None:
|
||||
if not tool.Drawing.is_intersecting_camera(obj, context.scene.camera):
|
||||
DecoratorData.cut_cache[element.id()] = (False, False)
|
||||
else:
|
||||
if tool.Drawing.is_intersecting_camera(obj, context.scene.camera):
|
||||
verts, edges = tool.Drawing.bisect_mesh(obj, context.scene.camera)
|
||||
DecoratorData.cut_cache[element.id()] = (verts, edges)
|
||||
else:
|
||||
DecoratorData.cut_cache[element.id()] = (False, False)
|
||||
|
||||
def recalculate_fill(self, context, obj: bpy.types.Object, element: ifcopenshell.entity_instance) -> None:
|
||||
element_id = element.id()
|
||||
@@ -1909,6 +1920,8 @@ class DecorationsHandler:
|
||||
def install(cls, context):
|
||||
if cls.installed:
|
||||
cls.uninstall()
|
||||
if not DecoratorData.is_loaded:
|
||||
DecoratorData.load()
|
||||
handler = cls()
|
||||
# NOTE: we USE POST_PIXEL here so that we can use both POLYLINE_UNIFORM_COLOR
|
||||
# and drawing text in the same handler. BUT this means that we supply coordinates in WINSPACE
|
||||
|
||||
Reference in New Issue
Block a user