main.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /****************************************************************************
  2. *
  3. * MODULE: r.contour
  4. *
  5. * AUTHOR(S): Terry Baker - CERL
  6. * Andrea Aime <aaime liberto it>
  7. *
  8. * PURPOSE: Produces a vector map of specified contours from a
  9. * raster map layer.
  10. *
  11. * COPYRIGHT: (C) 2001-2008 by the GRASS Development Team
  12. *
  13. * This program is free software under the GNU General Public
  14. * License (>=v2). Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. ***************************************************************************/
  18. /*
  19. * Fixes 3/2001: Andrea Aime <aaime libero.it>
  20. *
  21. * o category support bug has been fixed: r.contour now produces also dig_cats
  22. * file, so d.what.vect no more complain about missing category support.
  23. * Since a contour level could be floatig point I've inserted in the label
  24. * the true value, whilst category number remains its integer equivalent;
  25. * o a little trick (derived from GMT contour program) avoids any kind of
  26. * backtrack, so running v.spag -i is no more needed (I hope): data matrix
  27. * is parsed, and if a cell whose data matches exactly a contour value its
  28. * value is added a small quantity (the smaller one that makes cell[i] +
  29. * small != cell[i], I've taken into consideration double encoding)
  30. * o one can specify a minimum number of point for a contour line to be put
  31. * into outout, so that small spurs, single points and so on won't be
  32. * present and the output will be more clear (that's optional anyway);
  33. * o in my opinion there were minor memory handling problems in r.contour,
  34. * I've corrected them (Head.map_name was not guaranteed to be properly
  35. * terminated, Points structures in contour function were not
  36. * deallocated).
  37. */
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <math.h>
  42. #include <ctype.h>
  43. #include <float.h>
  44. #include <grass/gis.h>
  45. #include <grass/raster.h>
  46. #include <grass/dbmi.h>
  47. #include <grass/vector.h>
  48. #include <grass/glocale.h>
  49. #include "local_proto.h"
  50. int main(int argc, char *argv[])
  51. {
  52. struct GModule *module;
  53. struct Option *map;
  54. struct Option *levels;
  55. struct Option *vect;
  56. struct Option *min;
  57. struct Option *max;
  58. struct Option *step;
  59. struct Option *cut;
  60. struct Flag *notable;
  61. int i;
  62. struct Cell_head Wind;
  63. char *name;
  64. struct Map_info Map;
  65. DCELL **z_array;
  66. struct FPRange range;
  67. int fd;
  68. double *lev;
  69. int nlevels;
  70. int n_cut;
  71. /* Attributes */
  72. struct field_info *Fi;
  73. dbDriver *Driver;
  74. char buf[2000];
  75. dbString sql;
  76. G_gisinit(argv[0]);
  77. module = G_define_module();
  78. G_add_keyword(_("raster"));
  79. G_add_keyword(_("surface"));
  80. G_add_keyword(_("contours"));
  81. G_add_keyword(_("vector"));
  82. module->description = _("Produces a vector map of specified "
  83. "contours from a raster map.");
  84. map = G_define_standard_option(G_OPT_R_INPUT);
  85. vect = G_define_standard_option(G_OPT_V_OUTPUT);
  86. step = G_define_option();
  87. step->key = "step";
  88. step->type = TYPE_DOUBLE;
  89. step->required = NO;
  90. step->description = _("Increment between contour levels");
  91. step->guisection = _("Contour levels");
  92. levels = G_define_option();
  93. levels->key = "levels";
  94. levels->type = TYPE_DOUBLE;
  95. levels->required = NO;
  96. levels->multiple = YES;
  97. levels->description = _("List of contour levels");
  98. levels->guisection = _("Contour levels");
  99. min = G_define_option();
  100. min->key = "minlevel";
  101. min->type = TYPE_DOUBLE;
  102. min->required = NO;
  103. min->description = _("Minimum contour level");
  104. min->guisection = _("Contour levels");
  105. max = G_define_option();
  106. max->key = "maxlevel";
  107. max->type = TYPE_DOUBLE;
  108. max->required = NO;
  109. max->description = _("Maximum contour level");
  110. max->guisection = _("Contour levels");
  111. cut = G_define_option();
  112. cut->key = "cut";
  113. cut->type = TYPE_INTEGER;
  114. cut->required = NO;
  115. cut->answer = "0";
  116. cut->description =
  117. _("Minimum number of points for a contour line (0 -> no limit)");
  118. notable = G_define_standard_flag(G_FLG_V_TABLE);
  119. if (G_parser(argc, argv))
  120. exit(EXIT_FAILURE);
  121. if (!levels->answers && !step->answer) {
  122. G_fatal_error(_("Neither <%s> nor <%s> option must be specified"),
  123. levels->key, step->key);
  124. }
  125. name = map->answer;
  126. fd = Rast_open_old(name, "");
  127. if (Rast_read_fp_range(name, "", &range) < 0)
  128. G_fatal_error(_("Unable to read fp range of raster map <%s>"),
  129. name);
  130. /* get window info */
  131. G_get_window(&Wind);
  132. if (Vect_open_new(&Map, vect->answer, 1) < 0)
  133. G_fatal_error(_("Unable to create vector map <%s>"), vect->answer);
  134. Vect_hist_command(&Map);
  135. if (!notable->answer) {
  136. db_init_string(&sql);
  137. /* Open database, create table */
  138. Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE);
  139. Vect_map_add_dblink(&Map, Fi->number, Fi->name, Fi->table, Fi->key,
  140. Fi->database, Fi->driver);
  141. Driver =
  142. db_start_driver_open_database(Fi->driver,
  143. Vect_subst_var(Fi->database, &Map));
  144. if (Driver == NULL)
  145. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  146. Fi->database, Fi->driver);
  147. sprintf(buf, "create table %s ( cat integer, level double precision )",
  148. Fi->table);
  149. db_set_string(&sql, buf);
  150. G_debug(1, "SQL: %s", db_get_string(&sql));
  151. if (db_execute_immediate(Driver, &sql) != DB_OK) {
  152. G_fatal_error(_("Unable to create table: '%s'"),
  153. db_get_string(&sql));
  154. }
  155. if (db_create_index2(Driver, Fi->table, Fi->key) != DB_OK)
  156. G_warning(_("Unable to create index for table <%s>, key <%s>"),
  157. Fi->table, Fi->key);
  158. if (db_grant_on_table
  159. (Driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK)
  160. G_fatal_error(_("Unable to grant privileges on table <%s>"),
  161. Fi->table);
  162. }
  163. z_array = get_z_array(fd, Wind.rows, Wind.cols);
  164. lev = getlevels(levels, max, min, step, &range, &nlevels);
  165. displaceMatrix(z_array, Wind.rows, Wind.cols, lev, nlevels);
  166. n_cut = atoi(cut->answer);
  167. contour(lev, nlevels, Map, z_array, Wind, n_cut);
  168. G_message(_("Writing attributes..."));
  169. /* Write levels */
  170. if (!notable->answer) {
  171. db_begin_transaction(Driver);
  172. for (i = 0; i < nlevels; i++) {
  173. sprintf(buf, "insert into %s values ( %d, %e )", Fi->table, i + 1,
  174. lev[i]);
  175. db_set_string(&sql, buf);
  176. G_debug(3, "SQL: %s", db_get_string(&sql));
  177. if (db_execute_immediate(Driver, &sql) != DB_OK) {
  178. G_fatal_error(_("Unable to insert new record: '%s'"), db_get_string(&sql));
  179. }
  180. }
  181. db_commit_transaction(Driver);
  182. db_close_database_shutdown_driver(Driver);
  183. }
  184. Vect_build(&Map);
  185. Vect_close(&Map);
  186. exit(EXIT_SUCCESS);
  187. }
  188. /*********************************************************************/
  189. DCELL **get_z_array(int fd, int nrow, int ncol)
  190. {
  191. DCELL **z_array;
  192. int i;
  193. z_array = (DCELL **) G_malloc(nrow * sizeof(DCELL *));
  194. G_message(_("Reading data..."));
  195. for (i = 0; i < nrow; i++) {
  196. z_array[i] = (DCELL *) G_malloc(ncol * sizeof(DCELL));
  197. Rast_get_d_row(fd, z_array[i], i);
  198. G_percent(i + 1, nrow, 2);
  199. }
  200. return z_array;
  201. }
  202. /********************************************************************/
  203. double *getlevels(struct Option *levels,
  204. struct Option *max, struct Option *min,
  205. struct Option *step, struct FPRange *range, int *num)
  206. {
  207. double dmax, dmin, dstep;
  208. int nlevels, i, k, n;
  209. double j;
  210. DCELL zmin, zmax; /* min and max data values */
  211. double *lev;
  212. double tmp;
  213. Rast_get_fp_range_min_max(range, &zmin, &zmax);
  214. if (!Rast_is_d_null_value(&zmin) && !Rast_is_d_null_value(&zmax))
  215. G_verbose_message(_("Range of data: min=%f, max=%f"), zmin, zmax);
  216. else
  217. G_verbose_message(_("Range of data: empty"));
  218. nlevels = 0;
  219. if (levels->answers) {
  220. for (n = 0; levels->answers[n] != NULL; n++)
  221. nlevels++;
  222. lev = (double *)G_malloc((nlevels) * sizeof(double));
  223. n = nlevels;
  224. k = 0;
  225. for (i = 0; i < n; i++) {
  226. j = atof(levels->answers[i]);
  227. if ((j < zmin) || (j > zmax)) {
  228. nlevels--;
  229. }
  230. else {
  231. lev[k] = j;
  232. k++;
  233. }
  234. }
  235. }
  236. else { /* step */
  237. dstep = atof(step->answer);
  238. /* fix if step < 1, Roger Bivand 1/2001: */
  239. dmax = (max->answer) ? atof(max->answer) :
  240. dstep == 0 ? (G_fatal_error(_("This step value is not allowed")), 0) :
  241. zmax - fmod(zmax, dstep);
  242. dmin = (min->answer) ? atof(min->answer) :
  243. dstep == 0 ? (G_fatal_error(_("This step value is not allowed")), 0) :
  244. fmod(zmin, dstep) ? zmin - fmod(zmin, dstep) + dstep :
  245. zmin;
  246. while (dmin < zmin) {
  247. dmin += dstep;
  248. }
  249. while (dmin > zmax) {
  250. dmin -= dstep;
  251. }
  252. while (dmax > zmax) {
  253. dmax -= dstep;
  254. }
  255. while (dmax < zmin) {
  256. dmax += dstep;
  257. }
  258. if (dmin > dmax) {
  259. tmp = dmin;
  260. dmin = dmax;
  261. dmax = tmp;
  262. }
  263. dmin = dmin < zmin ? zmin : dmin;
  264. dmax = dmax > zmax ? zmax : dmax;
  265. G_verbose_message(_("Range of levels: min = %f, max = %f"), dmin, dmax);
  266. nlevels = (dmax - dmin) / dstep + 2;
  267. lev = (double *)G_malloc(nlevels * sizeof(double));
  268. for (nlevels = 0; dmin < dmax; dmin += dstep) {
  269. lev[nlevels] = dmin;
  270. nlevels++;
  271. }
  272. lev[nlevels] = dmax;
  273. nlevels++;
  274. }
  275. *num = nlevels;
  276. return lev;
  277. }
  278. /********************************************************************/
  279. /* parse the matrix and offset values that exactly match a */
  280. /* contour level. Contours values are added DBL_EPSILON*val, which */
  281. /* is defined in K&R as the minimum double x such as 1.0+x != 1.0 */
  282. /********************************************************************/
  283. void displaceMatrix(DCELL ** z, int nrow, int ncol, double *lev, int nlevels)
  284. {
  285. int i, j, k;
  286. double *currRow;
  287. double currVal;
  288. G_message(_("Displacing data..."));
  289. for (i = 0; i < nrow; i++) {
  290. currRow = z[i];
  291. for (j = 0; j < ncol; j++) {
  292. currVal = currRow[j];
  293. for (k = 0; k < nlevels; k++)
  294. if (currVal == lev[k]) {
  295. currRow[j] = currVal + currVal * DBL_EPSILON;
  296. break;
  297. }
  298. }
  299. G_percent(i + 1, nrow, 2);
  300. }
  301. }