[GRASS-SVN] r56365 - grass/trunk/raster/r.mapcalc

svn_grass at osgeo.org svn_grass at osgeo.org
Wed May 22 12:44:32 PDT 2013


Author: glynn
Date: 2013-05-22 12:44:31 -0700 (Wed, 22 May 2013)
New Revision: 56365

Modified:
   grass/trunk/raster/r.mapcalc/r.mapcalc.html
   grass/trunk/raster/r.mapcalc/r3.mapcalc.html
   grass/trunk/raster/r.mapcalc/xround.c
Log:
Allow control over return type, rounding to arbitrary multiples (issue #1976)


Modified: grass/trunk/raster/r.mapcalc/r.mapcalc.html
===================================================================
--- grass/trunk/raster/r.mapcalc/r.mapcalc.html	2013-05-22 18:27:41 UTC (rev 56364)
+++ grass/trunk/raster/r.mapcalc/r.mapcalc.html	2013-05-22 19:44:31 UTC (rev 56365)
@@ -318,8 +318,9 @@
 not(x)                  1 if x is zero, 0 otherwise
 pow(x,y)                x to the power y                                *
 rand(a,b)               random value x : a <= x < b
-round(x)                round x to nearest integer                      *
-round(x, y)             round x to y decimal places                     *
+round(x)                round x to nearest integer                      I
+round(x,y)              round x to nearest multiple of y
+round(x,y,z)            round x to nearest y*i+z for some integer i
 sin(x)                  sine of x (x is in degrees)                     F
 sqrt(x)                 square root of x                                F
 tan(x)                  tangent of x (x is in degrees)                  F
@@ -336,9 +337,6 @@
  null()                 NULL value
 </pre></div>
 Note, that the row() and col() indexing starts with 1.
-<p>
-round(x, y) supports a negative number of decimal places: for example, 
-round(119, -1) results in 120, and round(119, -2) results in 100.
 
 
 <h3>FLOATING POINT VALUES IN THE EXPRESSION</h3>

Modified: grass/trunk/raster/r.mapcalc/r3.mapcalc.html
===================================================================
--- grass/trunk/raster/r.mapcalc/r3.mapcalc.html	2013-05-22 18:27:41 UTC (rev 56364)
+++ grass/trunk/raster/r.mapcalc/r3.mapcalc.html	2013-05-22 19:44:31 UTC (rev 56365)
@@ -222,8 +222,9 @@
 not(x)                  1 if x is zero, 0 otherwise
 pow(x,y)                x to the power y                                *
 rand(a,b)               random value x : a <= x < b
-round(x)                round x to nearest integer                      *
-round(x, y)             round x to y decimal places                     *
+round(x)                round x to nearest integer                      I
+round(x,y)              round x to nearest multiple of y
+round(x,y,z)            round x to nearest y*i+z for some integer i
 sin(x)                  sine of x (x is in degrees)                     F
 sqrt(x)                 square root of x                                F
 tan(x)                  tangent of x (x is in degrees)                  F
@@ -243,9 +244,6 @@
  null()                 NULL value
 </pre></div>
 Note, that the row(), col() and depth() indexing starts with 1. 
-<p>
-round(x, y) supports a negative number of decimal places: for example, 
-round(119, -1) results in 120, and round(119, -2) results in 100.
 
 
 <h2>FLOATING POINT VALUES IN THE EXPRESSION</h2>

Modified: grass/trunk/raster/r.mapcalc/xround.c
===================================================================
--- grass/trunk/raster/r.mapcalc/xround.c	2013-05-22 18:27:41 UTC (rev 56364)
+++ grass/trunk/raster/r.mapcalc/xround.c	2013-05-22 19:44:31 UTC (rev 56365)
@@ -9,195 +9,197 @@
 #include "func_proto.h"
 
 /**********************************************************************
-round(x) rounds x to nearest integer
-round(x, y) rounds x to y decimal places
+round(x, step, start)
 
-  if input is CELL (which is an integer already)
-  and the number of decimal places is 0
-  the input argument (argv[0]) is simply copied to the output cell.
+  rounds x to nearest value in the sequence
+    y[i] = i * step + start
 
-  if the input is double, the input is rounded by adding .5 to positive
-  numbers, and subtracting .5 from negatives.
 **********************************************************************/
 
-/* d_round(x) rounds x to nearest integer value, handles negative correctly */
+/* i_round(x) rounds x to nearest value, handles negative correctly */
 
-static double d_round(double x)
+static double i_round(double x, double step, double start)
 {
-    if (!IS_NULL_D(&x)) {
-	x = floor(x + 0.5);
-    }
-
+    x -= start;
+    x /= step;
+    x = floor(x + 0.5);
+    x *= step;
+    x += start;
     return x;
 }
 
 /**********************************************************************/
 
-/* d_roundd(x, y) rounds x to y decimal places, handles negative correctly */
-
-static double d_roundd(double x, int y)
-{
-    if (!IS_NULL_D(&x)) {
-	double pow10, intx, sgn = 1.;
-
-	if (x < 0.) {
-	    sgn = -1.;
-	    x = -x;
-	}
-	if (y == 0)
-	    return (double)(sgn * d_round(x));
-	else if (y > 0) {
-	    pow10 = pow(10., y);
-	    intx = floor(x);
-	    return (double)(sgn * (intx + d_round((double)((x - intx) * pow10)) / pow10));
-	}
-	else {
-	    pow10 = pow(10., -y);
-	    return (double)(sgn * d_round((double)(x / pow10)) * pow10);
-	}
-    }
-
-    return x;
-}
-
-/**********************************************************************/
 int f_round(int argc, const int *argt, void **args)
 {
+    const DCELL *arg1 = args[1];
     int i;
 
     if (argc < 1)
 	return E_ARG_LO;
-    if (argc > 2)
+    if (argc > 3)
 	return E_ARG_HI;
 
+    if (argc == 1 && argt[0] != CELL_TYPE)
+	return E_RES_TYPE;
+    if (argt[1] != DCELL_TYPE)
+	return E_ARG_TYPE;
+    if (argc > 1 && argt[2] != DCELL_TYPE)
+	return E_ARG_TYPE;
+    if (argc > 2 && argt[3] != DCELL_TYPE)
+	return E_ARG_TYPE;
+
     if (argc == 1) {
-	switch (argt[1]) {
-	case CELL_TYPE:
-	    {
-		CELL *arg1 = args[1];
-		CELL *res = args[0];
+	CELL *res = args[0];
 
-		for (i = 0; i < columns; i++)
-		    if (IS_NULL_C(&arg1[i]))
-			SET_NULL_C(&res[i]);
-		    else
-			res[i] = arg1[i];
-		return 0;
+	for (i = 0; i < columns; i++) {
+	    if (IS_NULL_D(&arg1[i]))
+		SET_NULL_C(&res[i]);
+	    else {
+		DCELL x = i_round(arg1[i], 1.0, 0.0);
+		if (x > 2147483647.0 || x < -2147483647.0)
+		    SET_NULL_C(&res[i]);
+		else
+		    res[i] = (CELL) x;
 	    }
-	case FCELL_TYPE:
-	    {
-		FCELL *arg1 = args[1];
-		FCELL *res = args[0];
-
-		for (i = 0; i < columns; i++)
-		    if (IS_NULL_F(&arg1[i]))
-			SET_NULL_F(&res[i]);
-		    else
-			res[i] = d_round(arg1[i]);
-		return 0;
-	    }
-	case DCELL_TYPE:
-	    {
-		DCELL *arg1 = args[1];
-		DCELL *res = args[0];
-
-		for (i = 0; i < columns; i++)
-		    if (IS_NULL_D(&arg1[i]))
-			SET_NULL_D(&res[i]);
-		    else
-			res[i] = d_round(arg1[i]);
-		return 0;
-	    }
-	default:
-	    return E_INV_TYPE;
 	}
+	return 0;
     }
-    else {    /* argc == 2 */
-	int digits;
-	DCELL *arg2;
+    else if (argc == 2) {
+	const DCELL *arg2 = args[2];
 
-	switch (argt[1]) {
-	case CELL_TYPE:
-	    {
-		CELL *arg1 = args[1];
-		CELL *res = args[0];
+	switch (argt[0]) {
+        case CELL_TYPE:
+            {
+                CELL *res = args[0];
+    
+                for (i = 0; i < columns; i++) {
+                    if (IS_NULL_D(&arg1[i]))
+                        SET_NULL_C(&res[i]);
+                    else if (IS_NULL_D(&arg2[i]))
+                        SET_NULL_C(&res[i]);
+                    else {
+                        DCELL x = i_round(arg1[i], arg2[i], 0.0);
+                        if (x > 2147483647.0 || x < -2147483647.0)
+                            SET_NULL_C(&res[i]);
+                        else
+                            res[i] = (CELL) x;
+                    }
+                }
+                return 0;
+            }
+        case FCELL_TYPE:
+            {
+                FCELL *res = args[0];
+    
+                for (i = 0; i < columns; i++)
+                    if (IS_NULL_D(&arg1[i]))
+                        SET_NULL_F(&res[i]);
+                    else if (IS_NULL_D(&arg2[i]))
+                        SET_NULL_F(&res[i]);
+                    else
+                        res[i] = (FCELL) i_round(arg1[i], arg2[i], 0.0);
+                return 0;
+            }
+        case DCELL_TYPE:
+            {
+                DCELL *res = args[0];
+    
+                for (i = 0; i < columns; i++)
+                    if (IS_NULL_D(&arg1[i]))
+                        SET_NULL_D(&res[i]);
+                    else if (IS_NULL_D(&arg2[i]))
+                        SET_NULL_D(&res[i]);
+                    else
+                        res[i] = (DCELL) i_round(arg1[i], arg2[i], 0.0);
+                return 0;
+            }
+        default:
+            return E_INV_TYPE;
+        }
+    }
+    else if (argc == 3) {
+	const DCELL *arg2 = args[2];
+	const DCELL *arg3 = args[3];
 
-		arg2 = args[2];
-
-		for (i = 0; i < columns; i++)
-		    if (IS_NULL_C(&arg1[i]))
-			SET_NULL_C(&res[i]);
-		    else {
-			if (arg2[i] >= 0)
-			    digits = d_round(arg2[i]) + 0.5;
-			else
-			    digits = d_round(arg2[i]) - 0.5;
-			if (digits >= 0)
-			    res[i] = arg1[i];
-			else {
-			    if (arg1[i] >= 0)
-				res[i] = d_roundd(arg1[i], digits) + 0.5;
-			    else
-				res[i] = d_roundd(arg1[i], digits) - 0.5;
-			}
-		    }
-		return 0;
-	    }
-	case FCELL_TYPE:
-	    {
-		FCELL *arg1 = args[1];
-		FCELL *res = args[0];
-
-		arg2 = args[2];
-
-		for (i = 0; i < columns; i++)
-		    if (IS_NULL_F(&arg1[i]))
-			SET_NULL_F(&res[i]);
-		    else {
-			if (arg2[i] >= 0)
-			    digits = d_round(arg2[i]) + 0.5;
-			else
-			    digits = d_round(arg2[i]) - 0.5;
-			res[i] = d_roundd(arg1[i], digits);
-		    }
-		return 0;
-	    }
-	case DCELL_TYPE:
-	    {
-		DCELL *arg1 = args[1];
-		DCELL *res = args[0];
-
-		arg2 = args[2];
-
-		for (i = 0; i < columns; i++)
-		    if (IS_NULL_D(&arg1[i]))
-			SET_NULL_D(&res[i]);
-		    else {
-			if (arg2[i] >= 0)
-			    digits = d_round(arg2[i]) + 0.5;
-			else
-			    digits = d_round(arg2[i]) - 0.5;
-			res[i] = d_roundd(arg1[i], digits);
-		    }
-		return 0;
-	    }
-	default:
-	    return E_INV_TYPE;
-	}
+	switch (argt[0]) {
+        case CELL_TYPE:
+            {
+                CELL *res = args[0];
+    
+                for (i = 0; i < columns; i++) {
+                    if (IS_NULL_D(&arg1[i]))
+                        SET_NULL_C(&res[i]);
+                    else if (IS_NULL_D(&arg2[i]))
+                        SET_NULL_C(&res[i]);
+                    else if (IS_NULL_D(&arg3[i]))
+                        SET_NULL_C(&res[i]);
+                    else {
+                        DCELL x = i_round(arg1[i], arg2[i], arg3[i]);
+                        if (x > 2147483647.0 || x < -2147483647.0)
+                            SET_NULL_C(&res[i]);
+                        else
+                            res[i] = (CELL) x;
+                    }
+                }
+                return 0;
+            }
+        case FCELL_TYPE:
+            {
+                FCELL *res = args[0];
+    
+                for (i = 0; i < columns; i++)
+                    if (IS_NULL_D(&arg1[i]))
+                        SET_NULL_F(&res[i]);
+                    else if (IS_NULL_D(&arg2[i]))
+                        SET_NULL_F(&res[i]);
+                    else if (IS_NULL_D(&arg3[i]))
+                        SET_NULL_F(&res[i]);
+                    else
+                        res[i] = (FCELL) i_round(arg1[i], arg2[i], arg3[i]);
+                return 0;
+            }
+        case DCELL_TYPE:
+            {
+                DCELL *res = args[0];
+    
+                for (i = 0; i < columns; i++)
+                    if (IS_NULL_D(&arg1[i]))
+                        SET_NULL_D(&res[i]);
+                    else if (IS_NULL_D(&arg2[i]))
+                        SET_NULL_D(&res[i]);
+                    else if (IS_NULL_D(&arg3[i]))
+                        SET_NULL_D(&res[i]);
+                    else
+                        res[i] = (DCELL) i_round(arg1[i], arg2[i], arg3[i]);
+                return 0;
+            }
+        default:
+            return E_INV_TYPE;
+        }
     }
+    else
+	return E_WTF;
 }
 
 int c_round(int argc, int *argt)
 {
     if (argc < 1)
 	return E_ARG_LO;
-    if (argc > 2)
+    if (argc > 3)
 	return E_ARG_HI;
 
-    argt[0] = argt[1];
-    
-    if (argc == 2)
+    argt[0] = CELL_TYPE;
+    if (argc > 1 && argt[0] < argt[2])
+	argt[0] = argt[2];
+    if (argc > 2 && argt[0] < argt[3])
+	argt[0] = argt[3];
+
+    argt[1] = DCELL_TYPE;
+    if (argc > 1)
 	argt[2] = DCELL_TYPE;
+    if (argc > 2)
+	argt[3] = DCELL_TYPE;
 
     return 0;
 }



More information about the grass-commit mailing list