[GRASS-SVN] r58216 - grass/branches/develbranch_6/vector/v.what.rast

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Nov 14 01:34:55 PST 2013


Author: hamish
Date: 2013-11-14 01:34:55 -0800 (Thu, 14 Nov 2013)
New Revision: 58216

Modified:
   grass/branches/develbranch_6/vector/v.what.rast/description.html
   grass/branches/develbranch_6/vector/v.what.rast/main.c
Log:
add flag to interpolate values from the nearest four cells instead of using nearest neighbor; add flag to allow printing to stdout (merge from trunk)

Modified: grass/branches/develbranch_6/vector/v.what.rast/description.html
===================================================================
--- grass/branches/develbranch_6/vector/v.what.rast/description.html	2013-11-14 06:52:25 UTC (rev 58215)
+++ grass/branches/develbranch_6/vector/v.what.rast/description.html	2013-11-14 09:34:55 UTC (rev 58216)
@@ -1,41 +1,69 @@
 <h2>DESCRIPTION</h2>
 
-<em>v.what.rast</em> reads raster value for each point in the vector and updates <b>col</b> 
-column in vector attribute table by this value. The column should be type
-number (integer, float, double, ... ).
-<br>
-If more points have the same category, attribute value is set to NULL.
-If raster values is NULL, attribute value is set to NULL.
+<em>v.what.rast</em> reads the raster value for each point in the vector map
+and updates <b>column</b> in the vector attribute table by this value. The
+column should be type number (integer, float, double, ... ).
+<p>
+If the <b>-p</b> flag is used, then the attribute table is not updated
+and the results are printed to <tt>stdout</tt>.
+<p>
+If the <b>-i</b> flag is used, then the value to be uploaded to the database
+is interpolated from the four nearest raster cells values using an inverse
+distance weighting method (IDW). This is useful for cases when the vector
+point density is much higher than the raster cell size.
 
+
 <h2>NOTES</h2>
 
+If multiple points have the same category, the attribute value is set to NULL.
+If the raster value is NULL, then attribute value is set to NULL.
+<p>
 <em>v.what.rast</em> operates on the attribute table. To modify the vector
 geometry instead, use <em>v.drape</em>.
+<p>
+Categories and values are output unsorted with the print flag. To sort them
+pipe the output of this module into the UNIX <tt>sort</tt> tool
+(<tt>sort -n</tt>). If you need coordinates, after sorting use
+<em>v.out.ascii</em> and the UNIX <tt>paste</tt> tool
+(<tt>paste -d'|'</tt>). In the case of a NULL result, a "<tt>*</tt>"
+will be printed in lieu of the value.
+<p>
+The interpolation flag is only useful for continuous value raster maps,
+if a categorical raster is given as input the results will be nonsense.
+Since the search window is limited to four raster cells there may still
+be raster cell-edge artifacts visible in the results, this compromise
+has been made for processing speed. If one or more of the nearest four
+raster cells is NULL, then only the raster cells containing values will
+be used in the weighted average.
 
+
 <h2>EXAMPLES</h2>
 
-A) Reading values from raster map at position of vector points, writing these values
-   into a column of the attribute table connected to the vector map:
+A) Reading values from raster map at position of vector points,
+   writing these values into a column of the attribute table
+   connected to the vector map:
 <br>
+
 <div class="code"><pre>
-v.what.rast vect=pnts rast=elevation col=heights
+v.what.rast vector=pnts raster=elevation column=heights
 </pre></div>
 
 <p>
 B) In case of a vector map without attached attribute table, first add
-a new attribute table. This table is then populated with values
-queried from the raster map:
+   a new attribute table. This table is then populated with values
+   queried from the raster map:
 <br>
+
 <div class="code"><pre>
 # create new random vector points map
 v.random pnts n=100
 
 # add new table, link to map
-v.db.addtable pnts col="heights double precision"
+v.db.addtable pnts column="heights double precision"
 
 # query raster map and upload values to vector table into specified column
 g.region rast=elevation -p
-v.what.rast vect=pnts raster=elevation column=heights
+v.what.rast vector=pnts raster=elevation column=heights
 
 # verify new attribute table:
 v.db.select pnts
@@ -44,6 +72,7 @@
 v.univar map=pnts column=heights type=point
 </pre></div>
 
+
 <h2>SEE ALSO</h2>
 
 <em>
@@ -52,11 +81,14 @@
 <a href="v.drape.html">v.drape</a>,
 <a href="v.univar.html">v.univar</a>,
 <a href="v.rast.stats.html">v.rast.stats</a>,
