[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [2114] trunk/py/scripts/addons/modules/ curve_utils.py: added some more methods of evaluating the curve.

Campbell Barton ideasman42 at gmail.com
Sun Jul 10 19:27:58 CEST 2011


Revision: 2114
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=2114
Author:   campbellbarton
Date:     2011-07-10 17:27:57 +0000 (Sun, 10 Jul 2011)
Log Message:
-----------
added some more methods of evaluating the curve.

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-10 11:29:59 UTC (rev 2113)
+++ trunk/py/scripts/addons/modules/curve_utils.py	2011-07-10 17:27:57 UTC (rev 2114)
@@ -92,10 +92,7 @@
 def solve_curvature(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,
+    from mathutils.geometry import (intersect_line_line,
                                     )
 
     p1_a = p1 + n1
@@ -126,7 +123,7 @@
 def points_to_bezier(points_orig,
                      double_limit=0.0001,
                      kink_tolerance=0.25,
-                     bezier_tolerance=0.02,  # error distance, scale dependant
+                     bezier_tolerance=0.05,  # error distance, scale dependant
                      subdiv=8,
                      angle_span=0.95,  # 1.0 tries to evaluate splines of 180d
                      ):
@@ -360,28 +357,75 @@
             self.points[0].is_joint, self.points[-1].is_joint = joint
 
             self.calc_all()
+            # raise Exception("END")
 
-        def bezier_solve_(self):
-            """ Calculate bezier handles,
-                assume the splines have been broken up.
-
-                http://polymathprogrammer.com/
+        def intersect_line(self, l1, l2, reverse=False):
+            """ Spectial kind of intersection, works in 3d on the plane
+                defimed by the points normal and the line.
             """
 
-            p1 = self.points[0]
-            p2 = self.points[-1]
+            from mathutils.geometry import (intersect_point_line,
+                                            )
 
-            line_ix_p1 = self.points[len(self.points) // 3]
-            line_ix_p2 = self.points[int((len(self.points) / 3) * 2)]
+            if reverse:
+                p_first = self.points[-1]
+                no = -self.points[-1].no
+                point_iter = reversed(self.points[:-1])
+            else:
+                p_first = self.points[0]
+                no = self.points[0].no
+                point_iter = self.points[1:]
 
-            u = 1 / 3
-            v = 2 / 3
+            # calculate the line right angles to the line
+            bi_no = (no - no.project(l2 - l1)).normalized()
 
-            p0x, p0y, p0z = p1.co
-            p1x, p1y, p1z = line_ix_p1.co
-            p2x, p2y, p2z = line_ix_p2.co
-            p3x, p3y, p3z = p2.co
-            
+            bi_l1 = p_first.co
+            bi_l2 = p_first.co + bi_no
+
+            for p_apex in point_iter:
+                ix, fac = intersect_point_line(p_apex.co, bi_l1, bi_l2)
+
+                if fac < 0.0001:
+
+                    if reverse:
+                        p_apex_other = p_apex.next
+                    else:
+                        p_apex_other = p_apex.prev
+
+                    # find the exact point on the line between the apex and
+                    # the middle
+                    p_test_1 = intersect_point_line(p_apex.co,
+                                                    l1,
+                                                    l2)[0]
+                    p_test_2 = intersect_point_line(p_apex_other.co,
+                                                    l1,
+                                                    l2)[0]
+
+                    w1 = (p_test_1 - p_apex.co).length
+                    w2 = (p_test_2 - p_apex_other.co).length
+
+                    #assert(w1 + w2 != 0)
+                    try:
+                        fac = w1 / (w1 + w2)
+                    except ZeroDivisionError:
+                        fac = 0.5
+                    assert(fac >= 0.0 and fac <= 1.0)
+
+                    p_apex_co = p_apex.co.lerp(p_apex_other.co, fac)
+                    p_apex_no = p_apex.no.lerp(p_apex_other.no, fac)
+                    p_apex_no.normalize()
+
+                    # visualize_line(p_mid.to_3d(), corner.to_3d())
+                    # visualize_line(p_apex.co.to_3d(), p_apex_co.to_3d())
+
+                    return p_apex_co, p_apex_no, p_apex
+
+            # intersection not found
+            return None, None, None
+
+
+        @staticmethod
+        def bez_solve(p0, p1, p2, p3, u, v):
             ui = 1.0 - u
             vi = 1.0 - v
             u_p3 = u * u * u
@@ -389,14 +433,6 @@
             ui_p3 = ui * ui * ui
             vi_p3 = vi * vi * vi
 
-
-            # --- snip
-
-            q1 = Vector()
-            q2 = Vector()
-
-            pos = Vector(), Vector(), Vector(), Vector()
-
             a = 3.0 * ui * ui * u
             b = 3.0 * ui * u * u
             c = 3.0 * vi * vi * v
@@ -407,26 +443,117 @@
                 assert(0)
                 return 0
 
-            q1.x = p1x - (ui_p3 * p0x + u_p3 * p3x)
-            q1.y = p1y - (ui_p3 * p0y + u_p3 * p3y)
-            q1.z = p1z - (ui_p3 * p0z + u_p3 * p3z)
+            q1 = p1 - (ui_p3 * p0 + u_p3 * p3)
+            q2 = p2 - (vi_p3 * p0 + v_p3 * p3)
 
-            q2.x = p2x - (vi_p3 * p0x + v_p3 * p3x)
-            q2.y = p2y - (vi_p3 * p0y + v_p3 * p3y)
-            q2.z = p2z - (vi_p3 * p0z + v_p3 * p3z)
+            return ((d * q1 - b * q2) / det,
+                    (-c * q1 + a * q2) / det
+                    )
 
-            pos[1].x = (d * q1.x - b * q2.x) / det
-            pos[1].y = (d * q1.y - b * q2.y) / det
-            pos[1].z = (d * q1.z - b * q2.z) / det
+        def bezier_solve__math1(self):
+            """ Calculate bezier handles,
+                assume the splines have been broken up.
 
-            pos[2].x = ((-c) * q1.x + a * q2.x) / det
-            pos[2].y = ((-c) * q1.y + a * q2.y) / det
-            pos[2].z = ((-c) * q1.z + a * q2.z) / det
+                http://polymathprogrammer.com/
+            """
 
-            self.handle_left = pos[1]
-            self.handle_right = pos[2]
+            def get(f, min=0.0, max=1.0):
+                f = (f * (max - min) + min)
+                return self.points[int((len(self.points) - 1) * f)].co
+            
+            
+            p1 = get(0.0)
+            p2 = get(1.0)
+            i1 = get(1/3)
+            i2 = get(2/3)
 
-        def bezier_solve(self):
+            pos = __class__.bez_solve(p1, i1, i2, p2, 1.0 / 3.0, 2.0 / 3.0)
+            self.handle_left = self.points[0].co + (pos[0] - self.points[0].co)
+            self.handle_right = self.points[-1].co + (pos[1] - self.points[-1].co)
+        
+        def bezier_solve__math2(self):
+
+            def get(f, min=0.0, max=1.0):
+                f = (f * (max - min) + min)
+                return self.points[int((len(self.points) - 1) * f)].co
+
+            p1 = get(0.0, min=0.0, max=0.5)
+            p2 = get(1.0, min=0.0, max=0.5)
+            i1 = get(1/3, min=0.0, max=0.5)
+            i2 = get(2/3, min=0.0, max=0.5)
+            
+            pos_a = __class__.bez_solve(p1, i1, i2, p2, 1.0 / 3.0, 2.0 / 3.0)
+            
+            p1 = get(0.0, min=0.5, max=1.0)
+            p2 = get(1.0, min=0.5, max=1.0)
+            i1 = get(1/3, min=0.5, max=1.0)
+            i2 = get(2/3, min=0.5, max=1.0)
+            
+            pos_b = __class__.bez_solve(p1, i1, i2, p2, 1.0 / 3.0, 2.0 / 3.0)
+
+            self.handle_left = self.points[0].co + (pos_a[0] - self.points[0].co) * 2
+            self.handle_right = self.points[-1].co + (pos_b[1] - self.points[-1].co) * 2
+
+        def bezier_solve__inkscape(self):
+                        
+            # static void
+            # estimate_bi(Point bezier[4], unsigned const ei,
+            #             Point const data[], double const u[], unsigned const len)
+            def estimate_bi(bezier, ei, data, u):
+
+                def B0(u): return ( ( 1.0 - u )  *  ( 1.0 - u )  *  ( 1.0 - u ) )
+                def B1(u): return ( 3 * u  *  ( 1.0 - u )  *  ( 1.0 - u ) )
+                def B2(u): return ( 3 * u * u  *  ( 1.0 - u ) )
+                def B3(u): return ( u * u * u )
+
+                # assert( not (1 <= ei and ei <= 2))
+                oi = 3 - ei
+                num = [0.0, 0.0, 0.0]
+                den = 0.0
+                
+                for i in range(len(data)):
+                    ui = u[i];
+                    b = [
+                        B0(ui),
+                        B1(ui),
+                        B2(ui),
+                        B3(ui)
+                    ]
+
+                    for d in range(3):
+                        num[d] += (b[ei] * (b[0]  * bezier[0][d] +
+                                           b[oi] * bezier[oi][d] +
+                                           b[3]  * bezier[3][d] +
+                                           - data[i][d]))
+
+                    den -= b[ei] * b[ei]
+
+                if den:
+                    for d in range(3):
+                        bezier[ei][d] = num[d] / den
+                else:
+                    bezier[ei] = (oi * bezier[0] + ei * bezier[3]) / 3.0
+            bezier = [
+                self.points[0].co,
+                self.points[0].co.lerp(self.points[-1].co, 1/3),
+                self.points[0].co.lerp(self.points[-1].co, 2/3),
+                self.points[-1].co,
+            ]
+            data = [p.co for p in self.points]
+            u = [i / len(self.points) for i in range(len(self.points))]
+            estimate_bi(bezier, 1, data, u)
+            estimate_bi(bezier, 2, data, u)
+            estimate_bi(bezier, 1, data, u)
+            estimate_bi(bezier, 2, data, u)
+            estimate_bi(bezier, 1, data, u)
+            estimate_bi(bezier, 2, data, u)
+            estimate_bi(bezier, 1, data, u)
+            estimate_bi(bezier, 2, data, u)
+            
+            self.handle_left = bezier[1]
+            self.handle_right = bezier[2]
+
+        def bezier_solve_ideasman42(self):
             from mathutils.geometry import (intersect_point_line,
                                             intersect_line_line,
                                             )
@@ -449,56 +576,110 @@
             # visualize_line(p1.co, l1_co)
             # visualize_line(p2.co, l2_co)
 
-            # picking 1/2 and 2/3'rds works best

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list