main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /****************************************************************************
  2. *
  3. * MODULE: v.voronoi
  4. * AUTHOR(S): James McCauley <mccauley ecn.purdue.edu>, s.voronoi, based
  5. * on netlib code (see README) (original contributor)
  6. * Andrea Aime <aaime libero.it>
  7. * Radim Blazek <radim.blazek gmail.com> (GRASS 5.1 v.voronoi)
  8. * Glynn Clements <glynn gclements.plus.com>,
  9. * Markus Neteler <neteler itc.it>,
  10. * Markus Metz
  11. * PURPOSE: produce a Voronoi diagram using vector points
  12. * COPYRIGHT: (C) 1993-2006, 2001, 2013 by the GRASS Development Team
  13. *
  14. * This program is free software under the GNU General Public
  15. * License (>=v2). Read the file COPYING that comes with GRASS
  16. * for details.
  17. *
  18. *****************************************************************************/
  19. /*-s.voronoi
  20. **
  21. ** Author: James Darrell McCauley (mccauley@ecn.purdue.edu)
  22. ** USDA Fellow
  23. ** Department of Agricultural Engineering
  24. ** Purdue University
  25. ** West Lafayette, Indiana 47907-1146 USA
  26. **
  27. ** Permission to use, copy, modify, and distribute this software and its
  28. ** documentation for any purpose and without fee is hereby granted. This
  29. ** software is provided "as is" without express or implied warranty.
  30. **
  31. ** Modification History:
  32. ** 06 Feb 93 - James Darrell McCauley <mccauley@ecn.purdue.edu> pieced
  33. ** this together from stuff he found on netlib (see the manpage).
  34. **/
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <stdlib.h>
  38. #include <unistd.h>
  39. #include <math.h>
  40. #include <grass/gis.h>
  41. #include <grass/dbmi.h>
  42. #include <grass/vector.h>
  43. #include <grass/glocale.h>
  44. #include "sw_defs.h"
  45. #include "defs.h"
  46. typedef struct
  47. {
  48. double x, y;
  49. } COOR;
  50. int cmp(void *a, void *b)
  51. {
  52. COOR *ca = (COOR *) a;
  53. COOR *cb = (COOR *) b;
  54. double ma, mb;
  55. /* calculate measure */
  56. ma = mb = 0.0;
  57. if (fabs(ca->y - Box.S) < GRASS_EPSILON) { /* bottom */
  58. ma = ca->x - Box.W;
  59. }
  60. else if (fabs(ca->x - Box.E) < GRASS_EPSILON) { /* right */
  61. ma = (Box.E - Box.W) + (ca->y - Box.S);
  62. }
  63. else if (fabs(ca->y - Box.N) < GRASS_EPSILON) { /* top */
  64. ma = (Box.E - Box.W) + (Box.N - Box.S) + (Box.E - ca->x);
  65. }
  66. else { /* left */
  67. ma = 2 * (Box.E - Box.W) + (Box.N - Box.S) + (Box.N - ca->y);
  68. }
  69. if (fabs(cb->y - Box.S) < GRASS_EPSILON) { /* bottom */
  70. mb = cb->x - Box.W;
  71. }
  72. else if (fabs(cb->x - Box.E) < GRASS_EPSILON) { /* right */
  73. mb = (Box.E - Box.W) + (cb->y - Box.S);
  74. }
  75. else if (fabs(cb->y - Box.N) < GRASS_EPSILON) { /* top */
  76. mb = (Box.E - Box.W) + (Box.N - Box.S) + (Box.E - cb->x);
  77. }
  78. else { /* left */
  79. mb = 2 * (Box.E - Box.W) + (Box.N - Box.S) + (Box.N - cb->y);
  80. }
  81. if (ma < mb)
  82. return -1;
  83. if (ma > mb)
  84. return 1;
  85. return 0;
  86. }
  87. int main(int argc, char **argv)
  88. {
  89. int i;
  90. int **cats, *ncats, nfields, *fields;
  91. struct {
  92. struct Option *in, *out, *field, *smooth, *thin;
  93. } opt;
  94. struct {
  95. struct Flag *line, *table, *area, *skeleton;
  96. } flag;
  97. struct GModule *module;
  98. struct line_pnts *Points;
  99. struct line_cats *Cats;
  100. int node, nnodes;
  101. COOR *coor;
  102. int verbose;
  103. int ncoor, acoor;
  104. int line, nlines, type, ctype;
  105. double thresh;
  106. G_gisinit(argv[0]);
  107. module = G_define_module();
  108. G_add_keyword(_("vector"));
  109. G_add_keyword(_("geometry"));
  110. G_add_keyword(_("triangulation"));
  111. G_add_keyword(_("skeleton"));
  112. module->description = _("Creates a Voronoi diagram in current region from "
  113. "an input vector map containing points or centroids.");
  114. opt.in = G_define_standard_option(G_OPT_V_INPUT);
  115. opt.in->label = _("Name of input vector point map");
  116. opt.field = G_define_standard_option(G_OPT_V_FIELD_ALL);
  117. opt.out = G_define_standard_option(G_OPT_V_OUTPUT);
  118. opt.smooth = G_define_option();
  119. opt.smooth->type = TYPE_DOUBLE;
  120. opt.smooth->key = "smoothness";
  121. opt.smooth->answer = "0.25";
  122. opt.smooth->label = _("Factor for output smoothness");
  123. opt.smooth->description = _("Applies to input areas only. "
  124. "Smaller values produce smoother output but can cause numerical instability.");
  125. opt.thin = G_define_option();
  126. opt.thin->type = TYPE_DOUBLE;
  127. opt.thin->key = "thin";
  128. opt.thin->answer = "-1";
  129. opt.thin->label = _("Maximum dangle length of skeletons");
  130. opt.thin->description = _("Applies only to skeleton extraction. "
  131. "Default = -1 will extract the center line.");
  132. flag.area = G_define_flag();
  133. flag.area->key = 'a';
  134. flag.area->description =
  135. _("Create Voronoi diagram for input areas");
  136. flag.skeleton = G_define_flag();
  137. flag.skeleton->key = 's';
  138. flag.skeleton->description =
  139. _("Extract skeletons for input areas");
  140. flag.line = G_define_flag();
  141. flag.line->key = 'l';
  142. flag.line->description =
  143. _("Output tessellation as a graph (lines), not areas");
  144. flag.table = G_define_standard_flag(G_FLG_V_TABLE);
  145. if (G_parser(argc, argv))
  146. exit(EXIT_FAILURE);
  147. if (flag.line->answer)
  148. Type = GV_LINE;
  149. else
  150. Type = GV_BOUNDARY;
  151. in_area = flag.area->answer;
  152. segf = atof(opt.smooth->answer);
  153. if (segf < GRASS_EPSILON) {
  154. segf = 0.25;
  155. G_warning(_("Option '%s' is too small, set to %g"), opt.smooth->key, segf);
  156. }
  157. thresh = atof(opt.thin->answer);
  158. skeleton = flag.skeleton->answer;
  159. if (skeleton)
  160. Type = GV_LINE;
  161. Points = Vect_new_line_struct();
  162. Cats = Vect_new_cats_struct();
  163. /* open files */
  164. Vect_set_open_level(2);
  165. if (Vect_open_old2(&In, opt.in->answer, "", opt.field->answer) < 0)
  166. G_fatal_error(_("Unable to open vector map <%s>"), opt.in->answer);
  167. Field = Vect_get_field_number(&In, opt.field->answer);
  168. /* initialize working region */
  169. G_get_window(&Window);
  170. Vect_region_box(&Window, &Box);
  171. Box.T = 0.5;
  172. Box.B = -0.5;
  173. freeinit(&sfl, sizeof(struct Site));
  174. G_message(_("Reading features..."));
  175. if (in_area || skeleton)
  176. readbounds();
  177. else
  178. readsites();
  179. if (Vect_open_new(&Out, opt.out->answer, 0) < 0)
  180. G_fatal_error(_("Unable to create vector map <%s>"), opt.out->answer);
  181. Vect_hist_copy(&In, &Out);
  182. Vect_hist_command(&Out);
  183. siteidx = 0;
  184. geominit();
  185. plot = 0;
  186. debug = 0;
  187. G_message(n_("Voronoi triangulation for %d point...",
  188. "Voronoi triangulation for %d points...",
  189. nsites), nsites);
  190. voronoi(nextone);
  191. G_message(_("Writing edges..."));
  192. vo_write();
  193. verbose = G_verbose();
  194. G_set_verbose(0);
  195. Vect_build_partial(&Out, GV_BUILD_BASE);
  196. G_set_verbose(verbose);
  197. if (skeleton) {
  198. G_message(_("Thin skeletons ..."));
  199. thin_skeleton(thresh);
  200. tie_up();
  201. }
  202. else {
  203. /* Close free ends by current region */
  204. ncoor = 0;
  205. acoor = 100;
  206. coor = (COOR *) G_malloc(sizeof(COOR) * acoor);
  207. nnodes = Vect_get_num_nodes(&Out);
  208. for (node = 1; node <= nnodes; node++) {
  209. double x, y;
  210. if (Vect_get_node_n_lines(&Out, node) < 2) { /* add coordinates */
  211. Vect_get_node_coor(&Out, node, &x, &y, NULL);
  212. if (ncoor == acoor - 5) { /* always space for 5 region corners */
  213. acoor += 100;
  214. coor = (COOR *) G_realloc(coor, sizeof(COOR) * acoor);
  215. }
  216. coor[ncoor].x = x;
  217. coor[ncoor].y = y;
  218. ncoor++;
  219. }
  220. }
  221. /* Add region corners */
  222. coor[ncoor].x = Box.W;
  223. coor[ncoor].y = Box.S;
  224. ncoor++;
  225. coor[ncoor].x = Box.E;
  226. coor[ncoor].y = Box.S;
  227. ncoor++;
  228. coor[ncoor].x = Box.E;
  229. coor[ncoor].y = Box.N;
  230. ncoor++;
  231. coor[ncoor].x = Box.W;
  232. coor[ncoor].y = Box.N;
  233. ncoor++;
  234. /* Sort */
  235. qsort(coor, ncoor, sizeof(COOR), (void *)cmp);
  236. /* add last (first corner) */
  237. coor[ncoor].x = Box.W;
  238. coor[ncoor].y = Box.S;
  239. ncoor++;
  240. for (i = 1; i < ncoor; i++) {
  241. if (coor[i].x == coor[i - 1].x && coor[i].y == coor[i - 1].y)
  242. continue; /* duplicate */
  243. Vect_reset_line(Points);
  244. Vect_append_point(Points, coor[i].x, coor[i].y, 0.0);
  245. Vect_append_point(Points, coor[i - 1].x, coor[i - 1].y, 0.0);
  246. Vect_write_line(&Out, Type, Points, Cats);
  247. }
  248. G_free(coor);
  249. }
  250. nfields = Vect_cidx_get_num_fields(&In);
  251. cats = (int **)G_malloc(nfields * sizeof(int *));
  252. ncats = (int *)G_malloc(nfields * sizeof(int));
  253. fields = (int *)G_malloc(nfields * sizeof(int));
  254. for (i = 0; i < nfields; i++) {
  255. ncats[i] = 0;
  256. cats[i] =
  257. (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&In, i) *
  258. sizeof(int));
  259. fields[i] = Vect_cidx_get_field_number(&In, i);
  260. }
  261. /* Copy input points */
  262. if (Type == GV_LINE)
  263. ctype = GV_POINT;
  264. else
  265. ctype = GV_CENTROID;
  266. nlines = Vect_get_num_lines(&In);
  267. G_important_message(_("Writing features..."));
  268. for (line = 1; line <= nlines; line++) {
  269. G_percent(line, nlines, 2);
  270. type = Vect_read_line(&In, Points, Cats, line);
  271. if (!(type & GV_POINTS))
  272. continue;
  273. if (!skeleton) {
  274. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &Box))
  275. continue;
  276. Vect_write_line(&Out, ctype, Points, Cats);
  277. }
  278. for (i = 0; i < Cats->n_cats; i++) {
  279. int f, j;
  280. f = -1;
  281. for (j = 0; j < nfields; j++) { /* find field */
  282. if (fields[j] == Cats->field[i]) {
  283. f = j;
  284. break;
  285. }
  286. }
  287. if (f > -1) {
  288. cats[f][ncats[f]] = Cats->cat[i];
  289. ncats[f]++; }
  290. }
  291. }
  292. /* Copy tables */
  293. if (!(flag.table->answer)) {
  294. int ttype, ntabs = 0;
  295. struct field_info *IFi, *OFi;
  296. /* Number of output tabs */
  297. for (i = 0; i < Vect_get_num_dblinks(&In); i++) {
  298. int f, j;
  299. IFi = Vect_get_dblink(&In, i);
  300. f = -1;
  301. for (j = 0; j < nfields; j++) { /* find field */
  302. if (fields[j] == IFi->number) {
  303. f = j;
  304. break;
  305. }
  306. }
  307. if (f > -1) {
  308. if (ncats[f] > 0)
  309. ntabs++;
  310. }
  311. }
  312. if (ntabs > 1)
  313. ttype = GV_MTABLE;
  314. else
  315. ttype = GV_1TABLE;
  316. G_message(_("Writing attributes..."));
  317. for (i = 0; i < nfields; i++) {
  318. int ret;
  319. if (fields[i] == 0)
  320. continue;
  321. G_debug(1, "Layer %d", fields[i]);
  322. /* Make a list of categories */
  323. IFi = Vect_get_field(&In, fields[i]);
  324. if (!IFi) { /* no table */
  325. G_message(_("No table"));
  326. continue;
  327. }
  328. OFi =
  329. Vect_default_field_info(&Out, IFi->number, IFi->name, ttype);
  330. ret =
  331. db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
  332. OFi->driver,
  333. Vect_subst_var(OFi->database, &Out),
  334. OFi->table, IFi->key, cats[i],
  335. ncats[i]);
  336. if (ret == DB_FAILED) {
  337. G_warning(_("Cannot copy table"));
  338. }
  339. else {
  340. Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table,
  341. IFi->key, OFi->database, OFi->driver);
  342. }
  343. }
  344. }
  345. Vect_close(&In);
  346. if (Type == GV_BOUNDARY)
  347. clean_topo();
  348. /* build clean topology */
  349. Vect_build_partial(&Out, GV_BUILD_NONE);
  350. Vect_build(&Out);
  351. Vect_close(&Out);
  352. G_done_msg(" ");
  353. exit(EXIT_SUCCESS);
  354. }