+v.what.rast.buffer (AddOn module),
 <a href="v.what.vect.html">v.what.vect</a>
 </em>
 
-<h2>AUTHOR</h2>
-Radim Blazek
 
+<h2>AUTHORS</h2>
+Radim Blazek<br>
+Hamish Bowman (interpolation)
+
 <p>
 <i>Last changed: $Date$</i>

Modified: grass/branches/develbranch_6/vector/v.what.rast/main.c
===================================================================
--- grass/branches/develbranch_6/vector/v.what.rast/main.c	2013-11-14 06:52:25 UTC (rev 58215)
+++ grass/branches/develbranch_6/vector/v.what.rast/main.c	2013-11-14 09:34:55 UTC (rev 58216)
@@ -1,21 +1,24 @@
-/* ***************************************************************
- * *
- * * MODULE:       v.what.rast
- * * 
- * * AUTHOR(S):    Radim Blazek (using r.what)
- * *               Michael Shapiro, U.S. Army Construction Engineering Research Laboratory (r.what)
- * *               
- * * PURPOSE:      Query raster map
- * *               
- * * COPYRIGHT:    (C) 2001 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.
- * *
- * * TODO: fix user notification if where= is used
- * **************************************************************/
+
+/***************************************************************
+ *
+ * MODULE:	 v.what.rast
+ *
+ * AUTHOR(S):	 Radim Blazek (adapted from r.what)
+ *		 Michael Shapiro, U.S. Army Construction Engineering
+ *                 Research Laboratory (r.what)
+ *               Hamish Bowman, University of Otago, NZ (interpolation)
+ *
+ * PURPOSE:	 Query raster map
+ *
+ * COPYRIGHT:	 (C) 2001-2013 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.
+ *
+ * TODO: fix user notification if where= is used
+ **************************************************************/
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -30,6 +33,7 @@
     int count;			/* nuber of points with category 'cat' */
     int row;
     int col;
+    double x, y;		/* used with interp flag */
     CELL value;
     DCELL dvalue;		/* used for FCELL and DCELL */
 };
@@ -45,15 +49,16 @@
     int i, j, nlines, type, field, cat;
     int fd;
 
-    /* struct Categories RCats; *//* TODO */
+    /* struct Categories RCats; */ /* TODO */
     struct Cell_head window;
     RASTER_MAP_TYPE out_type;
-    CELL *cell;
-    DCELL *dcell;
+    CELL *cell_row, *prev_c_row, *next_c_row;
+    DCELL *dcell_row, *prev_d_row, *next_d_row;
     int width;
     double drow, dcol;
     char buf[2000];
     struct Option *vect_opt, *rast_opt, *field_opt, *col_opt, *where_opt;
+    struct Flag *interp_flag, *print_flag;
     int Cache_size;
     struct order *cache;
     int cur_row;
@@ -78,7 +83,7 @@
     G_gisinit(argv[0]);
 
     module = G_define_module();
-    module->keywords = _("vector, raster, attribute table");
+    module->keywords = _("vector, raster, attribute table, sampling");
     module->description =
 	_("Uploads raster values at positions of vector points to the table.");
 
@@ -96,12 +101,22 @@
     col_opt = G_define_option();
     col_opt->key = "column";
     col_opt->type = TYPE_STRING;
-    col_opt->required = YES;
+    col_opt->required = NO;
     col_opt->description =
 	_("Column name (will be updated by raster values)");
 
     where_opt = G_define_standard_option(G_OPT_WHERE);
 
+    interp_flag = G_define_flag();
+    interp_flag->key = 'i';
+    interp_flag->description =
+	_("Interpolate values from the nearest four cells");
+
+    print_flag = G_define_flag();
+    print_flag->key = 'p';
+    print_flag->description =
+	_("Print categories and values instead of updating the database");
+
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
 
@@ -112,6 +127,9 @@
     Points = Vect_new_line_struct();
     Cats = Vect_new_cats_struct();
 
+    if (!print_flag->answer && !col_opt->answer)
+	G_fatal_error(_("Required parameter <%s> not set"), col_opt->key);
+
     G_get_window(&window);
     Vect_region_box(&window, &box);	/* T and B set to +/- PORT_DOUBLE_MAX */
 
@@ -122,6 +140,7 @@
     Vect_set_open_level(2);
     Vect_open_old(&Map, vect_opt->answer, mapset);
 
