mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 23:36:20 +00:00
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:
@@ -14,14 +14,14 @@ def mode_callback(obj, data):
|
|||||||
if (
|
if (
|
||||||
obj.mode != "EDIT"
|
obj.mode != "EDIT"
|
||||||
or not obj.data
|
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 obj.BIMObjectProperties.ifc_definition_id
|
||||||
or not bpy.context.scene.BIMProjectProperties.is_authoring
|
or not bpy.context.scene.BIMProjectProperties.is_authoring
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
if obj.data.BIMMeshProperties.ifc_definition_id:
|
if obj.data.BIMMeshProperties.ifc_definition_id:
|
||||||
representation = IfcStore.get_file().by_id(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)
|
IfcStore.edited_objs.add(obj.name)
|
||||||
elif IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).is_a("IfcGridAxis"):
|
elif IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).is_a("IfcGridAxis"):
|
||||||
IfcStore.edited_objs.add(obj.name)
|
IfcStore.edited_objs.add(obj.name)
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ class Annotator:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_text(related_element=None):
|
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"
|
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
|
obj.matrix_world = bpy.context.scene.camera.matrix_world
|
||||||
if related_element is None:
|
if related_element is None:
|
||||||
location, _, _, _ = Annotator.get_placeholder_coords()
|
location, _, _, _ = Annotator.get_placeholder_coords()
|
||||||
@@ -138,12 +138,12 @@ class Annotator:
|
|||||||
if name in obj.name:
|
if name in obj.name:
|
||||||
return obj
|
return obj
|
||||||
if data_type == "mesh":
|
if data_type == "mesh":
|
||||||
data = bpy.data.meshes.new("Plan/Annotation/PLAN_VIEW/" + name)
|
data = bpy.data.meshes.new(name)
|
||||||
elif data_type == "curve":
|
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.dimensions = "3D"
|
||||||
data.resolution_u = 2
|
data.resolution_u = 2
|
||||||
obj = bpy.data.objects.new("IfcAnnotation/" + name, data)
|
obj = bpy.data.objects.new(name, data)
|
||||||
collection.objects.link(obj)
|
collection.objects.link(obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
@@ -164,4 +164,4 @@ class Annotator:
|
|||||||
return (camera.location + z_offset,
|
return (camera.location + z_offset,
|
||||||
camera.location + z_offset + y_offset,
|
camera.location + z_offset + y_offset,
|
||||||
camera.location + z_offset + x_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 json
|
||||||
import subprocess
|
import subprocess
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
import ifcopenshell.util.representation
|
||||||
import blenderbim.bim.module.drawing.svgwriter as svgwriter
|
import blenderbim.bim.module.drawing.svgwriter as svgwriter
|
||||||
import blenderbim.bim.module.drawing.annotation as annotation
|
import blenderbim.bim.module.drawing.annotation as annotation
|
||||||
from mathutils import Vector, Matrix, Euler, geometry
|
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__))
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
class AddDrawing(bpy.types.Operator):
|
class AddDrawing(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_drawing"
|
bl_idname = "bim.add_drawing"
|
||||||
bl_label = "Add Drawing"
|
bl_label = "Add Drawing"
|
||||||
@@ -69,7 +71,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
def combine_svgs(self, context, base, annotation):
|
def combine_svgs(self, context, base, annotation):
|
||||||
# Hacky :)
|
# Hacky :)
|
||||||
svg_path = context.scene.BIMProperties.ifc_file[0:-4] + ".svg"
|
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:
|
with open(base) as infile:
|
||||||
for line in infile:
|
for line in infile:
|
||||||
if "</svg>" in line:
|
if "</svg>" in line:
|
||||||
@@ -197,6 +199,11 @@ class AddAnnotation(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
if not bpy.context.scene.camera:
|
if not bpy.context.scene.camera:
|
||||||
return {"FINISHED"}
|
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 self.data_type == "text":
|
||||||
if bpy.context.selected_objects:
|
if bpy.context.selected_objects:
|
||||||
for selected_object in 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)
|
obj = annotation.Annotator.add_plane_to_annotation(obj)
|
||||||
else:
|
else:
|
||||||
obj = annotation.Annotator.add_line_to_annotation(obj)
|
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.ops.object.select_all(action="DESELECT")
|
||||||
bpy.context.view_layer.objects.active = obj
|
bpy.context.view_layer.objects.active = obj
|
||||||
|
obj.select_set(True)
|
||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import numpy as np
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
import ifcopenshell.util.representation
|
||||||
import logging
|
import logging
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
@@ -105,7 +106,7 @@ class AddRepresentation(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
box_context_id = get_context_id("Model", "Box", "MODEL_VIEW")
|
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 (
|
if (
|
||||||
box_context_id
|
box_context_id
|
||||||
and context_of_items.ContextType == "Model"
|
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)
|
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
||||||
|
|
||||||
box_context_id = get_context_id("Model", "Box", "MODEL_VIEW")
|
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 (
|
if (
|
||||||
box_context_id
|
box_context_id
|
||||||
and old_box
|
and old_box
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import ifcopenshell
|
|||||||
import ifcopenshell.util.selector
|
import ifcopenshell.util.selector
|
||||||
import ifcopenshell.util.geolocation
|
import ifcopenshell.util.geolocation
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
import ifcopenshell.util.representation
|
||||||
import ifcopenshell.util.schema
|
import ifcopenshell.util.schema
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from . import export_ifc
|
from . import export_ifc
|
||||||
@@ -617,7 +618,7 @@ class CutSection(bpy.types.Operator):
|
|||||||
if not element.Representation:
|
if not element.Representation:
|
||||||
return False
|
return False
|
||||||
for representation in element.Representation.Representations:
|
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
|
representation, "Plan", "Annotation", camera.data.BIMCameraProperties.target_view
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class Usecase:
|
|||||||
for modifier in self.settings["blender_object"].modifiers:
|
for modifier in self.settings["blender_object"].modifiers:
|
||||||
if modifier.type == "BOOLEAN":
|
if modifier.type == "BOOLEAN":
|
||||||
modifier.show_viewport = False
|
modifier.show_viewport = False
|
||||||
|
|
||||||
if self.settings["should_force_triangulation"]:
|
if self.settings["should_force_triangulation"]:
|
||||||
mesh = self.settings["blender_object"].evaluated_get(bpy.context.evaluated_depsgraph_get()).to_mesh()
|
mesh = self.settings["blender_object"].evaluated_get(bpy.context.evaluated_depsgraph_get()).to_mesh()
|
||||||
bm = bmesh.new()
|
bm = bmesh.new()
|
||||||
@@ -119,6 +119,41 @@ class Usecase:
|
|||||||
elif self.settings["context"].ContextIdentifier == "SurveyPoints":
|
elif self.settings["context"].ContextIdentifier == "SurveyPoints":
|
||||||
pass
|
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):
|
def create_variable_representation(self):
|
||||||
if self.settings["is_wireframe"]:
|
if self.settings["is_wireframe"]:
|
||||||
return self.create_wireframe_representation()
|
return self.create_wireframe_representation()
|
||||||
|
|||||||
@@ -108,24 +108,6 @@ def replace_attribute(element, old, new):
|
|||||||
element[i] = new_attribute
|
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):
|
def remove_deep(ifc_file, element):
|
||||||
# @todo maybe some sort of try-finally mechanism.
|
# @todo maybe some sort of try-finally mechanism.
|
||||||
ifc_file.batch()
|
ifc_file.batch()
|
||||||
@@ -159,14 +141,3 @@ def copy_deep(ifc_file, element):
|
|||||||
attribute[j] = copy_deep(ifc_file, item)
|
attribute[j] = copy_deep(ifc_file, item)
|
||||||
new[i] = attribute
|
new[i] = attribute
|
||||||
return new
|
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
|
||||||
Reference in New Issue
Block a user