Commit: b40acb2d98f2d95c7d2300b966798cf40b7b9eca
Author: Jonathan deWerd
Date:   Thu Jul 17 11:25:23 2014 -0400
https://developer.blender.org/rBb40acb2d98f2d95c7d2300b966798cf40b7b9eca

Added new eval code (computes first and second surface partials). Still buggy 
near multi-knots.

===================================================================

M       source/blender/blenkernel/BKE_curve.h
M       source/blender/blenkernel/intern/curve.cpp
M       source/blender/editors/curve/editcurve_add.c
M       source/blender/makesdna/DNA_curve_types.h

===================================================================

diff --git a/source/blender/blenkernel/BKE_curve.h 
b/source/blender/blenkernel/BKE_curve.h
index e40ed00..8420b86 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -53,6 +53,8 @@ typedef struct CurveCache {
        struct Path *path;
 } CurveCache;
 
+#define NURBS_MAX_ORDER 10
+
 #define KNOTSU(nu)      ( (nu)->orderu + (nu)->pntsu + (((nu)->flagu & 
CU_NURB_CYCLIC) ? ((nu)->orderu - 1) : 0) )
 #define KNOTSV(nu)      ( (nu)->orderv + (nu)->pntsv + (((nu)->flagv & 
CU_NURB_CYCLIC) ? ((nu)->orderv - 1) : 0) )
 
diff --git a/source/blender/blenkernel/intern/curve.cpp 
b/source/blender/blenkernel/intern/curve.cpp
index 7b51ff5..26faac0 100644
--- a/source/blender/blenkernel/intern/curve.cpp
+++ b/source/blender/blenkernel/intern/curve.cpp
@@ -872,132 +872,226 @@ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct 
BezTriple *bezt, float r_p
 }
 
 /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ 
*/
+float nurbs_eps = 1e-5;
 
