Skip to content
Snippets Groups Projects
Commit 23a8be0f authored by Campbell Barton's avatar Campbell Barton
Browse files

support for 3d splines

parent 96336775
No related branches found
No related tags found
No related merge requests found
...@@ -88,7 +88,7 @@ def treat_points(points, ...@@ -88,7 +88,7 @@ def treat_points(points,
return tot_len return tot_len
def solve_curvature_2d(p1, p2, n1, n2, fac, fallback): def solve_curvature(p1, p2, n1, n2, fac, fallback):
""" Add a nice circular curvature on """ Add a nice circular curvature on
""" """
from mathutils import Vector from mathutils import Vector
...@@ -100,24 +100,23 @@ def solve_curvature_2d(p1, p2, n1, n2, fac, fallback): ...@@ -100,24 +100,23 @@ def solve_curvature_2d(p1, p2, n1, n2, fac, fallback):
p1_a = p1 + n1 p1_a = p1 + n1
p2_a = p2 - n2 p2_a = p2 - n2
isect = intersect_line_line(p1.to_3d(), isect = intersect_line_line(p1,
p1_a.to_3d(), p1_a,
p2.to_3d(), p2,
p2_a.to_3d(), p2_a,
) )
if isect: if isect:
corner = isect[0] corner = isect[0].lerp(isect[1], 0.5)
else: else:
corner = None corner = None
if corner: if corner:
corner = corner.xy
p1_first_order = p1.lerp(corner, fac) p1_first_order = p1.lerp(corner, fac)
p2_first_order = corner.lerp(p2, fac) p2_first_order = corner.lerp(p2, fac)
co = p1_first_order.lerp(p2_first_order, fac) co = p1_first_order.lerp(p2_first_order, fac)
return co.xy return co
else: else:
# cant interpolate. just return interpolated value # cant interpolate. just return interpolated value
return fallback.copy() # p1.lerp(p2, fac) return fallback.copy() # p1.lerp(p2, fac)
...@@ -183,7 +182,7 @@ def points_to_bezier(points_orig, ...@@ -183,7 +182,7 @@ def points_to_bezier(points_orig,
self.no = v2 self.no = v2
else: else:
print("Warning, assigning dummy normal") print("Warning, assigning dummy normal")
self.no = Vector(0, 1) self.no = Vector((0.0, 1, 0.0))
class Spline(object): class Spline(object):
...@@ -258,7 +257,7 @@ def points_to_bezier(points_orig, ...@@ -258,7 +257,7 @@ def points_to_bezier(points_orig,
if len(self.points) == 1: if len(self.points) == 1:
return return
from mathutils.geometry import intersect_line_sphere_2d from mathutils.geometry import intersect_line_sphere
p_line = p = self.points[0] p_line = p = self.points[0]
points = [(p.co.copy(), p.co.copy())] points = [(p.co.copy(), p.co.copy())]
...@@ -284,13 +283,13 @@ def points_to_bezier(points_orig, ...@@ -284,13 +283,13 @@ def points_to_bezier(points_orig,
assert(fac >= 0.0 and fac <= 1.0) assert(fac >= 0.0 and fac <= 1.0)
co_smooth = solve_curvature_2d(p.prev.co, co_smooth = solve_curvature(p.prev.co,
p.co, p.co,
p.prev.no, p.prev.no,
p.no, p.no,
fac, fac,
co, co,
) )
points.append((co, co_smooth)) points.append((co, co_smooth))
...@@ -327,11 +326,11 @@ def points_to_bezier(points_orig, ...@@ -327,11 +326,11 @@ def points_to_bezier(points_orig,
raise Exception("eek3") raise Exception("eek3")
# print(p_start, p.co, points[-1][0], segment_length) # print(p_start, p.co, points[-1][0], segment_length)
i1, i2 = intersect_line_sphere_2d(p_start, i1, i2 = intersect_line_sphere(p_start,
p.co, p.co,
points[-1][0], points[-1][0],
segment_length, segment_length,
) )
# print() # print()
# print(i1, i2) # print(i1, i2)
# assert(i1 is not None) # assert(i1 is not None)
...@@ -401,10 +400,10 @@ def points_to_bezier(points_orig, ...@@ -401,10 +400,10 @@ def points_to_bezier(points_orig,
# the middle # the middle
p_test_1 = intersect_point_line(p_apex.co, p_test_1 = intersect_point_line(p_apex.co,
l1, l1,
l2)[0].xy l2)[0]
p_test_2 = intersect_point_line(p_apex_other.co, p_test_2 = intersect_point_line(p_apex_other.co,
l1, l1,
l2)[0].xy l2)[0]
w1 = (p_test_1 - p_apex.co).length w1 = (p_test_1 - p_apex.co).length
w2 = (p_test_2 - p_apex_other.co).length w2 = (p_test_2 - p_apex_other.co).length
...@@ -443,8 +442,6 @@ def points_to_bezier(points_orig, ...@@ -443,8 +442,6 @@ def points_to_bezier(points_orig,
p1 = self.points[0] p1 = self.points[0]
p2 = self.points[-1] p2 = self.points[-1]
# ------ # ------
# take 2 # take 2
p_vec = (p2.co - p1.co).normalized() p_vec = (p2.co - p1.co).normalized()
...@@ -483,7 +480,7 @@ def points_to_bezier(points_orig, ...@@ -483,7 +480,7 @@ def points_to_bezier(points_orig,
p1_apex_co = None p1_apex_co = None
p = self.points[1] p = self.points[1]
while p and (not p.is_joint) and p != line_ix_p1: while p and (not p.is_joint) and p != line_ix_p1:
ix = intersect_point_line(p.co, p1.co, l1_co)[0].xy ix = intersect_point_line(p.co, p1.co, l1_co)[0]
length = (ix - p.co).length length = (ix - p.co).length
if length > l1_max: if length > l1_max:
l1_max = length l1_max = length
...@@ -494,7 +491,7 @@ def points_to_bezier(points_orig, ...@@ -494,7 +491,7 @@ def points_to_bezier(points_orig,
p2_apex_co = None p2_apex_co = None
p = self.points[-2] p = self.points[-2]
while p and (not p.is_joint) and p != line_ix_p2: while p and (not p.is_joint) and p != line_ix_p2:
ix = intersect_point_line(p.co, p2.co, l2_co)[0].xy ix = intersect_point_line(p.co, p2.co, l2_co)[0]
length = (ix - p.co).length length = (ix - p.co).length
if length > l2_max: if length > l2_max:
l2_max = length l2_max = length
...@@ -523,11 +520,11 @@ def points_to_bezier(points_orig, ...@@ -523,11 +520,11 @@ def points_to_bezier(points_orig,
# first need to reflect the second normal for angle comparison # first need to reflect the second normal for angle comparison
# first fist need the reflection normal # first fist need the reflection normal
no_ref = p_vec.to_3d().cross(p2.no.to_3d()).cross(p_vec.to_3d()).normalized() no_ref = p_vec.cross(p2.no).cross(p_vec).normalized()
l2_no_ref = p2.no.reflect(no_ref).normalized() l2_no_ref = p2.no.reflect(no_ref).normalized()
del no_ref del no_ref
from math import pi from math import pi
# This could be tweaked but seems to work well # This could be tweaked but seems to work well
fac_fac = (p1.co - p2.co).length * (0.5 / 0.75) * p1.no.angle(l2_no_ref) / pi fac_fac = (p1.co - p2.co).length * (0.5 / 0.75) * p1.no.angle(l2_no_ref) / pi
...@@ -540,25 +537,25 @@ def points_to_bezier(points_orig, ...@@ -540,25 +537,25 @@ def points_to_bezier(points_orig,
h1 = p1.co + (p1.no * h1_fac) h1 = p1.co + (p1.no * h1_fac)
h2 = p2.co - (p2.no * h2_fac) h2 = p2.co - (p2.no * h2_fac)
self.handle_left = h1 self.handle_left = h1
self.handle_right = h2 self.handle_right = h2
''' '''
visualize_line(p1.co, p1_apex_co) visualize_line(p1.co, p1_apex_co)
visualize_line(p1_apex_co, p2_apex_co) visualize_line(p1_apex_co, p2_apex_co)
visualize_line(p2.co, p2_apex_co) visualize_line(p2.co, p2_apex_co)
visualize_line(p1.co, p2.co) visualize_line(p1.co, p2.co)
''' '''
def bezier_error(self, error_max=-1.0, test_count=8): def bezier_error(self, error_max=-1.0, test_count=8):
from mathutils.geometry import interpolate_bezier from mathutils.geometry import interpolate_bezier
test_points = interpolate_bezier(self.points[0].co.to_3d(), test_points = interpolate_bezier(self.points[0].co,
self.handle_left, self.handle_left,
self.handle_right, self.handle_right,
self.points[-1].co.to_3d(), self.points[-1].co,
test_count, test_count,
) )
...@@ -569,7 +566,7 @@ def points_to_bezier(points_orig, ...@@ -569,7 +566,7 @@ def points_to_bezier(points_orig,
# this is a rough method measuring the error but should be good enough # this is a rough method measuring the error but should be good enough
# TODO. dont test against every single point. # TODO. dont test against every single point.
for co in test_points: for co in test_points:
co = co.xy co = co
# initial values # initial values
co_best = self.points[0].co co_best = self.points[0].co
...@@ -582,7 +579,7 @@ def points_to_bezier(points_orig, ...@@ -582,7 +579,7 @@ def points_to_bezier(points_orig,
co_best = p.co co_best = p.co
p_ix, fac = intersect_point_line(co, p.co, p.prev.co) p_ix, fac = intersect_point_line(co, p.co, p.prev.co)
p_ix = p_ix.xy p_ix = p_ix
if fac >= 0.0 and fac <= 1.0: if fac >= 0.0 and fac <= 1.0:
length = (co - p_ix).length length = (co - p_ix).length
if length < length_best: if length < length_best:
...@@ -704,10 +701,9 @@ def points_to_bezier(points_orig, ...@@ -704,10 +701,9 @@ def points_to_bezier(points_orig,
spline = cu.splines.new(type='POLY') spline = cu.splines.new(type='POLY')
spline.points.add(len(s.points) - 1) spline.points.add(len(s.points) - 1)
for p, v in zip(s.points, spline.points): for p, v in zip(s.points, spline.points):
v.co.xy = p.co v.co.xyz = p.co
ob = bpy.data.objects.new(name="Test", object_data=cu) ob = bpy.data.objects.new(name="Test", object_data=cu)
ob.layers = [True] * 20 ob.layers = [True] * 20
base = scene.objects.link(ob) base = scene.objects.link(ob)
...@@ -715,7 +711,7 @@ def points_to_bezier(points_orig, ...@@ -715,7 +711,7 @@ def points_to_bezier(points_orig,
base.select = True base.select = True
# base.layers = [True] * 20 # base.layers = [True] * 20
print(ob, "Done") print(ob, "Done")
def to_blend_curve(self, cu=None, cu_matrix=None): def to_blend_curve(self, cu=None, cu_matrix=None):
""" return new bezier spline datablock or add to an existing """ return new bezier spline datablock or add to an existing
""" """
...@@ -739,17 +735,17 @@ def points_to_bezier(points_orig, ...@@ -739,17 +735,17 @@ def points_to_bezier(points_orig,
elif s: elif s:
pt = s.points[0] pt = s.points[0]
hr = s.handle_left hr = s.handle_left
hl = (pt.co.xy + (pt.co.xy - hr.xy)) hl = (pt.co + (pt.co - hr))
elif s_prev: elif s_prev:
pt = s_prev.points[-1] pt = s_prev.points[-1]
hl = s_prev.handle_right hl = s_prev.handle_right
hr = (pt.co.xy + (pt.co.xy - hl.xy)) hr = (pt.co + (pt.co - hl))
else: else:
assert(0) assert(0)
bp.co.xy = pt.co bp.co.xyz = pt.co
bp.handle_left.xy = hl bp.handle_left.xyz = hl
bp.handle_right.xy = hr bp.handle_right.xyz = hr
handle_type = 'FREE' handle_type = 'FREE'
...@@ -831,10 +827,10 @@ def points_to_bezier(points_orig, ...@@ -831,10 +827,10 @@ def points_to_bezier(points_orig,
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.wm.open_mainfile(filepath="/root/curve_test1.blend") bpy.ops.wm.open_mainfile(filepath="/root/curve_test2.blend")
ob = bpy.data.objects["Curve"] ob = bpy.data.objects["Curve"]
points = [p.co.xy for s in ob.data.splines for p in s.points] points = [p.co.xyz for s in ob.data.splines for p in s.points]
print("points_to_bezier 1") print("points_to_bezier 1")
points_to_bezier(points) points_to_bezier(points)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment