1 
2 #include <limits.h>
3 #include <math.h>
4 
5 #include <grass/gis.h>
6 #include <grass/raster.h>
7 #include <grass/calc.h>
8 
9 /**********************************************************************
10 round(x, step, start)
11 
12   rounds x to nearest value in the sequence
13     y[i] = i * step + start
14 
15 **********************************************************************/
16 
17 /* i_round(x) rounds x to nearest value, handles negative correctly */
18 
i_round(double x,double step,double start)19 static double i_round(double x, double step, double start)
20 {
21     x -= start;
22     x /= step;
23     x = floor(x + 0.5);
24     x *= step;
25     x += start;
26     return x;
27 }
28 
29 /**********************************************************************/
30 
f_round(int argc,const int * argt,void ** args)31 int f_round(int argc, const int *argt, void **args)
32 {
33     const DCELL *arg1 = args[1];
34     int i;
35 
36     if (argc < 1)
37 	return E_ARG_LO;
38     if (argc > 3)
39 	return E_ARG_HI;
40 
41     if (argc == 1 && argt[0] != CELL_TYPE)
42 	return E_RES_TYPE;
43     if (argt[1] != DCELL_TYPE)
44 	return E_ARG_TYPE;
45     if (argc > 1 && argt[2] != DCELL_TYPE)
46 	return E_ARG_TYPE;
47     if (argc > 2 && argt[3] != DCELL_TYPE)
48 	return E_ARG_TYPE;
49 
50     if (argc == 1) {
51 	CELL *res = args[0];
52 
53 	for (i = 0; i < columns; i++) {
54 	    if (IS_NULL_D(&arg1[i]))
55 		SET_NULL_C(&res[i]);
56 	    else {
57 		DCELL x = i_round(arg1[i], 1.0, 0.0);
58 		if (x > 2147483647.0 || x < -2147483647.0)
59 		    SET_NULL_C(&res[i]);
60 		else
61 		    res[i] = (CELL) x;
62 	    }
63 	}
64 	return 0;
65     }
66     else if (argc == 2) {
67 	const DCELL *arg2 = args[2];
68 
69 	switch (argt[0]) {
70         case CELL_TYPE:
71             {
72                 CELL *res = args[0];
73 
74                 for (i = 0; i < columns; i++) {
75                     if (IS_NULL_D(&arg1[i]))
76                         SET_NULL_C(&res[i]);
77                     else if (IS_NULL_D(&arg2[i]))
78                         SET_NULL_C(&res[i]);
79                     else {
80                         DCELL x = i_round(arg1[i], arg2[i], 0.0);
81                         if (x > 2147483647.0 || x < -2147483647.0)
82                             SET_NULL_C(&res[i]);
83                         else
84                             res[i] = (CELL) x;
85                     }
86                 }
87                 return 0;
88             }
89         case FCELL_TYPE:
90             {
91                 FCELL *res = args[0];
92 
93                 for (i = 0; i < columns; i++)
94                     if (IS_NULL_D(&arg1[i]))
95                         SET_NULL_F(&res[i]);
96                     else if (IS_NULL_D(&arg2[i]))
97                         SET_NULL_F(&res[i]);
98                     else
99                         res[i] = (FCELL) i_round(arg1[i], arg2[i], 0.0);
100                 return 0;
101             }
102         case DCELL_TYPE:
103             {
104                 DCELL *res = args[0];
105 
106                 for (i = 0; i < columns; i++)
107                     if (IS_NULL_D(&arg1[i]))
108                         SET_NULL_D(&res[i]);
109                     else if (IS_NULL_D(&arg2[i]))
110                         SET_NULL_D(&res[i]);
111                     else
112                         res[i] = (DCELL) i_round(arg1[i], arg2[i], 0.0);
113                 return 0;
114             }
115         default:
116             return E_INV_TYPE;
117         }
118     }
119     else if (argc == 3) {
120 	const DCELL *arg2 = args[2];
121 	const DCELL *arg3 = args[3];
122 
123 	switch (argt[0]) {
124         case CELL_TYPE:
125             {
126                 CELL *res = args[0];
127 
128                 for (i = 0; i < columns; i++) {
129                     if (IS_NULL_D(&arg1[i]))
130                         SET_NULL_C(&res[i]);
131                     else if (IS_NULL_D(&arg2[i]))
132                         SET_NULL_C(&res[i]);
133                     else if (IS_NULL_D(&arg3[i]))
134                         SET_NULL_C(&res[i]);
135                     else {
136                         DCELL x = i_round(arg1[i], arg2[i], arg3[i]);
137                         if (x > 2147483647.0 || x < -2147483647.0)
138                             SET_NULL_C(&res[i]);
139                         else
140                             res[i] = (CELL) x;
141                     }
142                 }
143                 return 0;
144             }
145         case FCELL_TYPE:
146             {
147                 FCELL *res = args[0];
148 
149                 for (i = 0; i < columns; i++)
150                     if (IS_NULL_D(&arg1[i]))
151                         SET_NULL_F(&res[i]);
152                     else if (IS_NULL_D(&arg2[i]))
153                         SET_NULL_F(&res[i]);
154                     else if (IS_NULL_D(&arg3[i]))
155                         SET_NULL_F(&res[i]);
156                     else
157                         res[i] = (FCELL) i_round(arg1[i], arg2[i], arg3[i]);
158                 return 0;
159             }
160         case DCELL_TYPE:
161             {
162                 DCELL *res = args[0];
163 
164                 for (i = 0; i < columns; i++)
165                     if (IS_NULL_D(&arg1[i]))
166                         SET_NULL_D(&res[i]);
167                     else if (IS_NULL_D(&arg2[i]))
168                         SET_NULL_D(&res[i]);
169                     else if (IS_NULL_D(&arg3[i]))
170                         SET_NULL_D(&res[i]);
171                     else
172                         res[i] = (DCELL) i_round(arg1[i], arg2[i], arg3[i]);
173                 return 0;
174             }
175         default:
176             return E_INV_TYPE;
177         }
178     }
179     else
180 	return E_WTF;
181 }
182 
c_round(int argc,int * argt)183 int c_round(int argc, int *argt)
184 {
185     if (argc < 1)
186 	return E_ARG_LO;
187     if (argc > 3)
188 	return E_ARG_HI;
189 
190     argt[0] = CELL_TYPE;
191     if (argc > 1 && argt[0] < argt[2])
192 	argt[0] = argt[2];
193     if (argc > 2 && argt[0] < argt[3])
194 	argt[0] = argt[3];
195 
196     argt[1] = DCELL_TYPE;
197     if (argc > 1)
198 	argt[2] = DCELL_TYPE;
199     if (argc > 2)
200 	argt[3] = DCELL_TYPE;
201 
202     return 0;
203 }
204