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 1aebac6 Provide more information in GridGeometry.toString() and
complete the testFromGeospatialEnvelope().
1aebac6 is described below
commit 1aebac6decbd299413bff80ca7f510fd7853c34f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Oct 15 18:59:23 2018 +0200
Provide more information in GridGeometry.toString() and complete the
testFromGeospatialEnvelope().
---
.../org/apache/sis/coverage/grid/GridExtent.java | 67 ++++-
.../org/apache/sis/coverage/grid/GridGeometry.java | 281 ++++++++++++++-------
.../apache/sis/coverage/grid/GridGeometryTest.java | 20 +-
.../org/apache/sis/util/resources/Vocabulary.java | 35 +++
.../sis/util/resources/Vocabulary.properties | 7 +
.../sis/util/resources/Vocabulary_fr.properties | 7 +
6 files changed, 309 insertions(+), 108 deletions(-)
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index aeefa6e..9ebd773 100644
--- a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -16,11 +16,14 @@
*/
package org.apache.sis.coverage.grid;
+import java.util.Map;
+import java.util.HashMap;
import java.util.Arrays;
import java.util.Optional;
+import java.util.Locale;
import java.io.Serializable;
-import java.util.Map;
-import java.util.HashMap;
+import java.io.IOException;
+import java.io.UncheckedIOException;
import org.opengis.geometry.DirectPosition;
import org.opengis.metadata.spatial.DimensionNameType;
import org.opengis.referencing.cs.AxisDirection;
@@ -30,6 +33,7 @@ import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.util.collection.WeakValueHashMap;
import org.apache.sis.internal.metadata.AxisDirections;
import org.apache.sis.internal.raster.Resources;
@@ -593,20 +597,59 @@ public class GridExtent implements Serializable {
*/
@Override
public String toString() {
- final TableAppender table = new TableAppender(" ");
+ final StringBuilder out = new StringBuilder(256);
+ appendTo(out, Vocabulary.getResources((Locale) null), false);
+ return out.toString();
+ }
+
+ /**
+ * Writes a string representation of this grid envelope in the given
buffer.
+ *
+ * @param out where to write the string representation.
+ * @param vocabulary resources for some words, or {@code null} if not yet
fetched.
+ * @param tree whether to format lines of a tree in the margin on
the left.
+ */
+ final void appendTo(final StringBuilder out, final Vocabulary vocabulary,
final boolean tree) {
+ final TableAppender table = new TableAppender(out, "");
final int dimension = getDimension();
for (int i=0; i<dimension; i++) {
- String name;
- if ((types == null) || (name = Types.getCodeLabel(types[i])) ==
null) {
- name = Integer.toString(i);
+ CharSequence name;
+ if ((types == null) || (name = Types.getCodeTitle(types[i])) ==
null) {
+ name = vocabulary.getString(Vocabulary.Keys.Dimension_1, i);
}
- table.append(name).append(':').nextColumn();
- table.setCellAlignment(TableAppender.ALIGN_RIGHT);
- table.append(Long.toString(ordinates[i])).nextColumn();
- table.append("to").nextColumn();
- table.append(Long.toString(ordinates[i + dimension])).nextLine();
+ final long lower = ordinates[i];
+ final long upper = ordinates[i + dimension];
table.setCellAlignment(TableAppender.ALIGN_LEFT);
+ if (tree) {
+ branch(table, i < dimension - 1);
+ }
+ table.append(name).append(": ").nextColumn();
+ table.append('[').nextColumn();
+ table.setCellAlignment(TableAppender.ALIGN_RIGHT);
+ table.append(Long.toString(lower)).append(" … ").nextColumn();
+ table.append(Long.toString(upper)).append("] ") .nextColumn();
+
table.append('(').append(vocabulary.getString(Vocabulary.Keys.CellCount_1,
+ Long.toUnsignedString(upper - lower +
1))).append(')').nextLine();
+ }
+ flush(table);
+ }
+
+ /**
+ * Formats the symbols on the left side of a node in a tree.
+ */
+ static void branch(final TableAppender table, final boolean hasMore) {
+ table.append(hasMore ? '├' : '└').append("─ ");
+ }
+
+ /**
+ * Writes the content of given table without throwing {@link IOException}.
+ * Shall be invoked only when the destination is known to be {@link
StringBuilder}.
+ */
+ static void flush(final TableAppender table) {
+ try {
+ table.flush();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
}
- return table.toString();
}
}
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index 47d800f..122eba6 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -18,8 +18,12 @@ package org.apache.sis.coverage.grid;
import java.util.Arrays;
import java.util.Objects;
+import java.util.Locale;
import java.io.Serializable;
+import java.io.IOException;
+import java.io.UncheckedIOException;
import java.awt.image.RenderedImage; // For javadoc only.
+import org.opengis.metadata.Identifier;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.datum.PixelInCell;
@@ -27,18 +31,23 @@ import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.cs.CoordinateSystem;
import org.apache.sis.math.MathFunctions;
import org.apache.sis.geometry.Envelopes;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.geometry.ImmutableEnvelope;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.operation.transform.PassThroughTransform;
import org.apache.sis.internal.raster.Resources;
+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.CharSequences;
import org.apache.sis.util.Debug;
+import org.apache.sis.io.TableAppender;
/**
@@ -323,7 +332,7 @@ public class GridGeometry implements Serializable {
}
this.gridToCRS = PixelTranslation.translate(gridToCRS, anchor,
PixelInCell.CELL_CENTER);
this.cornerToCRS = PixelTranslation.translate(gridToCRS, anchor,
PixelInCell.CELL_CORNER);
- Matrix matrix = MathTransforms.getMatrix(gridToCRS);
+ Matrix scales = MathTransforms.getMatrix(gridToCRS);
int numToIgnore = 1;
if (envelope != null && cornerToCRS != null) {
GeneralEnvelope env = Envelopes.transform(cornerToCRS.inverse(),
envelope);
@@ -331,15 +340,15 @@ public class GridGeometry implements Serializable {
env = extent.toCRS(cornerToCRS);
env.setCoordinateReferenceSystem(envelope.getCoordinateReferenceSystem());
this.envelope = new ImmutableEnvelope(env);
- if (matrix == null) {
- matrix = gridToCRS.derivative(extent.getCentroid()); //
'gridToCRS' can not be null if 'cornerToCRS' is non-null.
+ if (scales == null) {
+ scales = gridToCRS.derivative(extent.getCentroid()); //
'gridToCRS' can not be null if 'cornerToCRS' is non-null.
numToIgnore = 0;
}
} else {
this.extent = null;
this.envelope = ImmutableEnvelope.castOrCopy(envelope);
}
- resolution = (matrix != null) ? resolution(matrix, numToIgnore) : null;
+ resolution = (scales != null) ? resolution(scales, numToIgnore) : null;
nonLinears = findNonLinearTargets(gridToCRS);
}
@@ -788,12 +797,12 @@ public class GridGeometry implements Serializable {
* Current implementation is equivalent to the following:
*
* {@preformat java
- * return toString(EXTENT | CRS | GRID_TO_CRS | RESOLUTION);
+ * return toString(EXTENT | ENVELOPE | CRS | GRID_TO_CRS | RESOLUTION);
* }
*/
@Override
public String toString() {
- return toString(EXTENT | CRS | GRID_TO_CRS | RESOLUTION);
+ return toString(EXTENT | ENVELOPE | CRS | GRID_TO_CRS | RESOLUTION);
}
/**
@@ -801,114 +810,204 @@ public class GridGeometry implements Serializable {
* The string representation is for debugging purpose only and may change
* in any future SIS version.
*
- * @param bitmask any combination of {@link #EXTENT}, {@link #CRS},
- * {@link #GRID_TO_CRS} and {@link #RESOLUTION}.
+ * @param bitmask combination of {@link #EXTENT}, {@link #ENVELOPE},
+ * {@link #CRS}, {@link #GRID_TO_CRS} and {@link #RESOLUTION}.
* @return a string representation of the given elements.
*/
@Debug
public String toString(final int bitmask) {
- if ((bitmask & ~(EXTENT | CRS | GRID_TO_CRS | RESOLUTION)) != 0) {
+ if ((bitmask & ~(EXTENT | ENVELOPE | CRS | GRID_TO_CRS | RESOLUTION))
!= 0) {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.IllegalArgumentValue_2, "bitmask", bitmask));
}
- final boolean visible = Integer.bitCount(bitmask) >= 2;
- final int dimension = (extent != null) ? extent.getDimension() : 0;
- final StringBuilder buffer = new StringBuilder();
- if ((bitmask & EXTENT) != 0) {
- appendLabel(buffer, "Grid size", visible);
- if (dimension == 0) {
- buffer.append("unspecified");
- } else {
+ return new Formatter(bitmask).toString();
+ }
+
+ /**
+ * Helper class for formatting a {@link GridGeometry} instance.
+ */
+ private final class Formatter {
+ /**
+ * Combination of {@link #EXTENT}, {@link #ENVELOPE},
+ * {@link #CRS}, {@link #GRID_TO_CRS} and {@link #RESOLUTION}.
+ */
+ private final int bitmask;
+
+ /**
+ * Where to write the {@link GridGeometry} string representation.
+ */
+ private final StringBuilder buffer;
+
+ /**
+ * Platform-specific end-of-line characters.
+ */
+ private final String lineSeparator;
+
+ /**
+ * Localized words.
+ */
+ private final Vocabulary vocabulary;
+
+ /**
+ * The locale for the texts. Not used for numbers and dates.
+ */
+ private final Locale locale;
+
+ /**
+ * The coordinate reference system, or {@code null} if none.
+ */
+ private final CoordinateReferenceSystem crs;
+
+ /**
+ * The coordinate system, or {@code null} if none.
+ */
+ private final CoordinateSystem cs;
+
+ /**
+ * Creates a new formatter for the given combination of {@link
#EXTENT}, {@link #ENVELOPE},
+ * {@link #CRS}, {@link #GRID_TO_CRS} and {@link #RESOLUTION}.
+ */
+ Formatter(final int bitmask) {
+ this.bitmask = bitmask;
+ lineSeparator = System.lineSeparator();
+ locale = Locale.getDefault(Locale.Category.DISPLAY);
+ vocabulary = Vocabulary.getResources(locale);
+ buffer = new StringBuilder(512);
+ crs = (envelope != null) ?
envelope.getCoordinateReferenceSystem() : null;
+ cs = (crs != null) ? crs.getCoordinateSystem() : null;
+ }
+
+ /**
+ * Returns a string representation of the enclosing {@link
GridGeometry} instance.
+ */
+ @Override
+ public final String toString() {
+ /*
+ * Example: Grid extent
+ * ├─ Dimension 0: [370 … 389] (20 cells)
+ * └─ Dimension 1: [ 41 … 340] (300 cells)
+ */
+ if (section(EXTENT, Vocabulary.Keys.GridExtent, extent)) {
+ extent.appendTo(buffer, vocabulary, true);
+ }
+ /*
+ * Example: Envelope
+ * ├─ Geodetic latitude: -69.75 … 80.25 Δφ = 0.5°
+ * └─ Geodetic longitude: 4.75 … 14.75 Δλ = 0.5°
+ */
+ if (section(ENVELOPE, Vocabulary.Keys.Envelope, envelope)) {
+ final boolean appendResolution = (bitmask & RESOLUTION) != 0
&& resolution != null;
+ final TableAppender table = new TableAppender(buffer, "");
+ final int dimension = envelope.getDimension();
+ for (int i=0; i<dimension; i++) {
+ final CoordinateSystemAxis axis = (cs != null) ?
cs.getAxis(i) : null;
+ final String name = (axis != null) ?
axis.getName().getCode() :
+ vocabulary.getString(Vocabulary.Keys.Dimension_1,
i);
+ GridExtent.branch(table, i < dimension - 1);
+ table.append(name).append(": ").nextColumn();
+ table.setCellAlignment(TableAppender.ALIGN_RIGHT);
+
table.append(Double.toString(envelope.getLower(i))).nextColumn();
+ table.setCellAlignment(TableAppender.ALIGN_LEFT);
+ table.append(" …
").append(Double.toString(envelope.getUpper(i)));
+ if (appendResolution) {
+ final boolean isLinear = (i < Long.SIZE) &&
(nonLinears & (1L << i)) == 0;
+ table.nextColumn();
+ table.append(" Δ");
+ if (axis != null) {
+ table.append(axis.getAbbreviation());
+ }
+ table.nextColumn();
+ table.append(' ').append(isLinear ? '=' :
'≈').append(' ');
+ appendResolution(table, i);
+ }
+ table.nextLine();
+ }
+ GridExtent.flush(table);
+ } else if (section(RESOLUTION, Vocabulary.Keys.Resolution,
resolution)) {
/*
- * Get the string representations of all GridExtent numbers
before to write them.
- * We do that for computing their length, in order to apply
right alignment.
+ * Example: Resolution
+ * └─ 0.5° × 0.5°
*/
- final int NUM_PROPERTIES = 3;
- final int[] columnSizes = new int[dimension];
- final String[] values = new String[dimension *
NUM_PROPERTIES]; // Will contain (span, low, high) tuples.
- for (int i=0; i<values.length; i++) {
- final long value;
- int margin = 0;
- final int dim = i / NUM_PROPERTIES;
- switch (i % NUM_PROPERTIES) {
- case 0: value = extent.getSize(dim); if (i != 0)
margin = 1; break;
- case 1: value = extent.getLow (dim); break;
- case 2: value = extent.getHigh(dim); break;
- default: throw new AssertionError(i);
- }
- final int length = (values[i] =
String.valueOf(value)).length() + margin;
- if (length > columnSizes[dim]) columnSizes[dim] = length;
+ String separator = "└─ ";
+ for (int i=0; i<resolution.length; i++) {
+ appendResolution(buffer.append(separator), i);
+ separator = " × ";
+ }
+ buffer.append(lineSeparator);
+ }
+ /*
+ * Example: Coordinate reference system
+ * └─ EPSG:4326 — WGS 84 (φ,λ)
+ */
+ if (section(CRS, Vocabulary.Keys.CoordinateRefSys, crs)) {
+ buffer.append("└─ ");
+ final Identifier id = IdentifiedObjects.getIdentifier(crs,
null);
+ if (id != null) {
+ buffer.append(IdentifiedObjects.toString(id)).append(" —
");
}
- for (int t=0; t<NUM_PROPERTIES; t++) {
- String separator = ", ";
- switch (t) {
- case 0: separator = " ×"; break;
- case 1: appendLabel(buffer, "Grid low", visible);
break;
- case 2: appendLabel(buffer, "Grid high", visible);
break;
+ buffer.append(crs.getName()).append(lineSeparator);
+ }
+ /*
+ * Example: Conversion
+ * └─ 2D → 2D non linear in 2
+ */
+ if (section(GRID_TO_CRS, Vocabulary.Keys.Conversion, gridToCRS)) {
+ final Matrix matrix = MathTransforms.getMatrix(gridToCRS);
+ if (matrix != null) {
+ String separator = "└─ ";
+ for (final CharSequence line :
CharSequences.splitOnEOL(Matrices.toString(matrix))) {
+
buffer.append(separator).append(line).append(lineSeparator);
+ separator = " ";
}
- for (int i=0; i<dimension; i++) {
- if (i != 0) buffer.append(separator);
- final String value = values[i*NUM_PROPERTIES + t];
- buffer.append(CharSequences.spaces(columnSizes[i] -
value.length())).append(value);
+ } else {
+ buffer.append("└─
").append(gridToCRS.getSourceDimensions()).append("D → ")
+
.append(gridToCRS.getTargetDimensions()).append('D');
+ long nonLinearDimensions = nonLinears;
+ String separator = " non linear in ";
+ while (nonLinearDimensions != 0) {
+ final int i =
Long.numberOfTrailingZeros(nonLinearDimensions);
+ nonLinearDimensions &= ~(1L << i);
+ buffer.append(separator).append(cs != null ?
cs.getAxis(i).getName() : String.valueOf(i));
+ separator = ", ";
}
+ buffer.append(lineSeparator);
}
}
+ return buffer.toString();
}
- CoordinateSystem cs = null;
- if ((bitmask & CRS) != 0) {
- appendLabel(buffer, "CRS", visible);
- CoordinateReferenceSystem crs;
- if (envelope == null || (crs =
envelope.getCoordinateReferenceSystem()) == null) {
- buffer.append("unspecified");
- } else {
- buffer.append(crs.getName());
- cs = crs.getCoordinateSystem();
- }
- }
- if ((bitmask & GRID_TO_CRS) != 0) {
- appendLabel(buffer, "Conversion", visible);
- if (gridToCRS == null) {
- buffer.append("unspecified");
- } else {
- buffer.append(gridToCRS.getSourceDimensions()).append("D → ")
- .append(gridToCRS.getTargetDimensions()).append('D');
- long nonLinearDimensions = nonLinears;
- String separator = " non linear in ";
- while (nonLinearDimensions != 0) {
- final int i =
Long.numberOfTrailingZeros(nonLinearDimensions);
- nonLinearDimensions &= ~(1L << i);
- buffer.append(separator).append(cs != null ?
cs.getAxis(i).getName() : String.valueOf(i));
- separator = ", ";
+
+ /**
+ * Starts a new section for the given property.
+ *
+ * @param property one of {@link #EXTENT}, {@link #ENVELOPE}, {@link
#CRS}, {@link #GRID_TO_CRS} and {@link #RESOLUTION}.
+ * @param title the {@link Vocabulary} key for the title to show
for this section, if formatted.
+ * @param value the value to be formatted in that section.
+ * @return {@code true} if the caller shall format the value.
+ */
+ private boolean section(final int property, final short title, final
Object value) {
+ if ((bitmask & property) != 0) {
+
buffer.append(vocabulary.getString(title)).append(lineSeparator);
+ if (value != null) {
+ return true;
}
+ buffer.append("└─
").append(vocabulary.getString(Vocabulary.Keys.Unspecified)).append(lineSeparator);
}
+ return false;
}
- if ((bitmask & RESOLUTION) != 0) {
- appendLabel(buffer, "Resolution", visible);
- if (resolution == null) {
- buffer.append("unspecified");
- } else for (int i=0; i<resolution.length; i++) {
- if (i != 0) buffer.append(" × ");
- buffer.append((float) resolution[i]);
+
+ private void appendResolution(final Appendable out, final int
dimension) {
+ try {
+ out.append(Float.toString((float) resolution[dimension]));
if (cs != null) {
- final String unit =
String.valueOf(cs.getAxis(i).getUnit());
+ final String unit =
String.valueOf(cs.getAxis(dimension).getUnit());
if (unit.isEmpty() ||
Character.isLetterOrDigit(unit.codePointAt(0))) {
- buffer.append(' ');
+ out.append(' ');
}
- buffer.append(unit);
+ out.append(unit);
}
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
}
}
- return buffer.append(System.lineSeparator()).toString();
- }
-
- /**
- * Appends the given text to the given buffer, followed by colon and
spaces.
- * Adjusted for the specific needs of {@link #toString()} implementation.
- */
- private static void appendLabel(final StringBuilder appendTo, final String
label, final boolean visible) {
- if (appendTo.length() != 0) appendTo.append(System.lineSeparator());
- if (visible) {
- appendTo.append(label).append(':').append(CharSequences.spaces(12
- label.length()));
- }
}
}
diff --git
a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
index 1da415f..5c34e88 100644
---
a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
+++
b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
@@ -46,7 +46,7 @@ public final strictfp class GridGeometryTest extends TestCase
{
/**
* Verifies grid extent coordinates.
*/
- private static void assertExtentEquals(final GridExtent extent, final
long[] low, final long[] high) {
+ private static void assertExtentEquals(final long[] low, final long[]
high, final GridExtent extent) {
assertArrayEquals("extent.low", low, extent.getLow()
.getCoordinateValues());
assertArrayEquals("extent.high", high,
extent.getHigh().getCoordinateValues());
}
@@ -68,7 +68,7 @@ public final strictfp class GridGeometryTest extends TestCase
{
*/
final MathTransform trCorner =
grid.getGridToCRS(PixelInCell.CELL_CORNER);
assertSame("gridToCRS", identity, trCorner);
- assertExtentEquals(grid.getExtent(), low, high);
+ assertExtentEquals(low, high, grid.getExtent());
/*
* Verify computed math transform.
*/
@@ -114,7 +114,7 @@ public final strictfp class GridGeometryTest extends
TestCase {
*/
final MathTransform trCenter =
grid.getGridToCRS(PixelInCell.CELL_CENTER);
assertSame("gridToCRS", identity, trCenter);
- assertExtentEquals(grid.getExtent(), low, high);
+ assertExtentEquals(low, high, grid.getExtent());
/*
* Verify computed math transform.
*/
@@ -205,7 +205,17 @@ public final strictfp class GridGeometryTest extends
TestCase {
0, 0.5, -90,
0.5, 0, -180,
0, 0, 1}));
- final GridGeometry grid = new GridGeometry(PixelInCell.CELL_CENTER,
gridToCRS, envelope);
- // TODO: verify values.
+ final GridGeometry grid = new GridGeometry(PixelInCell.CELL_CORNER,
gridToCRS, envelope);
+ assertExtentEquals(
+ new long[] {370, 40},
+ new long[] {389, 339}, grid.getExtent());
+ assertEnvelopeEquals(new GeneralEnvelope(
+ new double[] {-70, 5},
+ new double[] {+80, 15}), grid.getEnvelope(), STRICT);
+ assertArrayEquals("resolution", new double[] {0.5, 0.5},
grid.getResolution(false), STRICT);
+ assertMatrixEquals("gridToCRS", Matrices.create(3, 3, new double[] {
+ 0, 0.5, -89.75,
+ 0.5, 0, -179.75,
+ 0, 0, 1}),
MathTransforms.getMatrix(grid.getGridToCRS(PixelInCell.CELL_CENTER)), STRICT);
}
}
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
index f652cd7..8cffb6f 100644
---
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
+++
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
@@ -122,6 +122,11 @@ public final class Vocabulary extends
IndexedResourceBundle {
public static final short CausedBy_1 = 11;
/**
+ * {0} cells
+ */
+ public static final short CellCount_1 = 149;
+
+ /**
* Character encoding
*/
public static final short CharacterEncoding = 12;
@@ -162,6 +167,11 @@ public final class Vocabulary extends
IndexedResourceBundle {
public static final short Container = 18;
/**
+ * Conversion
+ */
+ public static final short Conversion = 150;
+
+ /**
* Coordinate
*/
public static final short Coordinate = 129;
@@ -262,6 +272,11 @@ public final class Vocabulary extends
IndexedResourceBundle {
public static final short DigitalElevationModel = 146;
/**
+ * Dimension {0}
+ */
+ public static final short Dimension_1 = 148;
+
+ /**
* Dimensions
*/
public static final short Dimensions = 34;
@@ -317,6 +332,11 @@ public final class Vocabulary extends
IndexedResourceBundle {
public static final short EntryCount_1 = 121;
/**
+ * Envelope
+ */
+ public static final short Envelope = 151;
+
+ /**
* Exit
*/
public static final short Exit = 143;
@@ -352,6 +372,11 @@ public final class Vocabulary extends
IndexedResourceBundle {
public static final short GeographicIdentifier = 135;
/**
+ * Grid extent
+ */
+ public static final short GridExtent = 152;
+
+ /**
* Height
*/
public static final short Height = 46;
@@ -617,6 +642,11 @@ public final class Vocabulary extends
IndexedResourceBundle {
public static final short RepresentativeValue = 141;
/**
+ * Resolution
+ */
+ public static final short Resolution = 153;
+
+ /**
* Root
*/
public static final short Root = 90;
@@ -732,6 +762,11 @@ public final class Vocabulary extends
IndexedResourceBundle {
public static final short Unnamed = 108;
/**
+ * Unspecified
+ */
+ public static final short Unspecified = 154;
+
+ /**
* Untitled
*/
public static final short Untitled = 109;
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
index 41d1935..c2c24a8 100644
---
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
+++
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
@@ -27,6 +27,7 @@ AxisChanges = Axis changes
BarometricAltitude = Barometric altitude
Cardinality = Cardinality
CausedBy_1 = Caused by {0}
+CellCount_1 = {0} cells
CharacterEncoding = Character encoding
Characteristics = Characteristics
Classpath = Classpath
@@ -35,6 +36,7 @@ Code_1 = {0} code
Commands = Commands
ConstantPressureSurface = Constant pressure surface
Container = Container
+Conversion = Conversion
Coordinate = Coordinate
CoordinateRefSys = Coordinate reference system
Correlation = Correlation
@@ -55,6 +57,7 @@ Designation = Designation
Destination = Destination
Details = Details
DigitalElevationModel = Digital elevation model
+Dimension_1 = Dimension {0}
Dimensions = Dimensions
Directory = Directory
DittoMark = \u2033
@@ -66,6 +69,7 @@ EllipsoidChange = Ellipsoid change
EllipsoidalHeight = Ellipsoidal height
EndDate = End date
EntryCount_1 = {0} entr{0,choice,0#y|2#ies}
+Envelope = Envelope
Exit = Exit
File = File
Geocentric = Geocentric
@@ -73,6 +77,7 @@ GeocentricRadius = Geocentric radius
GeocentricConversion = Geocentric conversion
GeodeticDataset = Geodetic dataset
GeographicIdentifier = Geographic identifier
+GridExtent = Grid extent
Height = Height
Identifier = Identifier
Implementation = Implementation
@@ -126,6 +131,7 @@ Read = Read
Remarks = Remarks
RemoteConfiguration = Remote configuration
RepresentativeValue = Representative value
+Resolution = Resolution
Root = Root
RootMeanSquare = Root Mean Square
Scale = Scale
@@ -147,6 +153,7 @@ TruncatedJulian = Truncated Julian
Type = Type
Unknown = Unknown
Unnamed = Unnamed
+Unspecified = Unspecified
Untitled = Untitled
UnavailableContent = Unavailable content.
Units = Units
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
index 3be60cc..7dab7e5 100644
---
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
+++
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
@@ -34,6 +34,7 @@ AxisChanges = Changements d\u2019axes
BarometricAltitude = Altitude barom\u00e9trique
Cardinality = Cardinalit\u00e9
CausedBy_1 = Caus\u00e9e par {0}
+CellCount_1 = {0} cellules
CharacterEncoding = Encodage des caract\u00e8res
Characteristics = Caract\u00e9ristiques
Classpath = Chemin de classes
@@ -42,6 +43,7 @@ Code_1 = Code {0}
Commands = Commandes
ConstantPressureSurface = Surface \u00e0 pression constante
Container = Conteneur
+Conversion = Conversion
Coordinate = Coordonn\u00e9e
CoordinateRefSys = Syst\u00e8me de r\u00e9f\u00e9rence des
coordonn\u00e9es
Correlation = Corr\u00e9lation
@@ -62,6 +64,7 @@ Designation = D\u00e9signation
Destination = Destination
Details = D\u00e9tails
DigitalElevationModel = Mod\u00e8le num\u00e9rique de terrain
+Dimension_1 = Dimension {0}
Dimensions = Dimensions
Directory = R\u00e9pertoire
DittoMark = \u2033
@@ -73,6 +76,7 @@ EllipsoidChange = Changement d\u2019ellipso\u00efde
EllipsoidalHeight = Hauteur ellipso\u00efdale
EntryCount_1 = {0} entr\u00e9e{0,choice,0#|2#s}
EndDate = Date de fin
+Envelope = Enveloppe
Exit = Quitter
File = Fichier
Geocentric = G\u00e9ocentrique
@@ -80,6 +84,7 @@ GeocentricRadius = Rayon g\u00e9ocentrique
GeocentricConversion = Conversion g\u00e9ocentrique
GeodeticDataset = Base de donn\u00e9es g\u00e9od\u00e9sique
GeographicIdentifier = Identifiant g\u00e9ographique
+GridExtent = \u00c9tendue de la grille
Height = Hauteur
Identifier = Identifiant
Implementation = Impl\u00e9mentation
@@ -133,6 +138,7 @@ Read = Lecture
Remarks = Remarques
RemoteConfiguration = Configuration distante
RepresentativeValue = Valeur repr\u00e9sentative
+Resolution = R\u00e9solution
Root = Racine
RootMeanSquare = Moyenne quadratique
Scale = \u00c9chelle
@@ -154,6 +160,7 @@ TruncatedJulian = Julien tronqu\u00e9
Type = Type
Unknown = Inconnu
Unnamed = Sans nom
+Unspecified = Non-sp\u00e9cifi\u00e9
Untitled = Sans titre
UnavailableContent = Contenu non-disponible.
Units = Unit\u00e9s