From commits-return-13491-apmail-sis-commits-archive=sis.apache.org@sis.apache.org Wed Apr 22 17:16:17 2020
Return-Path:
X-Original-To: apmail-sis-commits-archive@www.apache.org
Delivered-To: apmail-sis-commits-archive@www.apache.org
Received: from mail.apache.org (hermes.apache.org [207.244.88.153])
by minotaur.apache.org (Postfix) with SMTP id CAD2B1945F
for ; Wed, 22 Apr 2020 17:16:16 +0000 (UTC)
Received: (qmail 24787 invoked by uid 500); 22 Apr 2020 17:16:16 -0000
Delivered-To: apmail-sis-commits-archive@sis.apache.org
Received: (qmail 24761 invoked by uid 500); 22 Apr 2020 17:16:16 -0000
Mailing-List: contact commits-help@sis.apache.org; run by ezmlm
Precedence: bulk
List-Help:
List-Unsubscribe:
List-Post:
List-Id:
Reply-To: sis-dev@sis.apache.org
Delivered-To: mailing list commits@sis.apache.org
Received: (qmail 24748 invoked by uid 99); 22 Apr 2020 17:16:16 -0000
Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70)
by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Apr 2020 17:16:16 +0000
Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33)
id 9D1C48B6C9; Wed, 22 Apr 2020 17:16:15 +0000 (UTC)
Date: Wed, 22 Apr 2020 17:16:17 +0000
To: "commits@sis.apache.org"
Subject: [sis] 02/02: Make `CoordinateFormat` more robust to change of CRS.
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
From: desruisseaux@apache.org
In-Reply-To: <158757577549.10227.18082023534246733838@gitbox.apache.org>
References: <158757577549.10227.18082023534246733838@gitbox.apache.org>
X-Git-Host: gitbox.apache.org
X-Git-Repo: sis
X-Git-Refname: refs/heads/geoapi-4.0
X-Git-Reftype: branch
X-Git-Rev: 0707557f01169941fd6aa69dc445dc2f0fedb829
X-Git-NotificationType: diff
X-Git-Multimail-Version: 1.5.dev
Auto-Submitted: auto-generated
Message-Id: <20200422171615.9D1C48B6C9@gitbox.apache.org>
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 0707557f01169941fd6aa69dc445dc2f0fedb829
Author: Martin Desruisseaux
AuthorDate: Wed Apr 22 17:50:21 2020 +0200
Make `CoordinateFormat` more robust to change of CRS.
---
.../java/org/apache/sis/gui/map/StatusBar.java | 3 +-
.../gui/referencing/RecentReferenceSystems.java | 10 +-
.../org/apache/sis/geometry/CoordinateFormat.java | 269 ++++++++++++++-------
.../apache/sis/referencing/GeodeticCalculator.java | 3 +-
.../apache/sis/geometry/CoordinateFormatTest.java | 9 +-
5 files changed, 201 insertions(+), 93 deletions(-)
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
index ae8f08b..5f4abe9 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
@@ -51,6 +51,7 @@ import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.portrayal.RenderException;
import org.apache.sis.internal.util.Strings;
+import org.apache.sis.measure.Quantities;
import org.apache.sis.measure.Units;
import org.apache.sis.util.Classes;
import org.apache.sis.util.Exceptions;
@@ -371,7 +372,7 @@ public class StatusBar extends Widget implements EventHandler {
sourceCoordinates = targetCoordinates.coordinates; // Okay to share array if same dimension.
}
setDisplayCRS(crs);
- format.setPrecision(resolution, unit);
+ format.setGroundPrecision(Quantities.create(resolution, unit));
lastX = lastY = Double.NaN;
}
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/referencing/RecentReferenceSystems.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/referencing/RecentReferenceSystems.java
index fd4b0da..cba3feb 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/referencing/RecentReferenceSystems.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/referencing/RecentReferenceSystems.java
@@ -590,7 +590,7 @@ public class RecentReferenceSystems {
*/
final ObservableList items = referenceSystems;
final ComparisonMode mode = duplicationCriterion.get();
- final int count = items.size() - NUM_OTHER_ITEMS;
+ int count = items.size() - NUM_OTHER_ITEMS;
boolean found = false;
for (int i=0; i= NUM_SHOWN_ITEMS) {
- items.remove(count - 1); // Remove the last item before `OTHER`.
+ final List selected = getSelectedItems();
+ for (int i=count; --i >= NUM_CORE_ITEMS;) {
+ if (!selected.contains(items.get(i))) { // Do not remove selected items.
+ items.remove(i); // Remove an item before `OTHER`.
+ if (--count < NUM_SHOWN_ITEMS) break;
+ }
+ }
}
items.add(Math.min(items.size(), NUM_CORE_ITEMS), newValue);
notifyChanges();
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
index 4be8aaf..b1e925d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
@@ -32,6 +32,7 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import javax.measure.Unit;
import javax.measure.UnitConverter;
+import javax.measure.Quantity;
import javax.measure.quantity.Time;
import javax.measure.IncommensurableException;
import org.opengis.geometry.DirectPosition;
@@ -58,6 +59,7 @@ import org.apache.sis.measure.AngleFormat;
import org.apache.sis.measure.Latitude;
import org.apache.sis.measure.Longitude;
import org.apache.sis.measure.Units;
+import org.apache.sis.measure.Quantities;
import org.apache.sis.referencing.CRS;
import org.apache.sis.io.CompoundFormat;
@@ -79,11 +81,10 @@ import org.apache.sis.io.CompoundFormat;
* or by overriding the {@link #createFormat(Class)} protected method.
*
* Coordinate reference system
- * If the Coordinate Reference System (CRS) of the positions to format is known, it should
- * {@linkplain #setDefaultCRS(CoordinateReferenceSystem) be specified} before to invoke other methods in this
- * class because that CRS may impact calculation of properties like the number of fraction digits achieving a
- * {@linkplain #setPrecision(double, Unit) specified precision}.
- * That default CRS is used only if the {@link DirectPosition} does not specify its own CRS.
+ * {@code CoordinateFormat} uses the {@link DirectPosition#getCoordinateReferenceSystem()} value for determining
+ * how to format each coordinate value. If the position does not specify a coordinate reference system, then the
+ * {@linkplain #setDefaultCRS(CoordinateReferenceSystem) default CRS} is assumed. If no default CRS has been
+ * specified, then all coordinates are formatted as decimal numbers.
*
* {@code CoordinateFormat} does not transform the given coordinates in a unique CRS.
* If the coordinates need to be formatted in a specific CRS, then the caller should
@@ -122,6 +123,9 @@ public class CoordinateFormat extends CompoundFormat {
/**
* The separator between each coordinate values to be formatted.
* The default value is a space.
+ *
+ * @see #getSeparator()
+ * @see #setSeparator(String)
*/
private String separator;
@@ -131,6 +135,13 @@ public class CoordinateFormat extends CompoundFormat {
private String parseSeparator;
/**
+ * The desired ground precision, or {@code null} if unspecified.
+ *
+ * @see #setGroundPrecision(Quantity)
+ */
+ private Quantity> groundPrecision;
+
+ /**
* The desired precisions for each coordinate, or {@code null} if unspecified.
* The length of this array does not need to be equal to the number of dimensions;
* extraneous values are ignored and missing values are assumed equal to 0.
@@ -145,14 +156,29 @@ public class CoordinateFormat extends CompoundFormat {
private double[] desiredPrecisions;
/**
+ * Whether the {@link Format} instances have been configured for the precision specified by
+ * {@link #groundPrecision} and {@link #desiredPrecisions}. We use a field separated from
+ * {@link #lastCRS} because precision needs to be set only for formatting, not for parsing.
+ *
+ * @see #setPrecisions(double...)
+ * @see #setGroundPrecision(Quantity)
+ * @see #configure(CoordinateReferenceSystem)
+ */
+ private transient boolean isPrecisionApplied;
+
+ /**
* The coordinate reference system to assume if no CRS is attached to the position to format.
* May be {@code null}.
+ *
+ * @see #setDefaultCRS(CoordinateReferenceSystem)
*/
private CoordinateReferenceSystem defaultCRS;
/**
- * The coordinate reference system of the last {@link DirectPosition} that we formatted.
+ * The coordinate reference system of the last {@link DirectPosition} that we parsed or formatted.
* This is used for determining if we need to recompute all other transient fields in this class.
+ *
+ * @see #createFormats(CoordinateReferenceSystem)
*/
private transient CoordinateReferenceSystem lastCRS;
@@ -164,6 +190,8 @@ public class CoordinateFormat extends CompoundFormat {
/**
* The type for each value in the {@code formats} array, or {@code null} if not yet computed.
* Types are: 0=number, 1=longitude, 2=latitude, 3=other angle, 4=date, 5=elapsed time.
+ *
+ * @see #createFormats(CoordinateReferenceSystem)
*/
private transient byte[] types;
@@ -172,6 +200,8 @@ public class CoordinateFormat extends CompoundFormat {
* not been able to configure the precision. This is the same array than {@link #formats},
* unless {@link #setPrecisions(double...)} has been invoked.
* Values at different indices may reference the same {@link Format} instance.
+ *
+ * @see #createFormats(CoordinateReferenceSystem)
*/
private transient Format[] sharedFormats;
@@ -179,6 +209,8 @@ public class CoordinateFormat extends CompoundFormat {
* The formats to use for formatting each coordinate value, or {@code null} if not yet computed.
* The length of this array should be equal to the number of dimensions in {@link #lastCRS}.
* Values at different indices may reference the same {@link Format} instance.
+ *
+ * @see #createFormats(CoordinateReferenceSystem)
*/
private transient Format[] formats;
@@ -271,7 +303,7 @@ public class CoordinateFormat extends CompoundFormat {
/**
* Returns the coordinate reference system to use if no CRS is explicitly associated to a given {@code DirectPosition}.
* This CRS determines the type of format to use for each coordinate (number, angle or date) and the number of fraction
- * digits to use for achieving a {@linkplain #setPrecision(double, Unit) specified precision}.
+ * digits to use for achieving a {@linkplain #setGroundPrecision(Quantity) specified precision on ground}.
*
* @return the default coordinate reference system, or {@code null} if none.
*/
@@ -291,33 +323,44 @@ public class CoordinateFormat extends CompoundFormat {
}
/**
- * Computes the value of transient fields from the given CRS.
+ * Computes the values of transient fields from the given CRS. The {@link #lastCRS} field is set to the given CRS
+ * for allowing callers to check if this method needs to be invoked again (this method does not check by itself).
+ * This method does not configure the formats for precisions specified by {@link #setPrecisions(double...)} and
+ * related methods; that work is done by {@link #configure(CoordinateReferenceSystem)} at formatting time
+ * (it is not needed at parsing time).
+ *
+ * @param crs the CRS for which to create the {@link Format} instances.
+ *
+ * @see #configure(CoordinateReferenceSystem)
*/
- private void configure(final CoordinateReferenceSystem crs) {
- types = null;
- formats = null;
- sharedFormats = null;
- units = null;
- toFormatUnit = null;
- unitSymbols = null;
- epochs = null;
- negate = 0;
- lastCRS = crs;
- if (crs == null) {
- return;
- }
+ private void createFormats(final CoordinateReferenceSystem crs) {
+ types = null;
+ formats = null;
+ sharedFormats = null;
+ units = null;
+ toFormatUnit = null;
+ unitSymbols = null;
+ epochs = null;
+ negate = 0L;
+ lastCRS = crs;
+ isPrecisionApplied = false;
/*
* If no CRS were specified, we will format everything as numbers. Working with null CRS
* is sometime useful because null CRS are allowed in DirectPosition according ISO 19107.
- * Otherwise (if a CRS is given), infer the format subclasses from the axes.
*/
+ if (crs == null) {
+ return;
+ }
final CoordinateSystem cs = crs.getCoordinateSystem();
if (cs == null) {
return; // Paranoiac check (should never be null).
}
- final int dimension = cs.getDimension();
- final byte[] types = new byte [dimension];
- final Format[] formats = new Format[dimension];
+ /*
+ * Otherwise (if a CRS is given), infer the format subclasses from the axes.
+ */
+ final int dimension = cs.getDimension();
+ final byte[] types = new byte [dimension];
+ final Format[] formats = new Format[dimension];
for (int i=0; i {
}
}
}
- this.types = types; // Assign only on success.
+ this.types = types; // Assign only on success.
this.formats = formats;
- sharedFormats = formats;
+ sharedFormats = formats; // `getFormatClone(int)` will separate arrays later if needed.
}
/**
@@ -461,9 +504,7 @@ public class CoordinateFormat extends CompoundFormat {
* @since 1.1
*/
public double[] getPrecisions() {
- if (lastCRS != defaultCRS) {
- configure(defaultCRS);
- }
+ configure(defaultCRS);
Format[] cf = formats;
if (cf == null) {
cf = new Format[DEFAULT_DIMENSION];
@@ -492,21 +533,21 @@ public class CoordinateFormat extends CompoundFormat {
* will be shown with two fraction digits when formatted as decimal numbers, or with "D°MM"
* pattern when formatted as angles.
*
- * This precision does not have a clear relationship to the precision on the ground.
+ *
This precision does not have a direct relationship to the precision on the ground.
* For example a precision of 0.01 could be one centimeter or 10 meters, depending if
* the units of measurement in that dimension is meter or kilometer.
- * For a precision related to the ground, use {@link #setPrecision(double, Unit)} instead.
+ * For a precision related to the ground, use {@link #setGroundPrecision(Quantity)} instead.
*
* If any value in the given array is 0 or {@link Double#NaN}, then there is a choice:
- * if {@link #setPrecision(double, Unit)} has been invoked, the ground precision specified to that
+ * if {@link #setGroundPrecision(Quantity)} has been invoked, the precision specified to that
* method will apply (if possible). Otherwise an implementation-specific default precision is used.
- * So it is possible to use {@link #setPrecision(double, Unit)} for specifying a precision in "real
- * world" units and to use this {@code setPrecisions(double...)} method for adjusting the precision
- * of only the vertical axis for example.
+ * A typical use case is to use {@link #setGroundPrecision(Quantity)} for specifying an horizontal
+ * precision in "real world" units and to use this {@code setPrecisions(double...)} method for adjusting
+ * the precision of the vertical axis only.
*
* @param precisions desired precision at which to format coordinate values in each dimension
- * (may have 0 values for unspecified precision in some of those dimensions),
- * or {@code null} for restoring the default values.
+ * (may have 0 or {@link Double#NaN} values for unspecified precisions in some
+ * of those dimensions), or {@code null} for restoring the default values.
*
* @see AngleFormat#setPrecision(double, boolean)
* @see DecimalFormat#setMaximumFractionDigits(int)
@@ -514,20 +555,27 @@ public class CoordinateFormat extends CompoundFormat {
* @since 1.1
*/
public void setPrecisions(final double... precisions) {
+ /*
+ * Implementation note: this method configures (indirectly through calls to `applyPrecision(int)`)
+ * the formats given in the `formats` array but does not touch the `sharedFormats` array. This is
+ * the opposite of `setGroundPrecision(…)` which performs a more global change that affect formats
+ * in the `sharedFormats` array.
+ */
if (precisions == null) {
desiredPrecisions = null;
- formats = sharedFormats;
+ formats = sharedFormats; // `getFormatClone(int)` will separate arrays later if needed.
} else {
- if (desiredPrecisions == null || desiredPrecisions.length != 0) {
+ if (desiredPrecisions == null || desiredPrecisions.length != precisions.length) {
desiredPrecisions = new double[precisions.length];
- Arrays.fill(desiredPrecisions, Double.NaN);
+ // Initial zero values mean "unspecified".
}
+ isPrecisionApplied &= (formats != null);
for (int i=0; i {
private void applyPrecision(final int dim) {
final double precision = desiredPrecisions[dim];
if (precision > 0) {
- final Format format = formats[dim];
+ final Format format = formats[dim]; // Will be cloned below if needed.
/*
* Intentionally check the DecimalFormat subtype, not the more generic NumberFormat type,
* because the calculation below assumes base 10 and assumes that fraction digits are for
@@ -562,13 +610,57 @@ public class CoordinateFormat extends CompoundFormat {
}
/**
+ * Computes the values of transient fields from the given CRS and configure the format precisions.
+ * This method updates the {@link #lastCRS} and {@link #isPrecisionApplied} fields.
+ * This method does nothing if above-cited fields are already up to date.
+ *
+ * @param crs the CRS for which to create and configure the {@link Format} instances.
+ *
+ * @see #createFormats(CoordinateReferenceSystem)
+ */
+ private void configure(final CoordinateReferenceSystem crs) {
+ if (lastCRS != crs) {
+ createFormats(crs); // This method sets the `lastCRS` field.
+ }
+ if (!isPrecisionApplied) {
+ if (groundPrecision != null) {
+ applyGroundPrecision(crs);
+ }
+ if (desiredPrecisions != null) {
+ if (sharedFormats == null) {
+ formats = sharedFormats = new Format[desiredPrecisions.length];
+ Arrays.fill(formats, getDefaultFormat());
+ types = new byte[formats.length];
+ }
+ final int n = Math.min(desiredPrecisions.length, formats.length);
+ for (int i=0; i unit) {
+ setGroundPrecision(Quantities.create(resolution, unit));
+ }
+
+ /**
* Adjusts the number of fraction digits to show in coordinates for achieving the given precision.
* The {@link NumberFormat} and {@link AngleFormat} are configured for coordinates expressed in the
- * {@linkplain #getDefaultCRS() default coordinate reference system} defined at the moment this method is invoked.
- * The number of fraction digits is not updated if a different CRS is specified after this method call
- * or if the coordinates to format are associated to a different CRS.
+ * coordinate reference system of the position to format.
*
- * The given resolution will be converted to the units used by coordinate system axes. For example if a 10 metres
+ * The given resolution will be converted to the units used by coordinate system axes. For example if a 10 metres
* resolution is specified but the {@linkplain #getDefaultCRS() default CRS} axes use kilometres, then this method
* converts the resolution to 0.01 kilometre and uses that value for inferring that coordinates should be formatted
* with 2 fraction digits. If the resolution is specified in an angular units such as degrees, this method uses the
@@ -576,21 +668,41 @@ public class CoordinateFormat extends CompoundFormat {
* computing an equivalent resolution in linear units. For example if the ellipsoid of default CRS is WGS84,
* then this method considers a resolution of 1 second of angle as equivalent to a resolution of about 31 meters.
* Conversions work also in the opposite direction (from linear to angular units) and are also used for choosing
- * which angle fields (degrees, minutes or seconds) to show.
+ * which angle fields (degrees, minutes or seconds) to show.
*
- * @param resolution the desired resolution.
- * @param unit unit of the desired resolution.
+ * If both {@link #setPrecisions(double...)} and {@code setGroundPrecision(Quantity)} are used,
+ * then the values specified with {@code setPrecisions(…)} have precedence and this ground precision
+ * is used only as a fallback. A typical use case is to specify the ground precision for horizontal
+ * dimensions, then to specify a different precision dz for the vertical axis only with
+ * {@code setPrecisions(NaN, NaN, dz)}.
+ *
+ * @param precision the desired precision together with its linear or angular unit.
*
* @see DecimalFormat#setMaximumFractionDigits(int)
* @see AngleFormat#setPrecision(double, boolean)
*
- * @since 1.0
+ * @since 1.1
*/
@SuppressWarnings("null")
- public void setPrecision(double resolution, Unit> unit) {
- ArgumentChecks.ensureFinite("resolution", resolution);
- ArgumentChecks.ensureNonNull("unit", unit);
- resolution = Math.abs(resolution);
+ public void setGroundPrecision(final Quantity> precision) {
+ ArgumentChecks.ensureNonNull("precision", precision);
+ groundPrecision = precision;
+ if (isPrecisionApplied) {
+ applyGroundPrecision(lastCRS);
+ }
+ }
+
+ /**
+ * Configures the formats for {@link #groundPrecision} value. Contrarily to {@link #applyPrecision(int)},
+ * this method modifies the default formats provided by {@link #getFormat(Class)}. They are the formats
+ * stored in the {@link #sharedFormats} array. Those formats are used as fallback when the {@link #formats}
+ * array does not provide more specific format.
+ *
+ * @param crs the target CRS in the conversion from ground units to CRS units.
+ */
+ private void applyGroundPrecision(final CoordinateReferenceSystem crs) {
+ final double resolution = Math.abs(groundPrecision.getValue().doubleValue());
+ final Unit> unit = groundPrecision.getUnit();
if (Units.isTemporal(unit)) {
return; // Setting temporal resolution is not yet implemented.
}
@@ -603,7 +715,7 @@ public class CoordinateFormat extends CompoundFormat {
Resolution related = null;
IncommensurableException error = null;
if (specified.isAngular || Units.isLinear(unit)) try {
- related = specified.related(ReferencingUtilities.getEllipsoid(defaultCRS));
+ related = specified.related(ReferencingUtilities.getEllipsoid(crs));
} catch (IncommensurableException e) {
error = e;
}
@@ -613,8 +725,8 @@ public class CoordinateFormat extends CompoundFormat {
* units which result in the finest resolution.
*/
boolean relatedUsed = false;
- if (defaultCRS != null) {
- final CoordinateSystem cs = defaultCRS.getCoordinateSystem();
+ if (crs != null) {
+ final CoordinateSystem cs = crs.getCoordinateSystem();
if (cs != null) { // Paranoiac check (should never be null).
final int dimension = cs.getDimension();
for (int i=0; i {
}
}
if (error != null) {
- Logging.unexpectedException(Logging.getLogger(Loggers.MEASURE), CoordinateFormat.class, "setPrecision", error);
+ Logging.unexpectedException(Logging.getLogger(Loggers.MEASURE), CoordinateFormat.class, "setGroundPrecision", error);
}
specified.setPrecision(this);
if (relatedUsed) {
@@ -646,9 +758,9 @@ public class CoordinateFormat extends CompoundFormat {
/**
* Desired resolution in a given units, together with methods for converting to the units of a coordinate system axis.
- * This is a helper class for {@link CoordinateFormat#setPrecision(double, Unit)} implementation. An execution of that
- * method typically creates two instances of this {@code Resolution} class: one for the resolution in metres and another
- * one for the resolution in degrees.
+ * This is a helper class for {@link CoordinateFormat#setGroundPrecision(Quantity)} implementation. An execution of
+ * that method typically creates two instances of this {@code Resolution} class: one for the resolution in metres
+ * and another one for the resolution in degrees.
*/
private static final class Resolution {
/** The desired resolution in the unit of measurement given by {@link #unit}. */
@@ -726,7 +838,8 @@ public class CoordinateFormat extends CompoundFormat {
/**
* Configures the {@link NumberFormat} or {@link AngleFormat} for a number of fraction digits
- * sufficient for the given resolution.
+ * sufficient for the given resolution. This method configures the shared formats returned by
+ * {@link #getFormat(Class)}. They are the formats stored in the {@link #sharedFormats} array.
*/
void setPrecision(final CoordinateFormat owner) {
final Format format = owner.getFormat(isAngular ? Angle.class : Number.class);
@@ -872,26 +985,12 @@ public class CoordinateFormat extends CompoundFormat {
if (crs == null) {
crs = defaultCRS; // May still be null.
}
- if (crs != lastCRS) {
- configure(crs);
- }
/*
- * Unconditionally configure the formatters for the desired precisions because those precisions
- * may change for every point. Note that the formatters may not have been created if the CRS is
- * null (because `configure(…)` does not know which format to use), in which case generic number
- * formats will be used.
+ * Configure the formatters for the desired precision, which can potentially change for each point.
+ * Note that the formatters may not have been created if the CRS is null (because `createFormats(…)`
+ * does not know which format to use), in which case generic number formats will be used.
*/
- if (desiredPrecisions != null) {
- if (sharedFormats == null) {
- formats = sharedFormats = new Format[desiredPrecisions.length];
- Arrays.fill(formats, getDefaultFormat());
- types = new byte[formats.length];
- }
- final int n = Math.min(desiredPrecisions.length, formats.length);
- for (int i=0; i {
case LONGITUDE: object = new Longitude (value); break;
case LATITUDE: object = new Latitude (value); break;
case ANGLE: object = new Angle (value); break;
- case DATE: object = new Date(Math.round(value) + epochs[i]); break;
+ case DATE: object = new Date(Math.addExact(Math.round(value), epochs[i])); break;
}
} else {
object = value;
@@ -1005,7 +1104,7 @@ public class CoordinateFormat extends CompoundFormat {
* If no such CRS has been specified, then we will parse everything as plain numbers.
*/
if (lastCRS != defaultCRS) {
- configure(defaultCRS);
+ createFormats(defaultCRS);
}
final double[] coordinates;
Format format;
@@ -1079,7 +1178,7 @@ public class CoordinateFormat extends CompoundFormat {
if (object instanceof Angle) {
value = ((Angle) object).degrees();
} else if (object instanceof Date) {
- value = ((Date) object).getTime() - epochs[i];
+ value = Math.subtractExact(((Date) object).getTime(), epochs[i]);
} else {
value = ((Number) object).doubleValue();
}
@@ -1150,7 +1249,7 @@ public class CoordinateFormat extends CompoundFormat {
final CoordinateFormat clone = (CoordinateFormat) super.clone();
clone.dummy = null;
clone.buffer = null;
- clone.configure(null);
+ clone.createFormats(null);
if (desiredPrecisions != null) {
clone.desiredPrecisions = desiredPrecisions.clone();
}
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 8ed2c3b..4dd9582 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
@@ -36,6 +36,7 @@ import org.opengis.geometry.DirectPosition;
import org.apache.sis.measure.AngleFormat;
import org.apache.sis.measure.Latitude;
import org.apache.sis.measure.Units;
+import org.apache.sis.measure.Quantities;
import org.apache.sis.geometry.CoordinateFormat;
import org.apache.sis.internal.referencing.PositionTransformer;
import org.apache.sis.internal.referencing.ReferencingUtilities;
@@ -1109,7 +1110,7 @@ public class GeodeticCalculator {
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);
+ pointFormat.setGroundPrecision(Quantities.create(Formulas.LINEAR_TOLERANCE, Units.METRE));
final TableAppender table = new TableAppender(buffer, " │ ");
table.setCellAlignment(TableAppender.ALIGN_CENTER);
table.appendHorizontalSeparator();
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java
index d098362..60b1e38 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java
@@ -24,6 +24,7 @@ import java.text.ParseException;
import java.io.IOException;
import org.opengis.geometry.DirectPosition;
import org.apache.sis.measure.Angle;
+import org.apache.sis.measure.Quantities;
import org.apache.sis.measure.Units;
import org.apache.sis.referencing.crs.HardCodedCRS;
import org.apache.sis.test.mock.VerticalCRSMock;
@@ -257,16 +258,16 @@ public final strictfp class CoordinateFormatTest extends TestCase {
}
/**
- * Tests {@link CoordinateFormat#setPrecision(double, Unit)}.
+ * Tests {@link CoordinateFormat#setGroundPrecision(Quantity)}.
*/
@Test
- public void testSetPrecision() {
+ public void testSetGroundPrecision() {
final CoordinateFormat format = new CoordinateFormat(Locale.FRANCE, null);
final DirectPosition2D pos = new DirectPosition2D(40.123456789, 9.87654321);
format.setDefaultCRS(HardCodedCRS.WGS84_φλ);
- format.setPrecision(0.01, Units.GRAD);
+ format.setGroundPrecision(Quantities.create(0.01, Units.GRAD));
assertEquals("40°07,4′N 9°52,6′E", format.format(pos));
- format.setPrecision(0.01, Units.METRE);
+ format.setGroundPrecision(Quantities.create(0.01, Units.METRE));
assertEquals("40°07′24,4444″N 9°52′35,5556″E", format.format(pos));
}