mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-19 11:43:53 +00:00
See #4699. Continue refactoring logic from drawing decorator into DecoratorData.
This commit is contained in:
@@ -236,23 +236,39 @@ class DecoratorData:
|
|||||||
fill_cache = {}
|
fill_cache = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls, handler):
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
cls.cut_cache = {}
|
cls.cut_cache = {}
|
||||||
cls.layerset_cache = {}
|
cls.layerset_cache = {}
|
||||||
|
|
||||||
text = {}
|
text = {}
|
||||||
dimension = {}
|
dimension = {}
|
||||||
|
fall = {}
|
||||||
|
symbol = {}
|
||||||
for obj in bpy.context.visible_objects:
|
for obj in bpy.context.visible_objects:
|
||||||
if not (element := tool.Ifc.get_entity(obj)):
|
if not (element := tool.Ifc.get_entity(obj)):
|
||||||
continue
|
continue
|
||||||
if tool.Drawing.is_annotation_object_type(element, ["TEXT", "TEXT_LEADER"]):
|
if tool.Drawing.is_annotation_object_type(element, ("TEXT", "TEXT_LEADER")):
|
||||||
text[obj.name] = cls.get_ifc_text_data(obj)
|
text[obj.name] = cls.get_text_data(obj)
|
||||||
|
if text[obj.name]["Symbol"]:
|
||||||
|
symbol[obj.name] = cls.get_symbol_data(obj)
|
||||||
elif tool.Drawing.is_annotation_object_type(
|
elif tool.Drawing.is_annotation_object_type(
|
||||||
element, ("DIMENSION", "DIAMETER", "SECTION_LEVEL", "PLAN_LEVEL", "RADIUS")
|
element, ("DIMENSION", "DIAMETER", "SECTION_LEVEL", "PLAN_LEVEL", "RADIUS")
|
||||||
):
|
):
|
||||||
dimension[obj.name] = cls.get_dimension_data(obj)
|
dimension[obj.name] = cls.get_dimension_data(obj)
|
||||||
cls.data = {"text": text, "dimension": dimension}
|
elif tool.Drawing.is_annotation_object_type(
|
||||||
|
element, ("FALL", "SLOPE_ANGLE", "SLOPE_FRACTION", "SLOPE_PERCENT")
|
||||||
|
):
|
||||||
|
fall[obj.name] = cls.get_fall_data(obj)
|
||||||
|
elif tool.Drawing.is_annotation_object_type(element, ("SYMBOL",)):
|
||||||
|
symbol[obj.name] = cls.get_symbol_data(obj)
|
||||||
|
cls.data = {
|
||||||
|
"text": text,
|
||||||
|
"dimension": dimension,
|
||||||
|
"fall": fall,
|
||||||
|
"symbol": symbol,
|
||||||
|
"object_decorators": cls.object_decorators(handler),
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_batting_thickness(cls, obj):
|
def get_batting_thickness(cls, obj):
|
||||||
@@ -311,7 +327,7 @@ class DecoratorData:
|
|||||||
return display_data
|
return display_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ifc_text_data(cls, obj: bpy.types.Object) -> dict:
|
def get_text_data(cls, obj: bpy.types.Object) -> dict:
|
||||||
"""used by Ifc Annotations with ObjectType = "TEXT" / "TEXT_LEADER"\n
|
"""used by Ifc Annotations with ObjectType = "TEXT" / "TEXT_LEADER"\n
|
||||||
returns font size in mm for current ifc text object"""
|
returns font size in mm for current ifc text object"""
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
@@ -354,11 +370,6 @@ class DecoratorData:
|
|||||||
|
|
||||||
return {"Literals": literals_data, "FontSize": font_size, "Symbol": symbol, "Newline_At": newline_at}
|
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]:
|
|
||||||
"""used by IfcAnnotations with ObjectType MULTI_SYMBOL"""
|
|
||||||
return tool.Drawing.get_annotation_symbol(tool.Ifc.get_entity(obj))
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_dimension_data(cls, obj):
|
def get_dimension_data(cls, obj):
|
||||||
"""used by Ifc Annotations with ObjectType:
|
"""used by Ifc Annotations with ObjectType:
|
||||||
@@ -394,6 +405,59 @@ class DecoratorData:
|
|||||||
"custom_unit": custom_unit,
|
"custom_unit": custom_unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_fall_data(cls, obj):
|
||||||
|
object_type = None
|
||||||
|
if element := tool.Ifc.get_entity(obj):
|
||||||
|
object_type = ifcopenshell.util.element.get_predefined_type(element)
|
||||||
|
return {"object_type": object_type}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_symbol_data(cls, obj):
|
||||||
|
return tool.Drawing.get_annotation_symbol(tool.Ifc.get_entity(obj))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def object_decorators(cls, handler):
|
||||||
|
import bonsai.bim.module.drawing.decoration
|
||||||
|
|
||||||
|
if not bonsai.bim.module.drawing.decoration.DecorationsHandler.installed:
|
||||||
|
return []
|
||||||
|
|
||||||
|
props = tool.Drawing.get_document_props()
|
||||||
|
if (drawing := props.get_active_drawing()) is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
camera = tool.Ifc.get_object(drawing)
|
||||||
|
assert isinstance(camera, bpy.types.Object)
|
||||||
|
collection = tool.Blender.get_object_bim_props(camera).collection
|
||||||
|
assert collection
|
||||||
|
|
||||||
|
results = []
|
||||||
|
viewport = tool.Blender.get_view3d_space()
|
||||||
|
|
||||||
|
for obj in collection.all_objects:
|
||||||
|
if not obj.visible_get(viewport=viewport):
|
||||||
|
continue
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
if not element:
|
||||||
|
continue
|
||||||
|
if not element.is_a("IfcAnnotation"):
|
||||||
|
continue
|
||||||
|
object_type: Union[str, None] = ifcopenshell.util.element.get_predefined_type(element)
|
||||||
|
if object_type == "DRAWING":
|
||||||
|
continue
|
||||||
|
if dec := handler.decorators.get(object_type, None):
|
||||||
|
results.append((obj, dec))
|
||||||
|
elif isinstance(obj.data, bpy.types.Mesh):
|
||||||
|
if object_type == "LINEWORK" and "dashed" in str(
|
||||||
|
ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Classes")
|
||||||
|
).split(" "):
|
||||||
|
results.append((obj, handler.decorators["HIDDEN_LINE"]))
|
||||||
|
else:
|
||||||
|
results.append((obj, handler.decorators["MISC"]))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
class AnnotationData:
|
class AnnotationData:
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
@@ -562,8 +562,7 @@ class BaseDecorator:
|
|||||||
MiscDecorator.decorate(self, context, obj)
|
MiscDecorator.decorate(self, context, obj)
|
||||||
return
|
return
|
||||||
|
|
||||||
symbol = DecoratorData.get_symbol(obj)
|
if not (symbol := DecoratorData.data["symbol"].get(obj.name, None)):
|
||||||
if not symbol:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
for vert in mesh.vertices:
|
for vert in mesh.vertices:
|
||||||
@@ -572,8 +571,7 @@ class BaseDecorator:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# EMPTY objects
|
# EMPTY objects
|
||||||
symbol = DecoratorData.get_symbol(obj)
|
if not (symbol := DecoratorData.data["symbol"].get(obj.name, None)):
|
||||||
if not symbol:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
rotation = -Vector((1, 0)).angle_signed(annotation_dir)
|
rotation = -Vector((1, 0)).angle_signed(annotation_dir)
|
||||||
@@ -998,8 +996,6 @@ class FallDecorator(BaseDecorator):
|
|||||||
# generate label text
|
# generate label text
|
||||||
# same function as in svgwriter.py
|
# same function as in svgwriter.py
|
||||||
def get_label_text():
|
def get_label_text():
|
||||||
element = tool.Ifc.get_entity(obj)
|
|
||||||
assert element
|
|
||||||
B, A = [v.co.xyz for v in spline_points[:2]]
|
B, A = [v.co.xyz for v in spline_points[:2]]
|
||||||
rise = abs(A.z - B.z)
|
rise = abs(A.z - B.z)
|
||||||
O = A.copy()
|
O = A.copy()
|
||||||
@@ -1011,8 +1007,8 @@ class FallDecorator(BaseDecorator):
|
|||||||
else:
|
else:
|
||||||
angle = 90
|
angle = 90
|
||||||
|
|
||||||
# ues SLOPE_ANGLE as default
|
# uses SLOPE_ANGLE as default
|
||||||
object_type = ifcopenshell.util.element.get_predefined_type(element)
|
DecoratorData.data["fall"].get(obj, {}).get("object_type", None)
|
||||||
if object_type in ("FALL", "SLOPE_ANGLE"):
|
if object_type in ("FALL", "SLOPE_ANGLE"):
|
||||||
return f"{angle}°"
|
return f"{angle}°"
|
||||||
elif object_type == "SLOPE_FRACTION":
|
elif object_type == "SLOPE_FRACTION":
|
||||||
@@ -1023,6 +1019,7 @@ class FallDecorator(BaseDecorator):
|
|||||||
if angle == 90:
|
if angle == 90:
|
||||||
return "-"
|
return "-"
|
||||||
return f"{round(angle_tg * 100)} %"
|
return f"{round(angle_tg * 100)} %"
|
||||||
|
return "NO DATA"
|
||||||
|
|
||||||
if spline_points:
|
if spline_points:
|
||||||
text = get_label_text()
|
text = get_label_text()
|
||||||
@@ -1921,17 +1918,18 @@ class DecorationsHandler:
|
|||||||
]
|
]
|
||||||
|
|
||||||
installed = None
|
installed = None
|
||||||
|
handler = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def install(cls, context):
|
def install(cls, context):
|
||||||
if cls.installed:
|
if cls.installed:
|
||||||
cls.uninstall()
|
cls.uninstall()
|
||||||
if not DecoratorData.is_loaded:
|
|
||||||
DecoratorData.load()
|
|
||||||
handler = cls()
|
handler = cls()
|
||||||
# NOTE: we USE POST_PIXEL here so that we can use both POLYLINE_UNIFORM_COLOR
|
# 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
|
# and drawing text in the same handler. BUT this means that we supply coordinates in WINSPACE
|
||||||
cls.installed = SpaceView3D.draw_handler_add(handler, (context,), "WINDOW", "POST_PIXEL")
|
cls.installed = SpaceView3D.draw_handler_add(handler, (context,), "WINDOW", "POST_PIXEL")
|
||||||
|
if not DecoratorData.is_loaded:
|
||||||
|
DecoratorData.load(handler)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def uninstall(cls):
|
def uninstall(cls):
|
||||||
@@ -1954,53 +1952,9 @@ class DecorationsHandler:
|
|||||||
for decorator in self.decorators.values():
|
for decorator in self.decorators.values():
|
||||||
decorator.font_id = font_id
|
decorator.font_id = font_id
|
||||||
|
|
||||||
def get_objects_and_decorators(self, collection):
|
|
||||||
# TODO: do it in data instead of the handler for performance?
|
|
||||||
results = []
|
|
||||||
viewport = bpy.context.space_data
|
|
||||||
|
|
||||||
for obj in collection.all_objects:
|
|
||||||
if not obj.visible_get(viewport=viewport):
|
|
||||||
continue
|
|
||||||
|
|
||||||
element = tool.Ifc.get_entity(obj)
|
|
||||||
if not element:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not element.is_a("IfcAnnotation"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
object_type: Union[str, None] = ifcopenshell.util.element.get_predefined_type(element)
|
|
||||||
if object_type == "DRAWING":
|
|
||||||
continue
|
|
||||||
|
|
||||||
if dec := self.decorators.get(object_type, None):
|
|
||||||
results.append((obj, dec))
|
|
||||||
|
|
||||||
elif isinstance(obj.data, bpy.types.Mesh):
|
|
||||||
if object_type == "LINEWORK" and "dashed" in str(
|
|
||||||
ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Classes")
|
|
||||||
).split(" "):
|
|
||||||
results.append((obj, self.decorators["HIDDEN_LINE"]))
|
|
||||||
else:
|
|
||||||
results.append((obj, self.decorators["MISC"]))
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
def __call__(self, context):
|
def __call__(self, context):
|
||||||
props = tool.Drawing.get_document_props()
|
|
||||||
drawing = props.get_active_drawing()
|
|
||||||
if drawing is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
camera = tool.Ifc.get_object(drawing)
|
|
||||||
assert isinstance(camera, bpy.types.Object)
|
|
||||||
collection = tool.Blender.get_object_bim_props(camera).collection
|
|
||||||
assert collection
|
|
||||||
|
|
||||||
if not DrawingsData.is_loaded:
|
if not DrawingsData.is_loaded:
|
||||||
DrawingsData.load()
|
DrawingsData.load()
|
||||||
|
|
||||||
object_decorators = self.get_objects_and_decorators(collection)
|
for obj, decorator in DecoratorData.data["object_decorators"]:
|
||||||
for obj, decorator in object_decorators:
|
|
||||||
decorator.decorate(context, obj)
|
decorator.decorate(context, obj)
|
||||||
|
|||||||
@@ -789,7 +789,7 @@ class BIMTextProperties(PropertyGroup):
|
|||||||
|
|
||||||
def get_text_edited_data(self) -> dict[str, Any]:
|
def get_text_edited_data(self) -> dict[str, Any]:
|
||||||
"""should be called only if `is_editing`
|
"""should be called only if `is_editing`
|
||||||
otherwise should use `DecoratorData.get_ifc_text_data(obj)` instead
|
otherwise should use `DecoratorData.get_text_data(obj)` instead
|
||||||
because this data could be out of date
|
because this data could be out of date
|
||||||
"""
|
"""
|
||||||
literals_data = []
|
literals_data = []
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ class BIM_PT_text(Panel):
|
|||||||
col.label(text=f' {literal_props.attributes["BoxAlignment"].string_value}')
|
col.label(text=f' {literal_props.attributes["BoxAlignment"].string_value}')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
text_data = DecoratorData.get_ifc_text_data(obj)
|
text_data = DecoratorData.get_text_data(obj)
|
||||||
|
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.operator("bim.enable_editing_text", icon="GREASEPENCIL")
|
row.operator("bim.enable_editing_text", icon="GREASEPENCIL")
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ class AnnotationToolUI:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def draw_edit_object_interface(cls, context):
|
def draw_edit_object_interface(cls, context):
|
||||||
if DecoratorData.get_ifc_text_data(bpy.context.active_object):
|
if DecoratorData.get_text_data(bpy.context.active_object):
|
||||||
add_layout_hotkey_operator(cls.layout, "Edit Text", "S_E", "")
|
add_layout_hotkey_operator(cls.layout, "Edit Text", "S_E", "")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -311,7 +311,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if not bpy.context.active_object:
|
if not bpy.context.active_object:
|
||||||
return
|
return
|
||||||
|
|
||||||
if DecoratorData.get_ifc_text_data(bpy.context.active_object):
|
if DecoratorData.get_text_data(bpy.context.active_object):
|
||||||
bpy.ops.bim.edit_text_popup()
|
bpy.ops.bim.edit_text_popup()
|
||||||
|
|
||||||
def hotkey_S_G(self):
|
def hotkey_S_G(self):
|
||||||
|
|||||||
@@ -1048,7 +1048,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
|
|
||||||
from bonsai.bim.module.drawing.data import DecoratorData
|
from bonsai.bim.module.drawing.data import DecoratorData
|
||||||
|
|
||||||
text_data = DecoratorData.get_ifc_text_data(obj)
|
text_data = DecoratorData.get_text_data(obj)
|
||||||
props.font_size = str(text_data["FontSize"])
|
props.font_size = str(text_data["FontSize"])
|
||||||
props.newline_at = text_data["Newline_At"]
|
props.newline_at = text_data["Newline_At"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user