diff --git a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py index 4ab398f270..f748de523a 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py @@ -30,7 +30,7 @@ from math import acos, pi, atan, degrees from functools import reduce from itertools import chain from bpy.types import SpaceView3D -from mathutils import Vector, Matrix +from mathutils import Vector, Matrix, geometry from bpy_extras.view3d_utils import location_3d_to_region_2d from gpu.types import GPUShader, GPUBatch, GPUIndexBuf, GPUVertBuf, GPUVertFormat from gpu_extras.batch import batch_for_shader @@ -384,7 +384,7 @@ class BaseDecorator: context, text, pos, - dir, + text_dir, gap=4, center=True, vcenter=False, @@ -409,9 +409,10 @@ class BaseDecorator: color = context.scene.DocProperties.decorations_colour - ang = -Vector((1, 0)).angle_signed(dir) + ang = -Vector((1, 0)).angle_signed(text_dir) cos = math.cos(ang) sin = math.sin(ang) + rotated_y_axis = Vector([-sin, cos]) # Horrific prototype code factor = self.camera_zoom_to_factor(context.space_data.region_3d.view_camera_zoom) @@ -423,7 +424,7 @@ class BaseDecorator: # font_size = 16 <-- this is a good default # TODO: need to synchronize it better with svg font_size_px = int(0.004118616 * mm_to_px) * font_size_mm / 2.5 - pos = pos - Vector((0, line_no * font_size_px)) + pos = pos - line_no * font_size_px * rotated_y_axis blf.size(font_id, font_size_px, dpi) @@ -2074,11 +2075,48 @@ class TextDecorator(BaseDecorator): def decorate(self, context, obj): self.draw_labels(context, obj) + def project_point_onto_camera(self, point, camera_projection): + # TODO is this needlessly complex? + camera = bpy.context.scene.camera + return camera.matrix_world.inverted() @ geometry.intersect_line_plane( + point.xyz, + point.xyz - Vector(camera_projection), + camera.location, + Vector(camera_projection), + ) + + def get_camera_dimensions(self): + render = bpy.context.scene.render + camera = bpy.context.scene.camera + if render.resolution_x > render.resolution_y: # is_landscape + width = camera.data.ortho_scale + height = width / render.resolution_x * render.resolution_y + else: + height = camera.data.ortho_scale + width = height / render.resolution_y * render.resolution_x + return width, height + def draw_labels(self, context, obj): region = context.region region3d = context.region_data - # TODO: support text rotation - dir = Vector((1, 0)) + + # TODO: optimize for realtime viewport render + # currently it's just copied from svgwriter + # to make rotation work in viewport + camera = bpy.context.scene.camera + camera_dimensions = Vector(self.get_camera_dimensions()) + x_offset, y_offset = camera_dimensions / 2 + position = obj.matrix_world.translation + camera_projection = tuple( + camera.matrix_world.to_quaternion() @ Vector((0, 0, -1)) + ) + text_position = self.project_point_onto_camera(position, camera_projection) + text_position = Vector(((x_offset + text_position.x), (y_offset - text_position.y))) + local_x_axis = obj.matrix_world.to_quaternion() @ Vector((1, 0, 0)) + projected_x_axis = self.project_point_onto_camera(position + local_x_axis, camera_projection) + text_dir = (Vector((x_offset + projected_x_axis.x, y_offset + projected_x_axis.y)) - text_position) + + pos = location_3d_to_region_2d(region, region3d, obj.matrix_world.translation) props = obj.BIMTextProperties text_data = props.get_text_edited_data() if props.is_editing else DecoratorData.get_ifc_text_data(obj) @@ -2104,7 +2142,7 @@ class TextDecorator(BaseDecorator): context, line, pos, - dir, + text_dir, gap=0, center=False, vcenter=False,