[GRASS-SVN] r69708 - in grass/trunk/lib/raster: . testsuite

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Oct 19 15:17:34 PDT 2016


Author: wenzeslaus
Date: 2016-10-19 15:17:34 -0700 (Wed, 19 Oct 2016)
New Revision: 69708

Added:
   grass/trunk/lib/raster/testsuite/
   grass/trunk/lib/raster/testsuite/rast_parse_color_rule.py
Modified:
   grass/trunk/lib/raster/color_rules.c
Log:
rasterlib: use G_str_to_color() for parsing color table rules

This introduces whatever syntax from G_str_to_color() to Rast_parse_color_rule(),
i.e. not only 'v r g b', 'v r:g:b', and 'v name' is supported, but also any other
separator from G_str_to_color() which now adds comma and semicolon.

Also hexadecimal colors from r69683 are now supported which makes the fact
that comments in color rules (indicated by hash) must start at the first column (character)
more important than before. (Comments starting in the middle of the line are not
currently supported, but from now on they cannot be supported because it would interfere
with color identification because hexadecimal colors are (usually and in G_str_to_color())
indicated by hash.)

Now also NONE/none color is parsed but considered as an syntax error and not reported
separately to the user.

Number of errors (error strings) reported to user was reduced because G_str_to_color()
has limited diagnostics. Specifically, out-of-range RGB values and broken syntax (which
includes and was not distinguished from wrong color names) is reported and syntax
error in color (if the paring of the whole rule was successful).

The commit removes last/only usage of the G_color_values() function. Named
colors for Rast_parse_color_rule() now go from the lib/gis/color_str.c file and
not from the lib/gis/named_colr.c file.


