main.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /****************************************************************************
  2. *
  3. * MODULE: r.to.vect
  4. *
  5. * AUTHOR(S): Bill Brown, Mike Baba, Jean Ezell and Andrew Heekin,
  6. * David Satnik, Andrea Aime, Radim Blazek
  7. *
  8. * PURPOSE: Converts a raster map into a vector map layer
  9. *
  10. * COPYRIGHT: (C) 2007, 2011, 2017 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <grass/gis.h>
  21. #include <grass/raster.h>
  22. #include <grass/dbmi.h>
  23. #include <grass/vector.h>
  24. #include <grass/glocale.h>
  25. #include "global.h"
  26. /*
  27. * Attributes for lines are ignored. For points and area by default unique new
  28. * category is assigned to each and raster value is written to 'value' column.
  29. * Labels are written to 'label' column if exists. If value flag (-v) is used
  30. * and type is CELL, raster values are used as categories.
  31. *
  32. * 2007/2: attributes for lines supported
  33. */
  34. int data_type;
  35. int data_size;
  36. struct Map_info Map;
  37. int input_fd; /* input raster map descriptor */
  38. struct line_cats *Cats;
  39. struct Cell_head cell_head;
  40. int direction;
  41. int first_read, last_read;
  42. int input_fd;
  43. int row_length, row_count, n_rows;
  44. int total_areas;
  45. int n_alloced_ptrs;
  46. int smooth_flag; /* this is 0 for no smoothing, 1 for smoothing of lines */
  47. int value_flag; /* use raster values as categories */
  48. struct Categories RastCats;
  49. int has_cats; /* Category labels available */
  50. struct field_info *Fi;
  51. dbDriver *driver;
  52. dbString sql, label;
  53. static int cmp_int(const void *a, const void *b)
  54. {
  55. return (*(int *)a - *(int *)b);
  56. }
  57. int main(int argc, char *argv[])
  58. {
  59. struct GModule *module;
  60. struct Option *in_opt, *out_opt, *feature_opt, *column_name;
  61. struct Flag *smooth_flg, *value_flg, *z_flg, *no_topol, *notab_flg;
  62. int feature, notab_flag;
  63. G_gisinit(argv[0]);
  64. module = G_define_module();
  65. G_add_keyword(_("raster"));
  66. G_add_keyword(_("conversion"));
  67. G_add_keyword(_("geometry"));
  68. G_add_keyword(_("vectorization"));
  69. module->description = _("Converts a raster map into a vector map.");
  70. in_opt = G_define_standard_option(G_OPT_R_INPUT);
  71. out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  72. feature_opt = G_define_standard_option(G_OPT_V_TYPE);
  73. feature_opt->description = _("Output feature type");
  74. feature_opt->required = YES;
  75. feature_opt->multiple = NO;
  76. feature_opt->options = "point,line,area";
  77. feature_opt->answer = NULL;
  78. column_name = G_define_standard_option(G_OPT_DB_COLUMN);
  79. column_name->label = _("Name of attribute column to store value");
  80. column_name->description = _("Name must be SQL compliant");
  81. column_name->answer = "value";
  82. smooth_flg = G_define_flag();
  83. smooth_flg->key = 's';
  84. smooth_flg->description = _("Smooth corners of area features");
  85. value_flg = G_define_flag();
  86. value_flg->key = 'v';
  87. value_flg->description =
  88. _("Use raster values as categories instead of unique sequence (CELL only)");
  89. value_flg->guisection = _("Attributes");
  90. z_flg = G_define_flag();
  91. z_flg->key = 'z';
  92. z_flg->label = _("Write raster values as z coordinate");
  93. z_flg->description = _("Table is not created. "
  94. "Currently supported only for points.");
  95. z_flg->guisection = _("Attributes");
  96. no_topol = G_define_flag();
  97. no_topol->key = 'b';
  98. no_topol->label = _("Do not build vector topology");
  99. no_topol->description = _("Recommended for massive point conversion");
  100. notab_flg = G_define_standard_flag(G_FLG_V_TABLE);
  101. if (G_parser(argc, argv))
  102. exit(EXIT_FAILURE);
  103. feature = Vect_option_to_types(feature_opt);
  104. smooth_flag = (smooth_flg->answer) ? SMOOTH : NO_SMOOTH;
  105. value_flag = value_flg->answer;
  106. notab_flag = notab_flg->answer;
  107. if (z_flg->answer && (feature != GV_POINT))
  108. G_fatal_error(_("z flag is supported only for points"));
  109. /* Open files */
  110. input_fd = Rast_open_old(in_opt->answer, "");
  111. data_type = Rast_get_map_type(input_fd);
  112. data_size = Rast_cell_size(data_type);
  113. G_get_window(&cell_head);
  114. if (value_flag && data_type != CELL_TYPE) {
  115. if (!notab_flag)
  116. G_warning(_("Raster is not CELL, '-v' flag ignored, raster values will be written to the table."));
  117. else if (z_flg->answer)
  118. G_warning(_("Raster is not CELL, '-v' flag ignored, raster values will be z coordinate."));
  119. else
  120. G_warning(_("Raster is not CELL, '-v' flag ignored, raster values will be lost."));
  121. value_flag = 0;
  122. }
  123. if (!value_flag && notab_flag) {
  124. G_warning(_("Categories will be unique sequence, raster values will be lost."));
  125. }
  126. set_error_handler(&Map, &driver);
  127. if (Vect_open_new(&Map, out_opt->answer, z_flg->answer) < 0)
  128. G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
  129. Vect_hist_command(&Map);
  130. Cats = Vect_new_cats_struct();
  131. /* Open category labels */
  132. if (data_type == CELL_TYPE) {
  133. if (0 == Rast_read_cats(in_opt->answer, "", &RastCats))
  134. has_cats = 1;
  135. }
  136. else
  137. has_cats = 0;
  138. db_init_string(&sql);
  139. db_init_string(&label);
  140. /* Create table */
  141. if ((feature & (GV_AREA | GV_POINT | GV_LINE)) &&
  142. (!value_flag || (value_flag && has_cats)) && !(z_flg->answer)
  143. && !notab_flag) {
  144. char buf[1000];
  145. Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE);
  146. Vect_map_add_dblink(&Map, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
  147. Fi->driver);
  148. driver =
  149. db_start_driver_open_database(Fi->driver,
  150. Vect_subst_var(Fi->database, &Map));
  151. if (driver == NULL)
  152. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  153. Fi->database, Fi->driver);
  154. /* Create new table */
  155. db_zero_string(&sql);
  156. sprintf(buf, "create table %s ( cat integer", Fi->table);
  157. db_append_string(&sql, buf);
  158. if (!value_flag) { /* add value to the table */
  159. if (data_type == CELL_TYPE) {
  160. db_append_string(&sql, ", ");
  161. db_append_string(&sql, column_name->answer);
  162. db_append_string(&sql, " integer");
  163. } else {
  164. db_append_string(&sql, ",");
  165. db_append_string(&sql, column_name->answer);
  166. db_append_string(&sql, " double precision");
  167. }
  168. }
  169. if (has_cats) {
  170. int i, len;
  171. int clen = 0;
  172. /* Get maximum column length */
  173. for (i = 0; i < RastCats.ncats; i++) {
  174. len = strlen(RastCats.labels[i]);
  175. if (len > clen)
  176. clen = len;
  177. }
  178. clen += 10;
  179. sprintf(buf, ", label varchar(%d)", clen);
  180. db_append_string(&sql, buf);
  181. }
  182. db_append_string(&sql, ")");
  183. G_debug(3, "%s", db_get_string(&sql));
  184. if (db_execute_immediate(driver, &sql) != DB_OK)
  185. G_fatal_error(_("Unable to create table: %s"),
  186. db_get_string(&sql));
  187. if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
  188. G_warning(_("Unable to create index"));
  189. if (db_grant_on_table
  190. (driver, Fi->table, DB_PRIV_SELECT,
  191. DB_GROUP | DB_PUBLIC) != DB_OK)
  192. G_fatal_error(_("Unable to grant privileges on table <%s>"),
  193. Fi->table);
  194. db_begin_transaction(driver);
  195. }
  196. else {
  197. driver = NULL;
  198. }
  199. /* init variables for lines and areas */
  200. first_read = 1;
  201. last_read = 0;
  202. direction = FORWARD;
  203. row_length = cell_head.cols;
  204. n_rows = cell_head.rows;
  205. row_count = 0;
  206. if (feature == GV_LINE) {
  207. alloc_lines_bufs(row_length + 2);
  208. extract_lines();
  209. }
  210. else if (feature == GV_AREA) {
  211. alloc_areas_bufs(row_length + 2);
  212. extract_areas();
  213. }
  214. else { /* GV_POINT */
  215. extract_points(z_flg->answer);
  216. }
  217. Rast_close(input_fd);
  218. /* insert cats and optionally labels if raster cats were used */
  219. if (driver && value_flag) {
  220. char buf[1000];
  221. int c, i, j, cat;
  222. struct ilist *clist;
  223. int type;
  224. clist = G_new_ilist();
  225. /* create category list */
  226. Vect_rewind(&Map);
  227. while (1) {
  228. /* register line */
  229. type = Vect_read_next_line(&Map, NULL, Cats);
  230. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  231. if (type == -1) {
  232. G_warning(_("Unable to read vector map"));
  233. break;
  234. }
  235. else if (type == -2) {
  236. break;
  237. }
  238. for (i = 0; i < Cats->n_cats; i++)
  239. G_ilist_add(clist, Cats->cat[i]);
  240. }
  241. if (clist->n_values > 0) {
  242. qsort(clist->value, clist->n_values, sizeof(int), cmp_int);
  243. j = 1;
  244. for (i = 1; i < clist->n_values; i++) {
  245. if (clist->value[i] != clist->value[j - 1]) {
  246. clist->value[j] = clist->value[i];
  247. j++;
  248. }
  249. }
  250. clist->n_values = j;
  251. G_important_message(_("Updating attributes..."));
  252. for (c = 0; c < clist->n_values; c++) {
  253. G_percent(c, clist->n_values, 4);
  254. cat = clist->value[c];
  255. /* find label, slow -> TODO faster */
  256. db_set_string(&label, "");
  257. for (i = 0; i < RastCats.ncats; i++) {
  258. if (cat == (int)RastCats.q.table[i].dLow) { /* cats are in dLow/High not in cLow/High !!! */
  259. db_set_string(&label, RastCats.labels[i]);
  260. db_double_quote_string(&label);
  261. break;
  262. }
  263. }
  264. G_debug(3, "cat = %d label = %s", cat, db_get_string(&label));
  265. sprintf(buf, "insert into %s values ( %d, '%s')", Fi->table,
  266. cat, db_get_string(&label));
  267. db_set_string(&sql, buf);
  268. G_debug(3, "%s", db_get_string(&sql));
  269. if (db_execute_immediate(driver, &sql) != DB_OK)
  270. G_fatal_error(_("Unable to insert into table: %s"),
  271. db_get_string(&sql));
  272. }
  273. G_percent(1, 1, 1);
  274. }
  275. G_free_ilist(clist);
  276. }
  277. if (has_cats)
  278. Rast_free_cats(&RastCats);
  279. if (driver != NULL) {
  280. db_commit_transaction(driver);
  281. db_close_database_shutdown_driver(driver);
  282. }
  283. if (!no_topol->answer)
  284. Vect_build(&Map);
  285. Vect_close(&Map);
  286. G_done_msg(" ");
  287. exit(EXIT_SUCCESS);
  288. }