sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 02/02: Add SampleDimension.Builder.mapQualitative(…) method for specifying explicitly the NaN value to map to a sample value.
Date Fri, 17 Jul 2020 18:07:57 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit fa27367258ac47ab12c4247df12862b39e442b70
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Jul 17 11:05:52 2020 +0200

    Add SampleDimension.Builder.mapQualitative(…) method for specifying explicitly the NaN
value to map to a sample value.
---
 .../org/apache/sis/coverage/SampleDimension.java   | 65 +++++++++++++++++++++-
 .../apache/sis/coverage/SampleDimensionTest.java   | 65 +++++++++++++++++++++-
 2 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
index 34925c3..8b86eab 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
@@ -36,7 +36,9 @@ import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.internal.feature.Resources;
 import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.measure.NumberRange;
+import org.apache.sis.math.MathFunctions;
 import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.iso.Names;
 import org.apache.sis.util.Numbers;
@@ -517,7 +519,7 @@ public class SampleDimension implements Serializable {
      * After properties have been set, the sample dimension is created by invoking {@link
#build()}.
      *
      * @author  Martin Desruisseaux (IRD, Geomatys)
-     * @version 1.0
+     * @version 1.1
      * @since   1.0
      * @module
      */
@@ -803,6 +805,67 @@ public class SampleDimension implements Serializable {
         }
 
         /**
+         * Adds a qualitative category for the given sample value mapped to the specified
converted NaN value.
+         * The given {@code converted} value must be {@linkplain Float#isNaN(float) a NaN
value}
+         * (not necessarily the {@link Float#NaN} canonical value)
+         * and that value shall not have been used by another category.
+         *
+         * <div class="note"><b>Implementation note:</b>
+         * this convenience method delegates to {@link #mapQualitative(CharSequence, NumberRange,
float)}.</div>
+         *
+         * @param  name       the category name as a {@link String} or {@link InternationalString}
object,
+         *                    or {@code null} for a default "no data" name.
+         * @param  sample     the sample value as a real or integer number.
+         * @param  converted  the converted value to map to the given sample value.
+         *                    {@code Float.isNaN(converted)} must be {@code true}.
+         * @return {@code this}, for method call chaining.
+         * @throws IllegalArgumentException if {@code converted} is not a NaN value.
+         *
+         * @see MathFunctions#toNanFloat(int)
+         *
+         * @since 1.1
+         */
+        public Builder mapQualitative(CharSequence name, final Number sample, final float
converted) {
+            ArgumentChecks.ensureNonNull("sample", sample);
+            return mapQualitative(name, range(sample.getClass(), sample, sample), converted);
+        }
+
+        /**
+         * Adds a qualitative category for the given samples values mapped to the specified
converted NaN value.
+         * The given {@code converted} value must be {@linkplain Float#isNaN(float) a NaN
value}
+         * (not necessarily the {@link Float#NaN} canonical value)
+         * and that value shall not have been used by another category.
+         *
+         * <p>The {@code addQualitative(…)} methods select automatically a converted
value.
+         * The {@code mapQualitative(…)} methods are for the less common case where caller
+         * needs to control which converted NaN value is mapped to the samples values.</p>
+         *
+         * @param  name       the category name as a {@link String} or {@link InternationalString}
object,
+         *                    or {@code null} for a default "no data" name.
+         * @param  samples    the minimum and maximum sample values in the category.
+         * @param  converted  the converted value to map to the given sample values.
+         *                    {@code Float.isNaN(converted)} must be {@code true}.
+         * @return {@code this}, for method call chaining.
+         * @throws IllegalArgumentException if {@code converted} is not a NaN value.
+         *
+         * @see MathFunctions#toNanFloat(int)
+         *
+         * @since 1.1
+         */
+        public Builder mapQualitative(CharSequence name, final NumberRange<?> samples,
final float converted) {
+            ArgumentChecks.ensureNonNull("samples", samples);
+            final int ordinal = MathFunctions.toNanOrdinal(converted);
+            if (!toNaN.add(ordinal)) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.ValueAlreadyDefined_1,
"NaN #" + ordinal));
+            }
+            if (name == null) {
+                name = Vocabulary.formatInternational(Vocabulary.Keys.Nodata);
+            }
+            add(new Category(name, samples, null, null, (v) -> ordinal));
+            return this;
+        }
+
+        /**
          * Constructs a quantitative category mapping samples to real values in the specified
range.
          * Sample values in the {@code samples} range will be mapped to real values in the
{@code converted} range
          * through a linear equation of the form:
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/SampleDimensionTest.java
b/core/sis-feature/src/test/java/org/apache/sis/coverage/SampleDimensionTest.java
index a2d9f50..2d81b75 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/SampleDimensionTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/SampleDimensionTest.java
@@ -35,13 +35,26 @@ import static org.opengis.test.Assert.*;
  * Tests {@link SampleDimension}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   1.0
  * @module
  */
 public final strictfp class SampleDimensionTest extends TestCase {
     /**
      * Tests a sample dimension having only qualitative categories.
+     * Expected value:
+     *
+     * {@preformat text
+     * ┌────────┬─────────┐
+     * │ Values │  Name   │
+     * ╞════════╧═════════╡
+     * │ Some data        │
+     * ├────────┬─────────┤
+     * │     1  │ Clouds  │
+     * │     2  │ Lands   │
+     * │   255  │ Missing │
+     * └────────┴─────────┘
+     * }
      */
     @Test
     public void testQualitative() {
@@ -61,7 +74,57 @@ public final strictfp class SampleDimensionTest extends TestCase {
     }
 
     /**
+     * Tests {@link SampleDimension.Builder#mapQualitative(CharSequence, Number, float)}.
+     * Expected result (not that "Values" column differ from NaN numbers, which is the
+     * purpose of this test).
+     *
+     * {@preformat text
+     * ┌───────────┬───────────────┬─────────────┐
+     * │  Values   │   Measures    │    Name     │
+     * ╞═══════════╧═══════════════╧═════════════╡
+     * │ Temperature                             │
+     * ├───────────┬───────────────┬─────────────┤
+     * │        1  │ NaN #1        │ Clouds      │
+     * │        3  │ NaN #2        │ No data     │
+     * │ [5 … 254] │ [-2.0 … 35.0] │ Temperature │
+     * │      255  │ NaN #4        │ Lands       │
+     * └───────────┴───────────────┴─────────────┘
+     * }
+     */
+    @Test
+    public void testMapQualitative() {
+        final SampleDimension dimension = new SampleDimension.Builder()
+                .addQualitative("Clouds",  1)
+                .mapQualitative("Lands", 255, MathFunctions.toNanFloat(4))
+                .mapQualitative("No data", 3, MathFunctions.toNanFloat(2))
+                .addQuantitative("Temperature", NumberRange.create( 5, true, 254, true),
+                                                NumberRange.create(-2, true,  35, true))
+                .build();
+
+        assertArrayEquals("nodataValues", new Integer[] {1, 3, 255}, dimension.getNoDataValues().toArray());
+        final Object[] padValues = dimension.forConvertedValues(true).getNoDataValues().toArray();
+        for (int i=0; i<padValues.length; i++) {
+            padValues[i] = MathFunctions.toNanOrdinal(((Float) padValues[i]));
+        }
+        assertArrayEquals("nodataValues", new Integer[] {1, 2, 4}, padValues);
+    }
+
+    /**
      * Tests a sample dimension having one quantitative category and a few "no data" values.
+     * Expected value:
+     *
+     * {@preformat text
+     * ┌────────────┬──────────────────┬─────────────┐
+     * │   Values   │     Measures     │    Name     │
+     * ╞════════════╧══════════════════╧═════════════╡
+     * │ Temperature                                 │
+     * ├────────────┬──────────────────┬─────────────┤
+     * │         0  │ NaN #0           │ Fill value  │
+     * │         1  │ NaN #1           │ Clouds      │
+     * │ [10 … 200) │ [6.00 … 25.00)°C │ Temperature │
+     * │       255  │ NaN #255         │ Lands       │
+     * └────────────┴──────────────────┴─────────────┘
+     * }
      */
     @Test
     public void testQuantitativeWithMissingValues() {


Mime
View raw message