Modified: grass/trunk/lib/raster/color_rules.c
===================================================================
--- grass/trunk/lib/raster/color_rules.c	2016-10-19 15:05:57 UTC (rev 69707)
+++ grass/trunk/lib/raster/color_rules.c	2016-10-19 22:17:34 UTC (rev 69708)
@@ -1,9 +1,9 @@
 /*!
-  \file lib/raster/color_read.c
+  \file lib/raster/color_rules.c
   
   \brief Raster Library - Read and parse color rules file
   
-  (C) 2007 by the GRASS Development Team
+  (C) 2007-2016 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
@@ -15,6 +15,7 @@
 #include <stdio.h>
 
 #include <grass/gis.h>
+#include <grass/colors.h>
 #include <grass/raster.h>
 #include <grass/glocale.h>
 
@@ -28,9 +29,8 @@
 enum rule_error
 {
     CR_OK = 0,
-    CR_ERROR_SYNTAX,
-    CR_ERROR_RGB,
-    CR_ERROR_COLOR,
+    CR_ERROR_RULE_SYNTAX,
+    CR_ERROR_COLOR_SYNTAX,
     CR_ERROR_PERCENT,
     CR_ERROR_VALUE,
 };
@@ -38,16 +38,24 @@
 /*!
   \brief Read color rule
 
+  The val output parameter is always an absolute value and is derived
+  from the rule and the min and max values in case the rule is in percents.
+
+  Always only one of the norm, nval, and dflt output parameters is set
+  to non-zero value, the others are set to zero.
+
+  The return code can be translated to an error message using
+  the Rast_parse_color_rule_error() function.
+
   \param min, max min & max values (used only when color rules are in percentage)
-  \param buf
-  \param val value
+  \param buf string with the color rule
+  \param[out] val value which the color is assigned to
   \param[out] r,g,b color values
-  \param norm
-  \param nval
-  \param dflt
+  \param[out] norm set to non-zero value if the value and color are set
+  \param[out] nval set to non-zero value if rule is for null value
+  \param[out] dflt set to non-zero value if rule specifies the default color
 
-  \return 0 on failure
-  \return 1 on success
+  \returns enum rule_error values (non-zero on failure)
 */
 int Rast_parse_color_rule(DCELL min, DCELL max, const char *buf,
 			  DCELL * val, int *r, int *g, int *b,
@@ -60,26 +68,13 @@
     *norm = *nval = *dflt = 0;
 
     if (sscanf(buf, "%s %[^\n]", value, color) != 2)
-	return CR_ERROR_SYNTAX;
+	return CR_ERROR_RULE_SYNTAX;
 
-    G_chop(color);
+    /* we don't allow 'none' color here (ret == 2) */
+    /* G_str_to_color chops and has only 1 error state */
+    if (G_str_to_color(color, r, g, b) != 1)
+	    return CR_ERROR_COLOR_SYNTAX;
 
-    if (sscanf(color, "%d:%d:%d", r, g, b) == 3 ||
-	sscanf(color, "%d %d %d", r, g, b) == 3) {
-	if (*r < 0 || *r > 255 || *g < 0 || *g > 255 || *b < 0 || *b > 255)
-	    return CR_ERROR_RGB;
-    }
-    else {
-	float fr, fg, fb;
-
-	if (G_color_values(color, &fr, &fg, &fb) < 0)
-	    return CR_ERROR_COLOR;
-
-	*r = (int)(fr * 255.99);
-	*g = (int)(fg * 255.99);
-	*b = (int)(fb * 255.99);
-    }
-
     G_chop(value);
 
     if (G_strcasecmp(value, "default") == 0) {
@@ -121,12 +116,16 @@
     switch (code) {
     case CR_OK:
 	return "";
-    case CR_ERROR_SYNTAX:
-	return _("syntax error");
+    case CR_ERROR_RULE_SYNTAX:
+	return _("syntax error in the color rule");
+    case CR_ERROR_COLOR_SYNTAX:
+	return _("syntax error in the color format");
+/* we no longer distinguish between these two errors
     case CR_ERROR_RGB:
 	return _("R/G/B not in range 0-255");
     case CR_ERROR_COLOR:
 	return _("invalid color name");
+*/
     case CR_ERROR_PERCENT:
 	return _("percentage not in range 0-100");
     case CR_ERROR_VALUE:

Added: grass/trunk/lib/raster/testsuite/rast_parse_color_rule.py
===================================================================
--- grass/trunk/lib/raster/testsuite/rast_parse_color_rule.py	                        (rev 0)
+++ grass/trunk/lib/raster/testsuite/rast_parse_color_rule.py	2016-10-19 22:17:34 UTC (rev 69708)
@@ -0,0 +1,98 @@
+"""Test of raster library string color rule to value and color conversions
+
+ at author Vaclav Petras
+
+ at copyright 2016 by Vaclav Petras and the GRASS Development Team
+
+ at license This program is free software under the 
+GNU General Public License (>=v2). 
+Read the file COPYING that comes with GRASS
+for details
+"""
+
+from ctypes import byref, c_int, c_double
+
+from grass.gunittest.case import TestCase
+from grass.gunittest.main import test
+
+from grass.lib.raster import Rast_parse_color_rule, Rast_parse_color_rule_error
+
+
+# TODO: add also a test class for values
+class ParseSingleColorRuleColorsTestCase(TestCase):
+    """Color-focused test of C function Rast_parse_color_rule()"""
+
+    def convert_rule(self, string, value, red, green, blue):
+        """General test function to convert string to value and color
+
+        value, red, green, blue are expected values.
+        """
+        # we are not testing value, but color, so using these values
+        # so that value and percentage can be used interchangeably
+        min_val = 0.
+        max_val = 100.
+        r = c_int()
+        g = c_int()
+        b = c_int()
+        v = c_double()  # DCELL
+        # not testing any of these three
+        norm = c_int()
+        nv = c_int()
+        default = c_int()
+        ret = Rast_parse_color_rule(min_val, max_val, string, 
+                                    byref(v), byref(r), byref(g), byref(b),
+                                    byref(norm), byref(nv), byref(default))
+        colors = ("{string} -> "
+                  "{v.value}: {r.value}, {g.value}, {b.value}".format(**locals()))
+        error_text = Rast_parse_color_rule_error(ret)
+        self.assertEqual(error_text, "",
+                         msg=("Conversion not successful (%s): %s (%s)"
+                              % (colors, error_text, ret)))
+        self.assertEqual(v.value, value,
+                         msg="Wrong number for value (%s)" % colors)
+        self.assertEqual(r.value, red,
+                         msg="Wrong number for red (%s)" % colors)
+        self.assertEqual(g.value, green,
+                         msg="Wrong number for green (%s)" % colors)
+        self.assertEqual(b.value, blue,
+                         msg="Wrong number for blue (%s)" % colors)
+
+    def test_grass_format_separators(self):
+        """Test GRASS GIS color format with all allowed separators"""
+        self.convert_rule("15% 50,150,250", 15, 50, 150, 250)
+        self.convert_rule("15% 50:150:250", 15, 50, 150, 250)
+        self.convert_rule("15 50;150;250", 15, 50, 150, 250)
+        self.convert_rule("15 50 150 250", 15, 50, 150, 250)
+
+    def test_grass_format_multiple_separators(self):
+        """Test GRASS GIS color format with duplicated separators"""
+        self.convert_rule("15%  50, 150, 250", 15, 50, 150, 250)
+        self.convert_rule("15%   50::150:250", 15, 50, 150, 250)
+        self.convert_rule("15   50  ; 150 ; 250", 15, 50, 150, 250)
+        self.convert_rule("15    50   150  250", 15, 50, 150, 250)
+
+    def test_grass_format_whitespace(self):
+        """Test with whitespace (spaces) around and in the string"""
+        self.convert_rule("    15%    50:150:250    ", 15, 50, 150, 250)
+        self.convert_rule("    15    50  150   250    ", 15, 50, 150, 250)
+
+    def test_html_hash_hex(self):
+        """Test HTML format with hash and hexadecimal (6 letters, #RRGGBB)
+
+        comments (with #) and empty lines are handled in
+        Rast_read_color_rule() by simple first-character test
+        so we have not much here to test
+        """
+        self.convert_rule("15% #A6CEE3", 15, 166, 206, 227)
+        self.convert_rule("15 #33a02c", 15, 51, 160, 44)
+        self.convert_rule("15 #fB9A99", 15, 251, 154, 153)
+
+    def test_grass_named(self):
+        """Test GRASS GIS named colors"""
+        self.convert_rule("15% black   ", 15, 0, 0, 0)
+        self.convert_rule("15    white", 15, 255, 255, 255)
+        self.convert_rule("   15 white", 15, 255, 255, 255)
+
+
+if __name__ == '__main__':
+    test()



More information about the grass-commit mailing list