main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  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. G_add_keyword(_("point pattern"));
  90. G_add_keyword(_("stratified random sampling"));
  91. module->description = _("Generates random 2D/3D vector points.");
  92. parm.output = G_define_standard_option(G_OPT_V_OUTPUT);
  93. parm.nsites = G_define_option();
  94. parm.nsites->key = "npoints";
  95. parm.nsites->type = TYPE_INTEGER;
  96. parm.nsites->required = YES;
  97. parm.nsites->description = _("Number of points to be created");
  98. parm.input = G_define_standard_option(G_OPT_V_INPUT);
  99. parm.input->key = "restrict";
  100. parm.input->required = NO;
  101. parm.input->description = _("Restrict points to areas in input vector");
  102. parm.input->guisection = _("Selection");
  103. parm.field = G_define_standard_option(G_OPT_V_FIELD_ALL);
  104. parm.field->guisection = _("Selection");
  105. parm.cats = G_define_standard_option(G_OPT_V_CATS);
  106. parm.cats->guisection = _("Selection");
  107. parm.where = G_define_standard_option(G_OPT_DB_WHERE);
  108. parm.where->guisection = _("Selection");
  109. parm.zmin = G_define_option();
  110. parm.zmin->key = "zmin";
  111. parm.zmin->type = TYPE_DOUBLE;
  112. parm.zmin->required = NO;
  113. parm.zmin->description =
  114. _("Minimum z height (needs -z flag or column name)");
  115. parm.zmin->answer = "0.0";
  116. parm.zmin->guisection = _("3D output");
  117. parm.zmax = G_define_option();
  118. parm.zmax->key = "zmax";
  119. parm.zmax->type = TYPE_DOUBLE;
  120. parm.zmax->required = NO;
  121. parm.zmax->description =
  122. _("Maximum z height (needs -z flag or column name)");
  123. parm.zmax->answer = "0.0";
  124. parm.zmax->guisection = _("3D output");
  125. parm.seed = G_define_option();
  126. parm.seed->key = "seed";
  127. parm.seed->type = TYPE_INTEGER;
  128. parm.seed->required = NO;
  129. parm.seed->description =
  130. _("The seed to initialize the random generator. If not set the process ID is used");
  131. parm.zcol = G_define_standard_option(G_OPT_DB_COLUMN);
  132. parm.zcol->label = _("Name of column for z values");
  133. parm.zcol->description =
  134. _("Writes z values to column");
  135. parm.zcol->guisection = _("3D output");
  136. parm.ztype = G_define_option();
  137. parm.ztype->key = "column_type";
  138. parm.ztype->type = TYPE_STRING;
  139. parm.ztype->required = NO;
  140. parm.ztype->multiple = NO;
  141. parm.ztype->description = _("Type of column for z values");
  142. parm.ztype->options = "integer,double precision";
  143. parm.ztype->answer = "double precision";
  144. parm.ztype->guisection = _("3D output");
  145. flag.z = G_define_flag();
  146. flag.z->key = 'z';
  147. flag.z->description = _("Create 3D output");
  148. flag.z->guisection = _("3D output");
  149. flag.a = G_define_flag();
  150. flag.a->key = 'a';
  151. flag.a->description = _("Generate n points for each individual area");
  152. flag.notopo = G_define_standard_flag(G_FLG_V_TOPO);
  153. if (G_parser(argc, argv))
  154. exit(EXIT_FAILURE);
  155. output = parm.output->answer;
  156. n = atoi(parm.nsites->answer);
  157. if(parm.seed->answer)
  158. seed = atoi(parm.seed->answer);
  159. if (n <= 0) {
  160. G_fatal_error(_("Number of points must be > 0 (%d given)"), n);
  161. }
  162. nareas = 0;
  163. cat_list = NULL;
  164. field = -1;
  165. if (parm.input->answer) {
  166. Vect_set_open_level(2); /* topology required */
  167. if (2 > Vect_open_old2(&In, parm.input->answer, "", parm.field->answer))
  168. G_fatal_error(_("Unable to open vector map <%s>"),
  169. parm.input->answer);
  170. if (parm.field->answer)
  171. field = Vect_get_field_number(&In, parm.field->answer);
  172. if ((parm.cats->answer || parm.where->answer) && field == -1) {
  173. G_warning(_("Invalid layer number (%d). Parameter '%s' or '%s' specified, assuming layer '1'."),
  174. field, parm.cats->key, parm.where->key);
  175. field = 1;
  176. }
  177. if (field > 0)
  178. cat_list = Vect_cats_set_constraint(&In, field, parm.where->answer,
  179. parm.cats->answer);
  180. nareas = Vect_get_num_areas(&In);
  181. if (nareas == 0) {
  182. Vect_close(&In);
  183. G_fatal_error(_("No areas in vector map <%s>"), parm.input->answer);
  184. }
  185. }
  186. else {
  187. if (flag.a->answer)
  188. G_fatal_error(_("The <-%c> flag requires an input vector with areas"),
  189. flag.a->key);
  190. }
  191. /* create new vector map */
  192. if (-1 == Vect_open_new(&Out, output, flag.z->answer ? WITH_Z : WITHOUT_Z))
  193. G_fatal_error(_("Unable to create vector map <%s>"), output);
  194. Vect_set_error_handler_io(NULL, &Out);
  195. /* Do we need to write random values into attribute table? */
  196. usefloat = -1;
  197. if (parm.zcol->answer) {
  198. Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
  199. driver =
  200. db_start_driver_open_database(Fi->driver,
  201. Vect_subst_var(Fi->database, &Out));
  202. if (driver == NULL) {
  203. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  204. Vect_subst_var(Fi->database, &Out), Fi->driver);
  205. }
  206. db_set_error_handler_driver(driver);
  207. db_begin_transaction(driver);
  208. db_init_string(&sql);
  209. /* Create table */
  210. sprintf(buf, "create table %s (%s integer, %s %s)", Fi->table, GV_KEY_COLUMN,
  211. parm.zcol->answer, parm.ztype->answer);
  212. db_set_string(&sql, buf);
  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. Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
  245. Fi->driver);
  246. }
  247. Vect_hist_command(&Out);
  248. /* Init the random seed */
  249. if(parm.seed->answer)
  250. G_srand48(seed);
  251. else
  252. G_srand48_auto();
  253. G_get_window(&window);
  254. Points = Vect_new_line_struct();
  255. Cats = Vect_new_cats_struct();
  256. if (nareas > 0) {
  257. int first = 1, count;
  258. struct bound_box abox, bbox;
  259. box.W = window.west;
  260. box.E = window.east;
  261. box.S = window.south;
  262. box.N = window.north;
  263. box.B = -PORT_DOUBLE_MAX;
  264. box.T = PORT_DOUBLE_MAX;
  265. count = 0;
  266. for (i = 1; i <= nareas; i++) {
  267. if (!Vect_get_area_centroid(&In, i))
  268. continue;
  269. if (field > 0) {
  270. if (Vect_get_area_cats(&In, i, Cats))
  271. continue;
  272. if (!Vect_cats_in_constraint(Cats, field, cat_list))
  273. continue;
  274. }
  275. Vect_get_area_box(&In, i, &abox);
  276. if (!Vect_box_overlap(&abox, &box))
  277. continue;
  278. if (first) {
  279. Vect_box_copy(&bbox, &abox);
  280. first = 0;
  281. }
  282. else
  283. Vect_box_extend(&bbox, &abox);
  284. count++;
  285. }
  286. if (count == 0) {
  287. Vect_close(&In);
  288. Vect_close(&Out);
  289. Vect_delete(output);
  290. G_fatal_error(_("Selected areas in input vector <%s> do not overlap with the current region"),
  291. parm.input->answer);
  292. }
  293. Vect_box_copy(&box, &bbox);
  294. /* does the vector overlap with the current region ? */
  295. if (box.W >= window.east || box.E <= window.west ||
  296. box.S >= window.north || box.N <= window.south) {
  297. Vect_close(&In);
  298. Vect_close(&Out);
  299. Vect_delete(output);
  300. G_fatal_error(_("Input vector <%s> does not overlap with the current region"),
  301. parm.input->answer);
  302. }
  303. /* try to reduce the current region */
  304. if (window.east > box.E)
  305. window.east = box.E;
  306. if (window.west < box.W)
  307. window.west = box.W;
  308. if (window.north > box.N)
  309. window.north = box.N;
  310. if (window.south < box.S)
  311. window.south = box.S;
  312. List = Vect_new_boxlist(1);
  313. alloc_size_list = 10;
  314. size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE));
  315. }
  316. zmin = zmax = 0;
  317. if (flag.z->answer || parm.zcol->answer) {
  318. zmax = atof(parm.zmax->answer);
  319. zmin = atof(parm.zmin->answer);
  320. }
  321. G_message(_("Generating points..."));
  322. if (flag.a->answer && nareas > 0) {
  323. struct bound_box abox, bbox;
  324. int cat = 1;
  325. /* n points for each area */
  326. nareas = Vect_get_num_areas(&In);
  327. G_percent(0, nareas, 1);
  328. for (area = 1; area <= nareas; area++) {
  329. G_percent(area, nareas, 1);
  330. if (!Vect_get_area_centroid(&In, area))
  331. continue;
  332. if (field > 0) {
  333. if (Vect_get_area_cats(&In, area, Cats))
  334. continue;
  335. if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
  336. continue;
  337. }
  338. }
  339. box.W = window.west;
  340. box.E = window.east;
  341. box.S = window.south;
  342. box.N = window.north;
  343. box.B = -PORT_DOUBLE_MAX;
  344. box.T = PORT_DOUBLE_MAX;
  345. Vect_get_area_box(&In, area, &abox);
  346. if (!Vect_box_overlap(&box, &abox))
  347. continue;
  348. bbox = abox;
  349. if (bbox.W < box.W)
  350. bbox.W = box.W;
  351. if (bbox.E > box.E)
  352. bbox.E = box.E;
  353. if (bbox.S < box.S)
  354. bbox.S = box.S;
  355. if (bbox.N > box.N)
  356. bbox.N = box.N;
  357. for (i = 0; i < n; ++i) {
  358. double x, y, z;
  359. int outside = 1;
  360. int ret;
  361. Vect_reset_line(Points);
  362. Vect_reset_cats(Cats);
  363. while (outside) {
  364. x = rng() * (bbox.W - bbox.E) + bbox.E;
  365. y = rng() * (bbox.N - bbox.S) + bbox.S;
  366. z = rng() * (zmax - zmin) + zmin;
  367. ret = Vect_point_in_area(x, y, &In, area, &abox);
  368. G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret);
  369. if (ret >= 1) {
  370. outside = 0;
  371. }
  372. }
  373. if (flag.z->answer)
  374. Vect_append_point(Points, x, y, z);
  375. else
  376. Vect_append_point(Points, x, y, 0.0);
  377. if (parm.zcol->answer) {
  378. sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
  379. db_set_string(&sql, buf);
  380. /* Round random value if column is integer type */
  381. if (usefloat)
  382. sprintf(buf, "%f )", z);
  383. else
  384. sprintf(buf, "%.0f )", z);
  385. db_append_string(&sql, buf);
  386. G_debug(3, "%s", db_get_string(&sql));
  387. if (db_execute_immediate(driver, &sql) != DB_OK) {
  388. G_fatal_error(_("Cannot insert new row: %s"),
  389. db_get_string(&sql));
  390. }
  391. }
  392. Vect_cat_set(Cats, 1, cat++);
  393. Vect_write_line(&Out, GV_POINT, Points, Cats);
  394. }
  395. }
  396. }
  397. else {
  398. /* n points in total */
  399. for (i = 0; i < n; ++i) {
  400. double x, y, z;
  401. G_percent(i, n, 4);
  402. Vect_reset_line(Points);
  403. Vect_reset_cats(Cats);
  404. x = rng() * (window.west - window.east) + window.east;
  405. y = rng() * (window.north - window.south) + window.south;
  406. z = rng() * (zmax - zmin) + zmin;
  407. if (nareas) {
  408. int outside = 1;
  409. do {
  410. /* select areas by box */
  411. box.E = x;
  412. box.W = x;
  413. box.N = y;
  414. box.S = y;
  415. box.T = PORT_DOUBLE_MAX;
  416. box.B = -PORT_DOUBLE_MAX;
  417. Vect_select_areas_by_box(&In, &box, List);
  418. G_debug(3, " %d areas selected by box", List->n_values);
  419. /* sort areas by size, the smallest is likely to be the nearest */
  420. if (alloc_size_list < List->n_values) {
  421. alloc_size_list = List->n_values;
  422. size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE));
  423. }
  424. k = 0;
  425. for (j = 0; j < List->n_values; j++) {
  426. area = List->id[j];
  427. if (!Vect_get_area_centroid(&In, area))
  428. continue;
  429. if (field > 0) {
  430. if (Vect_get_area_cats(&In, area, Cats))
  431. continue;
  432. if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
  433. continue;
  434. }
  435. }
  436. List->id[k] = List->id[j];
  437. List->box[k] = List->box[j];
  438. size_list[k].i = List->id[k];
  439. box = List->box[k];
  440. size_list[k].box = List->box[k];
  441. size_list[k].size = (box.N - box.S) * (box.E - box.W);
  442. k++;
  443. }
  444. List->n_values = k;
  445. if (List->n_values == 2) {
  446. /* simple swap */
  447. if (size_list[1].size < size_list[0].size) {
  448. size_list[0].i = List->id[1];
  449. size_list[1].i = List->id[0];
  450. size_list[0].box = List->box[1];
  451. size_list[1].box = List->box[0];
  452. }
  453. }
  454. else if (List->n_values > 2)
  455. qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size);
  456. for (j = 0; j < List->n_values; j++) {
  457. int ret;
  458. area = size_list[j].i;
  459. ret = Vect_point_in_area(x, y, &In, area, &size_list[j].box);
  460. G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret);
  461. if (ret >= 1) {
  462. outside = 0;
  463. break;
  464. }
  465. }
  466. if (outside) {
  467. x = rng() * (window.west - window.east) + window.east;
  468. y = rng() * (window.north - window.south) + window.south;
  469. z = rng() * (zmax - zmin) + zmin;
  470. }
  471. } while (outside);
  472. }
  473. if (flag.z->answer)
  474. Vect_append_point(Points, x, y, z);
  475. else
  476. Vect_append_point(Points, x, y, 0.0);
  477. if (parm.zcol->answer) {
  478. sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
  479. db_set_string(&sql, buf);
  480. /* Round random value if column is integer type */
  481. if (usefloat)
  482. sprintf(buf, "%f )", z);
  483. else
  484. sprintf(buf, "%.0f )", z);
  485. db_append_string(&sql, buf);
  486. G_debug(3, "%s", db_get_string(&sql));
  487. if (db_execute_immediate(driver, &sql) != DB_OK) {
  488. G_fatal_error(_("Cannot insert new row: %s"),
  489. db_get_string(&sql));
  490. }
  491. }
  492. Vect_cat_set(Cats, 1, i + 1);
  493. Vect_write_line(&Out, GV_POINT, Points, Cats);
  494. }
  495. G_percent(1, 1, 1);
  496. }
  497. if (parm.zcol->answer) {
  498. db_commit_transaction(driver);
  499. db_close_database_shutdown_driver(driver);
  500. }
  501. if (!flag.notopo->answer) {
  502. Vect_build(&Out);
  503. }
  504. Vect_close(&Out);
  505. exit(EXIT_SUCCESS);
  506. }