mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 06:21:40 +00:00
Annotations are now auto collected correctly and simpler drawings UI. See #1153.
This commit is contained in:
@@ -35,13 +35,13 @@ class Annotator:
|
|||||||
return float(sizes[str(size)])
|
return float(sizes[str(size)])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_text(context, related_element=None):
|
def add_text(related_element=None):
|
||||||
curve = bpy.data.curves.new(type="FONT", name="Text")
|
curve = bpy.data.curves.new(type="FONT", name="Text")
|
||||||
curve.body = "TEXT"
|
curve.body = "TEXT"
|
||||||
obj = bpy.data.objects.new("Text", curve)
|
obj = bpy.data.objects.new("Text", curve)
|
||||||
obj.matrix_world = context.scene.camera.matrix_world
|
obj.matrix_world = bpy.context.scene.camera.matrix_world
|
||||||
if related_element is None:
|
if related_element is None:
|
||||||
location, _, _, _ = Annotator.get_placeholder_coords(context)
|
location, _, _, _ = Annotator.get_placeholder_coords(bpy.context)
|
||||||
else:
|
else:
|
||||||
obj.data.BIMTextProperties.related_element = related_element
|
obj.data.BIMTextProperties.related_element = related_element
|
||||||
location = related_element.location
|
location = related_element.location
|
||||||
@@ -50,12 +50,12 @@ class Annotator:
|
|||||||
font = bpy.data.fonts.get("OpenGost TypeB TT")
|
font = bpy.data.fonts.get("OpenGost TypeB TT")
|
||||||
if not font:
|
if not font:
|
||||||
font = bpy.data.fonts.load(
|
font = bpy.data.fonts.load(
|
||||||
os.path.join(context.scene.BIMProperties.data_dir, "fonts", "OpenGost Type B TT.ttf")
|
os.path.join(bpy.context.scene.BIMProperties.data_dir, "fonts", "OpenGost Type B TT.ttf")
|
||||||
)
|
)
|
||||||
font.name = "OpenGost Type B TT"
|
font.name = "OpenGost Type B TT"
|
||||||
obj.data.font = font
|
obj.data.font = font
|
||||||
obj.data.BIMTextProperties.font_size = "2.5"
|
obj.data.BIMTextProperties.font_size = "2.5"
|
||||||
collection = context.scene.camera.users_collection[0]
|
collection = bpy.context.scene.camera.users_collection[0]
|
||||||
collection.objects.link(obj)
|
collection.objects.link(obj)
|
||||||
Annotator.resize_text(obj)
|
Annotator.resize_text(obj)
|
||||||
return obj
|
return obj
|
||||||
@@ -83,9 +83,9 @@ class Annotator:
|
|||||||
text_obj.data.size = font_size
|
text_obj.data.size = font_size
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_line_to_annotation(obj, context, co1=None, co2=None):
|
def add_line_to_annotation(obj, co1=None, co2=None):
|
||||||
if co1 is None:
|
if co1 is None:
|
||||||
co1, co2, _, _ = Annotator.get_placeholder_coords(context)
|
co1, co2, _, _ = Annotator.get_placeholder_coords()
|
||||||
co1 = obj.matrix_world.inverted() @ co1
|
co1 = obj.matrix_world.inverted() @ co1
|
||||||
co2 = obj.matrix_world.inverted() @ co2
|
co2 = obj.matrix_world.inverted() @ co2
|
||||||
if isinstance(obj.data, bpy.types.Mesh):
|
if isinstance(obj.data, bpy.types.Mesh):
|
||||||
@@ -102,8 +102,8 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_plane_to_annotation(obj, context):
|
def add_plane_to_annotation(obj):
|
||||||
co1, co2, co3, co4 = Annotator.get_placeholder_coords(context)
|
co1, co2, co3, co4 = Annotator.get_placeholder_coords()
|
||||||
co1 = obj.matrix_world.inverted() @ co1 # bot left
|
co1 = obj.matrix_world.inverted() @ co1 # bot left
|
||||||
co2 = obj.matrix_world.inverted() @ co2 # top left
|
co2 = obj.matrix_world.inverted() @ co2 # top left
|
||||||
co3 = obj.matrix_world.inverted() @ co3 # bot right
|
co3 = obj.matrix_world.inverted() @ co3 # bot right
|
||||||
@@ -151,8 +151,8 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_annotation_obj(object_type, data_type, context):
|
def get_annotation_obj(object_type, data_type):
|
||||||
collection = context.scene.camera.users_collection[0]
|
collection = bpy.context.scene.camera.users_collection[0]
|
||||||
if object_type == "TEXT":
|
if object_type == "TEXT":
|
||||||
obj = bpy.data.objects.new(object_type, None)
|
obj = bpy.data.objects.new(object_type, None)
|
||||||
collection.objects.link(obj)
|
collection.objects.link(obj)
|
||||||
@@ -179,11 +179,15 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_placeholder_coords(context):
|
def get_placeholder_coords():
|
||||||
camera = context.scene.camera
|
camera = bpy.context.scene.camera
|
||||||
z_offset = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1))
|
z_offset = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1))
|
||||||
if context.scene.render.resolution_x > context.scene.render.resolution_y:
|
if bpy.context.scene.render.resolution_x > bpy.context.scene.render.resolution_y:
|
||||||
y = camera.data.ortho_scale * (context.scene.render.resolution_y / context.scene.render.resolution_x) / 4
|
y = (
|
||||||
|
camera.data.ortho_scale
|
||||||
|
* (bpy.context.scene.render.resolution_y / bpy.context.scene.render.resolution_x)
|
||||||
|
/ 4
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
y = camera.data.ortho_scale / 4
|
y = camera.data.ortho_scale / 4
|
||||||
y_offset = camera.matrix_world.to_quaternion() @ Vector((0, y, 0))
|
y_offset = camera.matrix_world.to_quaternion() @ Vector((0, y, 0))
|
||||||
|
|||||||
@@ -399,7 +399,8 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
# https://stackoverflow.com/questions/36018627/sorting-child-elements-with-lxml-based-on-attribute-value
|
# https://stackoverflow.com/questions/36018627/sorting-child-elements-with-lxml-based-on-attribute-value
|
||||||
group = root.find("{http://www.w3.org/2000/svg}g")
|
group = root.find("{http://www.w3.org/2000/svg}g")
|
||||||
# group[:] = sorted(group, key=lambda e : "projection" in e.get("class"))
|
# group[:] = sorted(group, key=lambda e : "projection" in e.get("class"))
|
||||||
group[:] = reversed(group)
|
if group:
|
||||||
|
group[:] = reversed(group)
|
||||||
|
|
||||||
def canonicalise_class_name(self, name):
|
def canonicalise_class_name(self, name):
|
||||||
return re.sub("[^0-9a-zA-Z]+", "", name)
|
return re.sub("[^0-9a-zA-Z]+", "", name)
|
||||||
@@ -520,7 +521,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
return "mat-" + str(element.id())
|
return "mat-" + str(element.id())
|
||||||
|
|
||||||
|
|
||||||
class AddAnnotation(bpy.types.Operator):
|
class AddAnnotation(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.add_annotation"
|
bl_idname = "bim.add_annotation"
|
||||||
bl_label = "Add Annotation"
|
bl_label = "Add Annotation"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
@@ -531,56 +532,11 @@ class AddAnnotation(bpy.types.Operator):
|
|||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return IfcStore.get_file() and context.scene.camera
|
return IfcStore.get_file() and context.scene.camera
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
context.scene.DocProperties.should_draw_decorations = True
|
drawing = tool.Ifc.get_entity(context.scene.camera)
|
||||||
subcontext = ifcopenshell.util.representation.get_context(
|
if not drawing:
|
||||||
IfcStore.get_file(), "Plan", "Annotation", context.scene.camera.data.BIMCameraProperties.target_view
|
return
|
||||||
)
|
core.add_annotation(tool.Ifc, tool.Collector, tool.Drawing, drawing=drawing, object_type=self.object_type)
|
||||||
if not subcontext:
|
|
||||||
return {"FINISHED"}
|
|
||||||
# TODO: reimplement bulk smart tagging
|
|
||||||
# if self.data_type == "text":
|
|
||||||
# if context.selected_objects:
|
|
||||||
# for selected_object in context.selected_objects:
|
|
||||||
# obj = annotation.Annotator.add_text(context, related_element=selected_object)
|
|
||||||
# else:
|
|
||||||
# obj = annotation.Annotator.add_text(context)
|
|
||||||
# else:
|
|
||||||
obj = annotation.Annotator.get_annotation_obj(self.object_type, self.data_type, context)
|
|
||||||
if self.object_type == "BREAKLINE":
|
|
||||||
obj = annotation.Annotator.add_plane_to_annotation(obj, context)
|
|
||||||
elif self.object_type != "TEXT":
|
|
||||||
obj = annotation.Annotator.add_line_to_annotation(obj, context)
|
|
||||||
|
|
||||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
||||||
ifc_representation_class = ""
|
|
||||||
if self.object_type == "TEXT":
|
|
||||||
ifc_representation_class = "IfcTextLiteral"
|
|
||||||
elif self.object_type == "TEXT_LEADER":
|
|
||||||
ifc_representation_class = "IfcGeometricCurveSet/IfcTextLiteral"
|
|
||||||
bpy.ops.bim.assign_class(
|
|
||||||
obj=obj.name,
|
|
||||||
ifc_class="IfcAnnotation",
|
|
||||||
context_id=subcontext.id(),
|
|
||||||
ifc_representation_class=ifc_representation_class,
|
|
||||||
)
|
|
||||||
element = tool.Ifc.get_entity(obj)
|
|
||||||
element.ObjectType = self.object_type
|
|
||||||
camera = tool.Ifc.get_entity(context.scene.camera)
|
|
||||||
group = [r for r in camera.HasAssignments if r.is_a("IfcRelAssignsToGroup")][0].RelatingGroup
|
|
||||||
bpy.ops.bim.assign_group(product=obj.name, group=group.id())
|
|
||||||
else:
|
|
||||||
bpy.ops.bim.update_representation(obj=obj.name)
|
|
||||||
|
|
||||||
bpy.ops.object.select_all(action="DESELECT")
|
|
||||||
context.view_layer.objects.active = obj
|
|
||||||
obj.select_set(True)
|
|
||||||
if obj.data:
|
|
||||||
bpy.ops.object.mode_set(mode="EDIT")
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddSheet(bpy.types.Operator, Operator):
|
class AddSheet(bpy.types.Operator, Operator):
|
||||||
|
|||||||
@@ -312,7 +312,6 @@ class BIM_PT_text(Panel):
|
|||||||
class BIM_PT_annotation_utilities(Panel):
|
class BIM_PT_annotation_utilities(Panel):
|
||||||
bl_idname = "BIM_PT_annotation_utilities"
|
bl_idname = "BIM_PT_annotation_utilities"
|
||||||
bl_label = "Annotation"
|
bl_label = "Annotation"
|
||||||
bl_options = {"DEFAULT_CLOSED"}
|
|
||||||
bl_space_type = "VIEW_3D"
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = "UI"
|
bl_region_type = "UI"
|
||||||
bl_category = "BIM Documentation"
|
bl_category = "BIM Documentation"
|
||||||
@@ -322,13 +321,6 @@ class BIM_PT_annotation_utilities(Panel):
|
|||||||
|
|
||||||
self.props = context.scene.DocProperties
|
self.props = context.scene.DocProperties
|
||||||
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.operator("bim.clean_wireframes")
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.operator("bim.add_grid")
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.operator("bim.add_sections_annotations")
|
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
op = row.operator("bim.add_annotation", text="Dim", icon="ARROW_LEFTRIGHT")
|
op = row.operator("bim.add_annotation", text="Dim", icon="ARROW_LEFTRIGHT")
|
||||||
op.object_type = "DIMENSION"
|
op.object_type = "DIMENSION"
|
||||||
@@ -369,8 +361,8 @@ class BIM_PT_annotation_utilities(Panel):
|
|||||||
op.object_type = "MISC"
|
op.object_type = "MISC"
|
||||||
op.data_type = "mesh"
|
op.data_type = "mesh"
|
||||||
|
|
||||||
layout.prop(self.props, "should_draw_decorations")
|
row = layout.row(align=True)
|
||||||
layout.prop(self.props, "decorations_colour")
|
row.prop(self.props, "should_draw_decorations", text="Viewport Annotations")
|
||||||
|
|
||||||
|
|
||||||
class BIM_UL_drawinglist(bpy.types.UIList):
|
class BIM_UL_drawinglist(bpy.types.UIList):
|
||||||
|
|||||||
@@ -47,3 +47,5 @@ class BIM_PT_misc_utilities(bpy.types.Panel):
|
|||||||
row.operator("bim.get_connected_system_elements")
|
row.operator("bim.get_connected_system_elements")
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator("bim.draw_system_arrows")
|
row.operator("bim.draw_system_arrows")
|
||||||
|
row = layout.row()
|
||||||
|
row.operator("bim.clean_wireframes")
|
||||||
|
|||||||
@@ -152,6 +152,9 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
|||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(context.scene.BIMModelProperties, "occurrence_name_function")
|
row.prop(context.scene.BIMModelProperties, "occurrence_name_function")
|
||||||
|
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(context.scene.DocProperties, "decorations_colour")
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(context.scene.BIMProperties, "schema_dir")
|
row.prop(context.scene.BIMProperties, "schema_dir")
|
||||||
row.operator("bim.select_schema_dir", icon="FILE_FOLDER", text="")
|
row.operator("bim.select_schema_dir", icon="FILE_FOLDER", text="")
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ def add_drawing(ifc, collector, drawing, target_view=None, location_hint=None):
|
|||||||
ifc_representation_class=None,
|
ifc_representation_class=None,
|
||||||
)
|
)
|
||||||
group = ifc.run("group.add_group")
|
group = ifc.run("group.add_group")
|
||||||
ifc.run("group.edit_group", group=group, attributes={"Name": drawing_name})
|
ifc.run("group.edit_group", group=group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"})
|
||||||
ifc.run("group.assign_group", group=group, product=element)
|
ifc.run("group.assign_group", group=group, product=element)
|
||||||
collector.assign(camera)
|
collector.assign(camera)
|
||||||
pset = ifc.run("pset.add_pset", product=element, name="EPset_Drawing")
|
pset = ifc.run("pset.add_pset", product=element, name="EPset_Drawing")
|
||||||
@@ -137,3 +137,24 @@ def update_drawing_name(ifc, drawing_tool, drawing=None, name=None):
|
|||||||
if drawing_tool.get_name(group) != name:
|
if drawing_tool.get_name(group) != name:
|
||||||
ifc.run("attribute.edit_attributes", product=group, attributes={"Name": name})
|
ifc.run("attribute.edit_attributes", product=group, attributes={"Name": name})
|
||||||
drawing_tool.set_drawing_collection_name(group, drawing_tool.get_drawing_collection(drawing))
|
drawing_tool.set_drawing_collection_name(group, drawing_tool.get_drawing_collection(drawing))
|
||||||
|
|
||||||
|
|
||||||
|
def add_annotation(ifc, collector, drawing_tool, drawing=None, object_type=None):
|
||||||
|
context = drawing_tool.get_annotation_context(drawing_tool.get_drawing_target_view(drawing))
|
||||||
|
if not context:
|
||||||
|
return
|
||||||
|
drawing_tool.show_decorations()
|
||||||
|
obj = drawing_tool.create_annotation_object(object_type)
|
||||||
|
element = ifc.get_entity(obj)
|
||||||
|
if not element:
|
||||||
|
element = drawing_tool.run_root_assign_class(
|
||||||
|
obj=obj,
|
||||||
|
ifc_class="IfcAnnotation",
|
||||||
|
predefined_type=object_type,
|
||||||
|
should_add_representation=True,
|
||||||
|
context=context,
|
||||||
|
ifc_representation_class=drawing_tool.get_ifc_representation_class(object_type),
|
||||||
|
)
|
||||||
|
ifc.run("group.assign_group", group=drawing_tool.get_drawing_group(drawing), product=element)
|
||||||
|
collector.assign(obj)
|
||||||
|
drawing_tool.enable_editing(obj)
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ class Debug:
|
|||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Drawing:
|
class Drawing:
|
||||||
|
def create_annotation_object(cls, object_type): pass
|
||||||
def create_camera(cls, name, matrix): pass
|
def create_camera(cls, name, matrix): pass
|
||||||
def create_svg_sheet(cls, document, titleblock): pass
|
def create_svg_sheet(cls, document, titleblock): pass
|
||||||
def delete_collection(cls, collection): pass
|
def delete_collection(cls, collection): pass
|
||||||
@@ -143,6 +144,7 @@ class Drawing:
|
|||||||
def disable_editing_sheets(cls): pass
|
def disable_editing_sheets(cls): pass
|
||||||
def disable_editing_text(cls, obj): pass
|
def disable_editing_text(cls, obj): pass
|
||||||
def disable_editing_text_product(cls, obj): pass
|
def disable_editing_text_product(cls, obj): pass
|
||||||
|
def enable_editing(cls, obj): pass
|
||||||
def enable_editing_drawings(cls): pass
|
def enable_editing_drawings(cls): pass
|
||||||
def enable_editing_sheets(cls): pass
|
def enable_editing_sheets(cls): pass
|
||||||
def enable_editing_text(cls, obj): pass
|
def enable_editing_text(cls, obj): pass
|
||||||
@@ -152,10 +154,14 @@ class Drawing:
|
|||||||
def export_text_literal_attributes(cls, obj): pass
|
def export_text_literal_attributes(cls, obj): pass
|
||||||
def generate_drawing_matrix(cls, target_view, location_hint): pass
|
def generate_drawing_matrix(cls, target_view, location_hint): pass
|
||||||
def generate_sheet_identification(cls): pass
|
def generate_sheet_identification(cls): pass
|
||||||
|
def get_annotation_context(cls, target_view): pass
|
||||||
def get_body_context(cls): pass
|
def get_body_context(cls): pass
|
||||||
def get_drawing_collection(cls, drawing): pass
|
def get_drawing_collection(cls, drawing): pass
|
||||||
def get_drawing_group(cls, drawing): pass
|
def get_drawing_group(cls, drawing): pass
|
||||||
|
def get_drawing_target_view(cls, drawing): pass
|
||||||
def get_group_elements(cls, group): pass
|
def get_group_elements(cls, group): pass
|
||||||
|
def get_ifc_representation_class(cls, object_type): pass
|
||||||
|
def get_name(cls, element): pass
|
||||||
def get_sheet_filename(cls, document): pass
|
def get_sheet_filename(cls, document): pass
|
||||||
def get_text_literal(cls, obj): pass
|
def get_text_literal(cls, obj): pass
|
||||||
def get_text_product(cls, element): pass
|
def get_text_product(cls, element): pass
|
||||||
@@ -165,6 +171,8 @@ class Drawing:
|
|||||||
def import_text_product(cls, obj): pass
|
def import_text_product(cls, obj): pass
|
||||||
def open_svg(cls, filepath): pass
|
def open_svg(cls, filepath): pass
|
||||||
def run_root_assign_class(cls, obj=None, ifc_class=None, predefined_type=None, should_add_representation=True, context=None, ifc_representation_class=None): pass
|
def run_root_assign_class(cls, obj=None, ifc_class=None, predefined_type=None, should_add_representation=True, context=None, ifc_representation_class=None): pass
|
||||||
|
def set_drawing_collection_name(cls, group, collection): pass
|
||||||
|
def show_decorations(cls): pass
|
||||||
def update_text_value(cls, obj): pass
|
def update_text_value(cls, obj): pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -125,9 +125,9 @@ class Collector(blenderbim.core.tool.Collector):
|
|||||||
return axes_col[0]
|
return axes_col[0]
|
||||||
return bpy.data.collections.new(axes)
|
return bpy.data.collections.new(axes)
|
||||||
|
|
||||||
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
if element.is_a("IfcAnnotation"):
|
||||||
for rel in element.HasAssignments or []:
|
for rel in element.HasAssignments or []:
|
||||||
if rel.is_a("IfcRelAssignsToGroup"):
|
if rel.is_a("IfcRelAssignsToGroup") and rel.RelatingGroup.ObjectType == "DRAWING":
|
||||||
name = "IfcGroup/" + rel.RelatingGroup.Name
|
name = "IfcGroup/" + rel.RelatingGroup.Name
|
||||||
return bpy.data.collections.get(name, bpy.data.collections.new(name))
|
return bpy.data.collections.get(name, bpy.data.collections.new(name))
|
||||||
|
|
||||||
@@ -162,8 +162,10 @@ class Collector(blenderbim.core.tool.Collector):
|
|||||||
if grid_obj:
|
if grid_obj:
|
||||||
return bpy.data.collections.get(grid_obj.name)
|
return bpy.data.collections.get(grid_obj.name)
|
||||||
|
|
||||||
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
if element.is_a("IfcAnnotation"):
|
||||||
return cls._create_project_child_collection("Views")
|
for rel in element.HasAssignments or []:
|
||||||
|
if rel.is_a("IfcRelAssignsToGroup") and rel.RelatingGroup.ObjectType == "DRAWING":
|
||||||
|
return cls._create_project_child_collection("Views")
|
||||||
|
|
||||||
if element.is_a("IfcStructuralItem"):
|
if element.is_a("IfcStructuralItem"):
|
||||||
return cls._create_project_child_collection("StructuralItems")
|
return cls._create_project_child_collection("StructuralItems")
|
||||||
|
|||||||
@@ -25,9 +25,31 @@ import blenderbim.core.tool
|
|||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
import blenderbim.bim.module.drawing.sheeter as sheeter
|
import blenderbim.bim.module.drawing.sheeter as sheeter
|
||||||
|
import blenderbim.bim.module.drawing.annotation as annotation
|
||||||
|
|
||||||
|
|
||||||
class Drawing(blenderbim.core.tool.Drawing):
|
class Drawing(blenderbim.core.tool.Drawing):
|
||||||
|
@classmethod
|
||||||
|
def create_annotation_object(cls, object_type):
|
||||||
|
data_type = {
|
||||||
|
"DIMENSION": "curve",
|
||||||
|
"EQUAL_DIMENSION": "curve",
|
||||||
|
"TEXT": "empty",
|
||||||
|
"TEXT_LEADER": "curve",
|
||||||
|
"STAIR_ARROW": "curve",
|
||||||
|
"HIDDEN_LINE": "mesh",
|
||||||
|
"PLAN_LEVEL": "curve",
|
||||||
|
"SECTION_LEVEL": "curve",
|
||||||
|
"BREAKLINE": "mesh",
|
||||||
|
"MISC": "mesh",
|
||||||
|
}[object_type]
|
||||||
|
obj = annotation.Annotator.get_annotation_obj(object_type, data_type)
|
||||||
|
if object_type == "BREAKLINE":
|
||||||
|
obj = annotation.Annotator.add_plane_to_annotation(obj)
|
||||||
|
elif object_type != "TEXT":
|
||||||
|
obj = annotation.Annotator.add_line_to_annotation(obj)
|
||||||
|
return obj
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_camera(cls, name, matrix):
|
def create_camera(cls, name, matrix):
|
||||||
camera = bpy.data.objects.new(name, bpy.data.cameras.new(name))
|
camera = bpy.data.objects.new(name, bpy.data.cameras.new(name))
|
||||||
@@ -77,6 +99,14 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
def disable_editing_text_product(cls, obj):
|
def disable_editing_text_product(cls, obj):
|
||||||
obj.BIMTextProperties.is_editing_product = False
|
obj.BIMTextProperties.is_editing_product = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def enable_editing(cls, obj):
|
||||||
|
bpy.ops.object.select_all(action="DESELECT")
|
||||||
|
bpy.context.view_layer.objects.active = obj
|
||||||
|
obj.select_set(True)
|
||||||
|
if obj.data:
|
||||||
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def enable_editing_drawings(cls):
|
def enable_editing_drawings(cls):
|
||||||
bpy.context.scene.DocProperties.is_editing_drawings = True
|
bpy.context.scene.DocProperties.is_editing_drawings = True
|
||||||
@@ -116,6 +146,10 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
def export_text_literal_attributes(cls, obj):
|
def export_text_literal_attributes(cls, obj):
|
||||||
return blenderbim.bim.helper.export_attributes(obj.BIMTextProperties.attributes)
|
return blenderbim.bim.helper.export_attributes(obj.BIMTextProperties.attributes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_annotation_context(cls, target_view):
|
||||||
|
return ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Plan", "Annotation", target_view)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_body_context(cls):
|
def get_body_context(cls):
|
||||||
return ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
return ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||||
@@ -131,11 +165,23 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
if rel.is_a("IfcRelAssignsToGroup"):
|
if rel.is_a("IfcRelAssignsToGroup"):
|
||||||
return rel.RelatingGroup
|
return rel.RelatingGroup
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_drawing_target_view(cls, drawing):
|
||||||
|
return ifcopenshell.util.element.get_psets(drawing)["EPset_Drawing"]["TargetView"]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_group_elements(cls, group):
|
def get_group_elements(cls, group):
|
||||||
for rel in group.IsGroupedBy or []:
|
for rel in group.IsGroupedBy or []:
|
||||||
return rel.RelatedObjects
|
return rel.RelatedObjects
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_ifc_representation_class(cls, object_type):
|
||||||
|
if object_type == "TEXT":
|
||||||
|
return "IfcTextLiteral"
|
||||||
|
elif object_type == "TEXT_LEADER":
|
||||||
|
return "IfcGeometricCurveSet/IfcTextLiteral"
|
||||||
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_name(cls, element):
|
def get_name(cls, element):
|
||||||
return element.Name
|
return element.Name
|
||||||
@@ -286,6 +332,10 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
def set_drawing_collection_name(cls, group, collection):
|
def set_drawing_collection_name(cls, group, collection):
|
||||||
collection.name = f"IfcGroup/{group.Name}"
|
collection.name = f"IfcGroup/{group.Name}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def show_decorations(cls):
|
||||||
|
bpy.context.scene.DocProperties.should_draw_decorations = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_text_value(cls, obj):
|
def update_text_value(cls, obj):
|
||||||
element = cls.get_text_literal(obj)
|
element = cls.get_text_literal(obj)
|
||||||
|
|||||||
@@ -198,3 +198,31 @@ class TestUpdateDrawingName:
|
|||||||
drawing.get_drawing_collection("drawing").should_be_called().will_return("collection")
|
drawing.get_drawing_collection("drawing").should_be_called().will_return("collection")
|
||||||
drawing.set_drawing_collection_name("group", "collection").should_be_called()
|
drawing.set_drawing_collection_name("group", "collection").should_be_called()
|
||||||
subject.update_drawing_name(ifc, drawing, drawing="drawing", name="name")
|
subject.update_drawing_name(ifc, drawing, drawing="drawing", name="name")
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddAnnotation:
|
||||||
|
def test_run(self, ifc, collector, drawing):
|
||||||
|
drawing.show_decorations().should_be_called()
|
||||||
|
drawing.get_drawing_target_view("drawing").should_be_called().will_return("target_view")
|
||||||
|
drawing.get_annotation_context("target_view").should_be_called().will_return("context")
|
||||||
|
drawing.create_annotation_object("object_type").should_be_called().will_return("obj")
|
||||||
|
ifc.get_entity("obj").should_be_called().will_return(None)
|
||||||
|
drawing.get_ifc_representation_class("object_type").should_be_called().will_return("ifc_representation_class")
|
||||||
|
drawing.run_root_assign_class(
|
||||||
|
obj="obj",
|
||||||
|
ifc_class="IfcAnnotation",
|
||||||
|
predefined_type="object_type",
|
||||||
|
should_add_representation=True,
|
||||||
|
context="context",
|
||||||
|
ifc_representation_class="ifc_representation_class",
|
||||||
|
).should_be_called().will_return("element")
|
||||||
|
drawing.get_drawing_group("drawing").should_be_called().will_return("group")
|
||||||
|
ifc.run("group.assign_group", group="group", product="element").should_be_called()
|
||||||
|
collector.assign("obj").should_be_called()
|
||||||
|
drawing.enable_editing("obj").should_be_called()
|
||||||
|
subject.add_annotation(ifc, collector, drawing, drawing="drawing", object_type="object_type")
|
||||||
|
|
||||||
|
def test_do_not_add_without_an_annotation_context(self, ifc, collector, drawing):
|
||||||
|
drawing.get_drawing_target_view("drawing").should_be_called().will_return("target_view")
|
||||||
|
drawing.get_annotation_context("target_view").should_be_called().will_return(None)
|
||||||
|
subject.add_annotation(ifc, collector, drawing, drawing="drawing", object_type="object_type")
|
||||||
|
|||||||
@@ -221,6 +221,20 @@ class TestAssign(NewFile):
|
|||||||
element = tool.Ifc.get().createIfcAnnotation(ObjectType="DRAWING")
|
element = tool.Ifc.get().createIfcAnnotation(ObjectType="DRAWING")
|
||||||
tool.Ifc.link(element, element_obj)
|
tool.Ifc.link(element, element_obj)
|
||||||
group = ifcopenshell.api.run("group.add_group", tool.Ifc.get())
|
group = ifcopenshell.api.run("group.add_group", tool.Ifc.get())
|
||||||
|
group.ObjectType = "DRAWING"
|
||||||
|
ifcopenshell.api.run("group.assign_group", tool.Ifc.get(), product=element, group=group)
|
||||||
|
subject.assign(element_obj)
|
||||||
|
assert element_obj.users_collection[0].name == "IfcGroup/Unnamed"
|
||||||
|
assert bpy.data.collections.get("Views").children.get("IfcGroup/Unnamed")
|
||||||
|
assert bpy.data.collections.get("IfcProject/My Project").children.get("Views")
|
||||||
|
|
||||||
|
def test_in_decomposition_mode_annotations_are_placed_in_a_group_in_a_views_collection(self):
|
||||||
|
bpy.ops.bim.create_project()
|
||||||
|
element_obj = bpy.data.objects.new("IfcAnnotation/Name", None)
|
||||||
|
element = tool.Ifc.get().createIfcAnnotation()
|
||||||
|
tool.Ifc.link(element, element_obj)
|
||||||
|
group = ifcopenshell.api.run("group.add_group", tool.Ifc.get())
|
||||||
|
group.ObjectType = "DRAWING"
|
||||||
ifcopenshell.api.run("group.assign_group", tool.Ifc.get(), product=element, group=group)
|
ifcopenshell.api.run("group.assign_group", tool.Ifc.get(), product=element, group=group)
|
||||||
subject.assign(element_obj)
|
subject.assign(element_obj)
|
||||||
assert element_obj.users_collection[0].name == "IfcGroup/Unnamed"
|
assert element_obj.users_collection[0].name == "IfcGroup/Unnamed"
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ class TestImplementsTool(NewFile):
|
|||||||
assert isinstance(subject(), blenderbim.core.tool.Drawing)
|
assert isinstance(subject(), blenderbim.core.tool.Drawing)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCreateAnnotationObject(NewFile):
|
||||||
|
def test_nothing(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestCreateCamera(NewFile):
|
class TestCreateCamera(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
obj = subject.create_camera("Name", mathutils.Matrix())
|
obj = subject.create_camera("Name", mathutils.Matrix())
|
||||||
@@ -105,6 +110,14 @@ class TestDisableEditingTextProduct(NewFile):
|
|||||||
assert obj.BIMTextProperties.is_editing_product == False
|
assert obj.BIMTextProperties.is_editing_product == False
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableEditing(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
obj = bpy.data.objects.new("Object", None)
|
||||||
|
bpy.context.scene.collection.objects.link(obj)
|
||||||
|
subject.enable_editing(obj)
|
||||||
|
assert obj in bpy.context.selected_objects
|
||||||
|
|
||||||
|
|
||||||
class TestEnableEditingDrawings(NewFile):
|
class TestEnableEditingDrawings(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
bpy.context.scene.DocProperties.is_editing_drawings = False
|
bpy.context.scene.DocProperties.is_editing_drawings = False
|
||||||
@@ -174,6 +187,16 @@ class TestExportTextLiteralAttributes(NewFile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetAnnotationContext(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
context = ifc.createIfcGeometricRepresentationSubContext(
|
||||||
|
ContextType="Plan", ContextIdentifier="Annotation", TargetView="PLAN_VIEW"
|
||||||
|
)
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
assert subject.get_annotation_context("PLAN_VIEW") == context
|
||||||
|
|
||||||
|
|
||||||
class TestGetBodyContext(NewFile):
|
class TestGetBodyContext(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -207,6 +230,16 @@ class TestGetDrawingGroup(NewFile):
|
|||||||
assert subject.get_drawing_group(element) == group
|
assert subject.get_drawing_group(element) == group
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetDrawingTargetView(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
element = ifc.createIfcAnnotation()
|
||||||
|
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="EPset_Drawing")
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"TargetView": "PLAN_VIEW"})
|
||||||
|
assert subject.get_drawing_target_view(element) == "PLAN_VIEW"
|
||||||
|
|
||||||
|
|
||||||
class TestGetGroupElements(NewFile):
|
class TestGetGroupElements(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -217,6 +250,13 @@ class TestGetGroupElements(NewFile):
|
|||||||
assert subject.get_group_elements(group) == (element,)
|
assert subject.get_group_elements(group) == (element,)
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetIfcRepresentationClass(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
assert subject.get_ifc_representation_class("TEXT") == "IfcTextLiteral"
|
||||||
|
assert subject.get_ifc_representation_class("TEXT_LEADER") == "IfcGeometricCurveSet/IfcTextLiteral"
|
||||||
|
assert subject.get_ifc_representation_class("FOOBAR") == ""
|
||||||
|
|
||||||
|
|
||||||
class TestGetName(NewFile):
|
class TestGetName(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -451,6 +491,13 @@ class TestSetDrawingCollectionName(NewFile):
|
|||||||
assert collection.name == "IfcGroup/Foobaz"
|
assert collection.name == "IfcGroup/Foobaz"
|
||||||
|
|
||||||
|
|
||||||
|
class TestShowDecorations(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.DocProperties.should_draw_decorations = False
|
||||||
|
subject.show_decorations()
|
||||||
|
assert bpy.context.scene.DocProperties.should_draw_decorations is True
|
||||||
|
|
||||||
|
|
||||||
class TestUpdateTextValue(NewFile):
|
class TestUpdateTextValue(NewFile):
|
||||||
def test_updating_arbitrary_strings(self):
|
def test_updating_arbitrary_strings(self):
|
||||||
TestGetTextLiteral().test_run()
|
TestGetTextLiteral().test_run()
|
||||||
|
|||||||
Reference in New Issue
Block a user