+    /* FIXME: if print flag is used then a database doesn't need to exist */
     Fi = Vect_get_field(&Map, field);
     if (Fi == NULL)
 	G_fatal_error(_("Database connection not defined for layer %d"),
@@ -153,20 +172,22 @@
        G_fatal_error ( "Cannot read category file");
      */
 
-    /* Check column type */
-    col_type = db_column_Ctype(driver, Fi->table, col_opt->answer);
+    if (!print_flag->answer) {
+	/* Check column type */
+	col_type = db_column_Ctype(driver, Fi->table, col_opt->answer);
 
-    if (col_type == -1)
-	G_fatal_error(_("Column <%s> not found"), col_opt->answer);
+	if (col_type == -1)
+	    G_fatal_error(_("Column <%s> not found"), col_opt->answer);
 
-    if (col_type != DB_C_TYPE_INT && col_type != DB_C_TYPE_DOUBLE)
-	G_fatal_error(_("Column type not supported"));
+	if (col_type != DB_C_TYPE_INT && col_type != DB_C_TYPE_DOUBLE)
+	    G_fatal_error(_("Column type not supported"));
 
-    if (out_type == CELL_TYPE && col_type == DB_C_TYPE_DOUBLE)
-	G_warning(_("Raster type is integer and column type is float"));
+	if (out_type == CELL_TYPE && col_type == DB_C_TYPE_DOUBLE)
+	    G_warning(_("Raster type is integer and column type is float"));
 
-    if (out_type != CELL_TYPE && col_type == DB_C_TYPE_INT)
-	G_warning(_("Raster type is float and column type is integer, some data lost!!"));
+	if (out_type != CELL_TYPE && col_type == DB_C_TYPE_INT)
+	    G_warning(_("Raster type is float and column type is integer, some data lost!!"));
+    }
 
     /* Read vector points to cache */
     Cache_size = Vect_get_num_primitives(&Map, GV_POINT);
@@ -218,6 +239,10 @@
 
 	cache[point_cnt].row = (int)drow;
 	cache[point_cnt].col = (int)dcol;
+	if (interp_flag->answer) {
+	    cache[point_cnt].x = Points->x[0];
+	    cache[point_cnt].y = Points->y[0];
+	}
 	cache[point_cnt].cat = cat;
 	cache[point_cnt].count = 1;
 	point_cnt++;
@@ -239,6 +264,7 @@
 	    cache[++i] = cache[j];
 	else
 	    cache[i].count++;
+
     point_cnt = i + 1;
 
     G_debug(1, "%d vector points left after removal of duplicates",
@@ -257,10 +283,22 @@
 
     /* Allocate space for raster row */
     if (out_type == CELL_TYPE)
-	cell = G_allocate_c_raster_buf();
+	cell_row = G_allocate_c_raster_buf();
     else
-	dcell = G_allocate_d_raster_buf();
+	dcell_row = G_allocate_d_raster_buf();
 
+    if (interp_flag->answer) {
+	if (out_type == CELL_TYPE) {
+	    prev_c_row = G_allocate_c_raster_buf();
+	    next_c_row = G_allocate_c_raster_buf();
+	}
+	else {
+	    prev_d_row = G_allocate_d_raster_buf();
+	    next_d_row = G_allocate_d_raster_buf();
+	}
+	G_begin_distance_calculations();
+    }
+
     /* Extract raster values from file and store in cache */
     G_debug(1, "Extracting raster values");
 
@@ -272,111 +310,377 @@
 
 	if (cur_row != cache[point].row) {
 	    if (out_type == CELL_TYPE) {
-		if (G_get_c_raster_row(fd, cell, cache[point].row) < 0)
+		if (G_get_c_raster_row(fd, cell_row, cache[point].row) < 0)
 		    G_fatal_error(_("Unable to read raster map <%s> row %d"),
 				  rast_opt->answer, cache[point].row);
+
+		if (interp_flag->answer) {
+		    if (cache[point].row <= 0)
+			G_set_null_value(prev_c_row, window.cols, out_type);
+		    else {
+			if (G_get_c_raster_row
+			    (fd, prev_c_row, cache[point].row - 1) < 0)
+			    G_fatal_error(_("Unable to read raster map <%s> row %d"),
+					  rast_opt->answer,
+					  cache[point].row - 1);
+		    }
+		    if (cache[point].row + 1 > window.rows - 1)
+			G_set_null_value(next_c_row, window.cols, out_type);
+		    else {
+
+			if (G_get_c_raster_row
+			    (fd, next_c_row, cache[point].row + 1) < 0)
+			    G_fatal_error(_("Unable to read raster map <%s> row %d"),
+					  rast_opt->answer,
+					  cache[point].row + 1);
+		    }
+		}
 	    }
 	    else {
-		if (G_get_d_raster_row(fd, dcell, cache[point].row) < 0)
+		if (G_get_d_raster_row(fd, dcell_row, cache[point].row) < 0)
 		    G_fatal_error(_("Unable to read raster map <%s> row %d"),
 				  rast_opt->answer, cache[point].row);
+
+		if (interp_flag->answer) {
+		    if (cache[point].row <= 0)
+			G_set_null_value(prev_d_row, window.cols, out_type);
+		    else {
+
+			if (G_get_d_raster_row
+			    (fd, prev_d_row, cache[point].row - 1) < 0)
+			    G_fatal_error(_("Unable to read raster map <%s> row %d"),
+					  rast_opt->answer,
+					  cache[point].row - 1);
+		    }
+		    if (cache[point].row + 1 > window.rows - 1)
+			G_set_null_value(next_d_row, window.cols, out_type);
+		    else {
+			if (G_get_d_raster_row
+			    (fd, next_d_row, cache[point].row + 1) < 0)
+			    G_fatal_error(_("Unable to read raster map <%s> row %d"),
+					  rast_opt->answer,
+					  cache[point].row + 1);
+		    }
+		}
 	    }
 	}
 	cur_row = cache[point].row;
 
-	if (out_type == CELL_TYPE) {
-	    cache[point].value = cell[cache[point].col];
+
+	if (!interp_flag->answer) {
+	    if (out_type == CELL_TYPE)
+		cache[point].value = cell_row[cache[point].col];
+	    else
+		cache[point].dvalue = dcell_row[cache[point].col];
 	}
 	else {
-	    cache[point].dvalue = dcell[cache[point].col];
-	}
-    }				/* point loop */
+	    /* do four-way IDW */
+	    /* TODO: optimize, parallelize, and function-ize! */
+	    double distance[4], weight[4];
+	    double weightsum, valweight;
+	    int col_offset, row_offset;
 
-    /* Update table from cache */
-    G_debug(1, "Updating db table");
+	    weightsum = valweight = 0;
 
-    /* select existing categories to array (array is sorted) */
-    select = db_select_int(driver, Fi->table, Fi->key, NULL, &catexst);
 
-    db_begin_transaction(driver);
+	    if (cache[point].x <
+		G_col_to_easting(cache[point].col,
+				 &window) + window.ew_res / 2)
+		col_offset = -1;
+	    else
+		col_offset = +1;
 
-    norec_cnt = update_cnt = upderr_cnt = dupl_cnt = 0;
+	    if (cache[point].y >
+		G_row_to_northing(cache[point].row,
+				  &window) - window.ns_res / 2)
+		row_offset = -1;
+	    else
+		row_offset = +1;
 
-    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++;
-	}
 
-	/* 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;
-	}
+	    distance[0] = G_distance(cache[point].x, cache[point].y,
+				     G_col_to_easting(cache[point].col,
+						      &window) +
+				     window.ew_res / 2,
+				     G_row_to_northing(cache[point].row,
+						       &window) -
+				     window.ns_res / 2);
 
-	sprintf(buf, "update %s set %s = ", Fi->table, col_opt->answer);
+	    distance[1] = G_distance(cache[point].x, cache[point].y,
+				     G_col_to_easting(cache[point].col +
+						      col_offset,
+						      &window) +
+				     window.ew_res / 2,
+				     G_row_to_northing(cache[point].row,
+						       &window) -
+				     window.ns_res / 2);
 
-	db_set_string(&stmt, buf);
+	    if (row_offset == -1) {
+		distance[2] = G_distance(cache[point].x, cache[point].y,
+					 G_col_to_easting(cache[point].col +
+							  col_offset,
+							  &window) +
+					 window.ew_res / 2,
+					 G_row_to_northing(cache[point].row -
+							   1,
+							   &window) -
+					 window.ns_res / 2);
+		distance[3] =
+		    G_distance(cache[point].x, cache[point].y,
+			       G_col_to_easting(cache[point].col,
+						&window) + window.ew_res / 2,
+			       G_row_to_northing(cache[point].row - 1,
+						 &window) -
+			       window.ns_res / 2);
+	    }
+	    else {
+		distance[2] = G_distance(cache[point].x, cache[point].y,
+					 G_col_to_easting(cache[point].col +
+							  col_offset,
+							  &window) +
+					 window.ew_res / 2,
+					 G_row_to_northing(cache[point].row + 1,
+							   &window) -
+					 window.ns_res / 2);
+		distance[3] =
+		    G_distance(cache[point].x, cache[point].y,
+			       G_col_to_easting(cache[point].col,
+						&window) + window.ew_res / 2,
+			       G_row_to_northing(cache[point].row + 1,
+						 &window) -
+			       window.ns_res / 2);
+	    }
 
-	if (out_type == CELL_TYPE) {
-	    if (cache[point].count > 1 ||
-		G_is_c_null_value(&cache[point].value)) {
-		sprintf(buf, "NULL");
+
+	    if (out_type == CELL_TYPE) {
+
+		CELL nearby_c_val[4];
+
+		/* avoid infinite weights */
+		if (distance[0] < GRASS_EPSILON) {
+		    cache[point].value = cell_row[cache[point].col];
+		    continue;
+		}
+
+		nearby_c_val[0] = cell_row[cache[point].col];
+
+		if (cache[point].col + col_offset < 0 ||
+		    cache[point].col + col_offset >= window.cols)    /* UNTESTED */
+		    G_set_null_value(&nearby_c_val[1], 1, out_type); /* UNTESTED */
+		else
+		    nearby_c_val[1] = cell_row[cache[point].col + col_offset];
+
+		if (row_offset == -1) {
+		    if (cache[point].col + col_offset < 0 ||
+			cache[point].col + col_offset >= window.cols)
+			G_set_null_value(&nearby_c_val[2], 1, out_type);
+		    else
+			nearby_c_val[2] =
+			    prev_c_row[cache[point].col + col_offset];
+
+		    nearby_c_val[3] = prev_c_row[cache[point].col];
+		}
+		else {
+		    if (cache[point].col + col_offset < 0 ||
+			cache[point].col + col_offset >= window.cols)
+			G_set_null_value(&nearby_c_val[2], 1, out_type);
+		    else
+			nearby_c_val[2] =
+			    next_c_row[cache[point].col + col_offset];
+
+		    nearby_c_val[3] = next_c_row[cache[point].col];
+		}
+
+		for (i = 0; i < 4; i++) {
+		    if (!G_is_null_value(&nearby_c_val[i], out_type)) {
+			weight[i] = 1.0 / (distance[i] * distance[i]);
+			weightsum += weight[i];
+			valweight += weight[i] * nearby_c_val[i];
+		    }
+		}
+
+		cache[point].value = valweight / weightsum;
 	    }
 	    else {
-		sprintf(buf, "%d ", cache[point].value);
+		DCELL nearby_d_val[4];
+
+		/* avoid infinite weights */
+		if (distance[0] < GRASS_EPSILON) {
+		    cache[point].dvalue = dcell_row[cache[point].col];
+		    continue;
+		}
+
+		nearby_d_val[0] = dcell_row[cache[point].col];
+
+		if (cache[point].col + col_offset < 0 ||
+		    cache[point].col + col_offset >= window.cols)
+		    G_set_null_value(&nearby_d_val[1], 1, out_type);
+		else
+
+		    nearby_d_val[1] =
+			dcell_row[cache[point].col + col_offset];
+
+		if (row_offset == -1) {
+		    if (cache[point].col + col_offset < 0 ||
+			cache[point].col + col_offset >= window.cols)
+			G_set_null_value(&nearby_d_val[2], 1, out_type);
+		    else
+			nearby_d_val[2] =
+			    prev_d_row[cache[point].col + col_offset];
+
+		    nearby_d_val[3] = prev_d_row[cache[point].col];
+		}
+		else {
+		    if (cache[point].col + col_offset < 0 ||
+			cache[point].col + col_offset >= window.cols)
+			G_set_null_value(&nearby_d_val[2], 1, out_type);
+		    else
+			nearby_d_val[2] =
+			    next_d_row[cache[point].col + col_offset];
+
+		    nearby_d_val[3] = next_d_row[cache[point].col];
+		}
+
+		for (i = 0; i < 4; i++) {
+		    if (!G_is_null_value(&nearby_d_val[i], out_type)) {
+			weight[i] = 1.0 / (distance[i] * distance[i]);
+			weightsum += weight[i];
+			valweight += weight[i] * nearby_d_val[i];
+		    }
+		}
+
+		cache[point].dvalue = valweight / weightsum;
 	    }
 	}
