/**************************************************************************** * * MODULE: r.elev.to.rast3 * * AUTHOR(S): Original author * Soeren Gebbert soerengebbert@gmx.de * 07 08 2006 Berlin * PURPOSE: Creates a 3D volume map based on a 2D elevation and value raster map * * COPYRIGHT: (C) 2006 by the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with GRASS * for details. * *****************************************************************************/ #include #include #include #include #include #include /*- Parameters and global variables -----------------------------------------*/ typedef struct { struct Option *input, *elev, *output, *upper, *lower; struct Flag *fillup, *filllow; } ParameterType; /*Data to be used */ typedef struct { void *map; /*The 3d voxel output map */ int input; /*The raster value map */ int elev; /*The raster elevation map */ int inputmaptype; int elevmaptype; double upper; /*The upper value */ double lower; /*The lower value */ int useUpperMapVal; /*0 = use upper value, 1 = use map value to fill upper cells */ int useLowerMapVal; /*0 = use lower value, 1 = use map value to fill lower cells */ } Database; ParameterType Parameter; /*Parameters */ /*- prototypes --------------------------------------------------------------*/ void FatalError(Database db, char *errorMsg); /*Simple Error message */ void SetParameters(); /*Fill the ParameterType structure */ void ElevRasterToG3D(Database db, G3D_Region region); /*Write the raster */ int OpenInputMap(char *name, char *mapset); /*opens the outputmap */ void CloseInputMap(int fd); /*close the map */ double GetRasterValueAsDouble(int maptype, void *ptr, double nullval); /* ************************************************************************* */ /* Get the value of the current raster pointer as double ******************* */ /* ************************************************************************* */ double GetRasterValueAsDouble(int MapType, void *ptr, double nullval) { double val = nullval; if (MapType == CELL_TYPE) { if (G_is_null_value(ptr, MapType)) { val = nullval; } else { val = *(CELL *) ptr; } } if (MapType == FCELL_TYPE) { if (G_is_null_value(ptr, MapType)) { val = nullval; } else { val = *(FCELL *) ptr; } } if (MapType == DCELL_TYPE) { if (G_is_null_value(ptr, MapType)) { val = nullval; } else { val = *(DCELL *) ptr; } } return val; } /* ************************************************************************* */ /* Open the raster input map *********************************************** */ /* ************************************************************************* */ int OpenInputMap(char *name, char *mapset) { int fd; G_debug(3, _("Open Raster file %s in Mapset %s"), name, mapset); /* open raster file */ fd = G_open_cell_old(name, mapset); if (fd < 0) G_fatal_error(_("Could not open map %s"), name); return fd; } /* ************************************************************************* */ /* Close the raster input map ********************************************** */ /* ************************************************************************* */ void CloseInputMap(int fd) { if (G_close_cell(fd) < 0) G_fatal_error(_("unable to close input map")); } /* ************************************************************************* */ /* Error handling ********************************************************** */ /* ************************************************************************* */ void FatalError(Database db, char *errorMsg) { /* Close files and exit */ if (db.map != NULL) { /* should unopen map here! but this functionality is not jet implemented */ if (!G3d_closeCell(db.map)) G3d_fatalError(_("Could not close the map")); } if (db.input) CloseInputMap(db.input); if (db.elev) CloseInputMap(db.elev); G3d_fatalError(errorMsg); exit(EXIT_FAILURE); } /* ************************************************************************* */ /* Set up the arguments **************************************************** */ /* ************************************************************************* */ void SetParameters() { Parameter.input = G_define_option(); Parameter.input->key = "input"; Parameter.input->type = TYPE_STRING; Parameter.input->required = YES; Parameter.input->description = _("2d raster maps which represent the values"); Parameter.input->gisprompt = "old,cell,raster"; Parameter.input->multiple = NO; Parameter.elev = G_define_option(); Parameter.elev->key = "elev"; Parameter.elev->type = TYPE_STRING; Parameter.elev->required = YES; Parameter.elev->description = _("2d raster maps which represent the elevation"); Parameter.elev->gisprompt = "old,cell,raster"; Parameter.elev->multiple = NO; Parameter.output = G_define_option(); Parameter.output->key = "output"; Parameter.output->type = TYPE_STRING; Parameter.output->required = YES; Parameter.output->gisprompt = "new,grid3,3d-raster"; Parameter.output->description = _("output 3dcell map"); Parameter.upper = G_define_option(); Parameter.upper->key = "upper"; Parameter.upper->type = TYPE_DOUBLE; Parameter.upper->required = NO; Parameter.upper->description = _("The value to fill the upper cells, default is null"); Parameter.lower = G_define_option(); Parameter.lower->key = "lower"; Parameter.lower->type = TYPE_DOUBLE; Parameter.lower->required = NO; Parameter.lower->description = _("The value to fill the lower cells, default is null"); Parameter.fillup = G_define_flag(); Parameter.fillup->key = 'u'; Parameter.fillup->description = _("Use the input map values to fill the upper cells"); Parameter.filllow = G_define_flag(); Parameter.filllow->key = 'l'; Parameter.filllow->description = _("Use the input map values to fill the lower cells"); return; } /* ************************************************************************* */ /* Write the raster map into the G3D map *********************************** */ /* ************************************************************************* */ void ElevRasterToG3D(Database db, G3D_Region region) { int x, y, z; int rows, cols, depths; void *input_rast; void *input_ptr; void *elev_rast; void *elev_ptr; double inval, value, null; double hight, top, bottom, tbres; rows = region.rows; cols = region.cols; depths = region.depths; top = region.top; bottom = region.bottom; /*Calculate the top-bottom resolution */ tbres = (top - bottom) / depths; /*memory */ input_rast = G_allocate_raster_buf(db.inputmaptype); elev_rast = G_allocate_raster_buf(db.elevmaptype); G3d_setNullValue(&null, 1, G3D_DOUBLE); G_debug(3, _ ("ElevRasterToG3D: Writing 3D raster maps with depths %i rows %i cols %i."), depths, rows, cols); /*The mainloop */ for (y = 0; y < rows; y++) { G_percent(y, rows - 1, 10); if (!G_get_raster_row(db.input, input_rast, y, db.inputmaptype)) FatalError(db, _("Could not get raster row from input map\n")); if (!G_get_raster_row(db.elev, elev_rast, y, db.elevmaptype)) FatalError(db, _("Could not get raster row from elev map\n")); for (x = 0, input_ptr = input_rast, elev_ptr = elev_rast; x < cols; x++, input_ptr = G_incr_void_ptr(input_ptr, G_raster_size(db.inputmaptype)), elev_ptr = G_incr_void_ptr(elev_ptr, G_raster_size(db.elevmaptype))) { /*Get the elevation and the input map value */ inval = GetRasterValueAsDouble(db.inputmaptype, input_ptr, null); hight = GetRasterValueAsDouble(db.elevmaptype, elev_ptr, null); /*Calculate if the G3D cell is lower or upper the elevation map */ for (z = 0; z < depths; z++) { /*Upper cells */ if (hight < (z * tbres + bottom)) { if (db.useUpperMapVal) value = inval; /*Input map value */ else value = db.upper; } /*lower cells */ if (hight > ((z + 1) * tbres + bottom)) { if (db.useLowerMapVal) value = inval; /*Input map value */ else value = db.lower; } /*If exactly at the border, fill upper AND lower cell */ if (hight >= (z * tbres + bottom) && hight <= ((z + 1) * tbres + bottom)) value = inval; /*If the elevation is null, set the G3D value null */ if (G3d_isNullValueNum(&hight, G3D_DOUBLE)) value = null; /*Write the value to the 3D map */ if (G3d_putValue(db.map, x, y, z, (char *)&value, G3D_DOUBLE) < 0) FatalError(db, _("error writing G3D double data")); } } } G_debug(2, _("\nDone\n")); if (input_rast) G_free(input_rast); if (elev_rast) G_free(elev_rast); return; } /* ************************************************************************* */ /* Main function, open the raster maps and create the G3D raster maps ****** */ /* ************************************************************************* */ int main(int argc, char *argv[]) { G3D_Region region; struct Cell_head window2d; struct GModule *module; int cols, rows; char *name = NULL; char *mapset = NULL; Database db; /*Initiate the database structure */ db.map = NULL; db.input = 0; db.elev = 0; db.useUpperMapVal = 0; db.useLowerMapVal = 0; /* Initialize GRASS */ G_gisinit(argv[0]); module = G_define_module(); module->keywords = _("raster, raster3d, voxel"); module->description = _ ("Creates a 3D volume map based on a 2D elevation and value raster map"); /* Get Parametereters from user */ SetParameters(); /* Have GRASS get inputs */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); /*Use the input map value to fill the upper cells */ if (Parameter.fillup->answer) { db.useUpperMapVal = 1; } /*Use the input map value to fill the lower cells */ if (Parameter.filllow->answer) { db.useLowerMapVal = 1; } /*Set the upper value */ if (Parameter.upper->answer) { if (sscanf(Parameter.upper->answer, "%lf", &db.upper)) db.useUpperMapVal = 0; else G_fatal_error(_("The upper value is not valid")); } else { G3d_setNullValue(&db.upper, 1, G3D_DOUBLE); } /*Set the lower value */ if (Parameter.lower->answer) { if (sscanf(Parameter.lower->answer, "%lf", &db.lower)) db.useLowerMapVal = 0; else G_fatal_error(_("The lower value is not valid")); } else { G3d_setNullValue(&db.lower, 1, G3D_DOUBLE); } /* Figure out the region from the map */ G3d_initDefaults(); G3d_getWindow(®ion); /*Check if the g3d-region is equal to the 2d rows and cols */ rows = G_window_rows(); cols = G_window_cols(); /*If not equal, set the 2D windows correct */ if (rows != region.rows || cols != region.cols) { G_message (_ ("The 2d and 3d region settings are different. I will use the g3d settings to adjust the 2d region.")); G_get_set_window(&window2d); window2d.ns_res = region.ns_res; window2d.ew_res = region.ew_res; window2d.rows = region.rows; window2d.cols = region.cols; G_set_window(&window2d); } if (G_legal_filename(Parameter.output->answer) < 0) FatalError(db, _("Illegal output file name")); /*Open input map */ if (Parameter.input->answer != NULL) { mapset = NULL; name = NULL; name = Parameter.input->answer; mapset = G_find_cell2(name, ""); } if (mapset == NULL) { FatalError(db, _("input cell file not found\n")); } db.input = OpenInputMap(name, mapset); db.inputmaptype = G_raster_map_type(name, mapset); /*Open elev map */ if (Parameter.elev->answer != NULL) { mapset = NULL; name = NULL; name = Parameter.elev->answer; mapset = G_find_cell2(name, ""); } if (mapset == NULL) { FatalError(db, _("elev cell file not found\n")); } db.elev = OpenInputMap(name, mapset); db.elevmaptype = G_raster_map_type(name, mapset); /*G3D output map */ G_message(_("Creating 3D raster map\n")); db.map = NULL; db.map = G3d_openCellNew(Parameter.output->answer, G3D_DOUBLE, G3D_USE_CACHE_DEFAULT, ®ion); if (db.map == NULL) FatalError(db, _("error opening g3d file")); /***************************/ /*Create the G3D Rastermap */ ElevRasterToG3D(db, region); /***************************/ /* Close files and exit */ CloseInputMap(db.input); CloseInputMap(db.elev); if (!G3d_closeCell(db.map)) G3d_fatalError(_("Error closing g3d file")); return (EXIT_SUCCESS); }