[fix] fix bezier when individual handles sit on points

bonus: prevent eternal while loop
This commit is contained in:
jrkb 2025-05-29 19:32:56 +02:00
parent 963d89daf9
commit 04229fbc31

View file

@ -215,6 +215,34 @@ def calc_bezier_length(bezier_point_1, bezier_point_2, resolution=20):
return length return length
def get_real_beziers_and_lengths(bezier_spline_obj, resolution_factor):
beziers = []
lengths = []
total_length = 0
n_bezier_points = len(bezier_spline_obj.bezier_points)
real_n_bezier_points = len(bezier_spline_obj.bezier_points)
if bezier_spline_obj.use_cyclic_u:
n_bezier_points += 1
for i in range(0, n_bezier_points - 1):
i_a = i % (n_bezier_points - 1)
i_b = (i_a + 1) % real_n_bezier_points
bezier = [
bezier_spline_obj.bezier_points[i_a],
bezier_spline_obj.bezier_points[i_b],
]
length = calc_bezier_length(
bezier[0],
bezier[1],
int(bezier_spline_obj.resolution_u * resolution_factor),
)
total_length += length
beziers.append(bezier)
lengths.append(length)
# if total_length > distance:
# break
return beziers, lengths, total_length
def calc_point_on_bezier_spline( def calc_point_on_bezier_spline(
bezier_spline_obj, distance, output_tangent=False, resolution_factor=1.0 bezier_spline_obj, distance, output_tangent=False, resolution_factor=1.0
): ):
@ -241,6 +269,17 @@ def calc_point_on_bezier_spline(
if distance <= 0: if distance <= 0:
p = bezier_spline_obj.bezier_points[0] p = bezier_spline_obj.bezier_points[0]
travel = (p.co - p.handle_left).normalized() * distance travel = (p.co - p.handle_left).normalized() * distance
# in case the handles sit on the points
# we interpolate the travel from points of the bezier
# if the bezier points sit on each other we have same issue
# but that is then to be fixed in the bezier
if p.handle_left == p.co and len(bezier_spline_obj.bezier_points) > 1:
beziers, lengths, total_length = get_real_beziers_and_lengths(bezier_spline_obj,
resolution_factor)
travel_point = calc_point_on_bezier(beziers[0][1], beziers[0][0], 0.001)
travel = travel_point.normalized() * distance
location = p.co + travel location = p.co + travel
if output_tangent: if output_tangent:
p2 = bezier_spline_obj.bezier_points[1] p2 = bezier_spline_obj.bezier_points[1]
@ -249,30 +288,8 @@ def calc_point_on_bezier_spline(
else: else:
return location return location
beziers = [] beziers, lengths, total_length = get_real_beziers_and_lengths(bezier_spline_obj,
lengths = [] resolution_factor)
total_length = 0
n_bezier_points = len(bezier_spline_obj.bezier_points)
real_n_bezier_points = len(bezier_spline_obj.bezier_points)
if bezier_spline_obj.use_cyclic_u:
n_bezier_points += 1
for i in range(0, n_bezier_points - 1):
i_a = i % (n_bezier_points - 1)
i_b = (i_a + 1) % real_n_bezier_points
bezier = [
bezier_spline_obj.bezier_points[i_a],
bezier_spline_obj.bezier_points[i_b],
]
length = calc_bezier_length(
bezier[0],
bezier[1],
int(bezier_spline_obj.resolution_u * resolution_factor),
)
total_length += length
beziers.append(bezier)
lengths.append(length)
# if total_length > distance:
# break
iterated_distance = 0 iterated_distance = 0
for i in range(0, len(beziers)): for i in range(0, len(beziers)):
@ -290,7 +307,16 @@ def calc_point_on_bezier_spline(
# if we are here, the point is outside the spline # if we are here, the point is outside the spline
last_i = len(beziers) - 1 last_i = len(beziers) - 1
p = beziers[last_i][1] p = beziers[last_i][1]
travel = (p.handle_right - p.co).normalized() * (distance - total_length) travel = (p.handle_right - p.co).normalized() * (distance - total_length)
# in case the handles sit on the points
# we interpolate the travel from points of the bezier
# if the bezier points sit on each other we have same issue
# but that is then to be fixed in the bezier
if p.handle_right == p.co and len(beziers) > 0:
travel_point = calc_point_on_bezier(beziers[-1][1], beziers[-1][0], 0.001)
travel = travel_point.normalized() * (distance - total_length)
location = p.co + travel location = p.co + travel
if output_tangent: if output_tangent:
tangent = calc_tangent_on_bezier(beziers[last_i][0], p, 1) tangent = calc_tangent_on_bezier(beziers[last_i][0], p, 1)
@ -580,7 +606,7 @@ def update_available_fonts():
f = abc3d_data.available_fonts.add() f = abc3d_data.available_fonts.add()
f.font_name = font_name f.font_name = font_name
f.face_name = face_name f.face_name = face_name
print(f"{__name__} added {font_name} {face_name}") print(f"{utils.prefix()}::update_available_fonts: {__name__} added {font_name} {face_name}")
# def update_available_texts(): # def update_available_texts():
@ -1474,26 +1500,39 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
mom, advance + glyph_advance, False, True mom, advance + glyph_advance, False, True
) )
if psi == si: if psi == si:
n_max = 100
n = 0
while ( while (
previous_location - new_location previous_location - new_location
).length > glyph_advance and psi == si: ).length > glyph_advance and psi == si and n < n_max:
curve_compensation = curve_compensation - glyph_advance * 0.01 curve_compensation = curve_compensation - glyph_advance * 0.01
new_location, si = calc_point_on_bezier_curve( tmp_new_location, si = calc_point_on_bezier_curve(
mom, mom,
advance + glyph_advance + curve_compensation, advance + glyph_advance + curve_compensation,
output_tangent=False, output_tangent=False,
output_spline_index=True, output_spline_index=True,
) )
if tmp_new_location == new_location:
print(f"{utils.prefix()}::set_text_on_curve::compensate_curvature while loop overstaying welcome")
break
new_location = tmp_new_location
n += 1
n = 0
while ( while (
previous_location - new_location previous_location - new_location
).length < glyph_advance and psi == si: ).length < glyph_advance and psi == si and n < n_max:
curve_compensation = curve_compensation + glyph_advance * 0.01 curve_compensation = curve_compensation + glyph_advance * 0.01
new_location, si = calc_point_on_bezier_curve( tmp_new_location, si = calc_point_on_bezier_curve(
mom, mom,
advance + glyph_advance + curve_compensation, advance + glyph_advance + curve_compensation,
output_tangent=False, output_tangent=False,
output_spline_index=True, output_spline_index=True,
) )
if tmp_new_location == new_location:
print(f"{utils.prefix()}::set_text_on_curve::compensate_curvature while loop overstaying welcome")
break
new_location = tmp_new_location
n += 1
advance = advance + glyph_advance + curve_compensation advance = advance + glyph_advance + curve_compensation
glyph_index += 1 glyph_index += 1