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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 252ab98b78 Adjust the default sample dimensions created by the GeoTIFF
reader. If a "no data" category is added, then a "data" category should also be
added.
252ab98b78 is described below
commit 252ab98b788da5290e30f0edb37c98806861ba53
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Jul 18 20:07:22 2025 +0200
Adjust the default sample dimensions created by the GeoTIFF reader.
If a "no data" category is added, then a "data" category should also be
added.
---
.../org/apache/sis/coverage/SampleDimension.java | 10 ++-
.../apache/sis/image/privy/ColorScaleBuilder.java | 17 ++--
.../main/org/apache/sis/storage/landsat/Band.java | 13 ++--
.../sis/storage/geotiff/ImageFileDirectory.java | 90 ++++++++++++++++------
.../sis/storage/modifier/CoverageModifier.java | 42 ++++++----
.../main/org/apache/sis/gui/map/StatusBar.java | 55 +++++++------
.../org/apache/sis/gui/map/ValuesFormatter.java | 25 +++---
.../org/apache/sis/gui/map/ValuesFromCoverage.java | 9 ++-
8 files changed, 166 insertions(+), 95 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/SampleDimension.java
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/SampleDimension.java
index ae04583836..f70aead042 100644
---
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/SampleDimension.java
+++
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/SampleDimension.java
@@ -542,7 +542,7 @@ public class SampleDimension implements Serializable {
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Alexis Manin (Geomatys)
- * @version 1.4
+ * @version 1.5
* @since 1.0
*/
public static class Builder {
@@ -1150,7 +1150,8 @@ public class SampleDimension implements Serializable {
* or {@code null} for a default "data" name.
* @param samples the minimum and maximum sample values in the
category. Element class is usually
* {@link Integer}, but {@link Float} and {@link
Double} types are accepted as well.
- * @param toUnits the transfer function from sample values to real
values in the specified units.
+ * @param toUnits the transfer function from sample values to real
values in the specified units,
+ * or {@code null} if none.
* @param units the units of measurement of values after
conversion by the transfer function,
* or {@code null} if unknown or not applicable.
* @return {@code this}, for method call chaining.
@@ -1160,10 +1161,13 @@ public class SampleDimension implements Serializable {
* @see TransferFunction
*/
public Builder addQuantitative(CharSequence name, NumberRange<?>
samples, MathTransform1D toUnits, Unit<?> units) {
- ArgumentChecks.ensureNonNull("toUnits", toUnits);
+ ArgumentChecks.ensureNonNull("samples", samples);
if (name == null) {
name = DATA;
}
+ if (toUnits == null) {
+ toUnits = Category.identity();
+ }
add(new Category(name, samples, toUnits, units, toNaN));
return this;
}
diff --git
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java
index f813f2a9da..3d6872bc5a 100644
---
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java
+++
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java
@@ -413,7 +413,7 @@ public final class ColorScaleBuilder {
var samples = NumberRange.create(1, true, MAX_VALUE, true);
builder.setBackground(TRANSPARENT, 0).addQuantitative(COLOR_INDEX,
samples, defaultRange);
} else {
- builder.addQuantitative(COLOR_INDEX, defaultRange, identity(),
null);
+ builder.addQuantitative(COLOR_INDEX, defaultRange, null, null);
}
target = builder.build();
/*
@@ -711,15 +711,12 @@ reuse: if (source != null) {
*/
public MathTransform1D getSampleToIndexValues() throws
NoninvertibleTransformException {
checkInitializationStatus(true);
- return (target != null) ?
target.getTransferFunction().orElseGet(ColorScaleBuilder::identity).inverse() :
identity();
- }
-
- /**
- * Returns the identity transform.
- *
- * @see Category#identity()
- */
- private static MathTransform1D identity() {
+ if (target != null) {
+ MathTransform1D toTarget =
target.getTransferFunction().orElse(null);
+ if (toTarget != null) {
+ return toTarget.inverse();
+ }
+ }
return (MathTransform1D) MathTransforms.identity(1);
}
}
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
index 96ffd4e4e4..c07058fda3 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
@@ -37,7 +37,6 @@ import
org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
import org.apache.sis.metadata.iso.content.DefaultSampleDimension;
import org.apache.sis.metadata.iso.content.DefaultBand;
import org.apache.sis.coverage.SampleDimension;
-import org.apache.sis.measure.NumberRange;
import org.apache.sis.measure.Units;
import static org.apache.sis.util.privy.CollectionsExt.first;
@@ -175,8 +174,8 @@ final class Band extends GridResourceWrapper implements
CoverageModifier {
sd.setOffset (sampleDimension.getOffset());
sd.setUnits (sampleDimension.getUnits());
if (sampleDimension instanceof DefaultBand) {
- final DefaultBand s = (DefaultBand) sampleDimension;
- final DefaultBand t = (DefaultBand) sd;
+ final var s = (DefaultBand) sampleDimension;
+ final var t = (DefaultBand) sd;
t.setPeakResponse(s.getPeakResponse());
t.setBoundUnits(s.getBoundUnits());
}
@@ -191,8 +190,8 @@ final class Band extends GridResourceWrapper implements
CoverageModifier {
public SampleDimension customize(final BandSource source, final
SampleDimension.Builder dimension) {
if (isMain(source) && source.getBandIndex() == 0) {
dimension.setName(identifier);
- final NumberRange<?> sampleRange =
source.getSampleRange().orElse(null);
- if (sampleRange != null) {
+ dimension.categories().clear();
+ source.getSampleRange().ifPresent((sampleRange) -> {
final Number min = sampleRange.getMinValue();
final Number max = sampleRange.getMaxValue();
final Double scale = sampleDimension.getScaleFactor();
@@ -203,10 +202,10 @@ final class Band extends GridResourceWrapper implements
CoverageModifier {
dimension.addQualitative(null, 0);
if (lower == 0) lower = 1;
}
- dimension.addQuantitative(this.band.group.measurement,
lower, max.intValue(),
+ dimension.addQuantitative(band.group.measurement, lower,
max.intValue(),
scale, offset,
sampleDimension.getUnits());
}
- }
+ });
}
return dimension.build();
}
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index 618c6709f3..f15e51650e 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -347,6 +347,8 @@ final class ImageFileDirectory extends DataCube {
/**
* The minimum or maximum sample value found in the image, with one value
per band.
* May be a vector of length 1 if the same single value applies to all
bands.
+ *
+ * @see #getValidValues(int, double)
*/
private Vector minValues, maxValues;
@@ -1157,8 +1159,11 @@ final class ImageFileDirectory extends DataCube {
}
/**
- * Computes the minimal or maximal values of the given vector. Those
vectors do not need to have the same length.
+ * Computes the minimal or maximal values of the given vector.
+ * Those vectors do not need to have the same length.
* One of those two vector will be modified in-place.
+ * This is a paranoiac safety in case a tag for minimal or maximum values
appears more than once.
+ * This duplication is not so unlikely since each extremum can be
described by two different tags.
*
* @param a the first vector, or {@code null} if none.
* @param b the new vector to combine with the existing one. Cannot be
null.
@@ -1399,8 +1404,8 @@ final class ImageFileDirectory extends DataCube {
metadata.addNewBand(sampleDimensions.get(band));
metadata.setBitPerSample(bitsPerSample);
if (!metadata.hasSampleValueRange()) {
- if (isMinSpecified)
metadata.addMinimumSampleValue(minValues.doubleValue(Math.min(band,
minValues.size()-1)));
- if (isMaxSpecified)
metadata.addMaximumSampleValue(maxValues.doubleValue(Math.min(band,
maxValues.size()-1)));
+ if (isMinSpecified)
metadata.addMinimumSampleValue(extremum(minValues, band).doubleValue());
+ if (isMaxSpecified)
metadata.addMaximumSampleValue(extremum(maxValues, band).doubleValue());
}
}
/*
@@ -1512,27 +1517,37 @@ final class ImageFileDirectory extends DataCube {
}
/**
- * Information about which band is subject to modification. This
information is given to
- * {@link CoverageModifier} for allowing users to modify name, metadata or
sample dimensions.
+ * Returns the minimum and maximum non-fill values in the specified band.
+ * This is the values explicitly defined in <abbr>TIFF</abbr> tags if
present,
+ * otherwise the values derived from the data type if it is an integer
type.
+ *
+ * @param band the band for which to get the minimum and maximum
values.
+ * @param exclude the fill value to exclude, or NaN if none.
+ * @return the minimum and maximum values in the specified band.
*/
- private final class Source extends CoverageModifier.BandSource {
- /** Creates a new source for the specified band. */
- Source(final int bandIndex, final DataType dataType) {
- super(reader.store, index, bandIndex, samplesPerPixel, dataType);
+ private Optional<NumberRange<?>> getValidValues(final int band, final
double exclude) {
+ Number min = extremum(minValues, band);
+ if (min != null) {
+ Number max = extremum(maxValues, band);
+ if (max != null) {
+ return Optional.of(NumberRange.createBestFit(
+ sampleFormat == FLOAT,
+ min, min.doubleValue() != exclude, // Always true
if `exclude` is NaN.
+ max, max.doubleValue() != exclude));
+ }
}
+ return Optional.empty();
+ }
- /** Computes the range of sample values if requested. */
- @Override public Optional<NumberRange<?>> getSampleRange() {
- final Vector minValues = ImageFileDirectory.this.minValues;
- final Vector maxValues = ImageFileDirectory.this.maxValues;
- if (minValues != null && maxValues != null) {
- final int band = getBandIndex();
- return Optional.of(NumberRange.createBestFit(sampleFormat ==
FLOAT,
- minValues.get(Math.min(band, minValues.size()-1)),
true,
- maxValues.get(Math.min(band, maxValues.size()-1)),
true));
- }
- return Optional.empty();
- }
+ /**
+ * Extracts a value from the vector of minimum or maximum values.
+ *
+ * @param values the vector of minimum or maximum values.
+ * @param band the index of the valud to get.
+ * @return the value for the given band, or {@code null} if none.
+ */
+ private static Number extremum(final Vector values, final int band) {
+ return (values == null) ? null : values.get(Math.min(band,
values.size() - 1));
}
/**
@@ -1575,10 +1590,39 @@ final class ImageFileDirectory extends DataCube {
} else {
builder.setName(band + 1);
}
- builder.setBackground(fill);
+ /*
+ * If a "no data" value is present, declare both as
background value and a qualitative category.
+ * The latter will cause the image to be converted to
floating point during resample operations,
+ * with "no data" replaced by NaN. For completeness, we
need to declare the range of real values.
+ */
+ final Optional<NumberRange<?>> sampleRange;
+ if (fill != null) {
+ builder.setBackground(fill);
+ sampleRange = getValidValues(band, fill.doubleValue());
+ sampleRange.ifPresent((range) -> {
+ if (!range.containsAny(fill)) {
+ builder.addQuantitative(null, range, null,
null);
+ builder.addQualitative(null, fill, fill);
+ }
+ });
+ } else {
+ // Do not declare any category. It will be understood
as "visualization only".
+ sampleRange = null;
+ }
+ /*
+ * Give a change to users to replace the above default
categories by their own.
+ * The information provided to the user include the
optional range of values,
+ * computed only when requested if it was not already
computed.
+ */
final SampleDimension sd;
if (isIndexValid) {
- sd = reader.store.customizer.customize(new
Source(band, dataType), builder);
+ var source = new
CoverageModifier.BandSource(reader.store, index, band, samplesPerPixel,
dataType) {
+ @Override public Optional<NumberRange<?>>
getSampleRange() {
+ if (sampleRange != null) return sampleRange;
+ return getValidValues(getBandIndex(),
Double.NaN);
+ }
+ };
+ sd = reader.store.customizer.customize(source,
builder);
} else {
sd = builder.build();
}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/modifier/CoverageModifier.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/modifier/CoverageModifier.java
index c8e2d63585..b2ab2fff1b 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/modifier/CoverageModifier.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/modifier/CoverageModifier.java
@@ -79,7 +79,7 @@ public interface CoverageModifier {
* @param connector the storage connector from which to get the modifier.
* @return the modifier to use, never {@code null}.
*/
- static CoverageModifier getOrDefault(StorageConnector connector) {
+ public static CoverageModifier getOrDefault(StorageConnector connector) {
final CoverageModifier customizer =
connector.getOption(DataOptionKey.COVERAGE_MODIFIER);
return (customizer != null) ? customizer : DEFAULT;
}
@@ -330,22 +330,44 @@ public interface CoverageModifier {
/**
* Invoked when a sample dimension is created in a coverage.
- * The data store invokes this method with a builder initialized to a
default name,
+ * The data store invokes this method with a {@link SampleDimension}
builder initialized to a default name,
* which may be the {@linkplain SampleDimension.Builder#setName(int) band
number}.
- * The builder may also contain a {@linkplain
SampleDimension.Builder#setBackground(Number) background value}.
+ * The builder may also contain a {@linkplain
SampleDimension.Builder#setBackground(Number) background value}
+ * and {@linkplain SampleDimension.Builder#categories() categories}.
* Implementations can override this method for setting a better name
- * or for declaring the meaning of sample values (by adding categories).
+ * or for declaring the meaning of sample values (by replacing categories).
*
* <h4>Default implementation</h4>
- * The default implementation creates a "no data" category for the
- * {@linkplain SampleDimension.Builder#getBackground() background value}
if such value exists.
+ * The default implementation returns {@code dimensions.build()} with no
modification on the given builder.
+ *
+ * <h4>Example: measurement data</h4>
+ * The following example declares that the values 0 means "no data".
* The presence of such "no data" category will cause the raster to be
converted to floating point
* values before operations such as {@code resample}, in order to replace
those "no data" by NaN values.
- * If this replacement is not desired, then subclass should override this
method for example like below:
+ * When a "no data" category is declared, it is strongly recommended to
also declare the range of real data.
+ * The following example declares the range 1 to 255 inclusive.
*
* {@snippet lang="java" :
* @Override
* public SampleDimension customize(BandSource source,
SampleDimension.Builder dimension) {
+ * dimension.categories().clear(); // Discard the categories
created by the store.
+ * dimension.addQualitative(null, 0); // Declare value 0 as "no
data".
+ * dimension.addQuantitative("Some name for my data", 1, 255, null);
+ * return dimension.build();
+ * }
+ * }
+ *
+ * See the various {@code addQuantitative(…)} methods for information
about how to declare a transfer function
+ * (a conversion from pixel values to the unit of measurement).
+ *
+ * <h4>Example: visualization only</h4>
+ * If the pixel values have no meaning other than visualization, this
method can be overridden
+ * as below for making sure that they raster is not interpreted as
measurement data:
+ *
+ * {@snippet lang="java" :
+ * @Override
+ * public SampleDimension customize(BandSource source,
SampleDimension.Builder dimension) {
+ * dimension.categories().clear(); // Discard the categories
created by the store.
* return dimension.build();
* }
* }
@@ -359,12 +381,6 @@ public interface CoverageModifier {
default SampleDimension customize(final BandSource source, final
SampleDimension.Builder dimension)
throws DataStoreException
{
- final Number fill = dimension.getBackground();
- if (fill != null) {
- @SuppressWarnings({"unchecked", "rawtypes"})
- NumberRange<?> samples = new NumberRange(fill.getClass(), fill,
true, fill, true);
- dimension.addQualitative(null, samples);
- }
return dimension.build();
}
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
index 5392aa1577..85590488cd 100644
--- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
+++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
@@ -125,7 +125,7 @@ import org.opengis.coordinate.MismatchedDimensionException;
* {@link #setLocalCoordinates(double, double)} explicitly instead.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.5
* @since 1.1
*/
public class StatusBar extends Widget implements EventHandler<MouseEvent> {
@@ -147,6 +147,11 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
*/
private static final int VALUES_PADDING = 9;
+ /**
+ * Minimal size of the text field where sample values are shown.
+ */
+ private static final int MINIMAL_VALUES_SIZE = 60;
+
/**
* The container of controls making the status bar.
* Contains {@link #message}, {@link #position} and {@link #sampleValues}.
@@ -1038,6 +1043,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
*
* @see #positionReferenceSystem
*/
+ @SuppressWarnings("StringEquality")
private void setFormatCRS(final CoordinateReferenceSystem crs, final
Quantity<Length> accuracy) {
int dimension = localToPositionCRS.getTargetDimensions();
GeneralDirectPosition target = targetCoordinates;
@@ -1060,7 +1066,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
precisionUnit = null;
String text = null;
if (crs != null) {
- final StringBuilder b = new StringBuilder().append('(');
+ final var b = new StringBuilder().append('(');
final CoordinateSystem cs = crs.getCoordinateSystem();
dimension = (cs != null) ? cs.getDimension() : 0; //
Paranoiac check (should never be null).
for (int i=0; i<dimension; i++) {
@@ -1474,6 +1480,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
/**
* Returns {@code true} if the position contains a valid coordinates.
*/
+ @SuppressWarnings("StringEquality")
private boolean isPositionVisible() {
if (position.isVisible()) {
final String text = position.getText();
@@ -1491,23 +1498,23 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
*/
private void setSampleValuesVisible(final boolean visible) {
final ObservableList<Node> c = view.getChildren();
- Label view = sampleValues;
+ Label sampleView = sampleValues;
if (visible) {
- if (view == null) {
- view = new Label();
- view.setAlignment(Pos.CENTER_RIGHT);
- view.setTextAlignment(TextAlignment.RIGHT);
- view.setMinWidth(Label.USE_PREF_SIZE);
- view.setMaxWidth(Label.USE_PREF_SIZE);
- sampleValues = view;
+ if (sampleView == null) {
+ sampleView = new Label();
+ sampleView.setAlignment(Pos.CENTER_RIGHT);
+ sampleView.setTextAlignment(TextAlignment.RIGHT);
+ sampleView.setMinWidth(Label.USE_PREF_SIZE);
+ sampleView.setMaxWidth(Label.USE_PREF_SIZE);
+ sampleValues = sampleView;
}
- if (c.lastIndexOf(view) < 0) {
+ if (c.lastIndexOf(sampleView) < 0) {
final Separator separator = new
Separator(Orientation.VERTICAL);
- c.addAll(separator, view);
+ c.addAll(separator, sampleView);
}
- } else if (view != null) {
- view.setText(null);
- int i = c.lastIndexOf(view);
+ } else if (sampleView != null) {
+ sampleView.setText(null);
+ int i = c.lastIndexOf(sampleView);
if (i >= 0) {
c.remove(i);
if (--i >= 0) {
@@ -1533,14 +1540,14 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
final boolean computeSizeOfSampleValues(final String prototype, final
Iterable<String> others) {
setSampleValuesVisible(prototype != null && !prototype.isEmpty());
if (isSampleValuesVisible) {
- final Label view = sampleValues;
- view.setText(prototype);
- view.setPrefWidth(Label.USE_COMPUTED_SIZE); //
Enable `prefWidth(…)` computation.
- double width = view.prefWidth(view.getHeight());
- final double max = Math.max(width * 1.25, 200);
// Arbitrary limit.
+ final Label sampleView = sampleValues;
+ sampleView.setText(prototype);
+ sampleView.setPrefWidth(Label.USE_COMPUTED_SIZE); //
Enable `prefWidth(…)` computation.
+ double width = sampleView.prefWidth(sampleView.getHeight());
+ final double max = Math.max(width * 1.25, 200); //
Arbitrary limit.
for (final String other : others) {
- view.setText(other);
- final double cw = view.prefWidth(view.getHeight());
+ sampleView.setText(other);
+ final double cw = sampleView.prefWidth(sampleView.getHeight());
if (cw > width) {
width = cw;
if (width > max) {
@@ -1549,11 +1556,11 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
}
}
}
- view.setText(null);
+ sampleView.setText(null);
if (!(width > 0)) { // May be 0 if canvas is not
yet added to scene graph.
return false;
}
- view.setPrefWidth(width + VALUES_PADDING);
+ sampleView.setPrefWidth(Math.max(width + VALUES_PADDING,
MINIMAL_VALUES_SIZE));
}
return true;
}
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFormatter.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFormatter.java
index 7eb697a26a..5fd734d7d3 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFormatter.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFormatter.java
@@ -103,8 +103,8 @@ final class ValuesFormatter extends
ValuesUnderCursor.Formatter {
private final FieldPosition field;
/**
- * Unit symbol to write after each value.
- * Array shall not be modified after construction.
+ * Unit symbol to write after each value, including the leading space
separator if needed.
+ * The content of this array shall not be modified after construction.
*/
private final String[] units;
@@ -188,9 +188,9 @@ final class ValuesFormatter extends
ValuesUnderCursor.Formatter {
* if selected or not. We do that on the assumption that the same
format and symbol
* are typically shared by all bands.
*/
- final Map<Integer,NumberFormat> sharedFormats = new HashMap<>();
- final Map<Unit<?>,String> sharedSymbols = new HashMap<>();
- final UnitFormat unitFormat = new UnitFormat(locale);
+ final var sharedFormats = new HashMap<Integer,NumberFormat>();
+ final var sharedSymbols = new HashMap<Unit<?>,String>();
+ final var unitFormat = new UnitFormat(locale);
for (int b=0; b<numBands; b++) {
/*
* Build the list of texts to show for missing values. A coverage
can have
@@ -215,8 +215,9 @@ final class ValuesFormatter extends
ValuesUnderCursor.Formatter {
* Infer a number of fraction digits to use for the resolution of
sample values in each band.
*/
final SampleDimension isd = sd.forConvertedValues(false);
- final Integer nf = isd.getTransferFunctionFormula().map(
- (formula) -> suggestFractionDigits(formula,
isd)).orElse(DEFAULT_FORMAT);
+ final Integer nf = isd.getTransferFunctionFormula()
+ .map((formula) -> suggestFractionDigits(formula, isd))
+ .orElse(DEFAULT_FORMAT);
/*
* Create number formats with a number of fraction digits inferred
from sample value resolution.
* The same format instances are shared when possible. Keys are
the number of fraction digits.
@@ -284,7 +285,7 @@ final class ValuesFormatter extends
ValuesUnderCursor.Formatter {
final String setSelectedBands(final BitSet selection, final String[]
labels, final HashSet<String> others) {
synchronized (buffer) {
final List<SampleDimension> bands =
evaluator.getCoverage().getSampleDimensions();
- final StringBuilder names = new StringBuilder().append('(');
+ final var names = new StringBuilder().append('(');
buffer.setLength(0);
for (int i = -1; (i = selection.nextSetBit(i+1)) >= 0;) {
if (buffer.length() != 0) {
@@ -293,9 +294,11 @@ final class ValuesFormatter extends
ValuesUnderCursor.Formatter {
}
names.append(labels[i]);
final int start = buffer.length();
- final Comparable<?>[] sampleValues =
bands.get(i).forConvertedValues(true)
- .getSampleRange().map((r) -> new Comparable<?>[]
{r.getMinValue(), r.getMaxValue()})
- .orElseGet(() -> new Comparable<?>[] {0xFFFF});
// Arbitrary value.
+ final Comparable<?>[] sampleValues = bands.get(i)
+ .forConvertedValues(true)
+ .getSampleRange()
+ .map((range) -> new Comparable<?>[]
{range.getMinValue(), range.getMaxValue()})
+ .orElseGet(() -> new Comparable<?>[] {0xFFFF}); //
Arbitrary value.
for (final Comparable<?> value : sampleValues) {
final int end = buffer.length();
sampleFormats[i].format(value, buffer, field);
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFromCoverage.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFromCoverage.java
index 3ff489d440..98acefe32f 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFromCoverage.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/ValuesFromCoverage.java
@@ -176,7 +176,7 @@ final class ValuesFromCoverage extends ValuesUnderCursor
implements ChangeListen
* (u,v) components of velocity vectors, which we want to
keep together by default.
*/
final int numBands = bands.size();
- final CheckMenuItem[] menuItems = new
CheckMenuItem[numBands];
+ final var menuItems = new CheckMenuItem[numBands];
final BitSet selection = selectedBands;
selection.clear();
selection.set(0, (numBands <= 3) ? numBands : 1, true);
@@ -227,15 +227,16 @@ final class ValuesFromCoverage extends ValuesUnderCursor
implements ChangeListen
if (refreshing) {
return null;
}
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final ValuesFormatter formatter = this.formatter;
if (formatter != null && needsBandRefresh && usePrototype()) {
final ObservableList<MenuItem> menus = valueChoices.getItems();
- final String[] labels = new String[menus.size()];
+ final var labels = new String[menus.size()];
for (int i=0; i<labels.length; i++) {
labels[i] = menus.get(i).getText();
}
- final HashSet<String> others = new HashSet<>();
- final BitSet selection = (BitSet) selectedBands.clone();
+ final var others = new HashSet<String>();
+ final var selection = (BitSet) selectedBands.clone();
BackgroundThreads.execute(new Task<String>() {
/** Invoked in background thread for configuring the
formatter. */
@Override protected String call() {