in endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java [2205:2370]
final void format() throws IOException {
/*
* Example: Grid extent
* ├─ Dimension 0: [370 … 389] (20 cells)
* └─ Dimension 1: [ 41 … 340] (300 cells)
*
* We need to use the implementation provided by GridExtent in order
* to format correctly the unsigned long numbers for very large sizes.
*/
if (section(EXTENT, Vocabulary.Keys.GridExtent, true, false)) {
extent.appendTo(buffer, vocabulary);
writeNodes();
}
/*
* Example: Geographic extent
* ├─Lower bound: 80°00′00″S 180°00′00″W 2019-05-01T21:00:00Z
* └─Upper bound: 90°00′00″N 180°00′00″E 2019-05-02T00:00:00Z
*
* The angle and date/time patterns are fixed for now, with a precision equivalent to about 30 metres.
* The angles are rounded toward up and down for making sure that the box encloses fully the coverage.
*/
if (section(GEOGRAPHIC_EXTENT, Vocabulary.Keys.GeographicExtent, false, false) ||
section(TEMPORAL_EXTENT, Vocabulary.Keys.TemporalExtent, false, false))
{
final var table = new TableAppender(buffer, " ");
final var nf = new AngleFormat("DD°MM′SS″", locale);
final GeographicBoundingBox bbox = ((bitmask & GEOGRAPHIC_EXTENT) != 0) ? geographicBBox() : null;
double westBoundLongitude = Double.NaN;
double eastBoundLongitude = Double.NaN;
final Instant[] times = ((bitmask & TEMPORAL_EXTENT) != 0) ? timeRange() : TemporalAccessor.EMPTY;
vocabulary.appendLabel(Vocabulary.Keys.LowerBound, table);
table.setCellAlignment(TableAppender.ALIGN_RIGHT);
if (bbox != null) {
nf.setRoundingMode(RoundingMode.FLOOR);
westBoundLongitude = bbox.getWestBoundLongitude();
table.nextColumn(); table.append(nf.format(new Latitude(bbox.getSouthBoundLatitude())));
table.nextColumn(); table.append(nf.format(new Longitude(westBoundLongitude)));
}
if (times.length >= 1) {
table.nextColumn();
table.append(times[0].toString());
}
table.nextLine();
table.setCellAlignment(TableAppender.ALIGN_LEFT);
vocabulary.appendLabel(Vocabulary.Keys.UpperBound, table);
table.setCellAlignment(TableAppender.ALIGN_RIGHT);
if (bbox != null) {
nf.setRoundingMode(RoundingMode.CEILING);
eastBoundLongitude = bbox.getEastBoundLongitude();
table.nextColumn(); table.append(nf.format(new Latitude(bbox.getNorthBoundLatitude())));
table.nextColumn(); table.append(nf.format(new Longitude(eastBoundLongitude)));
}
if (times.length >= 2) {
table.nextColumn();
table.append(times[1].toString());
}
table.flush();
if (Longitude.isWraparound(westBoundLongitude, eastBoundLongitude)) {
vocabulary.appendLabel(Vocabulary.Keys.Note, buffer);
buffer.append(' ')
.append(Messages.forLocale(locale).getString(Messages.Keys.BoxCrossesAntiMeridian));
}
writeNodes();
}
/*
* Example: Envelope
* ├─ Geodetic latitude: -69.75 … 80.25 ∆φ = 0.5°
* └─ Geodetic longitude: 4.75 … 14.75 ∆λ = 0.5°
*
* The minimum number of fraction digits is the number required for differentiating two consecutive cells.
* The maximum number of fraction digits avoids to print more digits than the precision of `double` type.
* Those numbers vary for each line depending on the envelope values and the resolution at that line.
*/
if (section(ENVELOPE, Vocabulary.Keys.Envelope, true, false)) {
final boolean appendResolution = (bitmask & RESOLUTION) != 0 && (resolution != null);
final var table = new TableAppender(buffer, "");
final int dimension = envelope.getDimension();
final NumberFormat nf = numberFormat();
for (int i=0; i<dimension; i++) {
final double lower = envelope.getLower(i);
final double upper = envelope.getUpper(i);
final double delta = (resolution != null) ? resolution[i] : Double.NaN;
nf.setMinimumFractionDigits(Numerics.fractionDigitsForDelta(delta));
nf.setMaximumFractionDigits(Numerics.suggestFractionDigits(lower, upper) - 1); // The -1 is for rounding errors.
final CoordinateSystemAxis axis = (cs != null) ? cs.getAxis(i) : null;
final String name = (axis != null) ? axis.getName().getCode() : vocabulary.getString(Vocabulary.Keys.Dimension_1, i);
table.append(name).append(": ").nextColumn();
table.setCellAlignment(TableAppender.ALIGN_RIGHT);
table.append(nf.format(lower)).nextColumn();
table.setCellAlignment(TableAppender.ALIGN_LEFT);
table.append(" … ").append(nf.format(upper));
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(' ');
append(table, delta, Double.NaN, i);
}
table.nextLine();
}
table.flush();
writeNodes();
nf.setMinimumFractionDigits(0);
}
if (section(ORIGIN, Vocabulary.Keys.Origin, true, false)) {
/*
* Example: Origin
* └─ 20° 30°
*/
buffer.append('(');
append(getOrigin(), resolution, " ");
buffer.append(')');
writeNode();
}
if (section(RESOLUTION, Vocabulary.Keys.Resolution, true, false)) {
/*
* Example: Resolution
* └─ 0.5° × 0.5°
*
* By default, this is formatted only as a fallback if the envelope was not formatted.
* Otherwise, this information is already part of above envelope.
*/
append(resolution, null, " × ");
writeNode();
}
/*
* Example: Coordinate reference system
* └─ EPSG:4326 — WGS 84 (φ,λ)
*/
if (section(CRS, Vocabulary.Keys.CoordinateRefSys, true, false)) {
final Identifier id = IdentifiedObjects.getIdentifier(crs, null);
if (id != null) {
buffer.append(IdentifiedObjects.toString(id)).append(" — ");
}
buffer.append(crs.getName().getCode());
writeNode();
}
/*
* Example: Conversion
* └─ 2D → 2D non linear in 2
*/
final Matrix matrix = MathTransforms.getMatrix(gridToCRS);
if (section(GRID_TO_CRS, Vocabulary.Keys.Conversion, true, matrix != null)) {
if (matrix != null) {
writeNode(Matrices.toString(matrix));
} else {
buffer.append(gridToCRS.getSourceDimensions()).append("D → ")
.append(gridToCRS.getTargetDimensions()).append("D ");
long nonLinearDimensions = nonLinears;
String separator = Resources.forLocale(locale)
.getString(Resources.Keys.NonLinearInDimensions_1, Long.bitCount(nonLinearDimensions));
while (nonLinearDimensions != 0) {
final int i = Long.numberOfTrailingZeros(nonLinearDimensions);
nonLinearDimensions &= ~(1L << i);
buffer.append(separator).append(' ')
.append(cs != null ? cs.getAxis(i).getName().getCode() : String.valueOf(i));
separator = ",";
}
writeNode();
}
}
}