You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2019/05/18 13:15:19 UTC
[sis] 03/03: Better formatting of GeodeticCalculator,
using the default accuracy (currently 1 cm).
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
commit 10215933bdc7bd6d5c919cd624485ebc3dad933d
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat May 18 15:12:48 2019 +0200
Better formatting of GeodeticCalculator, using the default accuracy (currently 1 cm).
---
.../internal/referencing/ReferencingUtilities.java | 37 +++++++
.../apache/sis/referencing/GeodeticCalculator.java | 106 ++++++++++++++-------
2 files changed, 110 insertions(+), 33 deletions(-)
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
index 1d47591..664920d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
@@ -44,6 +44,7 @@ import org.apache.sis.util.Static;
import org.apache.sis.util.Utilities;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.referencing.AbstractIdentifiedObject;
@@ -52,6 +53,7 @@ import org.apache.sis.referencing.crs.DefaultGeographicCRS;
import org.apache.sis.referencing.cs.AxesConvention;
import org.apache.sis.referencing.cs.DefaultEllipsoidalCS;
import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory.Context;
+import org.apache.sis.internal.metadata.AxisDirections;
import static java.util.Collections.singletonMap;
@@ -559,4 +561,39 @@ public final class ReferencingUtilities extends Static {
}
return mapping;
}
+
+ /**
+ * Returns short names for all axes of the given CRS. This method uses short names like "Latitude" or "Height",
+ * even if the full ISO 19111 names are "Geodetic latitude" or "Ellipsoidal height". This is suitable as header
+ * for columns in a table. This method does not include abbreviation or units in the returned names.
+ *
+ * @param resources the resources from which to get "latitude" and "longitude" localized labels.
+ * @param crs the coordinate reference system from which to get axis names.
+ * @return axis names, localized if possible.
+ */
+ public static String[] getShortAxisNames(final Vocabulary resources, final CoordinateReferenceSystem crs) {
+ final boolean isGeographic = (crs instanceof GeographicCRS);
+ final boolean isProjected = (crs instanceof ProjectedCRS);
+ final CoordinateSystem cs = crs.getCoordinateSystem();
+ final String[] names = new String[cs.getDimension()];
+ for (int i=0; i<names.length; i++) {
+ short key = 0;
+ final CoordinateSystemAxis axis = cs.getAxis(i);
+ final AxisDirection direction = axis.getDirection();
+ if (AxisDirections.isCardinal(direction)) {
+ final boolean isMeridional = AxisDirection.NORTH.equals(direction) || AxisDirection.SOUTH.equals(direction);
+ if (isGeographic) {
+ key = isMeridional ? Vocabulary.Keys.Latitude : Vocabulary.Keys.Longitude;
+ } else if (isProjected) {
+ // We could add "Easting" / "Northing" here for ProjectedCRS in a future version.
+ }
+ } else if (AxisDirection.UP.equals(direction)) {
+ if (isGeographic | isProjected) {
+ key = Vocabulary.Keys.Height;
+ }
+ }
+ names[i] = (key != 0) ? resources.getString(key) : axis.getName().getCode();
+ }
+ return names;
+ }
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java
index d474b26..2138605 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java
@@ -20,6 +20,7 @@ import java.awt.Shape;
import java.util.Locale;
import java.io.IOException;
import java.io.UncheckedIOException;
+import java.text.NumberFormat;
import javax.measure.Unit;
import javax.measure.quantity.Length;
@@ -32,14 +33,16 @@ import org.opengis.geometry.coordinate.Position;
import org.opengis.geometry.DirectPosition;
import org.apache.sis.io.TableAppender;
-import org.apache.sis.measure.Angle;
+import org.apache.sis.measure.AngleFormat;
import org.apache.sis.measure.Latitude;
+import org.apache.sis.measure.Units;
import org.apache.sis.geometry.CoordinateFormat;
import org.apache.sis.internal.referencing.PositionTransformer;
import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
import org.apache.sis.internal.referencing.Resources;
import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.internal.util.Numerics;
import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
@@ -693,51 +696,88 @@ public class GeodeticCalculator {
/**
* Returns a string representation of start point, end point, azimuths and distance.
+ * The text representation is implementation-specific and may change in any future version.
+ * Current implementation is like below:
+ *
+ * {@preformat text
+ * Coordinate reference system: Unspecified datum based upon the GRS 1980 Authalic Sphere
+ * ┌─────────────┬─────────────────┬──────────────────┬─────────────┐
+ * │ │ Latitude │ Longitude │ Azimuth │
+ * │ Start point │ 9°39′06.1120″N │ 132°37′37.1248″W │ -17°10′37″ │
+ * │ End point │ 70°32′45.0206″N │ 109°50′05.0533″E │ -119°03′12″ │
+ * └─────────────┴─────────────────┴──────────────────┴─────────────┘
+ * Geodesic distance: 9,967,530.74 m
+ * }
*
* @return a string representation of this calculator state.
*/
@Override
public String toString() {
- final Locale locale = Locale.getDefault();
- final Vocabulary resources = Vocabulary.getResources(locale);
- final StringBuilder buffer = new StringBuilder();
- final String lineSeparator = System.lineSeparator();
- final CoordinateReferenceSystem crs = userToGeodetic.getCoordinateReferenceSystem();
- final boolean isGeographic = crs.equals(userToGeodetic.defaultCRS);
+ final StringBuilder buffer = new StringBuilder();
+ final Locale locale = Locale.getDefault();
+ final Vocabulary resources = Vocabulary.getResources(locale);
+ final String lineSeparator = System.lineSeparator();
+ final CoordinateReferenceSystem crs = getPositionCRS();
try {
+ /*
+ * Header: name of the Coordinate Reference System.
+ */
resources.appendLabel(Vocabulary.Keys.CoordinateRefSys, buffer);
buffer.append(' ').append(crs.getName().getCode()).append(lineSeparator);
- final TableAppender table = new TableAppender(buffer, " │ ");
- table.appendHorizontalSeparator();
- table.nextColumn(); if (isGeographic) table.append(resources.getString(Vocabulary.Keys.Latitude));
- table.nextColumn(); if (isGeographic) table.append(resources.getString(Vocabulary.Keys.Longitude));
- for (int i=crs.getCoordinateSystem().getDimension(); --i >= 2;) {
- table.nextColumn(); // Insert space for additional coordinates, e.g. ellipsoidal height.
- }
- table.nextColumn();
- table.append(resources.getString(Vocabulary.Keys.Azimuth)).nextLine();
- final CoordinateFormat cf = new CoordinateFormat(locale, null);
- cf.setSeparator("\t"); // For distributing coordinate values on different columns.
- boolean endPoint = false;
- do {
- table.append(resources.getString(endPoint ? Vocabulary.Keys.EndPoint : Vocabulary.Keys.StartPoint))
- .nextColumn();
- try {
- cf.format(endPoint ? getEndPoint() : getStartPoint(), table);
+ /*
+ * Start point and end point together with their azimuth, formatted as a table.
+ */
+ if ((validity & (START_POINT | STARTING_AZIMUTH | END_POINT | ENDING_AZIMUTH)) != 0) {
+ final String[] axes = ReferencingUtilities.getShortAxisNames(resources, crs);
+ final AngleFormat azimuthFormat = new AngleFormat("DD°MM′SS″", locale);
+ final CoordinateFormat pointFormat = new CoordinateFormat(locale, null);
+ pointFormat.setSeparator("\t"); // For distributing coordinate values on different columns.
+ pointFormat.setDefaultCRS(crs);
+ pointFormat.setPrecision(Formulas.LINEAR_TOLERANCE, Units.METRE);
+ final TableAppender table = new TableAppender(buffer, " │ ");
+ table.setCellAlignment(TableAppender.ALIGN_CENTER);
+ table.appendHorizontalSeparator();
+ for (final String axis : axes) {
table.nextColumn();
- table.append(new Angle(endPoint ? getEndingAzimuth() : getStartingAzimuth()).toString());
- } catch (IllegalStateException | TransformException e) {
- // Ignore.
+ table.append(axis);
}
- table.nextLine();
- } while ((endPoint = !endPoint) == true);
- table.appendHorizontalSeparator();
- table.flush();
- resources.appendLabel(Vocabulary.Keys.GeodesicDistance, buffer);
+ table.nextColumn();
+ table.append(resources.getString(Vocabulary.Keys.Azimuth)).nextLine();
+ boolean endPoint = false;
+ do {
+ table.setCellAlignment(TableAppender.ALIGN_LEFT);
+ table.append(resources.getString(endPoint ? Vocabulary.Keys.EndPoint : Vocabulary.Keys.StartPoint)).nextColumn();
+ table.setCellAlignment(TableAppender.ALIGN_RIGHT);
+ try {
+ pointFormat.format(endPoint ? getEndPoint() : getStartPoint(), table);
+ table.nextColumn();
+ table.append(azimuthFormat.format(endPoint ? getEndingAzimuth() : getStartingAzimuth()));
+ } catch (IllegalStateException | TransformException e) {
+ // Ignore.
+ }
+ table.nextLine();
+ } while ((endPoint = !endPoint) == true);
+ table.appendHorizontalSeparator();
+ table.flush();
+ }
+ /*
+ * Distances, formatted with a number of decimal fraction digits suitable for at least 1 centimetre precision.
+ */
+ try {
+ final Unit<Length> unit = getDistanceUnit();
+ final double distance = getGeodesicDistance();
+ final double precision = Units.METRE.getConverterTo(unit).convert(Formulas.LINEAR_TOLERANCE);
+ final NumberFormat nf = NumberFormat.getNumberInstance(locale);
+ nf.setMaximumFractionDigits(max(Numerics.suggestFractionDigits(precision), 0));
+ resources.appendLabel(Vocabulary.Keys.GeodesicDistance, buffer);
+ buffer.append(' ').append(nf.format(distance))
+ .append(' ').append(unit).append(lineSeparator);
+ } catch (IllegalStateException e) {
+ // Ignore.
+ }
} catch (IOException e) {
throw new UncheckedIOException(e); // Should never happen since we are writting in a StringBuilder.
}
- buffer.append(String.format(locale, " %f %s", geodesicDistance, getDistanceUnit()));
return buffer.toString();
}
}