-
-static void calcknots(float *knots, const int pnts, const short order, const 
short flag)
+/* uv: 1=u 2=v */
+static void makeknots(Nurb *nu, short uv)
 {
-       /* knots: number of pnts NOT corrected for cyclic */
-       const int pnts_order = pnts + order;
-       float k;
-       int a;
-
-       switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
-               case CU_NURB_ENDPOINT:
-                       k = 0.0;
-                       for (a = 1; a <= pnts_order; a++) {
-                               knots[a - 1] = k;
-                               if (a >= order && a <= pnts)
-                                       k += 1.0f;
-                       }
-                       break;
-               case CU_NURB_BEZIER:
-                       /* Warning, the order MUST be 2 or 4,
-                        * if this is not enforced, the displist will be 
corrupt */
-                       if (order == 4) {
-                               k = 0.34;
-                               for (a = 0; a < pnts_order; a++) {
-                                       knots[a] = floorf(k);
-                                       k += (1.0f / 3.0f);
-                               }
-                       }
-                       else if (order == 3) {
-                               k = 0.6f;
-                               for (a = 0; a < pnts_order; a++) {
-                                       if (a >= order && a <= pnts)
-                                               k += 0.5f;
-                                       knots[a] = floorf(k);
-                               }
-                       }
-                       else {
-                               printf("bez nurb curve order is not 3 or 4, 
should never happen\n");
-                       }
-                       break;
-               default:
-                       for (a = 0; a < pnts_order; a++) {
-                               knots[a] = (float)a;
+       bool u = uv==1;
+       int flags=0, pnts=0, order=0;
+       if (u) {
+               if (!BKE_nurb_check_valid_u(nu)) return;
+               if (nu->knotsu) MEM_freeN(nu->knotsu);
+               flags = nu->flagu;
+               pnts = nu->pntsu;
+               order = nu->orderu;
+       } else {
+               if (!BKE_nurb_check_valid_v(nu)) return;
+               if (nu->knotsv) MEM_freeN(nu->knotsv);
+               flags = nu->flagv;
+               pnts = nu->pntsv;
+               order = nu->orderv;
+       }
+       printf("p:%i o:%i\n",pnts,order);
+       int num_knots = pnts + order;
+       if (flags & CU_NURB_CYCLIC) num_knots += order-1;
+       float *knots = (float*)MEM_callocN(sizeof(float)*num_knots, 
"makeknots");
+       if (flags & CU_NURB_BEZIER) {
+               /* Previous versions of blender supported "Bezier" knot 
vectors. These
+                * are useless to the user. *All* NURBS surfaces can be 
transformed into
+                * Bezier quilts (grids of connected Bezier surfaces). The 
"Bezier" knot
+                * vector is only an intermediate mathematical step in this 
process.
+                * Bezier quilts may be exposed to the user but there is no 
point in having
+                * the option to use Bezier-style knot vectors without 
Bezier-style controls.
+                *           |------------------ pnts+order -------------|
+                *           |--ord--||-ord-1-||-ord-1-||-ord-1-||--ord--|
+                * Bezier:  { 0 0 0 0   1 1 1    2 2 2    3 3 3   4 4 4 4 }
+                */
+               int v=0;
+               for (int i=0; i<order; i++)
+                       knots[i] = v;
+               for (int i=order,reps=0; i<pnts; i++) {
+                       if (reps==0) {
+                               v += 1;
+                               reps = order-1;
                        }
-                       break;
+                       knots[i] = v;
+               }
+               for (int i=pnts; i<pnts+order; i++)
+                       knots[i] = v;
+       } else if (flags & CU_NURB_ENDPOINT) {
+               /* "Endpoint" knot vectors ensure that the first and last knots 
are
+                * repeated $order times so that the valid NURBS domain 
actually touches
+                * the edges of the control polygon. These are the default.
+                *  |------- pnts+order ------------|
+                *  |-order-||--pnts-order-||-order-|
+                * { 0 0 0 0 1 2 3 4 5 6 7 8 9 9 9 9 }
+                */
+               for (int i=0; i<order; i++)
+                       knots[i] = 0;
+               int v=1;
+               for (int i=order; i<pnts; i++)
+                       knots[i] = v++;
+               for (int i=pnts; i<pnts+order; i++)
+                       knots[i] = v;
+       } else if ((flags&CU_NURB_CYCLIC) || true) {
+               /* Uniform knot vectors are the simplest mathematically but 
they create
+                * the annoying problem where the edges of the surface do not 
reach the
+                * edges of the control polygon which makes positioning them 
difficult.
+                *  |------ pnts+order --------|
+                *  |-----pnts----||---order---|
+                * { 0 1 2 3 4 5 6  7 8 9 10 11 }
+                */
+               /* Cyclic knot vectors are equivalent to uniform knot vectors 
over
+                * a control polygon of pnts+(order-1) points for a total of
+                * pnts+(order-1)+order knots. The additional (order-1) control 
points
+                * are repeats of the first (order-1) control points. This 
guarantees
+                * that all derivatives match at the join point.
+                *  |----- (pnts+order-1)+order --------|
+                *  |-----pnts----||--reps-||---order---|
+                * { 0 1 2 3 4 5 6  7  8  9  10 11 12 13 }
+                */
+               for (int i=0; i<num_knots; i++)
+                       knots[i]=i;
        }
+       /*
+       printf("Knots%s: ",u?"u":"v");
+       for (int i=0; i<num_knots; i++)
+               printf((i!=num_knots-1)?"%f, ":"%f\n", knots[i]);
+        */
+       
+       if (u)
+               nu->knotsu=knots;
+       else
+               nu->knotsv=knots;
 }
 
-static void makecyclicknots(float *knots, int pnts, short order)
-/* pnts, order: number of pnts NOT corrected for cyclic */
+void BKE_nurb_knot_calc_u(Nurb *nu)
 {
-       int a, b, order2, c;
-
-       if (knots == NULL)
-               return;
-
-       order2 = order - 1;
-
-       /* do first long rows (order -1), remove identical knots at endpoints */
-       if (order > 2) {
-               b = pnts + order2;
-               for (a = 1; a < order2; a++) {
-                       if (knots[b] != knots[b - a])
-                               break;
-               }
-               if (a == order2)
-                       knots[pnts + order - 2] += 1.0f;
-       }
-
-       b = order;
-       c = pnts + order + order2;
-       for (a = pnts + order2; a < c; a++) {
-               knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]);
-               b--;
-       }
+       makeknots(nu, 1);
 }
 
+void BKE_nurb_knot_calc_v(Nurb *nu)
+{
+       makeknots(nu, 2);
+}
 
