main.c 17 KB

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