main.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /****************************************************************************
  2. *
  3. * MODULE: r.out.pov
  4. * AUTHOR(S): Klaus D. Meyer, <GEUM.tec geum.de> (original contributor)
  5. * Markus Neteler <neteler itc.it>,
  6. * Roberto Flor <flor itc.it>,
  7. * Bernhard Reiter <bernhard intevation.de>,
  8. * Glynn Clements <glynn gclements.plus.com>,
  9. * Hamish Bowman <hamish_b yahoo.com>,
  10. * Jan-Oliver Wagner <jan intevation.de>
  11. * PURPOSE: converts a user-specified raster map layer into a
  12. * height-field file for POVray
  13. * COPYRIGHT: (C) 2000-2007 by the GRASS Development Team
  14. *
  15. * This program is free software under the GNU General Public
  16. * License (>=v2). Read the file COPYING that comes with GRASS
  17. * for details.
  18. *
  19. *****************************************************************************/
  20. /*
  21. Persistence of Vision (POV) raytracer can use a height-field
  22. defined in a Targa (.TGA) image file format where the RGB pixel
  23. values are 24 bits (3 bytes). A 16 bit unsigned integer height-field
  24. value is assigned as follows:
  25. RED high byte
  26. GREEN low byte
  27. BLUE empty
  28. This code is based on code by W.D. Kirby who wrote DEM2XYZ in 1996.
  29. Author: Klaus Meyer, GEUM.tec GbR, eMail: GEUM.tec@geum.de
  30. Date: July 1998
  31. */
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <math.h>
  36. #include <grass/gis.h>
  37. #include <grass/raster.h>
  38. #include <grass/glocale.h>
  39. void writeHeader(FILE * outf);
  40. void processProfiles(int inputFile, FILE * outputF);
  41. #define YMAX 65536 /* max length scan line */
  42. #define XMAX 65536 /* max # of scan lines */
  43. #define MIN(x,y) (((x) < (y)) ? (x) : (y))
  44. #define MAX(x,y) (((x) > (y)) ? (x) : (y))
  45. #define SW 0
  46. #define NW 1
  47. #define NE 2
  48. #define SE 3
  49. int base[XMAX]; /* array of base elevations */
  50. double defaultElev = 0; /* elevation for empty points */
  51. int width, height; /* height-field image width and height */
  52. int hfType = 0; /* height-field type */
  53. double hfBias, hfNorm = 1.0;
  54. double verticalScale = 1.0; /* to stretch or shrink elevations */
  55. double minValue = 50000., maxValue = -50000.;
  56. char mapLabel[145];
  57. int DEMlevel, elevationPattern, groundSystem, groundZone;
  58. double projectParams[15];
  59. int planeUnitOfMeasure, elevUnitOfMeasure, polygonSizes;
  60. double groundCoords[4][2], elevBounds[2], localRotation;
  61. int accuracyCode;
  62. double spatialResolution[3];
  63. int profileDimension[2];
  64. int firstRow, lastRow;
  65. int wcount = 0, hcount;
  66. double deltaY;
  67. char inText[24], **junk;
  68. double eastMost, westMost, southMost, northMost;
  69. int eastMostSample, westMostSample, southMostSample, northMostSample;
  70. int rowCount, columnCount, r, c;
  71. long int cellCount = 0;
  72. int rowStr, rowEnd, colStr, colEnd;
  73. int main(int argc, char *argv[])
  74. {
  75. struct Cell_head region;
  76. struct Range range;
  77. CELL range_min, range_max;
  78. FILE *outf;
  79. char *outfilename;
  80. CELL *cell;
  81. char *name;
  82. int fd;
  83. int nrows, ncols;
  84. double bias;
  85. struct GModule *module;
  86. struct
  87. {
  88. struct Option *map;
  89. struct Option *tga;
  90. struct Option *hftype;
  91. struct Option *bias;
  92. struct Option *scaleFactor;
  93. } parm;
  94. G_gisinit(argv[0]);
  95. module = G_define_module();
  96. G_add_keyword(_("raster"));
  97. G_add_keyword(_("export"));
  98. module->description =
  99. _("Converts a raster map layer into a height-field file for POV-Ray.");
  100. /* Define the different options */
  101. parm.map = G_define_standard_option(G_OPT_R_INPUT);
  102. parm.tga = G_define_standard_option(G_OPT_F_OUTPUT);
  103. parm.tga->description =
  104. _("Name of output povray file (TGA height field file)");
  105. parm.hftype = G_define_option();
  106. parm.hftype->key = "hftype";
  107. parm.hftype->type = TYPE_INTEGER;
  108. parm.hftype->required = NO;
  109. parm.hftype->description =
  110. _("Height-field type (0=actual heights 1=normalized)");
  111. parm.bias = G_define_option();
  112. parm.bias->key = "bias";
  113. parm.bias->type = TYPE_DOUBLE;
  114. parm.bias->required = NO;
  115. parm.bias->description = _("Elevation bias");
  116. parm.scaleFactor = G_define_option();
  117. parm.scaleFactor->key = "scale";
  118. parm.scaleFactor->type = TYPE_DOUBLE;
  119. parm.scaleFactor->required = NO;
  120. parm.scaleFactor->description = _("Vertical scaling factor");
  121. if (G_parser(argc, argv))
  122. exit(EXIT_FAILURE);
  123. if (parm.hftype->answer != NULL)
  124. sscanf(parm.hftype->answer, "%d", &hfType);
  125. if (parm.bias->answer != NULL)
  126. sscanf(parm.bias->answer, "%lf", &bias);
  127. if (parm.scaleFactor->answer != NULL)
  128. sscanf(parm.scaleFactor->answer, "%lf", &verticalScale);
  129. name = parm.map->answer;
  130. fd = Rast_open_old(name, "");
  131. outfilename = parm.tga->answer;
  132. if (outfilename == NULL)
  133. G_fatal_error(_("Invalid output filename <%s>"), outfilename);
  134. if (NULL == (outf = fopen(outfilename, "wb")))
  135. G_fatal_error(_("Unable to open output file <%s>"), outfilename);
  136. cell = Rast_allocate_c_buf();
  137. nrows = Rast_window_rows();
  138. ncols = Rast_window_cols();
  139. if (nrows > YMAX || ncols > XMAX)
  140. G_fatal_error(_("Raster map is too big! Exceeds %d columns or %d rows"),
  141. XMAX, YMAX);
  142. columnCount = ncols;
  143. rowCount = nrows;
  144. width = ncols;
  145. height = nrows;
  146. /* SW, NW, NE, SE corners */
  147. G_get_window(&region);
  148. eastMost = region.east;
  149. westMost = region.west;
  150. northMost = region.north;
  151. southMost = region.south;
  152. Rast_init_range(&range);
  153. Rast_read_range(name, "", &range);
  154. Rast_get_range_min_max(&range, &range_min, &range_max);
  155. if (range.min < 0 || range.max < 0)
  156. G_warning(_("Negative elevation values in input"));
  157. elevBounds[0] = range.min;
  158. elevBounds[1] = range.max;
  159. /* Normalize using max value of unsigned short integer (16 bit) */
  160. if (hfType == 1)
  161. hfNorm = 65535.0 / (elevBounds[1] + hfBias);
  162. spatialResolution[0] = region.ew_res;
  163. spatialResolution[1] = region.ew_res;
  164. spatialResolution[2] = region.ns_res;
  165. /* write TGA image file header */
  166. (void)writeHeader(outf);
  167. /* have to read everything */
  168. (void)processProfiles(fd, outf);
  169. fclose(outf);
  170. Rast_close(fd);
  171. exit(EXIT_SUCCESS);
  172. }
  173. void writeHeader(FILE * outputF)
  174. {
  175. int i;
  176. /* Write TGA image header */
  177. for (i = 0; i < 10; i++) /* 00, 00, 02, then 7 00's... */
  178. if (i == 2)
  179. putc((short)i, outputF);
  180. else
  181. putc(0, outputF);
  182. putc(0, outputF); /* y origin set to "First_Line" */
  183. putc(0, outputF);
  184. putc((short)(width % 256), outputF); /* write width and height */
  185. putc((short)(width / 256), outputF);
  186. putc((short)(height % 256), outputF);
  187. putc((short)(height / 256), outputF);
  188. putc(24, outputF); /* 24 bits/pixel (16 million colors!) */
  189. putc(32, outputF); /* Bitmask, pertinent bit: top-down raster */
  190. }
  191. /*
  192. * read profiles
  193. */
  194. void processProfiles(int inputFile, FILE * outputF)
  195. {
  196. CELL *cell;
  197. int c, r;
  198. double tempFloat;
  199. cell = Rast_allocate_c_buf();
  200. for (r = 0; r < rowCount; r++) {
  201. Rast_get_c_row(inputFile, cell, r);
  202. /* break; */
  203. for (c = 0; c < columnCount; c++) {
  204. tempFloat = ((float)cell[c] * verticalScale) + hfBias;
  205. /* Normalize */
  206. tempFloat *= hfNorm;
  207. if (tempFloat < 0.0)
  208. tempFloat = 0.0;
  209. if (tempFloat > 65535.0)
  210. tempFloat = 65535.0;
  211. if (tempFloat > maxValue)
  212. maxValue = tempFloat;
  213. if (tempFloat < minValue)
  214. minValue = tempFloat;
  215. /* write pixel */
  216. putc((char)0, outputF); /* Blue empty */
  217. putc((char)((int)tempFloat % 256), outputF); /* Green low byte */
  218. putc((char)((int)tempFloat / 256), outputF); /* Red high byte */
  219. }
  220. G_percent(r, rowCount, 2);
  221. }
  222. G_percent(r, rowCount, 2); /* 100% \n */
  223. }