[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [14688] trunk/blender/source/blender/src/ editipo.c: Bugfix:

Joshua Leung aligorith at gmail.com
Mon May 5 08:38:19 CEST 2008


Revision: 14688
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=14688
Author:   aligorith
Date:     2008-05-05 08:38:19 +0200 (Mon, 05 May 2008)

Log Message:
-----------
Bugfix:

IPO-Smooth should now give better results. It uses a moving-window approach, which looks at two points on either side of the point in interest (a total of 5 in optimal conditions), and does a weighted average on it.

Modified Paths:
--------------
    trunk/blender/source/blender/src/editipo.c

Modified: trunk/blender/source/blender/src/editipo.c
===================================================================
--- trunk/blender/source/blender/src/editipo.c	2008-05-05 06:30:19 UTC (rev 14687)
+++ trunk/blender/source/blender/src/editipo.c	2008-05-05 06:38:19 UTC (rev 14688)
@@ -3793,6 +3793,12 @@
 		MEM_freeN(old_bezts);
 }
 
+
+/* temp struct used for smooth_ipo */
+typedef struct tSmooth_Bezt {
+	float *h1, *h2, *h3;	/* bezt->vec[0,1,2][1] */
+} tSmooth_Bezt;
+
 void smooth_ipo(void)
 {
 	EditIpo *ei;
@@ -3804,7 +3810,6 @@
 	ei= G.sipo->editipo;
 	for(b=0; b<G.sipo->totipo; b++, ei++) {
 		if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
-		
 			ok= 0;
 			if(G.sipo->showkey) ok= 1;
 			else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2;
@@ -3813,52 +3818,94 @@
 			if(ok) {
 				IpoCurve *icu= ei->icu;
 				BezTriple *bezt;
-				float meanValSum = 0.0f, meanVal;
-				float valDiff;
-				int i, totSel = 0;
+				int i, x, totSel = 0;
 				
 				/* check if enough points */
 				if (icu->totvert >= 3) {
-					/* first loop through - obtain average value */
+					/* first loop through - count how many verts are selected, and fix up handles */
 					bezt= icu->bezt;
-					for (i=1; i < icu->totvert; i++, bezt++) {						
+					for (i=0; i < icu->totvert; i++, bezt++) {						
 						if (BEZSELECTED(bezt)) {							
 							/* line point's handles up with point's vertical position */
 							bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
-							if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
-							if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
+							if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
+							if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
 							
 							/* add value to total */
-							meanValSum += bezt->vec[1][1];
 							totSel++;
 						}
 					}
 					
-					/* calculate mean value */
-					meanVal= meanValSum / totSel;
-					
-					/* second loop through - update point positions */
-					bezt= icu->bezt;
-					for (i=0; i < icu->totvert; i++, bezt++) {						
-						if (BEZSELECTED(bezt)) {
-							/* 1. calculate difference between the points 
-							 * 2. move point half-way along that distance 
-							 */
-							if (bezt->vec[1][1] > meanVal) {
-								/* bezt val above mean */
-								valDiff= bezt->vec[1][1] - meanVal;
-								bezt->vec[1][1]= meanVal + (valDiff / 2);
+					/* if any points were selected, allocate tSmooth_Bezt points to work on */
+					if (totSel >= 3) {
+						tSmooth_Bezt *tarray, *tsb;
+						
+						/* allocate memory in one go */
+						tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
+						
+						/* populate tarray with data of selected points */
+						bezt= icu->bezt;
+						for (i=0, x=0; (i < icu->totvert) && (x < totSel); i++, bezt++) {
+							if (BEZSELECTED(bezt)) {
+								/* tsb simply needs pointer to vec, and index */
+								tsb->h1 = &bezt->vec[0][1];
+								tsb->h2 = &bezt->vec[1][1];
+								tsb->h3 = &bezt->vec[2][1];
+								
+								/* advance to the next tsb to populate */
+								if (x < totSel- 1) 
+									tsb++;
+								else
+									break;
 							}
-							else {
-								/* bezt val below mean */
-								valDiff= meanVal - bezt->vec[1][1];
-								bezt->vec[1][1] = bezt->vec[1][1] + (valDiff / 2);								
+						}
+						
+						/* calculate the new smoothed ipo's with weighted averages:
+						 *	- this is done with two passes
+						 *	- uses 5 points for each operation (which stores in the relevant handles)
+						 *	-	previous: w/a ratio = 3:5:2:1:1
+						 *	- 	next: w/a ratio = 1:1:2:5:3
+						 */
+						
+						/* round 1: calculate previous and next */ 
+						tsb= tarray;
+						for (i=0; i < totSel; i++, tsb++) {
+							/* don't touch end points (otherwise, curves slowly explode) */
+							if (ELEM(i, 0, (totSel-1)) == 0) {
+								tSmooth_Bezt *tP1 = tsb - 1;
+								tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
+								tSmooth_Bezt *tN1 = tsb + 1;
+								tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
+								
+								float p1 = *tP1->h2;
+								float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
+								float c1 = *tsb->h2;
+								float n1 = *tN1->h2;
+								float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
+								
+								/* calculate previous and next */
+								*tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
+								*tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
 							}
 						}
+						
+						/* round 2: calculate new values and reset handles */
+						tsb= tarray;
+						for (i=0; i < totSel; i++, tsb++) {
+							/* calculate new position by averaging handles */
+							*tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
+							
+							/* reset handles now */
+							*tsb->h1 = *tsb->h2;
+							*tsb->h3 = *tsb->h2;
+						}
+						
+						/* free memory required for tarray */
+						MEM_freeN(tarray);
 					}
 				}
-			
-				/* recalc handles */
+				
+				/* recalculate handles */
 				calchandles_ipocurve(icu);
 			}
 		}





More information about the Bf-blender-cvs mailing list