Old annotation systems now creates IFC elements again. Also text and misc annotations now work again with new system. See #1153.

This commit is contained in:
Dion Moult
2021-05-16 18:26:48 +10:00
parent e0b3a87fdb
commit f2352e9a17
8 changed files with 106 additions and 42 deletions
+2 -2
View File
@@ -14,14 +14,14 @@ def mode_callback(obj, data):
if (
obj.mode != "EDIT"
or not obj.data
or not isinstance(obj.data, bpy.types.Mesh)
or not isinstance(obj.data, (bpy.types.Mesh, bpy.types.Curve, bpy.types.TextCurve))
or not obj.BIMObjectProperties.ifc_definition_id
or not bpy.context.scene.BIMProjectProperties.is_authoring
):
return
if obj.data.BIMMeshProperties.ifc_definition_id:
representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
if representation.RepresentationType == "Tessellation" or representation.RepresentationType == "Brep":
if representation.RepresentationType in ["Tessellation", "Brep", "Annotation2D"]:
IfcStore.edited_objs.add(obj.name)
elif IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).is_a("IfcGridAxis"):
IfcStore.edited_objs.add(obj.name)
@@ -17,9 +17,9 @@ class Annotator:
@staticmethod
def add_text(related_element=None):
curve = bpy.data.curves.new(type="FONT", name="Plan/Annotation/PLAN_VIEW/Text")
curve = bpy.data.curves.new(type="FONT", name="Text")
curve.body = "TEXT"
obj = bpy.data.objects.new("IfcAnnotation/Text", curve)
obj = bpy.data.objects.new("Text", curve)
obj.matrix_world = bpy.context.scene.camera.matrix_world
if related_element is None:
location, _, _, _ = Annotator.get_placeholder_coords()
@@ -138,12 +138,12 @@ class Annotator:
if name in obj.name:
return obj
if data_type == "mesh":
data = bpy.data.meshes.new("Plan/Annotation/PLAN_VIEW/" + name)
data = bpy.data.meshes.new(name)
elif data_type == "curve":
data = bpy.data.curves.new("Plan/Annotation/PLAN_VIEW/" + name, type="CURVE")
data = bpy.data.curves.new(name, type="CURVE")
data.dimensions = "3D"
data.resolution_u = 2
obj = bpy.data.objects.new("IfcAnnotation/" + name, data)
obj = bpy.data.objects.new(name, data)
collection.objects.link(obj)
return obj
@@ -164,4 +164,4 @@ class Annotator:
return (camera.location + z_offset,
camera.location + z_offset + y_offset,
camera.location + z_offset + x_offset,
camera.location + z_offset + x_offset + y_offset)
camera.location + z_offset + x_offset + y_offset)
@@ -3,6 +3,7 @@ import bpy
import json
import subprocess
import webbrowser
import ifcopenshell.util.representation
import blenderbim.bim.module.drawing.svgwriter as svgwriter
import blenderbim.bim.module.drawing.annotation as annotation
from mathutils import Vector, Matrix, Euler, geometry
@@ -13,6 +14,7 @@ from ifcopenshell.api.pset.data import Data as PsetData
cwd = os.path.dirname(os.path.realpath(__file__))
class AddDrawing(bpy.types.Operator):
bl_idname = "bim.add_drawing"
bl_label = "Add Drawing"
@@ -69,7 +71,7 @@ class CreateDrawing(bpy.types.Operator):
def combine_svgs(self, context, base, annotation):
# Hacky :)
svg_path = context.scene.BIMProperties.ifc_file[0:-4] + ".svg"
with open(svg_path, 'w') as outfile:
with open(svg_path, "w") as outfile:
with open(base) as infile:
for line in infile:
if "</svg>" in line:
@@ -197,6 +199,11 @@ class AddAnnotation(bpy.types.Operator):
def execute(self, context):
if not bpy.context.scene.camera:
return {"FINISHED"}
subcontext = ifcopenshell.util.representation.get_context(
IfcStore.get_file(), "Plan", "Annotation", context.scene.camera.data.BIMCameraProperties.target_view
)
if not subcontext:
return {"FINISHED"}
if self.data_type == "text":
if bpy.context.selected_objects:
for selected_object in bpy.context.selected_objects:
@@ -209,7 +216,14 @@ class AddAnnotation(bpy.types.Operator):
obj = annotation.Annotator.add_plane_to_annotation(obj)
else:
obj = annotation.Annotator.add_line_to_annotation(obj)
if not obj.BIMObjectProperties.ifc_definition_id:
bpy.ops.bim.assign_class(obj=obj.name, ifc_class="IfcAnnotation", context_id=subcontext.id())
else:
bpy.ops.bim.update_mesh_representation(obj=obj.name)
bpy.ops.object.select_all(action="DESELECT")
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.mode_set(mode="EDIT")
return {"FINISHED"}
@@ -3,6 +3,7 @@ import numpy as np
import ifcopenshell
import ifcopenshell.util.unit
import ifcopenshell.util.element
import ifcopenshell.util.representation
import logging
import ifcopenshell.api
from blenderbim.bim.ifc import IfcStore
@@ -105,7 +106,7 @@ 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")
old_box = ifcopenshell.util.representation.get_representation(product, "Model", "Box", "MODEL_VIEW")
if (
box_context_id
and context_of_items.ContextType == "Model"
@@ -358,7 +359,7 @@ class UpdateMeshRepresentation(bpy.types.Operator):
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
box_context_id = get_context_id("Model", "Box", "MODEL_VIEW")
old_box = ifcopenshell.util.element.get_representation(product, "Model", "Box", "MODEL_VIEW")
old_box = ifcopenshell.util.representation.get_representation(product, "Model", "Box", "MODEL_VIEW")
if (
box_context_id
and old_box
+2 -1
View File
@@ -11,6 +11,7 @@ import ifcopenshell
import ifcopenshell.util.selector
import ifcopenshell.util.geolocation
import ifcopenshell.util.element
import ifcopenshell.util.representation
import ifcopenshell.util.schema
import numpy as np
from . import export_ifc
@@ -617,7 +618,7 @@ class CutSection(bpy.types.Operator):
if not element.Representation:
return False
for representation in element.Representation.Representations:
if ifcopenshell.util.element.is_representation_of_context(
if ifcopenshell.util.representation.is_representation_of_context(
representation, "Plan", "Annotation", camera.data.BIMCameraProperties.target_view
):
return True
@@ -48,7 +48,7 @@ class Usecase:
for modifier in self.settings["blender_object"].modifiers:
if modifier.type == "BOOLEAN":
modifier.show_viewport = False
if self.settings["should_force_triangulation"]:
mesh = self.settings["blender_object"].evaluated_get(bpy.context.evaluated_depsgraph_get()).to_mesh()
bm = bmesh.new()
@@ -119,6 +119,41 @@ class Usecase:
elif self.settings["context"].ContextIdentifier == "SurveyPoints":
pass
def create_text_representation(self):
return self.file.createIfcShapeRepresentation(
self.settings["context"],
self.settings["context"].ContextIdentifier,
"Annotation2D",
[self.create_text()],
)
def create_text(self):
text = self.settings["geometry"]
if text.align_y in ["TOP_BASELINE", "BOTTOM_BASELINE", "BOTTOM"]:
y = "bottom"
elif text.align_y == "CENTER":
y = "middle"
elif text.align_y == "TOP":
y = "top"
if text.align_x == "LEFT":
x = "left"
elif text.align_x == "CENTER":
x = "middle"
elif text.align_x == "RIGHT":
x = "right"
origin = self.file.createIfcAxis2Placement3D(
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
self.file.createIfcDirection((0.0, 0.0, 1.0)),
self.file.createIfcDirection((1.0, 0.0, 0.0)),
)
# TODO: Planar extent right now is wrong ...
return self.file.createIfcTextLiteralWithExtent(
text.body, origin, "RIGHT", self.file.createIfcPlanarExtent(1000, 1000), f"{y}-{x}"
)
def create_variable_representation(self):
if self.settings["is_wireframe"]:
return self.create_wireframe_representation()
@@ -108,24 +108,6 @@ def replace_attribute(element, old, new):
element[i] = new_attribute
def is_representation_of_context(representation, context, subcontext=None, target_view=None):
if target_view is not None:
return (
representation.ContextOfItems.is_a("IfcGeometricRepresentationSubContext")
and representation.ContextOfItems.TargetView == target_view
and representation.ContextOfItems.ContextIdentifier == subcontext
and representation.ContextOfItems.ContextType == context
)
elif subcontext is not None:
return (
representation.ContextOfItems.is_a("IfcGeometricRepresentationSubContext")
and representation.ContextOfItems.ContextIdentifier == subcontext
and representation.ContextOfItems.ContextType == context
)
elif representation.ContextOfItems.ContextType == context:
return True
def remove_deep(ifc_file, element):
# @todo maybe some sort of try-finally mechanism.
ifc_file.batch()
@@ -159,14 +141,3 @@ def copy_deep(ifc_file, element):
attribute[j] = copy_deep(ifc_file, item)
new[i] = attribute
return new
def get_representation(element, context, subcontext=None, target_view=None):
if element.is_a("IfcProduct") and element.Representation:
for r in element.Representation.Representations:
if is_representation_of_context(r, context, subcontext, target_view):
return r
elif element.is_a("IfcTypeProduct") and element.RepresentationMaps:
for r in element.RepresentationMaps:
if is_representation_of_context(r.MappedRepresentation, context, subcontext, target_view):
return r.MappedRepresentation
@@ -0,0 +1,42 @@
def get_context(ifc_file, context, subcontext=None, target_view=None):
if subcontext or target_view:
elements = ifc_file.by_type("IfcGeometricRepresentationSubContext")
else:
elements = ifc_file.by_type("IfcGeometricRepresentationContext", include_subtypes=False)
for element in elements:
if context and element.ContextType != context:
continue
if subcontext and getattr(element, "ContextIdentifier") != subcontext:
continue
if target_view and getattr(element, "TargetView") != target_view:
continue
return element
def is_representation_of_context(representation, context, subcontext=None, target_view=None):
if target_view is not None:
return (
representation.ContextOfItems.is_a("IfcGeometricRepresentationSubContext")
and representation.ContextOfItems.TargetView == target_view
and representation.ContextOfItems.ContextIdentifier == subcontext
and representation.ContextOfItems.ContextType == context
)
elif subcontext is not None:
return (
representation.ContextOfItems.is_a("IfcGeometricRepresentationSubContext")
and representation.ContextOfItems.ContextIdentifier == subcontext
and representation.ContextOfItems.ContextType == context
)
elif representation.ContextOfItems.ContextType == context:
return True
def get_representation(element, context, subcontext=None, target_view=None):
if element.is_a("IfcProduct") and element.Representation:
for r in element.Representation.Representations:
if is_representation_of_context(r, context, subcontext, target_view):
return r
elif element.is_a("IfcTypeProduct") and element.RepresentationMaps:
for r in element.RepresentationMaps:
if is_representation_of_context(r.MappedRepresentation, context, subcontext, target_view):
return r.MappedRepresentation