1
2 /***************************************************************************
3 *
4 * MODULE: r3.in.ascii
5 *
6 * AUTHOR(S): Roman Waupotitsch, Michael Shapiro, Helena Mitasova, Bill Brown,
7 * Lubos Mitas, Jaro Hofierka, Soeren Gebbert
8 *
9 * PURPOSE: Convert a 3D ASCII raster text file into a (binary) 3D raster map layer
10 *
11 * COPYRIGHT: (C) 2005 by the GRASS Development Team
12 *
13 * This program is free software under the GNU General Public
14 * License (>=v2). Read the file COPYING that comes with GRASS
15 * for details.
16 *
17 *****************************************************************************/
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <grass/gis.h>
23 #include <grass/raster3d.h>
24 #include <grass/glocale.h>
25
26 #define ROW_ORDER_NORTH_TO_SOUTH 1
27 #define ROW_ORDER_SOUTH_TO_NORTH 2
28 #define DEPTH_ORDER_BOTTOM_TO_TOP 3
29 #define DEPTH_ORDER_TOP_TO_BOTTOM 4
30
31 /*- prototypes --------------------------------------------------------------*/
32
33 static void fatalError(char *errorMsg); /*Simple Error message */
34
35 static void setParams(); /*Fill the paramType structure */
36
37 /*Puts the userdefined parameters into easier handable variables */
38 static void getParams(char **input, char **output, int *convertNull,
39 char *nullValue);
40
41 /* copy content of one file into another (taken form r.in.ascii) */
42 static int file_cpy(FILE *, FILE *);
43
44 /*reads a g3d ascii-file headerfile-string */
45 static void readHeaderString(FILE * fp, char *valueString, double *value);
46
47 static FILE *openAscii(char *asciiFile, RASTER3D_Region * region); /*open the g3d ascii file */
48
49 /*This function does all the work, it reads the values from the g3d ascii-file and put
50 it into an g3d-map */
51 static void asciiToG3d(FILE * fp, RASTER3D_Region * region, int convertNull,
52 char *nullValue);
53
54 /*---------------------------------------------------------------------------*/
55
56 /* global variables */
57 void *map = NULL;
58 int rowOrder;
59 int depthOrder;
60
61 extern void *Rast3d_open_new_param();
62
63 /*---------------------------------------------------------------------------*/
fatalError(char * errorMsg)64 void fatalError(char *errorMsg)
65 {
66 if (map != NULL) {
67 /* should unopen map here! */
68 Rast3d_close(map);
69 }
70
71 Rast3d_fatal_error("%s", errorMsg);
72 }
73
74 /*---------------------------------------------------------------------------*/
75
76 typedef struct {
77 struct Option *input, *output, *nv;
78 } paramType;
79
80 static paramType param;
81
setParams()82 static void setParams()
83 {
84 param.input = G_define_standard_option(G_OPT_F_INPUT);
85 param.input->required = YES;
86 param.input->label = _("Name of input file to be imported");
87 param.input->description = _("'-' for standard input");
88
89 param.output = G_define_standard_option(G_OPT_R3_OUTPUT);
90
91 param.nv = G_define_standard_option(G_OPT_M_NULL_VALUE);
92 param.nv->answer = "*";
93 param.nv->description = /* TODO: '*' or 'none' in the msg ?? */
94 _("String representing NULL value data cell (use 'none' if no such value)");
95 }
96
97 /*---------------------------------------------------------------------------*/
98
99 void
getParams(char ** input,char ** output,int * convertNull,char * nullValue)100 getParams(char **input, char **output, int *convertNull, char *nullValue)
101 {
102 *input = param.input->answer;
103 *output = param.output->answer;
104 *convertNull = (strcmp(param.nv->answer, "none") != 0);
105 if (*convertNull)
106 if (sscanf(param.nv->answer, "%s", nullValue) != 1)
107 fatalError("getParams: NULL-value value invalid");
108
109 G_debug(3, "getParams: input: %s, output: %s", *input, *output);
110 }
111
112 /*---------------------------------------------------------------------------*/
113
file_cpy(FILE * from,FILE * to)114 static int file_cpy(FILE * from, FILE * to)
115 {
116 char buf[BUFSIZ];
117 size_t size;
118 int written = 0;
119
120 while (1) {
121 size = fread(buf, 1, BUFSIZ, from);
122 if (!size) {
123 if (written) {
124 fflush(to);
125 G_fseek(to, 0L, SEEK_SET);
126 }
127 return 0;
128 }
129 if (!fwrite(buf, 1, size, to)) {
130 G_warning(_("Unable to write to file"));
131 return -1;
132 }
133 written = 1;
134 }
135 /* NOTREACHED */
136 return -1;
137 }
138
readHeaderString(FILE * fp,char * valueString,double * value)139 void readHeaderString(FILE * fp, char *valueString, double *value)
140 {
141 static char format[100];
142 char line_buff[1024];
143
144 /* to avoid buffer overflows we use G_snprintf */
145 G_snprintf(format, 100, "%s %%lf", valueString);
146 G_getl2(line_buff, 1024, fp);
147 if (sscanf(line_buff, format, value) != 1) {
148 /* this would be ideal to merge if Rast3d_close could be solved */
149 G_warning("Bad value for '%s': %s", valueString, line_buff);
150 fatalError("readHeaderString: header value invalid");
151 }
152 }
153
154 /*---------------------------------------------------------------------------*/
155
openAscii(char * asciiFile,RASTER3D_Region * region)156 FILE *openAscii(char *asciiFile, RASTER3D_Region * region)
157 {
158 FILE *fp;
159 char *tmp_file;
160 double tmp;
161 char buff[1024];
162 char line_buff[1024];
163
164 G_debug(3, "openAscii: opens the ascii file and reads the header");
165
166 if (strcmp(asciiFile, "-") == 0) {
167 tmp_file = G_tempfile();
168 if (NULL == (fp = fopen(tmp_file, "w+")))
169 G_fatal_error(_("Unable to open temporary file <%s>"), tmp_file);
170 unlink(tmp_file);
171 if (0 > file_cpy(stdin, fp))
172 G_fatal_error(_("Unable to read input from stdin"));
173 }
174 else {
175 fp = fopen(asciiFile, "r");
176 }
177 if (fp == NULL) {
178 perror(asciiFile);
179 G_usage();
180 exit(EXIT_FAILURE);
181 }
182
183 /* Initialize the default order */
184 rowOrder = ROW_ORDER_NORTH_TO_SOUTH;
185 depthOrder = DEPTH_ORDER_BOTTOM_TO_TOP;
186
187 /* Read the first line and check for grass version */
188 G_getl2(line_buff, 1024, fp);
189
190 /* First check for new ascii format*/
191 if (sscanf(line_buff, "version: %s", buff) == 1) {
192 G_message("Found version information: %s\n", buff);
193 if (G_strcasecmp(buff, "grass7") == 0) {
194
195 /* Parse the row and depth order */
196 G_getl2(line_buff, 1024, fp);
197 if (sscanf(line_buff, "order: %s", buff) != 1)
198 fatalError("Unable to parse the row and depth order");
199
200 if (G_strcasecmp(buff, "nsbt") == 0) {
201 rowOrder = ROW_ORDER_NORTH_TO_SOUTH;
202 depthOrder = DEPTH_ORDER_BOTTOM_TO_TOP;
203 G_message("Found north -> south, bottom -> top order (nsbt)");
204 }
205 if (G_strcasecmp(buff, "snbt") == 0) {
206 rowOrder = ROW_ORDER_SOUTH_TO_NORTH;
207 depthOrder = DEPTH_ORDER_BOTTOM_TO_TOP;
208 G_message("Found south -> north, bottom -> top order (snbt)");
209 }
210 if (G_strcasecmp(buff, "nstb") == 0) {
211 rowOrder = ROW_ORDER_NORTH_TO_SOUTH;
212 depthOrder = DEPTH_ORDER_TOP_TO_BOTTOM;
213 G_message("Found north -> south, top -> bottom order (nstb)");
214 }
215 if (G_strcasecmp(buff, "sntb") == 0) {
216 rowOrder = ROW_ORDER_SOUTH_TO_NORTH;
217 depthOrder = DEPTH_ORDER_TOP_TO_BOTTOM;
218 G_message("Found south -> north, top -> bottom order (sntb)");
219 }
220 } else {
221 G_fatal_error(_("Unsupported GRASS version %s"), buff);
222 }
223 } else {
224 /* Rewind the stream if no grass version info found */
225 rewind(fp);
226 }
227
228 Rast3d_get_window(region);
229
230 readHeaderString(fp, "north:", &(region->north));
231 readHeaderString(fp, "south:", &(region->south));
232 readHeaderString(fp, "east:", &(region->east));
233 readHeaderString(fp, "west:", &(region->west));
234 readHeaderString(fp, "top:", &(region->top));
235 readHeaderString(fp, "bottom:", &(region->bottom));
236 readHeaderString(fp, "rows:", &tmp);
237 region->rows = (int) tmp;
238 readHeaderString(fp, "cols:", &tmp);
239 region->cols = (int) tmp;
240 readHeaderString(fp, "levels:", &tmp);
241 region->depths = (int) tmp;
242
243 return fp;
244 }
245
246 /*---------------------------------------------------------------------------*/
247
248 #undef MAX
249 #define MAX(a,b) (a > b ? a : b)
250
251 void
asciiToG3d(FILE * fp,RASTER3D_Region * region,int convertNull,char * nullValue)252 asciiToG3d(FILE * fp, RASTER3D_Region * region, int convertNull, char *nullValue)
253 {
254 int x, y, z;
255 int col, row, depth;
256 double value;
257 char buff[256];
258 int tileX, tileY, tileZ;
259
260 Rast3d_get_tile_dimensions_map(map, &tileX, &tileY, &tileZ);
261 Rast3d_min_unlocked(map, RASTER3D_USE_CACHE_X);
262
263 Rast3d_autolock_on(map);
264 Rast3d_unlock_all(map);
265 G_message(_("Loading data ... (%dx%dx%d)"), region->cols, region->rows,
266 region->depths);
267
268 G_debug(3,
269 "asciiToG3d: writing the 3D raster map, with rows %i cols %i depths %i",
270 region->rows, region->cols, region->depths);
271
272 for (z = 0; z < region->depths; z++) {
273 G_percent(z, region->depths, 1);
274
275 if ((z % tileZ) == 0)
276 Rast3d_unlock_all(map);
277
278 for (y = 0; y < region->rows; y++) /* go south to north */
279 for (x = 0; x < region->cols; x++) {
280
281 /* From west to east */
282 col = x;
283 /* The default is to read rows from north to south */
284 row = y;
285 /* From bottom to the top */
286 depth = z;
287
288 /* Read rows as from south to north */
289 if (rowOrder == ROW_ORDER_SOUTH_TO_NORTH)
290 row = region->rows - y - 1;
291
292 /* Read XY layer from top to bottom */
293 if (depthOrder == DEPTH_ORDER_TOP_TO_BOTTOM)
294 depth = region->depths - z - 1;
295
296 if (fscanf(fp, "%s", buff) != 1) {
297 if (feof(fp))
298 G_warning(_("End of file reached while still loading data."));
299 G_debug(3,
300 "missing data at col=%d row=%d depth=%d last_value=[%.4f]",
301 x + 1, y + 1, z + 1, value);
302 fatalError("asciiToG3d: read failed");
303 }
304
305 /* Check for null value */
306 if (convertNull && strncmp(buff, nullValue, strlen(nullValue)) == 0) {
307 Rast3d_set_null_value(&value, 1, DCELL_TYPE);
308 } else {
309 if (sscanf(buff, "%lf", &value) != 1) {
310 G_warning(_("Invalid value detected"
311 " (at col=%d row=%d depth=%d): %s"),
312 x + 1, y + 1, z + 1, buff);
313 fatalError("asciiToG3d: read failed");
314 }
315 }
316 /* Write the data */
317 Rast3d_put_double(map, col, row, depth, value);
318 }
319 }
320
321 if (fscanf(fp, "%lf", &value) == 1) {
322 G_warning(_("Data exists in input file after fully importing "
323 "expected data. [%.4f ...]"), value);
324 }
325
326 if (!Rast3d_flush_all_tiles(map))
327 fatalError("asciiTog3d: error flushing tiles");
328
329 Rast3d_autolock_off(map);
330 Rast3d_unlock_all(map);
331
332 G_percent(1, 1, 1);
333 }
334
335 /*---------------------------------------------------------------------------*/
336
main(int argc,char * argv[])337 int main(int argc, char *argv[])
338 {
339 char *input, *output;
340 int convertNull;
341 char nullValue[256];
342 int useTypeDefault, type, useCompressionDefault, doCompression;
343 int usePrecisionDefault, precision, useDimensionDefault, tileX, tileY,
344 tileZ;
345 RASTER3D_Region region;
346 FILE *fp;
347 struct GModule *module;
348 struct History history;
349
350 map = NULL;
351
352 G_gisinit(argv[0]);
353 module = G_define_module();
354 G_add_keyword(_("raster3d"));
355 G_add_keyword(_("import"));
356 G_add_keyword(_("voxel"));
357 G_add_keyword(_("conversion"));
358 G_add_keyword("ASCII");
359 module->description =
360 _("Converts a 3D ASCII raster text file into a (binary) 3D raster map.");
361
362 setParams();
363 Rast3d_set_standard3d_input_params();
364
365 if (G_parser(argc, argv))
366 exit(EXIT_FAILURE);
367
368 getParams(&input, &output, &convertNull, nullValue);
369 if (!Rast3d_get_standard3d_params(&useTypeDefault, &type,
370 &useCompressionDefault, &doCompression,
371 &usePrecisionDefault, &precision,
372 &useDimensionDefault, &tileX, &tileY,
373 &tileZ))
374 fatalError("Error getting standard parameters");
375
376 Rast3d_init_defaults();
377
378 fp = openAscii(input, ®ion);
379
380 /*Open the new RASTER3D map */
381 map = Rast3d_open_new_param(output, RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_XY,
382 ®ion,
383 type, doCompression, precision, tileX, tileY,
384 tileZ);
385
386 if (map == NULL)
387 fatalError(_("Unable to open 3D raster map"));
388
389 /*Create the new RASTER3D Map */
390 asciiToG3d(fp, ®ion, convertNull, nullValue);
391
392 if (!Rast3d_close(map))
393 fatalError(_("Unable to close 3D raster map"));
394
395 /* write input name to map history */
396 Rast3d_read_history(output, G_mapset(), &history);
397 Rast_command_history(&history);
398 Rast_set_history(&history, HIST_DATSRC_1, input);
399 Rast3d_write_history(output, &history);
400
401 map = NULL;
402 if (fclose(fp))
403 fatalError(_("Unable to close ASCII file"));
404
405 return EXIT_SUCCESS;
406 }
407