main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /****************************************************************
  2. *
  3. * MODULE: v.random (based on s.rand)
  4. *
  5. * AUTHOR(S): James Darrell McCauley darrell@mccauley-usa.com
  6. * http://mccauley-usa.com/
  7. * OGR support by Martin Landa <landa.martin gmail.com>
  8. * Area support by Markus Metz
  9. *
  10. * PURPOSE: Randomly generate a 2D/3D GRASS vector points map.
  11. *
  12. * Modification History:
  13. *
  14. * s.rand v 0.5B <25 Jun 1995> Copyright (c) 1993-1995. James Darrell McCauley
  15. * <?? ??? 1993> - began coding and released test version (jdm)
  16. * <10 Jan 1994> - changed RAND_MAX for rand(), since it is different for
  17. * SunOS 4.1.x and Solaris 2.3. stdlib.h in the latter defines
  18. * RAND_MAX, but it doesn't in the former. v0.2B (jdm)
  19. * <02 Jan 1995> - clean Gmakefile, man page. added html v0.3B (jdm)
  20. * <25 Feb 1995> - cleaned 'gcc -Wall' warnings (jdm)
  21. * <25 Jun 1995> - new site API (jdm)
  22. * <13 Sep 2000> - released under GPL
  23. *
  24. * COPYRIGHT: (C) 2003-2010 by the GRASS Development Team
  25. *
  26. * This program is free software under the GNU General
  27. * Public License (>=v2). Read the file COPYING that
  28. * comes with GRASS for details.
  29. *
  30. **************************************************************/
  31. #include <stdlib.h>
  32. #include <math.h>
  33. #include <string.h>
  34. #include <grass/gis.h>
  35. #include <grass/vector.h>
  36. #include <grass/dbmi.h>
  37. #include <grass/glocale.h>
  38. /* for qsort */
  39. typedef struct {
  40. int i;
  41. double size;
  42. struct bound_box box;
  43. } BOX_SIZE;
  44. static int sort_by_size(const void *a, const void *b)
  45. {
  46. BOX_SIZE *as = (BOX_SIZE *)a;
  47. BOX_SIZE *bs = (BOX_SIZE *)b;
  48. if (as->size < bs->size)
  49. return -1;
  50. return (as->size > bs->size);
  51. }
  52. int main(int argc, char *argv[])
  53. {
  54. char *output, buf[DB_SQL_MAX];
  55. double (*rng)(void) = G_drand48;
  56. double zmin, zmax;
  57. int seed;
  58. int i, j, k, n, type, usefloat;
  59. int area, nareas, field;
  60. struct boxlist *List = NULL;
  61. BOX_SIZE *size_list = NULL;
  62. int alloc_size_list = 0;
  63. struct Map_info In, Out;
  64. struct line_pnts *Points;
  65. struct line_cats *Cats;
  66. struct cat_list *cat_list;
  67. struct bound_box box;
  68. struct Cell_head window;
  69. struct GModule *module;
  70. struct
  71. {
  72. struct Option *input, *field, *cats, *where, *output, *nsites,
  73. *zmin, *zmax, *zcol, *ztype, *seed;
  74. } parm;
  75. struct
  76. {
  77. struct Flag *z, *notopo, *a;
  78. } flag;
  79. struct field_info *Fi;
  80. dbDriver *driver;
  81. dbTable *table;
  82. dbString sql;
  83. G_gisinit(argv[0]);
  84. module = G_define_module();
  85. G_add_keyword(_("vector"));
  86. G_add_keyword(_("sampling"));
  87. G_add_keyword(_("statistics"));
  88. G_add_keyword(_("random"));
  89. module->description = _("Generates random 2D/3D vector points.");
  90. parm.output = G_define_standard_option(G_OPT_V_OUTPUT);
  91. parm.nsites = G_define_option();
  92. parm.nsites->key = "n";
  93. parm.nsites->type = TYPE_INTEGER;
  94. parm.nsites->required = YES;
  95. parm.nsites->description = _("Number of points to be created");
  96. parm.input = G_define_standard_option(G_OPT_V_INPUT);
  97. parm.input->required = NO;
  98. parm.input->description = _("Restrict points to areas in input vector");
  99. parm.input->guisection = _("Selection");
  100. parm.field = G_define_standard_option(G_OPT_V_FIELD_ALL);
  101. parm.field->guisection = _("Selection");
  102. parm.cats = G_define_standard_option(G_OPT_V_CATS);
  103. parm.cats->guisection = _("Selection");
  104. parm.where = G_define_standard_option(G_OPT_DB_WHERE);
  105. parm.where->guisection = _("Selection");
  106. parm.zmin = G_define_option();
  107. parm.zmin->key = "zmin";
  108. parm.zmin->type = TYPE_DOUBLE;
  109. parm.zmin->required = NO;
  110. parm.zmin->description =
  111. _("Minimum z height (needs -z flag or column name)");
  112. parm.zmin->answer = "0.0";
  113. parm.zmin->guisection = _("3D output");
  114. parm.zmax = G_define_option();
  115. parm.zmax->key = "zmax";
  116. parm.zmax->type = TYPE_DOUBLE;
  117. parm.zmax->required = NO;
  118. parm.zmax->description =
  119. _("Maximum z height (needs -z flag or column name)");
  120. parm.zmax->answer = "0.0";
  121. parm.zmax->guisection = _("3D output");
  122. parm.seed = G_define_option();
  123. parm.seed->key = "seed";
  124. parm.seed->type = TYPE_INTEGER;
  125. parm.seed->required = NO;
  126. parm.seed->description =
  127. _("The seed to initialize the random generator. If not set the process ID is used");
  128. parm.zcol = G_define_standard_option(G_OPT_DB_COLUMN);
  129. parm.zcol->label = _("Name of column for z values");
  130. parm.zcol->description =
  131. _("Writes z values to column");
  132. parm.zcol->guisection = _("3D output");
  133. parm.ztype = G_define_option();
  134. parm.ztype->key = "column_type";
  135. parm.ztype->type = TYPE_STRING;
  136. parm.ztype->required = NO;
  137. parm.ztype->multiple = NO;
  138. parm.ztype->description = _("Type of column for z values");
  139. parm.ztype->options = "integer,double precision";
  140. parm.ztype->answer = "double precision";
  141. parm.ztype->guisection = _("3D output");
  142. flag.z = G_define_flag();
  143. flag.z->key = 'z';
  144. flag.z->description = _("Create 3D output");
  145. flag.z->guisection = _("3D output");
  146. flag.a = G_define_flag();
  147. flag.a->key = 'a';
  148. flag.a->description = _("Generate n points for each individual area");
  149. flag.notopo = G_define_standard_flag(G_FLG_V_TOPO);
  150. if (G_parser(argc, argv))
  151. exit(EXIT_FAILURE);
  152. output = parm.output->answer;
  153. n = atoi(parm.nsites->answer);
  154. if(parm.seed->answer)
  155. seed = atoi(parm.seed->answer);
  156. if (n <= 0) {
  157. G_fatal_error(_("Number of points must be > 0 (%d given)"), n);
  158. }
  159. nareas = 0;
  160. cat_list = NULL;
  161. field = -1;
  162. if (parm.input->answer) {
  163. Vect_set_open_level(2); /* topology required */
  164. if (2 > Vect_open_old2(&In, parm.input->answer, "", parm.field->answer))
  165. G_fatal_error(_("Unable to open vector map <%s>"),
  166. parm.input->answer);
  167. if (parm.field->answer)
  168. field = Vect_get_field_number(&In, parm.field->answer);
  169. if ((parm.cats->answer || parm.where->answer) && field == -1) {
  170. G_warning(_("Invalid layer number (%d). Parameter '%s' or '%s' specified, assuming layer '1'."),
  171. field, parm.cats->key, parm.where->key);
  172. field = 1;
  173. }
  174. if (field > 0)
  175. cat_list = Vect_cats_set_constraint(&In, field, parm.where->answer,
  176. parm.cats->answer);
  177. nareas = Vect_get_num_areas(&In);
  178. if (nareas == 0) {
  179. Vect_close(&In);
  180. G_fatal_error(_("No areas in vector map <%s>"), parm.input->answer);
  181. }
  182. }
  183. else {
  184. if (flag.a->answer)
  185. G_fatal_error(_("The <-%c> flag requires an input vector with areas"),
  186. flag.a->key);
  187. }
  188. /* create new vector map */
  189. if (-1 == Vect_open_new(&Out, output, flag.z->answer ? WITH_Z : WITHOUT_Z))
  190. G_fatal_error(_("Unable to create vector map <%s>"), output);
  191. Vect_set_error_handler_io(NULL, &Out);
  192. /* Do we need to write random values into attribute table? */
  193. usefloat = -1;
  194. if (parm.zcol->answer) {
  195. Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
  196. driver =
  197. db_start_driver_open_database(Fi->driver,
  198. Vect_subst_var(Fi->database, &Out));
  199. if (driver == NULL) {
  200. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  201. Vect_subst_var(Fi->database, &Out), Fi->driver);
  202. }
  203. db_set_error_handler_driver(driver);
  204. db_begin_transaction(driver);
  205. db_init_string(&sql);
  206. sprintf(buf, "create table %s (%s integer, %s %s)", Fi->table, GV_KEY_COLUMN,
  207. parm.zcol->answer, parm.ztype->answer);
  208. db_set_string(&sql, buf);
  209. Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
  210. Fi->driver);
  211. /* Create table */
  212. G_debug(3, db_get_string(&sql));
  213. if (db_execute_immediate(driver, &sql) != DB_OK) {
  214. G_fatal_error(_("Unable to create table: %s"),
  215. db_get_string(&sql));
  216. }
  217. /* Create index */
  218. if (db_create_index2(driver, Fi->table, Fi->key) != DB_OK)
  219. G_warning(_("Unable to create index"));
  220. /* Grant */
  221. if (db_grant_on_table
  222. (driver, Fi->table, DB_PRIV_SELECT,
  223. DB_GROUP | DB_PUBLIC) != DB_OK) {
  224. G_fatal_error(_("Unable to grant privileges on table <%s>"),
  225. Fi->table);
  226. }
  227. /* OK. Let's check what type of column user has created */
  228. db_set_string(&sql, Fi->table);
  229. if (db_describe_table(driver, &sql, &table) != DB_OK) {
  230. G_fatal_error(_("Unable to describe table <%s>"), Fi->table);
  231. }
  232. if (db_get_table_number_of_columns(table) != 2) {
  233. G_fatal_error(_("Table should contain only two columns"));
  234. }
  235. type = db_get_column_sqltype(db_get_table_column(table, 1));
  236. if (type == DB_SQL_TYPE_SMALLINT || type == DB_SQL_TYPE_INTEGER)
  237. usefloat = 0;
  238. if (type == DB_SQL_TYPE_REAL || type == DB_SQL_TYPE_DOUBLE_PRECISION)
  239. usefloat = 1;
  240. if (usefloat < 0) {
  241. G_fatal_error(_("You have created unsupported column type. This module supports only INTEGER"
  242. " and DOUBLE PRECISION column types."));
  243. }
  244. }
  245. Vect_hist_command(&Out);
  246. /* Init the random seed */
  247. if(parm.seed->answer)
  248. G_srand48(seed);
  249. else
  250. G_srand48_auto();
  251. G_get_window(&window);
  252. Points = Vect_new_line_struct();
  253. Cats = Vect_new_cats_struct();
  254. if (nareas > 0) {
  255. int first = 1, count;
  256. struct bound_box abox, bbox;
  257. box.W = window.west;
  258. box.E = window.east;
  259. box.S = window.south;
  260. box.N = window.north;
  261. box.B = -PORT_DOUBLE_MAX;
  262. box.T = PORT_DOUBLE_MAX;
  263. count = 0;
  264. for (i = 1; i <= nareas; i++) {
  265. if (!Vect_get_area_centroid(&In, i))
  266. continue;
  267. if (field > 0) {
  268. if (Vect_get_area_cats(&In, i, Cats))
  269. continue;
  270. if (!Vect_cats_in_constraint(Cats, field, cat_list))
  271. continue;
  272. }
  273. Vect_get_area_box(&In, i, &abox);
  274. if (!Vect_box_overlap(&abox, &box))
  275. continue;
  276. if (first) {
  277. Vect_box_copy(&bbox, &abox);
  278. first = 0;
  279. }
  280. else
  281. Vect_box_extend(&bbox, &abox);
  282. count++;
  283. }
  284. if (count == 0) {
  285. Vect_close(&In);
  286. Vect_close(&Out);
  287. Vect_delete(output);
  288. G_fatal_error(_("Selected areas in input vector <%s> do not overlap with the current region"),
  289. parm.input->answer);
  290. }
  291. Vect_box_copy(&box, &bbox);
  292. /* does the vector overlap with the current region ? */
  293. if (box.W >= window.east || box.E <= window.west ||
  294. box.S >= window.north || box.N <= window.south) {
  295. Vect_close(&In);
  296. Vect_close(&Out);
  297. Vect_delete(output);
  298. G_fatal_error(_("Input vector <%s> does not overlap with the current region"),
  299. parm.input->answer);
  300. }
  301. /* try to reduce the current region */
  302. if (window.east > box.E)
  303. window.east = box.E;
  304. if (window.west < box.W)
  305. window.west = box.W;
  306. if (window.north > box.N)
  307. window.north = box.N;
  308. if (window.south < box.S)
  309. window.south = box.S;
  310. List = Vect_new_boxlist(1);
  311. alloc_size_list = 10;
  312. size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE));
  313. }
  314. zmin = zmax = 0;
  315. if (flag.z->answer || parm.zcol->answer) {
  316. zmax = atof(parm.zmax->answer);
  317. zmin = atof(parm.zmin->answer);
  318. }
  319. G_message(_("Generating points..."));
  320. if (flag.a->answer && nareas > 0) {
  321. struct bound_box abox, bbox;
  322. int cat = 1;
  323. /* n points for each area */
  324. nareas = Vect_get_num_areas(&In);
  325. G_percent(0, nareas, 1);
  326. for (area = 1; area <= nareas; area++) {
  327. G_percent(area, nareas, 1);
  328. if (!Vect_get_area_centroid(&In, area))
  329. continue;
  330. if (field > 0) {
  331. if (Vect_get_area_cats(&In, area, Cats))
  332. continue;
  333. if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
  334. continue;
  335. }
  336. }
  337. box.W = window.west;
  338. box.E = window.east;
  339. box.S = window.south;
  340. box.N = window.north;
  341. box.B = -PORT_DOUBLE_MAX;
  342. box.T = PORT_DOUBLE_MAX;
  343. Vect_get_area_box(&In, area, &abox);
  344. if (!Vect_box_overlap(&box, &abox))
  345. continue;
  346. bbox = abox;
  347. if (bbox.W < box.W)
  348. bbox.W = box.W;
  349. if (bbox.E > box.E)
  350. bbox.E = box.E;
  351. if (bbox.S < box.S)
  352. bbox.S = box.S;
  353. if (bbox.N > box.N)
  354. bbox.N = box.N;
  355. for (i = 0; i < n; ++i) {
  356. double x, y, z;
  357. int outside = 1;
  358. int ret;
  359. Vect_reset_line(Points);
  360. Vect_reset_cats(Cats);
  361. while (outside) {
  362. x = rng() * (bbox.W - bbox.E) + bbox.E;
  363. y = rng() * (bbox.N - bbox.S) + bbox.S;
  364. z = rng() * (zmax - zmin) + zmin;
  365. ret = Vect_point_in_area(x, y, &In, area, &abox);
  366. G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret);
  367. if (ret >= 1) {
  368. outside = 0;
  369. }
  370. }
  371. if (flag.z->answer)
  372. Vect_append_point(Points, x, y, z);
  373. else
  374. Vect_append_point(Points, x, y, 0.0);
  375. if (parm.zcol->answer) {
  376. sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
  377. db_set_string(&sql, buf);
  378. /* Round random value if column is integer type */
  379. if (usefloat)
  380. sprintf(buf, "%f )", z);
  381. else
  382. sprintf(buf, "%.0f )", z);
  383. db_append_string(&sql, buf);
  384. G_debug(3, db_get_string(&sql));
  385. if (db_execute_immediate(driver, &sql) != DB_OK) {
  386. G_fatal_error(_("Cannot insert new row: %s"),
  387. db_get_string(&sql));
  388. }
  389. }
  390. Vect_cat_set(Cats, 1, cat++);
  391. Vect_write_line(&Out, GV_POINT, Points, Cats);
  392. }
  393. }
  394. }
  395. else {
  396. /* n points in total */
  397. for (i = 0; i < n; ++i) {
  398. double x, y, z;
  399. G_percent(i, n, 4);
  400. Vect_reset_line(Points);
  401. Vect_reset_cats(Cats);
  402. x = rng() * (window.west - window.east) + window.east;
  403. y = rng() * (window.north - window.south) + window.south;
  404. z = rng() * (zmax - zmin) + zmin;
  405. if (nareas) {
  406. int outside = 1;
  407. do {
  408. /* select areas by box */
  409. box.E = x;
  410. box.W = x;
  411. box.N = y;
  412. box.S = y;
  413. box.T = PORT_DOUBLE_MAX;
  414. box.B = -PORT_DOUBLE_MAX;
  415. Vect_select_areas_by_box(&In, &box, List);
  416. G_debug(3, " %d areas selected by box", List->n_values);
  417. /* sort areas by size, the smallest is likely to be the nearest */
  418. if (alloc_size_list < List->n_values) {
  419. alloc_size_list = List->n_values;
  420. size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE));
  421. }
  422. k = 0;
  423. for (j = 0; j < List->n_values; j++) {
  424. area = List->id[j];
  425. if (!Vect_get_area_centroid(&In, area))
  426. continue;
  427. if (field > 0) {
  428. if (Vect_get_area_cats(&In, area, Cats))
  429. continue;
  430. if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
  431. continue;
  432. }
  433. }
  434. List->id[k] = List->id[j];
  435. List->box[k] = List->box[j];
  436. size_list[k].i = List->id[k];
  437. box = List->box[k];
  438. size_list[k].box = List->box[k];
  439. size_list[k].size = (box.N - box.S) * (box.E - box.W);
  440. k++;
  441. }
  442. List->n_values = k;
  443. if (List->n_values == 2) {
  444. /* simple swap */
  445. if (size_list[1].size < size_list[0].size) {
  446. size_list[0].i = List->id[1];
  447. size_list[1].i = List->id[0];
  448. size_list[0].box = List->box[1];
  449. size_list[1].box = List->box[0];
  450. }
  451. }
  452. else if (List->n_values > 2)
  453. qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size);
  454. for (j = 0; j < List->n_values; j++) {
  455. int ret;
  456. area = size_list[j].i;
  457. ret = Vect_point_in_area(x, y, &In, area, &size_list[j].box);
  458. G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret);
  459. if (ret >= 1) {
  460. outside = 0;
  461. break;
  462. }
  463. }
  464. if (outside) {
  465. x = rng() * (window.west - window.east) + window.east;
  466. y = rng() * (window.north - window.south) + window.south;
  467. z = rng() * (zmax - zmin) + zmin;
  468. }
  469. } while (outside);
  470. }
  471. if (flag.z->answer)
  472. Vect_append_point(Points, x, y, z);
  473. else
  474. Vect_append_point(Points, x, y, 0.0);
  475. if (parm.zcol->answer) {
  476. sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
  477. db_set_string(&sql, buf);
  478. /* Round random value if column is integer type */
  479. if (usefloat)
  480. sprintf(buf, "%f )", z);
  481. else
  482. sprintf(buf, "%.0f )", z);
  483. db_append_string(&sql, buf);
  484. G_debug(3, db_get_string(&sql));
  485. if (db_execute_immediate(driver, &sql) != DB_OK) {
  486. G_fatal_error(_("Cannot insert new row: %s"),
  487. db_get_string(&sql));
  488. }
  489. }
  490. Vect_cat_set(Cats, 1, i + 1);
  491. Vect_write_line(&Out, GV_POINT, Points, Cats);
  492. }
  493. G_percent(1, 1, 1);
  494. }
  495. if (parm.zcol->answer) {
  496. db_commit_transaction(driver);
  497. db_close_database_shutdown_driver(driver);
  498. }
  499. if (!flag.notopo->answer) {
  500. Vect_build(&Out);
  501. }
  502. Vect_close(&Out);
  503. exit(EXIT_SUCCESS);
  504. }