|
@@ -0,0 +1,333 @@
|
|
|
+/* ***************************************************************
|
|
|
+ *
|
|
|
+ * MODULE: v.what.rast3
|
|
|
+ *
|
|
|
+ * AUTHOR(S): Soeren Gebbert, this code is based on a slightly modified version of
|
|
|
+ * v.what.rast from Radim Blazek and Michael Shapiro
|
|
|
+ *
|
|
|
+ * PURPOSE: Uploads 3d raster values at positions of vector points to the table
|
|
|
+ *
|
|
|
+ * COPYRIGHT: (C) 2001, 2011 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 <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
+#include <grass/raster3d.h>
|
|
|
+#include <grass/dbmi.h>
|
|
|
+#include <grass/vector.h>
|
|
|
+#include <grass/glocale.h>
|
|
|
+
|
|
|
+#include "local_proto.h"
|
|
|
+
|
|
|
+int main(int argc, char *argv[])
|
|
|
+{
|
|
|
+ int i, j, nlines, type, field, cat;
|
|
|
+
|
|
|
+ char buf[2048];
|
|
|
+ struct {
|
|
|
+ struct Option *vect, *rast3d, *field, *col, *where;
|
|
|
+ } opt;
|
|
|
+ int Cache_size;
|
|
|
+ struct order *cache;
|
|
|
+ struct GModule *module;
|
|
|
+
|
|
|
+ RASTER3D_Region region;
|
|
|
+ RASTER3D_Map *map;
|
|
|
+
|
|
|
+ struct Map_info Map;
|
|
|
+ struct line_pnts *Points;
|
|
|
+ struct line_cats *Cats;
|
|
|
+ int point;
|
|
|
+ int point_cnt; /* number of points in cache */
|
|
|
+ int outside_cnt; /* points outside region */
|
|
|
+ int nocat_cnt; /* points inside region but without category */
|
|
|
+ int dupl_cnt; /* duplicate categories */
|
|
|
+ int typeIntern;
|
|
|
+ int is_empty;
|
|
|
+ struct bound_box box;
|
|
|
+
|
|
|
+ int *catexst, *cex;
|
|
|
+ struct field_info *Fi;
|
|
|
+ dbString stmt;
|
|
|
+ dbDriver *driver;
|
|
|
+ int select, norec_cnt, update_cnt, upderr_cnt, col_type;
|
|
|
+
|
|
|
+ G_gisinit(argv[0]);
|
|
|
+
|
|
|
+ module = G_define_module();
|
|
|
+ G_add_keyword(_("vector"));
|
|
|
+ G_add_keyword(_("raster"));
|
|
|
+ G_add_keyword(_("position"));
|
|
|
+ G_add_keyword(_("querying"));
|
|
|
+ G_add_keyword(_("attribute table"));
|
|
|
+ module->description =
|
|
|
+ _("Uploads 3d raster values at positions of vector points to the table.");
|
|
|
+
|
|
|
+ opt.vect = G_define_standard_option(G_OPT_V_MAP);
|
|
|
+ opt.vect->label =
|
|
|
+ _("Name of vector points map for which to edit attributes");
|
|
|
+
|
|
|
+ opt.field = G_define_standard_option(G_OPT_V_FIELD);
|
|
|
+
|
|
|
+ opt.rast3d = G_define_standard_option(G_OPT_R3_MAP);
|
|
|
+ opt.rast3d->key = "raster3d";
|
|
|
+ opt.rast3d->description = _("Name of existing 3d raster map to be queried");
|
|
|
+
|
|
|
+ opt.col = G_define_standard_option(G_OPT_DB_COLUMN);
|
|
|
+ opt.col->required = YES;
|
|
|
+ opt.col->description =
|
|
|
+ _("Name of attribute column to be updated with the query result");
|
|
|
+
|
|
|
+ opt.where = G_define_standard_option(G_OPT_DB_WHERE);
|
|
|
+
|
|
|
+ if (G_parser(argc, argv))
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
+
|
|
|
+ db_init_string(&stmt);
|
|
|
+ Points = Vect_new_line_struct();
|
|
|
+ Cats = Vect_new_cats_struct();
|
|
|
+
|
|
|
+ /* Initiate the default settings */
|
|
|
+ Rast3d_init_defaults();
|
|
|
+
|
|
|
+ /* Figure out the current region settings */
|
|
|
+ Rast3d_get_window(®ion);
|
|
|
+
|
|
|
+ box.N = region.north;
|
|
|
+ box.S = region.south;
|
|
|
+ box.E = region.east;
|
|
|
+ box.W = region.west;
|
|
|
+ box.T = region.top;
|
|
|
+ box.B = region.bottom;
|
|
|
+
|
|
|
+ /* Open vector */
|
|
|
+ Vect_set_open_level(2);
|
|
|
+ Vect_open_old2(&Map, opt.vect->answer, "", opt.field->answer);
|
|
|
+
|
|
|
+ field = Vect_get_field_number(&Map, opt.field->answer);
|
|
|
+
|
|
|
+ Fi = Vect_get_field(&Map, field);
|
|
|
+ if (Fi == NULL)
|
|
|
+ G_fatal_error(_("Database connection not defined for layer %d"),
|
|
|
+ field);
|
|
|
+
|
|
|
+ /* Open driver */
|
|
|
+ driver = db_start_driver_open_database(Fi->driver, Fi->database);
|
|
|
+ if (driver == NULL) {
|
|
|
+ G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
|
|
|
+ Fi->database, Fi->driver);
|
|
|
+ }
|
|
|
+
|
|
|
+ map = Rast3d_open_cell_old(opt.rast3d->answer, G_find_raster3d(opt.rast3d->answer, ""), ®ion,
|
|
|
+ RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_DEFAULT);
|
|
|
+
|
|
|
+ if (map == NULL)
|
|
|
+ G_fatal_error(_("Error opening 3d raster map <%s>"), opt.rast3d->answer);
|
|
|
+
|
|
|
+ /* Check column type */
|
|
|
+ col_type = db_column_Ctype(driver, Fi->table, opt.col->answer);
|
|
|
+
|
|
|
+ if (col_type == -1)
|
|
|
+ G_fatal_error(_("Column <%s> not found"), opt.col->answer);
|
|
|
+
|
|
|
+ if (col_type != DB_C_TYPE_DOUBLE)
|
|
|
+ G_fatal_error(_("Column type not supported, please use a column with double type"));
|
|
|
+
|
|
|
+ /* Read vector points to cache */
|
|
|
+ Cache_size = Vect_get_num_primitives(&Map, GV_POINT);
|
|
|
+ /* Note: Some space may be wasted (outside region or no category) */
|
|
|
+
|
|
|
+ cache = (struct order *)G_calloc(Cache_size, sizeof(struct order));
|
|
|
+
|
|
|
+ point_cnt = outside_cnt = nocat_cnt = 0;
|
|
|
+
|
|
|
+ nlines = Vect_get_num_lines(&Map);
|
|
|
+
|
|
|
+ G_debug(1, "Reading %d vector features from map", nlines);
|
|
|
+
|
|
|
+ G_important_message(_("Reading features from vector map..."));
|
|
|
+ for (i = 1; i <= nlines; i++) {
|
|
|
+ type = Vect_read_line(&Map, Points, Cats, i);
|
|
|
+ G_debug(4, "line = %d type = %d", i, type);
|
|
|
+
|
|
|
+ G_percent(i, nlines, 2);
|
|
|
+
|
|
|
+ /* check type */
|
|
|
+ if (!(type & GV_POINT))
|
|
|
+ continue; /* Points only */
|
|
|
+
|
|
|
+ /* check region */
|
|
|
+ if (!Vect_point_in_box(Points->x[0], Points->y[0], Points->z[0], &box)) {
|
|
|
+ outside_cnt++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vect_cat_get(Cats, field, &cat);
|
|
|
+ if (cat < 0) { /* no category of given field */
|
|
|
+ nocat_cnt++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ G_debug(4, " cat = %d", cat);
|
|
|
+
|
|
|
+ cache[point_cnt].x = Points->x[0];
|
|
|
+ cache[point_cnt].y = Points->y[0];
|
|
|
+ cache[point_cnt].z = Points->z[0];
|
|
|
+ cache[point_cnt].cat = cat;
|
|
|
+ cache[point_cnt].count = 1;
|
|
|
+ point_cnt++;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vect_set_db_updated(&Map);
|
|
|
+ Vect_hist_command(&Map);
|
|
|
+ Vect_set_db_updated(&Map);
|
|
|
+ Vect_close(&Map);
|
|
|
+
|
|
|
+ G_debug(1, "Read %d vector points", point_cnt);
|
|
|
+ /* Cache may contain duplicate categories, sort by cat, find and remove duplicates
|
|
|
+ * and recalc count and decrease point_cnt */
|
|
|
+ qsort(cache, point_cnt, sizeof(struct order), by_cat);
|
|
|
+
|
|
|
+ G_debug(1, "Points are sorted, starting duplicate removal loop");
|
|
|
+
|
|
|
+ for (i = 0, j = 1; j < point_cnt; j++)
|
|
|
+ if (cache[i].cat != cache[j].cat)
|
|
|
+ cache[++i] = cache[j];
|
|
|
+ else
|
|
|
+ cache[i].count++;
|
|
|
+ point_cnt = i + 1;
|
|
|
+
|
|
|
+ G_debug(1, "%d vector points left after removal of duplicates",
|
|
|
+ point_cnt);
|
|
|
+
|
|
|
+ /* Report number of points not used */
|
|
|
+ if (outside_cnt)
|
|
|
+ G_warning(_("%d points outside current region were skipped"),
|
|
|
+ outside_cnt);
|
|
|
+
|
|
|
+ if (nocat_cnt)
|
|
|
+ G_warning(_("%d points without category were skipped"), nocat_cnt);
|
|
|
+
|
|
|
+ /* Extract raster values from file and store in cache */
|
|
|
+ G_debug(1, "Extracting raster values");
|
|
|
+
|
|
|
+ typeIntern = Rast3d_tile_type_map(map);
|
|
|
+
|
|
|
+ /* Sample the 3d raster map */
|
|
|
+ for (point = 0; point < point_cnt; point++) {
|
|
|
+
|
|
|
+ if (cache[point].count > 1)
|
|
|
+ continue; /* duplicate cats */
|
|
|
+
|
|
|
+ if(typeIntern == FCELL_TYPE) {
|
|
|
+ Rast3d_get_window_value(map, cache[point].y, cache[point].x, cache[point].z,
|
|
|
+ &cache[point].fvalue, FCELL_TYPE);
|
|
|
+ } else {
|
|
|
+ Rast3d_get_window_value(map, cache[point].y, cache[point].x, cache[point].z,
|
|
|
+ &cache[point].dvalue, DCELL_TYPE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Rast3d_close(map);
|
|
|
+
|
|
|
+ /* Update table from cache */
|
|
|
+ G_debug(1, "Updating db table");
|
|
|
+
|
|
|
+ /* select existing categories to array (array is sorted) */
|
|
|
+ select = db_select_int(driver, Fi->table, Fi->key, NULL, &catexst);
|
|
|
+
|
|
|
+ db_begin_transaction(driver);
|
|
|
+
|
|
|
+ norec_cnt = update_cnt = upderr_cnt = dupl_cnt = 0;
|
|
|
+
|
|
|
+ G_message("Update vector attributes...");
|
|
|
+ for (point = 0; point < point_cnt; point++) {
|
|
|
+ if (cache[point].count > 1) {
|
|
|
+ G_warning(_("More points (%d) of category %d, value set to 'NULL'"),
|
|
|
+ cache[point].count, cache[point].cat);
|
|
|
+ dupl_cnt++;
|
|
|
+ }
|
|
|
+
|
|
|
+ G_percent(point, point_cnt, 2);
|
|
|
+
|
|
|
+ /* category exist in DB ? */
|
|
|
+ cex =
|
|
|
+ (int *)bsearch((void *)&(cache[point].cat), catexst, select,
|
|
|
+ sizeof(int), srch_cat);
|
|
|
+ if (cex == NULL) { /* cat does not exist in DB */
|
|
|
+ norec_cnt++;
|
|
|
+ G_warning(_("No record for category %d in table <%s>"),
|
|
|
+ cache[point].cat, Fi->table);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ G_snprintf(buf, 2048, "update %s set %s = ", Fi->table, opt.col->answer);
|
|
|
+
|
|
|
+ db_set_string(&stmt, buf);
|
|
|
+
|
|
|
+ is_empty = 0;
|
|
|
+
|
|
|
+ if (cache[point].count > 1)
|
|
|
+ is_empty = 1;
|
|
|
+ if(typeIntern == FCELL_TYPE)
|
|
|
+ is_empty = Rast3d_is_null_value_num(&cache[point].fvalue, FCELL_TYPE);
|
|
|
+ if(typeIntern == DCELL_TYPE)
|
|
|
+ is_empty = Rast3d_is_null_value_num(&cache[point].dvalue, DCELL_TYPE);
|
|
|
+
|
|
|
+ if (is_empty) {
|
|
|
+ G_snprintf(buf, 2048, "NULL");
|
|
|
+ }else {
|
|
|
+ if(typeIntern == FCELL_TYPE)
|
|
|
+ G_snprintf(buf, 2048, "%.10f", cache[point].fvalue);
|
|
|
+ if(typeIntern == DCELL_TYPE)
|
|
|
+ G_snprintf(buf, 2048, "%.15f", cache[point].dvalue);
|
|
|
+ }
|
|
|
+
|
|
|
+ db_append_string(&stmt, buf);
|
|
|
+
|
|
|
+ G_snprintf(buf, 2048, " where %s = %d", Fi->key, cache[point].cat);
|
|
|
+
|
|
|
+ db_append_string(&stmt, buf);
|
|
|
+ /* user provides where condition: */
|
|
|
+ if (opt.where->answer) {
|
|
|
+ G_snprintf(buf, 2048, " AND %s", opt.where->answer);
|
|
|
+ db_append_string(&stmt, buf);
|
|
|
+ }
|
|
|
+ G_debug(3, db_get_string(&stmt));
|
|
|
+
|
|
|
+ /* Update table */
|
|
|
+ if (db_execute_immediate(driver, &stmt) == DB_OK) {
|
|
|
+ update_cnt++;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ upderr_cnt++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ G_percent(1, 1, 1);
|
|
|
+
|
|
|
+ G_debug(1, "Committing DB transaction");
|
|
|
+ db_commit_transaction(driver);
|
|
|
+
|
|
|
+ G_free(catexst);
|
|
|
+ db_close_database_shutdown_driver(driver);
|
|
|
+ db_free_string(&stmt);
|
|
|
+
|
|
|
+ /* Report */
|
|
|
+ G_verbose_message(_("%d categories loaded from table"), select);
|
|
|
+ G_verbose_message(_("%d categories loaded from vector"), point_cnt);
|
|
|
+ G_verbose_message(_("%d categories from vector missing in table"), norec_cnt);
|
|
|
+ if (dupl_cnt > 0)
|
|
|
+ G_message(_("%d duplicate categories in vector"), dupl_cnt);
|
|
|
+ if (upderr_cnt > 0)
|
|
|
+ G_warning(_("%d update errors"), upderr_cnt);
|
|
|
+
|
|
|
+ G_done_msg(_("%d records updated."), update_cnt);
|
|
|
+
|
|
|
+ exit(EXIT_SUCCESS);
|
|
|
+}
|