/*! \file lib/ogsf/gvl_file.c \brief OGSF library - loading and manipulating volumes (lower level functions) GRASS OpenGL gsurf OGSF Library (C) 1999-2008 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. \author Tomas Paudits (February 2004) \author Doxygenized by Martin Landa (May 2008) */ #include #include #include #include #include #include #define LUCKY 33 #define MODE_DIRECT 0 #define MODE_SLICE 1 #define MODE_FULL 2 #define MODE_PRELOAD 3 #define MODE_DEFAULT 0 #define STATUS_READY 0 #define STATUS_BUSY 1 /*! \brief structure for slice mode reading from volume file */ typedef struct { int num, skip; int crnt, base; void *slice[MAX_VOL_SLICES]; } slice_data; static geovol_file *Data[MAX_VOL_FILES]; static geovol_file Df[MAX_VOL_FILES]; /* trying to avoid allocation */ static int Numfiles = 0; static int Cur_id = LUCKY; static int Cur_max; static int Rows, Cols, Depths; /* local functions prototypes */ void *open_g3d_file(const char *, IFLAG *, double *, double *); int close_g3d_file(void *); /*! \brief Initialize volume files \return 1 */ static int init_volfiles(void) { int i; RASTER3D_Region *w3; for (i = 0; i < MAX_VOL_FILES; i++) { /* avoiding dynamic allocation */ Data[i] = &(Df[i]); } Cur_max = MAX_VOL_FILES; /* get window */ w3 = GVL_get_window(); /* set cols, rows, depths from window */ Cols = w3->cols; Rows = w3->rows; Depths = w3->depths; return (1); } /*! \brief Check number of files \return 0 */ static int check_num_volfiles(void) { if (Numfiles < Cur_max) { return (0); } G_fatal_error(_("Maximum number of datafiles exceeded")); /* This return statement keeps compilers happy, it is never executed */ return (0); } /*! \brief Get geovol_file structure for given handle \param id \return pointer to geovol_file struct \return NULL on failure */ geovol_file *gvl_file_get_volfile(int id) { int i; for (i = 0; i < Numfiles; i++) { if (Data[i]->data_id == id) { return (Data[i]); } } return (NULL); } /*! \brief Find file with name and type in geovol_file array an return handle \param name file name \param begin \param data id \param -1 not found */ int find_datah(const char *name, IFLAG type, int begin) { static int i; int start; start = begin ? 0 : i + 1; for (i = start; i < Numfiles; i++) { if (!strcmp(Data[i]->file_name, name)) { if (Data[i]->file_type == type) { return (Data[i]->data_id); } } } return (-1); } /*! \brief Get file name for given handle \param id handle id \return file name \return NULL on failure */ char *gvl_file_get_name(int id) { int i; geovol_file *fvf; static char retstr[GPATH_MAX]; for (i = 0; i < Numfiles; i++) { if (Data[i]->data_id == id) { fvf = Data[i]; strcpy(retstr, fvf->file_name); return (retstr); } } return (NULL); } /*! \brief Get file type for given handle \param vf pointer to geovol_file struct \return file type */ int gvl_file_get_file_type(geovol_file * vf) { return (vf->file_type); } /*! \brief Get data type for given handle \param vf pointer to geovol_file struct \return data type */ int gvl_file_get_data_type(geovol_file * vf) { return (vf->data_type); } /*! \brief Get minimum and maximum value in volume file \param vf pointer to geovol_file struct \param[out] min min value \param[out] max max value */ void gvl_file_get_min_max(geovol_file * vf, double *min, double *max) { *min = vf->min; *max = vf->max; } /*! \brief Open 3d raster file \param name file name \param file_type file type \param data_type data type \param[out] min min value \param[out] max max value \return pointer to file \return NULL on failure */ void *open_volfile(const char *name, IFLAG file_type, IFLAG * data_type, double *min, double *max) { if (file_type == VOL_FTYPE_RASTER3D) { return open_g3d_file(name, data_type, min, max); } return (NULL); } /*! \brief Close volume file \param map volume filename \param type file type \return \return -1 on failure */ int close_volfile(void *map, IFLAG type) { if (type == VOL_FTYPE_RASTER3D) { return close_g3d_file(map); } return (-1); } /*! \brief Get handle for given file name and type \param name volume filename \param file_type file type \return data id \return -1 on failure */ int gvl_file_newh(const char *name, IFLAG file_type) { geovol_file *new; static int first = 1; int i, id; void *m; IFLAG data_type; double min, max; if (first) { if (0 > init_volfiles()) { return (-1); } first = 0; } if (0 <= (id = find_datah(name, file_type, 1))) { for (i = 0; i < Numfiles; i++) { if (Data[i]->data_id == id) { new = Data[i]; new->count++; return (id); } } } if (0 > check_num_volfiles()) { return (-1); } if (!name) { return (-1); } if ((m = open_volfile(name, file_type, &data_type, &min, &max)) == NULL) { return (-1); } new = Data[Numfiles]; if (new) { Numfiles++; new->data_id = Cur_id++; new->file_name = G_store(name); new->file_type = file_type; new->count = 1; new->map = m; new->min = min; new->max = max; new->data_type = data_type; new->status = STATUS_READY; new->buff = NULL; new->mode = 255; gvl_file_set_mode(new, MODE_DEFAULT); return (new->data_id); } return (-1); } /*! \brief Free allocated buffers \param vf pointer to geovol_file struct \return 1 */ int free_volfile_buffs(geovol_file * vf) { if (vf->mode == MODE_SLICE) { G_free(vf->buff); vf->buff = NULL; } if (vf->mode == MODE_PRELOAD) { G_free(vf->buff); vf->buff = NULL; } return (1); } /*! \brief Free geovol_file structure for given handle \param id \return */ int gvl_file_free_datah(int id) { int i, j, found = -1; geovol_file *fvf; G_debug(5, "gvl_file_free_datah(): id=%d", id); for (i = 0; i < Numfiles; i++) { if (Data[i]->data_id == id) { found = 1; fvf = Data[i]; if (fvf->count > 1) { fvf->count--; } else { close_volfile(fvf->map, fvf->file_type); free_volfile_buffs(fvf); G_free(fvf->file_name); fvf->file_name = NULL; fvf->data_id = 0; for (j = i; j < (Numfiles - 1); j++) { Data[j] = Data[j + 1]; } Data[j] = fvf; --Numfiles; } } } return (found); } /******************************************************************/ /* reading from RASTER3D raster volume files */ /******************************************************************/ /*! \brief Open 3d raster file \param filename file name \param type data type \param[out] min min value \param[out] max max value \returns pointer to data */ void *open_g3d_file(const char *filename, IFLAG * type, double *min, double *max) { const char *mapset; int itype; void *map; /* search for g3d file a return his mapset */ mapset = G_find_raster3d(filename, ""); if (!mapset) { G_warning(_("3D raster map <%s> not found"), filename); return (NULL); } /* open g3d file */ map = Rast3d_open_cell_old(filename, mapset, RASTER3D_DEFAULT_WINDOW, RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_DEFAULT); if (!map) { G_warning(_("Unable to open 3D raster map <%s>"), filename); return (NULL); } /* load range into range structure of map */ if (!Rast3d_range_load(map)) { G_warning(_("Unable to read range of 3D raster map <%s>"), filename); return (NULL); } Rast3d_range_min_max(map, min, max); /* get file data type */ itype = Rast3d_file_type_map(map); if (itype == FCELL_TYPE) *type = VOL_DTYPE_FLOAT; if (itype == DCELL_TYPE) *type = VOL_DTYPE_DOUBLE; return (map); } /*! \brief Close g3d file \param map 3d raster map \return -1 on failure \return 1 on success */ int close_g3d_file(void *map) { /* close opened g3d file */ if (Rast3d_close((RASTER3D_Map *) map) != 1) { G_warning(_("Unable to close 3D raster map <%s>"), ((RASTER3D_Map *) map)->fileName); return (-1); } return (1); } /*! \brief Eead value from g3d file \param type data type \param map 3D raster map \param x,y,z real coordinates \param[out] value data value \return -1 on failure \return 1 on success */ int read_g3d_value(IFLAG type, void *map, int x, int y, int z, void *value) { switch (type) { /* float data type */ case (VOL_DTYPE_FLOAT): *((float *)value) = Rast3d_get_float(map, x, y, z); break; /* double data type */ case (VOL_DTYPE_DOUBLE): *((double *)value) = Rast3d_get_double(map, x, y, z); break; /* unsupported data type */ default: return (-1); } return (1); } /*! \brief Read slice of values at level from g3d file \param type data type \param map 3D raster map \param level \param[out] data \return -1 on failure \return 0 on success */ int read_g3d_slice(IFLAG type, void *map, int level, void *data) { int x, y; switch (type) { /* float data type */ case (VOL_DTYPE_FLOAT): for (x = 0; x < Cols; x++) { for (y = 0; y < Rows; y++) { ((float *)data)[x + y * Cols] = Rast3d_get_float(map, x, y, level); } } break; /* double data type */ case (VOL_DTYPE_DOUBLE): for (x = 0; x < Cols; x++) { for (y = 0; y < Rows; y++) { ((double *)data)[x + y * Cols] = Rast3d_get_double(map, x, y, level); } } break; /* unsupported data type */ default: return (-1); } return (1); } /*! \brief Read all values from g3d file \param type data type \param map 3D raster map \param[out] data data buffer \return -1 on failure \return 1 on success */ int read_g3d_vol(IFLAG type, void *map, void *data) { int x, y, z; switch (type) { /* float data type */ case (VOL_DTYPE_FLOAT): for (x = 0; x < Cols; x++) { for (y = 0; y < Rows; y++) { for (z = 0; z < Depths; z++) { ((float *)data)[x + y * Cols + z * Rows * Cols] = Rast3d_get_float(map, x, y, z); } } } break; /* double data type */ case (VOL_DTYPE_DOUBLE): for (x = 0; x < Cols; x++) { for (y = 0; y < Rows; y++) { for (z = 0; z < Depths; z++) { ((double *)data)[x + y * Cols + z * Rows * Cols] = Rast3d_get_double(map, x, y, z); } } } break; /* unsupported data type */ default: return (-1); } return (1); } /*! \brief Check for null value \param type data type \param value \return 1 if value is null \return 0 if value is not null \return -1 on failure (unsupported data type */ int is_null_g3d_value(IFLAG type, void *value) { switch (type) { /* float data type */ case (VOL_DTYPE_FLOAT): return Rast3d_is_null_value_num(value, FCELL_TYPE); break; /* double data type */ case (VOL_DTYPE_DOUBLE): return Rast3d_is_null_value_num(value, DCELL_TYPE); break; /* unsupported data type */ default: return (-1); } return (-1); } /******************************************************************/ /* reading from buffer */ /******************************************************************/ /*! \brief Get value from buffer \param type data type \param data data buffer \param offset \param value \return -1 on failure (unsupported data type) \return 1 on success */ int get_buff_value(IFLAG type, void *data, int offset, void *value) { switch (type) { /* float data type */ case (VOL_DTYPE_FLOAT): *((float *)value) = ((float *)data)[offset]; break; /* double data type */ case (VOL_DTYPE_DOUBLE): *((double *)value) = ((double *)data)[offset]; break; /* unsupported data type */ default: return (-1); } return (1); } /******************************************************************/ /* direct mode reading from volume file */ /******************************************************************/ /*! \brief Read value direct from volume file \param vf pointer to geovol_file struct \param x,y,z real point \param[out] value data value \return -1 on failure \return 1 on success */ int get_direct_value(geovol_file * vf, int x, int y, int z, void *value) { switch (vf->file_type) { /* RASTER3D file type */ case (VOL_FTYPE_RASTER3D): if (0 > read_g3d_value(vf->data_type, vf->map, x, y, z, value)) return (-1); break; default: return (-1); } return (1); } /******************************************************************/ /* full mode reading from volume file */ /******************************************************************/ /*! \brief Allocate buffer memory for full mode reading \param vf pointer to geovol_file \return -1 on failure \return 1 on success */ int alloc_vol_buff(geovol_file * vf) { switch (vf->data_type) { /* float data type */ case (VOL_DTYPE_FLOAT): if ((vf->buff = (float *)G_malloc(sizeof(float) * Cols * Rows * Depths)) == NULL) return (-1); break; /* double data type */ case (VOL_DTYPE_DOUBLE): if ((vf->buff = (double *)G_malloc(sizeof(double) * Cols * Rows * Depths)) == NULL) return (-1); break; /* unsupported data type */ default: return (-1); } return (1); } /*! \brief Free memory buffer memory \param vf pointer to geovol_file struct \return 1 */ int free_vol_buff(geovol_file * vf) { G_free(vf->buff); return (1); } /*! \brief Read all values from volume file \param vf pointer to geovol_file struct \return -1 on failure \return 1 on success */ int read_vol(geovol_file * vf) { switch (vf->file_type) { /* RASTER3D file format */ case (VOL_FTYPE_RASTER3D): if (0 > read_g3d_vol(vf->data_type, vf->map, vf->buff)) return (-1); break; /* unsupported file format */ default: return (-1); } return (1); } /*! \brief Get value from volume buffer \param vf pointer to geovol_file struct \param x,y,z real point \param[out] value data value \return 1 */ int get_vol_value(geovol_file * vf, int x, int y, int z, void *value) { get_buff_value(vf->data_type, vf->buff, z * Rows * Cols + y * Cols + x, value); return (1); } /******************************************************************/ /* slice mode reading from volume file */ /******************************************************************/ /*! \brief Allocate buffer for slice mode reading \param vf pointer to geovol_file struct \return -1 on failure \return 1 on success */ int alloc_slice_buff(geovol_file * vf) { int i; slice_data *sd = (slice_data *) vf->buff; switch (vf->data_type) { /* float data type */ case (VOL_DTYPE_FLOAT): for (i = 0; i < sd->num; i++) { if ((sd->slice[i] = (float *)G_malloc(sizeof(float) * Cols * Rows)) == NULL) return (-1); } break; /* double data type */ case (VOL_DTYPE_DOUBLE): for (i = 0; i < sd->num; i++) { if ((sd->slice[i] = (double *)G_malloc(sizeof(double) * Cols * Rows)) == NULL) return (-1); } break; /* unsupported data type */ default: return (-1); } return (1); } /*! \brief Free buffer for slice mode reading \param vf pointer to geovol_file struct \return 1 */ int free_slice_buff(geovol_file * vf) { int i; slice_data *sd = (slice_data *) vf->buff; for (i = 0; i < sd->num; i++) { G_free(sd->slice[i]); } return (1); } /*! \brief Read slice of values at level from volume file \param vf pointer to geovol_file struct \param s \param l \return -1 on failure \return 1 on success */ int read_slice(geovol_file * vf, int s, int l) { /* get slice structure */ slice_data *sd = (slice_data *) vf->buff; switch (vf->file_type) { /* RASTER3D file format */ case (VOL_FTYPE_RASTER3D): if (0 > read_g3d_slice(vf->data_type, vf->map, l, sd->slice[s])) return (-1); break; /* unsupported file format */ default: return (-1); } return (1); } /*! \brief Read new slice into buffer \param vf pointer to geovol_file struct */ void shift_slices(geovol_file * vf) { void *tmp; int i; slice_data *sd = (slice_data *) vf->buff; /* change pointers to slices */ tmp = sd->slice[0]; for (i = 0; i < sd->num - 1; i++) { sd->slice[i] = sd->slice[i + 1]; } sd->slice[sd->num - 1] = tmp; /* read new slice data */ read_slice(vf, sd->num, sd->crnt + 1 + (sd->num - sd->base)); /* increase current slice value */ sd->crnt++; } /*! \brief Get value from slice buffer \param vf pointer to geovol_file struct \param x,y,z real point \param[out] value data value \return -1 on failure \return 1 on success */ int get_slice_value(geovol_file * vf, int x, int y, int z, void *value) { slice_data *sd = (slice_data *) vf->buff; /* value is in loaded slices */ if ((z >= sd->crnt - (sd->base - 1)) && (z <= sd->crnt + sd->num - sd->base)) { get_buff_value(vf->data_type, sd->slice[(z - sd->crnt)], y * Cols + x, value); } /* if value isn't in loaded slices, need read new data slice */ else if (z == sd->crnt - (sd->base - 1) + 1) { shift_slices(vf); get_buff_value(vf->data_type, sd->slice[(z - sd->crnt)], y * Cols + x, value); } /* value out of range */ else { return (-1); } return (1); } /******************************************************************/ /* reading from volume file */ /******************************************************************/ /*! \brief Start read - allocate memory buffer a read first data into buffer \param vf pointer to geovol_file struct \return -1 on failure \return 1 on success */ int gvl_file_start_read(geovol_file * vf) { int i; slice_data *sd; /* check status */ if (vf->status == STATUS_BUSY) return (-1); switch (vf->mode) { /* read whole volume into memory */ case (MODE_FULL): /* allocate memory */ if (0 > alloc_vol_buff(vf)) return (-1); /* read volume */ read_vol(vf); break; /* read first data slices into memory */ case (MODE_SLICE): /* allocate slices buffer memory */ if (0 > alloc_slice_buff(vf)) return (-1); /* read volume */ sd = (slice_data *) vf->buff; /* set current slice to 0 */ sd->crnt = 0; /* read first slices into buffer */ for (i = 0; i < (sd->num - sd->base + 1); i++) read_slice(vf, (sd->base - 1) + i, i); break; } /* set status */ vf->status = STATUS_BUSY; return (1); } /*! \brief End read - free buffer memory \param vf pointer to geovol_file struct \return -1 on failure \return 1 on success */ int gvl_file_end_read(geovol_file * vf) { /* check status */ if (vf->status == STATUS_READY) return (-1); switch (vf->mode) { case (MODE_FULL): if (0 > free_vol_buff(vf)) return (-1); break; case (MODE_SLICE): /* allocate slices buffer memory */ if (0 > free_slice_buff(vf)) return (-1); } /* set status */ vf->status = STATUS_READY; return (1); } /*! \brief Get value for volume file at x, y, z \param vf pointer to geovol_file struct \return -1 on failure \return 1 on success */ int gvl_file_get_value(geovol_file * vf, int x, int y, int z, void *value) { /* check status */ if (vf->status != STATUS_BUSY) { return (-1); } switch (vf->mode) { /* read value direct from g3d file */ case (MODE_DIRECT): if (0 > get_direct_value(vf, x, y, z, value)) return (-1); break; case (MODE_SLICE): if (0 > get_slice_value(vf, x, y, z, value)) return (-1); break; case (MODE_FULL): case (MODE_PRELOAD): if (0 > get_vol_value(vf, x, y, z, value)) return (-1); break; } return (1); } /*! \brief Check for null value \param vf pointer to geovol_file struct \param value data value \return -1 on failure \return 1 on success */ int gvl_file_is_null_value(geovol_file * vf, void *value) { switch (vf->file_type) { /* RASTER3D file format */ case (VOL_FTYPE_RASTER3D): return is_null_g3d_value(vf->file_type, value); break; /* unsupported file format */ default: return (-1); } return (-1); } /******************************************************************/ /* set parameters for reading volumes */ /******************************************************************/ /*! \brief Set read mode \param vf pointer to geovol_file struct \param mode read mode \return -1 on failure \return 1 on success */ int gvl_file_set_mode(geovol_file * vf, IFLAG mode) { slice_data *sd; if (vf->status == STATUS_BUSY) return (-1); if (vf->mode == mode) return (1); if (vf->mode == MODE_SLICE) G_free(vf->buff); if (vf->mode == MODE_PRELOAD) G_free(vf->buff); if (mode == MODE_SLICE) { if ((vf->buff = (slice_data *) G_malloc(sizeof(slice_data))) == NULL) return (-1); sd = (slice_data *) vf->buff; sd->num = 1; sd->crnt = 0; sd->base = 1; } if (mode == MODE_PRELOAD) { /* allocate memory */ if (0 > alloc_vol_buff(vf)) return (-1); /* read volume */ read_vol(vf); } vf->mode = mode; return (1); } /*! \brief Set parameters for slice reading \param vf pointer to geovol_file struct \param n \param b \return -1 on failure \return 1 on success */ int gvl_file_set_slices_param(geovol_file * vf, int n, int b) { slice_data *sd; if (vf->status == STATUS_BUSY) return (-1); if (!(vf->mode == MODE_SLICE)) return (-1); sd = (slice_data *) vf->buff; sd->num = n; sd->base = b; return (1); }