main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /***************************************************************************
  2. *
  3. * MODULE: r.info
  4. *
  5. * AUTHOR(S): Michael O'Shea
  6. *
  7. * PURPOSE: Outputs basic information about a user-specified raster map layer.
  8. *
  9. * COPYRIGHT: (C) 2005-2011 by the GRASS Development Team
  10. *
  11. * This program is free software under the GNU General Public
  12. * License (>=v2). Read the file COPYING that comes with GRASS
  13. * for details.
  14. *
  15. *****************************************************************************/
  16. #include <grass/config.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <stdarg.h>
  20. #include <grass/gis.h>
  21. #include <grass/raster.h>
  22. #include <grass/glocale.h>
  23. #include "local_proto.h"
  24. #define printline(x) fprintf (out," | %-74.74s |\n",x)
  25. #define divider(x) \
  26. fprintf (out," %c",x);\
  27. for (i = 0; i < 76; i++)\
  28. fprintf(out,"-");\
  29. fprintf (out,"%c\n",x)
  30. /* local prototypes */
  31. static void format_double(const double, char *);
  32. static void compose_line(FILE *, const char *, ...);
  33. int main(int argc, char **argv)
  34. {
  35. const char *name, *mapset;
  36. char tmp1[100], tmp2[100], tmp3[100];
  37. char timebuff[256];
  38. char *units, *vdatum;
  39. int i;
  40. CELL mincat = 0, maxcat = 0, cat;
  41. double zmin, zmax; /* min and max data values */
  42. FILE *out;
  43. struct Range crange;
  44. struct FPRange range;
  45. struct Cell_head cellhd;
  46. struct Categories cats;
  47. struct History hist;
  48. struct TimeStamp ts;
  49. int time_ok = 0, first_time_ok = 0, second_time_ok = 0;
  50. int cats_ok, hist_ok;
  51. int is_reclass;
  52. RASTER_MAP_TYPE data_type;
  53. struct Reclass reclass;
  54. struct GModule *module;
  55. struct Option *opt1;
  56. struct Flag *gflag, *rflag, *eflag, *hflag;
  57. /* Initialize GIS Engine */
  58. G_gisinit(argv[0]);
  59. module = G_define_module();
  60. G_add_keyword(_("raster"));
  61. G_add_keyword(_("metadata"));
  62. G_add_keyword(_("extent"));
  63. G_add_keyword(_("history"));
  64. module->description =
  65. _("Outputs basic information about a raster map.");
  66. opt1 = G_define_standard_option(G_OPT_R_MAP);
  67. gflag = G_define_flag();
  68. gflag->key = 'g';
  69. gflag->description = _("Print raster array information only");
  70. rflag = G_define_flag();
  71. rflag->key = 'r';
  72. rflag->description = _("Print range only");
  73. eflag = G_define_flag();
  74. eflag->key = 'e';
  75. eflag->description = _("Print extended metadata information only");
  76. hflag = G_define_flag();
  77. hflag->key = 'h';
  78. hflag->description = _("Print raster history instead of info");
  79. if (G_parser(argc, argv))
  80. exit(EXIT_FAILURE);
  81. name = G_store(opt1->answer);
  82. if ((mapset = G_find_raster2(name, "")) == NULL)
  83. G_fatal_error(_("Raster map <%s> not found"), name);
  84. Rast_get_cellhd(name, "", &cellhd);
  85. cats_ok = Rast_read_cats(name, "", &cats) >= 0;
  86. hist_ok = Rast_read_history(name, "", &hist) >= 0;
  87. is_reclass = Rast_get_reclass(name, "", &reclass);
  88. data_type = Rast_map_type(name, "");
  89. units = Rast_read_units(name, "");
  90. vdatum = Rast_read_vdatum(name, "");
  91. /*Check the Timestamp */
  92. time_ok = G_read_raster_timestamp(name, "", &ts) > 0;
  93. /*Check for valid entries, show none if no timestamp available */
  94. if (time_ok) {
  95. if (ts.count > 0)
  96. first_time_ok = 1;
  97. if (ts.count > 1)
  98. second_time_ok = 1;
  99. }
  100. if (Rast_read_fp_range(name, "", &range) < 0)
  101. G_fatal_error(_("Unable to read range file"));
  102. Rast_get_fp_range_min_max(&range, &zmin, &zmax);
  103. out = stdout;
  104. if (!gflag->answer && !rflag->answer &&
  105. !eflag->answer && !hflag->answer) {
  106. divider('+');
  107. compose_line(out, "Layer: %-29.29s Date: %s", name,
  108. hist_ok ? Rast_get_history(&hist, HIST_MAPID) : "??");
  109. compose_line(out, "Mapset: %-29.29s Login of Creator: %s",
  110. mapset, hist_ok ? Rast_get_history(&hist, HIST_CREATOR) : "??");
  111. compose_line(out, "Location: %s", G_location());
  112. compose_line(out, "DataBase: %s", G_gisdbase());
  113. compose_line(out, "Title: %s ( %s )",
  114. cats_ok ? cats.title : "??",
  115. hist_ok ? Rast_get_history(&hist, HIST_TITLE) : "??");
  116. /*This shows the TimeStamp */
  117. if (time_ok && (first_time_ok || second_time_ok)) {
  118. G_format_timestamp(&ts, timebuff);
  119. compose_line(out, "Timestamp: %s", timebuff);
  120. }
  121. else {
  122. compose_line(out, "Timestamp: none");
  123. }
  124. divider('|');
  125. printline("");
  126. if (cats_ok)
  127. format_double((double)cats.num, tmp1);
  128. compose_line(out,
  129. " Type of Map: %-20.20s Number of Categories: %-9s",
  130. hist_ok ? Rast_get_history(&hist, HIST_MAPTYPE) : "??", cats_ok ? tmp1 : "??");
  131. compose_line(out, " Data Type: %s",
  132. (data_type == CELL_TYPE ? "CELL" :
  133. (data_type == DCELL_TYPE ? "DCELL" :
  134. (data_type == FCELL_TYPE ? "FCELL" : "??"))));
  135. /* For now hide these unless they exist to keep the noise low. In
  136. * future when the two are used more widely they can be printed
  137. * along with the standard set. */
  138. if (units || vdatum)
  139. compose_line(out, " Data Units: %-20.20s Vertical datum: %s",
  140. units ? units : "(none)", vdatum ? vdatum : "(none)");
  141. {
  142. compose_line(out, " Rows: %d", cellhd.rows);
  143. compose_line(out, " Columns: %d", cellhd.cols);
  144. #ifdef HAVE_LONG_LONG_INT
  145. compose_line(out, " Total Cells: %llu",
  146. (unsigned long long)cellhd.rows * cellhd.cols);
  147. #else
  148. compose_line(out,
  149. " Total Cells: %lu (accuracy - see r.info manual)",
  150. (unsigned long)cellhd.rows * cellhd.cols);
  151. #endif
  152. /* This is printed as a guide to what the following eastings and
  153. * northings are printed in. This data is NOT from the values
  154. * stored in the map's Cell_head */
  155. if (G_projection() == PROJECTION_UTM) {
  156. compose_line(out, " Projection: %s (zone %d)",
  157. G_database_projection_name(), G_zone());
  158. }
  159. else {
  160. compose_line(out, " Projection: %s",
  161. G_database_projection_name());
  162. }
  163. G_format_northing(cellhd.north, tmp1, cellhd.proj);
  164. G_format_northing(cellhd.south, tmp2, cellhd.proj);
  165. G_format_resolution(cellhd.ns_res, tmp3, cellhd.proj);
  166. compose_line(out, " N: %10s S: %10s Res: %5s",
  167. tmp1, tmp2, tmp3);
  168. G_format_easting(cellhd.east, tmp1, cellhd.proj);
  169. G_format_easting(cellhd.west, tmp2, cellhd.proj);
  170. G_format_resolution(cellhd.ew_res, tmp3, cellhd.proj);
  171. compose_line(out, " E: %10s W: %10s Res: %5s",
  172. tmp1, tmp2, tmp3);
  173. if (data_type == CELL_TYPE) {
  174. if (2 == Rast_read_range(name, "", &crange))
  175. compose_line(out,
  176. " Range of data: min = NULL max = NULL");
  177. else
  178. compose_line(out,
  179. " Range of data: min = %i max = %i",
  180. (CELL) zmin, (CELL) zmax);
  181. }
  182. else if (data_type == FCELL_TYPE) {
  183. compose_line(out, " Range of data: min = %.7g max = %.7g",
  184. zmin, zmax);
  185. }
  186. else {
  187. compose_line(out, " Range of data: min = %.15g max = %.15g",
  188. zmin, zmax);
  189. }
  190. }
  191. printline("");
  192. if (hist_ok) {
  193. if (Rast_get_history(&hist, HIST_DATSRC_1)[0] != '\0' ||
  194. Rast_get_history(&hist, HIST_DATSRC_2)[0] != '\0') {
  195. printline(" Data Source:");
  196. compose_line(out, " %s", Rast_get_history(&hist, HIST_DATSRC_1));
  197. compose_line(out, " %s", Rast_get_history(&hist, HIST_DATSRC_2));
  198. printline("");
  199. }
  200. printline(" Data Description:");
  201. compose_line(out, " %s", Rast_get_history(&hist, HIST_KEYWRD));
  202. printline("");
  203. if (Rast_history_length(&hist)) {
  204. printline(" Comments: ");
  205. for (i = 0; i < Rast_history_length(&hist); i++)
  206. compose_line(out, " %s", Rast_history_line(&hist, i));
  207. }
  208. printline("");
  209. }
  210. if (is_reclass > 0) {
  211. int first = 1;
  212. divider('|');
  213. compose_line(out, " Reclassification of [%s] in mapset [%s]",
  214. reclass.name, reclass.mapset);
  215. printline("");
  216. printline(" Category Original categories");
  217. printline("");
  218. for (i = 0; i < reclass.num; i++) {
  219. CELL x = reclass.table[i];
  220. if (Rast_is_c_null_value(&x))
  221. continue;
  222. if (first || x < mincat)
  223. mincat = x;
  224. if (first || x > maxcat)
  225. maxcat = x;
  226. first = 0;
  227. }
  228. if (!first)
  229. for (cat = mincat; cat <= maxcat; cat++) {
  230. char text[80];
  231. char *num;
  232. int next;
  233. if (cat == 0)
  234. continue;
  235. if (G_asprintf(&num, "%5ld", (long)cat) < 1)
  236. G_fatal_error(_("Cannot allocate memory for string"));
  237. next = 0;
  238. do {
  239. next = reclass_text(text, cat, &reclass, next);
  240. compose_line(out, " %5s %s", num,
  241. text);
  242. *num = 0;
  243. }
  244. while (next >= 0);
  245. }
  246. }
  247. divider('+');
  248. fprintf(out, "\n");
  249. }
  250. else { /* g,r,e, or h flags */
  251. if (gflag->answer) {
  252. G_format_northing(cellhd.north, tmp1, -1);
  253. G_format_northing(cellhd.south, tmp2, -1);
  254. fprintf(out, "north=%s\n", tmp1);
  255. fprintf(out, "south=%s\n", tmp2);
  256. G_format_easting(cellhd.east, tmp1, -1);
  257. G_format_easting(cellhd.west, tmp2, -1);
  258. fprintf(out, "east=%s\n", tmp1);
  259. fprintf(out, "west=%s\n", tmp2);
  260. G_format_resolution(cellhd.ns_res, tmp3, -1);
  261. fprintf(out, "nsres=%s\n", tmp3);
  262. G_format_resolution(cellhd.ew_res, tmp3, -1);
  263. fprintf(out, "ewres=%s\n", tmp3);
  264. fprintf(out, "rows=%d\n", cellhd.rows);
  265. fprintf(out, "cols=%d\n", cellhd.cols);
  266. fprintf(out, "cells=%lld\n",
  267. (long long)cellhd.rows * cellhd.cols);
  268. fprintf(out, "datatype=%s\n",
  269. (data_type == CELL_TYPE ? "CELL" :
  270. (data_type == DCELL_TYPE ? "DCELL" :
  271. (data_type == FCELL_TYPE ? "FCELL" : "??"))));
  272. }
  273. if (rflag->answer) {
  274. if (data_type == CELL_TYPE) {
  275. if (2 == Rast_read_range(name, "", &crange)) {
  276. fprintf(out, "min=NULL\n");
  277. fprintf(out, "max=NULL\n");
  278. }
  279. else {
  280. fprintf(out, "min=%i\n", (CELL) zmin);
  281. fprintf(out, "max=%i\n", (CELL) zmax);
  282. }
  283. }
  284. else if (data_type == FCELL_TYPE) {
  285. fprintf(out, "min=%.7g\n", zmin);
  286. fprintf(out, "max=%.7g\n", zmax);
  287. }
  288. else {
  289. fprintf(out, "min=%.15g\n", zmin);
  290. fprintf(out, "max=%.15g\n", zmax);
  291. }
  292. }
  293. if (eflag->answer) {
  294. fprintf(out, "title=%s (%s)\n", cats_ok ? cats.title :
  295. "??", hist_ok ? Rast_get_history(&hist, HIST_TITLE) : "??");
  296. fprintf(out, "units=%s\n", units ? units : "\"none\"");
  297. fprintf(out, "vertical_datum=%s\n", vdatum ? vdatum : "\"none\"");
  298. if (time_ok && (first_time_ok || second_time_ok)) {
  299. G_format_timestamp(&ts, timebuff);
  300. /*Create the r.info timestamp string */
  301. fprintf(out, "timestamp=\"%s\"\n", timebuff);
  302. }
  303. else {
  304. fprintf(out, "timestamp=\"none\"\n");
  305. }
  306. }
  307. if (hflag->answer) {
  308. if (hist_ok) {
  309. fprintf(out, "Data Source:\n");
  310. fprintf(out, " %s\n", Rast_get_history(&hist, HIST_DATSRC_1));
  311. fprintf(out, " %s\n", Rast_get_history(&hist, HIST_DATSRC_2));
  312. fprintf(out, "Data Description:\n");
  313. fprintf(out, " %s\n", Rast_get_history(&hist, HIST_KEYWRD));
  314. if (Rast_history_length(&hist)) {
  315. fprintf(out, "Comments:\n");
  316. for (i = 0; i < Rast_history_length(&hist); i++)
  317. fprintf(out, " %s\n", Rast_history_line(&hist, i));
  318. }
  319. }
  320. }
  321. } /* else rflag or sflag or tflag or gflag or hflag or mflag */
  322. return EXIT_SUCCESS;
  323. }
  324. static void format_double(const double value, char *buf)
  325. {
  326. sprintf(buf, "%.8lf", value);
  327. G_trim_decimal(buf);
  328. }
  329. static void compose_line(FILE * out, const char *fmt, ...)
  330. {
  331. char *line = NULL;
  332. va_list ap;
  333. va_start(ap, fmt);
  334. if (G_vasprintf(&line, fmt, ap) <= 0)
  335. G_fatal_error(_("Cannot allocate memory for string"));
  336. va_end(ap);
  337. printline(line);
  338. G_free(line);
  339. }