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: