From 5c4ee030d3a9e28fcc43939c9542aaef59a2b15a Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Thu, 8 Aug 2024 11:23:08 +0200 Subject: [PATCH] metrics io add functions for metrics saving and loading we need to add and remove faces. if they don't have faces, blender gltf loader will ignore the meshes. but we want them in the end only with vertices and edges. --- butils.py | 149 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 33 deletions(-) diff --git a/butils.py b/butils.py index 96d6ced..dd21f2b 100644 --- a/butils.py +++ b/butils.py @@ -510,6 +510,37 @@ def completely_delete_objects(objs): # not important pass +def is_mesh(o): + return type(o.data) == bpy.types.Mesh + +def is_metrics_object(o): + return (re.match("[\w]*_metrics$", o.name) != None or re.match("[\w]*_metrics.[\d]{3}$", o.name) != None) and is_mesh(o) + +def is_glyph(o): + try: + return type(o.parent) is not type(None) \ + and "glyphs" in o.parent.name \ + and is_mesh(o) \ + and not is_metrics_object(o) + except ReferenceError as e: + return False + +# blender bound_box vertices +# +# 3------7. +# |`. | `. +y +# | `2------6 | +# | | | | | +# 0---|--4. | +--- +x +# `. | `.| `. +# `1------5 `+z + +def get_glyph_advance(glyph_obj): + for c in glyph_obj.children: + if is_metrics_object(c): + return abs(c.bound_box[4][0] - c.bound_box[0][0]) + return abs(glyph_obj.bound_box[4][0] - glyph_obj.bound_box[0][0]) + def set_text_on_curve(text_properties): # starttime = time.perf_counter_ns() mom = text_properties.text_object @@ -601,35 +632,45 @@ def set_text_on_curve(text_properties): elif distribution_type == 'CALCULATE': location, tangent = calc_point_on_bezier_curve(mom, advance, True) ob.location = mom.matrix_world @ (location + text_properties.translation) - mask = [0] - input_rotations = [mathutils.Vector((0.0, 0.0, 0.0))] - vectors = [tangent] - factors = [1.0] - local_main_axis = mathutils.Vector((1.0, 0.0, 0.0)) - motor = align_rotations_auto_pivot(mask, - input_rotations, - vectors, - factors, - local_main_axis) - if ob.rotation_mode != 'QUATERNION': - ob.rotation_mode = 'QUATERNION' - q = mathutils.Quaternion() - q.rotate(text_properties.orientation) - ob.rotation_quaternion = (mom.matrix_world @ motor[0] @ q.to_matrix().to_4x4()).to_quaternion() + if not text_properties.ignore_orientation: + mask = [0] + input_rotations = [mathutils.Vector((0.0, 0.0, 0.0))] + vectors = [tangent] + factors = [1.0] + local_main_axis = mathutils.Vector((1.0, 0.0, 0.0)) + motor = align_rotations_auto_pivot(mask, + input_rotations, + vectors, + factors, + local_main_axis) + if ob.rotation_mode != 'QUATERNION': + ob.rotation_mode = 'QUATERNION' + q = mathutils.Quaternion() + q.rotate(text_properties.orientation) + ob.rotation_quaternion = (mom.matrix_world @ motor[0] @ q.to_matrix().to_4x4()).to_quaternion() + else: + q = mathutils.Quaternion() + q.rotate(text_properties.orientation) + ob.rotation_quaternion = q + # ob.rotation_quaternion = (mom.matrix_world @ q.to_matrix().to_4x4()).to_quaternion() scalor = 0.001 * text_properties.font_size - glyph_advance = (-1 * glyph.bound_box[0][0] + glyph.bound_box[4][0]) * scalor + text_properties.letter_spacing + glyph_advance = get_glyph_advance(glyph) * scalor + text_properties.letter_spacing # now we need to compensate for curvature # otherwise letters will be closer together the curvier the bezier is # this could be done more efficiently, but whatever curve_compensation = 0 - previous_location = calc_point_on_bezier_curve(mom, advance, False) - new_location = calc_point_on_bezier_curve(mom, advance + glyph_advance, False) - while (previous_location - new_location).length < glyph_advance: - curve_compensation = curve_compensation + glyph_advance * 0.01 - new_location = calc_point_on_bezier_curve(mom, advance + glyph_advance + curve_compensation, False) + if text_properties.compensate_curvature: + previous_location = calc_point_on_bezier_curve(mom, advance, False) + new_location = calc_point_on_bezier_curve(mom, advance + glyph_advance, False) + while (previous_location - new_location).length > glyph_advance: + curve_compensation = curve_compensation - glyph_advance * 0.01 + new_location = calc_point_on_bezier_curve(mom, advance + glyph_advance + curve_compensation, False) + while (previous_location - new_location).length < glyph_advance: + curve_compensation = curve_compensation + glyph_advance * 0.01 + new_location = calc_point_on_bezier_curve(mom, advance + glyph_advance + curve_compensation, False) ob.scale = (scalor, scalor, scalor) @@ -695,20 +736,62 @@ def add_metrics_obj_from_bound_box(glyph, bound_box=None): mesh.from_pydata(verts, edges, faces) -def is_mesh(o): - return type(o.data) == bpy.types.Mesh +def add_faces_to_metrics(obj): + mesh = bpy.data.meshes.new(f"{obj.name}") # add the new mesh + bound_box = bound_box_as_array(obj.bound_box) + verts = [bound_box[0], + bound_box[1], + bound_box[2], + bound_box[3], + bound_box[4], + bound_box[5], + bound_box[6], + bound_box[7], + ] + edges = [[0,1],[1,2],[2,3],[3,0], + [0,4],[1,5],[2,6],[3,7], + [4,5],[5,6],[6,7],[7,4], + ] + faces = [ + [0,1,2], [2,3,0], + [2,6,7], [7,3,2], + [6,5,4], [4,7,6], + [4,5,1], [0,4,1], + [1,5,6], [1,6,2], + [4,0,7], [7,0,3], + ] -def is_metrics_object(o): - return (re.match("[\w]*_metrics$", o.name) != None or re.match("[\w]*_metrics.[\d]{3}$", o.name) != None) and is_mesh(o) + mesh.from_pydata(verts, edges, faces) + + old_mesh = obj.data + obj.data = mesh + bpy.data.meshes.remove(old_mesh) + +def remove_faces_from_metrics(obj): + mesh = bpy.data.meshes.new(f"{obj.name}") # add the new mesh + bound_box = bound_box_as_array(obj.bound_box) + verts = [bound_box[0], + bound_box[1], + bound_box[2], + bound_box[3], + bound_box[4], + bound_box[5], + bound_box[6], + bound_box[7], + ] + edges = [[0,1],[1,2],[2,3],[3,0], + [0,4],[1,5],[2,6],[3,7], + [4,5],[5,6],[6,7],[7,4], + ] + faces = [ + ] + + mesh.from_pydata(verts, edges, faces) + + old_mesh = obj.data + obj.data = mesh + bpy.data.meshes.remove(old_mesh) -def is_glyph(o): - try: - return type(o.parent) is not type(None) \ - and "glyphs" in o.parent.name \ - and is_mesh(o) \ - and not is_metrics_object(o) - except ReferenceError as e: - return False # duplicate # def remove_metrics_from_selection(): # for o in bpy.context.selected_objects: