[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [2094] trunk/py/scripts/addons/modules/ curve_utils.py: wip commit, basic bezier evaluation working, but still need to rewrite some parts of this script.
Campbell Barton
ideasman42 at gmail.com
Tue Jul 5 19:54:11 CEST 2011
Revision: 2094
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=2094
Author: campbellbarton
Date: 2011-07-05 17:54:10 +0000 (Tue, 05 Jul 2011)
Log Message:
-----------
wip commit, basic bezier evaluation working, but still need to rewrite some parts of this script.
Modified Paths:
--------------
trunk/py/scripts/addons/modules/curve_utils.py
Modified: trunk/py/scripts/addons/modules/curve_utils.py
===================================================================
--- trunk/py/scripts/addons/modules/curve_utils.py 2011-07-05 07:54:55 UTC (rev 2093)
+++ trunk/py/scripts/addons/modules/curve_utils.py 2011-07-05 17:54:10 UTC (rev 2094)
@@ -17,3 +17,830 @@
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
+
+import bpy
+
+def line_point_side_v2(l1, l2, pt):
+ return (((l1[0] - pt[0]) * (l2[1] - pt[1])) -
+ ((l2[0] - pt[0]) * (l1[1] - pt[1])))
+
+
+def shell_angle_to_dist(angle):
+ from math import cos
+ return 1.0 if (angle < 0.0001) else abs(1.0 / cos(angle))
+
+
+def vis_curve_object():
+ scene = bpy.data.scenes[0] # weak!
+ cu = bpy.data.curves.new(name="Line", type='CURVE')
+ ob = bpy.data.objects.new(name="Test", object_data=cu)
+ ob.layers = [True] * 20
+ base = scene.objects.link(ob)
+ return ob
+
+
+def vis_curve_spline(p1, h1, p2, h2):
+ ob = vis_curve_object()
+ spline = ob.data.splines.new(type='BEZIER')
+ spline.bezier_points.add(1)
+ spline.bezier_points[0].co = p1.to_3d()
+ spline.bezier_points[1].co = p2.to_3d()
+
+ spline.bezier_points[0].handle_right = h1.to_3d()
+ spline.bezier_points[1].handle_left = h2.to_3d()
+
+
+def vis_circle_object(co, rad=1.0):
+ import math
+ scene = bpy.data.scenes[0] # weak!
+ ob = bpy.data.objects.new(name="Circle", object_data=None)
+ ob.rotation_euler.x = math.pi / 2
+ ob.location = co.to_3d()
+ ob.empty_draw_size = rad
+ ob.layers = [True] * 20
+ base = scene.objects.link(ob)
+ return ob
+
+
+def visualize_line(p1, p2, p3=None, rad=None):
+ pair = p1.to_3d(), p2.to_3d()
+
+ ob = vis_curve_object()
+ spline = ob.data.splines.new(type='POLY')
+ spline.points.add(1)
+ for co, v in zip((pair), spline.points):
+ v.co.xyz = co
+
+ if p3:
+ spline = ob.data.splines.new(type='POLY')
+ spline.points[0].co.xyz = p3.to_3d()
+ print(rad)
+ if rad is not None:
+ vis_circle_object(p3, rad)
+
+
+def treat_points(points,
+ double_limit=0.0001,
+ ):
+
+ # first remove doubles
+ tot_len = 0.0
+ if double_limit != 0.0:
+ i = len(points) - 1
+ while i > 0:
+ length = (points[i] - points[i - 1]).length
+ if length < double_limit:
+ del points[i]
+ if i >= len(points):
+ i -= 1
+ else:
+ tot_len += length
+ i -= 1
+ return tot_len
+
+
+def solve_curvature_2d(p1, p2, n1, n2, fac, fallback):
+ """ Add a nice circular curvature on
+ """
+ from mathutils import Vector
+ from mathutils.geometry import (barycentric_transform,
+ intersect_line_line,
+ intersect_point_line,
+ )
+
+ p1_a = p1 + n1
+ p2_a = p2 - n2
+
+ isect = intersect_line_line(p1.to_3d(),
+ p1_a.to_3d(),
+ p2.to_3d(),
+ p2_a.to_3d(),
+ )
+
+ if isect:
+ corner = isect[0]
+ else:
+ corner = None
+
+ if corner:
+ corner = corner.xy
+ p1_first_order = p1.lerp(corner, fac)
+ p2_first_order = corner.lerp(p2, fac)
+ co = p1_first_order.lerp(p2_first_order, fac)
+
+ return co.xy
+ else:
+ # cant interpolate. just return interpolated value
+ return fallback.copy() # p1.lerp(p2, fac)
+
+
+def points_to_bezier(points_orig,
+ double_limit=0.0001,
+ kink_tolerance=0.25,
+ bezier_tolerance=0.1, # error distance, scale dependant
+ subdiv=8,
+ angle_span=0.95, # 1.0 tries to evaluate splines of 180d
+ ):
+
+ import math
+ from mathutils import Vector
+
+ class Point(object):
+ __slots__ = ("co",
+ "angle",
+ "no",
+ "is_joint",
+ "next",
+ "prev",
+ )
+
+ def __init__(self, co):
+ self.co = co
+ self.is_joint = False
+
+ def calc_angle(self):
+ if self.prev is None or self.next is None:
+ self.angle = 0.0
+ else:
+ va = self.co - self.prev.co
+ vb = self.next.co - self.co
+ self.angle = va.angle(vb, 0.0)
+
+ # XXX 2D
+ if line_point_side_v2(self.prev.co,
+ self.co,
+ self.next.co,
+ ) < 0.0:
+
+ self.angle = -self.angle
+
+ def angle_diff(self):
+ """ use for detecting joints, detect difference in angle from
+ surrounding points.
+ """
+ if self.prev is None or self.next is None:
+ return 0.0
+ else:
+ if (self.angle > self.prev.angle and
+ self.angle > self.next.angle):
+ return abs(self.angle - self.prev.angle) / math.pi
+ else:
+ return 0.0
+
+ def angle_filter(self):
+ tot = 1
+ a = self.angle
+ if self.prev:
+ tot += 1
+ a += self.prev.angle
+
+ if self.next:
+ tot += 1
+ a += self.next.angle
+
+ a = a / tot
+ return 0.0 if abs(a) < 0.01 else a
+
+ def calc_normal(self):
+ v1 = v2 = None
+ if self.prev and not self.prev.is_joint:
+ v1 = (self.co - self.prev.co).normalized()
+ if self.next and not self.next.is_joint:
+ v2 = (self.next.co - self.co).normalized()
+
+ if v1 and v2:
+ self.no = (v1 + v2).normalized()
+ elif v1:
+ self.no = v1
+ elif v2:
+ self.no = v2
+ else:
+ print("Warning, assigning dummy normal")
+ self.no = Vector(0, 1)
+
+
+ class Spline(object):
+ __slots__ = ("points",
+ "handle_left",
+ "handle_right",
+ "next",
+ "prev",
+ )
+
+ def __init__(self, points):
+ self.points = points
+
+ def link_points(self):
+
+ if hasattr(self.points[0], "prev"):
+ raise Exception("already linked")
+
+ p_prev = None
+ for p in self.points:
+ p.prev = p_prev
+ p_prev = p
+
+ p_prev = None
+ for p in reversed(self.points):
+ p.next = p_prev
+ p_prev = p
+
+ def split(self, i, is_joint=False):
+ prev = self.prev
+ next = self.next
+
+ if is_joint:
+ self.points[i].is_joint = True
+
+ # share a point
+ spline_a = Spline(self.points[:i + 1])
+ spline_b = Spline(self.points[i:])
+
+ # invalidate self, dont reuse!
+ self.points = None
+
+ spline_a.next = spline_b
+ spline_b.prev = spline_a
+
+ spline_a.prev = prev
+ spline_b.next = next
+ if prev:
+ prev.next = spline_a
+ if next:
+ next.prev = spline_b
+
+ return spline_a, spline_b
+
+ def calc_angle(self):
+ for p in self.points:
+ p.calc_angle()
+
+ def calc_normal(self):
+ for p in self.points:
+ p.calc_normal()
+
+ def calc_all(self):
+ self.link_points()
+ self.calc_angle()
+ self.calc_normal()
+
+ def total_angle(self):
+ return abs(sum((p.angle for p in self.points)))
+
+ def redistribute(self, segment_length, smooth=False):
+ if len(self.points) == 1:
+ return
+
+ from mathutils.geometry import intersect_line_sphere_2d
+
+ p_line = p = self.points[0]
+ points = [(p.co.copy(), p.co.copy())]
+ p = p.next
+
+ def point_add(co, p=None):
+ co = co.copy()
+ co_smooth = co.copy()
+
+ if smooth:
+ if p is None:
+ pass # works ok but no smoothing
+ elif (p.prev.no - p.no).length < 0.001:
+ pass # normals are too similar, paralelle
+ elif (p.angle > 0.0) != (p.prev.angle > 0.0):
+ pass
+ else:
+ # visualize_line(p.co, p.co + p.no)
+
+ # this assumes co is on the line
+ fac = ((p.prev.co - co).length /
+ (p.prev.co - p.co).length)
+
+ assert(fac >= 0.0 and fac <= 1.0)
+
+ co_smooth = solve_curvature_2d(p.prev.co,
+ p.co,
+ p.prev.no,
+ p.no,
+ fac,
+ co,
+ )
+
+ points.append((co, co_smooth))
+
+ def point_step(p):
+ if p.is_joint or p.next is None:
+ point_add(p.co)
+ return None
+ else:
+ return p.next
+
+ print("START")
+ while p:
+ # we want the first pont past the segment size
+
+ #if p.is_joint:
+ # vis_circle_object(p.co)
+
+ length = (points[-1][0] - p.co).length
+
+ if abs(length - segment_length) < 0.00001:
+ # close enough to be considered on the circle bounds
+ point_add(p.co)
+ p_line = p
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list