main.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /****************************************************************************
  2. *
  3. * MODULE: r.to.rast3elev
  4. *
  5. * AUTHOR(S): Original author
  6. * Soeren Gebbert soerengebbert@gmx.de
  7. * 07 08 2006 Berlin
  8. * PURPOSE: Creates a 3D volume map based on 2D elevation and value raster maps
  9. *
  10. * COPYRIGHT: (C) 2006 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/raster3d.h>
  23. #include <grass/glocale.h>
  24. #include <grass/config.h>
  25. /*- params and global variables -----------------------------------------*/
  26. typedef struct {
  27. struct Option *input, *elev, *output, *upper, *lower, *tilesize;
  28. struct Flag *fillup, *filllow, *mask;
  29. } paramType;
  30. /*Data to be used */
  31. typedef struct {
  32. int mapnum; /*The umber of input maps */
  33. int count; /*3d raster map access counter */
  34. void *map; /*The 3d voxel output map */
  35. int input; /*The current raster value map pointer */
  36. int elev; /*The current raster elevation map pointer */
  37. int inputmaptype;
  38. int elevmaptype;
  39. double upper; /*The upper value */
  40. double lower; /*The lower value */
  41. int useUpperVal; /*0 = use upper value, 1 = use map value to fill upper cells */
  42. int useLowerVal; /*0 = use lower value, 1 = use map value to fill lower cells */
  43. } Database;
  44. paramType param; /*params */
  45. /*- prototypes --------------------------------------------------------------*/
  46. void fatal_error(Database db, char *errorMsg); /*Simple Error message */
  47. void set_params(); /*Fill the paramType structure */
  48. void elev_raster_to_g3d(Database db, RASTER3D_Region region); /*Write the raster */
  49. int open_input_raster_map(const char *name); /*opens the outputmap */
  50. void close_input_raster_map(int fd); /*close the map */
  51. double get_raster_value_as_double(int maptype, void *ptr, double nullval);
  52. void check_input_maps(Database * db); /*Check input maps */
  53. /* ************************************************************************* */
  54. /* Get the value of the current raster pointer as double ******************* */
  55. /* ************************************************************************* */
  56. double get_raster_value_as_double(int MapType, void *ptr, double nullval)
  57. {
  58. if (Rast_is_null_value(ptr, MapType))
  59. return nullval;
  60. switch (MapType) {
  61. case CELL_TYPE: return *(CELL *) ptr;
  62. case FCELL_TYPE: return *(FCELL *) ptr;
  63. case DCELL_TYPE: return *(DCELL *) ptr;
  64. default: return nullval;
  65. }
  66. }
  67. /* ************************************************************************* */
  68. /* Check the input maps **************************************************** */
  69. /* ************************************************************************* */
  70. void check_input_maps(Database * db)
  71. {
  72. int i;
  73. int elevcount = 0, inputcount = 0;
  74. G_debug(2, "Checking input maps");
  75. /*Check elev maps */
  76. if (param.elev->answers != NULL)
  77. for (i = 0; param.elev->answers[i] != NULL; i++)
  78. elevcount++;
  79. /*Check input maps */
  80. if (param.input->answers != NULL)
  81. for (i = 0; param.input->answers[i] != NULL; i++)
  82. inputcount++;
  83. if (elevcount != inputcount)
  84. G_fatal_error(_("The number of input and elevation maps is not equal"));
  85. db->mapnum = inputcount;
  86. return;
  87. }
  88. /* ************************************************************************* */
  89. /* Open the raster input map *********************************************** */
  90. /* ************************************************************************* */
  91. int open_input_raster_map(const char *name)
  92. {
  93. G_debug(3, "Open Raster file %s", name);
  94. return Rast_open_old(name, "");
  95. }
  96. /* ************************************************************************* */
  97. /* Close the raster input map ********************************************** */
  98. /* ************************************************************************* */
  99. void close_input_raster_map(int fd)
  100. {
  101. Rast_close(fd);
  102. }
  103. /* ************************************************************************* */
  104. /* Error handling ********************************************************** */
  105. /* ************************************************************************* */
  106. void fatal_error(Database db, char *errorMsg)
  107. {
  108. /* Close files and exit */
  109. if (db.map != NULL) {
  110. /* should unopen map here! but this functionality is not jet implemented */
  111. if (!Rast3d_close(db.map))
  112. Rast3d_fatal_error(_("Could not close the map"));
  113. }
  114. if (db.input)
  115. close_input_raster_map(db.input);
  116. if (db.elev)
  117. close_input_raster_map(db.elev);
  118. Rast3d_fatal_error("%s", errorMsg);
  119. exit(EXIT_FAILURE);
  120. }
  121. /* ************************************************************************* */
  122. /* Set up the arguments **************************************************** */
  123. /* ************************************************************************* */
  124. void set_params()
  125. {
  126. param.input = G_define_standard_option(G_OPT_R_INPUTS);
  127. param.elev = G_define_standard_option(G_OPT_R_ELEVS);
  128. param.output = G_define_standard_option(G_OPT_R3_OUTPUT);
  129. param.upper = G_define_option();
  130. param.upper->key = "upper";
  131. param.upper->type = TYPE_DOUBLE;
  132. param.upper->required = NO;
  133. param.upper->description =
  134. _("The value to fill the upper cells, default is null");
  135. param.lower = G_define_option();
  136. param.lower->key = "lower";
  137. param.lower->type = TYPE_DOUBLE;
  138. param.lower->required = NO;
  139. param.lower->description =
  140. _("The value to fill the lower cells, default is null");
  141. param.tilesize = G_define_option();
  142. param.tilesize->description = _("The maximum tile size in kilo bytes. Default is 32KB.");
  143. param.tilesize->key = "tilesize";
  144. param.tilesize->answer = "32";
  145. param.tilesize->type = TYPE_INTEGER;
  146. param.tilesize->required = NO;
  147. param.tilesize->multiple = NO;
  148. param.fillup = G_define_flag();
  149. param.fillup->key = 'u';
  150. param.fillup->description =
  151. _("Use the input map values to fill the upper cells");
  152. param.filllow = G_define_flag();
  153. param.filllow->key = 'l';
  154. param.filllow->description =
  155. _("Use the input map values to fill the lower cells");
  156. param.mask = G_define_flag();
  157. param.mask->key = 'm';
  158. param.mask->description = _("Use 3D raster mask (if exists) with input map");
  159. return;
  160. }
  161. /* ************************************************************************* */
  162. /* Write the raster maps into the RASTER3D map *********************************** */
  163. /* ************************************************************************* */
  164. void elev_raster_to_g3d(Database db, RASTER3D_Region region)
  165. {
  166. int x, y, z = 0;
  167. int rows, cols, depths;
  168. void *input_rast;
  169. void *input_ptr;
  170. void *elev_rast;
  171. void *elev_ptr;
  172. double inval, value, null;
  173. double height, top, bottom, tbres;
  174. rows = region.rows;
  175. cols = region.cols;
  176. depths = region.depths;
  177. top = region.top;
  178. bottom = region.bottom;
  179. /*Calculate the top-bottom resolution */
  180. tbres = (top - bottom) / depths;
  181. /*memory */
  182. input_rast = Rast_allocate_buf(db.inputmaptype);
  183. elev_rast = Rast_allocate_buf(db.elevmaptype);
  184. Rast3d_set_null_value(&null, 1, DCELL_TYPE);
  185. G_debug(3,
  186. "elev_raster_to_g3d: Writing 3D raster map with depths %i rows %i cols %i and count %i.",
  187. depths, rows, cols, db.count);
  188. /*The mainloop */
  189. for (y = 0; y < rows; y++) { /* From north to south */
  190. G_percent(y, rows - 1, 10);
  191. Rast_get_row(db.input, input_rast, y, db.inputmaptype);
  192. Rast_get_row(db.elev, elev_rast, y, db.elevmaptype);
  193. for (x = 0, input_ptr = input_rast, elev_ptr = elev_rast; x < cols;
  194. x++, input_ptr =
  195. G_incr_void_ptr(input_ptr, Rast_cell_size(db.inputmaptype)),
  196. elev_ptr =
  197. G_incr_void_ptr(elev_ptr, Rast_cell_size(db.elevmaptype))) {
  198. /*Get the elevation and the input map value */
  199. inval =
  200. get_raster_value_as_double(db.inputmaptype, input_ptr, null);
  201. height =
  202. get_raster_value_as_double(db.elevmaptype, elev_ptr, null);
  203. G_debug(4,
  204. "Caluclating position in 3d region -> height %g with value %g",
  205. height, inval);
  206. /* Calculate if the RASTER3D cell is lower or upper the elevation map
  207. * and set the value.*/
  208. if (db.count == 0) {
  209. /*Use this method if the 3d raster map was not touched befor */
  210. for (z = 0; z < depths; z++) {
  211. /*Upper cells */
  212. if (height < (z * tbres + bottom)) {
  213. if (db.useUpperVal == 1)
  214. value = inval; /*Input map value */
  215. else
  216. value = db.upper;
  217. }
  218. /*lower cells */
  219. if (height > ((z + 1) * tbres + bottom)) {
  220. if (db.useLowerVal == 1)
  221. value = inval; /*Input map value */
  222. else
  223. value = db.lower;
  224. }
  225. /*If exactly at the border, fill upper AND lower cell */
  226. if (height >= (z * tbres + bottom) &&
  227. height <= ((z + 1) * tbres + bottom))
  228. value = inval;
  229. /*If the elevation is null, set the RASTER3D value null */
  230. if (Rast3d_is_null_value_num(&height, DCELL_TYPE))
  231. value = null;
  232. /*Write the value to the 3D map */
  233. if (Rast3d_put_double(db.map, x, y, z, value) < 0)
  234. fatal_error(db, _("Error writing 3D raster double data"));
  235. }
  236. } else {
  237. /*Use this method for every following 3d raster maps access */
  238. for (z = 0; z < depths; z++) {
  239. /*Upper cells */
  240. if (height < (z * tbres + bottom)) {
  241. if (db.useUpperVal == 1)
  242. value = inval; /*Input map value */
  243. else if (db.useUpperVal == 2)
  244. value = db.upper;
  245. else
  246. value = Rast3d_get_double(db.map, x, y, z);
  247. }
  248. /*lower cells */
  249. if (height > ((z + 1) * tbres + bottom)) {
  250. if (db.useLowerVal == 1)
  251. value = inval; /*Input map value */
  252. else if (db.useLowerVal == 2)
  253. value = db.lower;
  254. else
  255. value = Rast3d_get_double(db.map, x, y, z);
  256. }
  257. /*If exactly at the border, fill upper AND lower cell */
  258. if (height >= (z * tbres + bottom) &&
  259. height <= ((z + 1) * tbres + bottom))
  260. value = inval;
  261. /*If the elevation is null, set the RASTER3D value null */
  262. if (Rast3d_is_null_value_num(&height, DCELL_TYPE))
  263. value = Rast3d_get_double(db.map, x, y, z);
  264. /*Write the value to the 3D map */
  265. if (Rast3d_put_double(db.map, x, y, z, value) < 0)
  266. fatal_error(db, _("Error writing 3D raster double data"));
  267. }
  268. }
  269. }
  270. }
  271. if (input_rast)
  272. G_free(input_rast);
  273. if (elev_rast)
  274. G_free(elev_rast);
  275. return;
  276. }
  277. /* ************************************************************************* */
  278. /* Main function, open the raster maps and create the RASTER3D raster maps ****** */
  279. /* ************************************************************************* */
  280. int main(int argc, char *argv[])
  281. {
  282. RASTER3D_Region region;
  283. struct Cell_head window2d;
  284. struct GModule *module;
  285. int cols, rows, i;
  286. char *name = NULL;
  287. int changemask = 0;
  288. double maxSize;
  289. Database db;
  290. /*Initiate the database structure */
  291. db.map = NULL;
  292. db.input = 0;
  293. db.elev = 0;
  294. db.useUpperVal = 0;
  295. db.useLowerVal = 0;
  296. /* Initialize GRASS */
  297. G_gisinit(argv[0]);
  298. module = G_define_module();
  299. G_add_keyword(_("raster"));
  300. G_add_keyword(_("conversion"));
  301. G_add_keyword(_("raster3d"));
  302. G_add_keyword(_("voxel"));
  303. module->description =
  304. _("Creates a 3D volume map based on 2D elevation and value raster maps.");
  305. /* Get parameters from user */
  306. set_params();
  307. /* Have GRASS get inputs */
  308. if (G_parser(argc, argv))
  309. exit(EXIT_FAILURE);
  310. /*Check if maps exist */
  311. check_input_maps(&db);
  312. /* Get the tile size */
  313. maxSize = atoi(param.tilesize->answer);
  314. /*Do not use values */
  315. db.useUpperVal = 0;
  316. db.useLowerVal = 0;
  317. /*Use the input map value to fill the upper cells */
  318. if (param.fillup->answer) {
  319. db.useUpperVal = 1;
  320. }
  321. /*Use the input map value to fill the lower cells */
  322. if (param.filllow->answer) {
  323. db.useLowerVal = 1;
  324. }
  325. /*Set the upper value */
  326. if (param.upper->answer) {
  327. if (sscanf(param.upper->answer, "%lf", &db.upper))
  328. db.useUpperVal = 2;
  329. else
  330. G_fatal_error(_("The upper value is not valid"));
  331. } else {
  332. Rast3d_set_null_value(&db.upper, 1, DCELL_TYPE);
  333. }
  334. /*Set the lower value */
  335. if (param.lower->answer) {
  336. if (sscanf(param.lower->answer, "%lf", &db.lower))
  337. db.useLowerVal = 2;
  338. else
  339. G_fatal_error(_("The lower value is not valid"));
  340. } else {
  341. Rast3d_set_null_value(&db.lower, 1, DCELL_TYPE);
  342. }
  343. /* Figure out the current g3d region */
  344. Rast3d_init_defaults();
  345. Rast3d_get_window(&region);
  346. /*Check if the g3d-region is equal to the 2d rows and cols */
  347. rows = Rast_window_rows();
  348. cols = Rast_window_cols();
  349. G_debug(2, "Checking 2d and 3d region");
  350. /*If not equal, set the 2D windows correct */
  351. if (rows != region.rows || cols != region.cols) {
  352. G_message(_("The 2D and 3D region settings are different. I will use the 3D region settings to adjust the 2D region."));
  353. G_get_set_window(&window2d);
  354. window2d.ns_res = region.ns_res;
  355. window2d.ew_res = region.ew_res;
  356. window2d.rows = region.rows;
  357. window2d.cols = region.cols;
  358. Rast_set_window(&window2d);
  359. }
  360. G_debug(2, "Open 3d raster map %s", param.output->answer);
  361. /*open RASTER3D output map */
  362. db.map = NULL;
  363. db.map = Rast3d_open_new_opt_tile_size(param.output->answer, RASTER3D_USE_CACHE_XY, &region, DCELL_TYPE, maxSize);
  364. if (db.map == NULL)
  365. fatal_error(db, _("Error opening 3D raster map"));
  366. /*if requested set the Mask on */
  367. if (param.mask->answer) {
  368. if (Rast3d_mask_file_exists()) {
  369. changemask = 0;
  370. if (Rast3d_mask_is_off(db.map)) {
  371. Rast3d_mask_on(db.map);
  372. changemask = 1;
  373. }
  374. }
  375. }
  376. G_message(_("Creating 3D raster map"));
  377. /*For each elevation - input map couple */
  378. for (i = 0; i < db.mapnum; i++) {
  379. G_debug(2, "Open input raster map %s", param.input->answers[i]);
  380. db.count = i;
  381. /*Open input map */
  382. name = param.input->answers[i];
  383. db.input = open_input_raster_map(name);
  384. db.inputmaptype = Rast_map_type(name, "");
  385. G_debug(2, "Open elev raster map %s", param.elev->answers[i]);
  386. /*Open elev map */
  387. name = param.elev->answers[i];
  388. db.elev = open_input_raster_map(name);
  389. db.elevmaptype = Rast_map_type(name, "");
  390. /****************************************/
  391. /*Write the data into the RASTER3D Rastermap */
  392. elev_raster_to_g3d(db, region);
  393. /*****************************************/
  394. /* Close files */
  395. close_input_raster_map(db.input);
  396. close_input_raster_map(db.elev);
  397. }
  398. /*We set the Mask off, if it was off before */
  399. if (param.mask->answer) {
  400. if (Rast3d_mask_file_exists())
  401. if (Rast3d_mask_is_on(db.map) && changemask)
  402. Rast3d_mask_off(db.map);
  403. }
  404. G_debug(2, "Close 3d raster map");
  405. /* Flush all tile */
  406. if (!Rast3d_flush_all_tiles(db.map))
  407. Rast3d_fatal_error("Error flushing tiles with Rast3d_flush_all_tiles");
  408. if (!Rast3d_close(db.map))
  409. Rast3d_fatal_error(_("Error closing 3d raster map"));
  410. G_debug(2, "\nDone\n");
  411. return (EXIT_SUCCESS);
  412. }