-
-static void makeknots(Nurb *nu, short uv)
+/* Points on the surface of a NURBS curve are defined as an affine combination
+ * (sum of coeffs is 1) of points from the control polygon. HOWEVER, the
+ * locality property of NURBS dictates that at most $order consecutive
+ * control points are nonzero at a given curve coordinate u (or v, but we 
assume
+ * u WLOG for the purposes of naming the variable). Therefore
+ *     C(u) = \sum_{j=0}^n   Njp(u)*Pj
+ *          = \sum_{j=i-p}^j Njp(u)*Pj
+ *          = N(i-p)p*P(i-p) + N(i-p+1)p*P(i-p+1) + ... + Nip*Pi
+ * for u in knot range [u_i, u_{i+1}) given the m+1 knots
+ *     U[] = {u0, u1, ..., um}
+ * Arguments:
+ * uv = 1:u, 2:v
+ *  u = the curve parameter, as above (u is actually v if uv==2)
+ * returns: i such that basis functions i-p,i-p+1,...,i are possibly nonzero
+ */
+static int nurbs_nz_basis_range(Nurb *nu, int uv, float u)
 {
-       if (nu->type == CU_NURBS) {
-               if (uv == 1) {
-                       if (nu->knotsu)
-                               MEM_freeN(nu->knotsu);
-                       if (BKE_nurb_check_valid_u(nu)) {
-                               nu->knotsu = (float*)MEM_callocN(4 + 
sizeof(float) * KNOTSU(nu), "makeknots");
-                               if (nu->flagu & CU_NURB_CYCLIC) {
-                                       calcknots(nu->knotsu, nu->pntsu, 
nu->orderu, 0);  /* cyclic should be uniform */
-                                       makecyclicknots(nu->knotsu, nu->pntsu, 
nu->orderu);
-                               }
-                               else {
-                                       calcknots(nu->knotsu, nu->pntsu, 
nu->orderu, nu->flagu);
-                               }
+       int num_knots = (uv==1)? KNOTSU(nu) : KNOTSV(nu);
+       float *knots  = (uv==1)? nu->knotsu : nu->knotsv;
+       int order     = (uv==1)? nu->orderu : nu->orderv;
+       int p = order-1; /* p is the NURBS degree */
+       int n = num_knots-p; /* = number of control points + 1 */
+       
+       if (u>=knots[n+1])
+               return n;
+       if (u<=knots[p])
+               return p;
+       int low=p, high=n+1, mid=(low+high)/2;
+       while (u<knots[mid] || u>=knots[mid+1]) {
+               if (u<knots[mid]) high=mid;
+               else              low=mid;
+               mid = (low+high)/2;
+       }
+       return mid; /* called i in nurbs_basis_eval */
+}
+
+/* Computes the p+1=order nonvanishing NURBS basis functions at coordinate u.
+ * Arguments:
+ * uv = 1:u, 2:v
+ *  i = the return value of nurbs_nz_basis_range or -1 to compute automatically
+ *  u = the curve parameter, as above (u is actually v if uv==2)
+ *  nd= the number of derivatives to calculate (0 = just regular basis funcs)
+ * out = an array to put N(i-p),N(i-p+1),...,N(i) and their derivatives into
+ *  out[0][0]=N(i-p)        out[0][1]=N(i-p+1)        ...   out[0][p]=N(i)
+ *  out[1][0]=N'(i-p)       out[1][1]=N'(i-p+1)       ...   out[1][p]=N'(i)
+ *  ...
+ *  out[nd-1][0]=N'''(i-p)  out[nd-1][1]=N'''(i-p+1)  ...   
out[nd-1][p]=N'''(i)
+ *                 ^ let ''' stand for differentiation nd-1 times
+ * Adapted from Piegl&Tiller 1995
+ */
+static void nurbs_basis_eval(Nurb *nu, int uv, float u, int i, float 
out[][NURBS_MAX_ORDER], int nd) {
+       if (.99<u && u<1.01) {
+               i=4;
+       }
+       int num_knots = (uv==1)? KNOTSU(nu) : KNOTSV(nu);
+       float *U      = (uv==1)? nu->knotsu : nu->knotsv;
+       int order     = (uv==1)? nu->orderu : nu->orderv;
+       int p = order-1; /* p is the NURBS degree */
+       int n = num_knots-p; /* = number of control points + 1 */
+       if (i==-1) /* index st N(i-p),N(i-p+1),...,N(i) are nonzero */
+               i = nurbs_nz_basis_range(nu, uv, u);
+       double left[NURBS_MAX_ORDER], right[NURBS_MAX_ORDER];
+       double ndu[NURBS_MAX_ORDER][NURBS_MAX_ORDER];
+       double a[2][NURBS_MAX_ORDER];
+       double saved,temp;
+       
+       /* First, compute the 0th derivatives of the basis functions. */
+       ndu[0][0] = 1.0;
+       for (int j=1; j<=p; j++) {
+               left[j] = u-U[i+1-j];
+               right[j] = U[i+j]-u;
+               saved = 0;
+               /* Upper and lower triangles of Piegl&Tiller eval grid */
+               for (int r=0; r<j; r++) {
+                       ndu[j][r] = right[r+1]+left[j-r];
+                       temp = ndu[r][j-1]/ndu[j][r];
+                       ndu[r][j] = saved+right[r+1]*temp;
+                       saved = left[j-r]*temp;
+               }
+               ndu[j][j] = saved;
+       }
+       for (int j=0; j<=p; j++)
+               out[0][j] = ndu[j][p];
+       
+       /* Now compute the higher nd derivatives */
+       for (int r=0; r<=p; r++) {
+               int s1=0, s2=1, j1=0, j2=0;
+               a[0][0] = 1.0;
+               for (int k=1; k<=nd && k<=n; k++) {
+                       double d = 0.0;
+                       int rk=r-k, pk=p-k, j=0;
+                       if (r>=k) {
+                               a[s2][0] = a[s1][0]/ndu[pk+1][rk];
+                               d = a[s2][0]*ndu[

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to