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)); }