glyph properties, orientation fixes
This commit is contained in:
parent
6943a9189c
commit
d56ca84236
2 changed files with 359 additions and 136 deletions
428
butils.py
428
butils.py
|
@ -733,6 +733,12 @@ def get_glyph_advance(glyph_obj):
|
|||
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 get_glyph_prepost_advances(glyph_obj):
|
||||
for c in glyph_obj.children:
|
||||
if is_metrics_object(c):
|
||||
return -1 * c.bound_box[0][0], c.bound_box[4][0]
|
||||
return -1 * glyph_obj.bound_box[0][0], glyph_obj.bound_box[4][0]
|
||||
|
||||
|
||||
def get_glyph_height(glyph_obj):
|
||||
for c in glyph_obj.children:
|
||||
|
@ -802,6 +808,41 @@ def will_regenerate(text_properties):
|
|||
return False
|
||||
|
||||
|
||||
def update_matrices(obj):
|
||||
if obj.parent is None:
|
||||
obj.matrix_world = obj.matrix_basis
|
||||
|
||||
else:
|
||||
obj.matrix_world = obj.parent.matrix_world * \
|
||||
obj.matrix_parent_inverse * \
|
||||
obj.matrix_basis
|
||||
|
||||
def is_or_has_parent(o, parent, if_is_parent=True, max_depth=10):
|
||||
if o == parent and if_is_parent:
|
||||
return True
|
||||
for i in range(0, max_depth):
|
||||
o = o.parent
|
||||
if o == parent:
|
||||
return True
|
||||
if o is None:
|
||||
return False
|
||||
return False
|
||||
|
||||
def parent_to_curve(o, c):
|
||||
o.parent_type = 'OBJECT'
|
||||
o.parent = c
|
||||
# o.matrix_parent_inverse = c.matrix_world.inverted()
|
||||
|
||||
if c.data.use_path and len(c.data.splines) > 0:
|
||||
if c.data.splines[0].type == "BEZIER":
|
||||
i = -1 if c.data.splines[0].use_cyclic_u else 0
|
||||
p = c.data.splines[0].bezier_points[i].co
|
||||
o.matrix_parent_inverse.translation = p * -1.0
|
||||
elif c.data.splines[0].type == 'NURBS':
|
||||
cm = c.to_mesh()
|
||||
p = cm.vertices[0].co
|
||||
o.matrix_parent_inverse.translation = p * -1.0
|
||||
|
||||
def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4):
|
||||
"""set_text_on_curve
|
||||
|
||||
|
@ -815,8 +856,9 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
:param reset_depsgraph_n: reset external parameters after n-th depsgraph update. (<= 0) = immediate, (> 0) = reset after n-th depsgraph update, (False) = no depsgraph reset
|
||||
:type reset_depsgraph_n: int
|
||||
"""
|
||||
|
||||
global lock_depsgraph_update_n_times
|
||||
# NOTE: depsgraph update not locked
|
||||
# as we fixed data_path with parent_to_curve trick
|
||||
# global lock_depsgraph_update_n_times
|
||||
|
||||
# starttime = time.perf_counter_ns()
|
||||
mom = text_properties.text_object
|
||||
|
@ -825,26 +867,41 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
|
||||
distribution_type = "CALCULATE" if is_bezier(mom) else "FOLLOW_PATH"
|
||||
|
||||
# NOTE: following not necessary anymore
|
||||
# as we fixed data_path with parent_to_curve trick
|
||||
#
|
||||
# use_path messes with parenting
|
||||
# however, we need it for follow_path
|
||||
# https://projects.blender.org/blender/blender/issues/100661
|
||||
previous_use_path = mom.data.use_path
|
||||
if distribution_type == "CALCULATE":
|
||||
mom.data.use_path = False
|
||||
elif distribution_type == "FOLLOW_PATH":
|
||||
mom.data.use_path = True
|
||||
# previous_use_path = mom.data.use_path
|
||||
# if distribution_type == "CALCULATE":
|
||||
# mom.data.use_path = False
|
||||
# elif distribution_type == "FOLLOW_PATH":
|
||||
# mom.data.use_path = True
|
||||
|
||||
regenerate = will_regenerate(text_properties)
|
||||
|
||||
# if we regenerate.... delete objects
|
||||
if regenerate and text_properties.get("glyphs"):
|
||||
for g in text_properties.glyphs:
|
||||
print(dict(g))
|
||||
glyph_objects = [g["glyph_object"] for g in text_properties["glyphs"]]
|
||||
completely_delete_objects(glyph_objects, True)
|
||||
text_properties.glyphs.clear()
|
||||
|
||||
mom[f"{utils.prefix()}_type"] = "textobject"
|
||||
mom[f"{utils.prefix()}_linked_textobject"] = text_properties.text_id
|
||||
mom[f"{utils.prefix()}_font_name"] = text_properties.font_name
|
||||
mom[f"{utils.prefix()}_face_name"] = text_properties.face_name
|
||||
mom[f"{utils.prefix()}_font_size"] = text_properties.font_size
|
||||
mom[f"{utils.prefix()}_letter_spacing"] = text_properties.letter_spacing
|
||||
mom[f"{utils.prefix()}_orientation"] = text_properties.orientation
|
||||
mom[f"{utils.prefix()}_translation"] = text_properties.translation
|
||||
|
||||
curve_length = get_curve_length(mom)
|
||||
advance = text_properties.offset
|
||||
glyph_advance = 0
|
||||
glyph_index = 0
|
||||
is_command = False
|
||||
previous_spline_index = -1
|
||||
|
||||
|
@ -860,7 +917,6 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
is_newline = True
|
||||
next_line_advance = get_next_line_advance(mom, advance, glyph_advance)
|
||||
if advance == next_line_advance:
|
||||
# self.report({'INFO'}, f"would like to add new line for {text_properties.text} please")
|
||||
print(
|
||||
f"would like to add new line for {text_properties.text} please"
|
||||
)
|
||||
|
@ -870,9 +926,14 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
is_command = False
|
||||
glyph_id = c
|
||||
|
||||
glyph_tmp = Font.get_glyph(
|
||||
text_properties.font_name, text_properties.face_name, glyph_id
|
||||
)
|
||||
spline_index = 0
|
||||
|
||||
############### GET GLYPH
|
||||
|
||||
glyph_tmp = Font.get_glyph(text_properties.font_name,
|
||||
text_properties.face_name,
|
||||
glyph_id,
|
||||
-1)
|
||||
if glyph_tmp is None:
|
||||
space_width = Font.is_space(glyph_id)
|
||||
if space_width:
|
||||
|
@ -887,6 +948,7 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
text_properties.font_name,
|
||||
text_properties.face_name,
|
||||
possible_replacement,
|
||||
-1
|
||||
)
|
||||
if glyph_tmp is not None:
|
||||
message = message + f" (replaced with '{possible_replacement}')"
|
||||
|
@ -903,59 +965,82 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
|
||||
glyph = glyph_tmp.original
|
||||
|
||||
ob = None
|
||||
obg = None
|
||||
############### GLYPH PROPERTIES
|
||||
|
||||
glyph_properties = text_properties.glyphs[glyph_index] if not regenerate else text_properties.glyphs.add()
|
||||
|
||||
if regenerate:
|
||||
ob = bpy.data.objects.new(f"{glyph_id}", None)
|
||||
ob.hide_viewport = True
|
||||
obg = bpy.data.objects.new(f"{glyph_id}_mesh", glyph.data)
|
||||
ob[f"{utils.prefix()}_type"] = "glyph"
|
||||
ob[f"{utils.prefix()}_linked_textobject"] = text_properties.text_id
|
||||
ob[f"{utils.prefix()}_font_name"] = text_properties.font_name
|
||||
ob[f"{utils.prefix()}_face_name"] = text_properties.face_name
|
||||
glyph_properties["glyph_id"] = glyph_id
|
||||
glyph_properties["text_id"] = text_properties.text_id
|
||||
glyph_properties["letter_spacing"] = 0
|
||||
|
||||
############### NODE SCENE MANAGEMENT
|
||||
|
||||
inner_node = None
|
||||
outer_node = None
|
||||
if regenerate:
|
||||
outer_node = bpy.data.objects.new(f"{glyph_id}", None)
|
||||
inner_node = bpy.data.objects.new(f"{glyph_id}_mesh", glyph.data)
|
||||
outer_node[f"{utils.prefix()}_type"] = "glyph"
|
||||
outer_node[f"{utils.prefix()}_linked_textobject"] = text_properties.text_id
|
||||
outer_node[f"{utils.prefix()}_glyph_index"] = glyph_index
|
||||
outer_node[f"{utils.prefix()}_font_name"] = text_properties.font_name
|
||||
outer_node[f"{utils.prefix()}_face_name"] = text_properties.face_name
|
||||
|
||||
# Add into the scene.
|
||||
mom.users_collection[0].objects.link(outer_node)
|
||||
mom.users_collection[0].objects.link(inner_node)
|
||||
# bpy.context.scene.collection.objects.link(inner_node)
|
||||
|
||||
# Parenting is hard.
|
||||
inner_node.parent_type = 'OBJECT'
|
||||
inner_node.parent = outer_node
|
||||
inner_node.matrix_parent_inverse = outer_node.matrix_world.inverted()
|
||||
parent_to_curve(outer_node, mom)
|
||||
|
||||
glyph_properties["glyph_object"] = outer_node
|
||||
else:
|
||||
ob = text_properties.glyphs[i].glyph_object
|
||||
for c in ob.children:
|
||||
outer_node = glyph_properties.glyph_object
|
||||
outer_node[f"{utils.prefix()}_glyph_index"] = glyph_index
|
||||
for c in outer_node.children:
|
||||
if c.name.startswith(f"{glyph_id}_mesh"):
|
||||
obg = c
|
||||
inner_node = c
|
||||
|
||||
############### TRANSFORMS
|
||||
|
||||
# origins could be shifted
|
||||
# so we need to apply a pre_advance
|
||||
glyph_pre_advance, glyph_post_advance = get_glyph_prepost_advances(glyph)
|
||||
advance += glyph_pre_advance * scalor
|
||||
|
||||
if distribution_type == "FOLLOW_PATH":
|
||||
ob.constraints.new(type="FOLLOW_PATH")
|
||||
ob.constraints["Follow Path"].target = mom
|
||||
ob.constraints["Follow Path"].use_fixed_location = True
|
||||
ob.constraints["Follow Path"].offset_factor = advance / curve_length
|
||||
ob.constraints["Follow Path"].use_curve_follow = True
|
||||
ob.constraints["Follow Path"].forward_axis = "FORWARD_X"
|
||||
ob.constraints["Follow Path"].up_axis = "UP_Y"
|
||||
outer_node.constraints.new(type="FOLLOW_PATH")
|
||||
outer_node.constraints["Follow Path"].target = mom
|
||||
outer_node.constraints["Follow Path"].use_fixed_location = True
|
||||
outer_node.constraints["Follow Path"].offset_factor = advance / curve_length
|
||||
outer_node.constraints["Follow Path"].use_curve_follow = True
|
||||
outer_node.constraints["Follow Path"].forward_axis = "FORWARD_X"
|
||||
outer_node.constraints["Follow Path"].up_axis = "UP_Y"
|
||||
spline_index = 0
|
||||
elif distribution_type == "CALCULATE":
|
||||
previous_ob_rotation_mode = None
|
||||
previous_obg_rotation_mode = None
|
||||
if ob.rotation_mode != "QUATERNION":
|
||||
ob.rotation_mode = "QUATERNION"
|
||||
previous_ob_rotation_mode = ob.rotation_mode
|
||||
if obg.rotation_mode != "QUATERNION":
|
||||
obg.rotation_mode = "QUATERNION"
|
||||
previous_obg_rotation_mode = obg.rotation_mode
|
||||
previous_outer_node_rotation_mode = None
|
||||
previous_inner_node_rotation_mode = None
|
||||
if outer_node.rotation_mode != "QUATERNION":
|
||||
outer_node.rotation_mode = "QUATERNION"
|
||||
previous_outer_node_rotation_mode = outer_node.rotation_mode
|
||||
if inner_node.rotation_mode != "QUATERNION":
|
||||
inner_node.rotation_mode = "QUATERNION"
|
||||
previous_inner_node_rotation_mode = inner_node.rotation_mode
|
||||
|
||||
location, tangent, spline_index = calc_point_on_bezier_curve(
|
||||
mom, advance, True, True
|
||||
)
|
||||
# get info from bezier
|
||||
location, tangent, spline_index = calc_point_on_bezier_curve(mom, advance, True, True)
|
||||
|
||||
# check if we are on a new line
|
||||
if spline_index != previous_spline_index:
|
||||
is_newline = True
|
||||
|
||||
if regenerate:
|
||||
# ob.location = mom.matrix_world @ (
|
||||
# location + text_properties.translation
|
||||
# )
|
||||
ob.location = location + text_properties.translation
|
||||
mom.users_collection[0].objects.link(obg)
|
||||
mom.users_collection[0].objects.link(ob)
|
||||
ob.parent = mom
|
||||
obg.parent = ob
|
||||
obg.location = mathutils.Vector((0.0, 0.0, 0.0))
|
||||
else:
|
||||
ob.location = location + text_properties.translation
|
||||
# position
|
||||
outer_node.location = location + text_properties.translation
|
||||
|
||||
# orientation / rotation
|
||||
mask = [0]
|
||||
|
@ -969,26 +1054,28 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
|
||||
q = mathutils.Quaternion()
|
||||
q.rotate(text_properties.orientation)
|
||||
ob.rotation_quaternion = (motor[0].to_3x3() @ q.to_matrix()).to_quaternion()
|
||||
# if regenerate:
|
||||
# obg.rotation_quaternion = q
|
||||
# ob.rotation_quaternion = (
|
||||
# mom.matrix_world @ motor[0]
|
||||
# ).to_quaternion()
|
||||
# else:
|
||||
# ob.rotation_quaternion = motor[0].to_quaternion()
|
||||
outer_node.rotation_quaternion = (motor[0].to_3x3() @ q.to_matrix()).to_quaternion()
|
||||
|
||||
# NOTE: supercool but out of scope, as we wouldhave to update it everytime the curve object rotates,
|
||||
# but this would ignore the curve objects orientation:
|
||||
# ob.rotation_quaternion = (mom.matrix_world.inverted().to_3x3() @ motor[0].to_3x3() @ q.to_matrix()).to_quaternion()
|
||||
# # NOTE: supercool but out of scope, as we wouldhave to update it everytime the curve object rotates,
|
||||
# # but this would ignore the curve objects orientation:
|
||||
# outer_node.rotation_quaternion = (mom.matrix_world.inverted().to_3x3() @ motor[0].to_3x3() @ q.to_matrix()).to_quaternion()
|
||||
|
||||
if previous_ob_rotation_mode:
|
||||
ob.rotation_mode = previous_ob_rotation_mode
|
||||
if previous_obg_rotation_mode:
|
||||
obg.rotation_mode = previous_obg_rotation_mode
|
||||
# # scale
|
||||
outer_node.scale = (scalor, scalor, scalor)
|
||||
|
||||
if previous_outer_node_rotation_mode:
|
||||
outer_node.rotation_mode = previous_outer_node_rotation_mode
|
||||
if previous_inner_node_rotation_mode:
|
||||
inner_node.rotation_mode = previous_inner_node_rotation_mode
|
||||
|
||||
# outer_node.hide_viewport = True
|
||||
outer_node.hide_set(True)
|
||||
|
||||
############### PREPARE FOR THE NEXT
|
||||
|
||||
print(f"{glyph_id}: {glyph_properties.letter_spacing=}")
|
||||
glyph_advance = (
|
||||
get_glyph_advance(glyph) * scalor + text_properties.letter_spacing
|
||||
glyph_post_advance * scalor + text_properties.letter_spacing + glyph_properties.letter_spacing
|
||||
)
|
||||
|
||||
# now we need to compensate for curvature
|
||||
|
@ -997,7 +1084,7 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
curve_compensation = 0
|
||||
if distribution_type == "CALCULATE" and (
|
||||
not is_newline or spline_index == 0
|
||||
): # TODO: fix newline hack
|
||||
):
|
||||
if text_properties.compensate_curvature and glyph_advance > 0:
|
||||
previous_location, psi = calc_point_on_bezier_curve(
|
||||
mom, advance, False, True
|
||||
|
@ -1027,67 +1114,46 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4)
|
|||
output_spline_index=True,
|
||||
)
|
||||
|
||||
ob.scale = (scalor, scalor, scalor)
|
||||
|
||||
advance = advance + glyph_advance + curve_compensation
|
||||
glyph_index += 1
|
||||
previous_spline_index = spline_index
|
||||
|
||||
if regenerate:
|
||||
glyph_data = text_properties.glyphs.add()
|
||||
glyph_data.glyph_id = glyph_id
|
||||
glyph_data.glyph_object = ob
|
||||
glyph_data.letter_spacing = 0
|
||||
|
||||
if regenerate:
|
||||
mom[f"{utils.prefix()}_type"] = "textobject"
|
||||
mom[f"{utils.prefix()}_linked_textobject"] = text_properties.text_id
|
||||
mom[f"{utils.prefix()}_font_name"] = text_properties.font_name
|
||||
mom[f"{utils.prefix()}_face_name"] = text_properties.face_name
|
||||
mom[f"{utils.prefix()}_font_size"] = text_properties.font_size
|
||||
mom[f"{utils.prefix()}_letter_spacing"] = text_properties.letter_spacing
|
||||
mom[f"{utils.prefix()}_orientation"] = text_properties.orientation
|
||||
mom[f"{utils.prefix()}_translation"] = text_properties.translation
|
||||
|
||||
if lock_depsgraph_update_n_times < 0:
|
||||
lock_depsgraph_update_n_times = len(
|
||||
bpy.context.selected_objects
|
||||
)
|
||||
else:
|
||||
lock_depsgraph_update_n_times += len(
|
||||
bpy.context.selected_objects
|
||||
)
|
||||
|
||||
# NOTE: we reset with a timeout, as setting and resetting certain things
|
||||
# in fast succession will cause visual glitches (e.g. {}.data.use_path).
|
||||
def reset():
|
||||
mom.data.use_path = previous_use_path
|
||||
if counted_reset in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.remove(counted_reset)
|
||||
if bpy.app.timers.is_registered(reset):
|
||||
bpy.app.timers.unregister(reset)
|
||||
|
||||
molotov = reset_depsgraph_n + 0
|
||||
|
||||
def counted_reset(scene, depsgraph):
|
||||
nonlocal molotov
|
||||
if molotov == 0:
|
||||
reset()
|
||||
else:
|
||||
molotov -= 1
|
||||
|
||||
# unregister previous resets to avoid multiple execution
|
||||
if bpy.app.timers.is_registered(reset):
|
||||
bpy.app.timers.unregister(reset)
|
||||
if counted_reset in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.remove(counted_reset)
|
||||
|
||||
if not isinstance(reset_timeout_s, bool):
|
||||
if reset_timeout_s > 0:
|
||||
bpy.app.timers.register(reset, first_interval=reset_timeout_s)
|
||||
elif reset_timeout <= 0:
|
||||
reset()
|
||||
|
||||
bpy.app.handlers.depsgraph_update_post.append(counted_reset)
|
||||
# NOTE: depsgraph update not locked
|
||||
# as we fixed data_path with parent_to_curve trick
|
||||
# if lock_depsgraph_update_n_times < 0:
|
||||
# lock_depsgraph_update_n_times = len(
|
||||
# bpy.context.selected_objects
|
||||
# )
|
||||
# else:
|
||||
# lock_depsgraph_update_n_times += len(
|
||||
# bpy.context.selected_objects
|
||||
# )
|
||||
# # NOTE: we reset with a timeout, as setting and resetting certain things
|
||||
# # in fast succession will cause visual glitches (e.g. {}.data.use_path).
|
||||
# def reset():
|
||||
# mom.data.use_path = previous_use_path
|
||||
# if counted_reset in bpy.app.handlers.depsgraph_update_post:
|
||||
# bpy.app.handlers.depsgraph_update_post.remove(counted_reset)
|
||||
# if bpy.app.timers.is_registered(reset):
|
||||
# bpy.app.timers.unregister(reset)
|
||||
# molotov = reset_depsgraph_n + 0
|
||||
# def counted_reset(scene, depsgraph):
|
||||
# nonlocal molotov
|
||||
# if molotov == 0:
|
||||
# reset()
|
||||
# else:
|
||||
# molotov -= 1
|
||||
# # unregister previous resets to avoid multiple execution
|
||||
# if bpy.app.timers.is_registered(reset):
|
||||
# bpy.app.timers.unregister(reset)
|
||||
# if counted_reset in bpy.app.handlers.depsgraph_update_post:
|
||||
# bpy.app.handlers.depsgraph_update_post.remove(counted_reset)
|
||||
# if not isinstance(reset_timeout_s, bool):
|
||||
# if reset_timeout_s > 0:
|
||||
# bpy.app.timers.register(reset, first_interval=reset_timeout_s)
|
||||
# elif reset_timeout <= 0:
|
||||
# reset()
|
||||
# bpy.app.handlers.depsgraph_update_post.append(counted_reset)
|
||||
|
||||
# endtime = time.perf_counter_ns()
|
||||
# elapsedtime = endtime - starttime
|
||||
|
@ -1504,3 +1570,109 @@ def align_metrics_of_objects(objects=None):
|
|||
|
||||
add_metrics_obj_from_bound_box(t, bound_box)
|
||||
return ""
|
||||
|
||||
def align_origins_to_active_object(objects=None, axis=2):
|
||||
if objects is None:
|
||||
objects = bpy.context.selected_objects
|
||||
if len(objects) == 0:
|
||||
return "no objects selected"
|
||||
|
||||
if bpy.context.active_object is None:
|
||||
return "no active object selected"
|
||||
|
||||
reference_origin_position = bpy.context.active_object.matrix_world.translation[axis]
|
||||
|
||||
# do it
|
||||
for o in objects:
|
||||
is_possibly_glyph = is_glyph(o)
|
||||
if is_possibly_glyph and o is not bpy.context.active_object:
|
||||
if is_mesh(o):
|
||||
diff = reference_origin_position - o.matrix_world.translation[axis]
|
||||
|
||||
for v in o.data.vertices:
|
||||
v.co[axis] -= diff
|
||||
|
||||
o.matrix_world.translation[axis] = reference_origin_position
|
||||
|
||||
return ""
|
||||
|
||||
# NOTE:
|
||||
# Following code is not necessary anymore,
|
||||
# as we derive the advance through metrics
|
||||
# boundaries
|
||||
|
||||
# def divide_vectors(v1=mathutils.Vector((1.0,1.0,1.0)), v2=mathutils.Vector((1.0,1.0,1.0))):
|
||||
# return mathutils.Vector([v1[i] / v2[i] for i in range(3)])
|
||||
|
||||
# def get_origin_shift_metrics(o, axis=0):
|
||||
# if not is_metrics_object(o):
|
||||
# return False
|
||||
# min_value = sys.float_info.max
|
||||
# for v in o.data.vertices:
|
||||
# if v.co[axis] < min_value:
|
||||
# min_value = v.co[axis]
|
||||
# if min_value == sys.float_info.max:
|
||||
# return False
|
||||
# return min_value
|
||||
|
||||
# def fix_origin_shift_metrics(o, axis=0):
|
||||
# shift = get_origin_shift_metrics(o)
|
||||
# if not shift:
|
||||
# print("False")
|
||||
# return False
|
||||
# for v in o.data.vertices:
|
||||
# v.co[axis] -= shift
|
||||
# shift_vector = mathutils.Vector((0.0, 0.0, 0.0))
|
||||
# shift_vector[axis] = shift
|
||||
# # o.location = o.location - (divide_vectors(v2=o.matrix_world.to_scale()) * (o.matrix_world @ shift_vector))
|
||||
# o.matrix_local.translation = o.matrix_local.translation + (shift_vector @ o.matrix_local.inverted())
|
||||
# # update_matrices(o)
|
||||
# return True
|
||||
|
||||
|
||||
# def fix_objects_metrics_origins(objects=None, axis=0, handle_metrics_directly=True):
|
||||
# if objects is None:
|
||||
# objects = bpy.context.selected_objects
|
||||
# if len(objects) == 0:
|
||||
# return "no objects selected"
|
||||
|
||||
# for o in objects:
|
||||
# is_possibly_glyph = is_glyph(o)
|
||||
# if is_possibly_glyph:
|
||||
# for c in o.children:
|
||||
# if is_metrics_object(c):
|
||||
# fix_origin_shift_metrics(c, axis)
|
||||
# elif is_metrics_object(o) and handle_metrics_directly:
|
||||
# fix_origin_shift_metrics(o, axis)
|
||||
# return ""
|
||||
|
||||
# def align_origins_to_metrics(objects=None):
|
||||
# if objects is None:
|
||||
# objects = bpy.context.selected_objects
|
||||
# if len(objects) == 0:
|
||||
# return "no objects selected"
|
||||
|
||||
# for o in objects:
|
||||
# is_possibly_glyph = is_glyph(o)
|
||||
# if is_possibly_glyph:
|
||||
# min_x = 9999999999
|
||||
# for c in o.children:
|
||||
# if is_metrics_object(c):
|
||||
# for v in c.data.vertices:
|
||||
# if v.co[0] < min_x:
|
||||
# min_x = v.co[0]
|
||||
|
||||
# metrics_origin_x = c.matrix_world.translation[0] + min_x
|
||||
|
||||
# diff = metrics_origin_x - o.matrix_world.translation[0]
|
||||
|
||||
# for v in o.data.vertices:
|
||||
# v.co[0] -= diff
|
||||
|
||||
# o.location += mathutils.Vector((diff, 0.0, 0.0)) @ o.matrix_world.inverted()
|
||||
|
||||
# for c in o.children:
|
||||
# if is_metrics_object(c):
|
||||
# c.location -= mathutils.Vector((diff, 0.0, 0.0)) @ o.matrix_world.inverted()
|
||||
|
||||
# return ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue