[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17630] branches/nurbs/blender: More excellent work from Laurynas Duburas

Emmanuel Stone emmanuel.stone at gmail.com
Sat Nov 29 23:51:11 CET 2008


Revision: 17630
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17630
Author:   eman
Date:     2008-11-29 23:51:11 +0100 (Sat, 29 Nov 2008)

Log Message:
-----------
More excellent work from Laurynas Duburas
Non-destructive Refine for NURBS, works for weighted, uniform and cyclic surfaces/curves.
Hopefully this algorithm can be propigated to reduce/increase degree functions.
Note: Currently no proper UI, just a Refine button that adds a Knot in the middle of the surface, will eventually need interactive UI.
 

Modified Paths:
--------------
    branches/nurbs/blender/intern/nurbana/intern/NURBS_Knot.cpp
    branches/nurbs/blender/intern/nurbana/intern/NURBS_Knot.h
    branches/nurbs/blender/intern/nurbana/intern/Object_Base.cpp
    branches/nurbs/blender/intern/nurbana/intern/Object_Base.h
    branches/nurbs/blender/intern/nurbana/intern/Object_NURBS.cpp
    branches/nurbs/blender/intern/nurbana/intern/Object_NURBS.h
    branches/nurbs/blender/source/blender/src/buttons_editing.c
    branches/nurbs/blender/source/blender/src/editcurve.c

Modified: branches/nurbs/blender/intern/nurbana/intern/NURBS_Knot.cpp
===================================================================
--- branches/nurbs/blender/intern/nurbana/intern/NURBS_Knot.cpp	2008-11-29 22:16:23 UTC (rev 17629)
+++ branches/nurbs/blender/intern/nurbana/intern/NURBS_Knot.cpp	2008-11-29 22:51:11 UTC (rev 17630)
@@ -123,8 +123,34 @@
 	return(mid);
 } //eof NURBS_Knot::FindSpan()
 
+/*
+  Searches for knot span having u.
+  If u is less than first knot value KnotVector[first], changes u's value to KnotVector[first] and returns appropriate span.
+  If u is more than last knot value KnotVector[last],  changes u's value to KnotVector[last - 1] and returns appropriate span.
+*/
+int NURBS_Knot::FindSpanRef(nbReal &u, int first, int last, const nbReal *KnotVector) {
+	int low = first;
+	int high = last;
+	int mid = (low + high) / 2;
 
+	if (u >= KnotVector [last])
+		u = KnotVector [last - 1];
+	else if (u <= KnotVector [first])
+		u = KnotVector [first];
 
+	while (u < KnotVector[mid] || u >= KnotVector[mid+1]) {
+		if (u < KnotVector[mid])
+			high = mid;
+		else
+			low= mid;
+		mid = (low + high) / 2;
+	} //eow
+
+	return (mid);
+} //eof NURBS_Knot::FindSpan()
+
+
+
 void NURBS_Knot::Difference(nbReal *KV1, int L1, nbReal *KV2, int L2, nbReal *KV3, int &L3) {
 	// Given two Knot Vectors on same domain, store difference in KV3
 	int	KV1i,KV2i;
@@ -174,85 +200,140 @@
 
 
 void NURBS_Knot::Refine(Object_NURBS *obj, nbReal *X, int r, bool UV) {
-	int		a,b,i,j,k,l,m,n,ind,degree;
-	Point3d	*Qw,*Curve;
-	nbReal	*Ubar,alfa;
+	int		i,j,k,l,ind;
+	Point3d	*Qw, *bufferQw, *Curve, *bufferCurve;
+	nbReal	*Ubar, *bufferUbar, *knotVectCpy, *bufferKnotVectCpy, alfa;
+    const bool cyclic = obj -> Cyclic(UV);//for convenience
+	const int pitch = (UV ? obj -> Length(0) : obj -> Length(0) + r);
+	const int degree = obj -> Order(UV) - 1;
+	//extra space will be allocated before buffers Qw, Curve and Ubar for cyclics
+	const int extra = cyclic ? degree : 0;
+	const int oldKnotCount = obj -> Length(UV) + obj -> Order(UV);
+	const int oldKnotCount2 = obj -> Order(UV) + obj -> getLength(UV, 1);
+	const int newKnotCount = oldKnotCount + r;
+	// knot count including virtual knots
+	const int newKnotCount2 = oldKnotCount2 + r;
+	const int newLength = obj -> Length(UV) + r;
+	const int first = cyclic ? 0 : degree;
+	const int last = cyclic ? oldKnotCount - 1 : oldKnotCount - degree - 1;
+	const int a = FindSpanRef(X[0], first, last, obj -> KnotVector(UV));
 
 	// Allocate Memory for Qw
-	Qw= (Point3d*)MEM_callocN(sizeof(Point3d)*(obj -> Length(UV) + r + 1),"Refine() Qw");
-	Curve= (Point3d*)MEM_callocN(sizeof(Point3d)*(obj -> Length(UV) + r + 1),"Refine() Curve");
-	Ubar= (nbReal*)MEM_callocN(sizeof(nbReal)*(obj -> Length(UV) + obj -> Order(UV) + r + 1),"Refine() Ubar");
+	bufferQw = (Point3d*) MEM_callocN(sizeof(Point3d) * (obj -> Length(UV) + r + extra + extra + 1), "Refine() Qw");// + 1 is for Qw[k-degree-1] = Qw[k-degree]
+	bufferCurve = (Point3d*) MEM_callocN(sizeof(Point3d) * (obj -> Length(UV) + r + extra + extra), "Refine() Curve");
+	bufferUbar = (nbReal*) MEM_callocN(sizeof(nbReal) * (oldKnotCount2 + r + extra), "Refine() Ubar");
+	bufferKnotVectCpy = (nbReal*) MEM_callocN(sizeof(nbReal) * (oldKnotCount2 + extra), "Refine() knotVectCpy");
 
+    //skips extra space, if there is such
+	Qw = bufferQw + extra + 1;
+	Curve = bufferCurve + extra;
+	Ubar = bufferUbar + extra;
+	knotVectCpy = bufferKnotVectCpy + extra;
 
+	//fill knot vector copy(copy by itself is needed only for alfa calculation and Ubar initialization)
+	memcpy(knotVectCpy, obj -> KnotVector(UV), oldKnotCount2 * sizeof(*knotVectCpy));
+	//fill extra space around knotVectCpy if cyclic case
+	if (extra) {
+		nbReal firstK = knotVectCpy [0], lastK = knotVectCpy [oldKnotCount - 1];
+		for (int i = 1; i <= extra; i++) {
+			knotVectCpy [-i] = firstK - (lastK - knotVectCpy [oldKnotCount - i - 1]);
+			//knotVectCpy [m + i - 1] = lastK + knotVectCpy [i] - firstK;
+		}
+	}
+
 	// Allocate memory for curve
-	if (UV) {
-		obj -> SetLength(obj -> Length(0),obj -> Length(1)+r);
-		n= obj -> Length(0) * (obj -> Length(1) + r) - r - 1;
-		for (i= obj -> Length(0) * obj -> Length(1) - 1; i >= 0; i--) {
-			//      printf("n,i: %d,%d\n",n,i);
-			obj -> CtlPts()[n].x= obj -> CtlPts()[i].x;
-			obj -> CtlPts()[n].y= obj -> CtlPts()[i].y;
-			obj -> CtlPts()[n].z= obj -> CtlPts()[i].z;
-			!(i % obj -> Length(1)) ? n-= r+1: n--;
-		} //eof
-	} else {
-		obj -> SetLength(obj -> Length(0)+r,obj -> Length(1));
-	} //fi
+	if (UV)
+		obj -> SetLengthRef(obj -> Length(0), newLength);
+	else
+		obj -> SetLengthRef(newLength, obj -> Length(1));
 
 	// Decrement r
 	r--;
 
-	for (n= 0; n < obj -> Length(!UV); n++) {
+	for (int rowOffset = 0, n = 0; n < obj -> Length(!UV); n++, rowOffset += pitch) {
+		Point3d *oldPoints = obj -> CtlPts();
 		// Populate Curve
-		if (UV) {
-			for (i= 0; i < obj -> Length(1); i++) {
-				Curve[i].x= obj -> CtlPts()[i + n*(obj -> Length(1) + r + 1)].x;
-				Curve[i].y= obj -> CtlPts()[i + n*(obj -> Length(1) + r + 1)].y;
-				Curve[i].z= obj -> CtlPts()[i + n*(obj -> Length(1) + r + 1)].z;
+		if (!UV) {
+			oldPoints += rowOffset; //moves pointer to the n-th row
+			for (i= 0; i < obj -> Length(UV); i++, oldPoints++) {
+				Curve[i].x = oldPoints -> x;
+				Curve[i].y = oldPoints -> y;
+				Curve[i].z = oldPoints -> z;
+				Curve[i].H = oldPoints -> H;
+				if (1.0 != oldPoints -> H) {
+                    nbReal w = oldPoints -> H;
+                    Curve[i].x *= w;
+					Curve[i].y *= w;
+					Curve[i].z *= w;
+				}
 			} //eof
 		} else {
-			for (i= 0; i < obj -> Length(0); i++) {
-				Curve[i].x= obj -> CtlPts()[i*obj -> Length(1) + n].x;
-				Curve[i].y= obj -> CtlPts()[i*obj -> Length(1) + n].y;
-				Curve[i].z= obj -> CtlPts()[i*obj -> Length(1) + n].z;
+			oldPoints += n;// moves pointer to the n-th column
+			for (i= 0; i < obj -> Length(UV); i++, oldPoints += pitch) {//skips to new line by adding pitch
+				Curve[i].x = oldPoints -> x;
+				Curve[i].y = oldPoints -> y;
+				Curve[i].z = oldPoints -> z;
+				Curve[i].H = oldPoints -> H;
+				if (1.0 != oldPoints -> H) {
+                    nbReal w = oldPoints -> H;
+                    Curve[i].x *= w;
+					Curve[i].y *= w;
+					Curve[i].z *= w;
+				}
 			} //eof
 		} //fi
+        // fills space between realCurve and Curve (for cyclics)
+		if (cyclic) {
+			Point3d *copyTo = Curve - 1;
+			Point3d *copyFrom = Curve + obj -> Length (UV) - 1;
+			for (i = 0; i < extra; i++, copyTo--, copyFrom--) {
+				copyTo -> x = copyFrom -> x;
+			    copyTo -> y = copyFrom -> y;
+			    copyTo -> z = copyFrom -> z;
+			    copyTo -> H = copyFrom -> H;
+			}
+			copyTo = Curve + obj -> Length (UV);
+			copyFrom = Curve;
+			for (i = 0; i < extra; i++, copyTo++, copyFrom++) {
+				copyTo -> x = copyFrom -> x;
+			    copyTo -> y = copyFrom -> y;
+			    copyTo -> z = copyFrom -> z;
+			    copyTo -> H = copyFrom -> H;
+			}
+		}
+        // end populate Curve
 
+		const int b = FindSpanRef(X[r], first, last, obj -> KnotVector(UV)) + 1;
 
-		m= obj -> Length(UV) + obj -> Order(UV);
-		degree= obj -> Order(UV) - 1;
-
-		a= FindSpan(obj -> Length(UV),degree,X[0],obj -> KnotVector(UV));
-		b= FindSpan(obj -> Length(UV),degree,X[r],obj -> KnotVector(UV));
-		b++;
-
-		// Populate QW with Curve
-		for (i= 0; i <= a-degree; i++) {
-			Qw[i].x= Curve[i].x;
-			Qw[i].y= Curve[i].y;
-			Qw[i].z= Curve[i].z;
+		// Populate QW with Curve leaving gap for new CP's
+		for (i = 0 - extra; i <= a - degree; i++) {
+			Qw[i].x = Curve[i].x;
+			Qw[i].y = Curve[i].y;
+			Qw[i].z = Curve[i].z;
+			Qw[i].H = Curve[i].H;
 		} //eof
 
-		for (i= b-1; i <= obj -> Length(UV); i++) {
-			Qw[i+r+1].x= Curve[i].x;
-			Qw[i+r+1].y= Curve[i].y;
-			Qw[i+r+1].z= Curve[i].z;
+		for (i = b - 1; i < obj -> Length(UV) + extra; i++) {
+			Qw[i + r + 1].x = Curve[i].x;
+			Qw[i + r + 1].y = Curve[i].y;
+			Qw[i + r + 1].z = Curve[i].z;
+            Qw[i + r + 1].H = Curve[i].H; 
 		} //eof
 
-		for (i= 0; i <= a; i++)
-			Ubar[i]= obj -> KnotVector(UV)[i];
+        //copies starting knots to Ubar
+	    memcpy(Ubar - extra, knotVectCpy - extra, (a + 1 + extra) * sizeof(*Ubar));
+		//copies knots after gap
+		memcpy(Ubar + b + degree, knotVectCpy + b + degree - 1, (oldKnotCount2 - (b + degree) + 1) * sizeof(*Ubar));
 
-		for (i= b+degree; i <= m; i++)
-			Ubar[i+r+1]= obj -> KnotVector(UV)[i];
+		i = b + degree - 1;
+		k = b + degree + r;
 
-		i= b+degree-1;
-		k= b+degree+r;
-
 		for (j= r; j >= 0; j--) {
 			while (X[j] <= obj -> KnotVector(UV)[i] && i > a) {
 				Qw[k-degree-1].x= Curve[i-degree-1].x;
 				Qw[k-degree-1].y= Curve[i-degree-1].y;
 				Qw[k-degree-1].z= Curve[i-degree-1].z;
+				Qw[k-degree-1].H= Curve[i-degree-1].H;
 
 				Ubar[k]= obj -> KnotVector(UV)[i];
 				k--;
@@ -262,52 +343,96 @@
 			Qw[k-degree-1].x= Qw[k-degree].x;
 			Qw[k-degree-1].y= Qw[k-degree].y;
 			Qw[k-degree-1].z= Qw[k-degree].z;
+			Qw[k-degree-1].H= Qw[k-degree].H;
 
-			for (l= 1; l <= degree; l++) {
+			for (l = 1; l <= degree; l++) {
 				ind= k-degree+l;
-				alfa= Ubar[k+l]-X[j];
+				alfa = Ubar[k+l]-X[j];
 
 				if (fabs(alfa) == 0.0) {
 					Qw[ind-1].x= Qw[ind].x;
 					Qw[ind-1].y= Qw[ind].y;
 					Qw[ind-1].z= Qw[ind].z;
+					Qw[ind-1].H= Qw[ind].H;
 				} else {
-					alfa= alfa/(Ubar[k+l]-obj -> KnotVector(UV)[i-degree+l]);
+					alfa /= Ubar[k+l] - knotVectCpy[i-degree+l];
 					Qw[ind-1].x= alfa*Qw[ind-1].x + (1.0-alfa)*Qw[ind].x;
 					Qw[ind-1].y= alfa*Qw[ind-1].y + (1.0-alfa)*Qw[ind].y;
 					Qw[ind-1].z= alfa*Qw[ind-1].z + (1.0-alfa)*Qw[ind].z;
+					Qw[ind-1].H= alfa*Qw[ind-1].H + (1.0-alfa)*Qw[ind].H;
 				} //fi
 			} //eof
 			Ubar[k]= X[j];
+			//newly inserted knot appears at the end of knot vector also ...
+			if (cyclic && (b < 2 * degree)) {
+				//shift virtual knots
+				memmove(Ubar + newKnotCount + b - degree, Ubar + newKnotCount + b - degree - 1, (2 * degree - b) * sizeof(*Ubar));
+				// and write down new one
+				Ubar[newKnotCount + b - degree - 1] = obj -> KnotVector(UV)[oldKnotCount - degree + r - j - 1] + X[j];
+				//FIXME knotVectCpy also needs update for multiple inserts
+			}
 			k--;
 		} //eof
-
+		if (cyclic) {
+			int pre = b - degree;
+			Point3d *copyTo;
+			Point3d *copyFrom;
+			// copy cp's changed in pre buffer space
+			if (pre < 0) {
+				Point3d *copyTo = Qw + obj -> Length(UV) + r + 1 + pre;
+				Point3d *copyFrom = Qw + pre;
+				memcpy(copyTo, copyFrom, -pre * sizeof(*copyTo));

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list