2021-08-17 08:55:29 +10:00
|
|
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
2021-09-02 09:45:58 +10:00
|
|
|
# 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
|
2020-05-03 19:54:27 +10:00
|
|
|
import os
|
2021-11-16 08:35:49 +11:00
|
|
|
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
|
2022-02-04 19:21:24 +11:00
|
|
|
def add_text(related_element=None):
|
2021-05-16 18:26:48 +10:00
|
|
|
curve = bpy.data.curves.new(type="FONT", name="Text")
|
2020-11-01 20:08:48 +07:00
|
|
|
curve.body = "TEXT"
|
2021-05-16 18:26:48 +10:00
|
|
|
obj = bpy.data.objects.new("Text", curve)
|
2022-02-04 19:21:24 +11:00
|
|
|
obj.matrix_world = bpy.context.scene.camera.matrix_world
|
2020-05-07 09:36:38 +10:00
|
|
|
if related_element is None:
|
2022-02-04 19:21:24 +11:00
|
|
|
location, _, _, _ = Annotator.get_placeholder_coords(bpy.context)
|
2020-05-07 09:36:38 +10:00
|
|
|
else:
|
2023-03-24 10:55:03 +05:00
|
|
|
obj.data.BIMAssignedProductProperties.related_element = related_element
|
2020-05-07 09:36:38 +10:00
|
|
|
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")
|
2020-05-03 19:54:27 +10:00
|
|
|
if not font:
|
2020-11-01 20:08:48 +07:00
|
|
|
font = bpy.data.fonts.load(
|
2022-02-04 19:21:24 +11:00
|
|
|
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"
|
2020-05-03 19:54:27 +10:00
|
|
|
obj.data.font = font
|
2020-11-01 20:08:48 +07:00
|
|
|
obj.data.BIMTextProperties.font_size = "2.5"
|
2023-06-05 15:11:19 +10:00
|
|
|
collection = bpy.context.scene.camera.BIMObjectProperties.collection
|
2020-05-03 19:54:27 +10:00
|
|
|
collection.objects.link(obj)
|
|
|
|
|
Annotator.resize_text(obj)
|
2020-05-03 15:41:05 +10:00
|
|
|
return obj
|
|
|
|
|
|
2020-05-03 19:54:27 +10:00
|
|
|
@staticmethod
|
|
|
|
|
def resize_text(text_obj):
|
|
|
|
|
camera = None
|
2023-06-05 15:11:19 +10:00
|
|
|
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)
|
2020-05-03 19:54:27 +10:00
|
|
|
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)
|
2020-08-30 21:40:21 +10:00
|
|
|
|
2023-05-30 12:52:49 +10:00
|
|
|
font_size /= tool.Drawing.get_scale_ratio(tool.Drawing.get_diagram_scale(camera)["Scale"])
|
2020-08-30 21:40:21 +10:00
|
|
|
|
2020-05-03 19:54:27 +10:00
|
|
|
text_obj.data.size = font_size
|
|
|
|
|
|
2020-05-03 15:41:05 +10:00
|
|
|
@staticmethod
|
2022-02-04 19:21:24 +11:00
|
|
|
def add_line_to_annotation(obj, co1=None, co2=None):
|
2020-08-29 18:56:23 +10:00
|
|
|
if co1 is None:
|
2022-02-04 19:21:24 +11:00
|
|
|
co1, co2, _, _ = Annotator.get_placeholder_coords()
|
2020-08-29 18:56:23 +10:00
|
|
|
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):
|
2023-03-31 17:47:07 +05:00
|
|
|
# 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
|
|
|
|
2023-03-31 17:47:07 +05: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
|
2022-05-15 11:45:47 +10:00
|
|
|
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()
|
2023-04-18 14:55:45 +05:00
|
|
|
matrix_world.translation = co1
|
2023-06-05 15:11:19 +10:00
|
|
|
collection = camera.BIMObjectProperties.collection
|
2023-04-10 14:02:50 +05:00
|
|
|
|
2021-11-16 08:35:49 +11:00
|
|
|
if object_type == "TEXT":
|
|
|
|
|
obj = bpy.data.objects.new(object_type, None)
|
2022-05-15 11:45:47 +10:00
|
|
|
obj.matrix_world = matrix_world
|
2021-11-16 08:35:49 +11:00
|
|
|
collection.objects.link(obj)
|
|
|
|
|
return obj
|
2023-04-10 14:02:50 +05:00
|
|
|
|
2022-04-23 11:10:02 +10:00
|
|
|
elif object_type in ("TEXT_LEADER", "SECTION_LEVEL"):
|
2021-11-16 08:35:49 +11:00
|
|
|
data = bpy.data.curves.new(object_type, type="CURVE")
|
|
|
|
|
data.dimensions = "3D"
|
|
|
|
|
data.resolution_u = 2
|
|
|
|
|
obj = bpy.data.objects.new(object_type, data)
|
2022-05-15 11:45:47 +10:00
|
|
|
obj.matrix_world = matrix_world
|
2021-11-16 08:35:49 +11:00
|
|
|
collection.objects.link(obj)
|
|
|
|
|
return obj
|
2023-04-10 14:02:50 +05:00
|
|
|
|
2022-05-02 09:20:33 +10:00
|
|
|
if object_type != "ANGLE":
|
|
|
|
|
for obj in collection.objects:
|
|
|
|
|
element = tool.Ifc.get_entity(obj)
|
2023-01-29 20:10:09 +11:00
|
|
|
if element and element.ObjectType == object_type and obj.type == object_type.upper():
|
2022-05-02 09:20:33 +10:00
|
|
|
return obj
|
2023-04-10 14:02:50 +05:00
|
|
|
|
2020-11-01 20:08:48 +07:00
|
|
|
if data_type == "mesh":
|
2021-11-16 08:35:49 +11:00
|
|
|
data = bpy.data.meshes.new(object_type)
|
2020-11-01 20:08:48 +07:00
|
|
|
elif data_type == "curve":
|
2021-11-16 08:35:49 +11:00
|
|
|
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
|
|
|
|
2021-11-16 08:35:49 +11:00
|
|
|
obj = bpy.data.objects.new(object_type, data)
|
2022-05-15 11:45:47 +10:00
|
|
|
obj.matrix_world = matrix_world
|
2020-05-03 15:41:05 +10:00
|
|
|
collection.objects.link(obj)
|
|
|
|
|
return obj
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2022-05-15 11:45:47 +10:00
|
|
|
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))
|
2021-09-09 21:27:23 +10:00
|
|
|
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,
|
|
|
|
|
)
|