Search in sources :

Example 1 with IllegalSampleDimensionException

use of org.apache.sis.coverage.IllegalSampleDimensionException in project sis by apache.

the class RasterResource method createSampleDimension.

/**
 * Creates a single sample dimension for the given variable.
 *
 * @param  builder  the builder to use for creating the sample dimension.
 * @param  band     the data for which to create a sample dimension.
 * @param  index    index in the variable dimension identified by {@link #bandDimension}.
 */
private SampleDimension createSampleDimension(final SampleDimension.Builder builder, final Variable band, final int index) {
    /*
         * Take the minimum and maximum values as determined by Apache SIS through the Convention class.  The UCAR library
         * is used only as a fallback. We give precedence to the range computed by Apache SIS instead of the range given
         * by UCAR because we need the range of packed values instead of the range of converted values.
         */
    NumberRange<?> range;
    if (!createEnumeration(builder, band) && (range = band.getValidRange()) != null)
        try {
            final MathTransform1D mt = band.getTransferFunction().getTransform();
            if (!mt.isIdentity() && range instanceof MeasurementRange<?>) {
                /*
                 * Heuristic rule defined in UCAR documentation (see EnhanceScaleMissingUnsigned):
                 * if the type of the range is equal to the type of the scale, and the type of the
                 * data is not wider, then assume that the minimum and maximum are real values.
                 * This is identified in Apache SIS by the range given as a MeasurementRange.
                 */
                final MathTransform1D inverse = mt.inverse();
                boolean isMinIncluded = range.isMinIncluded();
                boolean isMaxIncluded = range.isMaxIncluded();
                double minimum = inverse.transform(range.getMinDouble());
                double maximum = inverse.transform(range.getMaxDouble());
                if (maximum < minimum) {
                    final double swap = maximum;
                    maximum = minimum;
                    minimum = swap;
                    final boolean sb = isMaxIncluded;
                    isMaxIncluded = isMinIncluded;
                    isMinIncluded = sb;
                }
                if (band.getDataType().number <= Numbers.LONG && minimum >= Long.MIN_VALUE && maximum <= Long.MAX_VALUE) {
                    range = NumberRange.create(Math.round(minimum), isMinIncluded, Math.round(maximum), isMaxIncluded);
                } else {
                    range = NumberRange.create(minimum, isMinIncluded, maximum, isMaxIncluded);
                }
            }
            /*
             * Range may be empty if min/max values declared in the netCDF files are erroneous,
             * or if we have not read them correctly (edu.ucar:cdm:4.6.13 sometime confuses an
             * unsigned integer with a signed one).
             */
            if (range.isEmpty()) {
                band.warning(RasterResource.class, "getSampleDimensions", Resources.Keys.IllegalValueRange_4, band.getFilename(), band.getName(), range.getMinValue(), range.getMaxValue());
            } else {
                String name = band.getDescription();
                if (name == null)
                    name = band.getName();
                if (band.getRole() == VariableRole.DISCRETE_COVERAGE) {
                    builder.addQualitative(name, range);
                } else {
                    builder.addQuantitative(name, range, mt, band.getUnit());
                }
            }
        } catch (TransformException e) {
            /*
             * This exception may happen in the call to `inverse.transform`, when we tried to convert
             * a range of measurement values (in the unit of measurement) to a range of sample values.
             * If we failed to do that, we will not add quantitative category. But we still can add
             * qualitative categories for "no data" sample values in the rest of this method.
             */
            warning(e);
        }
    /*
         * Adds the "missing value" or "fill value" as qualitative categories.  If a value has both roles, use "missing value"
         * as category name. If the sample values are already real values, then the "no data" values have been replaced by NaN
         * values by Variable.replaceNaN(Object). The qualitative categories constructed below must be consistent with the NaN
         * values created by `replaceNaN`.
         */
    boolean setBackground = true;
    int ordinal = band.hasRealValues() ? 0 : -1;
    final CharSequence[] names = new CharSequence[2];
    for (final Map.Entry<Number, Object> entry : band.getNodataValues().entrySet()) {
        final Number n;
        if (ordinal >= 0) {
            // Must be consistent with Variable.replaceNaN(Object).
            n = MathFunctions.toNanFloat(ordinal++);
        } else {
            // Should be real number, made unique by the HashMap.
            n = entry.getKey();
        }
        CharSequence name;
        final Object label = entry.getValue();
        if (label instanceof Integer) {
            // Bit 0 set (value 1) = pad value, bit 1 set = missing value.
            final int role = (Integer) label;
            // i=1 if role is only pad value, i=0 otherwise.
            final int i = (role == Convention.FILL_VALUE_MASK) ? 1 : 0;
            name = names[i];
            if (name == null) {
                name = Vocabulary.formatInternational(i == 0 ? Vocabulary.Keys.MissingValue : Vocabulary.Keys.FillValue);
                names[i] = name;
            }
            if (setBackground & (role & Convention.FILL_VALUE_MASK) != 0) {
                // Declare only one fill value.
                setBackground = false;
                builder.setBackground(name, n);
                continue;
            }
        } else {
            name = (CharSequence) label;
        }
        builder.addQualitative(name, n, n);
    }
    /*
         * At this point we have the list of all categories to put in the sample dimension.
         * Now create the sample dimension using the variable short name as dimension name.
         * The index is appended to the name only if bands are all in the same variable.
         */
    String name = band.getName();
    if (bandDimension >= 0) {
        name = Strings.toIndexed(name, index);
    }
    builder.setName(name);
    SampleDimension sd;
    try {
        sd = builder.build();
    } catch (IllegalSampleDimensionException e) {
        /*
             * This error may happen if we have overlapping ranges of sample values.
             * Abandon all categories. We do not keep the quantitative category because
             * using it without taking in account the "no data" values may be dangerous.
             */
        builder.categories().clear();
        sd = builder.build();
        warning(e);
    }
    return sd;
}
Also used : MeasurementRange(org.apache.sis.measure.MeasurementRange) TransformException(org.opengis.referencing.operation.TransformException) SampleDimension(org.apache.sis.coverage.SampleDimension) IllegalSampleDimensionException(org.apache.sis.coverage.IllegalSampleDimensionException) MathTransform1D(org.opengis.referencing.operation.MathTransform1D) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

HashMap (java.util.HashMap)1 Map (java.util.Map)1 IllegalSampleDimensionException (org.apache.sis.coverage.IllegalSampleDimensionException)1 SampleDimension (org.apache.sis.coverage.SampleDimension)1 MeasurementRange (org.apache.sis.measure.MeasurementRange)1 MathTransform1D (org.opengis.referencing.operation.MathTransform1D)1 TransformException (org.opengis.referencing.operation.TransformException)1