浏览代码

r.mapcalc: enhance round()

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@56313 15284696-431f-4ddb-bdfa-cd5b030d7da7
Markus Metz 12 年之前
父节点
当前提交
3d1d147a93
共有 4 个文件被更改,包括 166 次插入65 次删除
  1. 1 1
      raster/r.mapcalc/function.c
  2. 5 1
      raster/r.mapcalc/r.mapcalc.html
  3. 5 1
      raster/r.mapcalc/r3.mapcalc.html
  4. 155 62
      raster/r.mapcalc/xround.c

+ 1 - 1
raster/r.mapcalc/function.c

@@ -89,7 +89,7 @@ func_desc func_descs[] = {
     {"ewres", c_double0, f_ewres},
     {"nsres", c_double0, f_nsres},
     {"tbres", c_double0, f_tbres},
-    {NULL}
+    {NULL, NULL, NULL}
 };
 
 void print_function_names(void)

+ 5 - 1
raster/r.mapcalc/r.mapcalc.html

@@ -318,7 +318,8 @@ nmode(x,y[,z...])       mode value of those listed, excluding NULLs     *
 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                      I
+round(x)                round x to nearest integer                      *
+round(x, y)             round x to y decimal places                     *
 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
@@ -335,6 +336,9 @@ Internal variables:
  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>

+ 5 - 1
raster/r.mapcalc/r3.mapcalc.html

@@ -222,7 +222,8 @@ nmode(x,y[,z...])       mode value of those listed, excluding NULLs     *
 not(x)                  1 if x is zero, 0 otherwise
 pow(x,y)                x to the power y                                *
 rand(a,b)               random value x : a &lt;= x &lt; b
-round(x)                round x to nearest integer                      I
+round(x)                round x to nearest integer                      *
+round(x, y)             round x to y decimal places                     *
 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
@@ -242,6 +243,9 @@ Internal variables:
  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>

+ 155 - 62
raster/r.mapcalc/xround.c

@@ -1,5 +1,6 @@
 
 #include <limits.h>
+#include <math.h>
 
 #include <grass/gis.h>
 #include <grass/raster.h>
@@ -8,91 +9,181 @@
 #include "func_proto.h"
 
 /**********************************************************************
-round(x)
-
-  rounds x to nearest integer.
+round(x) rounds x to nearest integer
+round(x, y) rounds x to y decimal places
 
   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.
 
   if the input is double, the input is rounded by adding .5 to positive
   numbers, and subtracting .5 from negatives.
 **********************************************************************/
 
-/* i_round(x) rounds x to nearest CELL value, handles negative correctly */
+/* d_round(x) rounds x to nearest integer value, handles negative correctly */
 
-static int i_round(double x)
+static double d_round(double x)
 {
-    int n;
-
-    if (IS_NULL_D(&x))
-	SET_NULL_C(&n);
-    else if (x > INT_MAX || x < -INT_MAX) {
-	SET_NULL_C(&n);
-	if (!IS_NULL_D(&x))
-	    overflow_occurred = 1;
-    }
-    else if (x >= 0.0)
-	n = x + .5;
-    else {
-	n = -x + .5;
-	n = -n;
+    if (!IS_NULL_D(&x)) {
+	x = floor(x + 0.5);
     }
 
-    return n;
+    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)
 {
-    int *res = args[0];
     int i;
 
     if (argc < 1)
 	return E_ARG_LO;
-    if (argc > 1)
+    if (argc > 2)
 	return E_ARG_HI;
 
-    if (argt[0] != CELL_TYPE)
-	return E_RES_TYPE;
-
-    switch (argt[1]) {
-    case CELL_TYPE:
-	{
-	    CELL *arg1 = args[1];
-
-	    for (i = 0; i < columns; i++)
-		if (IS_NULL_C(&arg1[i]))
-		    SET_NULL_C(&res[i]);
-		else
-		    res[i] = arg1[i];
-	    return 0;
+    if (argc == 1) {
+	switch (argt[1]) {
+	case CELL_TYPE:
+	    {
+		CELL *arg1 = args[1];
+		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;
+	    }
+	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;
 	}
-    case FCELL_TYPE:
-	{
-	    FCELL *arg1 = args[1];
-
-	    for (i = 0; i < columns; i++)
-		if (IS_NULL_F(&arg1[i]))
-		    SET_NULL_C(&res[i]);
-		else
-		    res[i] = i_round(arg1[i]);
-	    return 0;
-	}
-    case DCELL_TYPE:
-	{
-	    DCELL *arg1 = args[1];
-
-	    for (i = 0; i < columns; i++)
-		if (IS_NULL_D(&arg1[i]))
-		    SET_NULL_C(&res[i]);
-		else
-		    res[i] = i_round(arg1[i]);
-	    return 0;
+    }
+    else {    /* argc == 2 */
+	int digits;
+	DCELL *arg2;
+
+	switch (argt[1]) {
+	case CELL_TYPE:
+	    {
+		CELL *arg1 = args[1];
+		CELL *res = args[0];
+
+		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;
 	}
-    default:
-	return E_INV_TYPE;
     }
 }
 
@@ -100,11 +191,13 @@ int c_round(int argc, int *argt)
 {
     if (argc < 1)
 	return E_ARG_LO;
-    if (argc > 1)
+    if (argc > 2)
 	return E_ARG_HI;
 
-    argt[0] = CELL_TYPE;
-    /*      argt[1] = argt[1];      */
+    argt[0] = argt[1];
+    
+    if (argc == 2)
+	argt[2] = DCELL_TYPE;
 
     return 0;
 }