Files
IfcOpenShell/src/blenderbim/blenderbim/bim/module/drawing/annotation.py
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

171 lines
6.5 KiB
Python
Raw Normal View History

2021-08-17 08:55:29 +10:00
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Maxim Vasilyev <qwiglydee@gmail.com>
2021-08-17 08:55:29 +10:00
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
2020-05-03 15:41:05 +10:00
import bpy
import os
import blenderbim.tool as tool
2020-05-03 15:41:05 +10:00
from mathutils import Vector
2023-05-27 15:22:07 +05:00
import bmesh
2020-05-03 15:41:05 +10:00
2020-11-01 20:08:48 +07:00
class Annotator:
2020-05-03 15:41:05 +10:00
@staticmethod
def add_text(related_element=None):
curve = bpy.data.curves.new(type="FONT", name="Text")
2020-11-01 20:08:48 +07:00
curve.body = "TEXT"
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(bpy.context)
else:
2023-03-24 10:55:03 +05:00
obj.data.BIMAssignedProductProperties.related_element = related_element
location = related_element.location
obj.location = location
2020-05-03 15:41:05 +10:00
obj.hide_render = True
2020-11-01 20:08:48 +07:00
font = bpy.data.fonts.get("OpenGost TypeB TT")
if not font:
2020-11-01 20:08:48 +07:00
font = bpy.data.fonts.load(
os.path.join(bpy.context.scene.BIMProperties.data_dir, "fonts", "OpenGost Type B TT.ttf")
2020-11-01 20:08:48 +07:00
)
font.name = "OpenGost Type B TT"
obj.data.font = font
2020-11-01 20:08:48 +07:00
obj.data.BIMTextProperties.font_size = "2.5"
collection = bpy.context.scene.camera.BIMObjectProperties.collection
collection.objects.link(obj)
Annotator.resize_text(obj)
2020-05-03 15:41:05 +10:00
return obj
@staticmethod
def resize_text(text_obj):
camera = None
group = tool.Drawing.get_drawing_group(tool.Ifc.get_entity(text_obj))
for element in tool.Drawing.get_drawing_elements(group):
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
camera = tool.Ifc.get_object(element)
break
if not camera:
return
# This is a magic number for OpenGost
font_size = 1.6 / 1000
font_size *= float(text_obj.data.BIMTextProperties.font_size)
font_size /= tool.Drawing.get_scale_ratio(tool.Drawing.get_diagram_scale(camera)["Scale"])
text_obj.data.size = font_size
2020-05-03 15:41:05 +10:00
@staticmethod
def add_line_to_annotation(obj, co1=None, co2=None):
if co1 is None:
co1, co2, _, _ = Annotator.get_placeholder_coords()
co1 = obj.matrix_world.inverted() @ co1
co2 = obj.matrix_world.inverted() @ co2
2023-04-10 14:02:50 +05:00
2020-05-03 15:41:05 +10:00
if isinstance(obj.data, bpy.types.Mesh):
obj.data.vertices.add(2)
obj.data.vertices[-2].co = co1
obj.data.vertices[-1].co = co2
2020-06-06 23:42:24 +02:00
obj.data.edges.add(1)
2020-05-03 15:41:05 +10:00
obj.data.edges[-1].vertices = (obj.data.vertices[-2].index, obj.data.vertices[-1].index)
2023-04-10 14:02:50 +05:00
2020-05-03 15:41:05 +10:00
if isinstance(obj.data, bpy.types.Curve):
2020-11-01 20:08:48 +07:00
polyline = obj.data.splines.new("POLY")
2020-05-03 15:41:05 +10:00
polyline.points.add(1)
polyline.points[-2].co = list(co1) + [1]
polyline.points[-1].co = list(co2) + [1]
2023-04-10 14:02:50 +05:00
2020-05-03 15:41:05 +10:00
return obj
2020-12-26 21:59:57 +07:00
@staticmethod
2023-05-27 15:22:07 +05:00
def add_plane_to_annotation(obj, remove_face=False):
# default order = bot left, top left, bot right, top right
# therefore we redefine the order
face_verts = [0, 2, 3, 1]
2020-12-26 21:59:57 +07:00
verts_world_space = Annotator.get_placeholder_coords()
verts_local = [obj.matrix_world.inverted() @ v for v in verts_world_space]
bm = tool.Blender.get_bmesh_for_mesh(obj.data, clean=True)
new_verts = [bm.verts.new(v) for v in verts_local]
2020-12-26 21:59:57 +07:00
2023-05-27 15:22:07 +05:00
face = bm.faces.new([new_verts[i] for i in face_verts])
if remove_face:
bmesh.ops.delete(bm, geom=[face], context="FACES_ONLY")
2023-04-03 12:06:56 +05:00
tool.Blender.apply_bmesh(obj.data, bm, obj)
2020-12-26 21:59:57 +07:00
return obj
2020-05-03 15:41:05 +10:00
@staticmethod
def get_annotation_obj(drawing, object_type, data_type):
camera = tool.Ifc.get_object(drawing)
co1, _, _, _ = Annotator.get_placeholder_coords(camera)
matrix_world = camera.matrix_world.copy()
matrix_world.translation = co1
collection = camera.BIMObjectProperties.collection
2023-04-10 14:02:50 +05:00
if object_type == "TEXT":
obj = bpy.data.objects.new(object_type, None)
obj.matrix_world = matrix_world
collection.objects.link(obj)
return obj
2023-04-10 14:02:50 +05:00
elif object_type in ("TEXT_LEADER", "SECTION_LEVEL"):
data = bpy.data.curves.new(object_type, type="CURVE")
data.dimensions = "3D"
data.resolution_u = 2
obj = bpy.data.objects.new(object_type, data)
obj.matrix_world = matrix_world
collection.objects.link(obj)
return obj
2023-04-10 14:02:50 +05:00
if object_type != "ANGLE":
for obj in collection.objects:
element = tool.Ifc.get_entity(obj)
if element and element.ObjectType == object_type and obj.type == object_type.upper():
return obj
2023-04-10 14:02:50 +05:00
2020-11-01 20:08:48 +07:00
if data_type == "mesh":
data = bpy.data.meshes.new(object_type)
2020-11-01 20:08:48 +07:00
elif data_type == "curve":
data = bpy.data.curves.new(object_type, type="CURVE")
2020-11-01 20:08:48 +07:00
data.dimensions = "3D"
2020-05-03 15:41:05 +10:00
data.resolution_u = 2
2023-04-10 14:02:50 +05:00
obj = bpy.data.objects.new(object_type, data)
obj.matrix_world = matrix_world
2020-05-03 15:41:05 +10:00
collection.objects.link(obj)
return obj
@staticmethod
def get_placeholder_coords(camera=None):
if not camera:
camera = bpy.context.scene.camera
2020-05-03 15:41:05 +10:00
z_offset = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1))
2023-04-10 14:02:50 +05:00
y = camera.data.ortho_scale / 4
res_x = bpy.context.scene.render.resolution_x
res_y = bpy.context.scene.render.resolution_y
if res_x > res_y:
y *= res_y / res_x
2020-05-03 15:41:05 +10:00
y_offset = camera.matrix_world.to_quaternion() @ Vector((0, y, 0))
x_offset = camera.matrix_world.to_quaternion() @ Vector((y / 2, 0, 0))
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,
)