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);
                        }
                }


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

Reply via email to