-	else {			/* FCELL or DCELL */
-	    if (cache[point].count > 1 ||
-		G_is_d_null_value(&cache[point].dvalue)) {
-		sprintf(buf, "NULL");
+    }				/* point loop */
+    G_close_cell(fd);
+
+    if (print_flag->answer) {
+	dupl_cnt = 0;
+
+	G_message("%s|value", Fi->key);
+
+	for (point = 0; point < point_cnt; point++) {
+	    if (cache[point].count > 1) {
+		G_warning(_("Multiple points (%d) of category %d, value set to 'NULL'"),
+			  cache[point].count, cache[point].cat);  /* TODO: improve message */
+		dupl_cnt++;
 	    }
-	    else {
-		sprintf(buf, "%.*g", width, cache[point].dvalue);
+
+	    fprintf(stdout, "%d|", cache[point].cat);
+
+	    if (out_type == CELL_TYPE) {
+		if (cache[point].count > 1 ||
+		    G_is_c_null_value(&cache[point].value)) {
+		    fprintf(stdout, "*");
+		}
+		else
+		    fprintf(stdout, "%d", cache[point].value);
 	    }
+	    else {		/* FCELL or DCELL */
+		if (cache[point].count > 1 ||
+		    G_is_d_null_value(&cache[point].dvalue)) {
+		    fprintf(stdout, "*");
+		}
+		else
+		    fprintf(stdout, "%.*g", width, cache[point].dvalue);
+	    }
+	    fprintf(stdout, "\n");
 	}
-	db_append_string(&stmt, buf);
+    }
+    else {
+	/* Update table from cache */
+	G_debug(1, "Updating db table");
 
-	sprintf(buf, " where %s = %d", Fi->key, cache[point].cat);
-	db_append_string(&stmt, buf);
-	/* user provides where condition: */
-	if (where_opt->answer) {
-	    sprintf(buf, " AND %s", where_opt->answer);
+	/* 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;
+
+	for (point = 0; point < point_cnt; point++) {
+	    if (cache[point].count > 1) {
+		G_warning(_("Multiple 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;
+	    }
+
+	    sprintf(buf, "update %s set %s = ", Fi->table, col_opt->answer);
+
+	    db_set_string(&stmt, buf);
+
+	    if (out_type == CELL_TYPE) {
+		if (cache[point].count > 1 ||
+		    G_is_c_null_value(&cache[point].value)) {
+		    sprintf(buf, "NULL");
+		}
+		else
+		    sprintf(buf, "%d ", cache[point].value);
+	    }
+	    else {		/* FCELL or DCELL */
+		if (cache[point].count > 1 ||
+		    G_is_d_null_value(&cache[point].dvalue)) {
+		    sprintf(buf, "NULL");
+		}
+		else
+		    sprintf(buf, "%.*g", width, cache[point].dvalue);
+	    }
 	    db_append_string(&stmt, buf);
+
+	    sprintf(buf, " where %s = %d", Fi->key, cache[point].cat);
+	    db_append_string(&stmt, buf);
+	    /* user provides where condition: */
+	    if (where_opt->answer) {
+		sprintf(buf, " AND %s", where_opt->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_debug(3, db_get_string(&stmt));
+	G_percent(1, 1, 1);
 
-	/* Update table */
-	if (db_execute_immediate(driver, &stmt) == DB_OK) {
-	    update_cnt++;
-	}
-	else {
-	    upderr_cnt++;
-	}
+	G_debug(1, "Committing DB transaction");
+	db_commit_transaction(driver);
+	G_free(catexst);
+	db_close_database_shutdown_driver(driver);
+	db_free_string(&stmt);
     }
 
-    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_message(_("%d categories loaded from table"), select);
     G_message(_("%d categories loaded from vector"), point_cnt);
-    G_message(_("%d categories from vector missing in table"), norec_cnt);
+
+    if (!print_flag->answer)
+	G_message(_("%d categories from vector missing in table"), norec_cnt);
+
     G_message(_("%d duplicate categories in vector"), dupl_cnt);
-    if (!where_opt->answer)
-	G_message(_("%d records updated"), update_cnt);
-    G_message(_("%d update errors"), upderr_cnt);
 
+    if (!print_flag->answer) {
+	if (!where_opt->answer)
+	    G_message(_("%d records updated"), update_cnt);
+	G_message(_("%d update errors"), upderr_cnt);
+    }
     exit(EXIT_SUCCESS);
 }
 



More information about the grass-commit mailing list