main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. /* r.in.mat
  2. *
  3. * Input a GRASS raster file from a MAT-File (version 4).
  4. *
  5. * Copyright (C) 2004 by the GRASS Development Team
  6. * Author: Hamish Bowman, University of Otago, New Zealand
  7. *
  8. * This program is free software under the GPL (>=v2)
  9. * Read the COPYING file that comes with GRASS for details.
  10. *
  11. * Code follows r.out.mat, which follows r.out.bin to a certain
  12. * extent, which in turn follows r.out.ascii, which is really old.
  13. *
  14. *
  15. * ARRAY MUST CONTAIN THE FOLLOWING MATRIX :
  16. * map_data with the map data
  17. *
  18. * AND OPTIONALLY :
  19. * map_name name for new map (max 64 chars, normal rules apply)
  20. * map_title contains map title
  21. *
  22. * THESE MUST BE PRESENT UNLESS USING THE "XY" PROJECTION :
  23. * map_northern_edge
  24. * map_southern_edge in decimal form (ie not DDD:MM:SS)
  25. * map_eastern_edge
  26. * map_western_edge
  27. *
  28. * ALL OTHER MATRICES WILL BE PASSED OVER. (cleanly, I hope)
  29. *
  30. * tip: Save a version 4 MAT-File with the command "save filename.mat map_* -v4"
  31. */
  32. /* #define DEBUG */
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <grass/gis.h>
  37. #include <grass/raster.h>
  38. #include <grass/glocale.h>
  39. /* typedef unsigned short uint16;
  40. typedef unsigned int uint32; */
  41. /* is_nan(): fn to test if incoming data point is either a IEEE NaN or a GRASS CELL null */
  42. int is_nan(void *, RASTER_MAP_TYPE);
  43. int main(int argc, char *argv[])
  44. {
  45. int i, row, col; /* counters */
  46. int machine_endianness, file_endianness, endian_mismatch; /* 0=little, 1=big */
  47. int data_format; /* 0=double 1=float 2=32bit signed int 5=8bit unsigned int (ie text) */
  48. int data_type; /* 0=numbers 1=text */
  49. int format_block; /* combo of endianness, 0, data_format, and type */
  50. int realflag = 0; /* 0=only real values used */
  51. /* should type be specifically uint32 ??? */
  52. char array_name[65]; /* 65 = 64 + null-terminator */
  53. int name_len;
  54. int mrows, ncols; /* text/data/map array dimensions */
  55. int *pval_i; /* for misc use */
  56. float *pval_f; /* for misc use */
  57. double *pval_d; /* for misc use */
  58. char c; /* for misc use */
  59. char map_name[65], map_title[1024]; /* 65 = 64 + null-terminator */
  60. double map_name_d[1024]; /* I'm not sure why you'd save char strings as double, but whatever */
  61. int have_name, have_data, have_title, have_n, have_s, have_e, have_w;
  62. char *infile, *outfile;
  63. struct Cell_head region;
  64. void *raster, *rastline_ptr, *array_data, *array_ptr;
  65. RASTER_MAP_TYPE map_type;
  66. struct History history;
  67. struct Option *inputfile, *outputfile;
  68. struct GModule *module;
  69. int cf;
  70. FILE *fp1;
  71. G_gisinit(argv[0]);
  72. module = G_define_module();
  73. G_add_keyword(_("raster"));
  74. G_add_keyword(_("import"));
  75. module->description =
  76. _("Imports a binary MAT-File(v4) to a GRASS raster.");
  77. /* Define the different options */
  78. inputfile = G_define_standard_option(G_OPT_F_INPUT);
  79. inputfile->required = YES;
  80. inputfile->gisprompt = "old,mat,file";
  81. inputfile->description = _("Name of input MAT-File(v4)");
  82. outputfile = G_define_standard_option(G_OPT_R_OUTPUT);
  83. outputfile->required = NO;
  84. outputfile->description = _("Name for output raster map (override)");
  85. if (G_parser(argc, argv))
  86. exit(EXIT_FAILURE);
  87. /****** SETUP ****************************************************/
  88. /* Check Endian State of Host Computer */
  89. if (G_is_little_endian())
  90. machine_endianness = 0; /* ie little endian */
  91. else
  92. machine_endianness = 1; /* ie big endian */
  93. G_debug(1, "Machine is %s endian.",
  94. machine_endianness ? "big" : "little");
  95. infile = inputfile->answer;
  96. outfile = outputfile->answer;
  97. /* open bin file for reading */
  98. fp1 = fopen(infile, "rb");
  99. if (NULL == fp1)
  100. G_fatal_error(_("Unable to open input file <%s>"), infile);
  101. have_name = have_data = have_title = 0;
  102. have_n = have_s = have_e = have_w = 0;
  103. /* Check Endian State of File */
  104. fread(&format_block, sizeof(int), 1, fp1);
  105. G_fseek(fp1, 0, SEEK_SET); /* frewind() */
  106. file_endianness = format_block / 1000; /* 0=little, 1=big */
  107. if (file_endianness != machine_endianness)
  108. endian_mismatch = 1;
  109. else
  110. endian_mismatch = 0;
  111. G_debug(1, "File is %s endian.\n", file_endianness ? "big" : "little");
  112. if (format_block > 51)
  113. G_warning
  114. ("Only little endian MAT-File(v4) binaries have been tested so far! Probably won't work.");
  115. /****** READ MAP ****************************************************/
  116. G_verbose_message(_("Reading MAT-File..."));
  117. while (!feof(fp1)) {
  118. /* scan for needed array variables */
  119. fread(&format_block, sizeof(int), 1, fp1);
  120. if (feof(fp1))
  121. break;
  122. /* 4 byte data format block = endianness*1000 + data_format*10 + data_type */
  123. /* 0=double 1=float 2=32bit signed int 5=8bit unsigned int(text) */
  124. data_format = format_block / 10;
  125. if (data_format != 0 && data_format != 1 &&
  126. data_format != 2 && data_format != 5)
  127. G_fatal_error("format [%d]", data_format);
  128. data_type = format_block - data_format * 10; /* 0=numbers 1=text */
  129. if (data_type != 0 && data_type != 1)
  130. G_fatal_error("type [%d]", data_type);
  131. /* 4 byte number of rows & columns */
  132. fread(&mrows, sizeof(int), 1, fp1);
  133. fread(&ncols, sizeof(int), 1, fp1);
  134. if (mrows < 1 || ncols < 1)
  135. G_fatal_error(_("Array contains no data"));
  136. /* 4 byte real/imag flag 0=real vals only */
  137. fread(&realflag, sizeof(int), 1, fp1);
  138. if (realflag != 0)
  139. G_fatal_error(_("Array contains imaginary data"));
  140. /* length of array_name+1 */
  141. fread(&name_len, sizeof(int), 1, fp1);
  142. if (name_len < 1)
  143. G_fatal_error(_("Invalid array name"));
  144. /* array name */
  145. for (i = 0; i < 64; i++) {
  146. fread(&c, sizeof(char), 1, fp1);
  147. array_name[i] = c;
  148. if (c == '\0')
  149. break;
  150. }
  151. G_debug(3, "array name = [%s]", array_name);
  152. G_debug(3, " format block = [%04d]", format_block);
  153. G_debug(3, " data format = [%d]", data_format);
  154. G_debug(3, " data type = [%d]", data_type);
  155. G_debug(3, " rows = [%d]", mrows);
  156. G_debug(3, " cols = [%d]", ncols);
  157. if (strcmp(array_name, "map_name") == 0) {
  158. have_name = 1;
  159. if (mrows != 1 || ncols > 64 || data_type != 1)
  160. G_fatal_error(_("Invalid 'map_name' array"));
  161. if (data_format == 5)
  162. fread(&map_name, sizeof(char), ncols, fp1);
  163. else if (data_format == 0) { /* sigh.. */
  164. fread(&map_name_d, sizeof(double), ncols, fp1);
  165. for (i = 0; i < ncols; i++)
  166. map_name[i] = (char)map_name_d[i];
  167. }
  168. else
  169. G_fatal_error(_("Error reading 'map_name' array"));
  170. map_name[ncols] = '\0';
  171. G_strip(map_name); /* remove leading and trailing whitespace */
  172. G_debug(1, "map name= <%s>", map_name);
  173. }
  174. else if (strcmp(array_name, "map_northern_edge") == 0) {
  175. have_n = 1;
  176. if (mrows != 1 || ncols != 1 || data_format != 0 ||
  177. data_type != 0)
  178. G_fatal_error(_("Invalid 'map_northern_edge' array"));
  179. fread(&region.north, sizeof(double), 1, fp1);
  180. G_debug(1, "northern edge=%f", region.north);
  181. }
  182. else if (strcmp(array_name, "map_southern_edge") == 0) {
  183. have_s = 1;
  184. if (mrows != 1 || ncols != 1 || data_format != 0 ||
  185. data_type != 0)
  186. G_fatal_error(_("Invalid 'map_southern_edge' array"));
  187. fread(&region.south, sizeof(double), 1, fp1);
  188. G_debug(1, "southern edge=%f", region.south);
  189. }
  190. else if (strcmp(array_name, "map_eastern_edge") == 0) {
  191. have_e = 1;
  192. if (mrows != 1 || ncols != 1 || data_format != 0 ||
  193. data_type != 0)
  194. G_fatal_error(_("Invalid 'map_eastern_edge' array"));
  195. fread(&region.east, sizeof(double), 1, fp1);
  196. G_debug(1, "eastern edge=%f", region.east);
  197. }
  198. else if (strcmp(array_name, "map_western_edge") == 0) {
  199. have_w = 1;
  200. if (mrows != 1 || ncols != 1 || data_format != 0 ||
  201. data_type != 0)
  202. G_fatal_error(_("Invalid 'map_western_edge' array"));
  203. fread(&region.west, sizeof(double), 1, fp1);
  204. G_debug(1, "western edge=%f", region.west);
  205. }
  206. else if (strcmp(array_name, "map_title") == 0) {
  207. have_title = 1;
  208. if (mrows != 1 || ncols > 1023 || data_type != 1)
  209. G_fatal_error(_("Invalid 'map_title' array"));
  210. if (data_format == 5)
  211. fread(&map_title, sizeof(char), ncols, fp1);
  212. else if (data_format == 0) { /* sigh.. */
  213. fread(&map_name_d, sizeof(double), ncols, fp1); /* note reusing variable */
  214. for (i = 0; i < ncols; i++)
  215. map_title[i] = (char)map_name_d[i];
  216. }
  217. else
  218. G_fatal_error(_("Error reading 'map_title' array"));
  219. map_title[ncols] = '\0';
  220. G_strip(map_title); /* remove leading and trailing whitespace */
  221. G_debug(1, "map title= [%s]", map_title);
  222. }
  223. else if (strcmp(array_name, "map_data") == 0) {
  224. have_data = 1;
  225. region.rows = (int)mrows;
  226. region.cols = (int)ncols;
  227. if (mrows < 1 || ncols < 1 || data_format > 2 || data_type != 0)
  228. G_fatal_error(_("Invalid 'map_data' array"));
  229. switch (data_format) {
  230. /* 0=double 1=float 2=32bit signed int 5=8bit unsigned int(text) */
  231. case 0:
  232. G_debug(1, " double map");
  233. map_type = DCELL_TYPE;
  234. array_data =
  235. G_calloc(mrows * (ncols + 1), Rast_cell_size(map_type));
  236. fread(array_data, sizeof(double), mrows * ncols, fp1);
  237. break;
  238. case 1:
  239. G_debug(1, " float map");
  240. map_type = FCELL_TYPE;
  241. array_data =
  242. G_calloc(mrows * (ncols + 1), Rast_cell_size(map_type));
  243. fread(array_data, sizeof(float), mrows * ncols, fp1);
  244. break;
  245. case 2:
  246. G_debug(1, " int map");
  247. map_type = CELL_TYPE;
  248. array_data =
  249. G_calloc(mrows * (ncols + 1), Rast_cell_size(map_type));
  250. fread(array_data, sizeof(int), mrows * ncols, fp1);
  251. break;
  252. default:
  253. G_fatal_error(_("Please contact the GRASS development team"));
  254. }
  255. } /* endif map_data */
  256. else {
  257. G_important_message(_("Skipping unknown array '%s'"), array_name);
  258. switch (data_format) {
  259. /* 0=double 1=float 2=32bit signed int 5=8bit unsigned int(text) */
  260. case 0:
  261. G_fseek(fp1, mrows * ncols * sizeof(double), SEEK_CUR);
  262. break;
  263. case 1:
  264. G_fseek(fp1, mrows * ncols * sizeof(float), SEEK_CUR);
  265. break;
  266. case 2:
  267. G_fseek(fp1, mrows * ncols * sizeof(int), SEEK_CUR);
  268. break;
  269. case 5:
  270. G_fseek(fp1, mrows * ncols * sizeof(char), SEEK_CUR);
  271. break;
  272. default:
  273. G_fatal_error("unusual array");
  274. }
  275. }
  276. G_debug(3, "Read array '%s' [%d,%d] format=%d type=%d\n",
  277. array_name, ncols, mrows, data_format, data_type);
  278. } /* while !EOF */
  279. /****** WRITE MAP ****************************************************/
  280. if (0 == have_data)
  281. G_fatal_error(_("No 'map_data' array found in <%s>"), infile);
  282. /* set map name */
  283. if (have_name) {
  284. if (outfile) {
  285. if (0 != strcmp(outfile, map_name))
  286. G_message(_("Setting map name to <%s> which overrides <%s>"),
  287. outfile, map_name);
  288. strncpy(map_name, outfile, 61);
  289. }
  290. }
  291. else {
  292. if (outfile) {
  293. G_verbose_message(_("Setting map name to <%s>"), outfile);
  294. strncpy(map_name, outfile, 61);
  295. }
  296. else {
  297. G_message(_("No 'map_name' array found; using <MatFile>"));
  298. strcpy(map_name, "MatFile");
  299. }
  300. }
  301. G_strip(map_name); /* remove leading and trailing whitespace */
  302. /* set region info */
  303. if (G_projection() != PROJECTION_XY) {
  304. if ((0 == have_n) || (0 == have_s) || (0 == have_e) || (0 == have_w))
  305. G_fatal_error(_("Missing bound"));
  306. }
  307. else {
  308. if ((0 == have_n) || (0 == have_s) || (0 == have_e) || (0 == have_w)) {
  309. G_warning(_("Using default bounds"));
  310. region.north = (double)region.rows;
  311. region.south = 0.;
  312. region.east = (double)region.cols;
  313. region.west = 0.;
  314. }
  315. }
  316. region.proj = G_projection();
  317. region.zone = G_zone();
  318. G_adjust_Cell_head(&region, 1, 1);
  319. Rast_set_window(&region);
  320. G_verbose_message("");
  321. G_verbose_message(_("Map <%s> bounds set to:"), map_name);
  322. G_verbose_message(_("northern edge=%f"), region.north);
  323. G_verbose_message(_("southern edge=%f"), region.south);
  324. G_verbose_message(_("eastern edge=%f"), region.east);
  325. G_verbose_message(_("western edge=%f"), region.west);
  326. G_verbose_message(_("nsres=%f"), region.ns_res);
  327. G_verbose_message(_("ewres=%f"), region.ew_res);
  328. G_verbose_message(_("rows=%d"), region.rows);
  329. G_verbose_message(_("cols=%d"), region.cols);
  330. G_verbose_message("");
  331. /* prep memory */
  332. raster = Rast_allocate_buf(map_type);
  333. cf = Rast_open_new(map_name, map_type);
  334. /* write new raster map */
  335. G_verbose_message(_("Writing new raster map..."));
  336. mrows = region.rows;
  337. ncols = region.cols;
  338. for (row = 0; row < mrows; row++) {
  339. rastline_ptr = raster;
  340. for (col = 0; col < ncols; col++) {
  341. array_ptr = array_data;
  342. array_ptr =
  343. G_incr_void_ptr(array_ptr,
  344. (row +
  345. col * mrows) * Rast_cell_size(map_type));
  346. if (is_nan(array_ptr, map_type))
  347. Rast_set_null_value(rastline_ptr, 1, map_type);
  348. else {
  349. switch (map_type) {
  350. case CELL_TYPE:
  351. pval_i = (int *)array_ptr;
  352. Rast_set_c_value(rastline_ptr, (CELL) pval_i[0],
  353. map_type);
  354. break;
  355. case FCELL_TYPE:
  356. pval_f = (float *)array_ptr;
  357. Rast_set_f_value(rastline_ptr, (FCELL) pval_f[0],
  358. map_type);
  359. break;
  360. case DCELL_TYPE:
  361. pval_d = (double *)array_ptr;
  362. Rast_set_d_value(rastline_ptr, (DCELL) pval_d[0],
  363. map_type);
  364. break;
  365. default:
  366. Rast_close(cf);
  367. G_fatal_error(_("Please contact the GRASS development team"));
  368. }
  369. }
  370. rastline_ptr =
  371. G_incr_void_ptr(rastline_ptr, Rast_cell_size(map_type));
  372. }
  373. #ifdef DEBUG
  374. fprintf(stderr, "row[%d]=[", row);
  375. rastline_ptr = raster;
  376. for (col = 0; col < ncols; col++) {
  377. if (Rast_is_null_value(rastline_ptr, map_type))
  378. fprintf(stderr, "_");
  379. else
  380. fprintf(stderr, "+");
  381. rastline_ptr =
  382. G_incr_void_ptr(rastline_ptr, Rast_cell_size(map_type));
  383. }
  384. fprintf(stderr, "]\n");
  385. #endif
  386. Rast_put_row(cf, raster, map_type);
  387. G_percent(row, mrows, 5);
  388. }
  389. G_percent(row, mrows, 5); /* finish it off */
  390. Rast_close(cf);
  391. G_free(array_data);
  392. G_free(raster);
  393. if (!have_title)
  394. strncpy(map_title, infile, 1023);
  395. Rast_put_cell_title(map_name, map_title);
  396. Rast_short_history(map_name, "raster", &history);
  397. Rast_command_history(&history);
  398. Rast_write_history(map_name, &history);
  399. G_done_msg("");
  400. exit(EXIT_SUCCESS);
  401. }
  402. int is_nan(void *p, RASTER_MAP_TYPE dtype)
  403. {
  404. /* fn to test if incoming data point is either a IEEE NaN or a GRASS CELL null
  405. *
  406. * Takes a value of type RASTER_MAP_TYPE stored at memory address "p"
  407. * Returns 1 if we think it is a null, 0 otherwise
  408. */
  409. /* please improve */
  410. float *pval_f;
  411. double *pval_d;
  412. switch (dtype) {
  413. case CELL_TYPE: /* int doesn't have a IEEE NaN value, but we'll accept GRASS's version */
  414. if (Rast_is_null_value(p, dtype))
  415. return 1;
  416. break;
  417. case FCELL_TYPE:
  418. pval_f = (float *)p;
  419. if (pval_f[0] != pval_f[0])
  420. return 1;
  421. break;
  422. case DCELL_TYPE:
  423. pval_d = (double *)p;
  424. if (pval_d[0] != pval_d[0])
  425. return 1;
  426. break;
  427. default:
  428. G_fatal_error(_("Please contact the GRASS development team"));
  429. }
  430. /* otherwise */
  431. return 0;
  432. }
  433. #ifdef NOTYET
  434. /* for endian swapping, sometime in the future .. */
  435. static void SwabShort(uint16 * wp)
  436. {
  437. register char *cp = (char *)wp;
  438. int t;
  439. t = cp[1];
  440. cp[1] = cp[0];
  441. cp[0] = t;
  442. }
  443. static void SwabLong(uint32 * lp)
  444. {
  445. register char *cp = (char *)lp;
  446. int t;
  447. t = cp[3];
  448. cp[3] = cp[0];
  449. cp[0] = t;
  450. t = cp[2];
  451. cp[2] = cp[1];
  452. cp[1] = t;
  453. }
  454. static void SwabFloat(float *fp)
  455. {
  456. SwabLong((uint32 *) fp);
  457. }
  458. static void SwabDouble(double *dp)
  459. {
  460. register char *cp = (char *)dp;
  461. int t;
  462. t = cp[7];
  463. cp[7] = cp[0];
  464. cp[0] = t;
  465. t = cp[6];
  466. cp[6] = cp[1];
  467. cp[1] = t;
  468. t = cp[5];
  469. cp[5] = cp[2];
  470. cp[2] = t;
  471. t = cp[4];
  472. cp[4] = cp[3];
  473. cp[3] = t;
  474. }
  475. #endif