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;
}
Aggregations