Merge branch 'geoapi-3.1'
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
index 7b20e57..5f87df7 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
@@ -41,7 +41,6 @@
import org.apache.sis.gui.coverage.CoverageCanvas;
import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.coverage.grid.GridCoverage;
-import org.apache.sis.coverage.grid.GridEvaluator;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.coverage.Category;
import org.apache.sis.internal.system.Modules;
@@ -211,7 +210,7 @@
/**
* The object computing or interpolation sample values in the coverage.
*/
- private GridEvaluator evaluator;
+ private GridCoverage.Evaluator evaluator;
/**
* The selection status of each band.
@@ -318,6 +317,7 @@
}
evaluator = coverage.forConvertedValues(true).evaluator();
evaluator.setNullIfOutside(true);
+ evaluator.setWraparoundEnabled(true);
canvas(property).ifPresent((c) -> setSlice(c.getSliceExtent()));
if (previous != null && bands.equals(previous.getSampleDimensions())) {
// Same configuration than previous coverage.
@@ -479,7 +479,7 @@
* @param point the cursor location in arbitrary CRS, or {@code null} if outside canvas region.
* @return string representation of data under given position, or {@code null} if none.
*
- * @see GridEvaluator#apply(DirectPosition)
+ * @see GridCoverage.Evaluator#apply(DirectPosition)
*/
@Override
public String evaluate(final DirectPosition point) {
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java
index 454d496..d402b89 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java
@@ -260,10 +260,9 @@
/*
* Search for a title in metadata first because it has better chances to be human-readable
* compared to the resource identifier. If the title is the same text as the identifier,
- * then we will execute the code path for identifier unless the caller did not asked for
- * qualified name, in which case it would make no difference.
+ * then execute the code path for identifier (i.e. try to find a more informative text).
*/
- GenericName name = qualified ? resource.getIdentifier().orElse(null) : null;
+ GenericName name = resource.getIdentifier().orElse(null);
Collection<? extends Identification> identifications = null;
final Metadata metadata = resource.getMetadata();
if (metadata != null) {
@@ -273,7 +272,7 @@
final Citation citation = identification.getCitation();
if (citation != null) {
final String t = string(citation.getTitle(), locale);
- if (t != null && (name == null || !t.equals(name.toString()))) {
+ if (t != null && (name == null || !t.equals(name.tip().toString()))) {
return t;
}
}
@@ -285,13 +284,8 @@
* We search for explicitly declared identifier first before to fallback on
* metadata identifier, because the latter is more subject to interpretation.
*/
- if (!qualified) {
- name = resource.getIdentifier().orElse(null);
- }
if (name != null) {
- if (qualified) {
- name = name.toFullyQualifiedName();
- }
+ name = qualified ? name.toFullyQualifiedName() : name.tip();
final String t = string(name.toInternationalString(), locale);
if (t != null) return t;
}
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/SyncWindowList.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/SyncWindowList.java
index 1c8a824..bb5ddfb 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/SyncWindowList.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/SyncWindowList.java
@@ -36,8 +36,8 @@
/**
- * Provides a widget for listing all available windows and selecting the ones to follow
- * on gesture events (zoom, pans, <i>etc</i>).
+ * Provides a widget for listing all available windows and selecting the ones
+ * on which to replicate gesture events (zoom, pans, <i>etc</i>).
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.3
@@ -46,19 +46,19 @@
*/
public final class SyncWindowList extends TabularWidget implements ListChangeListener<WindowHandler> {
/**
- * Window containing a {@link MapCanvas} to follow on gesture events.
- * Gestures are followed only if {@link #linked} is {@code true}.
+ * Window containing a {@link MapCanvas} on which to replicate gesture events.
+ * Gestures are replicated only if {@link #transformEnabled} is {@code true}.
*/
private static final class Link extends GestureFollower {
/**
- * The "foreigner" view for which to follow the gesture.
+ * The "foreigner" view on which to replicate the gestures.
*/
public final WindowHandler view;
/**
- * Creates a new row for a window to follow.
+ * Creates a new row for a window on which to replicate gestures.
*
- * @param view the "foreigner" view for which to follow the gesture.
+ * @param view the "foreigner" view on which to replicate the gesture events.
* @param source the canvas which is the source of zoom, pan or rotation events.
* @param target the canvas on which to apply the changes of zoom, pan or rotation.
*/
@@ -68,23 +68,23 @@
}
/**
- * Converts the given list of handled to a list of table rows.
+ * Converts the given list of handlers to a list of table rows.
*
* @param added list of new items to put in the table.
* @param addTo where to add the converted items.
* @param owner item to exclude (because the referenced window is itself).
- * @param target the canvas on which to apply the changes of zoom, pan or rotation.
+ * @param source the canvas for which to replicate the changes of zoom, pan or rotation.
*/
static void wrap(final List<? extends WindowHandler> added, final List<Link> addTo,
- final WindowHandler owner, final MapCanvas target)
+ final WindowHandler owner, final MapCanvas source)
{
final Link[] items = new Link[added.size()];
int count = 0;
try {
for (final WindowHandler view : added) {
if (view != owner) {
- final MapCanvas source = view.getCanvas().orElse(null);
- if (source != null) {
+ final MapCanvas target = view.getCanvas().orElse(null);
+ if (target != null) {
final Link item = new Link(view, source, target);;
items[count++] = item; // Add now for disposing if an exception is thrown.
item.initialize(); // Invoked outside constructor for allowing disposal.
@@ -118,11 +118,11 @@
private final WindowHandler owner;
/**
- * The canvas on which to apply the change of zoom, pan or rotation.
+ * The canvas for which to replicate the changes of zoom, pan or rotation.
* Needs to be fetched only when first needed (not at construction time)
* for avoiding a stack overflow.
*/
- private MapCanvas target;
+ private MapCanvas source;
/**
* The component to be returned by {@link #getView()}.
@@ -244,9 +244,9 @@
* Adds the given window handlers and items in {@link #table}.
*/
private void addAll(final List<? extends WindowHandler> windows) {
- if (target == null) {
- target = owner.getCanvas().get();
+ if (source == null) {
+ source = owner.getCanvas().get();
}
- Link.wrap(windows, table.getItems(), owner, target);
+ Link.wrap(windows, table.getItems(), owner, source);
}
}
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ValueColorMapper.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ValueColorMapper.java
index b6a2766..55c7438 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ValueColorMapper.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ValueColorMapper.java
@@ -126,7 +126,7 @@
* This method compares all properties, including visibility and color.
*
* @param other the other object to compare with this step.
- * @return whether the other object is equals to this step.
+ * @return whether the other object is equal to this step.
*/
@Override
public boolean equals(final Object other) {
diff --git a/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/TransformerTest.java b/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/TransformerTest.java
index 5401e00..fdf383b 100644
--- a/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/TransformerTest.java
+++ b/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/TransformerTest.java
@@ -62,7 +62,7 @@
}
/**
- * Asserts that the transformation result is equals to the expected result.
+ * Asserts that the transformation result is equal to the expected result.
*/
static void assertPointsEqual(final double[][] expected, final double[][] actual, final double tolerance) {
assertNotSame("transform", expected, actual);
diff --git a/core/sis-build-helper/src/main/java/org/apache/sis/util/resources/IndexedResourceCompiler.java b/core/sis-build-helper/src/main/java/org/apache/sis/util/resources/IndexedResourceCompiler.java
index bfd7c62..c14c9bd 100644
--- a/core/sis-build-helper/src/main/java/org/apache/sis/util/resources/IndexedResourceCompiler.java
+++ b/core/sis-build-helper/src/main/java/org/apache/sis/util/resources/IndexedResourceCompiler.java
@@ -563,7 +563,7 @@
if (endOfLine >= 0) {
if (buffer.substring(startLineToCompare, endOfLine).equals(line)) {
startLineToCompare = endOfLine + lineSeparator.length();
- continue; // Content is equals, do not set the `modified` flag.
+ continue; // Content is equal, do not set the `modified` flag.
}
} else if (brackets == 0) {
break; // Content finished at the same time, do not set the `modified` flag.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/BandedCoverage.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/BandedCoverage.java
index d5fda2b..db74ab3 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/BandedCoverage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/BandedCoverage.java
@@ -47,7 +47,7 @@
* {@link Evaluator#apply(DirectPosition)} method signatures.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -112,7 +112,7 @@
*
* <h4>Multi-threading</h4>
* {@code Evaluator}s are not thread-safe. For computing sample values concurrently,
- * a new {@link Evaluator} instance should be created for each thread by invoking this
+ * a new {@code Evaluator} instance should be created for each thread by invoking this
* method multiply times.
*
* @return a new function for computing or interpolating sample values.
@@ -129,7 +129,7 @@
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see BandedCoverage#evaluator()
*
@@ -139,6 +139,7 @@
public interface Evaluator extends Function<DirectPosition, double[]> {
/**
* Returns the coverage from which this evaluator is computing sample values.
+ * This is the coverage on which the {@link BandedCoverage#evaluator()} method has been invoked.
*
* @return the source of sample values for this evaluator.
*/
@@ -164,6 +165,31 @@
void setNullIfOutside(boolean flag);
/**
+ * Returns {@code true} if this evaluator is allowed to wraparound coordinates that are outside the coverage.
+ * The initial value is {@code false}. This method may continue to return {@code false} even after a call to
+ * {@code setWraparoundEnabled(true)} if no wraparound axis has been found in the coverage CRS,
+ * or if automatic wraparound is not supported.
+ *
+ * @return {@code true} if this evaluator may wraparound coordinates that are outside the coverage.
+ *
+ * @since 1.3
+ */
+ boolean isWraparoundEnabled();
+
+ /**
+ * Specifies whether this evaluator is allowed to wraparound coordinates that are outside the coverage.
+ * If {@code true} and if a given coordinate is outside the coverage, then this evaluator may translate
+ * the point along a wraparound axis in an attempt to get the point inside the coverage. For example if
+ * the coverage CRS has a longitude axis, then the evaluator may translate the longitude value by a
+ * multiple of 360°.
+ *
+ * @param allow whether to allow wraparound of coordinates that are outside the coverage.
+ *
+ * @since 1.3
+ */
+ void setWraparoundEnabled(final boolean allow);
+
+ /**
* Returns a sequence of double values for a given point in the coverage.
* The CRS of the given point may be any coordinate reference system;
* coordinate conversions will be applied as needed.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/Category.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/Category.java
index 019c4ea..d560e57 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/Category.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/Category.java
@@ -504,7 +504,7 @@
* Compares the specified object with this category for equality.
*
* @param object the object to compare with.
- * @return {@code true} if the given object is equals to this category.
+ * @return {@code true} if the given object is equal to this category.
*/
@Override
public boolean equals(final Object object) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
index b3cef34..56cf885 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
@@ -455,7 +455,7 @@
* Compares the specified object with this sample dimension for equality.
*
* @param object the object to compare with.
- * @return {@code true} if the given object is equals to this sample dimension.
+ * @return {@code true} if the given object is equal to this sample dimension.
*/
@Override
public boolean equals(final Object object) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/BufferedGridCoverage.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/BufferedGridCoverage.java
index a919e9f..646eb2d 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/BufferedGridCoverage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/BufferedGridCoverage.java
@@ -232,11 +232,11 @@
* Creates a new function for computing or interpolating sample values at given locations.
*
* <h4>Multi-threading</h4>
- * {@code GridEvaluator}s are not thread-safe. For computing sample values concurrently,
- * a new {@link GridEvaluator} instance should be created for each thread.
+ * {@code Evaluator}s are not thread-safe. For computing sample values concurrently,
+ * a new {@link Evaluator} instance should be created for each thread.
*/
@Override
- public GridEvaluator evaluator() {
+ public Evaluator evaluator() {
return new CellAccessor(this);
}
@@ -289,7 +289,7 @@
/**
* Implementation of evaluator returned by {@link #evaluator()}.
*/
- private static class CellAccessor extends GridEvaluator {
+ private static final class CellAccessor extends DefaultEvaluator {
/**
* A copy of {@link BufferedGridCoverage#data} reference.
*/
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ConvertedGridCoverage.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ConvertedGridCoverage.java
index a05ee9f..3644a3b 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ConvertedGridCoverage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ConvertedGridCoverage.java
@@ -16,7 +16,6 @@
*/
package org.apache.sis.coverage.grid;
-import java.util.Map;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
@@ -31,9 +30,11 @@
import org.apache.sis.measure.MeasurementRange;
import org.apache.sis.measure.NumberRange;
import org.apache.sis.image.DataType;
-import org.apache.sis.coverage.CannotEvaluateException;
import org.apache.sis.image.ImageProcessor;
+// Branch-dependent imports
+import org.apache.sis.coverage.CannotEvaluateException;
+
/**
* Decorates a {@link GridCoverage} in order to convert sample values on the fly.
@@ -43,7 +44,7 @@
* <li>In calls to {@link #render(GridExtent)}, sample values are converted when first needed
* on a tile-by-tile basis then cached for future reuse. Note however that discarding the
* returned image may result in the lost of cached tiles.</li>
- * <li>In calls to {@link GridEvaluator#apply(DirectPosition)}, the conversion is applied
+ * <li>In calls to {@link GridCoverage.Evaluator#apply(DirectPosition)}, the conversion is applied
* on-the-fly each time in order to avoid the potentially costly tile computations.</li>
* </ul>
*
@@ -232,76 +233,33 @@
* Creates a new function for computing or interpolating sample values at given locations.
*
* <h4>Multi-threading</h4>
- * {@code GridEvaluator}s are not thread-safe. For computing sample values concurrently,
- * a new {@link GridEvaluator} instance should be created for each thread.
+ * {@code Evaluator}s are not thread-safe. For computing sample values concurrently,
+ * a new {@link Evaluator} instance should be created for each thread.
*/
@Override
- public GridEvaluator evaluator() {
- return new SampleConverter(this);
+ public Evaluator evaluator() {
+ return new SampleConverter();
}
/**
- * Implementation of evaluator returned by {@link #evaluator()}.
+ * Implementation of evaluator returned by {@link ConvertedGridCoverage#evaluator()}.
+ * This evaluator delegates all operations to the {@link #source} coverage and converts
+ * the returned sample values.
*/
- private static final class SampleConverter extends GridEvaluator {
- /**
- * The evaluator provided by source coverage.
- */
- private final GridEvaluator evaluator;
-
- /**
- * Conversions from {@linkplain #source source} values to converted values.
- */
- private final MathTransform1D[] converters;
-
+ private final class SampleConverter extends EvaluatorWrapper {
/**
* Creates a new evaluator for the enclosing coverage.
*/
- SampleConverter(final ConvertedGridCoverage coverage) {
- super(coverage);
- evaluator = coverage.source.evaluator();
- converters = coverage.converters;
+ SampleConverter() {
+ super(source.evaluator());
}
/**
- * Returns the default slice where to perform evaluation, or an empty map if unspecified.
+ * Returns the enclosing coverage.
*/
@Override
- public Map<Integer,Long> getDefaultSlice() {
- return evaluator.getDefaultSlice();
- }
-
- /**
- * Sets the default slice where to perform evaluation when the points do not have enough dimensions.
- */
- @Override
- public void setDefaultSlice(Map<Integer,Long> slice) {
- evaluator.setDefaultSlice(slice);
- }
-
- /**
- * Returns {@code true} if this evaluator is allowed to wraparound coordinates that are outside the grid.
- */
- @Override
- public boolean isWraparoundEnabled() {
- return evaluator.isWraparoundEnabled();
- }
-
- /**
- * Specifies whether this evaluator is allowed to wraparound coordinates that are outside the grid.
- */
- @Override
- public void setWraparoundEnabled(final boolean allow) {
- evaluator.setWraparoundEnabled(allow);
- }
-
- /**
- * Forwards configuration to the wrapped evaluator.
- */
- @Override
- public void setNullIfOutside(final boolean flag) {
- evaluator.setNullIfOutside(flag);
- super.setNullIfOutside(flag);
+ public GridCoverage getCoverage() {
+ return ConvertedGridCoverage.this;
}
/**
@@ -313,8 +271,9 @@
*/
@Override
public double[] apply(final DirectPosition point) throws CannotEvaluateException {
- final double[] values = evaluator.apply(point);
+ final double[] values = super.apply(point);
if (values != null) try {
+ final MathTransform1D[] converters = ConvertedGridCoverage.this.converters;
for (int i=0; i<converters.length; i++) {
values[i] = converters[i].transform(values[i]);
}
@@ -323,14 +282,6 @@
}
return values;
}
-
- /**
- * Converts the specified geospatial position to grid coordinates.
- */
- @Override
- public FractionalGridCoordinates toGridCoordinates(final DirectPosition point) throws TransformException {
- return evaluator.toGridCoordinates(point);
- }
}
/**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DefaultEvaluator.java
similarity index 90%
rename from core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java
rename to core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DefaultEvaluator.java
index 02026ff..ac85973 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DefaultEvaluator.java
@@ -46,18 +46,20 @@
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.Logging;
-import org.apache.sis.coverage.CannotEvaluateException;
-import org.apache.sis.coverage.PointOutsideCoverageException;
import static java.util.logging.Logger.getLogger;
+// Branch-dependent imports
+import org.apache.sis.coverage.CannotEvaluateException;
+import org.apache.sis.coverage.PointOutsideCoverageException;
+
/**
- * Computes or interpolates values of sample dimensions at given positions.
+ * Default implementation of {@link GridCoverage.Evaluator} for interpolating values at given positions.
* Values are computed by calls to {@link #apply(DirectPosition)} and are returned as {@code double[]}.
*
* <h2>Multi-threading</h2>
- * Evaluators are not thread-safe. An instance of {@code GridEvaluator} should be created
+ * Evaluators are not thread-safe. An instance of {@code DefaultEvaluator} should be created
* for each thread that need to compute sample values.
*
* <h2>Limitations</h2>
@@ -72,7 +74,7 @@
* @since 1.1
* @module
*/
-public class GridEvaluator implements GridCoverage.Evaluator {
+class DefaultEvaluator implements GridCoverage.Evaluator {
/**
* The coverage in which to evaluate sample values.
*/
@@ -156,22 +158,21 @@
/**
* Creates a new evaluator for the given coverage. This constructor is protected for allowing
- * {@link GridCoverage} subclasses to provide their own {@code GridEvaluator} implementations.
+ * {@link GridCoverage} subclasses to provide their own {@code DefaultEvaluator} implementations.
* For using an evaluator, invoke {@link GridCoverage#evaluator()} instead.
*
* @param coverage the coverage for which to create an evaluator.
*
* @see GridCoverage#evaluator()
*/
- protected GridEvaluator(final GridCoverage coverage) {
+ protected DefaultEvaluator(final GridCoverage coverage) {
ArgumentChecks.ensureNonNull("coverage", coverage);
this.coverage = coverage;
}
/**
* Returns the coverage from which this evaluator is fetching sample values.
- * This is usually the coverage on which the {@link GridCoverage#evaluator()} method has been invoked,
- * but not necessarily. Implementations are allowed to use a different coverage for efficiency.
+ * This is the coverage on which the {@link GridCoverage#evaluator()} method has been invoked.
*
* @return the source of sample values for this evaluator.
*/
@@ -183,7 +184,7 @@
/**
* Returns the default slice where to perform evaluation, or an empty map if unspecified.
* Keys are dimensions from 0 inclusive to {@link GridGeometry#getDimension()} exclusive,
- * and values are the grid coordinate of the slice in that dimension.
+ * and values are the grid coordinates of the slice in the dimension specified by the key.
*
* <p>This information allows to invoke {@link #apply(DirectPosition)} with for example two-dimensional points
* even if the underlying coverage is three-dimensional. The missing coordinate values are replaced by the
@@ -193,6 +194,7 @@
*
* @since 1.3
*/
+ @Override
@SuppressWarnings("ReturnOfCollectionOrArrayField") // Because the map is unmodifiable.
public Map<Integer,Long> getDefaultSlice() {
if (slice == null) {
@@ -204,7 +206,7 @@
/**
* Sets the default slice where to perform evaluation when the points do not have enough dimensions.
- * A {@code null} argument restore the default value, which is to infer the slice from the coverage
+ * A {@code null} argument restores the default value, which is to infer the slice from the coverage
* grid geometry.
*
* @param slice the default slice where to perform evaluation, or an empty map if none.
@@ -214,6 +216,8 @@
*
* @since 1.3
*/
+ @Override
+ @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
public void setDefaultSlice(Map<Integer,Long> slice) {
if (!Objects.equals(this.slice, slice)) {
if (slice != null) {
@@ -242,6 +246,7 @@
*
* @since 1.2
*/
+ @Override
public boolean isWraparoundEnabled() {
return (wraparoundAxes != 0);
}
@@ -257,6 +262,7 @@
*
* @since 1.2
*/
+ @Override
public void setWraparoundEnabled(final boolean allow) {
wraparoundAxes = 0;
if (allow) try {
@@ -408,28 +414,25 @@
}
/**
- * Converts the specified geospatial position to grid coordinates. If the given position
- * is associated to a non-null coordinate reference system (CRS) different than the
- * {@linkplain #coverage} CRS, then this method automatically transforms that position to the
+ * Converts the specified geospatial position to grid coordinates.
+ * If the given position is associated to a non-null coordinate reference system (CRS) different than the
+ * {@linkplain #getCoverage() coverage} CRS, then this method automatically transforms that position to the
* {@linkplain GridCoverage#getCoordinateReferenceSystem() coverage CRS} before to compute grid coordinates.
*
* <p>This method does not put any restriction on the grid coordinates result.
* The result may be outside the {@linkplain GridGeometry#getExtent() grid extent}
* if the {@linkplain GridGeometry#getGridToCRS(PixelInCell) grid to CRS} transform allows it.</p>
*
- * <p>The grid coordinates are relative to the grid of the coverage returned by {@link #getCoverage()}.
- * This is usually the coverage on which the {@link GridCoverage#evaluator()} method has been invoked,
- * but not necessarily. Implementations are allowed to use a different coverage for efficiency.</p>
- *
* @param point geospatial coordinates (in arbitrary CRS) to transform to grid coordinates.
* @return the grid coordinates for the given geospatial coordinates.
* @throws IncompleteGridGeometryException if the {@linkplain GridCoverage#getGridGeometry() grid geometry}
* does not define a "grid to CRS" transform, or if the given point has a non-null CRS but the
- * {@linkplain #coverage} does not {@linkplain GridCoverage#getCoordinateReferenceSystem() have a CRS}.
+ * coverage does not {@linkplain GridCoverage#getCoordinateReferenceSystem() have a CRS}.
* @throws TransformException if the given coordinates can not be transformed.
*
* @see FractionalGridCoordinates#toPosition(MathTransform)
*/
+ @Override
public FractionalGridCoordinates toGridCoordinates(final DirectPosition point) throws TransformException {
ArgumentChecks.ensureNonNull("point", point);
try {
@@ -474,7 +477,6 @@
* If most cases, the work of this method ends here. The remaining code in this method
* is for handling wraparound axes. If a coordinate is outside the coverage extent,
* check if a wraparound on some axes would bring the coordinates inside the extent.
- * The first step is to get the point closest to the extent.
*/
long axes = wraparoundAxes;
if (axes != 0) {
@@ -486,6 +488,12 @@
final double c = coordinates[i];
double border;
if (c < (border = wraparoundExtent[j++]) || c > (border = wraparoundExtent[j])) {
+ /*
+ * Detected that the point is outside the grid extent along an axis where wraparound is possible.
+ * The first time that we find such axis, expand the coordinates array for storing two points.
+ * The two points will have the same coordinates, except on all axes where the point is outside.
+ * On those axes, the coordinate of the first point is set to the closest border of the grid.
+ */
if (outsideAxes == 0) {
final int n = coordinates.length;
coordinates = Arrays.copyOf(coordinates, 2*Math.max(n, gridToWraparound.getTargetDimensions()));
@@ -501,7 +509,10 @@
/*
* If a coordinate was found outside the grid, transform to a CRS where we can apply shift.
* It may be the same CRS than the coverage CRS or the source CRS, but not necessarily.
- * Current version does not try to optimize by checking if `point` argument can be reused.
+ * For example if the CRS is projected, then we need to use a geographic intermediate CRS.
+ * In the common case where the source CRS is already geographic, the second point in the
+ * `coordinates` array after `transform(…)` will contain the same coordinates as `point`,
+ * but potentially with more dimensions.
*/
if (outsideAxes != 0) {
gridToWraparound.transform(coordinates, 0, coordinates, 0, 2);
@@ -514,7 +525,7 @@
* then round that shift to an integer amount of periods. Modify the original
* coordinate by applying that modified translation.
*/
- final int oi = i + s;
+ final int oi = i + s; // Index of original coordinates.
double shift = coordinates[i] - coordinates[oi];
shift = Math.copySign(Math.ceil(Math.abs(shift) / period), shift) * period;
coordinates[oi] += shift;
@@ -535,7 +546,23 @@
}
outsideAxes &= ~(1L << i);
} while (outsideAxes != 0);
- System.arraycopy(coordinates, 0, position.coordinates, 0, position.coordinates.length);
+ /*
+ * Copy shifted coordinate values to the final `FractionalGridCoordinates`, except the NaN values.
+ * NaN values may exist if the given `point` has less dimensions than the grid geometry, in which
+ * case missing values have been replaced by `slice` values in the `target` array but not in the
+ * `coordinates` array. We want to keep the `slice` values in the `target` array.
+ *
+ * TODO: to be strict, we should skip the copy only if `slice.containsKey(i)` is true, because it
+ * could happen that a transform resulted in NaN values in other dimensions. But that check would
+ * be costly, so we avoid it for now.
+ */
+ final double[] target = position.coordinates;
+ for (int i = target.length; --i >= 0;) {
+ final double value = coordinates[i];
+ if (!Double.isNaN(value)) {
+ target[i] = value;
+ }
+ }
}
}
return position;
@@ -626,6 +653,6 @@
* @param exception the exception that occurred.
*/
private static void recoverableException(final String caller, final TransformException exception) {
- Logging.recoverableException(getLogger(Modules.RASTER), GridEvaluator.class, caller, exception);
+ Logging.recoverableException(getLogger(Modules.RASTER), DefaultEvaluator.class, caller, exception);
}
}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DerivedGridCoverage.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DerivedGridCoverage.java
index 67c0f3c..e91dffc 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DerivedGridCoverage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DerivedGridCoverage.java
@@ -94,13 +94,12 @@
* That function accepts {@link DirectPosition} in arbitrary Coordinate Reference System;
* conversions to grid indices are applied by the {@linkplain #source} as needed.
*
- * @todo The results returned by {@link GridEvaluator#toGridCoordinates(DirectPosition)}
- * would need to be transformed. But it would force us to return a wrapper, which
- * would add an indirection level for all others (more important) method calls.
- * Is it worth to do so?
+ * @todo The results returned by {@link GridCoverage.Evaluator#toGridCoordinates(DirectPosition)}
+ * would need to be transformed. But it would force us to return a wrapper, which would add
+ * an indirection level for all others (more important) method calls. Is it worth to do so?
*/
@Override
- public GridEvaluator evaluator() {
+ public Evaluator evaluator() {
return source.evaluator();
}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/EvaluatorWrapper.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/EvaluatorWrapper.java
new file mode 100644
index 0000000..1d685fa
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/EvaluatorWrapper.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.coverage.grid;
+
+import java.util.Map;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.referencing.operation.TransformException;
+
+// Branch-dependent imports
+import org.apache.sis.coverage.CannotEvaluateException;
+
+
+/**
+ * An evaluator which delegates all operations to another evaluator.
+ * The default implementation of all methods except {@link #getCoverage()} delegates to the source evaluator.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 1.3
+ * @module
+ */
+abstract class EvaluatorWrapper implements GridCoverage.Evaluator {
+ /**
+ * The evaluator provided by source coverage.
+ * This is where all operations are delegated.
+ */
+ private final GridCoverage.Evaluator source;
+
+ /**
+ * Creates a new evaluator wrapper.
+ *
+ * @param source the evaluator to wrap.
+ */
+ EvaluatorWrapper(final GridCoverage.Evaluator source) {
+ this.source = source;
+ }
+
+ /**
+ * Returns whether to return {@code null} instead of throwing an exception if a point is outside coverage bounds.
+ */
+ @Override
+ public boolean isNullIfOutside() {
+ return source.isNullIfOutside();
+ }
+
+ /**
+ * Specifies whether to return {@code null} instead of throwing an exception if a point is outside coverage bounds.
+ */
+ @Override
+ public void setNullIfOutside(final boolean flag) {
+ source.setNullIfOutside(flag);
+ }
+
+ /**
+ * Returns {@code true} if this evaluator is allowed to wraparound coordinates that are outside the grid.
+ */
+ @Override
+ public boolean isWraparoundEnabled() {
+ return source.isWraparoundEnabled();
+ }
+
+ /**
+ * Specifies whether this evaluator is allowed to wraparound coordinates that are outside the grid.
+ */
+ @Override
+ public void setWraparoundEnabled(final boolean allow) {
+ source.setWraparoundEnabled(allow);
+ }
+
+ /**
+ * Returns the default slice where to perform evaluation, or an empty map if unspecified.
+ * This method should be overridden if this evaluator has been created for a coverage
+ * with a different grid geometry than the coverage of the wrapped evaluator.
+ */
+ @Override
+ public Map<Integer,Long> getDefaultSlice() {
+ return source.getDefaultSlice();
+ }
+
+ /**
+ * Sets the default slice where to perform evaluation when the points do not have enough dimensions.
+ * This method should be overridden if this evaluator has been created for a coverage
+ * with a different grid geometry than the coverage of the wrapped evaluator.
+ */
+ @Override
+ public void setDefaultSlice(Map<Integer,Long> slice) {
+ source.setDefaultSlice(slice);
+ }
+
+ /**
+ * Converts the specified geospatial position to grid coordinates.
+ * This method should be overridden if this evaluator has been created for a coverage
+ * with a different grid geometry than the coverage of the wrapped evaluator.
+ */
+ @Override
+ public FractionalGridCoordinates toGridCoordinates(final DirectPosition point) throws TransformException {
+ return source.toGridCoordinates(point);
+ }
+
+ /**
+ * Returns a sequence of double values for a given point in the coverage.
+ * This method should be overridden if this evaluator is for a coverage
+ * doing some on-the-fly conversion of sample values.
+ *
+ * @param point the coordinate point where to evaluate.
+ * @throws CannotEvaluateException if the values can not be computed.
+ */
+ @Override
+ public double[] apply(final DirectPosition point) throws CannotEvaluateException {
+ return source.apply(point);
+ }
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/FractionalGridCoordinates.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/FractionalGridCoordinates.java
index 76f9edb..1001b77 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/FractionalGridCoordinates.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/FractionalGridCoordinates.java
@@ -49,7 +49,7 @@
* @author Martin Desruisseaux (Geomatys)
* @version 1.2
*
- * @see GridEvaluator#toGridCoordinates(DirectPosition)
+ * @see GridCoverage.Evaluator#toGridCoordinates(DirectPosition)
*
* @since 1.1
* @module
@@ -70,7 +70,7 @@
*
* <div class="note"><b>Note:</b>
* {@code FractionalGridCoordinates} are usually not created directly, but are instead obtained
- * indirectly for example from the {@linkplain GridEvaluator#toGridCoordinates(DirectPosition)
+ * indirectly for example from the {@linkplain GridCoverage.Evaluator#toGridCoordinates(DirectPosition)
* conversion of a geospatial position}.</div>
*
* @param dimension the number of dimensions.
@@ -343,7 +343,7 @@
* @return the grid coordinates converted using the given transform.
* @throws TransformException if the grid coordinates can not be converted by {@code gridToCRS}.
*
- * @see GridEvaluator#toGridCoordinates(DirectPosition)
+ * @see GridCoverage.Evaluator#toGridCoordinates(DirectPosition)
*/
public DirectPosition toPosition(final MathTransform gridToCRS) throws TransformException {
return gridToCRS.transform(new Position(this), null);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
index b5d06dc..2e51512 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.coverage.grid;
+import java.util.Map;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
@@ -26,6 +27,7 @@
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.TransformException;
import org.opengis.referencing.operation.NoninvertibleTransformException;
import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.measure.NumberRange;
@@ -299,8 +301,8 @@
* conversions to grid indices are applied as needed.
*
* <h4>Multi-threading</h4>
- * {@code GridEvaluator}s are not thread-safe. For computing sample values concurrently,
- * a new {@link GridEvaluator} instance should be created for each thread by invoking this
+ * {@code Evaluator}s are not thread-safe. For computing sample values concurrently,
+ * a new {@code Evaluator} instance should be created for each thread by invoking this
* method multiply times.
*
* @return a new function for computing or interpolating sample values.
@@ -308,8 +310,84 @@
* @since 1.1
*/
@Override
- public GridEvaluator evaluator() {
- return new GridEvaluator(this);
+ public Evaluator evaluator() {
+ return new DefaultEvaluator(this);
+ }
+
+ /**
+ * Interpolates values of sample dimensions at given positions.
+ * Values are computed by calls to {@link #apply(DirectPosition)} and are returned as {@code double[]}.
+ * This method extends {@link BandedCoverage.Evaluator} with the addition of some methods specific to
+ * gridded data.
+ *
+ * <h2>Multi-threading</h2>
+ * Evaluators are not thread-safe. An instance of {@code Evaluator} should be created
+ * for each thread that need to interpolate sample values.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ *
+ * @see GridCoverage#evaluator()
+ *
+ * @since 1.3
+ * @module
+ */
+ public interface Evaluator extends BandedCoverage.Evaluator {
+ /**
+ * Returns the coverage from which this evaluator is fetching sample values.
+ * This is the coverage on which the {@link GridCoverage#evaluator()} method has been invoked.
+ *
+ * @return the source of sample values for this evaluator.
+ */
+ @Override
+ GridCoverage getCoverage();
+
+ /**
+ * Returns the default slice where to perform evaluation, or an empty map if unspecified.
+ * Keys are dimensions from 0 inclusive to {@link GridGeometry#getDimension()} exclusive,
+ * and values are the grid coordinates of the slice in the dimension specified by the key.
+ *
+ * <p>This information allows to invoke {@link #apply(DirectPosition)} with for example
+ * two-dimensional points even if the underlying coverage is three-dimensional.
+ * The missing coordinate values are replaced by the values provided in the map.</p>
+ *
+ * @return the default slice where to perform evaluation, or an empty map if unspecified.
+ */
+ Map<Integer,Long> getDefaultSlice();
+
+ /**
+ * Sets the default slice where to perform evaluation when the points do not have enough dimensions.
+ * A {@code null} argument restores the default value, which is to infer the slice from the coverage
+ * grid geometry.
+ *
+ * @param slice the default slice where to perform evaluation, or an empty map if none.
+ * @throws IllegalArgumentException if the map contains an illegal dimension or grid coordinate value.
+ *
+ * @see GridExtent#getSliceCoordinates()
+ */
+ void setDefaultSlice(Map<Integer,Long> slice);
+
+ /**
+ * Converts the specified geospatial position to grid coordinates. If the given position is associated to
+ * a non-null coordinate reference system (CRS) different than the {@linkplain #getCoverage() coverage} CRS,
+ * then this method automatically transforms that position to the {@linkplain #getCoordinateReferenceSystem()
+ * coverage CRS} before to compute grid coordinates.
+ *
+ * <p>This method does not put any restriction on the grid coordinates result.
+ * The result may be outside the {@linkplain GridGeometry#getExtent() grid extent}
+ * if the {@linkplain GridGeometry#getGridToCRS(PixelInCell) grid to CRS} transform allows it.</p>
+ *
+ * @param point geospatial coordinates (in arbitrary CRS) to transform to grid coordinates.
+ * @return the grid coordinates for the given geospatial coordinates.
+ * @throws IncompleteGridGeometryException if the {@linkplain GridCoverage#getGridGeometry() grid geometry}
+ * does not define a "grid to CRS" transform, or if the given point has a non-null CRS but the
+ * coverage does not {@linkplain GridCoverage#getCoordinateReferenceSystem() have a CRS}.
+ * @throws TransformException if the given coordinates can not be transformed.
+ *
+ * @see FractionalGridCoordinates#toPosition(MathTransform)
+ */
+ FractionalGridCoordinates toGridCoordinates(final DirectPosition point) throws TransformException;
}
/**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
index 5e3a755..e5b5d26 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
@@ -502,20 +502,20 @@
* Creates a new function for computing or interpolating sample values at given locations.
*
* <h4>Multi-threading</h4>
- * {@code GridEvaluator}s are not thread-safe. For computing sample values concurrently,
- * a new {@link GridEvaluator} instance should be created for each thread.
+ * {@code Evaluator}s are not thread-safe. For computing sample values concurrently,
+ * a new {@code Evaluator} instance should be created for each thread.
*
* @since 1.1
*/
@Override
- public GridEvaluator evaluator() {
+ public Evaluator evaluator() {
return new PixelAccessor();
}
/**
* Implementation of evaluator returned by {@link #evaluator()}.
*/
- private final class PixelAccessor extends GridEvaluator {
+ private final class PixelAccessor extends DefaultEvaluator {
/**
* Creates a new evaluator for the enclosing coverage.
*/
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index 90091c7..727897c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -675,7 +675,7 @@
*
* @param index the dimension for which to obtain the coordinate value.
* @return the low coordinate value at the given dimension, inclusive.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() grid dimension}.
*
* @see #getHigh(int)
@@ -691,7 +691,7 @@
*
* @param index the dimension for which to obtain the coordinate value.
* @return the high coordinate value at the given dimension, <strong>inclusive</strong>.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() grid dimension}.
*
* @see #getLow(int)
@@ -709,7 +709,7 @@
*
* @param index the dimension for which to obtain the size.
* @return the number of integer grid coordinates along the given dimension.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() grid dimension}.
* @throws ArithmeticException if the size is too large for the {@code long} primitive type.
*
@@ -796,7 +796,7 @@
*
* @return grid coordinates for all dimensions where the grid has a size of 1.
*
- * @see GridEvaluator#setDefaultSlice(Map)
+ * @see GridCoverage.Evaluator#setDefaultSlice(Map)
*
* @since 1.3
*/
@@ -908,7 +908,7 @@
*
* @param index the dimension for which to obtain the axis type.
* @return the axis type at the given dimension. May be absent if the type is unknown.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() grid dimension}.
*/
public Optional<DimensionNameType> getAxisType(final int index) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index 8c816b4..2e6bf42 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -245,7 +245,7 @@
/**
* An <em>estimation</em> of the grid resolution, in units of the CRS axes.
* Computed from {@link #gridToCRS}, eventually together with {@link #extent}.
- * May be {@code null} if unknown. If non-null, the array length is equals to
+ * May be {@code null} if unknown. If non-null, the array length is equal to
* the number of CRS dimensions.
*
* @see #RESOLUTION
@@ -559,7 +559,7 @@
}
/**
- * Ensures that the given dimension is equals to the expected value. If not, throws an exception.
+ * Ensures that the given dimension is equal to the expected value. If not, throws an exception.
* This method assumes that the argument name is {@code "extent"}.
*
* @param extent the extent to validate, or {@code null} if none.
@@ -1563,7 +1563,7 @@
* This method delegates to {@code equals(object, ComparisonMode.STRICT)}.
*
* @param object the object to compare with.
- * @return {@code true} if the given object is equals to this grid geometry.
+ * @return {@code true} if the given object is equal to this grid geometry.
*/
@Override
public boolean equals(final Object object) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
index c0ab6e9..f129e9d 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
@@ -379,7 +379,7 @@
}
/**
- * Ensures that the given number is equals to the expected number of bands.
+ * Ensures that the given number is equal to the expected number of bands.
* The given number shall be either 1 (case of interleaved sample model) or
* {@link #getNumBands()} (case of banded sample model).
*/
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
index 3d31c69..217cc3d 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
@@ -352,7 +352,7 @@
* Compares this type with the given object for equality.
*
* @param obj the object to compare with this type.
- * @return {@code true} if the given object is equals to this type.
+ * @return {@code true} if the given object is equal to this type.
*/
@Override
public boolean equals(final Object obj) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/BinarySpatialFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/BinarySpatialFilter.java
index a178bc7..c799d72 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/BinarySpatialFilter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/BinarySpatialFilter.java
@@ -31,7 +31,7 @@
/**
* Spatial operations between two geometries.
* The nature of the operation depends on {@link #getOperatorType()}.
- * A standard set of spatial operators is equals, disjoin, touches,
+ * A standard set of spatial operators is equal, disjoin, touches,
* within, overlaps, crosses, intersects, contains, beyond and BBOX.
*
* @author Johann Sorel (Geomatys)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
index 7feb03e..b8e5678 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
@@ -706,7 +706,7 @@
}
/**
- * Creates an operator that checks if first temporal operand is equals to the second.
+ * Creates an operator that checks if first temporal operand is equal to the second.
*
* @param time1 expression fetching the first temporal value.
* @param time2 expression fetching the second temporal value.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java b/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java
index 7649a25..b70ac74 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java
@@ -29,7 +29,6 @@
import org.apache.sis.feature.builder.PropertyTypeBuilder;
import org.apache.sis.feature.builder.AttributeTypeBuilder;
import org.apache.sis.util.resources.Errors;
-import org.apache.sis.internal.util.XPaths;
// Branch-dependent imports
import org.opengis.util.ScopedName;
@@ -110,7 +109,7 @@
@SuppressWarnings("unchecked")
static <V> ValueReference<AbstractFeature,V> create(String xpath, final Class<V> type) {
boolean isVirtual = false;
- List<String> path = XPaths.split(xpath);
+ List<String> path = XPath.split(xpath);
split: if (path != null) {
/*
* If the XPath is like "/∗/property" where the root "/" is the feature instance,
@@ -119,7 +118,7 @@
*/
final String head = path.get(0); // List and items in the list are guaranteed non-empty.
isVirtual = head.equals("/*");
- if (isVirtual || head.charAt(0) != XPaths.SEPARATOR) {
+ if (isVirtual || head.charAt(0) != XPath.SEPARATOR) {
final int offset = isVirtual ? 1 : 0; // Skip the "/*/" component at index 0.
final int last = path.size() - 1;
if (last >= offset) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/XPath.java b/core/sis-feature/src/main/java/org/apache/sis/filter/XPath.java
new file mode 100644
index 0000000..cd86706
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/XPath.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.filter;
+
+import java.util.List;
+import java.util.ArrayList;
+import org.apache.sis.util.Static;
+import org.apache.sis.util.resources.Errors;
+
+import static org.apache.sis.util.CharSequences.*;
+
+
+/**
+ * Basic support of X-Path in {@link PropertyValue} expression.
+ * This is intended to be only a lightweight support, not a replacement for {@link javax.xml.xpath} implementations.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 0.4
+ * @module
+ */
+final class XPath extends Static {
+ /**
+ * The separator between path components.
+ */
+ public static final char SEPARATOR = '/';
+
+ /**
+ * Do not allow instantiation of this class.
+ */
+ private XPath() {
+ }
+
+ /**
+ * Splits the given URL around the {@code '/'} separator, or returns {@code null} if there is no separator.
+ * By convention if the URL is absolute, then the leading {@code '/'} character is kept in the first element.
+ * For example {@code "/∗/property"} is splitted as two elements: {@code "/∗"} and {@code "property"}.
+ *
+ * <p>This method trims the whitespaces of components except the last one (the tip),
+ * for consistency with the case where this method returns {@code null}.</p>
+ *
+ * @param xpath the URL to split.
+ * @return the splitted URL with the heading separator kept in the first element, or {@code null}
+ * if there is no separator. If non-null, the list always contains at least one element.
+ * @throws IllegalArgumentException if the XPath contains at least one empty component.
+ */
+ static List<String> split(final String xpath) {
+ int next = xpath.indexOf(SEPARATOR);
+ if (next < 0) {
+ return null;
+ }
+ final List<String> components = new ArrayList<>(4);
+ int start = skipLeadingWhitespaces(xpath, 0, next);
+ if (start < next) {
+ // No leading '/' (the characters before it are a path element, added below).
+ components.add(xpath.substring(start, skipTrailingWhitespaces(xpath, start, next)));
+ start = ++next;
+ } else {
+ // Keep the `start` position on the leading '/'.
+ next++;
+ }
+ while ((next = xpath.indexOf(SEPARATOR, next)) >= 0) {
+ components.add(trimWhitespaces(xpath, start, next).toString());
+ start = ++next;
+ }
+ components.add(xpath.substring(start)); // No whitespace trimming.
+ if (components.stream().anyMatch(String::isEmpty)) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.UnsupportedXPath_1, xpath));
+ }
+ return components;
+ }
+}
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
index 597742d..24d0f50 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
@@ -193,11 +193,11 @@
}
/**
- * Tests {@link GridEvaluator#apply(DirectPosition)}.
+ * Tests {@link GridCoverage.Evaluator#apply(DirectPosition)}.
*/
@Test
public void testEvaluator() {
- final GridEvaluator evaluator = createTestCoverage().evaluator();
+ final GridCoverage.Evaluator evaluator = createTestCoverage().evaluator();
/*
* Test evaluation at indeger indices. No interpolation should be applied.
*/
@@ -229,11 +229,8 @@
}
/**
- * Tests {@link GridEvaluator#apply(DirectPosition)} with a wraparound on the longitude axis.
+ * Tests {@link GridCoverage.Evaluator#apply(DirectPosition)} with a wraparound on the longitude axis.
* This method tests a coordinate that would be outside the grid if wraparound was not applied.
- *
- * @todo Not yet implemented. One potential place where to implement this functionality could be
- * {@link GridEvaluator#toGridPosition(DirectPosition)}.
*/
@Test
@DependsOnMethod("testEvaluator")
@@ -241,12 +238,12 @@
final Matrix3 gridToCRS = new Matrix3();
gridToCRS.m00 = 100; // Scale
gridToCRS.m02 = 100; // Offset
- final GridEvaluator evaluator = createTestCoverage(MathTransforms.linear(gridToCRS)).evaluator();
+ final GridCoverage.Evaluator evaluator = createTestCoverage(MathTransforms.linear(gridToCRS)).evaluator();
evaluator.setWraparoundEnabled(true);
assertArrayEquals(new double[] {2}, evaluator.apply(new DirectPosition2D(100, 0)), STRICT);
assertArrayEquals(new double[] {5}, evaluator.apply(new DirectPosition2D(200, 0)), STRICT);
/*
- * Following tests fail if wraparound is not applied by `GridEvaluator`.
+ * Following tests fail if wraparound is not applied by `GridCoverage.Evaluator`.
*/
assertArrayEquals(new double[] {5}, evaluator.apply(new DirectPosition2D(200 - 360, 0)), STRICT);
assertArrayEquals(new double[] {2}, evaluator.apply(new DirectPosition2D(100 - 360, 0)), STRICT);
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
index c8b0f69..8bf4b8d 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
@@ -647,7 +647,7 @@
assertExtentEquals(new long[] {0, -3410}, new long[] {75, -3158}, result.getExtent());
assertEnvelopeEquals(new Envelope2D(null,
-175, // Expected minimum value.
- 80, // Not interresting for this test.
+ 80, // Not interesting for this test.
-172 - -175, // Expected maximum value minus minimum.
90 - 80),
result.getEnvelope(), 0.02);
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java b/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
index 177a958..3ef2671 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
@@ -121,7 +121,7 @@
/**
* Sets the attribute of the given name to the given value.
- * First, this method verifies that the previous value is equals to the given one.
+ * First, this method verifies that the previous value is equal to the given one.
* Then, this method set the attribute to the given value and check if the result.
*
* @param name the name of the attribute to set.
diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/XPathTest.java b/core/sis-feature/src/test/java/org/apache/sis/filter/XPathTest.java
new file mode 100644
index 0000000..3c3ae24
--- /dev/null
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/XPathTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.filter;
+
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests {@link XPath}.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 0.4
+ * @module
+ */
+public final strictfp class XPathTest extends TestCase {
+ /**
+ * Tests {@link XPath#split(String)}.
+ */
+ @Test
+ public void testSplit() {
+ assertNull(XPath.split("property"));
+ assertArrayEquals(new String[] {"/property"}, XPath.split("/property").toArray());
+ assertArrayEquals(new String[] {"Feature", "property", "child"}, XPath.split("Feature/property/child").toArray());
+ assertArrayEquals(new String[] {"/Feature", "property"}, XPath.split("/Feature/property").toArray());
+ }
+}
diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/InterpolationTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/InterpolationTest.java
index 42899a0..3d08d30 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/image/InterpolationTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/image/InterpolationTest.java
@@ -169,7 +169,7 @@
}
/**
- * Verifies that a pixel value interpolated in the source image is equals to the expected value.
+ * Verifies that a pixel value interpolated in the source image is equal to the expected value.
*
* @param x <var>x</var> coordinate in the source image, from {@value #XMIN} to {@value #XUP} (exclusive).
* @param y <var>y</var> coordinate in the source image, from {@value #YMIN} to {@value #YUP} (exclusive).
diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java
index adec4f9..9c037b7 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java
@@ -334,7 +334,7 @@
}
/**
- * Verifies that actual iteration order is equals to the expected one.
+ * Verifies that actual iteration order is equal to the expected one.
*
* @param singleTile {@code true} if iteration occurs in a single tile, or {@code false} for the whole image.
*/
diff --git a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
index fa897c6..e22cba9 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
@@ -50,6 +50,7 @@
org.apache.sis.feature.FeatureOperationsTest.class,
org.apache.sis.feature.FeatureFormatTest.class,
org.apache.sis.feature.FeaturesTest.class,
+ org.apache.sis.filter.XPathTest.class,
org.apache.sis.filter.LeafExpressionTest.class,
org.apache.sis.filter.LogicalFilterTest.class,
org.apache.sis.filter.IdentifierFilterTest.class,
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/Context.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/Context.java
index 801ccad..034d1bb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/Context.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/Context.java
@@ -378,7 +378,7 @@
}
/**
- * Returns {@code true} if the GML version is equals or newer than the specified version.
+ * Returns {@code true} if the GML version is equal or newer than the specified version.
* If no GML version was specified, then this method returns {@code true}, i.e. newest
* version is assumed.
*
@@ -387,7 +387,7 @@
*
* @param context the current context, or {@code null} if none.
* @param version the version to compare to.
- * @return {@code true} if the GML version is equals or newer than the specified version.
+ * @return {@code true} if the GML version is equal or newer than the specified version.
*
* @see #getVersion(String)
*/
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/LocaleAndCharset.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/LocaleAndCharset.java
index aaab4d7..2461e8b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/LocaleAndCharset.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/LocaleAndCharset.java
@@ -106,7 +106,7 @@
/**
* Returns the key or the value of the given {@link Map.Entry}. If the given object is not a map entry
- * or is null, then it is returned as-is. This later case should never happen (the object shall always be
+ * or is null, then it is returned as-is. This latter case should never happen (the object shall always be
* a non-null map entry), but we nevertheless check for making the code more robust to ill-formed metadata.
* We apply this tolerance because this method is used (indirectly) for {@code toString()} implementations,
* and failure in those methods make debugging more difficult (string representations are often requested
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
index 87206bf..e2b3f25 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
@@ -381,7 +381,7 @@
* in order to get the singular form instead of the plural one, because we will create one
* node for each element in a collection.
*
- * <p>If the property name is equals, ignoring case, to the simple type name, then this method
+ * <p>If the property name is equal, ignoring case, to the simple type name, then this method
* returns the subtype name (<a href="https://issues.apache.org/jira/browse/SIS-298">SIS-298</a>).
* For example instead of:</p>
*
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java
index 9063a05..9e069dc 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultRepresentativeFraction.java
@@ -232,7 +232,7 @@
}
/**
- * Returns 1 if the {@linkplain #getDenominator() denominator} is equals to 1, or 0 otherwise.
+ * Returns 1 if the {@linkplain #getDenominator() denominator} is equal to 1, or 0 otherwise.
*
* <div class="note"><b>Rational:</b>
* This method is defined that way because scales smaller than 1 can
@@ -246,7 +246,7 @@
}
/**
- * Returns 1 if the {@linkplain #getDenominator() denominator} is equals to 1, or 0 otherwise.
+ * Returns 1 if the {@linkplain #getDenominator() denominator} is equal to 1, or 0 otherwise.
*
* <div class="note"><b>Rational:</b>
* This method is defined that way because scales smaller than 1 can
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java
index 37fced0..2b0b649 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java
@@ -304,7 +304,7 @@
}
/*
* We have found a column to add. Check if the column actually needs to be added to the parent table
- * (if such parent exists). In most case, the answer is "no" and 'addTo' is equals to 'table'.
+ * (if such parent exists). In most case, the answer is "no" and 'addTo' is equal to 'table'.
*/
String addTo = table;
if (helper.dialect.supportsTableInheritance) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/AbstractName.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/AbstractName.java
index 89e8faa..26b31ae 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/AbstractName.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/AbstractName.java
@@ -277,14 +277,9 @@
* @param name the name after which to write a separator.
* @return the separator to write after the given name.
*/
- static String separator(final GenericName name) {
- if (name != null) {
- final NameSpace scope = name.scope();
- if (scope instanceof DefaultNameSpace) {
- return ((DefaultNameSpace) scope).headSeparator;
- }
- }
- return DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
+ private static String headSeparator(final GenericName name) {
+ return (name != null) ? DefaultNameSpace.getSeparator(name.scope(), true)
+ : DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
}
/**
@@ -310,7 +305,7 @@
final StringBuilder buffer = new StringBuilder();
for (final LocalName name : getParsedNames()) {
if (insertSeparator) {
- buffer.append(separator(name));
+ buffer.append(headSeparator(name));
}
insertSeparator = true;
buffer.append(name);
@@ -383,7 +378,7 @@
final StringBuilder buffer = new StringBuilder();
for (final LocalName name : parsedNames) {
if (insertSeparator) {
- buffer.append(separator(name));
+ buffer.append(headSeparator(name));
}
insertSeparator = true;
buffer.append(name.toInternationalString().toString(locale));
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
index 0bcfdff..fdfb57f 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
@@ -37,8 +37,6 @@
import org.apache.sis.util.collection.WeakHashSet;
import org.apache.sis.internal.util.Strings;
-import static org.apache.sis.util.iso.DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
-
/**
* A factory for creating {@link AbstractName} objects.
@@ -293,12 +291,7 @@
*/
@Override
public GenericName parseGenericName(final NameSpace scope, final CharSequence name) {
- final String separator;
- if (scope instanceof DefaultNameSpace) {
- separator = ((DefaultNameSpace) scope).separator;
- } else {
- separator = DEFAULT_SEPARATOR_STRING;
- }
+ final String separator = DefaultNameSpace.getSeparator(scope, false);
final int s = separator.length();
final List<String> names = new ArrayList<>();
int lower = 0;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java
index d0ba3d8..9fbe7bd 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultNameSpace.java
@@ -52,7 +52,7 @@
* remain safe to call from multiple threads and do not change any public {@code NameSpace} state.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.3
*
* @see DefaultScopedName
* @see DefaultLocalName
@@ -98,12 +98,16 @@
/**
* The separator to insert between the namespace and the {@linkplain AbstractName#head() head}
* of any name in that namespace.
+ *
+ * @see #getSeparator(NameSpace, boolean)
*/
- final String headSeparator;
+ private final String headSeparator;
/**
* The separator to insert between the {@linkplain AbstractName#getParsedNames() parsed names}
* of any name in that namespace.
+ *
+ * @see #getSeparator(NameSpace, boolean)
*/
final String separator;
@@ -253,6 +257,31 @@
}
/**
+ * Returns the separator between name components in the given namespace.
+ * If the given namespace is an instance of {@code DefaultNameSpace}, then this method
+ * returns the {@code headSeparator} or {@code separator} argument given to the constructor.
+ * Otherwise this method returns the {@linkplain #DEFAULT_SEPARATOR default separator}.
+ *
+ * <div class="note"><b>API note:</b>
+ * this method is static because the {@code getSeparator(…)} method is not part of GeoAPI interfaces.
+ * A static method makes easier to use without {@code (if (x instanceof DefaultNameSpace)} checks.</div>
+ *
+ * @param ns the namespace for which to get the separator. May be {@code null}.
+ * @param head {@code true} for the separator between namespace and {@linkplain AbstractName#head() head}, or
+ * {@code false} for the separator between {@linkplain AbstractName#getParsedNames() parsed names}.
+ * @return separator between name components.
+ *
+ * @since 1.3
+ */
+ public static String getSeparator(final NameSpace ns, final boolean head) {
+ if (ns instanceof DefaultNameSpace) {
+ final DefaultNameSpace ds = (DefaultNameSpace) ns;
+ return head ? ds.headSeparator : ds.separator;
+ }
+ return DEFAULT_SEPARATOR_STRING;
+ }
+
+ /**
* Indicates whether this namespace is a "top level" namespace. Global, or top-level
* namespaces are not contained within another namespace. The global namespace has no
* parent.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
index 4e57b96..7b25c5a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
@@ -162,13 +162,13 @@
this.container = container;
this.fieldTypes = computeTransientFields(fields);
/*
- * Ensure that the record namespace is equals to the schema name. For example if the schema
+ * Ensure that the record namespace is equal to the schema name. For example if the schema
* name is "MyNameSpace", then the record type name can be "MyNameSpace:MyRecordType".
*/
final LocalName schemaName = container.getSchemaName();
final GenericName fullTypeName = typeName.toFullyQualifiedName();
if (schemaName.compareTo(typeName.scope().name().tip()) != 0) {
- throw new IllegalArgumentException(Errors.format(Errors.Keys.InconsistentNamespace_2, schemaName, fullTypeName));
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.UnexpectedNamespace_2, schemaName, fullTypeName));
}
final int size = size();
for (int i=0; i<size; i++) {
@@ -178,7 +178,7 @@
throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalMemberType_2, name, type));
}
if (fullTypeName.compareTo(name.scope().name()) != 0) {
- throw new IllegalArgumentException(Errors.format(Errors.Keys.InconsistentNamespace_2,
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.UnexpectedNamespace_2,
fullTypeName, name.toFullyQualifiedName()));
}
}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/package-info.java
index fadfbb6..105afcd 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/package-info.java
@@ -99,7 +99,7 @@
* </table>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.3
* @module
*/
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
index 94d925e..b48f4dc 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
@@ -66,7 +66,7 @@
* {@code ValueConverter} to a (un)marshaller.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.5
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -304,13 +304,16 @@
}
/**
- * Converts the given string to a unit. The default implementation is as below, omitting
- * the check for null value and the call to {@link #exceptionOccured exceptionOccured(…)}
- * in case of error:
+ * Converts the given string to a unit.
+ * This method shall accept all the following forms (example for the metre unit):
*
- * {@preformat java
- * return Units.valueOf(value);
- * }
+ * <ul>
+ * <li>{@code m}</li>
+ * <li>{@code EPSG:9001}</li>
+ * <li>{@code urn:ogc:def:uom:epsg::9001}</li>
+ * <li>{@code http://www.opengis.net/def/uom/EPSG/0/9001}</li>
+ * <li>{@code http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])}</li>
+ * </ul>
*
* @param context context (GML version, locale, <i>etc.</i>) of the (un)marshalling process.
* @param value the string to convert to a unit, or {@code null}.
@@ -323,6 +326,36 @@
public Unit<?> toUnit(final MarshalContext context, String value) throws IllegalArgumentException {
value = trimWhitespaces(value);
if (value != null && !value.isEmpty()) try {
+ /*
+ * First, check for X-Paths like below:
+ *
+ * http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])
+ *
+ * Technically the 'm' value in the X-Path is not necessarily a unit symbol.
+ * It is rather a reference to a definition like below:
+ *
+ * <uomItem>
+ * <gml:BaseUnit gml:id="m">
+ * <gml:description>
+ * The metre is the length of the path travelled by ligth in vaccum during a time interval of 1/299 792 458 of a second
+ * </gml:description>
+ * <gml:identifier codeSpace="http://www.bipm.fr/en/si/base_units">metre</gml:identifier>
+ * <gml:quantityType>length</gml:quantityType>
+ * <gml:catalogSymbol codeSpace="http://www.bipm.org/en/si/base_units">m</gml:catalogSymbol>
+ * <gml:unitsSystem xlink:href="http://www.bipm.fr/en/si"/>
+ * </gml:BaseUnit>
+ * </uomItem>
+ *
+ * But current version of this method parses the anchor as if it was a unit symbol,
+ * because we do not have a resolution mechanism yet.
+ */
+ final int endOfURI = XPointer.endOfURI(value, 0);
+ if (endOfURI > 0) {
+ final String anchor = XPointer.UOM.reference(value.substring(0, endOfURI));
+ if (anchor != null) {
+ value = anchor;
+ }
+ }
return Units.valueOf(value);
} catch (ParserException e) {
if (!exceptionOccured(context, value, String.class, Unit.class, e)) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPointer.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/XPointer.java
similarity index 62%
rename from core/sis-utility/src/main/java/org/apache/sis/internal/util/XPointer.java
rename to core/sis-metadata/src/main/java/org/apache/sis/xml/XPointer.java
index 6bacf3b..284568d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPointer.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/XPointer.java
@@ -14,8 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sis.internal.util;
-
+package org.apache.sis.xml;
import static org.apache.sis.util.CharSequences.*;
import static org.apache.sis.internal.util.DefinitionURI.regionMatches;
@@ -25,11 +24,11 @@
* Parsers of pointers in x-paths, adapted to the syntax found in GML documents.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.2
* @module
*/
-public enum XPointer {
+enum XPointer {
/**
* Pointer to units of measurement. Example:
* {@code "http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"})
@@ -63,7 +62,7 @@
private int startOfFragment(final String url) {
final int f = url.indexOf('#');
if (f >= 1) {
- final int i = url.lastIndexOf(XPaths.SEPARATOR, f-1) + 1;
+ final int i = url.lastIndexOf('/', f-1) + 1;
for (final String document : documents) {
if (regionMatches(document, url, i, f)) {
return f + 1;
@@ -110,4 +109,47 @@
}
return null;
}
+
+ /**
+ * If the given character sequences seems to be a URI, returns the presumed end of that URN.
+ * Otherwise returns -1.
+ * Examples:
+ * <ul>
+ * <li>{@code "urn:ogc:def:uom:EPSG::9001"}</li>
+ * <li>{@code "http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"}</li>
+ * </ul>
+ *
+ * @param uri the URI candidate to verify.
+ * @param offset index of the first character to verify.
+ * @return index after the last character of the presumed URI, or -1 if this
+ * method thinks that the given character sequence is not a URI.
+ */
+ public static int endOfURI(final CharSequence uri, int offset) {
+ boolean isURI = false;
+ int parenthesis = 0;
+ final int length = uri.length();
+scan: while (offset < length) {
+ final int c = Character.codePointAt(uri, offset);
+ if (!Character.isLetterOrDigit(c)) {
+ switch (c) {
+ case '#': // Anchor in URL, presumed followed by xpointer.
+ case ':': isURI |= (parenthesis == 0); break; // Scheme or URN separator.
+ case '_':
+ case '-': // Valid character in URL.
+ case '%': // Encoded character in URL.
+ case '.': // Domain name separator in URL.
+ case '/': break; // Path separator, but could also be division as in "m/s".
+ case '(': parenthesis++; break;
+ case ')': parenthesis--; break;
+ default: {
+ if (Character.isSpaceChar(c)) break; // Not supposed to be valid, but be lenient.
+ if (parenthesis != 0) break;
+ break scan; // Non-valid character outside parenthesis.
+ }
+ }
+ }
+ offset += Character.charCount(c);
+ }
+ return isURI ? offset : -1;
+ }
}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/package-info.java
index c12e529..c078aaf 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/package-info.java
@@ -59,7 +59,7 @@
* @author Guilhem Legal (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @author Cullen Rombach (Image Matters)
- * @version 1.2
+ * @version 1.3
* @since 0.3
* @module
*/
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/ModifiableIdentifierMapTest.java b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/ModifiableIdentifierMapTest.java
index ea161da..7e09c87 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/ModifiableIdentifierMapTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/ModifiableIdentifierMapTest.java
@@ -52,7 +52,7 @@
private static final String TO_REPLACE = "xlink:href=“";
/**
- * Asserts that the content of the given map is equals to the given content, represented as a string.
+ * Asserts that the content of the given map is equal to the given content, represented as a string.
* This method replaces the {@code xlink:href} value by the {@link XLink#toString()} value before to
* compare with the map content. This is needed because the "special case rules" cause the {@code "href"}
* identifier to be replaced by {@code "xlink:href"}.
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/SpecialCasesTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/SpecialCasesTest.java
index 365790b..70d623e 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/SpecialCasesTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/SpecialCasesTest.java
@@ -69,14 +69,14 @@
/**
* Invokes {@link SpecialCases#type(int, TypeValuePolicy)}
- * and ensures that the result is equals to the expected value.
+ * and ensures that the result is equal to the expected value.
*/
private void assertTypeEquals(final String name, final Class<?> expected) {
assertEquals(name, expected, accessor.type(accessor.indexOf(name, true), TypeValuePolicy.ELEMENT_TYPE));
}
/**
- * Invokes {@link SpecialCases#get(int, Object)} and ensures that the result is equals to the expected value.
+ * Invokes {@link SpecialCases#get(int, Object)} and ensures that the result is equal to the expected value.
*/
private void assertPropertyEquals(final String name, final Object expected) {
assertEquals(name, expected, accessor.get(accessor.indexOf(name, true), box));
@@ -84,7 +84,7 @@
/**
* Invokes {@link SpecialCases#set(int, Object, Object, int)} in {@code RETURN_PREVIOUS} mode with the given
- * {@code newValue}, and ensures that the return value is equals to the given {@code oldValue}.
+ * {@code newValue}, and ensures that the return value is equal to the given {@code oldValue}.
*/
private void assertPreviousEquals(final String name, final Object oldValue, final Object newValue) {
final Object value = accessor.set(accessor.indexOf(name, true), box, newValue, PropertyAccessor.RETURN_PREVIOUS);
@@ -93,7 +93,7 @@
/**
* Invokes {@link SpecialCases#set(int, Object, Object, int)} in {@code APPEND} mode with the given
- * {@code newValue}, and ensures that the return value is equals to the given {@code changed}.
+ * {@code newValue}, and ensures that the return value is equal to the given {@code changed}.
*/
private void assertAppendResultEquals(final String name, final Boolean changed, final Object newValue) {
final Object value = accessor.set(accessor.indexOf(name, true), box, newValue, PropertyAccessor.APPEND);
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBoxTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBoxTest.java
index 0dfa5d9..3c0582f 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBoxTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBoxTest.java
@@ -323,7 +323,7 @@
/**
* Asserts that the result of applying the {@code add} or {@code intersect} operation on {@code b1}
- * is equals to the given values. This method tests also with horizontally flipped boxes, and tests
+ * is equal to the given values. This method tests also with horizontally flipped boxes, and tests
* with interchanged boxes.
*
* @param union {@code true} for {@code b1.add(b2)}, or {@code false} for {@code b1.intersect(b2)}.
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
index 09667c1..134f1be 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
@@ -147,7 +147,7 @@
@Test
public void testArea() {
/*
- * The nautical mile is equals to the length of 1 second of arc along a meridian or parallel at the equator.
+ * The nautical mile is equal to the length of 1 second of arc along a meridian or parallel at the equator.
* Since we are using the GRS80 authalic sphere instead of WGS84, and since the nautical mile definition
* itself is a little bit approximated, we add a slight empirical shift.
*/
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java b/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
index d05ce40..b900302 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
@@ -58,7 +58,7 @@
}
/**
- * Asserts that the English title of the given citation is equals to the expected string.
+ * Asserts that the English title of the given citation is equal to the expected string.
*
* @param message the message to report in case of test failure.
* @param expected the expected English title.
@@ -77,7 +77,7 @@
/**
* Asserts that the given citation has only one responsible party,
- * and its English name is equals to the expected string.
+ * and its English name is equal to the expected string.
*
* @param message the message to report in case of test failure.
* @param expected the expected English responsibly party name.
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java b/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
index e5c0d00..7b1c1e1 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
@@ -25,7 +25,7 @@
* All tests from the {@code sis-metadata} module, in rough dependency order.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -59,6 +59,7 @@
org.apache.sis.internal.test.DocumentComparatorTest.class,
org.apache.sis.xml.NamespacesTest.class,
org.apache.sis.xml.XLinkTest.class,
+ org.apache.sis.xml.XPointerTest.class,
org.apache.sis.xml.NilReasonTest.class,
org.apache.sis.xml.LegacyCodesTest.class,
org.apache.sis.xml.ValueConverterTest.class,
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
index b8b722e..2fddaa9 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
@@ -910,7 +910,7 @@
getter.isAnnotationPresent(XmlElementRefs.class));
}
/*
- * If the annotation is @XmlElement, ensure that XmlElement.name() is equals
+ * If the annotation is @XmlElement, ensure that XmlElement.name() is equal
* to the UML identifier. Then verify that the namespace is the expected one.
*/
if (element != null) {
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java
index 5b293b0..14a34c3 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java
@@ -715,7 +715,7 @@
* The first line will contain the root of the tree. Other lines will contain
* the child down in the hierarchy until the given node, inclusive.
*
- * <p>This method formats only a summary if the hierarchy is equals to the expected one.</p>
+ * <p>This method formats only a summary if the hierarchy is equal to the expected one.</p>
*
* @param buffer the buffer in which to append the formatted hierarchy.
* @param node the node for which to format the parents.
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/TestCase.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/TestCase.java
index 925ba3b..74d6acd 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/TestCase.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/TestCase.java
@@ -196,7 +196,7 @@
}
/**
- * Marshals the given object and ensure that the result is equals to the content of the given file.
+ * Marshals the given object and ensure that the result is equal to the content of the given file.
*
* @param filename the name of the XML file in the package of the final subclass of {@code this}.
* @param object the object to marshal.
@@ -213,7 +213,7 @@
}
/**
- * Marshals the given object and ensure that the result is equals to the content of the given file.
+ * Marshals the given object and ensure that the result is equal to the content of the given file.
*
* @param filename the name of the XML file in the package of the final subclass of {@code this}.
* @param object the object to marshal.
@@ -231,7 +231,7 @@
}
/**
- * Marshals the given object and ensure that the result is equals to the content of the given file,
+ * Marshals the given object and ensure that the result is equal to the content of the given file,
* within a tolerance threshold for numerical values.
*
* @param filename the name of the XML file in the package of the final subclass of {@code this}.
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/xml/ValueConverterTest.java b/core/sis-metadata/src/test/java/org/apache/sis/xml/ValueConverterTest.java
index 0bbb05c..2d0d6dc 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/xml/ValueConverterTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/xml/ValueConverterTest.java
@@ -22,6 +22,9 @@
import org.apache.sis.test.TestCase;
import org.junit.Test;
+import static org.apache.sis.measure.Units.METRE;
+import static org.apache.sis.measure.Units.DEGREE;
+import static org.apache.sis.measure.Units.RADIAN;
import static org.junit.Assert.*;
@@ -29,7 +32,7 @@
* Tests the {@link ValueConverter} class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.5
+ * @version 1.3
* @since 0.4
* @module
*/
@@ -91,4 +94,17 @@
assertEquals(StandardCharsets.ISO_8859_1, ValueConverter.DEFAULT.toCharset(null, "8859part1"));
assertEquals(StandardCharsets.ISO_8859_1, ValueConverter.DEFAULT.toCharset(null, "ISO-8859-1"));
}
+
+ /**
+ * Tests {@link ValueConverter#toUnit(MarshalContext, String)}.
+ */
+ @Test
+ public void testToUnit() {
+ assertSame(METRE, ValueConverter.DEFAULT.toUnit(null, "http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
+ assertSame(DEGREE, ValueConverter.DEFAULT.toUnit(null, "http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='deg'])"));
+ assertSame(RADIAN, ValueConverter.DEFAULT.toUnit(null, "http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='rad'])"));
+ assertSame(METRE, ValueConverter.DEFAULT.toUnit(null, "gmxUom.xml#m"));
+ assertSame(METRE, ValueConverter.DEFAULT.toUnit(null, "EPSG:9001"));
+ assertSame(DEGREE, ValueConverter.DEFAULT.toUnit(null, "urn:ogc:def:uom:EPSG::9102"));
+ }
}
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/XPointerTest.java b/core/sis-metadata/src/test/java/org/apache/sis/xml/XPointerTest.java
similarity index 68%
rename from core/sis-utility/src/test/java/org/apache/sis/internal/util/XPointerTest.java
rename to core/sis-metadata/src/test/java/org/apache/sis/xml/XPointerTest.java
index c8e952c..ba7c817 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/XPointerTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/xml/XPointerTest.java
@@ -14,8 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sis.internal.util;
+package org.apache.sis.xml;
+import org.apache.sis.util.Characters;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -26,7 +27,7 @@
* Tests {@link XPointer}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.2
* @module
*/
@@ -41,4 +42,17 @@
assertEquals("m", XPointer.UOM.reference("http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/uom/ML_gmxUom.xml#xpointer(//*[@gml:id='m'])"));
assertEquals("m", XPointer.UOM.reference("../uom/ML_gmxUom.xml#xpointer(//*[@gml:id='m'])"));
}
+
+ /**
+ * Tests the {@link XPointer#endOfURI(CharSequence, int)} method.
+ */
+ @Test
+ public void testEndOfURI() {
+ assertEquals(26, XPointer.endOfURI("urn:ogc:def:uom:EPSG::9001", 0));
+ assertEquals(80, XPointer.endOfURI("http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])", 0));
+ assertEquals(97, XPointer.endOfURI("http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])", 0));
+ assertEquals(-1, XPointer.endOfURI("m/s", 0));
+ assertEquals(-1, XPointer.endOfURI("m.s", 0));
+ assertEquals(11, XPointer.endOfURI("EPSG" + Characters.NO_BREAK_SPACE + ": 9001", 0));
+ }
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
index 6f1e13b..a7b24f5 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
@@ -133,7 +133,7 @@
*
* @param dimension the dimension for the coordinate of interest.
* @param value the coordinate value of interest.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() position dimension}.
* @throws UnsupportedOperationException if this direct position is immutable.
*/
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
index a6d372f..09bb5b4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
@@ -355,7 +355,7 @@
*
* @param dimension the dimension for which to obtain the coordinate value.
* @return the starting coordinate value at the given dimension.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() envelope dimension}.
*
* @see #getLowerCorner()
@@ -370,7 +370,7 @@
*
* @param dimension the dimension for which to obtain the coordinate value.
* @return the starting coordinate value at the given dimension.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() envelope dimension}.
*
* @see #getUpperCorner()
@@ -387,7 +387,7 @@
*
* @param dimension the dimension for which to obtain the coordinate value.
* @return the minimal coordinate value at the given dimension.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() envelope dimension}.
*/
@Override
@@ -409,7 +409,7 @@
*
* @param dimension the dimension for which to obtain the coordinate value.
* @return the maximal coordinate value at the given dimension.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() envelope dimension}.
*/
@Override
@@ -424,7 +424,7 @@
/**
* Returns the median coordinate along the specified dimension.
- * In most cases, the result is equals (minus rounding error) to:
+ * In most cases, the result is equal (minus rounding error) to:
*
* {@preformat java
* median = (getUpper(dimension) + getLower(dimension)) / 2;
@@ -442,7 +442,7 @@
*
* @param dimension the dimension for which to obtain the coordinate value.
* @return the median coordinate at the given dimension, or {@link Double#NaN}.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() envelope dimension}.
*
* @see #getMedian()
@@ -477,7 +477,7 @@
/**
* Returns the envelope span (typically width or height) along the specified dimension.
- * In most cases, the result is equals (minus rounding error) to:
+ * In most cases, the result is equal (minus rounding error) to:
*
* {@preformat java
* span = getUpper(dimension) - getLower(dimension);
@@ -493,7 +493,7 @@
*
* @param dimension the dimension for which to obtain the span.
* @return the span (typically width or height) at the given dimension, or {@link Double#NaN}.
- * @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
+ * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater
* than the {@linkplain #getDimension() envelope dimension}.
*/
@Override
@@ -873,7 +873,7 @@
/*
* If this envelope does not cross the anti-meridian but the given envelope does,
* then this envelope does not contain the given envelope except in the special
- * case where the envelope spanning is equals or greater than the axis spanning
+ * case where the envelope spanning is equal or greater than the axis spanning
* (including the case where this envelope expands to infinities).
*/
if ((lower0 == Double.NEGATIVE_INFINITY && upper0 == Double.POSITIVE_INFINITY) ||
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 194ae0e..c06a064 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
@@ -178,7 +178,7 @@
/**
* Value of {@link #desiredPrecisions} which cause {@link #accuracyText} to be shown.
* For each dimension identified by {@link #groundDimensions}, if the corresponding
- * value in {@link #desiredPrecisions} is equals or smaller to this threshold, then
+ * value in {@link #desiredPrecisions} is equal or smaller to this threshold, then
* {@link #accuracyText} will be appended after the formatted coordinates.
*
* @see #desiredPrecisions
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
index c420ab4..e270524 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
@@ -833,7 +833,7 @@
if ((includedMinValue & includedMaxValue & dimensionBitMask) == 0 && CoordinateOperations.isWrapAround(axis)) {
isWrapAroundAxis |= dimensionBitMask;
}
- // Restore `targetPt` to its initial state, which is equals to `centerPt`.
+ // Restore `targetPt` to its initial state, which is equal to `centerPt`.
if (targetPt != null) {
targetPt.setOrdinate(i, centerPt[i]);
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
index 30f6354..62ef1b3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
@@ -23,6 +23,7 @@
import javax.measure.Unit;
import javax.measure.quantity.Time;
import javax.measure.quantity.Length;
+import org.opengis.util.GenericName;
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterNotFoundException;
@@ -63,11 +64,11 @@
* However this class may move in a public package later if we feel confident that its API is mature enough.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.6
* @module
*/
-public final class GeodeticObjectBuilder extends Builder<GeodeticObjectBuilder> {
+public class GeodeticObjectBuilder extends Builder<GeodeticObjectBuilder> {
/**
* The geodetic datum, or {@code null} if none.
*/
@@ -517,8 +518,7 @@
/**
* Replaces the component starting at given index by the given component. This method can be used for replacing
* e.g. the horizontal component of a CRS, or the vertical component, <i>etc.</i>. If a new compound CRS needs
- * to be created and a {@linkplain #addName(org.opengis.util.GenericName) name has been specified}, that name
- * will be used.
+ * to be created and a {@linkplain #addName(GenericName) name has been specified}, that name will be used.
*
* <h4>Limitations</h4>
* Current implementation can replace exactly one component of {@link CompoundCRS}.
@@ -538,7 +538,11 @@
final int srcDim = ReferencingUtilities.getDimension(source);
final int repDim = ReferencingUtilities.getDimension(replacement);
if (firstDimension == 0 && srcDim == repDim) {
- return replacement;
+ /*
+ * conceptually return the replacement. But returning the original instance if applicable
+ * allows the caller to detect that a compound CRS does not need to be replaced.
+ */
+ return source.equals(replacement) ? source : replacement;
}
ArgumentChecks.ensureValidIndex(srcDim - repDim, firstDimension);
if (source instanceof CompoundCRS) {
@@ -556,8 +560,8 @@
Object ids = properties.remove(IdentifiedObject.IDENTIFIERS_KEY);
final CoordinateReferenceSystem nc = replaceComponent(c, firstDimension - lower, replacement);
/*
- * Restore the names and identifiers before to create the final CompoundCRS. If no name was specified,
- * reuse the primary name of existing CRS but not the identifiers.
+ * Restore the names and identifiers before to create the final CompoundCRS.
+ * If no name was specified, reuse the primary name of existing CRS but not the identifiers.
*/
if (name == null) {
name = source.getName();
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 473528a..aa8b68b 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
@@ -509,38 +509,33 @@
}
/**
- * Sets the source and target ellipsoids and coordinate systems to values inferred from the given CRS.
- * The ellipsoids will be non-null only if the given CRS is geographic (not geocentric).
+ * Creates a context with source and target ellipsoids and coordinate systems inferred from the given CRS.
+ * The ellipsoids will be non-null only if the given CRS is geodetic (geographic or geocentric).
*
- * @param sourceCRS the CRS from which to get the source coordinate system and ellipsoid.
- * @param targetCRS the CRS from which to get the target coordinate system and ellipsoid.
- * @param context a pre-allocated context, or {@code null} for creating a new one.
- * @return the given context if it was non-null, or a new context otherwise.
+ * @param sourceCRS the CRS from which to get the source coordinate system and ellipsoid, or {@code null}.
+ * @param targetCRS the CRS from which to get the target coordinate system and ellipsoid, or {@code null}.
+ * @return the context to provides to math transform factory.
*/
public static Context createTransformContext(final CoordinateReferenceSystem sourceCRS,
- final CoordinateReferenceSystem targetCRS, Context context)
+ final CoordinateReferenceSystem targetCRS)
{
- if (context == null) {
- context = new Context();
+ final Context context = new Context();
+ if (sourceCRS instanceof GeodeticCRS) {
+ context.setSource((GeodeticCRS) sourceCRS);
+ } else if (sourceCRS != null) {
+ context.setSource(sourceCRS.getCoordinateSystem());
}
- final CoordinateSystem sourceCS = (sourceCRS != null) ? sourceCRS.getCoordinateSystem() : null;
- final CoordinateSystem targetCS = (targetCRS != null) ? targetCRS.getCoordinateSystem() : null;
- if (sourceCRS instanceof GeodeticCRS && sourceCS instanceof EllipsoidalCS) {
- context.setSource((EllipsoidalCS) sourceCS, ((GeodeticCRS) sourceCRS).getDatum().getEllipsoid());
- } else {
- context.setSource(sourceCS);
- }
- if (targetCRS instanceof GeodeticCRS && targetCS instanceof EllipsoidalCS) {
- context.setTarget((EllipsoidalCS) targetCS, ((GeodeticCRS) targetCRS).getDatum().getEllipsoid());
- } else {
- context.setTarget(targetCS);
+ if (targetCRS instanceof GeodeticCRS) {
+ context.setTarget((GeodeticCRS) targetCRS);
+ } else if (targetCRS != null) {
+ context.setTarget(targetCRS.getCoordinateSystem());
}
return context;
}
/**
* Substitute for the deprecated {@link MathTransformFactory#createBaseToDerived createBaseToDerived(…)} method.
- * This substitute use the full {@code targetCRS} instead of only the coordinate system of the target.
+ * This substitute uses the full {@code targetCRS} instead of only the coordinate system of the target.
* This is needed for setting the {@code "tgt_semi_minor"} and {@code "tgt_semi_major"} parameters of
* Molodensky transformation for example.
*
@@ -561,7 +556,7 @@
{
if (factory instanceof DefaultMathTransformFactory) {
return ((DefaultMathTransformFactory) factory).createParameterizedTransform(
- parameters, createTransformContext(sourceCRS, targetCRS, null));
+ parameters, createTransformContext(sourceCRS, targetCRS));
} else {
// Fallback for non-SIS implementations. Work for map projections but not for Molodensky.
return factory.createBaseToDerived(sourceCRS, parameters, targetCRS.getCoordinateSystem());
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java
index afff092..329bf5c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java
@@ -44,7 +44,7 @@
*
* @author Rueben Schulz (UBC)
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -86,15 +86,7 @@
* @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
*/
private AbridgedMolodensky(int sourceDimensions, int targetDimensions, GeodeticOperation[] redimensioned) {
- super(sourceDimensions, targetDimensions, PARAMETERS, redimensioned);
- }
-
- /**
- * While Abridged Molodensky method is an approximation of geocentric translation, this is not exactly that.
- */
- @Override
- int getType() {
- return OTHER;
+ super(Type.MOLODENSKY, PARAMETERS, sourceDimensions, targetDimensions, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractLambert.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractLambert.java
index 4b73df5..25e79a8 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractLambert.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractLambert.java
@@ -29,7 +29,7 @@
* Base class of providers for all Lambert Conical projections.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.6
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -78,17 +78,7 @@
* For subclass constructors only.
*/
AbstractLambert(final ParameterDescriptorGroup parameters) {
- super(parameters);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code ConicProjection.class}
- */
- @Override
- public final Class<ConicProjection> getOperationType() {
- return ConicProjection.class;
+ super(ConicProjection.class, parameters);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractMercator.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractMercator.java
index 417dfb6..e4ecf0e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractMercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractMercator.java
@@ -31,7 +31,7 @@
* Base class of providers for all Mercator projections, and for Mercator-like projections.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -97,17 +97,7 @@
* For subclass constructors only.
*/
AbstractMercator(final ParameterDescriptorGroup parameters) {
- super(parameters);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code CylindricalProjection.class}
- */
- @Override
- public final Class<CylindricalProjection> getOperationType() {
- return CylindricalProjection.class;
+ super(CylindricalProjection.class, parameters);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
index 78738e9..eb2e7aa 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
@@ -24,7 +24,8 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.operation.SingleOperation;
import org.apache.sis.internal.util.Constants;
import org.apache.sis.measure.Units;
import org.apache.sis.measure.Latitude;
@@ -43,12 +44,15 @@
import static java.util.logging.Logger.getLogger;
+// Branch-dependent imports
+import org.opengis.referencing.ReferenceIdentifier;
+
/**
* Base class for all providers defined in this package.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -57,7 +61,45 @@
/**
* For cross-version compatibility.
*/
- private static final long serialVersionUID = 2239172887926695217L;
+ private static final long serialVersionUID = 1165868434518724597L;
+
+ /**
+ * The base interface of the {@code CoordinateOperation} instances that use this method.
+ *
+ * @see #getOperationType()
+ */
+ private final Class<? extends SingleOperation> operationType;
+
+ /**
+ * The base interface of the coordinate system of source/target coordinates.
+ * This is used for resolving some ambiguities at WKT parsing time.
+ */
+ public final Class<? extends CoordinateSystem> sourceCSType, targetCSType;
+
+ /**
+ * Flags whether the source and/or target ellipsoid are concerned by this operation. Those flags are read by
+ * {@link org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory} for determining if this
+ * operation has {@code "semi_major"}, {@code "semi_minor"}, {@code "src_semi_major"}, {@code "src_semi_minor"}
+ * parameters that may need to be filled with values inferred from the source or target
+ * {@link org.apache.sis.referencing.datum.DefaultGeodeticDatum}.
+ * Meaning of return values:
+ *
+ * <ul>
+ * <li>({@code false},{@code false}) if neither the source coordinate system or the destination
+ * coordinate system is ellipsoidal. There are no parameters that need to be completed.</li>
+ * <li>({@code true},{@code false}) if this operation has {@code "semi_major"} and {@code "semi_minor"}
+ * parameters that need to be set to the axis lengths of the source ellipsoid.</li>
+ * <li>({@code false},{@code true}) if this operation has {@code "semi_major"} and {@code "semi_minor"}
+ * parameters that need to be set to the axis lengths of the target ellipsoid.</li>
+ * <li>({@code true},{@code true}) if this operation has {@code "src_semi_major"}, {@code "src_semi_minor"},
+ * {@code "tgt_semi_major"} and {@code "tgt_semi_minor"} parameters that need to be set to the axis lengths
+ * of the source and target ellipsoids.</li>
+ * </ul>
+ *
+ * Those flags are only hints. If the information is not provided, {@code DefaultMathTransformFactory}
+ * will try to infer it from the type of user-specified source and target CRS.
+ */
+ public final boolean sourceOnEllipsoid, targetOnEllipsoid;
/**
* Constructs a math transform provider from the given properties and a set of parameters.
@@ -67,27 +109,42 @@
* @param targetDimension number of dimensions in the target CRS of this operation method.
* @param parameters the set of parameters (never {@code null}).
*/
- AbstractProvider(final Map<String,?> properties,
- final int sourceDimension,
- final int targetDimension,
- final ParameterDescriptorGroup parameters)
+ protected AbstractProvider(final Map<String,?> properties,
+ final int sourceDimension,
+ final int targetDimension,
+ final ParameterDescriptorGroup parameters)
{
super(properties, sourceDimension, targetDimension, parameters);
+ operationType = SingleOperation.class;
+ sourceCSType = CoordinateSystem.class;
+ targetCSType = CoordinateSystem.class;
+ sourceOnEllipsoid = false;
+ targetOnEllipsoid = false;
}
/**
* Constructs a math transform provider from a set of parameters. The provider name and
* {@linkplain #getIdentifiers() identifiers} will be the same than the parameter ones.
*
- * @param sourceDimensions number of dimensions in the source CRS of this operation method.
- * @param targetDimensions number of dimensions in the target CRS of this operation method.
- * @param parameters description of parameters expected by this operation.
+ * @param operationType base interface of the {@code CoordinateOperation} instances that use this method.
+ * @param parameters description of parameters expected by this operation.
+ * @param sourceDimensions number of dimensions in the source CRS of this operation method.
+ * @param sourceCSType base interface of the coordinate system of source coordinates.
+ * @param sourceOnEllipsoid whether the operation needs source ellipsoid axis lengths.
+ * @param targetDimensions number of dimensions in the target CRS of this operation method.
+ * @param targetCSType base interface of the coordinate system of target coordinates.
+ * @param targetOnEllipsoid whether the operation needs target ellipsoid axis lengths.
*/
- AbstractProvider(final int sourceDimensions,
- final int targetDimensions,
- final ParameterDescriptorGroup parameters)
+ AbstractProvider(final Class<? extends SingleOperation> operationType, final ParameterDescriptorGroup parameters,
+ final Class<? extends CoordinateSystem> sourceCSType, final int sourceDimensions, final boolean sourceOnEllipsoid,
+ final Class<? extends CoordinateSystem> targetCSType, final int targetDimensions, final boolean targetOnEllipsoid)
{
super(toMap(parameters), sourceDimensions, targetDimensions, parameters);
+ this.operationType = operationType;
+ this.sourceCSType = sourceCSType;
+ this.targetCSType = targetCSType;
+ this.sourceOnEllipsoid = sourceOnEllipsoid;
+ this.targetOnEllipsoid = targetOnEllipsoid;
}
/**
@@ -212,32 +269,14 @@
}
/**
- * Flags whether the source and/or target ellipsoid are concerned by this operation. This method is invoked by
- * {@link org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory} for determining if this
- * operation has {@code "semi_major"}, {@code "semi_minor"}, {@code "src_semi_major"}, {@code "src_semi_minor"}
- * parameters that may need to be filled with values inferred from the source or target
- * {@link org.apache.sis.referencing.datum.DefaultGeodeticDatum}.
- * Meaning of return values:
+ * Returns the interface implemented by the coordinate operation.
+ * This method returns the type specified at construction time.
*
- * <ul>
- * <li>0 if neither the source coordinate system or the destination coordinate system is ellipsoidal.
- * There are no parameters that need to be completed.</li>
- * <li>1 if this operation has {@code "semi_major"} and {@code "semi_minor"} parameters that need
- * to be set to the axis lengths of the source ellipsoid.</li>
- * <li>2 if this operation has {@code "semi_major"} and {@code "semi_minor"} parameters that need
- * to be set to the axis lengths of the target ellipsoid.</li>
- * <li>3 if this operation has {@code "src_semi_major"}, {@code "src_semi_minor"}, {@code "tgt_semi_major"}
- * and {@code "tgt_semi_minor"} parameters that need to be set to the axis lengths of the source and
- * target ellipsoids.</li>
- * </ul>
- *
- * This method is just a hint. If the information is not provided, {@code DefaultMathTransformFactory}
- * will try to infer it from the type of user-specified source and target CRS.
- *
- * @return 0, 1, 2 or 3.
+ * @return interface implemented by all coordinate operations that use this method.
*/
- public int getEllipsoidsMask() {
- return 0;
+ @Override
+ public final Class<? extends SingleOperation> getOperationType() {
+ return operationType;
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractStereographic.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractStereographic.java
index d15a4a9..0de2d14 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractStereographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractStereographic.java
@@ -30,7 +30,7 @@
* Base class of providers for all Stereographic projections.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -79,17 +79,7 @@
* For subclass constructors only.
*/
AbstractStereographic(final ParameterDescriptorGroup parameters) {
- super(parameters);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code PlanarProjection.class}
- */
- @Override
- public final Class<PlanarProjection> getOperationType() {
- return PlanarProjection.class;
+ super(PlanarProjection.class, parameters);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AlbersEqualArea.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AlbersEqualArea.java
index 93b512d..5267604 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AlbersEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AlbersEqualArea.java
@@ -31,7 +31,7 @@
*
* @author Rueben Schulz (UBC)
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/albers_equal_area_conic.html">GeoTIFF parameters for Albers Equal-Area Conic</a>
*
@@ -250,17 +250,7 @@
* Constructs a new provider.
*/
public AlbersEqualArea() {
- super(PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code ConicProjection.class}
- */
- @Override
- public final Class<ConicProjection> getOperationType() {
- return ConicProjection.class;
+ super(ConicProjection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal.java
index 7545371..eebde60 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal.java
@@ -19,6 +19,7 @@
import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -29,11 +30,11 @@
/**
* The provider for <cite>"axis order reversal (2D)"</cite> (EPSG:9843).
- * This is a trivial operation that just swap the two axes.
+ * This is a trivial operation that just swap the two first axes.
* The inverse operation is this operation itself.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -59,7 +60,7 @@
* Constructs a provider with default parameters.
*/
public AxisOrderReversal() {
- super(2, 2, PARAMETERS);
+ this(PARAMETERS, 2);
}
/**
@@ -68,18 +69,10 @@
* @param dimensions number of dimensions in the source and target CRS of this operation method.
* @param parameters description of parameters expected by this operation.
*/
- AxisOrderReversal(final int dimensions, final ParameterDescriptorGroup parameters) {
- super(dimensions, dimensions, parameters);
- }
-
- /**
- * Returns the operation type.
- *
- * @return interface implemented by all coordinate operations that use this method.
- */
- @Override
- public final Class<Conversion> getOperationType() {
- return Conversion.class;
+ AxisOrderReversal(final ParameterDescriptorGroup parameters, final int dimensions) {
+ super(Conversion.class, parameters,
+ CoordinateSystem.class, dimensions, false,
+ CoordinateSystem.class, dimensions, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal3D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal3D.java
index 019d62c..1ad20ce 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal3D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AxisOrderReversal3D.java
@@ -26,7 +26,7 @@
* The inverse operation is this operation itself.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -47,6 +47,6 @@
* Constructs a provider with default parameters.
*/
public AxisOrderReversal3D() {
- super(3, PARAMETERS);
+ super(PARAMETERS, 3);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AzimuthalEquidistantSpherical.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AzimuthalEquidistantSpherical.java
index e5727b7..294c733 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AzimuthalEquidistantSpherical.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AzimuthalEquidistantSpherical.java
@@ -28,7 +28,7 @@
* This projection method has no EPSG code.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/azimuthal_equidistant.html">GeoTIFF parameters for Azimuthal Equidistant</a>
*
@@ -60,15 +60,7 @@
* Constructs a new provider.
*/
public AzimuthalEquidistantSpherical() {
- super(PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- */
- @Override
- public Class<PlanarProjection> getOperationType() {
- return PlanarProjection.class;
+ super(PlanarProjection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CassiniSoldner.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CassiniSoldner.java
index 307b019..b71609e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CassiniSoldner.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CassiniSoldner.java
@@ -19,6 +19,7 @@
import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.operation.Projection;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.referencing.operation.projection.NormalizedProjection;
import org.apache.sis.parameter.Parameters;
@@ -29,7 +30,7 @@
* This projection is similar to {@link TransverseMercator}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/cassini_soldner.html">GeoTIFF parameters for Cassini-Soldner</a>
*
@@ -161,14 +162,14 @@
* Constructs a new provider.
*/
public CassiniSoldner() {
- super(PARAMETERS);
+ this(PARAMETERS);
}
/**
* Constructs a provider from a set of parameters.
*/
CassiniSoldner(final ParameterDescriptorGroup parameters) {
- super(parameters);
+ super(Projection.class, parameters);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java
index c56dde6..19250d6 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java
@@ -26,7 +26,7 @@
* except that the rotation angles have the opposite sign.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -57,14 +57,6 @@
* Constructs the provider.
*/
public CoordinateFrameRotation() {
- super(3, 3, PARAMETERS, null);
- }
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return FRAME_ROTATION;
+ super(Type.FRAME_ROTATION, PARAMETERS, 3, 3, null);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java
index 793ee0ba..0636a5c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java
@@ -27,7 +27,7 @@
* except that the rotation angles have the opposite sign.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -66,7 +66,7 @@
* Constructs a provider that can be resized.
*/
CoordinateFrameRotation2D(GeodeticOperation[] redimensioned) {
- super(2, 2, PARAMETERS, redimensioned);
+ super(Type.FRAME_ROTATION, PARAMETERS, 2, 2, redimensioned);
}
/**
@@ -76,12 +76,4 @@
Class<CoordinateFrameRotation3D> variant3D() {
return CoordinateFrameRotation3D.class;
}
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return FRAME_ROTATION;
- }
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java
index 12807fb..3bad35f 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java
@@ -26,7 +26,7 @@
* except that the rotation angles have the opposite sign.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -72,14 +72,6 @@
* @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
*/
private CoordinateFrameRotation3D(int sourceDimensions, int targetDimensions, GeodeticOperation[] redimensioned) {
- super(sourceDimensions, targetDimensions, PARAMETERS, redimensioned);
- }
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return FRAME_ROTATION;
+ super(Type.FRAME_ROTATION, PARAMETERS, sourceDimensions, targetDimensions, redimensioned);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
index aceb60b..690a331 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
@@ -22,6 +22,8 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.CylindricalProjection;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -61,7 +63,7 @@
*
* @author John Grange
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
*
* @see PseudoPlateCarree
* @see <a href="http://geotiff.maptools.org/proj_list/equirectangular.html">GeoTIFF parameters for Equirectangular</a>
@@ -270,30 +272,13 @@
/**
* Constructs a new provider.
+ *
+ * @see MapProjection#MapProjection(Class, ParameterDescriptorGroup)
*/
public Equirectangular() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code CylindricalProjection.class}
- */
- @Override
- public Class<CylindricalProjection> getOperationType() {
- return CylindricalProjection.class;
- }
-
- /**
- * Notifies {@code DefaultMathTransformFactory} that map projections require
- * values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
- *
- * @return 1, meaning that the operation requires a source ellipsoid.
- */
- @Override
- public final int getEllipsoidsMask() {
- return 1;
+ super(CylindricalProjection.class, PARAMETERS,
+ EllipsoidalCS.class, 2, true,
+ CartesianCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java
index 73435de..8fab5d5 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java
@@ -38,6 +38,8 @@
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.parameter.InvalidParameterValueException;
import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.operation.Transformation;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.NoninvertibleTransformException;
@@ -84,7 +86,7 @@
*
* @author Simon Reynard (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -242,7 +244,9 @@
final ParameterDescriptorGroup parameters,
final GeodeticOperation[] redimensioned)
{
- super(sourceDimensions, targetDimensions, parameters, redimensioned);
+ super(Transformation.class, parameters,
+ EllipsoidalCS.class, sourceDimensions, true,
+ EllipsoidalCS.class, targetDimensions, true, redimensioned);
}
/**
@@ -269,18 +273,6 @@
}
/**
- * Notifies {@code DefaultMathTransformFactory} that map projections require values for the
- * {@code "src_semi_major"}, {@code "src_semi_minor"} , {@code "tgt_semi_major"} and
- * {@code "tgt_semi_minor"} parameters.
- *
- * @return 3, meaning that the operation requires source and target ellipsoids.
- */
- @Override
- public int getEllipsoidsMask() {
- return 3;
- }
-
- /**
* Creates the source or the target ellipsoid. This is a temporary ellipsoid
* used only at {@link InterpolatedGeocentricTransform} time, then discarded.
*
@@ -337,6 +329,7 @@
final Path file = pg.getMandatoryValue(FILE);
final DatumShiftGridFile<Angle,Length> grid = getOrLoad(file,
isRecognized(file) ? new double[] {TX, TY, TZ} : null, PRECISION);
+
MathTransform tr = createGeodeticTransformation(factory,
createEllipsoid(pg, Molodensky.TGT_SEMI_MAJOR,
Molodensky.TGT_SEMI_MINOR, CommonCRS.ETRS89.ellipsoid()), // GRS 1980 ellipsoid
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java
index ff3ecc2..0488d2b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java
@@ -28,6 +28,8 @@
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.Transformation;
import org.apache.sis.internal.referencing.Formulas;
import org.apache.sis.internal.referencing.WKTUtilities;
import org.apache.sis.internal.referencing.WKTKeywords;
@@ -58,16 +60,25 @@
* "Geocentric translations" is an operation name defined by EPSG.</div>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.7
* @module
*/
@XmlTransient
public abstract class GeocentricAffine extends GeodeticOperation {
/**
+ * The transformation type (translation, frame rotation, <i>etc.</i>).
+ *
+ * @todo Merge with {@link DatumShiftMethod}.
+ *
+ * @see #type
+ */
+ protected enum Type {TRANSLATION, SEVEN_PARAM, FRAME_ROTATION, MOLODENSKY, CONVERSION};
+
+ /**
* Serial number for inter-operability with different versions.
*/
- private static final long serialVersionUID = 8291967302538661639L;
+ private static final long serialVersionUID = 5597594719123422532L;
/**
* The tolerance factor for comparing the {@link BursaWolfParameters} values.
@@ -206,27 +217,42 @@
}
/**
- * Return value for {@link #getType()}.
+ * The transformation type (translation, frame rotation, <i>etc.</i>).
*/
- static final int TRANSLATION=1, SEVEN_PARAM=2, FRAME_ROTATION=3, OTHER=0;
+ private final Type type;
/**
* Constructs a provider with the specified parameters.
*
- * @param sourceDimensions number of dimensions in the source CRS of this operation method.
- * @param targetDimensions number of dimensions in the target CRS of this operation method.
- * @param parameters description of parameters expected by this operation.
- * @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
+ * @param type the operation type as an enumeration value.
+ * @param parameters description of parameters expected by this operation.
+ * @param sourceDimensions number of dimensions in the source CRS of this operation method.
+ * @param sourceCSType base interface of the coordinate system of source coordinates.
+ * @param sourceOnEllipsoid whether the operation needs source ellipsoid axis lengths.
+ * @param targetDimensions number of dimensions in the target CRS of this operation method.
+ * @param targetCSType base interface of the coordinate system of target coordinates.
+ * @param targetOnEllipsoid whether the operation needs target ellipsoid axis lengths.
+ * @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
*/
- GeocentricAffine(int sourceDimensions, int targetDimensions, ParameterDescriptorGroup parameters, GeodeticOperation[] redimensioned) {
- super(sourceDimensions, targetDimensions, parameters, redimensioned);
+ GeocentricAffine(Type operationType, ParameterDescriptorGroup parameters,
+ Class<? extends CoordinateSystem> sourceCSType, int sourceDimensions, boolean sourceOnEllipsoid,
+ Class<? extends CoordinateSystem> targetCSType, int targetDimensions, boolean targetOnEllipsoid,
+ GeodeticOperation[] redimensioned)
+ {
+ super((operationType == Type.CONVERSION) ? Conversion.class : Transformation.class, parameters,
+ sourceCSType, sourceDimensions, sourceOnEllipsoid,
+ targetCSType, targetDimensions, targetOnEllipsoid, redimensioned);
+ type = operationType;
}
/**
- * Returns the operation sub-type as one of {@link #TRANSLATION}, {@link #SEVEN_PARAM},
- * {@link #FRAME_ROTATION} or {@link #OTHER} constants.
+ * Constructs a provider with the specified parameters for an operation in Cartesian space.
*/
- abstract int getType();
+ GeocentricAffine(Type operationType, ParameterDescriptorGroup parameters, int sourceDimensions, int targetDimensions, GeodeticOperation[] redimensioned) {
+ this(operationType, parameters,
+ CartesianCS.class, sourceDimensions, false,
+ CartesianCS.class, targetDimensions, false, redimensioned);
+ }
/**
* Creates a math transform from the specified group of parameter values.
@@ -246,8 +272,8 @@
final BursaWolfParameters parameters = new BursaWolfParameters(null, null);
final Parameters pv = Parameters.castOrWrap(values);
boolean reverseRotation = false;
- switch (getType()) {
- default: throw new AssertionError();
+ switch (type) {
+ default: throw new AssertionError(type);
case FRAME_ROTATION: reverseRotation = true; // Fall through
case SEVEN_PARAM: parameters.rX = pv.doubleValue(RX);
parameters.rY = pv.doubleValue(RY);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
index 96a2e34..32f5e45 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
@@ -21,6 +21,7 @@
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.NoninvertibleTransformException;
@@ -38,8 +39,17 @@
* operation methods performing <em>approximation</em> of above, even if they do not really pass
* through geocentric coordinates.
*
+ * <h2>Default values to verify</h2>
+ * This class assumes the following default values.
+ * Subclasses should verify if those default values are suitable from them:
+ *
+ * <ul>
+ * <li>{@link #getOperationType()} defaults to {@link org.opengis.referencing.operation.Transformation}.</li>
+ * <li>{@link #sourceCSType} and {@link #targetCSType} default to {@link EllipsoidalCS}.</li>
+ * </ul>
+ *
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -157,27 +167,18 @@
/**
* Constructs a provider with the specified parameters.
*
+ * @param type the operation type as an enumeration value.
+ * @param parameters description of parameters expected by this operation.
* @param sourceDimensions number of dimensions in the source CRS of this operation method.
* @param targetDimensions number of dimensions in the target CRS of this operation method.
- * @param parameters description of parameters expected by this operation.
* @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
*/
- GeocentricAffineBetweenGeographic(int sourceDimensions, int targetDimensions,
- ParameterDescriptorGroup parameters, GeodeticOperation[] redimensioned)
+ GeocentricAffineBetweenGeographic(Type operationType, ParameterDescriptorGroup parameters,
+ int sourceDimensions, int targetDimensions, GeodeticOperation[] redimensioned)
{
- super(sourceDimensions, targetDimensions, parameters, redimensioned);
- }
-
- /**
- * Notifies {@code DefaultMathTransformFactory} that this operation requires values for
- * the {@code "src_semi_major"}, {@code "src_semi_minor"}, {@code "tgt_semi_major"} and
- * {@code "tgt_semi_minor"} parameters.
- *
- * @return 3, meaning that the operation requires source and target ellipsoids.
- */
- @Override
- public final int getEllipsoidsMask() {
- return 3;
+ super(operationType, parameters,
+ EllipsoidalCS.class, sourceDimensions, true,
+ EllipsoidalCS.class, targetDimensions, true, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java
index 3c67c3c..161d313 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java
@@ -22,6 +22,8 @@
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.util.FactoryException;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.parameter.Parameters;
@@ -32,7 +34,7 @@
* This provider creates transforms from geocentric to geographic coordinate reference systems.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see GeographicToGeocentric
*
@@ -77,28 +79,9 @@
* @param redimensioned providers for all combinations between 2D and 3D cases.
*/
private GeocentricToGeographic(int targetDimensions, GeodeticOperation[] redimensioned) {
- super(3, targetDimensions, PARAMETERS, redimensioned);
- }
-
- /**
- * Returns the operation type.
- *
- * @return {@code Conversion.class}.
- */
- @Override
- public Class<Conversion> getOperationType() {
- return Conversion.class;
- }
-
- /**
- * Notifies {@code DefaultMathTransformFactory} that Geographic/geocentric conversions
- * require values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
- *
- * @return 2, meaning that the operation requires a target ellipsoid.
- */
- @Override
- public int getEllipsoidsMask() {
- return 2;
+ super(Conversion.class, PARAMETERS,
+ CartesianCS.class, 3, false,
+ EllipsoidalCS.class, targetDimensions, true, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToTopocentric.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToTopocentric.java
new file mode 100644
index 0000000..18141be
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToTopocentric.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.referencing.provider;
+
+import javax.measure.Unit;
+import javax.measure.quantity.Length;
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.referencing.operation.transform.EllipsoidToCentricTransform;
+import org.apache.sis.referencing.operation.matrix.Matrix4;
+import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.measure.Units;
+import org.apache.sis.internal.util.Constants;
+
+import static java.lang.Math.cos;
+import static java.lang.Math.sin;
+import static java.lang.Math.toRadians;
+
+
+/**
+ * The provider for the <cite>"Geocentric/topocentric conversions"</cite> (EPSG:9836).
+ * This operation is implemented using existing {@link MathTransform} implementations;
+ * there is no need for a class specifically for this transform.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 1.3
+ * @module
+ */
+public final class GeocentricToTopocentric extends AbstractProvider {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = 6064563343153407987L;
+
+ /**
+ * The operation parameter descriptor for the <cite>Geocentric X of topocentric origin</cite> (X) parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ * <table class="sis">
+ * <caption>Parameter names</caption>
+ * <tr><td> EPSG: </td><td> Geocentric X of topocentric origin </td></tr>
+ * </table>
+ * <b>Notes:</b>
+ * <ul>
+ * <li>No default value</li>
+ * </ul>
+ */
+ private static final ParameterDescriptor<Double> ORIGIN_X;
+
+ /**
+ * The operation parameter descriptor for the <cite>Geocentric Y of topocentric origin</cite> (Y) parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ * <table class="sis">
+ * <caption>Parameter names</caption>
+ * <tr><td> EPSG: </td><td> Geocentric Y of topocentric origin </td></tr>
+ * </table>
+ * <b>Notes:</b>
+ * <ul>
+ * <li>No default value</li>
+ * </ul>
+ */
+ private static final ParameterDescriptor<Double> ORIGIN_Y;
+
+ /**
+ * The operation parameter descriptor for the <cite>Geocentric Z of topocentric origin</cite> (Z) parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ * <table class="sis">
+ * <caption>Parameter names</caption>
+ * <tr><td> EPSG: </td><td> Geocentric Z of topocentric origin </td></tr>
+ * </table>
+ * <b>Notes:</b>
+ * <ul>
+ * <li>No default value</li>
+ * </ul>
+ */
+ private static final ParameterDescriptor<Double> ORIGIN_Z;
+
+ /**
+ * The group of all parameters expected by this coordinate operation.
+ */
+ private static final ParameterDescriptorGroup PARAMETERS;
+ static {
+ final ParameterBuilder builder = builder();
+ ORIGIN_X = builder
+ .addIdentifier("8837")
+ .addName("Geocentric X of topocentric origin")
+ .create(Double.NaN, Units.METRE);
+
+ ORIGIN_Y = builder
+ .addIdentifier("8838")
+ .addName("Geocentric Y of topocentric origin")
+ .create(Double.NaN, Units.METRE);
+
+ ORIGIN_Z = builder
+ .addIdentifier("8839")
+ .addName("Geocentric Z of topocentric origin")
+ .create(Double.NaN, Units.METRE);
+
+ PARAMETERS = builder
+ .addIdentifier("9836")
+ .addName("Geocentric/topocentric conversions")
+ .createGroupForMapProjection(ORIGIN_X, ORIGIN_Y, ORIGIN_Z);
+ // Not really a map projection, but we leverage the same axis parameters.
+ }
+
+ /**
+ * Constructs a provider for the 3-dimensional case.
+ */
+ public GeocentricToTopocentric() {
+ super(Conversion.class, PARAMETERS,
+ CartesianCS.class, 3, true,
+ CartesianCS.class, 3, false);
+ }
+
+ /**
+ * Creates a transform from the specified group of parameter values.
+ * The unit of measurement of input coordinates will be the units of the ellipsoid axes.
+ *
+ * @param factory the factory to use for creating the transform.
+ * @param values the parameter values that define the transform to create.
+ * @return the conversion from geocentric to topocentric coordinates.
+ * @throws FactoryException if an error occurred while creating a transform.
+ */
+ @Override
+ public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
+ throws FactoryException
+ {
+ try {
+ return create(factory, Parameters.castOrWrap(values), false);
+ } catch (TransformException e) {
+ throw new FactoryException(e);
+ }
+ }
+
+ /**
+ * Implementation of {@link #createMathTransform(MathTransformFactory, ParameterValueGroup)}
+ * shared with {@link GeographicToTopocentric}.
+ *
+ * @param factory the factory to use for creating the transform.
+ * @param values the parameter values that define the transform to create.
+ * @param geographic {@code true} if the source coordinates are geographic, or
+ * {@code false} if the source coordinates are geocentric.
+ */
+ static MathTransform create(final MathTransformFactory factory, final Parameters values, final boolean geographic)
+ throws FactoryException, TransformException
+ {
+ final ParameterValue<?> ap = values.parameter(Constants.SEMI_MAJOR);
+ final Unit<Length> unit = ap.getUnit().asType(Length.class);
+ final double a = ap.doubleValue();
+ final double b = values.parameter(Constants.SEMI_MINOR).doubleValue(unit);
+ final double x, y, z, λ, φ;
+ final MathTransform toGeocentric;
+ if (geographic) {
+ /*
+ * Full conversion from (longitude, latitude, height) in degrees
+ * to geocentric coordinates in linear units (usually metres).
+ */
+ toGeocentric = EllipsoidToCentricTransform.createGeodeticConversion(factory,
+ a, b, unit, true, EllipsoidToCentricTransform.TargetType.CARTESIAN);
+
+ final double[] origin = new double[] {
+ values.doubleValue(GeographicToTopocentric.ORIGIN_X),
+ values.doubleValue(GeographicToTopocentric.ORIGIN_Y),
+ values.doubleValue(GeographicToTopocentric.ORIGIN_Z)};
+
+ λ = toRadians(origin[0]);
+ φ = toRadians(origin[1]);
+ toGeocentric.transform(origin, 0, origin, 0, 1);
+ x = origin[0];
+ y = origin[1];
+ z = origin[2];
+ } else {
+ /*
+ * Shorter conversion from (longitude, latitude) in radians to
+ * geocentric coordinates as fractions of semi-major axis length.
+ * This conversion is used only in this block and is not kept.
+ */
+ toGeocentric = new EllipsoidToCentricTransform(
+ a, b, unit, false, EllipsoidToCentricTransform.TargetType.CARTESIAN);
+
+ final double[] origin = new double[] {
+ (x = values.doubleValue(ORIGIN_X, unit)) / a,
+ (y = values.doubleValue(ORIGIN_Y, unit)) / a,
+ (z = values.doubleValue(ORIGIN_Z, unit)) / a};
+
+ toGeocentric.inverse().transform(origin, 0, origin, 0, 1);
+ λ = origin[0]; // Already in radians.
+ φ = origin[1];
+ }
+ final double sinλ = sin(λ);
+ final double cosλ = cos(λ);
+ final double sinφ = sin(φ);
+ final double cosφ = cos(φ);
+ /*
+ * Following transform uses the inverse of the matrix R given in EPSG guidance note
+ * because it allows us to put the (x,y,z) translation terms directly in the matrix.
+ */
+ MathTransform mt = factory.createAffineTransform(new Matrix4(
+ -sinλ, -sinφ*cosλ, cosφ*cosλ, x,
+ cosλ, -sinφ*sinλ, cosφ*sinλ, y,
+ 0, cosφ, sinφ, z,
+ 0, 0, 0, 1)).inverse();
+ if (geographic) {
+ mt = factory.createConcatenatedTransform(toGeocentric, mt);
+ }
+ return mt;
+ }
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java
index b2d75a4..30c55e1 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java
@@ -26,7 +26,7 @@
* can be set to a non-null value.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -52,14 +52,6 @@
* Constructs the provider.
*/
public GeocentricTranslation() {
- super(3, 3, PARAMETERS, null);
- }
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return TRANSLATION;
+ super(Type.TRANSLATION, PARAMETERS, 3, 3, null);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java
index 2ddc373..9adfcfd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java
@@ -27,7 +27,7 @@
* terms can be set to a non-null value.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -65,7 +65,7 @@
* Constructs a provider that can be resized.
*/
GeocentricTranslation2D(GeodeticOperation[] redimensioned) {
- super(2, 2, PARAMETERS, redimensioned);
+ super(Type.TRANSLATION, PARAMETERS, 2, 2, redimensioned);
}
/**
@@ -75,12 +75,4 @@
Class<GeocentricTranslation3D> variant3D() {
return GeocentricTranslation3D.class;
}
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return TRANSLATION;
- }
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java
index 9a09fec..7e3ec85 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java
@@ -26,7 +26,7 @@
* terms can be set to a non-null value.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -67,14 +67,6 @@
* @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
*/
private GeocentricTranslation3D(int sourceDimensions, int targetDimensions, GeodeticOperation[] redimensioned) {
- super(sourceDimensions, targetDimensions, PARAMETERS, redimensioned);
- }
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return TRANSLATION;
+ super(Type.TRANSLATION, PARAMETERS, sourceDimensions, targetDimensions, redimensioned);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java
index d57b33c..1590b27 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java
@@ -18,9 +18,9 @@
import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.operation.OperationMethod;
import org.opengis.referencing.operation.SingleOperation;
-import org.opengis.referencing.operation.Transformation;
/**
@@ -31,7 +31,7 @@
* variants are specific to Apache SIS and can be fetched only by a call to {@link #redimension(int, int)}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -54,9 +54,13 @@
* <strong>Do not modify this array after construction</strong>, since the same array is shared by many
* objects and there is no synchronization.
*
- * @deprecated ISO 19111:2019 removed source/target dimensions attributes.
+ * <div class="note"><b>Historical note:</b>
+ * in ISO 19111:2007, the {@code OperationMethod} type had two attributes for the number of source
+ * and target dimensions. Those attributes have been removed in ISO 19111:2019 revision because not
+ * really needed in practice. However the EPSG database still distinguishes between 2D and 3D variants
+ * for some of those operations, so we still need the capability to switch operation methods according
+ * to the number of dimensions.</div>
*/
- @Deprecated
final GeodeticOperation[] redimensioned;
/**
@@ -72,17 +76,24 @@
* <li>3 → 3 dimensions in {@code redimensioned[3]}</li>
* </ol>
*
- * @param sourceDimensions number of dimensions in the source CRS of this operation method.
- * @param targetDimensions number of dimensions in the target CRS of this operation method.
- * @param parameters description of parameters expected by this operation.
- * @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
+ * @param operationType base interface of the {@code CoordinateOperation} instances that use this method.
+ * @param parameters description of parameters expected by this operation.
+ * @param sourceDimensions number of dimensions in the source CRS of this operation method.
+ * @param sourceCSType base interface of the coordinate system of source coordinates.
+ * @param sourceOnEllipsoid whether the operation needs source ellipsoid axis lengths.
+ * @param targetDimensions number of dimensions in the target CRS of this operation method.
+ * @param targetCSType base interface of the coordinate system of target coordinates.
+ * @param targetOnEllipsoid whether the operation needs target ellipsoid axis lengths.
+ * @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
*/
- GeodeticOperation(final int sourceDimensions,
- final int targetDimensions,
- final ParameterDescriptorGroup parameters,
+ GeodeticOperation(Class<? extends SingleOperation> operationType, ParameterDescriptorGroup parameters,
+ Class<? extends CoordinateSystem> sourceCSType, int sourceDimensions, boolean sourceOnEllipsoid,
+ Class<? extends CoordinateSystem> targetCSType, int targetDimensions, boolean targetOnEllipsoid,
final GeodeticOperation[] redimensioned)
{
- super(sourceDimensions, targetDimensions, parameters);
+ super(operationType, parameters,
+ sourceCSType, sourceDimensions, sourceOnEllipsoid,
+ targetCSType, targetDimensions, targetOnEllipsoid);
this.redimensioned = redimensioned;
}
@@ -121,16 +132,6 @@
}
/**
- * Returns the interface implemented by most coordinate operations that extends this class.
- *
- * @return default to {@link Transformation}.
- */
- @Override
- public Class<? extends SingleOperation> getOperationType() {
- return Transformation.class;
- }
-
- /**
* The inverse of {@code GeodeticOperation} is usually the same operation with parameter signs inverted.
*
* @return {@code this} for most {@code GeodeticOperation} instances.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java
index 0d01f25..aa73a35 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java
@@ -40,7 +40,7 @@
* format the inverse ({@code "INVERSE_MT"}) of 3D to 2D transform.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
*
* @see Geographic3Dto2D
*
@@ -86,7 +86,7 @@
* Constructs a provider that can be resized.
*/
Geographic2Dto3D(GeodeticOperation[] redimensioned) {
- super(2, 3, PARAMETERS, redimensioned);
+ super(PARAMETERS, 2, 3, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java
index 8f3d26d..14030f8 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java
@@ -39,7 +39,7 @@
* The inverse operation arbitrarily sets the ellipsoidal height to zero.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
*
* @see Geographic2Dto3D
*
@@ -79,7 +79,7 @@
* Constructs a provider that can be resized.
*/
private Geographic3Dto2D(GeodeticOperation[] redimensioned) {
- super(3, 2, PARAMETERS, redimensioned);
+ super(PARAMETERS, 3, 2, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java
index ec3470c..7f12ab2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java
@@ -21,6 +21,8 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.operation.Transformation;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.apache.sis.parameter.ParameterBuilder;
@@ -35,7 +37,7 @@
* but subclasses will provide different operations.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -95,7 +97,7 @@
* Constructs a provider with default parameters.
*/
public GeographicOffsets() {
- super(3, 3, PARAMETERS, new GeographicOffsets[4]);
+ this(3, 3, PARAMETERS, new GeographicOffsets[4]);
redimensioned[0] = new GeographicOffsets2D(redimensioned);
redimensioned[1] = new GeographicOffsets(2, 3, PARAMETERS, redimensioned);
redimensioned[2] = new GeographicOffsets(3, 2, PARAMETERS, redimensioned);
@@ -106,9 +108,11 @@
* For default constructors in this class and subclasses.
*/
GeographicOffsets(int sourceDimensions, int targetDimensions,
- ParameterDescriptorGroup parameters, GeodeticOperation[] redimensioned)
+ ParameterDescriptorGroup parameters, GeodeticOperation[] redimensioned)
{
- super(sourceDimensions, targetDimensions, parameters, redimensioned);
+ super(Transformation.class, parameters,
+ EllipsoidalCS.class, sourceDimensions, false,
+ EllipsoidalCS.class, targetDimensions, false, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicRedimension.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicRedimension.java
index b1715cd..8c435cf 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicRedimension.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicRedimension.java
@@ -20,6 +20,7 @@
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -34,7 +35,7 @@
* to {@link Geographic3Dto2D#redimension(int, int)} when the given number of dimensions are equal.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -49,30 +50,22 @@
* Constructs a math transform provider from a set of parameters.
* This is for sub-class constructors only.
*/
- GeographicRedimension(final int sourceDimensions,
+ GeographicRedimension(final ParameterDescriptorGroup parameters,
+ final int sourceDimensions,
final int targetDimensions,
- final ParameterDescriptorGroup parameters,
final GeodeticOperation[] redimensioned)
{
- super(sourceDimensions, targetDimensions, parameters, redimensioned);
+ super(Conversion.class, parameters,
+ CoordinateSystem.class, sourceDimensions, false,
+ CoordinateSystem.class, targetDimensions, false, redimensioned);
}
/**
* Creates an identity operation of the given number of dimensions.
*/
GeographicRedimension(final int dimension, final GeodeticOperation[] redimensioned) {
- super(dimension, dimension, builder().setCodeSpace(Citations.SIS, Constants.SIS)
- .addName("Identity " + dimension + 'D').createGroup(), redimensioned);
- }
-
- /**
- * Returns the interface implemented by all coordinate operations that extends this class.
- *
- * @return default to {@link Conversion}.
- */
- @Override
- public final Class<Conversion> getOperationType() {
- return Conversion.class;
+ this(builder().setCodeSpace(Citations.SIS, Constants.SIS).addName("Identity " + dimension + 'D').createGroup(),
+ dimension, dimension, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
index 7fa6fc4..0ab4bd1 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
@@ -41,7 +41,7 @@
* This provider creates transforms from geographic to geocentric coordinate reference systems.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see GeocentricToGeographic
*
@@ -116,17 +116,9 @@
* @param redimensioned providers for all combinations between 2D and 3D cases.
*/
private GeographicToGeocentric(int sourceDimensions, GeodeticOperation[] redimensioned) {
- super(sourceDimensions, 3, PARAMETERS, redimensioned);
- }
-
- /**
- * Returns the operation type.
- *
- * @return {@code Conversion.class}.
- */
- @Override
- public Class<Conversion> getOperationType() {
- return Conversion.class;
+ super(Conversion.class, PARAMETERS,
+ EllipsoidalCS.class, sourceDimensions, true,
+ CartesianCS.class, 3, false, redimensioned);
}
/**
@@ -152,17 +144,6 @@
}
/**
- * Notifies {@code DefaultMathTransformFactory} that Geographic/geocentric conversions
- * require values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
- *
- * @return 1, meaning that the operation requires a source ellipsoid.
- */
- @Override
- public int getEllipsoidsMask() {
- return 1;
- }
-
- /**
* Specifies that the inverse of this operation is a different kind of operation.
*
* @return {@code null}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToTopocentric.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToTopocentric.java
new file mode 100644
index 0000000..368cd18
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToTopocentric.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.referencing.provider;
+
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.measure.Units;
+import org.apache.sis.parameter.Parameters;
+
+
+/**
+ * The provider for the <cite>"Geographic/topocentric conversions"</cite> (EPSG:9837).
+ * This operation is implemented using existing {@link MathTransform} implementations;
+ * there is no need for a class specifically for this transform.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 1.3
+ * @module
+ */
+public final class GeographicToTopocentric extends AbstractProvider {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = -3829993731324133815L;
+
+ /**
+ * The operation parameter descriptor for the <cite>Longitude of topocentric origin</cite> parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ * <table class="sis">
+ * <caption>Parameter names</caption>
+ * <tr><td> EPSG: </td><td> Longitude of topocentric origin </td></tr>
+ * </table>
+ * <b>Notes:</b>
+ * <ul>
+ * <li>Value domain: [-180.0 … 180.0]°</li>
+ * </ul>
+ */
+ static final ParameterDescriptor<Double> ORIGIN_X;
+
+ /**
+ * The operation parameter descriptor for the <cite>Latitude of topocentric origin</cite> parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ * <table class="sis">
+ * <caption>Parameter names</caption>
+ * <tr><td> EPSG: </td><td> Latitude of topocentric origin </td></tr>
+ * </table>
+ * <b>Notes:</b>
+ * <ul>
+ * <li>Value domain: [-90.0 … 90.0]°</li>
+ * </ul>
+ */
+ static final ParameterDescriptor<Double> ORIGIN_Y;
+
+ /**
+ * The operation parameter descriptor for the <cite>Ellipsoidal height of topocentric origin</cite> parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ * <table class="sis">
+ * <caption>Parameter names</caption>
+ * <tr><td> EPSG: </td><td> Ellipsoidal height of topocentric origin </td></tr>
+ * </table>
+ */
+ static final ParameterDescriptor<Double> ORIGIN_Z;
+
+ /**
+ * The group of all parameters expected by this coordinate operation.
+ */
+ private static final ParameterDescriptorGroup PARAMETERS;
+ static {
+ final ParameterBuilder builder = builder();
+ ORIGIN_X = createLongitude(builder
+ .addIdentifier("8835")
+ .addName("Longitude of topocentric origin"));
+
+ ORIGIN_Y = createLatitude(builder
+ .addIdentifier("8834")
+ .addName("Latitude of topocentric origin"), true);
+
+ ORIGIN_Z = builder
+ .addIdentifier("8836")
+ .addName("Ellipsoidal height of topocentric origin")
+ .create(0, Units.METRE);
+
+ PARAMETERS = builder
+ .addIdentifier("9837")
+ .addName("Geographic/topocentric conversions")
+ .createGroupForMapProjection(ORIGIN_Y, ORIGIN_X, ORIGIN_Z);
+ // Not really a map projection, but we leverage the same axis parameters.
+ }
+
+ /**
+ * Constructs a provider for the 3-dimensional case.
+ * While this operation method looks like a map projection because it has a
+ * {@link org.opengis.referencing.crs.GeographicCRS} source and
+ * {@link org.opengis.referencing.cs.CartesianCS} destination,
+ * it is classified in the "Coordinate Operations other than Map Projections" category in EPSG guidance note.
+ */
+ public GeographicToTopocentric() {
+ super(Conversion.class, PARAMETERS,
+ EllipsoidalCS.class, 3, true,
+ CartesianCS.class, 3, false);
+ }
+
+ /**
+ * Creates a transform from the specified group of parameter values.
+ * The unit of measurement of input coordinates will be the units of the ellipsoid axes.
+ *
+ * @param factory the factory to use for creating the transform.
+ * @param values the parameter values that define the transform to create.
+ * @return the conversion from geographic to topocentric coordinates.
+ * @throws FactoryException if an error occurred while creating a transform.
+ */
+ @Override
+ public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
+ throws FactoryException
+ {
+ try {
+ return GeocentricToTopocentric.create(factory, Parameters.castOrWrap(values), true);
+ } catch (TransformException e) {
+ throw new FactoryException(e);
+ }
+ }
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Interpolation1D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Interpolation1D.java
index fe0942b..09e7603 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Interpolation1D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Interpolation1D.java
@@ -20,6 +20,7 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -34,7 +35,7 @@
* The provider for interpolation of one-dimensional coordinates.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -73,17 +74,9 @@
* Constructs a provider for the 1-dimensional case.
*/
public Interpolation1D() {
- super(1, 1, PARAMETERS);
- }
-
- /**
- * Returns the operation type.
- *
- * @return {@code Conversion.class}.
- */
- @Override
- public Class<Conversion> getOperationType() {
- return Conversion.class;
+ super(Conversion.class, PARAMETERS,
+ CoordinateSystem.class, 1, false,
+ CoordinateSystem.class, 1, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertAzimuthalEqualArea.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertAzimuthalEqualArea.java
index 18f34ba..17707f0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertAzimuthalEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertAzimuthalEqualArea.java
@@ -30,7 +30,7 @@
* The provider for "<cite>Lambert Azimuthal Equal Area</cite>" projection (EPSG:9820).
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/lambert_azimuthal_equal_area.html">GeoTIFF parameters for Lambert Azimuthal Equal Area</a>
*
@@ -152,7 +152,7 @@
* Constructs a new provider.
*/
public LambertAzimuthalEqualArea() {
- super(PARAMETERS);
+ this(PARAMETERS);
}
/**
@@ -161,17 +161,7 @@
* @param parameters the set of parameters (never {@code null}).
*/
LambertAzimuthalEqualArea(final ParameterDescriptorGroup parameters) {
- super(parameters);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code PlanarProjection.class}
- */
- @Override
- public Class<PlanarProjection> getOperationType() {
- return PlanarProjection.class;
+ super(PlanarProjection.class, parameters);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualArea.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualArea.java
index 1491426..6db14be 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualArea.java
@@ -30,7 +30,7 @@
* The provider for <cite>"Lambert Cylindrical Equal Area"</cite> projection (EPSG:9835).
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/cylindrical_equal_area.html">GeoTIFF parameters for Cylindrical Equal Area</a>
*
@@ -164,17 +164,7 @@
* Constructs a new provider.
*/
public LambertCylindricalEqualArea() {
- super(PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code CylindricalProjection.class}
- */
- @Override
- public final Class<CylindricalProjection> getOperationType() {
- return CylindricalProjection.class;
+ super(CylindricalProjection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualAreaSpherical.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualAreaSpherical.java
index 62d617f..2fa39b7 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualAreaSpherical.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertCylindricalEqualAreaSpherical.java
@@ -28,7 +28,7 @@
* The provider for <cite>"Lambert Cylindrical Equal Area (Spherical)"</cite> projection (EPSG:9834).
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -64,17 +64,7 @@
* Constructs a new provider.
*/
public LambertCylindricalEqualAreaSpherical() {
- super(PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code CylindricalProjection.class}
- */
- @Override
- public final Class<CylindricalProjection> getOperationType() {
- return CylindricalProjection.class;
+ super(CylindricalProjection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
index 89ecb62..ee3c81f 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
@@ -31,6 +31,8 @@
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.OperationMethod;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -49,18 +51,18 @@
import org.apache.sis.parameter.ParameterBuilder;
import org.apache.sis.parameter.Parameters;
import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.Debug;
import static org.opengis.metadata.Identifier.AUTHORITY_KEY;
/**
- * Base class for all map projection providers defined in this package. This base class defines some descriptors
- * for the most commonly used parameters. Subclasses will declare additional parameters and group them in a
+ * Base class for most two-dimensional map projection providers defined in this package.
+ * This base class defines some descriptors for the most commonly used parameters.
+ * Subclasses will declare additional parameters and group them in a
* {@linkplain ParameterDescriptorGroup descriptor group} named {@code PARAMETERS}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -119,7 +121,7 @@
/**
* The ellipsoid eccentricity, computed from the semi-major and semi-minor axis lengths.
- * This a SIS-specific parameter used mostly for debugging purpose.
+ * This a SIS-specific parameter.
*
* <!-- Generated by ParameterNameTableGenerator -->
* <table class="sis">
@@ -132,7 +134,6 @@
* <li>No default value</li>
* </ul>
*/
- @Debug
public static final DefaultParameterDescriptor<Double> ECCENTRICITY;
static {
final MeasurementRange<Double> valueDomain = MeasurementRange.createGreaterThan(0, Units.METRE);
@@ -185,20 +186,15 @@
* Constructs a math transform provider from a set of parameters. The provider
* {@linkplain #getIdentifiers() identifiers} will be the same than the parameter ones.
*
- * @param parameters the set of parameters (never {@code null}).
+ * @param operationType interface of the {@code CoordinateOperation} instances that use this projection.
+ * @param parameters the set of parameters (never {@code null}).
*/
- protected MapProjection(final ParameterDescriptorGroup parameters) {
- super(2, 2, parameters);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code Projection.class} or a sub-type.
- */
- @Override
- public Class<? extends Projection> getOperationType() {
- return Projection.class;
+ protected MapProjection(final Class<? extends Projection> operationType,
+ final ParameterDescriptorGroup parameters)
+ {
+ super(operationType, parameters,
+ EllipsoidalCS.class, 2, true,
+ CartesianCS.class, 2, false);
}
/**
@@ -290,17 +286,6 @@
*/
protected abstract NormalizedProjection createProjection(final Parameters parameters) throws ParameterNotFoundException;
- /**
- * Notifies {@code DefaultMathTransformFactory} that map projections require
- * values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
- *
- * @return 1, meaning that the operation requires a source ellipsoid.
- */
- @Override
- public final int getEllipsoidsMask() {
- return 1;
- }
-
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection3D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection3D.java
index 0796416..890e57c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection3D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection3D.java
@@ -21,7 +21,6 @@
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.referencing.operation.Projection;
import org.opengis.util.FactoryException;
@@ -30,7 +29,7 @@
* with only the ellipsoidal height which pass through.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.8
* @module
*
@@ -56,7 +55,9 @@
* Constructs a three-dimensional map projection for the given two-dimensional projection.
*/
MapProjection3D(final MapProjection proj) {
- super(3, 3, proj.getParameters());
+ super(proj.getOperationType(), proj.getParameters(),
+ proj.sourceCSType, 3, proj.sourceOnEllipsoid,
+ proj.targetCSType, 3, proj.targetOnEllipsoid);
redimensioned = proj;
}
@@ -76,25 +77,6 @@
}
/**
- * Returns the operation type for this map projection.
- */
- @Override
- public Class<? extends Projection> getOperationType() {
- return redimensioned.getOperationType();
- }
-
- /**
- * Notifies {@code DefaultMathTransformFactory} that map projections require
- * values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
- *
- * @return 1, meaning that the operation requires a source ellipsoid.
- */
- @Override
- public int getEllipsoidsMask() {
- return redimensioned.getEllipsoidsMask();
- }
-
- /**
* Creates a three-dimensional map projections for the given parameters.
* The ellipsoidal height is assumed to be in the third dimension.
*/
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ModifiedAzimuthalEquidistant.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ModifiedAzimuthalEquidistant.java
index cf3c3c9..25a6257 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ModifiedAzimuthalEquidistant.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ModifiedAzimuthalEquidistant.java
@@ -38,7 +38,7 @@
* approximation.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/azimuthal_equidistant.html">GeoTIFF parameters for Azimuthal Equidistant</a>
*
@@ -155,15 +155,7 @@
* Constructs a new provider.
*/
public ModifiedAzimuthalEquidistant() {
- super(PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- */
- @Override
- public Class<PlanarProjection> getOperationType() {
- return PlanarProjection.class;
+ super(PlanarProjection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mollweide.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mollweide.java
index 57446c0..bca51a1 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mollweide.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mollweide.java
@@ -19,6 +19,7 @@
import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.operation.Projection;
import org.apache.sis.parameter.Parameters;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.referencing.operation.projection.NormalizedProjection;
@@ -30,7 +31,7 @@
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
*
* @see <a href="https://mathworld.wolfram.com/MollweideProjection.html">Mathworld formulas</a>
* @see <a href="http://geotiff.maptools.org/proj_list/mollweide.html">GeoTIFF parameters for Mollweide</a>
@@ -108,7 +109,7 @@
* Constructs a new provider.
*/
public Mollweide() {
- super(PARAMETERS);
+ super(Projection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
index 6ae4795..3e6c8d2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
@@ -59,7 +59,7 @@
*
* @author Rueben Schulz (UBC)
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -170,15 +170,7 @@
* @param redimensioned providers for all combinations between 2D and 3D cases.
*/
private Molodensky(int sourceDimensions, int targetDimensions, GeodeticOperation[] redimensioned) {
- super(sourceDimensions, targetDimensions, PARAMETERS, redimensioned);
- }
-
- /**
- * While Molodensky method is an approximation of geocentric translation, this is not exactly that.
- */
- @Override
- int getType() {
- return OTHER;
+ super(Type.MOLODENSKY, PARAMETERS, sourceDimensions, targetDimensions, redimensioned);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java
index 94afa26..f648888 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java
@@ -32,6 +32,7 @@
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.Transformation;
@@ -55,7 +56,7 @@
*
* @author Martin Desruisseaux (Geomatys)
* @author Rueben Schulz (UBC)
- * @version 0.8
+ * @version 1.3
*
* @see <a href="http://www.ngs.noaa.gov/cgi-bin/nadcon.prl">NADCON on-line computation</a>
*
@@ -125,17 +126,9 @@
* Creates a new provider.
*/
public NADCON() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the base interface of the {@code CoordinateOperation} instances that use this method.
- *
- * @return fixed to {@link Transformation}.
- */
- @Override
- public Class<Transformation> getOperationType() {
- return Transformation.class;
+ super(Transformation.class, PARAMETERS,
+ EllipsoidalCS.class, 2, false,
+ EllipsoidalCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv1.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv1.java
index 8d2c756..4865d99 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv1.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv1.java
@@ -21,6 +21,7 @@
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.Transformation;
@@ -32,7 +33,7 @@
* This transform requires data that are not bundled by default with Apache SIS.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -59,17 +60,9 @@
* Creates a new provider.
*/
public NTv1() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the base interface of the {@code CoordinateOperation} instances that use this method.
- *
- * @return fixed to {@link Transformation}.
- */
- @Override
- public Class<Transformation> getOperationType() {
- return Transformation.class;
+ super(Transformation.class, PARAMETERS,
+ EllipsoidalCS.class, 2, false,
+ EllipsoidalCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java
index 0651f60..88a2b1b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java
@@ -39,6 +39,7 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.Transformation;
@@ -62,7 +63,7 @@
*
* @author Simon Reynard (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -109,17 +110,9 @@
* Creates a new provider.
*/
public NTv2() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the base interface of the {@code CoordinateOperation} instances that use this method.
- *
- * @return fixed to {@link Transformation}.
- */
- @Override
- public Class<Transformation> getOperationType() {
- return Transformation.class;
+ super(Transformation.class, PARAMETERS,
+ EllipsoidalCS.class, 2, false,
+ EllipsoidalCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NorthPoleRotation.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NorthPoleRotation.java
index 1298e9d..97fe742 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NorthPoleRotation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NorthPoleRotation.java
@@ -21,6 +21,7 @@
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -39,7 +40,7 @@
* The 0° rotated meridian is defined as the meridian that runs through both the geographical and the rotated North pole.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see SouthPoleRotation
* @see <a href="https://cfconventions.org/cf-conventions/cf-conventions.html#_rotated_pole">Rotated pole in CF-conventions</a>
@@ -138,17 +139,9 @@
* Constructs a new provider.
*/
public NorthPoleRotation() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code Conversion.class} or a sub-type.
- */
- @Override
- public Class<? extends Conversion> getOperationType() {
- return Conversion.class;
+ super(Conversion.class, PARAMETERS,
+ EllipsoidalCS.class, 2, false,
+ EllipsoidalCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Orthographic.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Orthographic.java
index 4bd68a8..06bf4c4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Orthographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Orthographic.java
@@ -33,11 +33,11 @@
*
* @author Rueben Schulz (UBC)
* @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/orthographic.html">GeoTIFF parameters for Orthographic</a>
*
- * @version 1.1
- * @since 1.1
+ * @since 1.1
* @module
*/
@XmlTransient
@@ -173,15 +173,7 @@
* Constructs a new provider.
*/
public Orthographic() {
- super(PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- */
- @Override
- public Class<PlanarProjection> getOperationType() {
- return PlanarProjection.class;
+ super(PlanarProjection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Polyconic.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Polyconic.java
index 069d956..ff15228 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Polyconic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Polyconic.java
@@ -30,7 +30,7 @@
*
* @author Simon Reynard (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
*
* @see <a href="http://geotiff.maptools.org/proj_list/polyconic.html">GeoTIFF parameters for Polyconic</a>
*
@@ -136,17 +136,7 @@
* Constructs a new provider.
*/
public Polyconic() {
- super(PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code ConicProjection.class}
- */
- @Override
- public Class<ConicProjection> getOperationType() {
- return ConicProjection.class;
+ super(ConicProjection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java
index 203f706..42c54f6 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java
@@ -56,14 +56,6 @@
* Constructs the provider.
*/
public PositionVector7Param() {
- super(3, 3, PARAMETERS, null);
- }
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return SEVEN_PARAM;
+ super(Type.SEVEN_PARAM, PARAMETERS, 3, 3, null);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java
index 9ef0cd3..e0f2218 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java
@@ -25,7 +25,7 @@
* The provider for <cite>"Position Vector transformation (geog2D domain)"</cite> (EPSG:9606).
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -68,7 +68,7 @@
* Constructs a provider that can be resized.
*/
PositionVector7Param2D(GeodeticOperation[] redimensioned) {
- super(2, 2, PARAMETERS, redimensioned);
+ super(Type.SEVEN_PARAM, PARAMETERS, 2, 2, redimensioned);
}
/**
@@ -78,12 +78,4 @@
Class<PositionVector7Param3D> variant3D() {
return PositionVector7Param3D.class;
}
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return SEVEN_PARAM;
- }
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java
index f788490..707cc0c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java
@@ -24,7 +24,7 @@
* The provider for <cite>"Position Vector transformation (geog3D domain)"</cite> (EPSG:1037).
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -70,14 +70,6 @@
* @param redimensioned providers for all combinations between 2D and 3D cases, or {@code null}.
*/
private PositionVector7Param3D(int sourceDimensions, int targetDimensions, GeodeticOperation[] redimensioned) {
- super(sourceDimensions, targetDimensions, PARAMETERS, redimensioned);
- }
-
- /**
- * Returns the type of this operation.
- */
- @Override
- int getType() {
- return SEVEN_PARAM;
+ super(Type.SEVEN_PARAM, PARAMETERS, sourceDimensions, targetDimensions, redimensioned);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoPlateCarree.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoPlateCarree.java
index eb0a09e..b8a0513 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoPlateCarree.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoPlateCarree.java
@@ -19,6 +19,7 @@
import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -35,7 +36,7 @@
* axis units are degrees.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see Equirectangular
*
@@ -60,18 +61,9 @@
* Constructs a new provider.
*/
public PseudoPlateCarree() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the operation type. We do not declare that operation method as a
- * {@link org.opengis.referencing.operation.Projection} because axis units are degrees.
- *
- * @return interface implemented by all coordinate operations that use this method.
- */
- @Override
- public final Class<Conversion> getOperationType() {
- return Conversion.class;
+ super(Conversion.class, PARAMETERS,
+ EllipsoidalCS.class, 2, false,
+ EllipsoidalCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoSinusoidal.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoSinusoidal.java
new file mode 100644
index 0000000..bcf34ef
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PseudoSinusoidal.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.referencing.provider;
+
+import javax.xml.bind.annotation.XmlTransient;
+import org.opengis.parameter.ParameterDescriptorGroup;
+
+
+/**
+ * The provider for <cite>"Pseudo sinusoidal equal-area"</cite> projection.
+ * This is similar to Pseudo-Mercator: uses spherical formulas but apply the result on an ellipsoid.
+ * This is sometime used with remote sensing data.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 1.3
+ * @module
+ */
+@XmlTransient
+public final class PseudoSinusoidal extends Sinusoidal {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = 6523477856049963388L;
+
+ /**
+ * Name of this projection.
+ */
+ public static final String NAME = "Pseudo sinusoidal";
+
+ /**
+ * The group of all parameters expected by this coordinate operation.
+ */
+ private static ParameterDescriptorGroup parameters() {
+ return builder().addName(NAME)
+ .createGroupForMapProjection(AbstractMercator.toArray(PARAMETERS.descriptors(), 0));
+ }
+
+ /**
+ * Constructs a new provider.
+ */
+ public PseudoSinusoidal() {
+ super(parameters());
+ }
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SatelliteTracking.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SatelliteTracking.java
index 1d6a946..6d9a5f3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SatelliteTracking.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SatelliteTracking.java
@@ -20,6 +20,7 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.operation.Projection;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.parameter.ParameterBuilder;
import org.apache.sis.parameter.Parameters;
@@ -37,7 +38,7 @@
*
* @author Matthieu Bastianelli (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -177,7 +178,7 @@
* Constructs a new provider.
*/
public SatelliteTracking() {
- super(PARAMETERS);
+ super(Projection.class, PARAMETERS);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java
index 3c3dfff..fe7b7d8 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Sinusoidal.java
@@ -20,6 +20,7 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.operation.Projection;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.internal.util.Constants;
import org.apache.sis.parameter.Parameters;
@@ -32,7 +33,7 @@
* This projection method has no associated EPSG code.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
*
* @see <a href="https://en.wikipedia.org/wiki/Sinusoidal_projection">Sinusoidal projection on Wikipedia</a>
* @see <a href="http://geotiff.maptools.org/proj_list/sinusoidal.html">GeoTIFF parameters for Sinusoidal</a>
@@ -41,18 +42,13 @@
* @module
*/
@XmlTransient
-public final class Sinusoidal extends MapProjection {
+public class Sinusoidal extends MapProjection {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = -3236247448683326299L;
/**
- * Name of this projection.
- */
- public static final String NAME = "Sinusoidal";
-
- /**
* The operation parameter descriptor for the <cite>Longitude of projection center</cite> (λ₀) parameter value.
* Valid values range is [-180 … 180]° and default value is 0°.
*
@@ -97,10 +93,10 @@
/**
* The group of all parameters expected by this coordinate operation.
*/
- private static final ParameterDescriptorGroup PARAMETERS;
+ static final ParameterDescriptorGroup PARAMETERS;
static {
PARAMETERS = builder().setCodeSpace(Citations.OGC, Constants.OGC)
- .addName (NAME)
+ .addName ("Sinusoidal")
.addName ("Sanson-Flamsteed")
.addName (Citations.GEOTIFF, "CT_Sinusoidal")
.addIdentifier(Citations.GEOTIFF, "24")
@@ -112,7 +108,16 @@
* Constructs a new provider.
*/
public Sinusoidal() {
- super(PARAMETERS);
+ this(PARAMETERS);
+ }
+
+ /**
+ * Constructs a math transform provider from a set of parameters.
+ *
+ * @param parameters the set of parameters (never {@code null}).
+ */
+ Sinusoidal(final ParameterDescriptorGroup parameters) {
+ super(Projection.class, parameters);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SouthPoleRotation.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SouthPoleRotation.java
index 72452c7..2aa80b0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SouthPoleRotation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/SouthPoleRotation.java
@@ -21,6 +21,7 @@
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -43,7 +44,7 @@
* in UCAR netCDF library version 5.5.2.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see NorthPoleRotation
*
@@ -149,17 +150,9 @@
* Constructs a new provider.
*/
public SouthPoleRotation() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the operation type for this map projection.
- *
- * @return {@code Conversion.class} or a sub-type.
- */
- @Override
- public Class<? extends Conversion> getOperationType() {
- return Conversion.class;
+ super(Conversion.class, PARAMETERS,
+ EllipsoidalCS.class, 2, false,
+ EllipsoidalCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/VerticalOffset.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/VerticalOffset.java
index 455f1ea..b36da8b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/VerticalOffset.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/VerticalOffset.java
@@ -20,6 +20,8 @@
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.cs.VerticalCS;
+import org.opengis.referencing.operation.Transformation;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.Matrix;
@@ -46,12 +48,12 @@
* <cite>"Vertical Offset"</cite> parameter value needs to be reversed if the target coordinate system axis is down.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.7
* @module
*/
@XmlTransient
-public final class VerticalOffset extends GeographicOffsets {
+public final class VerticalOffset extends GeodeticOperation {
/**
* Serial number for inter-operability with different versions.
*/
@@ -62,14 +64,16 @@
*/
private static final ParameterDescriptorGroup PARAMETERS;
static {
- PARAMETERS = builder().addIdentifier("9616").addName("Vertical Offset").createGroup(TZ);
+ PARAMETERS = builder().addIdentifier("9616").addName("Vertical Offset").createGroup(GeographicOffsets.TZ);
}
/**
* Constructs a provider with default parameters.
*/
public VerticalOffset() {
- super(1, 1, PARAMETERS, null);
+ super(Transformation.class, PARAMETERS,
+ VerticalCS.class, 1, false,
+ VerticalCS.class, 1, false, null);
}
/**
@@ -86,7 +90,7 @@
throws ParameterNotFoundException
{
final Parameters pv = Parameters.castOrWrap(values);
- return MathTransforms.translation(pv.doubleValue(TZ));
+ return MathTransforms.translation(pv.doubleValue(GeographicOffsets.TZ));
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Wraparound.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Wraparound.java
index 568799d..ff6749a 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Wraparound.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Wraparound.java
@@ -21,6 +21,7 @@
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -34,7 +35,7 @@
* Provider for {@link WraparoundTransform} (SIS-specific operation).
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -112,17 +113,9 @@
* Constructs a new provider.
*/
public Wraparound() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the operation type.
- *
- * @return interface implemented by all coordinate operations that use this method.
- */
- @Override
- public final Class<Conversion> getOperationType() {
- return Conversion.class;
+ super(Conversion.class, PARAMETERS,
+ CoordinateSystem.class, 2, false,
+ CoordinateSystem.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ZonedTransverseMercator.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ZonedTransverseMercator.java
index 250b7bb..2095efc 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ZonedTransverseMercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ZonedTransverseMercator.java
@@ -22,6 +22,7 @@
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.Projection;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -36,7 +37,7 @@
* The provider for <cite>"Transverse Mercator Zoned Grid System"</cite> projection (EPSG:9824).
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -104,31 +105,13 @@
/**
* Constructs a new provider.
+ * We do not classify this operation as a cylindrical projection
+ * because of the discontinuities between zones.
*/
public ZonedTransverseMercator() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the operation type for this projection. We do not classify this operation as a cylindrical projection
- * for now because of the discontinuities between zones. But we may revisit that choice in any future SIS version.
- *
- * @return {@code Projection.class} or a sub-type.
- */
- @Override
- public Class<? extends Projection> getOperationType() {
- return Projection.class;
- }
-
- /**
- * Notifies {@code DefaultMathTransformFactory} that this projection requires
- * values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
- *
- * @return 1, meaning that the operation requires a source ellipsoid.
- */
- @Override
- public final int getEllipsoidsMask() {
- return 1;
+ super(Projection.class, PARAMETERS,
+ EllipsoidalCS.class, 2, true,
+ EllipsoidalCS.class, 2, false);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/package-info.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/package-info.java
index 466e271..8c4f94d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/package-info.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/package-info.java
@@ -22,7 +22,7 @@
*
* @author Martin Desruisseaux (Geomatys)
* @author Matthieu Bastianelli (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see org.apache.sis.referencing.operation.transform.MathTransformProvider
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
index fb6a77b..4f258bd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
@@ -76,10 +76,12 @@
import org.apache.sis.internal.metadata.AxisNames;
import org.apache.sis.internal.metadata.TransformationAccuracy;
import org.apache.sis.internal.referencing.ServicesForMetadata;
+import org.apache.sis.internal.referencing.provider.AbstractProvider;
import org.apache.sis.internal.referencing.ReferencingFactoryContainer;
import org.apache.sis.internal.referencing.EllipsoidalHeightCombiner;
import org.apache.sis.internal.referencing.VerticalDatumTypes;
import org.apache.sis.internal.referencing.AxisDirections;
+import org.apache.sis.internal.referencing.WKTUtilities;
import org.apache.sis.internal.referencing.WKTKeywords;
import org.apache.sis.internal.util.Constants;
import org.apache.sis.internal.util.Numerics;
@@ -100,7 +102,7 @@
* @author Rémi Eve (IRD)
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -465,15 +467,15 @@
identifiers[n] = id;
}
properties.put(IdentifiedObject.IDENTIFIERS_KEY, identifiers);
- // REMINDER: values associated to IDENTIFIERS_KEY shall be recognized by 'toIdentifier(Object)'.
+ // REMINDER: values associated to IDENTIFIERS_KEY shall be recognized by `toIdentifier(Object)`.
}
}
/*
* Other metadata (SCOPE, AREA, etc.). ISO 19162 said that at most one of each type shall be present,
* but our parser accepts an arbitrary amount of some kinds of metadata. They can be recognized by the
- * 'while' loop.
+ * `while` loop.
*
- * Most WKT do not contain any of those metadata, so we perform an 'isEmpty()' check as an optimization
+ * Most WKT do not contain any of those metadata, so we perform an `isEmpty()` check as an optimization
* for those common cases.
*/
if (!parent.isEmpty()) {
@@ -618,7 +620,7 @@
/*
* Consider the following element: UNIT[“kilometre”, 1000, ID[“EPSG”, “9036”]]
*
- * - if the authority code (“9036”) refers to a unit incompatible with 'baseUnit' (“metre”), log a warning.
+ * - if the authority code (“9036”) refers to a unit incompatible with `baseUnit` (“metre”), log a warning.
* - otherwise: 1) unconditionally replace the parsed unit (“km”) by the unit referenced by the authority code.
* 2) if the new unit is not equivalent to the old one (i.e. different scale factor), log a warning.
*/
@@ -780,14 +782,14 @@
* two-dimensional Projected or three-dimensional Geocentric CRS.
*/
case WKTKeywords.Cartesian: {
- if (!(datum instanceof GeodeticDatum)) {
+ if (datum != null && !(datum instanceof GeodeticDatum)) {
throw parent.missingComponent(WKTKeywords.Axis);
}
if (defaultUnit == null) {
throw parent.missingComponent(WKTKeywords.LengthUnit);
}
if (is3D) { // If dimension can not be 2, then CRS can not be Projected.
- return Legacy.standard(defaultUnit.asType(Length.class));
+ return Legacy.standard(defaultUnit);
}
nx = AxisNames.EASTING; x = "E";
ny = AxisNames.NORTHING; y = "N";
@@ -895,7 +897,7 @@
* Example: "Compound CS: East (km), North (km), Up (m)."
*/
final String name;
- { // For keeping the 'buffer' variable local to this block.
+ { // For keeping the `buffer` variable local to this block.
final StringBuilder buffer = new StringBuilder();
if (type != null && !type.isEmpty()) {
final int c = type.codePointAt(0);
@@ -1076,7 +1078,7 @@
/*
* At this point we are done and ready to create the CoordinateSystemAxis. But there is one last element
* specified by ISO 19162 but not in Apache SIS representation of axis: ORDER[n], which specify the axis
- * ordering. If present we will store that value for processing by the 'parseCoordinateSystem(…)' method.
+ * ordering. If present we will store that value for processing by the `parseCoordinateSystem(…)` method.
*/
final Element order = element.pullElement(OPTIONAL, WKTKeywords.Order);
Integer n = null;
@@ -1118,9 +1120,9 @@
if (n2 != null) {
return n1 - n2;
}
- return -1; // Axis 1 before Axis 2 since the latter has no 'ORDER' element.
+ return -1; // Axis 1 before Axis 2 since the latter has no `ORDER` element.
} else if (n2 != null) {
- return +1; // Axis 2 before Axis 1 since the latter has no 'ORDER' element.
+ return +1; // Axis 2 before Axis 1 since the latter has no `ORDER` element.
}
return 0;
}
@@ -1245,16 +1247,28 @@
}
/**
- * Returns the number of source dimensions of the given operation method, or 2 if unspecified.
+ * Parses a {@code "GeodeticCRS"} (WKT 2) element where the number of dimensions and coordinate system type
+ * are derived from the operation method. This is used for parsing the base CRS component of derived CRS.
+ *
+ * @param mode {@link #OPTIONAL} or {@link #MANDATORY}.
+ * @param parent the parent element.
+ * @param method the operation method, or {@code null} if unknown.
+ * @throws ParseException if the {@code "GeodeticCRS"} element can not be parsed.
*/
- private static int getSourceDimensions(final OperationMethod method) {
+ private SingleCRS parseBaseCRS(final int mode, final Element parent, final OperationMethod method)
+ throws ParseException
+ {
+ int dimension = 2;
+ String csType = WKTKeywords.ellipsoidal;
if (method != null) {
- final Integer dimension = method.getSourceDimensions();
- if (dimension != null) {
- return dimension;
+ final Integer d = method.getSourceDimensions();
+ if (d != null) dimension = d;
+ if (method instanceof AbstractProvider) {
+ csType = WKTUtilities.toType(CoordinateSystem.class, ((AbstractProvider) method).sourceCSType);
+ if (csType == null) csType = WKTKeywords.ellipsoidal;
}
}
- return 2;
+ return parseGeodeticCRS(mode, parent, dimension, csType);
}
/**
@@ -1273,7 +1287,7 @@
/*
* The map projection method may be specified by an EPSG identifier (or any other authority),
* which is preferred to the method name since the latter is potentially ambiguous. However not
- * all CoordinateOperationFactory may accept identifier as an argument to 'getOperationMethod'.
+ * all CoordinateOperationFactory may accept identifier as an argument to `getOperationMethod(…)`.
* So if an identifier is present, we will try to use it but fallback on the name if we can
* not use the identifier.
*/
@@ -1630,7 +1644,7 @@
*/
baseCRS = parseEngineeringCRS(OPTIONAL, element, true);
if (baseCRS == null) {
- baseCRS = parseGeodeticCRS(OPTIONAL, element, getSourceDimensions(fromBase.getMethod()), WKTKeywords.ellipsoidal);
+ baseCRS = parseBaseCRS(OPTIONAL, element, fromBase.getMethod());
if (baseCRS == null) {
baseCRS = parseProjectedCRS(MANDATORY, element, true);
}
@@ -1750,15 +1764,16 @@
angularUnit = csUnit.asType(Angle.class);
} else {
angularUnit = Units.DEGREE;
- if (csUnit == null) {
+ if (csUnit == null && csType != null) {
/*
* A UNIT[…] is mandatory either in the CoordinateSystem as a whole (csUnit != null),
* or inside each AXIS[…] component (csUnit == null). An exception to this rule is when
* parsing a BaseGeodCRS inside a ProjectedCRS or DerivedCRS, in which case axes are omitted.
- * We recognize those cases by a non-null 'csType' given in argument to this method.
+ * We recognize those cases by a non-null `csType` given in argument to this method.
*/
- if (WKTKeywords.ellipsoidal.equals(csType)) {
- csUnit = Units.DEGREE; // For BaseGeodCRS in ProjectedCRS.
+ switch (csType) {
+ case WKTKeywords.ellipsoidal: csUnit = Units.DEGREE; break; // For BaseGeodCRS in ProjectedCRS.
+ case WKTKeywords.Cartesian: csUnit = Units.METRE; break;
}
}
}
@@ -1807,11 +1822,11 @@
*/
fromBase = parseDerivingConversion(OPTIONAL, element, WKTKeywords.DerivingConversion, csUnit, angularUnit);
if (fromBase != null) {
- baseCRS = parseGeodeticCRS(MANDATORY, element, getSourceDimensions(fromBase.getMethod()), WKTKeywords.ellipsoidal);
+ baseCRS = parseBaseCRS(MANDATORY, element, fromBase.getMethod());
}
}
/*
- * At this point, we have either a non-null 'datum' or non-null 'baseCRS' + 'fromBase'.
+ * At this point, we have either a non-null `datum` or non-null `baseCRS` + `fromBase`.
* The coordinate system is parsed in the same way for both cases, but the CRS is created differently.
*/
final CRSFactory crsFactory = factories.getCRSFactory();
@@ -1828,7 +1843,7 @@
* "(snip) the prime meridian’s <irm longitude> value shall be given in the
* same angular units as those for the horizontal axes of the geographic CRS."
*
- * This is a little bit different than using the 'angularUnit' variable directly,
+ * This is a little bit different than using the `angularUnit` variable directly,
* since the WKT could have overwritten the unit directly in the AXIS[…] element.
* So we re-fetch the angular unit. Normally, we will get the same value (unless
* the previous value was null).
@@ -1924,7 +1939,7 @@
return crsFactory.createDerivedCRS(properties, baseCRS, fromBase, cs);
}
/*
- * The 'parseVerticalDatum(…)' method may have been unable to resolve the datum type.
+ * The `parseVerticalDatum(…)` method may have been unable to resolve the datum type.
* But sometime the axis (which was not available when we created the datum) provides
* more information. Verify if we can have a better type now, and if so rebuild the datum.
*/
@@ -2133,7 +2148,7 @@
isWKT1 ? null : WKTKeywords.Conversion, linearUnit, angularUnit);
/*
* Parse the coordinate system. The linear unit must be specified somewhere, either explicitly in each axis
- * or for the whole CRS with the above 'csUnit' value. If 'csUnit' is null, then an exception will be thrown
+ * or for the whole CRS with the above `csUnit` value. If `csUnit` is null, then an exception will be thrown
* with a message like "A LengthUnit component is missing in ProjectedCRS".
*
* However we make an exception if we are parsing a BaseProjCRS, since the coordinate system is unspecified
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
index 40e2a0e..0ae1e2a 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
@@ -570,7 +570,7 @@
*
* <h4>Scientific notation</h4>
* The {@link NumberFormat} created here does not use scientific notation. This is okay for many
- * WKT formatting purpose since Earth ellipsoid axis lengths in metres are large enough for trigging
+ * WKT formatting purpose since Earth ellipsoid axis lengths in metres are large enough for triggering
* scientific notation, while we want to express them as normal numbers with centimetre precision.
* However this is problematic for small numbers like 1E-5. Callers may need to adjust the precision
* depending on the kind of numbers (length or angle) to format.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java
index 494f7fc..c73c256 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java
@@ -625,7 +625,7 @@
/**
* Parses the current {@link #buffer} content as a WKT elements (possibly with children elements).
- * This method does not build the full {@link IdentifiedObject}; this later part will be done only
+ * This method does not build the full {@link IdentifiedObject}; this latter part will be done only
* when first needed.
*
* <p>If {@link #aliasKey} is non-null, the first WKT is taken as a {@linkplain WKTFormat#addFragment
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java
index 5d64aeb..3590268 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java
@@ -83,7 +83,7 @@
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Rémi Eve (IRD)
* @author Rueben Schulz (UBC)
- * @version 1.2
+ * @version 1.3
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
* @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
index f8b88db..5f711ba 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
@@ -366,7 +366,7 @@
/**
* Invoked by JAXB for marshalling the {@link #minimumOccurs} value. Omit marshalling of this
- * {@code gml:minimumOccurs} element if its value is equals to the default value, which is 1.
+ * {@code gml:minimumOccurs} element if its value is equal to the default value, which is 1.
*/
@XmlElement(name = "minimumOccurs")
@XmlSchemaType(name = "nonNegativeInteger")
@@ -377,7 +377,7 @@
/**
* Invoked by JAXB for marshalling the {@link #maximumOccurs} value. Omit marshalling of this
- * {@code gml:maximumOccurs} element if its value is equals to the default value, which is 1.
+ * {@code gml:maximumOccurs} element if its value is equal to the default value, which is 1.
*
* <p>This property should not be marshalled in {@link DefaultParameterDescriptor} objects (the GML schema
* does not allow that). It should be marshalled only for {@link DefaultParameterDescriptorGroup} objects.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
index fc38819..6e96894 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
@@ -420,10 +420,14 @@
* <td>Array of 1 or 2 elements mapped to {@code "standard_parallel_1"} and {@code "standard_parallel_2"}.</td></tr>
* </table>
*
- * <div class="note"><b>Note:</b>
- * When the {@code "earth_radius"} parameter is read, its value is the
- * {@linkplain org.apache.sis.referencing.datum.DefaultEllipsoid#getAuthalicRadius() authalic radius}
- * computed from the semi-major and semi-minor axis lengths.</div>
+ * <b>Notes:</b>
+ * <ul>
+ * <li>The {@code "standard_parallel"} parameter descriptor is added only if the {@code parameters} argument
+ * contains {@code "standard_parallel_1"} and {@code "standard_parallel_2"} descriptors.</li>
+ * <li>When the {@code "earth_radius"} parameter is read, its value is the
+ * {@linkplain org.apache.sis.referencing.datum.DefaultEllipsoid#getAuthalicRadius() authalic radius}
+ * computed from the semi-major and semi-minor axis lengths.</li>
+ * </ul>
*
* Map projection parameter groups always have a {@linkplain DefaultParameterDescriptorGroup#getMinimumOccurs()
* minimum} and {@linkplain DefaultParameterDescriptorGroup#getMaximumOccurs() maximum occurrence} of 1,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
index c5ed946..0b4e5a1 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
@@ -22,6 +22,7 @@
import java.io.Serializable;
import javax.xml.bind.annotation.XmlTransient;
import javax.measure.Unit;
+import javax.measure.IncommensurableException;
import org.opengis.util.MemberName;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
@@ -101,7 +102,7 @@
* overriding one method has no impact on other methods.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.4
* @module
*/
@@ -670,6 +671,40 @@
}
/**
+ * Returns the floating point value of the parameter identified by the given descriptor,
+ * converted to the given unit of measurement. See {@link #getValue(ParameterDescriptor)}
+ * for more information about how this method uses the given {@code parameter} argument.
+ *
+ * @param parameter the name or alias of the parameter to look for.
+ * @param unit the desired unit of measurement.
+ * @return the requested parameter value if it exists, or the <strong>non-null</strong>
+ * {@linkplain DefaultParameterDescriptor#getDefaultValue() default value} otherwise.
+ * @throws ParameterNotFoundException if the given {@code parameter} name or alias is not legal for this group.
+ * @throws IllegalStateException if the value is not defined and there is no default value.
+ * @throws IllegalArgumentException if the specified unit is invalid for the parameter.
+ *
+ * @see DefaultParameterValue#doubleValue(Unit)
+ *
+ * @since 1.3
+ */
+ public double doubleValue(final ParameterDescriptor<? extends Number> parameter, final Unit<?> unit) throws ParameterNotFoundException {
+ ArgumentChecks.ensureNonNull("unit", unit);
+ final ParameterValue<?> value = getParameter(parameter);
+ if (value != null) {
+ return value.doubleValue(unit);
+ } else {
+ double d = defaultValue(parameter).doubleValue();
+ final Unit<?> source = parameter.getUnit();
+ if (source != null) try {
+ d = source.getConverterToAny(unit).convert(d);
+ } catch (IncommensurableException e) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, source, unit), e);
+ }
+ return d;
+ }
+ }
+
+ /**
* Returns the floating point values of the parameter identified by the given descriptor.
* See {@link #getValue(ParameterDescriptor)} for more information about how this method
* uses the given {@code parameter} argument.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
index b23ca74..9894189 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
@@ -384,7 +384,7 @@
}
/**
- * Verifies that the length of the given array is equals to the tensor rank.
+ * Verifies that the length of the given array is equal to the tensor rank.
*/
private void verifyRank(final int[] indices) {
if (indices.length != rank()) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
index 3cfbba4..6553561 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
@@ -45,7 +45,7 @@
/**
- * Base class of builders for various kind of {@link IdentifiedObject}. This class provides convenience methods
+ * Base class of builders for various kinds of {@link IdentifiedObject}. This class provides convenience methods
* for filling the {@link #properties} map to be given to an {@link org.opengis.referencing.ObjectFactory}.
* The main properties are:
*
@@ -233,7 +233,7 @@
* Verifies that {@code B} in {@code <B extends Builder<B>} is the expected class.
* This method is for assertion purposes only.
*/
- private static boolean verifyParameterizedType(final Class<?> expected) {
+ private static boolean verifyParameterizedType(Class<?> expected) {
for (Class<?> c = expected; c != null; c = c.getSuperclass()) {
Type type = c.getGenericSuperclass();
if (type instanceof ParameterizedType) {
@@ -243,6 +243,8 @@
if (type == expected) return true;
throw new AssertionError(type);
}
+ } else {
+ expected = c.getSuperclass();
}
}
return false;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
index eac90c0..b88fabd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
@@ -1281,8 +1281,8 @@
* searches for a {@linkplain CompoundCRS#getComponents() component} where:
* <ul>
* <li>The {@linkplain org.apache.sis.referencing.cs.AbstractCS#getDimension() number of dimensions}
- * is equals to {@code upper - lower};</li>
- * <li>The sum of the number of dimensions of all previous CRS is equals to {@code lower}.</li>
+ * is equal to {@code upper - lower};</li>
+ * <li>The sum of the number of dimensions of all previous CRS is equal to {@code lower}.</li>
* </ul>
* If such component is found, then it is returned.</li>
* <li>Otherwise (i.e. no component match), this method returns {@code null}.</li>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
index 9e8e0e5..4f4b1f0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
@@ -22,7 +22,6 @@
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import org.opengis.parameter.GeneralParameterValue;
import org.opengis.referencing.datum.Datum;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.datum.VerticalDatum;
@@ -46,8 +45,8 @@
import org.opengis.geometry.MismatchedDimensionException;
import org.apache.sis.referencing.AbstractIdentifiedObject;
import org.apache.sis.referencing.operation.DefaultConversion;
-import org.apache.sis.referencing.operation.DefaultOperationMethod;
import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.referencing.cs.CoordinateSystems;
import org.apache.sis.internal.jaxb.referencing.SC_SingleCRS;
import org.apache.sis.internal.jaxb.referencing.SC_DerivedCRSType;
import org.apache.sis.internal.jaxb.referencing.CS_CoordinateSystem;
@@ -55,10 +54,8 @@
import org.apache.sis.internal.referencing.WKTUtilities;
import org.apache.sis.internal.referencing.WKTKeywords;
import org.apache.sis.io.wkt.Convention;
-import org.apache.sis.io.wkt.FormattableObject;
import org.apache.sis.io.wkt.Formatter;
import org.apache.sis.util.ComparisonMode;
-import org.apache.sis.util.Classes;
// Branch-dependent imports
import org.apache.sis.referencing.cs.DefaultParametricCS;
@@ -96,7 +93,7 @@
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 0.7
+ * @version 1.3
*
* @see org.apache.sis.referencing.factory.GeodeticAuthorityFactory#createDerivedCRS(String)
*
@@ -566,18 +563,7 @@
return WKTKeywords.Fitted_CS;
} else {
formatter.newLine();
- formatter.append(new FormattableObject() { // Format inside a "DefiningConversion" element.
- @Override protected String formatTo(final Formatter formatter) {
- WKTUtilities.appendName(conversion, formatter, null);
- formatter.newLine();
- formatter.append(DefaultOperationMethod.castOrCopy(conversion.getMethod()));
- formatter.newLine();
- for (final GeneralParameterValue param : conversion.getParameterValues().values()) {
- WKTUtilities.append(param, formatter);
- }
- return WKTKeywords.DerivingConversion;
- }
- });
+ formatter.append(new ExplicitParameters(this, WKTKeywords.DerivingConversion)); // Format inside a "DefiningConversion" element.
if (convention == Convention.INTERNAL || !isBaseCRS(formatter)) {
final CoordinateSystem cs = getCoordinateSystem();
formatCS(formatter, cs, ReferencingUtilities.getUnit(cs), isWKT1);
@@ -608,9 +594,7 @@
/**
* Returns the WKT 2 keyword for a {@code DerivedCRS} having the given base CRS and derived coordinate system.
- * Note that an ambiguity exists if the given base CRS is a {@code GeodeticCRS}, as the result could be either
- * {@code "GeodeticCRS"} or {@code "EngineeringCRS"}. The current implementation returns the former if the
- * derived coordinate system is of the same kind than the base coordinate system.
+ * If the type can not be identifier, then this method returns {@code null}.
*/
static String getType(final SingleCRS baseCRS, final CoordinateSystem derivedCS) {
final Class<?> type;
@@ -625,14 +609,8 @@
} else {
return null;
}
- if (GeodeticCRS.class.isAssignableFrom(type)) {
- if (Classes.implementSameInterfaces(derivedCS.getClass(),
- baseCRS.getCoordinateSystem().getClass(), CoordinateSystem.class))
- {
- return WKTKeywords.GeodeticCRS;
- } else {
- return WKTKeywords.EngineeringCRS;
- }
+ if (GeodeticCRS.class.isAssignableFrom(type) && CoordinateSystems.isGeodetic(derivedCS)) {
+ return WKTKeywords.GeodeticCRS;
} else if (VerticalCRS.class.isAssignableFrom(type) && derivedCS instanceof VerticalCS) {
return WKTKeywords.VerticalCRS;
} else if (TemporalCRS.class.isAssignableFrom(type) && derivedCS instanceof TimeCS) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
index 04c86d3..42aaad4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
@@ -19,38 +19,25 @@
import java.util.Map;
import javax.measure.Unit;
import javax.measure.quantity.Angle;
-import javax.measure.quantity.Length;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.parameter.ParameterValue;
-import org.opengis.parameter.GeneralParameterValue;
-import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.CoordinateSystem; // For javadoc
-import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.Projection;
import org.opengis.geometry.MismatchedDimensionException;
-import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.referencing.cs.AxesConvention;
-import org.apache.sis.referencing.operation.DefaultOperationMethod;
import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.internal.referencing.WKTKeywords;
import org.apache.sis.internal.referencing.WKTUtilities;
-import org.apache.sis.internal.util.Constants;
-import org.apache.sis.internal.system.Loggers;
import org.apache.sis.io.wkt.Convention;
-import org.apache.sis.io.wkt.FormattableObject;
import org.apache.sis.io.wkt.Formatter;
import org.apache.sis.util.ComparisonMode;
-import org.apache.sis.util.logging.Logging;
-
-import static java.util.logging.Logger.getLogger;
import static org.apache.sis.internal.referencing.WKTUtilities.toFormattable;
@@ -404,7 +391,7 @@
formatter.newLine();
formatter.append(toFormattable(baseCRS));
formatter.newLine();
- final Parameters p = new Parameters(this);
+ final ExplicitParameters p = new ExplicitParameters(this, WKTKeywords.Conversion);
final boolean isBaseCRS;
if (isWKT1) {
p.append(formatter); // Format outside of any "Conversion" element.
@@ -426,76 +413,6 @@
: formatter.shortOrLong(WKTKeywords.ProjCRS, WKTKeywords.ProjectedCRS);
}
- /**
- * Temporary object for formatting the projection method and parameters inside a {@code Conversion} element.
- */
- private static final class Parameters extends FormattableObject {
- /** The conversion which specify the operation method and parameters. */
- private final Conversion conversion;
-
- /** Semi-major and semi-minor axis lengths. */
- private final Ellipsoid ellipsoid;
-
- /** Creates a new temporary {@code Conversion} elements for the parameters of the given CRS. */
- Parameters(final DefaultProjectedCRS crs) {
- conversion = crs.getConversionFromBase();
- ellipsoid = crs.getDatum().getEllipsoid();
- }
-
- /** Formats this {@code Conversion} element. */
- @Override protected String formatTo(final Formatter formatter) {
- WKTUtilities.appendName(conversion, formatter, null);
- formatter.newLine();
- append(formatter);
- return WKTKeywords.Conversion;
- }
-
- /** Formats this {@code Conversion} element without the conversion name. */
- void append(final Formatter formatter) {
- final Unit<Length> axisUnit = ellipsoid.getAxisUnit();
- formatter.append(DefaultOperationMethod.castOrCopy(conversion.getMethod()));
- formatter.newLine();
- for (final GeneralParameterValue param : conversion.getParameterValues().values()) {
- final GeneralParameterDescriptor desc = param.getDescriptor();
- String name;
- if (IdentifiedObjects.isHeuristicMatchForName(desc, name = Constants.SEMI_MAJOR) ||
- IdentifiedObjects.isHeuristicMatchForName(desc, name = Constants.SEMI_MINOR))
- {
- /*
- * Do not format semi-major and semi-minor axis length in most cases, since those
- * information are provided in the ellipsoid. An exception to this rule occurs if
- * the lengths are different from the ones declared in the datum.
- */
- if (param instanceof ParameterValue<?>) {
- final double value;
- try {
- value = ((ParameterValue<?>) param).doubleValue(axisUnit);
- } catch (IllegalStateException e) {
- /*
- * May happen if the 'conversionFromBase' parameter group does not provide values
- * for "semi_major" or "semi_minor" axis length. This should not happen with SIS
- * implementation, but may happen with user-defined map projection implementations.
- * Since the intent of this check was to skip those parameters anyway, it is okay
- * for the purpose of WKT formatting if there are no parameters for axis lengths.
- */
- Logging.recoverableException(getLogger(Loggers.WKT), DefaultProjectedCRS.class, "formatTo", e);
- continue;
- }
- if (Double.isNaN(value)) {
- continue;
- }
- final double expected = (name == Constants.SEMI_MINOR) // using '==' is okay here.
- ? ellipsoid.getSemiMinorAxis() : ellipsoid.getSemiMajorAxis();
- if (value == expected) {
- continue;
- }
- }
- }
- WKTUtilities.append(param, formatter);
- }
- }
- }
-
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ExplicitParameters.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ExplicitParameters.java
new file mode 100644
index 0000000..61e0d41
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ExplicitParameters.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.crs;
+
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.referencing.datum.Datum;
+import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.operation.Conversion;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.operation.DefaultOperationMethod;
+import org.apache.sis.internal.referencing.WKTKeywords;
+import org.apache.sis.internal.referencing.WKTUtilities;
+import org.apache.sis.internal.util.Constants;
+import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.util.logging.Logging;
+
+import static java.util.logging.Logger.getLogger;
+
+
+/**
+ * Temporary object for formatting the projection method and parameters inside a {@code Conversion} element.
+ * This object formats only the explicit parameters. Implicit parameters derived from source ellipsoid are omitted.
+ *
+ * @author Martin Desruisseaux (IRD, Geomatys)
+ * @version 1.3
+ * @since 0.6
+ * @module
+ */
+final class ExplicitParameters extends FormattableObject {
+ /**
+ * The conversion which specify the operation method and parameters.
+ */
+ private final Conversion conversion;
+
+ /**
+ * Semi-major and semi-minor axis lengths, or {@code null} if the datum is not geodetic.
+ */
+ private final Ellipsoid ellipsoid;
+
+ /**
+ * The keyword to be returned by {@link #formatTo(Formatter)}.
+ * Should be {@link WKTKeywords#Conversion} or {@link WKTKeywords#DerivingConversion}.
+ */
+ private final String keyword;
+
+ /**
+ * Creates a new temporary {@code Conversion} elements for the parameters of the given CRS.
+ */
+ ExplicitParameters(final AbstractDerivedCRS<?> crs, final String keyword) {
+ conversion = crs.getConversionFromBase();
+ final Datum datum = crs.getDatum();
+ ellipsoid = (datum instanceof GeodeticDatum) ? ((GeodeticDatum) datum).getEllipsoid() : null;
+ this.keyword = keyword;
+ }
+
+ /**
+ * Formats this {@code Conversion} element.
+ */
+ @Override
+ protected String formatTo(final Formatter formatter) {
+ WKTUtilities.appendName(conversion, formatter, null);
+ formatter.newLine();
+ append(formatter);
+ return keyword;
+ }
+
+ /**
+ * Formats this {@code Conversion} element without the conversion name.
+ */
+ void append(final Formatter formatter) {
+ formatter.append(DefaultOperationMethod.castOrCopy(conversion.getMethod()));
+ formatter.newLine();
+ for (final GeneralParameterValue param : conversion.getParameterValues().values()) {
+ final GeneralParameterDescriptor desc = param.getDescriptor();
+ if (ellipsoid != null) {
+ String name;
+ if (IdentifiedObjects.isHeuristicMatchForName(desc, name = Constants.SEMI_MAJOR) ||
+ IdentifiedObjects.isHeuristicMatchForName(desc, name = Constants.SEMI_MINOR))
+ {
+ /*
+ * Do not format semi-major and semi-minor axis length in most cases, since those
+ * information are provided in the ellipsoid. An exception to this rule occurs if
+ * the lengths are different from the ones declared in the datum.
+ */
+ if (param instanceof ParameterValue<?>) {
+ final double value;
+ try {
+ value = ((ParameterValue<?>) param).doubleValue(ellipsoid.getAxisUnit());
+ } catch (IllegalStateException e) {
+ /*
+ * May happen if the 'conversionFromBase' parameter group does not provide values
+ * for "semi_major" or "semi_minor" axis length. This should not happen with SIS
+ * implementation, but may happen with user-defined map projection implementations.
+ * Since the intent of this check was to skip those parameters anyway, it is okay
+ * for the purpose of WKT formatting if there are no parameters for axis lengths.
+ */
+ Logging.recoverableException(getLogger(Loggers.WKT), DefaultProjectedCRS.class, "formatTo", e);
+ continue;
+ }
+ if (Double.isNaN(value)) {
+ continue;
+ }
+ final double expected = (name == Constants.SEMI_MINOR) // using '==' is okay here.
+ ? ellipsoid.getSemiMinorAxis() : ellipsoid.getSemiMajorAxis();
+ if (value == expected) {
+ continue;
+ }
+ }
+ }
+ }
+ WKTUtilities.append(param, formatter);
+ }
+ }
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
index b945ed4..1102f49 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
@@ -28,6 +28,7 @@
import org.opengis.referencing.cs.RangeMeaning;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.SphericalCS;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
@@ -72,6 +73,20 @@
}
/**
+ * Returns whether the given coordinate system can be associated to a {@link org.opengis.referencing.crs.GeodeticCRS}.
+ * This is true for instances of {@link EllipsoidalCS}, {@link CartesianCS} and {@link SphericalCS},
+ * and false for all other types of coordinate system.
+ *
+ * @param cs the coordinate system to test (can be {@code null}).
+ * @return whether the given coordinate system can be associated to a geodetic CRS.
+ *
+ * @since 1.3
+ */
+ public static boolean isGeodetic(final CoordinateSystem cs) {
+ return (cs instanceof EllipsoidalCS) || (cs instanceof CartesianCS) || (cs instanceof SphericalCS);
+ }
+
+ /**
* Returns an axis direction code from the given direction name.
* Names are case-insensitive. They may be:
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
index 71cfec9..004fcdf 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
@@ -344,7 +344,7 @@
}
/**
- * Returns {@code true} if the {@linkplain #targetDatum target datum} is equals (at least on computation purpose)
+ * Returns {@code true} if the {@linkplain #targetDatum target datum} is equal (at least on computation purpose)
* to the WGS84 datum. If the datum is unspecified, then this method returns {@code true} since WGS84 is the only
* datum supported by the WKT 1 format, and is what users often mean.
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
index cac325a..19f8396 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
@@ -570,7 +570,7 @@
* <p>This method is invoked by the default {@link #find(IdentifiedObject)} method implementation.
* The caller iterates through the returned codes, instantiate the objects and compare them with
* the specified one in order to determine which codes are really applicable.
- * The iteration stops as soon as a match is found (in other words, if more than one object is equals
+ * The iteration stops as soon as a match is found (in other words, if more than one object is equal
* to the specified one, then the {@code find(…)} method selects the first one in iteration order).</p>
*
* <h4>Default implementation</h4>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
index f1365b5..de5a619 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
@@ -476,7 +476,7 @@
* {@link FactoryException} (except the ones accepted as {@linkplain #isRecoverableFailure recoverable failures})
* are thrown as if they were never wrapped into {@link BackingStoreException}.
*
- * @param n the number of object to resolve. If this number is equals or greater than {@link #size()}, then
+ * @param n the number of object to resolve. If this number is equal or greater than {@link #size()}, then
* this method ensures that all {@code IdentifiedObject} instances in this collection are created.
* @throws FactoryException if an {@linkplain #createObject(String) object creation} failed.
*/
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 2738f08..fcb1c87 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -1493,6 +1493,12 @@
* For a ProjectedCRS, the baseCRS is always geographic. So in theory we would not
* need the `instanceof` check. However the EPSG dataset version 8.9 also uses the
* "projected" type for CRS that are actually derived CRS. See EPSG:5820 and 5821.
+ *
+ * TODO: there is an ambiguity when the source CRS is geographic but the operation
+ * is nevertheless considered as not a map projection. It is the case of EPSG:5819.
+ * The problem is that the "COORD_REF_SYS_KIND" column still contains "Projected".
+ * We need to check if EPSG database 10+ has more specific information.
+ * See https://issues.apache.org/jira/browse/SIS-518
*/
final Map<String, Object> properties = createProperties("Coordinate Reference System",
name, epsg, area, scope, remarks, deprecated);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
index e099d5e..7925511 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
@@ -507,7 +507,7 @@
}
/**
- * Replaces the text at the given position in the buffer if it is equals to the {@code expected} text.
+ * Replaces the text at the given position in the buffer if it is equal to the {@code expected} text.
*/
private static boolean replaceIfEquals(final StringBuilder ansi, final int pos,
final String expected, final String replacement)
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index 71f2c44..d709744 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@ -524,8 +524,9 @@
* set to Greenwich in EPSG dataset 8.9. For safety, the SIS's DefaultGeodeticDatum class ensures that if the
* prime meridians are not the same, then the target meridian must be Greenwich.
*/
- final DefaultMathTransformFactory.Context context = ReferencingUtilities.createTransformContext(
- sourceCRS, targetCRS, new MathTransformContext(sourceDatum, targetDatum));
+ final DefaultMathTransformFactory.Context context = new MathTransformContext(sourceDatum, targetDatum);
+ context.setSource(sourceCRS);
+ context.setTarget(targetCRS);
/*
* If both CRS use the same datum and the same prime meridian, then the coordinate operation is only axis
* swapping, unit conversion or change of coordinate system type (Ellipsoidal ↔ Cartesian ↔ Spherical).
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
index ffb2925..1fb1361 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
@@ -982,7 +982,7 @@
final MathTransformFactory mtFactory = factorySIS.getMathTransformFactory();
if (mtFactory instanceof DefaultMathTransformFactory) {
MathTransform mt = ((DefaultMathTransformFactory) mtFactory).createParameterizedTransform(
- parameters, ReferencingUtilities.createTransformContext(sourceCRS, targetCRS, null));
+ parameters, ReferencingUtilities.createTransformContext(sourceCRS, targetCRS));
return factorySIS.createSingleOperation(IdentifiedObjects.getProperties(operation),
sourceCRS, targetCRS, null, operation.getMethod(), mt);
}
@@ -1104,7 +1104,7 @@
try {
mt = ((DefaultMathTransformFactory) mtFactory).createParameterizedTransform(
((SingleOperation) op).getParameterValues(),
- ReferencingUtilities.createTransformContext(sourceCRS, targetCRS, null));
+ ReferencingUtilities.createTransformContext(sourceCRS, targetCRS));
} catch (InvalidGeodeticParameterException e) {
log(null, e);
break;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
index dcc444c..8cec2a3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
@@ -256,10 +256,10 @@
*/
final DefaultMathTransformFactory.Context context;
if (target instanceof GeneralDerivedCRS) {
- context = ReferencingUtilities.createTransformContext(source, null, null);
+ context = ReferencingUtilities.createTransformContext(source, null);
context.setTarget(target.getCoordinateSystem()); // Using `target` would be unsafe here.
} else {
- context = ReferencingUtilities.createTransformContext(source, target, null);
+ context = ReferencingUtilities.createTransformContext(source, target);
}
transform = ((DefaultMathTransformFactory) factory).createParameterizedTransform(parameters, context);
parameters = Parameters.unmodifiable(context.getCompletedParameters());
@@ -431,7 +431,7 @@
}
/**
- * Ensures that the {@code actual} CRS uses a datum which is equals, ignoring metadata,
+ * Ensures that the {@code actual} CRS uses a datum which is equal, ignoring metadata,
* to the datum of the {@code expected} CRS.
*
* @param param the parameter name, used only in case of error.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
index 1b85df1..e7a566d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
@@ -555,7 +555,7 @@
* - Otherwise we have a datum change, which implies that we have a Transformation.
*
* In the case of Conversion, we can specialize one step more if the conversion is going from a geographic CRS
- * to a projected CRS. It may seems that we should check if ProjectedCRS.getBaseCRS() is equals (ignoring meta
+ * to a projected CRS. It may seems that we should check if ProjectedCRS.getBaseCRS() is equal (ignoring meta
* data) to source CRS. But we already checked the datum, which is the important part. The axis order and unit
* could be different, which we want to allow.
*/
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/MathTransformContext.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/MathTransformContext.java
index 1103ec4..defcd75 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/MathTransformContext.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/MathTransformContext.java
@@ -36,7 +36,7 @@
/**
* Information about the context in which a {@code MathTransform} is created.
* This class performs the same normalization than the super-class (namely axis swapping and unit conversions),
- * with the addition of longitude rotation for supporting change of prime meridian. This later change is not
+ * with the addition of longitude rotation for supporting change of prime meridian. This latter change is not
* applied by the super-class because prime meridian is part of geodetic datum, and the public math transform
* factory know nothing about datum (on design, for separation of concerns).
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
index e9d8cae..19bc0d2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
@@ -226,8 +226,10 @@
}
/**
- * Converts the specified (θ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (θ,φ) coordinates and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The units of measurement are implementation-specific (see super-class javadoc).
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicMercator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicMercator.java
index 2f331d4..039802a 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicMercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicMercator.java
@@ -54,9 +54,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}
- * (linear distance on a unit sphere). In addition, opportunistically computes the projection derivative
- * if {@code derivate} is {@code true}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
+ * In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java
index ba8c3e8..500c481 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java
@@ -157,7 +157,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate and stores the (<var>x</var>,<var>y</var>) result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
+ * In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @param srcPts source point coordinate, as (<var>longitude</var>, <var>latitude</var>) in radians.
* @param srcOff the offset of the single coordinate to be converted in the source array.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CassiniSoldner.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CassiniSoldner.java
index 10b3684..aba6518 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CassiniSoldner.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CassiniSoldner.java
@@ -233,8 +233,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @param srcPts the array containing the source point coordinate,
* as (<var>longitude</var>, <var>latitude</var>) angles in <strong>radians</strong>.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
index 0b1eca0..2261170 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
@@ -230,9 +230,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}
- * (linear distance on a unit sphere). In addition, opportunistically computes the projection derivative
- * if {@code derivate} is {@code true}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
+ * In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
index 58cff5e..1ba7d95 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
@@ -163,8 +163,9 @@
}
/**
- * Converts the specified (λ,φ)) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
index 0a6923d..459212d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
@@ -442,8 +442,10 @@
}
/**
- * Converts the specified (θ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (θ,φ) coordinates and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The units of measurement are implementation-specific (see super-class javadoc).
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
index 90097ef..e0fed81 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
@@ -381,7 +381,7 @@
@Override
public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException {
NormalizedProjection kernel = this;
-subst: if ((variant.spherical || eccentricity == 0) && getClass() == Mercator.class) {
+subst: if (variant.spherical || (eccentricity == 0 && getClass() == Mercator.class)) {
if (variant == Variant.AUXILIARY && eccentricity != 0) {
final int type = context.getValue(MercatorAuxiliarySphere.AUXILIARY_SPHERE_TYPE);
if (type == AuthalicMercator.TYPE) {
@@ -408,8 +408,9 @@
}
/**
- * Converts the specified coordinate (implementation-specific units) and stores the result in {@code dstPts}.
+ * Projects the specified coordinates (implementation-specific units) and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistant.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistant.java
index 744aea5..0a50fe3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistant.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ModifiedAzimuthalEquidistant.java
@@ -155,7 +155,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate and stores the (<var>x</var>,<var>y</var>) result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinate (units in radians)
+ * and stores the (<var>x</var>,<var>y</var>) result in {@code dstPts}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
index f9c4d75..5285f2a 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
@@ -119,8 +119,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate and stores the (<var>x</var>,<var>y</var>) result in {@code dstPts}.
+ * Projects the specified (Λ,φ) coordinates and stores the (<var>x</var>,<var>y</var>) result in {@code dstPts}.
* The units of measurement are implementation-specific (see super-class javadoc).
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
index d67e177..fd2bb37 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
@@ -692,9 +692,9 @@
*/
/**
- * Converts a single coordinate in {@code srcPts} at the given offset and stores the result
- * in {@code dstPts} at the given offset. In addition, opportunistically computes the
- * transform derivative if requested.
+ * Projects a single coordinate tuple in {@code srcPts} at the given offset
+ * and stores the result in {@code dstPts} at the given offset.
+ * In addition, opportunistically computes the transform derivative if requested.
*
* <h4>Normalization</h4>
* The input coordinates are (<var>λ</var>,<var>φ</var>) (the variable names for <var>longitude</var> and
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueMercator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueMercator.java
index 061f586..b3cc32a 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueMercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueMercator.java
@@ -327,8 +327,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
index 615bad7..fcd61d7 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
@@ -257,8 +257,10 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (Λ,φ) coordinates and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The units of measurement are implementation-specific (see super-class javadoc).
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
@@ -327,7 +329,7 @@
final double cosφ = cos(φ);
final double dχ_dφ = (1/cosφ - cosφ*eccentricitySquared/(1 - ℯsinφ*ℯsinφ)) * 2*n*sqrt(w) / (w + 1);
/*
- * Above ∂χ/∂φ is equals to 1 in the spherical case.
+ * Above ∂χ/∂φ is equal to 1 in the spherical case.
* Remaining formulas below are the same than in the spherical case.
*/
final double B2 = B * B;
@@ -360,7 +362,7 @@
final double j = atan2(x, g - y) - i;
/*
* The conformal longitude is Λ = j + 2i + Λ₀. In the particular case of stereographic projection,
- * the geodetic longitude λ is equals to Λ. Furthermore in Apache SIS implementation, Λ₀ is added by
+ * the geodetic longitude λ is equal to Λ. Furthermore in Apache SIS implementation, Λ₀ is added by
* the denormalization matrix and shall not be handled here. The only remaining part is λ = j + 2i.
*/
final double λ = j + 2*i;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java
index 70979ec..95a2664 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java
@@ -145,8 +145,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate and stores the (<var>x</var>,<var>y</var>) result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates and stores the result in {@code dstPts}.
* The units of measurement are implementation-specific (see super-class javadoc).
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
index 0694632..ce77e48 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
@@ -317,8 +317,9 @@
}
/**
- * Converts the specified (θ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Polyconic.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Polyconic.java
index 4170432..e19d6a0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Polyconic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Polyconic.java
@@ -168,9 +168,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}
- * (linear distance on a unit sphere). In addition, opportunistically computes the projection derivative
- * if {@code derivate} is {@code true}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
+ * In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java
index 7bab551..454920c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java
@@ -295,8 +295,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The units of measurement are implementation-specific (see super-class javadoc).
* The results must be multiplied by the denormalization matrix before to get linear distances.
*
* <p>The <var>y</var> axis lies along the central meridian λ₀, <var>y</var> increasing northerly, and
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java
index 808d9e4..0912b32 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Sinusoidal.java
@@ -17,6 +17,7 @@
package org.apache.sis.referencing.operation.projection;
import java.util.EnumMap;
+import java.util.regex.Pattern;
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.referencing.operation.Matrix;
@@ -41,7 +42,7 @@
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 1.0
* @module
*/
@@ -52,16 +53,60 @@
private static final long serialVersionUID = 7908925241331303236L;
/**
+ * Variants of Sinusoidal projection. Those variants modify the way the projections are constructed
+ * (e.g. in the way parameters are interpreted), but formulas are basically the same after construction.
+ *
+ * <p>We do not provide such codes in public API because they duplicate the functionality of
+ * {@link OperationMethod} instances. We use them only for constructors convenience.</p>
+ */
+ private enum Variant implements ProjectionVariant {
+ // Declaration order matter. Patterns are matched in that order.
+
+ /** The <cite>"Pseudo sinusoidal equal-area"</cite> projection. */
+ PSEUDO(".*\\bPseudo.*");
+
+ /** Name pattern for this variant. */
+ private final Pattern operationName;
+
+ /** Creates a new enumeration value. */
+ private Variant(final String operationName) {
+ this.operationName = Pattern.compile(operationName, Pattern.CASE_INSENSITIVE);
+ }
+
+ /** The expected name pattern of an operation method for this variant. */
+ @Override public Pattern getOperationNamePattern() {
+ return operationName;
+ }
+
+ /** EPSG identifier of an operation method for this variant. */
+ @Override public String getIdentifier() {
+ return null;
+ }
+ }
+
+ /**
+ * The type of sinusoidal projection. Possible values are:
+ * <ul>
+ * <li>{@link Variant#PSEUDO} if this projection is the "Pseudo sinusoidal equal-area" case.</li>
+ * <li>{@code null} for the standard case.</li>
+ * </ul>
+ *
+ * Other cases may be added in the future.
+ */
+ private final Variant variant;
+
+ /**
* Work around for RFE #4093999 in Sun's bug database
* ("Relax constraint on placement of this()/super() call in constructors").
*/
@Workaround(library="JDK", version="1.8")
private static Initializer initializer(final OperationMethod method, final Parameters parameters) {
+ final Variant variant = variant(method, Variant.values(), null);
final EnumMap<ParameterRole, ParameterDescriptor<Double>> roles = new EnumMap<>(ParameterRole.class);
roles.put(ParameterRole.CENTRAL_MERIDIAN, CENTRAL_MERIDIAN);
roles.put(ParameterRole.FALSE_EASTING, FALSE_EASTING);
roles.put(ParameterRole.FALSE_NORTHING, FALSE_NORTHING);
- return new Initializer(method, parameters, roles, null);
+ return new Initializer(method, parameters, roles, variant);
}
/**
@@ -76,7 +121,17 @@
* @param parameters the parameter values of the projection to create.
*/
public Sinusoidal(final OperationMethod method, final Parameters parameters) {
- super(initializer(method, parameters));
+ this(initializer(method, parameters));
+ }
+
+ /**
+ * Work around for RFE #4093999 in Sun's bug database
+ * ("Relax constraint on placement of this()/super() call in constructors").
+ */
+ @Workaround(library="JDK", version="1.7")
+ private Sinusoidal(final Initializer initializer) {
+ super(initializer);
+ variant = (Variant) initializer.variant;
}
/**
@@ -84,6 +139,7 @@
*/
Sinusoidal(final Sinusoidal other) {
super(other);
+ variant = other.variant;
}
/**
@@ -101,16 +157,16 @@
@Override
public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException {
Sinusoidal kernel = this;
- if (eccentricity == 0 && getClass() == Sinusoidal.class) {
+ if ((eccentricity == 0 && getClass() == Sinusoidal.class) || variant == Variant.PSEUDO) {
kernel = new Spherical(this);
}
return context.completeTransform(factory, kernel);
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}
- * (linear distance on a unit sphere). In addition, opportunistically computes the projection derivative
- * if {@code derivate} is {@code true}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
+ * In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* @return the matrix of the projection derivative at the given source position,
* or {@code null} if the {@code derivate} argument is {@code false}.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
index 10ee421..2ad53aa 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
@@ -409,8 +409,9 @@
}
/**
- * Converts the specified (λ,φ) coordinate (units in radians) and stores the result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates (units in radians) and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
+ * The results must be multiplied by the denormalization matrix before to get linear distances.
*
* <h4>Accuracy and domain of validity</h4>
* Projection errors depend on the difference ∆λ between longitude λ and the central meridian λ₀.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java
index 146f574..524c6fd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java
@@ -165,7 +165,7 @@
}
/**
- * Converts the specified (λ,φ) coordinate and stores the result in {@code dstPts}.
+ * Projects the specified (λ,φ) coordinates and stores the result in {@code dstPts}.
* In addition, opportunistically computes the projection derivative if {@code derivate} is {@code true}.
* Note that the derivative does not contain zone prefix.
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java
index f2ad345..0fa929c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java
@@ -160,7 +160,7 @@
* @author Rémi Maréchal (Geomatys)
* @author Adrian Custer (Geomatys)
* @author Matthieu Bastianelli (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see <a href="https://mathworld.wolfram.com/MapProjection.html">Map projections on MathWorld</a>
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
index 8e3709d..fc1a854 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
@@ -785,7 +785,7 @@
* The default implementation performs the following steps:
*
* <ul>
- * <li>Ensure that the {@code point} dimension is equals to this math transform
+ * <li>Ensure that the {@code point} dimension is equal to this math transform
* {@linkplain #getSourceDimensions() source dimensions}.</li>
* <li>Copy the coordinate in a temporary array and pass that array to the
* {@link #transform(double[], int, double[], int, boolean)} method,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index f551bbb..1ea0400 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -38,6 +38,7 @@
import org.opengis.parameter.InvalidParameterNameException;
import org.opengis.parameter.InvalidParameterValueException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeodeticCRS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.CartesianCS;
@@ -165,7 +166,7 @@
* There is typically only one {@code MathTransformFactory} instance for the whole application.
*
* @author Martin Desruisseaux (Geomatys, IRD)
- * @version 1.1
+ * @version 1.3
*
* @see MathTransformProvider
* @see AbstractMathTransform
@@ -541,16 +542,17 @@
* coordinate systems are not {@linkplain AxesConvention#NORMALIZED normalized}.</li>
* </ul>
*
- * By default this class does <strong>not</strong> handle change of
+ * This class does <strong>not</strong> handle change of
* {@linkplain org.apache.sis.referencing.datum.DefaultGeodeticDatum#getPrimeMeridian() prime meridian}
* or anything else related to datum. Datum changes have dedicated {@link OperationMethod},
* for example <cite>"Longitude rotation"</cite> (EPSG:9601) for changing the prime meridian.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
+ @SuppressWarnings("serial") // Fields are not statically typed as Serializable.
public static class Context implements Serializable {
/**
* For cross-version compatibility.
@@ -575,14 +577,14 @@
*
* @todo We could make this information public as a replacement of {@link #getLastMethodUsed()}.
*/
- OperationMethod provider;
+ private OperationMethod provider;
/**
* The parameters actually used.
*
* @see #getCompletedParameters()
*/
- ParameterValueGroup parameters;
+ private ParameterValueGroup parameters;
/**
* Creates a new context with all properties initialized to {@code null}.
@@ -615,13 +617,39 @@
*
* @param cs the coordinate system to set as the source, or {@code null}.
* @param ellipsoid the ellipsoid associated to the given coordinate system, or {@code null}.
+ *
+ * @deprecated Replaced by {@link #setSource(GeodeticCRS)}.
*/
+ @Deprecated
public void setSource(final EllipsoidalCS cs, final Ellipsoid ellipsoid) {
sourceCS = cs;
sourceEllipsoid = ellipsoid;
}
/**
+ * Sets the source coordinate system and related ellipsoid to the components of given CRS.
+ * The {@link Ellipsoid}, fetched from the geodetic datum, is often used together with an {@link EllipsoidalCS},
+ * but not necessarily. The geodetic CRS may also be associated with a spherical or Cartesian coordinate system,
+ * and the ellipsoid information may still be needed even with those non-ellipsoidal coordinate systems.
+ *
+ * <p><strong>This method is not for datum shifts.</strong>
+ * All datum information other than the ellipsoid are ignored.</p>
+ *
+ * @param crs the coordinate system and ellipsoid to set as the source, or {@code null}.
+ *
+ * @since 1.3
+ */
+ public void setSource(final GeodeticCRS crs) {
+ if (crs != null) {
+ sourceCS = crs.getCoordinateSystem();
+ sourceEllipsoid = crs.getDatum().getEllipsoid();
+ } else {
+ sourceCS = null;
+ sourceEllipsoid = null;
+ }
+ }
+
+ /**
* Sets the target coordinate system to the given value.
* The target ellipsoid is unconditionally set to {@code null}.
*
@@ -640,13 +668,39 @@
*
* @param cs the coordinate system to set as the source, or {@code null}.
* @param ellipsoid the ellipsoid associated to the given coordinate system, or {@code null}.
+ *
+ * @deprecated Replaced by {@link #setTarget(GeodeticCRS)}.
*/
+ @Deprecated
public void setTarget(final EllipsoidalCS cs, final Ellipsoid ellipsoid) {
targetCS = cs;
targetEllipsoid = ellipsoid;
}
/**
+ * Sets the target coordinate system and related ellipsoid to the components of given CRS.
+ * The {@link Ellipsoid}, fetched from the geodetic datum, is often used together with an {@link EllipsoidalCS},
+ * but not necessarily. The geodetic CRS may also be associated with a spherical or Cartesian coordinate system,
+ * and the ellipsoid information may still be needed even with those non-ellipsoidal coordinate systems.
+ *
+ * <p><strong>This method is not for datum shifts.</strong>
+ * All datum information other than the ellipsoid are ignored.</p>
+ *
+ * @param crs the coordinate system and ellipsoid to set as the target, or {@code null}.
+ *
+ * @since 1.3
+ */
+ public void setTarget(final GeodeticCRS crs) {
+ if (crs != null) {
+ targetCS = crs.getCoordinateSystem();
+ targetEllipsoid = crs.getDatum().getEllipsoid();
+ } else {
+ targetCS = null;
+ targetEllipsoid = null;
+ }
+ }
+
+ /**
* Returns the source coordinate system, or {@code null} if unspecified.
*
* @return the source coordinate system, or {@code null}.
@@ -981,39 +1035,35 @@
* not a SIS implementation, use as a fallback whether ellipsoids are provided. This fallback
* may be less reliable.
*/
- int n;
+ final boolean sourceOnEllipsoid, targetOnEllipsoid;
if (provider instanceof AbstractProvider) {
- n = ((AbstractProvider) provider).getEllipsoidsMask();
+ final AbstractProvider p = (AbstractProvider) provider;
+ sourceOnEllipsoid = p.sourceOnEllipsoid;
+ targetOnEllipsoid = p.targetOnEllipsoid;
} else {
- n = 0;
- if (sourceEllipsoid != null) n = 1;
- if (targetEllipsoid != null) n |= 2;
+ sourceOnEllipsoid = getSourceEllipsoid() != null;
+ targetOnEllipsoid = getTargetEllipsoid() != null;
}
/*
* Set the ellipsoid axis-length parameter values. Those parameters may appear in the source ellipsoid,
* in the target ellipsoid or in both ellipsoids.
*/
- switch (n) {
- case 0: return null;
- case 1: return setEllipsoid(getSourceEllipsoid(), Constants.SEMI_MAJOR, Constants.SEMI_MINOR, true, null);
- case 2: return setEllipsoid(getTargetEllipsoid(), Constants.SEMI_MAJOR, Constants.SEMI_MINOR, true, null);
- case 3: {
- RuntimeException failure = null;
- if (sourceCS != null) try {
- ensureCompatibleParameters(true);
- final ParameterValue<?> p = parameters.parameter("dim"); // Really `parameters`, not `userParams`.
- if (p.getValue() == null) {
- p.setValue(sourceCS.getDimension());
- }
- } catch (IllegalArgumentException | IllegalStateException e) {
- failure = e;
- }
- failure = setEllipsoid(getSourceEllipsoid(), "src_semi_major", "src_semi_minor", false, failure);
- failure = setEllipsoid(getTargetEllipsoid(), "tgt_semi_major", "tgt_semi_minor", false, failure);
- return failure;
+ if (!(sourceOnEllipsoid | targetOnEllipsoid)) return null;
+ if (!targetOnEllipsoid) return setEllipsoid(getSourceEllipsoid(), Constants.SEMI_MAJOR, Constants.SEMI_MINOR, true, null);
+ if (!sourceOnEllipsoid) return setEllipsoid(getTargetEllipsoid(), Constants.SEMI_MAJOR, Constants.SEMI_MINOR, true, null);
+ RuntimeException failure = null;
+ if (sourceCS != null) try {
+ ensureCompatibleParameters(true);
+ final ParameterValue<?> p = parameters.parameter("dim"); // Really `parameters`, not `userParams`.
+ if (p.getValue() == null) {
+ p.setValue(sourceCS.getDimension());
}
- default: throw new AssertionError(n);
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ failure = e;
}
+ failure = setEllipsoid(getSourceEllipsoid(), "src_semi_major", "src_semi_minor", false, failure);
+ failure = setEllipsoid(getTargetEllipsoid(), "tgt_semi_major", "tgt_semi_minor", false, failure);
+ return failure;
}
}
@@ -1356,7 +1406,7 @@
ArgumentChecks.ensureNonNull("baseCRS", baseCRS);
ArgumentChecks.ensureNonNull("parameters", parameters);
ArgumentChecks.ensureNonNull("derivedCS", derivedCS);
- final Context context = ReferencingUtilities.createTransformContext(baseCRS, null, null);
+ final Context context = ReferencingUtilities.createTransformContext(baseCRS, null);
context.setTarget(derivedCS);
return createParameterizedTransform(parameters, context);
}
@@ -1403,12 +1453,14 @@
final String operation;
if (isEllipsoidalSource) {
operation = GeographicToGeocentric.NAME;
- context.setSource(cs = (EllipsoidalCS) source, ellipsoid);
+ context.setSource(cs = (EllipsoidalCS) source);
context.setTarget(target);
+ context.sourceEllipsoid = ellipsoid;
} else {
operation = GeocentricToGeographic.NAME;
context.setSource(source);
- context.setTarget(cs = (EllipsoidalCS) target, ellipsoid);
+ context.setTarget(cs = (EllipsoidalCS) target);
+ context.targetEllipsoid = ellipsoid;
}
final ParameterValueGroup pg = getDefaultParameters(operation);
if (cs.getDimension() < 3) pg.parameter("dim").setValue(2); // Apache SIS specific parameter.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
index 81b3bbe..ce4215e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
@@ -90,14 +90,13 @@
* The units of measurements depend on how the {@code MathTransform} has been created:
* <ul>
* <li>{@code EllipsoidToCentricTransform} instances created directly by the constructor expect (λ,φ) values
- * in radians and compute (X,Y,Z) values in units of an ellipsoid having a semi-major axis length of 1.
- * That constructor is reserved for subclasses only.</li>
+ * in radians and compute (X,Y,Z) values in units of an ellipsoid having a semi-major axis length of 1.</li>
* <li>Transforms created by the {@link #createGeodeticConversion createGeodeticConversion(…)} static method expect
* (λ,φ) values in degrees and compute (X,Y,Z) values in units of the ellipsoid axes (usually metres).</li>
* </ul>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -265,7 +264,7 @@
*
* @see #createGeodeticConversion(MathTransformFactory, double, double, Unit, boolean, TargetType)
*/
- protected EllipsoidToCentricTransform(final double semiMajor, final double semiMinor,
+ public EllipsoidToCentricTransform(final double semiMajor, final double semiMinor,
final Unit<Length> unit, final boolean withHeight, final TargetType target)
{
ArgumentChecks.ensureStrictlyPositive("semiMajor", semiMajor);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
index 8e1ce01..92b3765 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
@@ -373,9 +373,9 @@
* <p>Invariants:</p>
* <ul>
* <li>The {@linkplain AbstractMathTransform#getSourceDimensions() source dimensions} of the returned transform
- * is equals to the sum of the source dimensions of all given transforms.</li>
+ * is equal to the sum of the source dimensions of all given transforms.</li>
* <li>The {@linkplain AbstractMathTransform#getTargetDimensions() target dimensions} of the returned transform
- * is equals to the sum of the target dimensions of all given transforms.</li>
+ * is equal to the sum of the target dimensions of all given transforms.</li>
* </ul>
*
* @param components the transforms to aggregate in a single transform, in the given order.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
index e8992a2..5a8cd86 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
@@ -62,8 +62,7 @@
*
* The units of measurements depend on how the {@code MathTransform} has been created:
* <ul>
- * <li>{@code MolodenskyTransform} instances created directly by the constructor work with angular values in radians.
- * That constructor is reserved for subclasses only.</li>
+ * <li>{@code MolodenskyTransform} instances created directly by the constructor work with angular values in radians.</li>
* <li>Transforms created by the {@link #createGeodeticTransformation createGeodeticTransformation(…)} static method
* work with angular values in degrees and heights in the same units than the <strong>source</strong> ellipsoid
* axes (usually metres).</li>
@@ -82,7 +81,7 @@
* @author Rueben Schulz (UBC)
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Rémi Maréchal (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.7
* @module
*/
@@ -145,10 +144,10 @@
*
* @see #createGeodeticTransformation(MathTransformFactory, Ellipsoid, boolean, Ellipsoid, boolean, double, double, double, boolean)
*/
- protected MolodenskyTransform(final Ellipsoid source, final boolean isSource3D,
- final Ellipsoid target, final boolean isTarget3D,
- final double tX, final double tY, final double tZ,
- final boolean isAbridged)
+ public MolodenskyTransform(final Ellipsoid source, final boolean isSource3D,
+ final Ellipsoid target, final boolean isTarget3D,
+ final double tX, final double tY, final double tZ,
+ final boolean isAbridged)
{
super(source, isSource3D, target, isTarget3D, tX, tY, tZ, null, isAbridged,
isAbridged ? AbridgedMolodensky.PARAMETERS : Molodensky.PARAMETERS);
diff --git a/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod b/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
index 52f61ed..4c04e55 100644
--- a/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
+++ b/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
@@ -64,6 +64,7 @@
org.apache.sis.internal.referencing.provider.AzimuthalEquidistantSpherical
org.apache.sis.internal.referencing.provider.ZonedTransverseMercator
org.apache.sis.internal.referencing.provider.Sinusoidal
+org.apache.sis.internal.referencing.provider.PseudoSinusoidal
org.apache.sis.internal.referencing.provider.Polyconic
org.apache.sis.internal.referencing.provider.Mollweide
org.apache.sis.internal.referencing.provider.SouthPoleRotation
@@ -75,3 +76,5 @@
org.apache.sis.internal.referencing.provider.Interpolation1D
org.apache.sis.internal.referencing.provider.SatelliteTracking
org.apache.sis.internal.referencing.provider.Wraparound
+org.apache.sis.internal.referencing.provider.GeocentricToTopocentric
+org.apache.sis.internal.referencing.provider.GeographicToTopocentric
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
index 5f4967b..3f17668 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
@@ -102,7 +102,7 @@
}
/**
- * Asserts that the given envelope is equals to the expected value.
+ * Asserts that the given envelope is equal to the expected value.
*/
@Override
void assertGeometryEquals(GeneralEnvelope expected, GeneralEnvelope actual, double tolx, double toly) {
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
index 13aae3b..15c4130 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
@@ -85,7 +85,7 @@
}
/**
- * Asserts that the given two-dimensional envelope is equals to the given rectangle.
+ * Asserts that the given two-dimensional envelope is equal to the given rectangle.
* The {@code xLower} and {@code xUpper} arguments are the <var>x</var> coordinate values
* for the lower and upper corners respectively. The actual {@code xmin} and {@code ymin}
* values will be inferred from those corners.
@@ -129,7 +129,7 @@
}
/**
- * Asserts that the intersection of the two following envelopes is equals to the given rectangle.
+ * Asserts that the intersection of the two following envelopes is equal to the given rectangle.
* First, this method tests using the {@link Envelope2D} implementation. Then, it tests using the
* {@link GeneralEnvelope} implementation.
*/
@@ -159,7 +159,7 @@
}
/**
- * Asserts that the union of the two following envelopes is equals to the given rectangle.
+ * Asserts that the union of the two following envelopes is equal to the given rectangle.
* First, this method tests using the {@link Envelope2D} implementation.
* Then, it tests using the {@link GeneralEnvelope} implementation.
*
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java
index 8862db4..53a6556 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java
@@ -79,7 +79,7 @@
}
/**
- * Asserts that the given rectangle is equals to the expected value.
+ * Asserts that the given rectangle is equal to the expected value.
*/
@Override
void assertGeometryEquals(Rectangle2D expected, Rectangle2D actual, double tolx, double toly) {
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
index 0514d7f..27233c2 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
@@ -80,7 +80,7 @@
abstract boolean contains(G outer, G inner);
/**
- * Asserts that the given envelope or rectangle is equals to the expected value.
+ * Asserts that the given envelope or rectangle is equal to the expected value.
*/
abstract void assertGeometryEquals(G expected, G actual, double tolx, double toly);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
index a0653a9..efac0d6 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
@@ -44,7 +44,7 @@
private static final double EPS = 1E-12;
/**
- * Asserts that the given point is equals to the given value.
+ * Asserts that the given point is equal to the given value.
*/
private static void assertPointEquals(final double x, final double y, final Point2D point) {
assertEquals(x, point.getX(), EPS);
@@ -95,7 +95,7 @@
/**
* Invokes {@code ShapeUtilities.fitParabol(x1, y1, px, py, x2, y2, horizontal)},
- * then verifies that the control point of the returned curve is equals to {@code (cx, cy)}.
+ * then verifies that the control point of the returned curve is equal to {@code (cx, cy)}.
*/
private static void assertParabolEquals(final double cx, final double cy,
final double x1, final double y1,
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProviderMock.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProviderMock.java
index f2692cd..448bc8d 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProviderMock.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProviderMock.java
@@ -18,6 +18,8 @@
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.operation.SingleOperation;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
@@ -33,7 +35,7 @@
* <p>Subclasses may be promoted to a real operation if we implement their formulas in a future Apache SIS version.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -42,11 +44,13 @@
/**
* Creates a new mock provider.
*/
- ProviderMock(final int sourceDimension,
- final int targetDimension,
- final ParameterDescriptorGroup parameters)
+ ProviderMock(final ParameterDescriptorGroup parameters,
+ final int sourceDimension,
+ final int targetDimension)
{
- super(sourceDimension, targetDimension, parameters);
+ super(SingleOperation.class, parameters,
+ CoordinateSystem.class, sourceDimension, false,
+ CoordinateSystem.class, targetDimension, false);
}
/**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
index da88f46..8cf5f89 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
@@ -37,7 +37,7 @@
* Tests {@link Providers} and some consistency rules of all providers defined in this package.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -72,6 +72,8 @@
GeocentricTranslation3D.class,
GeographicToGeocentric.class,
GeocentricToGeographic.class,
+ GeocentricToTopocentric.class,
+ GeographicToTopocentric.class,
Geographic3Dto2D.class,
Geographic2Dto3D.class,
Molodensky.class,
@@ -115,6 +117,7 @@
ZonedTransverseMercator.class,
SatelliteTracking.class,
Sinusoidal.class,
+ PseudoSinusoidal.class,
Polyconic.class,
Mollweide.class,
SouthPoleRotation.class,
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java
index a08e3b2..7f625ad 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java
@@ -65,6 +65,6 @@
* Creates a new <cite>"Seismic bin grid transformation"</cite> operation method.
*/
public SeismicBinGridMock() {
- super(2, 2, PARAMETERS);
+ super(PARAMETERS, 2, 2);
}
}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java
deleted file mode 100644
index 3e56fe0..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.internal.referencing.provider;
-
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterDescriptorGroup;
-import org.apache.sis.parameter.ParameterBuilder;
-import org.apache.sis.measure.Units;
-
-
-/**
- * The provider for <cite>"Geographic/topocentric conversions"</cite> conversion (EPSG:9837).
- *
- * This conversion is not yet implemented in Apache SIS, but we need to at least accept the parameters
- * for a Well Known Text (WKT) parsing test in the {@code org.apache.sis.io.wkt.WKTParserTest} class.
- *
- * <p>This class may be promoted to a real operation if we implement the formulas in a future Apache SIS version.</p>
- *
- * @author Martin Desruisseaux (Geomatys)
- * @version 0.8
- * @since 0.6
- * @module
- */
-@SuppressWarnings("serial")
-public final strictfp class TopocentricConversionMock extends ProviderMock {
- /**
- * The group of all parameters expected by this coordinate operation.
- */
- private static final ParameterDescriptorGroup PARAMETERS;
- static {
- final ParameterBuilder builder = builder();
- final ParameterDescriptor<?>[] parameters = {
- createLatitude (builder.addIdentifier("8834").addName("Latitude of topocentric origin"), true),
- createLongitude(builder.addIdentifier("8835").addName("Longitude of topocentric origin")),
- builder.addIdentifier("8836").addName("Ellipsoidal height of topocentric origin").create(0, Units.METRE)
- };
- PARAMETERS = builder
- .addIdentifier("9837")
- .addName("Geographic/topocentric conversions")
- .createGroup(parameters);
- }
-
- /**
- * Creates a new <cite>"Geographic/topocentric conversions"</cite> operation method.
- */
- public TopocentricConversionMock() {
- super(3, 3, PARAMETERS);
- }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
index ab30254..39cfa41 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
@@ -57,7 +57,7 @@
* Tests {@link GeodeticObjectParser}.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -971,6 +971,53 @@
}
/**
+ * Tests the parsing of a derived CRS from a WKT 2 string.
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ public void testDerivedCRS() throws ParseException {
+ final DerivedCRS crs = parse(DerivedCRS.class,
+ "GeodCRS[“EPSG topocentric example B”,\n" +
+ " BaseGeodCRS[“WGS 84”,\n" +
+ " Datum[“World Geodetic System 1984”,\n" +
+ " Ellipsoid[“WGS 84”, 6378137.0, 298.257223563, LengthUnit[“metre”, 1]]],\n" +
+ " PrimeM[“Greenwich”, 0.0, AngleUnit[“degree”, 0.017453292519943295]]],\n" +
+ " DerivingConversion[“EPSG topocentric example B”,\n" +
+ " Method[“Geocentric/topocentric conversions”, Id[“EPSG”, 9836]],\n" +
+ " Parameter[“Geocentric X of topocentric origin”, 3771793.97, LengthUnit[“metre”, 1], Id[“EPSG”, 8837]],\n" +
+ " Parameter[“Geocentric Y of topocentric origin”, 140253.34, LengthUnit[“metre”, 1], Id[“EPSG”, 8838]],\n" +
+ " Parameter[“Geocentric Z of topocentric origin”, 5124304.35, LengthUnit[“metre”, 1], Id[“EPSG”, 8839]]],\n" +
+ " CS[Cartesian, 3],\n" +
+ " Axis[“Topocentric East (U)”, east],\n" +
+ " Axis[“Topocentric North (V)”, north],\n" +
+ " Axis[“Topocentric height (W)”, up],\n" +
+ " LengthUnit[“metre”, 1],\n" +
+ " Scope[“Example only - fictitious.”],\n" +
+ " Id[“EPSG”, 5820, “9.9.1”, URI[“urn:ogc:def:crs:EPSG:9.9.1:5820”]]]");
+
+ assertNameAndIdentifierEqual("EPSG topocentric example B", 5820, crs);
+ assertNameAndIdentifierEqual("EPSG topocentric example B", 0, crs.getConversionFromBase());
+ CoordinateSystem cs = crs.getCoordinateSystem();
+ assertInstanceOf("coordinateSystem", CartesianCS.class, cs);
+ assertEquals("dimension", 3, cs.getDimension());
+ assertUnboundedAxisEquals("Topocentric East", "U", AxisDirection.EAST, Units.METRE, cs.getAxis(0));
+ assertUnboundedAxisEquals("Topocentric North", "V", AxisDirection.NORTH, Units.METRE, cs.getAxis(1));
+ assertUnboundedAxisEquals("Topocentric height", "W", AxisDirection.UP, Units.METRE, cs.getAxis(2));
+ /*
+ * The type of the coordinate system of the base CRS is not specified in the WKT.
+ * The parser should use the `AbstractProvider.sourceCSType` field for detecting
+ * that the expected type for “Geocentric/topocentric conversions” is Cartesian.
+ */
+ cs = crs.getBaseCRS().getCoordinateSystem();
+ assertInstanceOf("coordinateSystem", CartesianCS.class, cs);
+ assertEquals("dimension", 3, cs.getDimension());
+ assertUnboundedAxisEquals(AxisNames.GEOCENTRIC_X, "X", AxisDirection.GEOCENTRIC_X, Units.METRE, cs.getAxis(0));
+ assertUnboundedAxisEquals(AxisNames.GEOCENTRIC_Y, "Y", AxisDirection.GEOCENTRIC_Y, Units.METRE, cs.getAxis(1));
+ assertUnboundedAxisEquals(AxisNames.GEOCENTRIC_Z, "Z", AxisDirection.GEOCENTRIC_Z, Units.METRE, cs.getAxis(2));
+ }
+
+ /**
* Tests the parsing of an engineering CRS from a WKT 2 string.
*
* @throws ParseException if the parsing failed.
@@ -989,6 +1036,7 @@
assertNameAndIdentifierEqual("A building-centred CRS", 0, crs);
assertNameAndIdentifierEqual("Building reference point", 0, crs.getDatum());
final CoordinateSystem cs = crs.getCoordinateSystem();
+ assertInstanceOf("coordinateSystem", CartesianCS.class, cs);
assertEquals("dimension", 3, cs.getDimension());
// Axis names are arbitrary and could change in future SIS versions.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/TransliteratorTest.java b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/TransliteratorTest.java
index c1f35d7..77e89b7 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/TransliteratorTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/TransliteratorTest.java
@@ -119,7 +119,7 @@
/**
* Asserts that the name of the given axis, after replacement by a short name,
- * is equals to the expected string.
+ * is equal to the expected string.
*/
private static void assertShortAxisNameEquals(final String expected, final CoordinateSystemAxisMock axis) {
assertEquals("name", expected, Transliterator.DEFAULT.toShortAxisName(axis,
@@ -128,7 +128,7 @@
/**
* Asserts that the abbreviation of the given axis, after replacement of Greek letters,
- * is equals to the expected string.
+ * is equal to the expected string.
*/
private static void assertAbbreviationEquals(final String expected, final CoordinateSystemAxisMock axis) {
assertEquals("abbreviation", expected, Transliterator.DEFAULT.toLatinAbbreviation(axis,
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorValuesTest.java b/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorValuesTest.java
index a47d554..f2fc84d 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorValuesTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorValuesTest.java
@@ -333,7 +333,7 @@
* Tests {@link TensorParameters#ALPHANUM} formatting.
* <ul>
* <li>Group name shall be {@code "Affine parametric transformation"}.</li>
- * <li>No {@code "num_row"} or {@code "num_col"} parameters if their value is equals to 3.</li>
+ * <li>No {@code "num_row"} or {@code "num_col"} parameters if their value is equal to 3.</li>
* <li>Parameter names shall be of the form {@code "A0"}.</li>
* <li>Identifiers present, but only for A0-A2 and B0-B2.</li>
* </ul>
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
index 02722f4..b48ee80 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
@@ -92,6 +92,8 @@
/**
* Tests {@link CRS#forCode(String)} with EPSG codes.
+ * The codes tested by this method shall be in the list of EPSG codes
+ * for which Apache SIS has hard-coded fallbacks to use if no EPSG database is available.
*
* @throws FactoryException if a CRS can not be constructed.
*
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java
index 57a37fa..2e7e9ec 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java
@@ -74,7 +74,7 @@
}
/**
- * Verifies that the given point is equals to the given latitude and longitude.
+ * Verifies that the given point is equal to the given latitude and longitude.
*
* @param φ the expected latitude value, in degrees.
* @param λ the expected longitude value, in degrees.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java
index 8863ecf..003ed81 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java
@@ -44,7 +44,7 @@
* Tests the {@link DefaultDerivedCRS} class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -87,13 +87,13 @@
assertEquals("Using consistent arguments but one less dimension.", WKTKeywords.GeodeticCRS,
DefaultDerivedCRS.getType(HardCodedCRS.GEOCENTRIC, HardCodedCS.CARTESIAN_2D));
- assertEquals("Using different coordinate system type.", WKTKeywords.EngineeringCRS,
+ assertEquals("Using different coordinate system type.", WKTKeywords.GeodeticCRS,
DefaultDerivedCRS.getType(HardCodedCRS.GEOCENTRIC, HardCodedCS.SPHERICAL));
- assertEquals("Using different coordinate system type.", WKTKeywords.EngineeringCRS,
+ assertEquals("Using different coordinate system type.", WKTKeywords.GeodeticCRS,
DefaultDerivedCRS.getType(HardCodedCRS.WGS84, HardCodedCS.CARTESIAN_2D));
- assertEquals("Using illegal coordinate system type.", WKTKeywords.EngineeringCRS,
+ assertNull("Using illegal coordinate system type.",
DefaultDerivedCRS.getType(HardCodedCRS.WGS84, HardCodedCS.GRAVITY_RELATED_HEIGHT));
}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java
index cc10dab..cc4dbc8 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java
@@ -132,7 +132,7 @@
}
/**
- * Asserts that the angle between the parsed directions is equals to the given value.
+ * Asserts that the angle between the parsed directions is equal to the given value.
* This method tests also the angle by interchanging the axis directions.
*/
private static void assertAngleEquals(final boolean isElevation, final double expected,
@@ -146,7 +146,7 @@
}
/**
- * Asserts that the angle between the given directions is equals to the given value.
+ * Asserts that the angle between the given directions is equal to the given value.
* This method tests also the angle by interchanging the given directions.
*/
private static void assertAngleEquals(final boolean isElevation, final double expected,
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java
index 83e29ba..3baf8bd 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java
@@ -89,7 +89,7 @@
finder.findSingleton(search));
finder.setSearchDomain(IdentifiedObjectFinder.Domain.VALID_DATASET);
- assertSame("A full scan should allow us to find WGS84, since it is equals ignoring metadata to CRS:84.",
+ assertSame("A full scan should allow us to find WGS84, since it is equal ignoring metadata to CRS:84.",
CRS84, finder.findSingleton(search));
}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
index 749ddb1..d1522ed 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
@@ -149,7 +149,7 @@
}
/**
- * Verifies that the SIS matrix is equals to the JAMA one, up to the given tolerance value.
+ * Verifies that the SIS matrix is equal to the JAMA one, up to the given tolerance value.
*
* @param expected the JAMA matrix used as a reference implementation.
* @param actual the SIS matrix to compare to JAMA.
@@ -177,7 +177,7 @@
}
/**
- * Asserts that the given matrix is equals to the given expected values, up to the given tolerance threshold.
+ * Asserts that the given matrix is equal to the given expected values, up to the given tolerance threshold.
* This method compares the elements values in two slightly redundant ways.
*/
static void assertEqualsElements(final double[] expected, final int numRow, final int numCol,
@@ -190,7 +190,7 @@
}
/**
- * Asserts that an element from the given matrix is equals to the expected value, using a relative threshold.
+ * Asserts that an element from the given matrix is equal to the expected value, using a relative threshold.
*/
private static void assertEqualsRelative(final String message, final double expected,
final MatrixSIS matrix, final int row, final int column)
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
index 46fb7d8..bd13467 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
@@ -153,7 +153,7 @@
}
/**
- * Transforms the given coordinates and verifies that the result is equals (within a positive delta)
+ * Transforms the given coordinates and verifies that the result is equal (within a positive delta)
* to the expected ones. If the difference between an expected and actual coordinate value is greater
* than the {@linkplain #tolerance tolerance} threshold, then the assertion fails.
*
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java
index c3608a5..17a1e32 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java
@@ -61,7 +61,7 @@
}
/**
- * Delegates to the tested implementation and verifies that the value is equals
+ * Delegates to the tested implementation and verifies that the value is equal
* to the one provided by the reference implementation.
*/
@Override
@@ -72,7 +72,7 @@
}
/**
- * Delegates to the tested implementation and verifies that the value is equals
+ * Delegates to the tested implementation and verifies that the value is equal
* to the one provided by the reference implementation.
*/
@Override
@@ -83,7 +83,7 @@
}
/**
- * Delegates to the tested implementation and verifies that the value is equals
+ * Delegates to the tested implementation and verifies that the value is equal
* to the one provided by the reference implementation.
*/
@Override
@@ -94,7 +94,7 @@
}
/**
- * Delegates to the tested implementation and verifies that the value is equals
+ * Delegates to the tested implementation and verifies that the value is equal
* to the one provided by the reference implementation.
*/
@Override
@@ -105,7 +105,7 @@
}
/**
- * Delegates to the tested implementation and verifies that the value is equals
+ * Delegates to the tested implementation and verifies that the value is equal
* to the one provided by the reference implementation.
*/
@Override
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java
index f8751f3..86404ec 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java
@@ -185,7 +185,7 @@
}
/**
- * Closes the last HTML tag if it is equals to the given element, and opens a new tag on the same line.
+ * Closes the last HTML tag if it is equal to the given element, and opens a new tag on the same line.
*
* @param tag the HTML tag without brackets (e.g. {@code "h2"}).
* @throws IOException if an error occurred while writing to the file.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java b/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
index 30d6d62..b8ed337 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
@@ -133,7 +133,7 @@
}
/**
- * Asserts that the tip of the unique alias of the given object is equals to the expected value.
+ * Asserts that the tip of the unique alias of the given object is equal to the expected value.
* As a special case if the expected value is null, then this method verifies that the given object has no alias.
*
* @param expected the expected alias, or {@code null} if we expect no alias.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
index cfe9e5a..94e1127 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
@@ -74,7 +74,7 @@
*/
private static final Set<String> EXCLUDES = new HashSet<>(Arrays.asList(
"CRS:1", // Computer display: WKT parser alters the (i,j) axis names.
- "EPSG:5819", // EPSG topocentric example A: error while parsing WKT.
+ "EPSG:5819", // EPSG topocentric example A: DerivedCRS wrongly handled as a ProjectedCRS. See SIS-518.
"AUTO2:42001", // This projection requires parameters, but we provide none.
"AUTO2:42002", // This projection requires parameters, but we provide none.
"AUTO2:42003", // This projection requires parameters, but we provide none.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
index f600d68..a9ca705 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
@@ -17,6 +17,11 @@
package org.apache.sis.test.integration;
import org.opengis.util.FactoryException;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.crs.DerivedCRS;
+import org.opengis.referencing.crs.GeodeticCRS;
+import org.opengis.referencing.crs.GeneralDerivedCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.referencing.CRS;
import org.apache.sis.referencing.factory.TestFactorySource;
@@ -24,15 +29,15 @@
import org.apache.sis.test.TestCase;
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.opengis.test.Assert.*;
import static org.junit.Assume.assumeNotNull;
/**
- * Advances CRS constructions requiring the EPSG geodetic dataset.
+ * Advanced CRS constructions requiring the EPSG geodetic dataset.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -55,4 +60,31 @@
CoordinateReferenceSystem crs = CRS.forCode("urn:ogc:def:crs, crs:EPSG::27700, crs:EPSG::5701");
assertSame("OSGB 1936 / British National Grid + ODN height", CRS.forCode("EPSG:7405"), crs);
}
+
+ /**
+ * Tests creation of "EPSG topocentric example A/B". They are derived geodetic CRS.
+ *
+ * @throws FactoryException if an authority or a code is not recognized.
+ */
+ @Test
+ public void testDerivedCRS() throws FactoryException {
+ assumeNotNull(TestFactorySource.getSharedFactory());
+ CoordinateReferenceSystem crs = CRS.forCode("EPSG:5820");
+ assertInstanceOf("Derived CRS type", DerivedCRS .class, crs);
+ assertInstanceOf("Derived CRS type", GeodeticCRS.class, crs);
+ assertInstanceOf("CS of derived CRS", CartesianCS.class, crs.getCoordinateSystem());
+ assertInstanceOf("CS of base CRS", CartesianCS.class, ((GeneralDerivedCRS) crs).getBaseCRS().getCoordinateSystem());
+ /*
+ * Some tests are disabled because `EPSGDataAccess` confuse this derived CRS
+ * with a projected CRS. We are waiting for upgrade to EPSG database 10+
+ * before to re-evaluate how to fix this issue.
+ *
+ * https://issues.apache.org/jira/browse/SIS-518
+ */
+ crs = CRS.forCode("EPSG:5819");
+// assertInstanceOf("Derived CRS type", DerivedCRS .class, crs);
+// assertInstanceOf("Derived CRS type", GeodeticCRS.class, crs);
+ assertInstanceOf("CS of derived CRS", CartesianCS.class, crs.getCoordinateSystem());
+ assertInstanceOf("CS of base CRS", EllipsoidalCS.class, ((GeneralDerivedCRS) crs).getBaseCRS().getCoordinateSystem());
+ }
}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java
index c6b7788..53f6cdc 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java
@@ -23,7 +23,7 @@
* environment variable.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.4
* @module
*/
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/widget/SwingAssertions.java b/core/sis-referencing/src/test/java/org/apache/sis/test/widget/SwingAssertions.java
index afbf9b4..ed2aee7 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/widget/SwingAssertions.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/widget/SwingAssertions.java
@@ -38,7 +38,7 @@
}
/**
- * Ensures that a tree is equals to an other tree.
+ * Ensures that a tree is equal to an other tree.
* This method invokes itself recursively for every child nodes.
*
* @param expected the expected tree, or {@code null}.
diff --git a/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod b/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
index b6d93bb..2fcd0f5 100644
--- a/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
+++ b/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
@@ -1,4 +1,3 @@
# Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements;
# and to You under the Apache License, Version 2.0.
-org.apache.sis.internal.referencing.provider.TopocentricConversionMock
org.apache.sis.internal.referencing.provider.SeismicBinGridMock
diff --git a/core/sis-referencing/src/test/resources/org/apache/sis/referencing/crs/DerivedCRS.xml b/core/sis-referencing/src/test/resources/org/apache/sis/referencing/crs/DerivedCRS.xml
index 8e72f0f..5b76845 100644
--- a/core/sis-referencing/src/test/resources/org/apache/sis/referencing/crs/DerivedCRS.xml
+++ b/core/sis-referencing/src/test/resources/org/apache/sis/referencing/crs/DerivedCRS.xml
@@ -147,7 +147,7 @@
<gml:derivedCRSType> is specific to <gml:DerivedCRS> and is not stored explicitly in Apache SIS
implementation. Instead, we infer this value from the interface implemented by DefaultDerivedCRS.
-->
- <gml:derivedCRSType codeSpace="EPSG">engineering</gml:derivedCRSType>
+ <gml:derivedCRSType codeSpace="EPSG">geodetic</gml:derivedCRSType>
<gml:coordinateSystem>
<gml:CartesianCS gml:id="test-cs-derivedcs">
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java b/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java
index eb25d93..2d1a07e 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java
@@ -151,7 +151,7 @@
}
/**
- * If {@code existing} or one of its children is equals to the given {@code converter},
+ * If {@code existing} or one of its children is equal to the given {@code converter},
* returns it. Otherwise returns {@code null}.
*
* @param <S> the {@code converter} source class.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DefinitionURI.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DefinitionURI.java
index 2e86876..615fdf8 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DefinitionURI.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DefinitionURI.java
@@ -33,7 +33,6 @@
*
* <p>For example, all the following URIs are for the same object:</p>
* <ul>
- * <li>{@code "4326"} (codespace inferred by the caller)</li>
* <li>{@code "EPSG:4326"} (older format)</li>
* <li>{@code "EPSG::4326"} (often seen for similarity with URN below)</li>
* <li>{@code "urn:ogc:def:crs:EPSG::4326"} (version number is omitted)</li>
@@ -106,7 +105,7 @@
* {@code "urn:ogc:def:crs,crs:EPSG:6.3:27700,crs:EPSG:6.3:5701"}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
*
* @see org.apache.sis.internal.metadata.NameMeaning
* @see <a href="https://portal.ogc.org/files/?artifact_id=24045">Definition identifier URNs in OGC namespace</a>
@@ -122,7 +121,7 @@
public static final String PREFIX = "urn:ogc:def";
/**
- * The URN separator.
+ * The path separator in URN.
*/
public static final char SEPARATOR = ':';
@@ -403,7 +402,7 @@
do {
/*
* Find indices of URI sub-component to parse. The sub-component will
- * go from 'splitAt' to 'next' exclusive ('splitAt' is exclusive too).
+ * go from `splitAt` to `next` exclusive (`splitAt` is exclusive too).
*/
int next = uri.indexOf(componentSeparator, splitAt+1);
hasMore = next >= 0 && next < componentsEnd;
@@ -468,7 +467,7 @@
* @param upper index after the last character in {@code urn} to compare, ignoring whitespaces.
* @return {@code true} if the given sub-region of {@code urn} match the given part.
*/
- static boolean regionMatches(final String part, final String urn, int lower, int upper) {
+ public static boolean regionMatches(final String part, final String urn, int lower, int upper) {
lower = skipLeadingWhitespaces (urn, lower, upper);
upper = skipTrailingWhitespaces(urn, lower, upper);
final int length = upper - lower;
@@ -493,39 +492,8 @@
}
/**
- * Returns the substring of the given URN, ignoring whitespaces and version number if present.
- * The substring is expected to contains at most one {@code ':'} character. If such separator
- * character is present, then that character and everything before it are ignored. The ignored
- * part should be the version number, but this is not verified.
- *
- * <p>If the remaining substring is empty or contains more {@code ':'} characters, then this method
- * returns {@code null}. The presence of more {@code ':'} characters means that the code has parameters,
- * (e.g. {@code "urn:ogc:def:crs:OGC:1.3:AUTO42003:1:-100:45"}) which are not handled by this method.</p>
- *
- * @param urn the URN from which to get the code.
- * @param fromIndex index of the first character in {@code urn} to check.
- * @return the code part of the URN, or {@code null} if empty or invalid.
- */
- private static String codeIgnoreVersion(final String urn, int fromIndex) {
- final int length = urn.length();
- fromIndex = skipLeadingWhitespaces(urn, fromIndex, length);
- if (fromIndex >= length) {
- return null; // Empty code.
- }
- final int s = urn.indexOf(SEPARATOR, fromIndex);
- if (s >= 0) {
- // Ignore the version number (actually everything up to the first ':').
- fromIndex = skipLeadingWhitespaces(urn, s+1, length);
- if (fromIndex >= length || urn.indexOf(SEPARATOR, fromIndex) >= 0) {
- return null; // Empty code, or the code is followed by parameters.
- }
- }
- return urn.substring(fromIndex, skipTrailingWhitespaces(urn, fromIndex, length));
- }
-
- /**
* Returns the code part of the given URI, provided that it matches the given object type and authority.
- * This lightweight method is useful when:
+ * This method is useful when:
*
* <ul>
* <li>the URI is expected to have a specific <cite>object type</cite> and <cite>authority</cite>;</li>
@@ -536,77 +504,63 @@
* This method accepts the following URI representations:
*
* <ul>
- * <li>Code alone, without any {@code ':'} character (e.g. {@code "4326"}).</li>
* <li>The given authority followed by the code (e.g. {@code "EPSG:4326"}).</li>
* <li>The URN form (e.g. {@code "urn:ogc:def:crs:EPSG::4326"}), ignoring version number.
* This method accepts also the former {@code "x-ogc"} in place of {@code "ogc"}.</li>
- * <li>The HTTP form (e.g. {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}).</li>
+ * <li>The HTTP form (e.g. {@code "http://www.opengis.net/def/crs/EPSG/0/4326"}).</li>
+ * <li>The GML form (e.g. {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}).</li>
* </ul>
*
* @param type the expected object type (e.g. {@code "crs"}) in lower cases. See class javadoc for a list of types.
- * @param authority the expected authority, typically {@code "epsg"}. See class javadoc for a list of authorities.
+ * @param authority the expected authority, typically {@code "EPSG"}. See class javadoc for a list of authorities.
* @param uri the URI to parse.
* @return the code part of the given URI, or {@code null} if the codespace does not match the given type
* and authority, the code is empty, or the code is followed by parameters.
*/
- public static String codeOf(final String type, final String authority, final String uri) {
+ public static String codeOf(final String type, final String authority, final CharSequence uri) {
ensureNonNull("type", type);
ensureNonNull("authority", authority);
- ensureNonNull("uri", uri);
- /*
- * Get the part before the first ':' character. If none, assume that the given URI is already the code.
- * Otherwise the part may be either "http" or "urn" protocol, or the given authority (typically "EPSG").
- * In the latter case, we return immediately the code after the authority part.
- */
- int upper = uri.indexOf(SEPARATOR);
- if (upper < 0) {
- return trimWhitespaces(uri);
- }
- int lower = skipLeadingWhitespaces(uri, 0, upper);
- int length = skipTrailingWhitespaces(uri, lower, upper) - lower;
- if (length == authority.length() && uri.regionMatches(true, lower, authority, 0, length)) {
- return codeIgnoreVersion(uri, upper+1);
- }
- /*
- * Check for supported protocols: only "urn" and "http" at this time.
- * All other protocols are rejected as unrecognized.
- */
- String part;
- switch (length) {
- case 3: part = "urn"; break;
- case 4: part = "http"; break;
- default: return null;
- }
- if (!uri.regionMatches(true, lower, part, 0, length)) {
- return null;
- }
- if (length == 4) {
- return codeForGML(type, authority, uri, upper+1, null);
- }
- /*
- * At this point we have determined that the protocol is URN. The next parts after "urn"
- * shall be "ogc" or "x-ogc", then "def", then the type and authority given in arguments.
- */
- for (int p=0; p!=4; p++) {
- lower = upper + 1;
- upper = uri.indexOf(SEPARATOR, lower);
- if (upper < 0) {
- return null; // No more parts.
+ final int length = uri.length();
+ int s = indexOf(uri, SEPARATOR, 0, length);
+ if (s >= 0) {
+ int from = skipLeadingWhitespaces(uri, 0, s); // Start of authority part.
+ if (skipTrailingWhitespaces(uri, from, s) - from == authority.length()
+ && CharSequences.regionMatches(uri, from, authority, true))
+ {
+ from = skipLeadingWhitespaces(uri, s+1, length); // Start of code part.
+ if (from >= length) {
+ return null;
+ }
+ /*
+ * The substring is expected to contains zero or one more separator character.
+ * If present, then the separator character and everything before it are ignored.
+ * The ignored part should be the version number, but this is not verified.
+ */
+ s = indexOf(uri, SEPARATOR, from, length);
+ if (s >= 0) {
+ from = skipLeadingWhitespaces(uri, s+1, length);
+ if (from >= length || indexOf(uri, SEPARATOR, from, length) >= 0) {
+ /*
+ * If the remaining substring contains more ':' characters, then it means that
+ * the code has parameters, e.g. "urn:ogc:def:crs:OGC:1.3:AUTO42003:1:-100:45".
+ */
+ return null;
+ }
+ }
+ return uri.subSequence(from, skipTrailingWhitespaces(uri, from, length)).toString();
}
- switch (p) {
- // "ogc" is tested before "x-ogc" because more common.
- case 0: if (regionMatches("ogc", uri, lower, upper)) continue;
- part = "x-ogc"; break; // Fallback if the part is not "ogc".
- case 1: part = "def"; break;
- case 2: part = type; break;
- case 3: part = authority; break;
- default: throw new AssertionError(p);
- }
- if (!regionMatches(part, uri, lower, upper)) {
- return null;
+ final DefinitionURI def = parse(uri.toString());
+ if (def != null && def.parameters == null) {
+ if (type.equalsIgnoreCase(def.type) && authority.equalsIgnoreCase(def.authority)) {
+ String code = def.code;
+ if (code == null) {
+ code = def.version; // May happen with for example "EPSG:4326" instead of "EPSG::4326".
+ }
+ return code;
+ }
}
}
- return codeIgnoreVersion(uri, upper+1);
+ return null;
}
/**
@@ -632,13 +586,13 @@
return null;
}
// TODO: For now do nothing since PATHS is a singleton. However if a future SIS version
- // defines more PATHS entries, then we should replace here the 'paths' reference by
+ // defines more PATHS entries, then we should replace here the `paths` reference by
// a new Collections.singletonMap containing only the entry of interest.
}
for (final Map.Entry<String,String> entry : paths.entrySet()) {
final String path = entry.getValue();
if (url.regionMatches(true, lower, path, 0, path.length())) {
- lower = CharSequences.skipLeadingWhitespaces(url, lower + path.length(), url.length());
+ lower = skipLeadingWhitespaces(url, lower + path.length(), url.length());
if (authority == null) {
authority = url.substring(lower, skipIdentifierPart(url, lower));
} else if (!url.regionMatches(true, lower, authority, 0, authority.length())) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
index 792ecb4..4b483d6 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
@@ -88,7 +88,7 @@
/**
* When computing <var>a</var> - <var>b</var> as a double-double (106 significand bits) value,
- * if the amount of non-zero significand bits is equals or lower than {@code ZERO_THRESHOLD+1},
+ * if the amount of non-zero significand bits is equal or lower than {@code ZERO_THRESHOLD+1},
* consider the result as zero.
*/
private static final int ZERO_THRESHOLD = 2;
@@ -382,9 +382,9 @@
}
/**
- * Returns {@code true} if this {@code DoubleDouble} is equals to zero.
+ * Returns {@code true} if this {@code DoubleDouble} is equal to zero.
*
- * @return {@code true} if this {@code DoubleDouble} is equals to zero.
+ * @return {@code true} if this {@code DoubleDouble} is equal to zero.
*/
public boolean isZero() {
return value == 0 && error == 0;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/SetOfUnknownSize.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/SetOfUnknownSize.java
index be3fcda..620ef2b 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/SetOfUnknownSize.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/SetOfUnknownSize.java
@@ -68,8 +68,8 @@
/**
* Returns the number of elements in this set. The default implementation counts the number of elements
- * returned by the {@link #iterator() iterator}. Subclasses are encouraged to cache this value if they
- * know that the underlying storage is immutable.
+ * returned by the {@linkplain #iterator() iterator}. Subclasses are encouraged to cache this value
+ * if they know that the underlying storage is immutable.
*
* @return the number of elements in this set.
*/
@@ -181,7 +181,7 @@
* iterate over the elements of this Set. The reason is that this Set may compute the values dynamically and
* it is sometime difficult to ensure that this Set's iterator is fully consistent with the values recognized
* by the contains(Object) method. For example the iterator may return "EPSG:4326" while the contains(Object)
- * method may accept both "EPSG:4326" and "EPSG:4326". For this equals(Object) method, we consider the
+ * method may accept both "EPSG:4326" and "EPSG:4326". For this equal(Object) method, we consider the
* contains(Object) method of the other Set as more reliable.
*/
if (object == this) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java
deleted file mode 100644
index 01544a8..0000000
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.internal.util;
-
-import java.util.List;
-import java.util.ArrayList;
-import org.apache.sis.util.Static;
-import org.apache.sis.util.resources.Errors;
-
-import static org.apache.sis.util.CharSequences.*;
-import static org.apache.sis.internal.util.DefinitionURI.regionMatches;
-
-
-/**
- * Utility methods related to x-paths. This is intended to be only a lightweight support;
- * this is not a replacement for {@link javax.xml.xpath} implementations. This is used as
- * a place where to centralize XPath handling for possible replacement by a more advanced
- * framework in the future.
- *
- * @author Martin Desruisseaux (Geomatys)
- * @version 1.2
- * @since 0.4
- * @module
- */
-public final class XPaths extends Static {
- /**
- * The separator between path components.
- */
- public static final char SEPARATOR = '/';
-
- /**
- * Do not allow instantiation of this class.
- */
- private XPaths() {
- }
-
- /**
- * If the given character sequences seems to be a URI, returns the presumed end of that URN.
- * Otherwise returns -1.
- * Examples:
- * <ul>
- * <li>{@code "urn:ogc:def:uom:EPSG::9001"}</li>
- * <li>{@code "http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"}</li>
- * </ul>
- *
- * @param uri the URI candidate to verify.
- * @param offset index of the first character to verify.
- * @return index after the last character of the presumed URI, or -1 if this
- * method thinks that the given character sequence is not a URI.
- */
- public static int endOfURI(final CharSequence uri, int offset) {
- boolean isURI = false;
- int parenthesis = 0;
- final int length = uri.length();
-scan: while (offset < length) {
- final int c = Character.codePointAt(uri, offset);
- if (!Character.isLetterOrDigit(c)) {
- switch (c) {
- case '#': // Anchor in URL, presumed followed by xpointer.
- case ':': isURI |= (parenthesis == 0); break; // Scheme or URN separator.
- case '_':
- case '-': // Valid character in URL.
- case '%': // Encoded character in URL.
- case '.': // Domain name separator in URL.
- case SEPARATOR: break; // Path separator, but could also be division as in "m/s".
- case '(': parenthesis++; break;
- case ')': parenthesis--; break;
- default: {
- if (Character.isSpaceChar(c)) break; // Not supposed to be valid, but be lenient.
- if (parenthesis != 0) break;
- break scan; // Non-valid character outside parenthesis.
- }
- }
- }
- offset += Character.charCount(c);
- }
- return isURI ? offset : -1;
- }
-
- /**
- * Splits the given URL around the {@code '/'} separator, or returns {@code null} if there is no separator.
- * By convention if the URL is absolute, then the leading {@code '/'} character is kept in the first element.
- * For example {@code "/∗/property"} is splitted as two elements: {@code "/∗"} and {@code "property"}.
- *
- * <p>This method trims the whitespaces of components except the last one (the tip),
- * for consistency with the case where this method returns {@code null}.</p>
- *
- * @param xpath the URL to split.
- * @return the splitted URL with the heading separator kept in the first element, or {@code null}
- * if there is no separator. If non-null, the list always contains at least one element.
- * @throws IllegalArgumentException if the XPath contains at least one empty component.
- */
- public static List<String> split(final String xpath) {
- int next = xpath.indexOf(SEPARATOR);
- if (next < 0) {
- return null;
- }
- final List<String> components = new ArrayList<>(4);
- int start = skipLeadingWhitespaces(xpath, 0, next);
- if (start < next) {
- // No leading '/' (the characters before it are a path element, added below).
- components.add(xpath.substring(start, skipTrailingWhitespaces(xpath, start, next)));
- start = ++next;
- } else {
- // Keep the `start` position on the leading '/'.
- next++;
- }
- while ((next = xpath.indexOf(SEPARATOR, next)) >= 0) {
- components.add(trimWhitespaces(xpath, start, next).toString());
- start = ++next;
- }
- components.add(xpath.substring(start)); // No whitespace trimming.
- if (components.stream().anyMatch(String::isEmpty)) {
- throw new IllegalArgumentException(Errors.format(Errors.Keys.UnsupportedXPath_1, xpath));
- }
- return components;
- }
-
- /**
- * Parses a URL which contains a pointer to a XML fragment.
- * The current implementation recognizes the following types:
- *
- * <ul>
- * <li>{@code uom} for Unit Of Measurement (example:
- * {@code "http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"})</li>
- * </ul>
- *
- * @param type the object type.
- * @param url the URL to parse.
- * @return the reference, or {@code null} if none.
- */
- public static String xpointer(final String type, final String url) {
- if (type.equals("uom")) {
- final int f = url.indexOf('#');
- if (f >= 1) {
- /*
- * For now we accept any path as long as it ends with the "gmxUom.xml" file
- * because resources may be hosted on different servers, or the path may be
- * relative instead of absolute.
- */
- int i = url.lastIndexOf('/', f-1) + 1;
- if (regionMatches("gmxUom.xml", url, i, f) || regionMatches("ML_gmxUom.xml", url, i, f)) {
- /*
- * The fragment should typically be of the form "xpointer(//*[@gml:id='m'])".
- * However sometime we found no "xpointer", but directly the unit instead.
- */
- i = url.indexOf('(', f+1);
- if (i >= 0 && regionMatches("xpointer", url, f+1, i)) {
- i = url.indexOf("@gml:id=", i+1);
- if (i >= 0) {
- i = skipLeadingWhitespaces(url, i+8, url.length()); // 8 is the length of "@gml:id="
- final int c = url.charAt(i);
- if (c == '\'' || c == '"') {
- final int s = url.indexOf(c, ++i);
- if (s >= 0) {
- return trimWhitespaces(url, i, s).toString();
- }
- }
- }
- } else {
- return trimWhitespaces(url, f+1, url.length()).toString();
- }
- }
- }
- }
- return null;
- }
-}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java b/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java
index 1b5c65a..c2b108f 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java
@@ -275,7 +275,7 @@
return true;
}
- /** Returns whether this vector in the given range is equals to the specified vector. */
+ /** Returns whether this vector in the given range is equal to the specified vector. */
@Override boolean equals(final int lower, final int upper, final Vector other, final int otherOffset) {
if (other instanceof Doubles) {
return JDK9.equals(array, lower, upper,
@@ -395,7 +395,7 @@
return true;
}
- /** Returns whether this vector in the given range is equals to the specified vector. */
+ /** Returns whether this vector in the given range is equal to the specified vector. */
@Override final boolean equals(final int lower, final int upper, final Vector other, final int otherOffset) {
if (other.getClass() == getClass()) {
return JDK9.equals(array, lower, upper,
@@ -555,7 +555,7 @@
return index;
}
- /** Returns whether this vector in the given range is equals to the specified vector. */
+ /** Returns whether this vector in the given range is equal to the specified vector. */
@Override final boolean equals(final int lower, final int upper, final Vector other, final int otherOffset) {
if (other.getClass() == getClass()) {
return JDK9.equals(array, lower, upper,
@@ -685,7 +685,7 @@
return index;
}
- /** Returns whether this vector in the given range is equals to the specified vector. */
+ /** Returns whether this vector in the given range is equal to the specified vector. */
@Override final boolean equals(final int lower, final int upper, final Vector other, final int otherOffset) {
if (other.getClass() == getClass()) {
return JDK9.equals(array, lower, upper,
@@ -819,7 +819,7 @@
return index;
}
- /** Returns whether this vector in the given range is equals to the specified vector. */
+ /** Returns whether this vector in the given range is equal to the specified vector. */
@Override final boolean equals(final int lower, final int upper, final Vector other, final int otherOffset) {
if (other.getClass() == getClass()) {
return JDK9.equals(array, lower, upper,
@@ -928,7 +928,7 @@
return index;
}
- /** Returns whether this vector in the given range is equals to the specified vector. */
+ /** Returns whether this vector in the given range is equal to the specified vector. */
@Override final boolean equals(int lower, final int upper, final Vector other, int otherOffset) {
if (other.getClass() == getClass()) {
return JDK9.equals(array, lower, upper,
diff --git a/core/sis-utility/src/main/java/org/apache/sis/math/Fraction.java b/core/sis-utility/src/main/java/org/apache/sis/math/Fraction.java
index 6e59a67..c3479f3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/math/Fraction.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/math/Fraction.java
@@ -92,7 +92,7 @@
* will be smaller depending on the {@linkplain #denominator} required for representing that value.
*
* @param value the double-precision value to convert to a fraction.
- * @return a fraction such as {@link #doubleValue()} is equals to the given value.
+ * @return a fraction such as {@link #doubleValue()} is equal to the given value.
* @throws IllegalArgumentException if the given value can not be converted to a fraction.
*
* @since 1.0
@@ -210,7 +210,7 @@
/**
* Returns a fraction equivalent to {@code num} / {@code den} after simplification.
- * If the simplified fraction is equals to {@code this}, then this method returns {@code this}.
+ * If the simplified fraction is equal to {@code this}, then this method returns {@code this}.
*
* <p>The arguments given to this method are the results of multiplications and additions of {@code int} values.
* This method fails if any argument value is {@link Long#MIN_VALUE} because that value can not be made positive.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java b/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
index 223eb73..46d5ad7 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
@@ -212,7 +212,7 @@
* the value is negative.
*
* @param value the value to truncate.
- * @return the largest in magnitude (further from zero) integer value which is equals
+ * @return the largest in magnitude (further from zero) integer value which is equal
* or less in magnitude than the given value.
*/
public static double truncate(final double value) {
@@ -385,8 +385,8 @@
*
* Special cases:
* <ul>
- * <li>If <var>x</var> is equals or lower than -324, then the result is 0.</li>
- * <li>If <var>x</var> is equals or greater than 309, then the result is {@linkplain Double#POSITIVE_INFINITY positive infinity}.</li>
+ * <li>If <var>x</var> is equal or lower than -324, then the result is 0.</li>
+ * <li>If <var>x</var> is equal or greater than 309, then the result is {@linkplain Double#POSITIVE_INFINITY positive infinity}.</li>
* <li>If <var>x</var> is in the [0 … 18] range inclusive, then the result is exact.</li>
* <li>For all other <var>x</var> values, the result is the closest IEEE 754 approximation.</li>
* </ul>
diff --git a/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java b/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java
index 31556b5..2270ece 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java
@@ -1663,7 +1663,7 @@
}
/**
- * Returns {@code true} if this vector in the given range is equals to the specified vector.
+ * Returns {@code true} if this vector in the given range is equal to the specified vector.
* NaN values are considered equal to all other NaN values, and -0.0 is different than +0.0.
*
* @param lower index of the first value to compare in this vector, inclusive.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java b/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
index 47bb1b6..18e0436 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
@@ -361,7 +361,7 @@
/**
* Returns the result of setting the origin of the scale of measurement to the given value.
- * For example {@code CELSIUS = KELVIN.shift(273.15)} returns a unit where 0°C is equals to 273.15 K.
+ * For example {@code CELSIUS = KELVIN.shift(273.15)} returns a unit where 0°C is equal to 273.15 K.
*
* @param offset the value to add when converting from the new unit to this unit.
* @return this unit offset by the specified value, or {@code this} if the given offset is zero.
@@ -385,7 +385,7 @@
/**
* Returns the result of multiplying this unit by the specified factor.
- * For example {@code KILOMETRE = METRE.multiply(1000)} returns a unit where 1 km is equals to 1000 m.
+ * For example {@code KILOMETRE = METRE.multiply(1000)} returns a unit where 1 km is equal to 1000 m.
*
* @param multiplier the scale factor when converting from the new unit to this unit.
* @return this unit scaled by the specified multiplier.
@@ -413,7 +413,7 @@
/**
* Returns the result of dividing this unit by an approximate divisor.
- * For example {@code GRAM = KILOGRAM.divide(1000)} returns a unit where 1 g is equals to 0.001 kg.
+ * For example {@code GRAM = KILOGRAM.divide(1000)} returns a unit where 1 g is equal to 0.001 kg.
*
* @param divisor the inverse of the scale factor when converting from the new unit to this unit.
* @return this unit divided by the specified divisor.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java b/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java
index 3c47d62..f798ca6 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java
@@ -42,7 +42,7 @@
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -218,25 +218,23 @@
Number v2 = u2.getConverterTo(s2).convert(q2.getValue());
if (Numbers.isNaN(v2)) return q1;
if (Numbers.isNaN(v1)) return q2;
- /*
- * If the two types are instances of `Scalar`, we can compare them directly. Otherwise convert the
- * `Scalar` type (if any) to `Double` type, then convert again to the widest type of both values.
- */
- final boolean t1 = (v1 instanceof Scalar);
- final boolean t2 = (v2 instanceof Scalar);
- if (!(t1 & t2)) {
- if (t1) v1 = v1.doubleValue();
- if (t2) v2 = v2.doubleValue();
- final Class<? extends Number> type = Numbers.widestClass(v1, v2);
- v1 = Numbers.cast(v1, type);
- v2 = Numbers.cast(v2, type);
- }
- /*
- * Both v1 and v2 are instance of `Comparable<?>` because `Numbers.widestClass(…)`
- * accepts only known number types such as `Integer`, `Float`, `BigDecimal`, etc.
- */
- @SuppressWarnings("unchecked")
- final int c = ((Comparable) v1).compareTo((Comparable) v2);
+ final int c = compare(v1, v2);
return (max ? c >= 0 : c <= 0) ? q1 : q2;
}
+
+ /**
+ * Compares the two given number, without casting to {@code double} if we can avoid that cast.
+ * The intent is to avoid loosing precision for example by casting a {@code BigDecimal}.
+ */
+ @SuppressWarnings("unchecked")
+ private static int compare(final Number v1, final Number v2) {
+ if (v1 instanceof Comparable<?>) {
+ if (v1.getClass().isInstance(v2)) {
+ return ((Comparable) v1).compareTo(v2);
+ } else if (v2 instanceof Comparable<?> && v2.getClass().isInstance(v1)) {
+ return -((Comparable) v2).compareTo(v1);
+ }
+ }
+ return Double.compare(v1.doubleValue(), v2.doubleValue());
+ }
}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java b/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java
index 9060ccf..8471563 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java
@@ -23,7 +23,13 @@
import java.text.ParsePosition;
import javax.measure.Quantity;
import javax.measure.Unit;
+import javax.measure.format.ParserException;
+import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.internal.util.FinalFieldSetter;
+
+import static java.util.logging.Logger.getLogger;
/**
@@ -86,7 +92,7 @@
/**
* Formats the specified quantity in the given buffer.
- * The given object shall be an {@link Quantity} instance.
+ * The given object shall be a {@link Quantity} instance.
*
* @param quantity the quantity to format.
* @param toAppendTo where to format the quantity.
@@ -107,16 +113,22 @@
*
* @param source the text, part of which should be parsed.
* @param pos index and error index information.
- * @return a unit parsed from the string, or {@code null} in case of error.
+ * @return a quantity parsed from the string, or {@code null} in case of error.
*/
@Override
public Object parseObject(final String source, final ParsePosition pos) {
+ final int start = pos.getIndex();
final Number value = numberFormat.parse(source, pos);
if (value != null) {
- final Unit<?> unit = unitFormat.parse(source, pos);
- if (unit != null) {
- return Quantities.create(value.doubleValue(), unit);
+ try {
+ final Unit<?> unit = unitFormat.parse(source, pos);
+ if (unit != null) {
+ return Quantities.create(value.doubleValue(), unit);
+ }
+ } catch (ParserException e) {
+ Logging.ignorableException(getLogger(Loggers.MEASURE), QuantityFormat.class, "parseObject", e);
}
+ pos.setIndex(start); // By `Format.parseObject(…)` method contract.
}
return null;
}
@@ -130,16 +142,10 @@
public QuantityFormat clone() {
final QuantityFormat clone = (QuantityFormat) super.clone();
try {
- java.lang.reflect.Field field;
- field = QuantityFormat.class.getField("numberFormat");
- field.setAccessible(true);
- field.set(clone, numberFormat.clone());
-
- field = QuantityFormat.class.getField("unitFormat");
- field.setAccessible(true);
- field.set(clone, unitFormat.clone());
+ FinalFieldSetter.set(QuantityFormat.class, "numberFormat", "unitFormat",
+ clone, numberFormat.clone(), unitFormat.clone());
} catch (ReflectiveOperationException e) {
- throw new AssertionError(e);
+ throw FinalFieldSetter.cloneFailure(e);
}
return clone;
}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java b/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java
index 63dd667..03128ca 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java
@@ -664,7 +664,7 @@
*
* <ul>
* <li>If the range {@linkplain #isEmpty() is empty}, then this method returns "{@code {}}".</li>
- * <li>Otherwise if the minimal value is equals to the maximal value, then the string
+ * <li>Otherwise if the minimal value is equal to the maximal value, then the string
* representation of that value is returned inside braces as in "{@code {value}}".</li>
* <li>Otherwise the string representation of the minimal and maximal values are formatted
* like "{@code [min … max]}" for inclusive endpoints or "{@code (min … max)}" for exclusive
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java b/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
index 3e35eac..a6c4337 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
@@ -55,7 +55,7 @@
*
* <ul>
* <li>If the range {@linkplain Range#isEmpty() is empty}, then the range is represented by "{@code {}}".</li>
- * <li>Otherwise if the {@linkplain Range#getMinValue() minimal value} is equals to the
+ * <li>Otherwise if the {@linkplain Range#getMinValue() minimal value} is equal to the
* {@linkplain Range#getMaxValue() maximal value}, then that single value is formatted
* inside braces as in "{@code {value}}".</li>
* <li>Otherwise the minimal and maximal values are formatted inside bracket or parenthesis,
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java b/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
index bb87fd2..0e91221 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
@@ -20,7 +20,6 @@
import javax.measure.quantity.Angle;
import javax.measure.UnitConverter;
import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.internal.util.Numerics;
import org.apache.sis.math.MathFunctions;
@@ -40,7 +39,7 @@
* This class and all inner classes are immutable, and thus inherently thread-safe.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.2
* @since 0.3
* @module
*/
@@ -280,7 +279,7 @@
if (min >= 0) deg++; else deg--;
min = 0;
} else {
- throw illegalField(angle, min, Vocabulary.Keys.AngularMinutes);
+ throw illegalField(angle, min, 0);
}
}
if (sec <= -60 || sec >= 60) { // Do not enter for NaN
@@ -288,7 +287,7 @@
if (sec >= 0) min++; else min--;
sec = 0;
} else {
- throw illegalField(angle, sec, Vocabulary.Keys.AngularSeconds);
+ throw illegalField(angle, sec, 1);
}
}
return (sec/60 + min)/60 + deg;
@@ -299,12 +298,11 @@
*
* @param value the user-supplied angle value.
* @param field the value of the illegal field.
- * @param unit the vocabulary key for the field (minutes or seconds).
+ * @param unit 0 for minutes or 1 for seconds.
* @return the exception to throw.
*/
- private static IllegalArgumentException illegalField(final double value, final double field, final short unit) {
- return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentField_4,
- "angle", value, Vocabulary.format(unit), field));
+ private static IllegalArgumentException illegalField(final double value, final double field, final int unit) {
+ return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalSexagesimalField_3, value, unit, field));
}
}
}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java b/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
index d4ddc59..0fdaec9 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
@@ -320,7 +320,7 @@
}
/**
- * Returns {@code true} if this unit is equals to the given unit ignoring name, symbol and EPSG code.
+ * Returns {@code true} if this unit is equal to the given unit ignoring name, symbol and EPSG code.
* This method should always returns {@code true} if parameterized type has not been compromised with
* raw types or unchecked casts.
*
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
index d5df26e..c9a3020 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
@@ -37,8 +37,6 @@
import org.apache.sis.internal.util.Constants;
import org.apache.sis.internal.util.DefinitionURI;
import org.apache.sis.internal.util.FinalFieldSetter;
-import org.apache.sis.internal.util.XPointer;
-import org.apache.sis.internal.util.XPaths;
import org.apache.sis.math.Fraction;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.math.MathFunctions;
@@ -60,23 +58,22 @@
* some symbols found in <cite>Well Known Text</cite> (WKT) definitions or in XML files.
*
* <h2>Parsing authority codes</h2>
- * As a special case, if a character sequence given to the {@link #parse(CharSequence)} method is of the
- * {@code "EPSG:####"} or {@code "urn:ogc:def:uom:EPSG::####"} form (ignoring case and whitespaces),
- * then {@code "####"} is parsed as an integer and forwarded to the {@link Units#valueOfEPSG(int)} method.
+ * If a character sequence given to the {@link #parse(CharSequence)} method is of the form {@code "EPSG:####"},
+ * {@code "urn:ogc:def:uom:EPSG::####"} or {@code "http://www.opengis.net/def/uom/EPSG/0/####"} (ignoring case
+ * and whitespaces around path separators), then {@code "####"} is parsed as an integer and forwarded to the
+ * {@link Units#valueOfEPSG(int)} method.
*
- * <h2>NetCDF unit symbols</h2>
- * The attributes in netCDF files often merge the axis direction with the angular unit,
- * as in {@code "degrees_east"}, {@code "degrees_north"} or {@code "Degrees North"}.
- * This class ignores those suffixes and unconditionally returns {@link Units#DEGREE} for all axis directions.
- * In particular, the units for {@code "degrees_west"} and {@code "degrees_east"} do <strong>not</strong> have
- * opposite sign. It is caller responsibility to handle the direction of axes associated to netCDF units.
+ * <h2>Note on netCDF unit symbols</h2>
+ * In netCDF files, values of "unit" attribute are concatenations of an angular unit with an axis direction,
+ * as in {@code "degrees_east"} or {@code "degrees_north"}. This class ignores those suffixes and unconditionally
+ * returns {@link Units#DEGREE} for all axis directions.
*
* <h2>Multi-threading</h2>
* {@code UnitFormat} is generally not thread-safe. If units need to be parsed or formatted in different threads,
* each thread should have its own {@code UnitFormat} instance.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
*
* @see Units#valueOf(String)
*
@@ -90,6 +87,11 @@
private static final long serialVersionUID = -3064428584419360693L;
/**
+ * Whether the parsing of authority codes such as {@code "EPSG:9001"} is allowed.
+ */
+ private static final boolean PARSE_AUTHORITY_CODES = true;
+
+ /**
* The unit name for degrees (not necessarily angular), to be handled in a special way.
* Must contain only ASCII lower case letters ([a … z]).
*/
@@ -549,7 +551,7 @@
nameToUnit = map;
}
/*
- * The 'nameToUnit' map contains plural forms (declared in UnitAliases.properties),
+ * The `nameToUnit` map contains plural forms (declared in UnitAliases.properties),
* but we make a special case for "degrees", "metres" and "meters" because they
* appear in numerous places.
*/
@@ -677,7 +679,7 @@
* have been created by SystemUnit.transform(…), in which case "Choice 3" above would have been executed.
*/
final Unit<?> unscaled = unit.getSystemUnit();
- @SuppressWarnings("unchecked") // Both 'unit' and 'unscaled' are 'Unit<Q>'.
+ @SuppressWarnings("unchecked") // Both `unit` and `unscaled` are `Unit<Q>`.
final double scale = AbstractConverter.scale(unit.getConverterTo((Unit) unscaled));
if (Double.isNaN(scale)) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.NonRatioUnit_1,
@@ -733,7 +735,7 @@
* Append the scale factor. If we can use a prefix (e.g. "km" instead of "1000⋅m"), we will do that.
* Otherwise if the scale is a power of 10 and we are allowed to use Unicode symbols, we will write
* for example 10⁵⋅m instead of 100000⋅m. If the scale is not a power of 10, or if we are requested
- * to format UCUM symbol, then we fallback on the usual 'Double.toString(double)' representation.
+ * to format UCUM symbol, then we fallback on the usual `Double.toString(double)` representation.
*/
if (scale != 1) {
final char prefix = Prefixes.symbol(scale, prefixPower);
@@ -759,9 +761,9 @@
toAppendTo.append(text, 0, length);
}
/*
- * The 'formatComponents' method appends division symbol only, no multiplication symbol.
+ * The `formatComponents` method appends division symbol only, no multiplication symbol.
* If we have formatted a scale factor and there is at least one component to multiply,
- * we need to append the multiplication symbol ourselves. Note that 'formatComponents'
+ * we need to append the multiplication symbol ourselves. Note that `formatComponents`
* put numerators before denominators, so we are sure that the first term after the
* multiplication symbol is a numerator.
*/
@@ -806,7 +808,7 @@
/*
* At this point, all numerators have been appended. Now append the denominators together.
* For example pressure dimension is formatted as M∕(L⋅T²) no matter if 'M' was the first
- * dimension in the given 'components' map or not.
+ * dimension in the given `components` map or not.
*/
if (!deferred.isEmpty()) {
toAppendTo.append(style.divide);
@@ -1112,22 +1114,14 @@
*/
int end = symbols.length();
int start = CharSequences.skipLeadingWhitespaces(symbols, position.getIndex(), end);
- int endOfURI = XPaths.endOfURI(symbols, start);
- if (endOfURI >= 0) {
- final String uom = symbols.subSequence(start, endOfURI).toString();
- String code = DefinitionURI.codeOf("uom", Constants.EPSG, uom);
- /*
- * DefinitionURI.codeOf(…) returns 'uom' directly (provided that whitespaces were already trimmed)
- * if no ':' character were found, in which case the string is assumed to be the code directly.
- * This is the intended behavior for AuthorityFactory, but in the particular case of this method
- * we want to try to parse as a xpointer before to give up.
- */
- if (code != null && code != uom) {
+ if (PARSE_AUTHORITY_CODES) {
+ final String code = DefinitionURI.codeOf("uom", Constants.EPSG, symbols);
+ if (code != null) {
NumberFormatException failure = null;
try {
final Unit<?> unit = Units.valueOfEPSG(Integer.parseInt(code));
if (unit != null) {
- position.setIndex(endOfURI);
+ position.setIndex(end);
finish(position);
return unit;
}
@@ -1135,36 +1129,15 @@
failure = e;
}
throw (ParserException) new ParserException(Errors.format(Errors.Keys.UnknownUnit_1,
- Constants.EPSG + Constants.DEFAULT_SEPARATOR + code),
- symbols, start + Math.max(0, uom.lastIndexOf(code))).initCause(failure);
- }
- /*
- * Not an EPSG code. Maybe it is a URI like this example:
- * http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])
- *
- * If we find such 'uom' value, we could replace 'symbols' by that 'uom'. But it would cause a wrong
- * error index to be reported in case of parsing failure. We will rather try to adjust the indices
- * (and replace 'symbols' only in last resort).
- */
- code = XPointer.UOM.reference(uom);
- if (code != null) {
- final int base = start;
- start = endOfURI - code.length();
- do if (--start < base) { // Should never happen (see above comment), but we are paranoiac.
- symbols = code;
- start = 0;
- break;
- } while (!CharSequences.regionMatches(symbols, start, code));
- end = start + code.length();
- } else {
- endOfURI = -1;
+ Constants.EPSG + Constants.DEFAULT_SEPARATOR + code), symbols,
+ start + Math.max(0, symbols.toString().lastIndexOf(code))).initCause(failure);
}
}
/*
* Split the unit around the multiplication and division operators and parse each term individually.
* Note that exponentation need to be kept as part of a single unit symbol.
*
- * The 'start' variable is the index of the first character of the next unit term to parse.
+ * The `start` variable is the index of the first character of the next unit term to parse.
*/
final Operation operation = new Operation(symbols); // Enumeration value: NOOP, IMPLICIT, MULTIPLY, DIVIDE.
Unit<?> unit = null;
@@ -1279,7 +1252,7 @@
* between the previously parsed units and the next unit to parse. A special case is IMPLICIT, which is
* a multiplication without explicit × symbol after the parenthesis. The implicit multiplication can be
* overridden by an explicit × or / symbol, which is what happened if we reach this point (tip: look in
- * the above 'switch' statement all cases that end with 'break', not 'break scan' or 'continue').
+ * the above `switch` statement all cases that end with `break`, not `break scan` or `continue`).
*/
if (operation.code != Operation.IMPLICIT) {
unit = operation.apply(unit, parseTerm(symbols, start, i, operation), start);
@@ -1328,13 +1301,13 @@
}
}
if (!(operation.finished = (component != null))) {
- component = parseTerm(symbols, start, i, operation); // May set 'operation.finished' flag.
+ component = parseTerm(symbols, start, i, operation); // May set `operation.finished` flag.
}
if (operation.finished) {
finish(position); // For preventing interpretation of "degree minute" as "degree × minute".
}
unit = operation.apply(unit, component, start);
- position.setIndex(endOfURI >= 0 ? endOfURI : i);
+ position.setIndex(i);
return unit;
}
@@ -1514,7 +1487,7 @@
try {
power = new Fraction(uom.substring(i));
} catch (NumberFormatException e) {
- // Should never happen unless the number is larger than 'int' capacity.
+ // Should never happen unless the number is larger than `int` capacity.
throw (ParserException) new ParserException(Errors.format(
Errors.Keys.UnknownUnit_1, uom), symbols, lower+i).initCause(e);
}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
index 386e114..0c615ea 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
@@ -46,7 +46,7 @@
* without direct dependency. A {@code UnitServices} instance can be obtained by call to {@link #current()}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
* @since 0.8
* @module
*/
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java b/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
index 0cad26f..090d7a8 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
@@ -1701,17 +1701,14 @@
* and may change in future SIS versions.
*
* <h4>Parsing authority codes</h4>
- * As a special case, if the given {@code uom} arguments is of the form {@code "EPSG:####"}
- * or {@code "urn:ogc:def:uom:EPSG:####"} (ignoring case and whitespaces), then {@code "####"}
- * is parsed as an integer and forwarded to the {@link #valueOfEPSG(int)} method.
+ * If the given {@code uom} arguments is of the form {@code "EPSG:####"}, {@code "urn:ogc:def:uom:EPSG:####"}
+ * or {@code "http://www.opengis.net/def/uom/EPSG/0/####"} (ignoring case and whitespaces around separators),
+ * then {@code "####"} is parsed as an integer and forwarded to the {@link #valueOfEPSG(int)} method.
*
- * <h4>NetCDF unit symbols</h4>
- * The attributes in netCDF files often merge the axis direction with the angular unit,
- * as in {@code "degrees_east"} or {@code "degrees_north"}. This {@code valueOf} method
- * ignores those suffixes and unconditionally returns {@link #DEGREE} for all axis directions.
- * In particular, the units for {@code "degrees_west"} and {@code "degrees_east"}
- * do <strong>not</strong> have opposite sign.
- * It is caller responsibility to handle the direction of axes associated to netCDF units.
+ * <h4>Note on netCDF unit symbols</h4>
+ * In netCDF files, values of "unit" attribute are concatenations of an angular unit with an axis direction,
+ * as in {@code "degrees_east"} or {@code "degrees_north"}. This {@code valueOf(…)} method ignores those suffixes
+ * and unconditionally returns {@link #DEGREE} for all axis directions.
*
* @param uom the symbol to parse, or {@code null}.
* @return the parsed symbol, or {@code null} if {@code uom} was null.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java b/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
index 439258c..1bc49aa 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
@@ -170,7 +170,7 @@
/**
* Makes sure that an array is non-null and non-empty. If the given {@code array} is null,
- * then a {@link NullArgumentException} is thrown. Otherwise if the array length is equals
+ * then a {@link NullArgumentException} is thrown. Otherwise if the array length is equal
* to 0, then an {@link IllegalArgumentException} is thrown.
*
* @param name the name of the argument to be checked. Used only if an exception is thrown.
@@ -328,7 +328,7 @@
}
/**
- * Ensures that the given index is equals or greater than zero and lower than the given
+ * Ensures that the given index is equal or greater than zero and lower than the given
* upper value. This method is designed for methods that expect an index value as the only
* argument. For this reason, this method does not take the argument name.
*
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java b/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
index 80006a0..da114b3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
@@ -518,7 +518,7 @@
* Returns the index of the first non-white character in the given range.
* If the given range contains only space characters, then this method returns the index of the
* first character after the given range, which is always equals or greater than {@code toIndex}.
- * Note that this character may not exist if {@code toIndex} is equals to the text length.
+ * Note that this character may not exist if {@code toIndex} is equal to the text length.
*
* <p>Special cases:</p>
* <ul>
@@ -2165,7 +2165,7 @@
*
* <p>This method is similar to {@link String#replace(CharSequence, CharSequence)} except that is accepts
* arbitrary {@code CharSequence} objects. As of Java 10, another difference is that this method does not
- * create a new {@code String} if {@code toSearch} is equals to {@code replaceBy}.</p>
+ * create a new {@code String} if {@code toSearch} is equal to {@code replaceBy}.</p>
*
* @param text the character sequence in which to perform the replacements, or {@code null}.
* @param toSearch the string to replace.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/Emptiable.java b/core/sis-utility/src/main/java/org/apache/sis/util/Emptiable.java
index 6d3171e..a377a31 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/Emptiable.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/Emptiable.java
@@ -23,7 +23,7 @@
* Some examples of emptiable classes are:
*
* <ul>
- * <li>{@link org.apache.sis.measure.Range} when the lower bounds is equals to the upper bounds and at least
+ * <li>{@link org.apache.sis.measure.Range} when the lower bounds is equal to the upper bounds and at least
* one bound is exclusive.</li>
* <li>{@link org.apache.sis.metadata.AbstractMetadata} when no property value has been given to the metadata,
* or all properties are themselves empty.</li>
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/RangeSet.java b/core/sis-utility/src/main/java/org/apache/sis/util/collection/RangeSet.java
index ad0b995..ce7df4d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/RangeSet.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/RangeSet.java
@@ -1402,7 +1402,7 @@
return -1;
}
} else if (!((index & 1) == 0 ? isMinIncluded : isMaxIncluded)) {
- // The value is equals to an excluded endpoint.
+ // The value is equal to an excluded endpoint.
return -1;
}
index /= 2; // Round toward 0 (odd index are maximum values).
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java
index 8d71f62..3665317 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java
@@ -242,9 +242,9 @@
*
* <ul>
* <li>The given object is also a {@code Node}.</li>
- * <li>The list returned by {@link TreeTable#getColumns()} is equals for both nodes.</li>
+ * <li>The list returned by {@link TreeTable#getColumns()} is equal for both nodes.</li>
* <li>The objects returned by {@link #getValue(TableColumn)} are equal for each column.</li>
- * <li>The list returned by {@linkplain #getChildren() children} is equals for both node.</li>
+ * <li>The list returned by {@linkplain #getChildren() children} is equal for both node.</li>
* </ul>
*
* The node returned by {@link #getParent()} shall <strong>not</strong> be taken in account.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java b/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java
index fec31f2..a518ae3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java
@@ -45,7 +45,7 @@
* <h2>Optimizing memory use in factory implementations</h2>
* The {@code WeakHashSet} class has a {@link #get(Object)} method that is not part of the
* {@link java.util.Set} interface. This {@code get} method retrieves an entry from this set
- * that is equals to the supplied object. The {@link #unique(Object)} method combines a
+ * that is equal to the supplied object. The {@link #unique(Object)} method combines a
* {@code get} followed by a {@code add} operation if the specified object was not in the set.
* This is similar in spirit to the {@link String#intern()} method. The following example shows
* a convenient way to use {@code WeakHashSet} as an internal pool of immutable objects:
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
index 739c255..de7a003 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
@@ -340,12 +340,6 @@
public static final short IllegalArgumentClass_3 = 43;
/**
- * Argument ‘{0}’ can not take the “{1}” value, because the ‘{2}’ field can not take the “{3}”
- * value.
- */
- public static final short IllegalArgumentField_4 = 44;
-
- /**
* Argument ‘{0}’ can not take the “{1}” value.
*/
public static final short IllegalArgumentValue_2 = 45;
@@ -436,6 +430,12 @@
public static final short IllegalRange_2 = 60;
/**
+ * Sexagesimal angle {0,number} is illegal because the {1,choice,0#minutes|1#seconds} field can
+ * not take the {2,number} value.
+ */
+ public static final short IllegalSexagesimalField_3 = 44;
+
+ /**
* Value {1} for “{0}” is not a valid Unicode code point.
*/
public static final short IllegalUnicodeCodePoint_2 = 61;
@@ -477,11 +477,6 @@
public static final short InconsistentAttribute_2 = 67;
/**
- * Expected “{0}” namespace for “{1}”.
- */
- public static final short InconsistentNamespace_2 = 68;
-
- /**
* Inconsistent table columns.
*/
public static final short InconsistentTableColumns = 69;
@@ -897,6 +892,11 @@
public static final short UnexpectedFileFormat_2 = 139;
/**
+ * The “{1}” name is not valid in this context, because the “{0}” namespace was expected.
+ */
+ public static final short UnexpectedNamespace_2 = 68;
+
+ /**
* Parameter “{0}” was not expected.
*/
public static final short UnexpectedParameter_1 = 140;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
index c0b3168..ec0853a 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
@@ -79,7 +79,6 @@
ForbiddenProperty_1 = Property \u201c{0}\u201d is not allowed.
IllegalArgumentClass_2 = Argument \u2018{0}\u2019 can not be an instance of \u2018{1}\u2019.
IllegalArgumentClass_3 = Argument \u2018{0}\u2019 can not be an instance of \u2018{2}\u2019. Expected an instance of \u2018{1}\u2019 or derived type.
-IllegalArgumentField_4 = Argument \u2018{0}\u2019 can not take the \u201c{1}\u201d value, because the \u2018{2}\u2019 field can not take the \u201c{3}\u201d value.
IllegalArgumentValue_2 = Argument \u2018{0}\u2019 can not take the \u201c{1}\u201d value.
IllegalBitsPattern_1 = Illegal bits pattern: {0}.
IllegalCharacter_2 = The \u201c{1}\u201d character can not be used for \u201c{0}\u201d.
@@ -98,6 +97,7 @@
IllegalPropertyValueClass_2 = Property \u201c{0}\u201d does not accept instances of \u2018{1}\u2019.
IllegalPropertyValueClass_3 = Expected an instance of \u2018{1}\u2019 for the \u201c{0}\u201d property, but got an instance of \u2018{2}\u2019.
IllegalRange_2 = Range [{0} \u2026 {1}] is not valid.
+IllegalSexagesimalField_3 = Sexagesimal angle {0,number} is illegal because the {1,choice,0#minutes|1#seconds} field can not take the {2,number} value.
IllegalUnicodeCodePoint_2 = Value {1} for \u201c{0}\u201d is not a valid Unicode code point.
IllegalValueForProperty_2 = Illegal value for property \u201c{1}\u201d in \u201c{0}\u201d.
IncompatibleFormat_2 = Can not use the {1} format with \u201c{0}\u201d.
@@ -106,7 +106,6 @@
IncompatibleUnits_2 = Units \u201c{0}\u201d and \u201c{1}\u201d are incompatible.
IncompatibleUnitDimension_5 = The \u201c{0}\u201d unit of measurement has dimension of \u2018{1}\u2019 ({2}). It is incompatible with dimension of \u2018{3}\u2019 ({4}).
InconsistentAttribute_2 = Value \u201c{1}\u201d of attribute \u2018{0}\u2019 is inconsistent with other attributes.
-InconsistentNamespace_2 = Expected \u201c{0}\u201d namespace for \u201c{1}\u201d.
InconsistentTableColumns = Inconsistent table columns.
InconsistentUnitsForCS_1 = Unit of measurement \u201c{0}\u201d is inconsistent with coordinate system axes.
IndexOutOfBounds_1 = Index {0} is out of bounds.
@@ -190,6 +189,7 @@
UnexpectedEndOfFile_1 = Unexpected end of file while reading \u201c{0}\u201d.
UnexpectedEndOfString_1 = More characters were expected at the end of \u201c{0}\u201d.
UnexpectedFileFormat_2 = File \u201c{1}\u201d seems to be encoded in an other format than {0}.
+UnexpectedNamespace_2 = The \u201c{1}\u201d name is not valid in this context, because the \u201c{0}\u201d namespace was expected.
UnexpectedParameter_1 = Parameter \u201c{0}\u201d was not expected.
UnexpectedProperty_2 = Property \u201c{1}\u201d was not expected in \u201c{0}\u201d.
UnexpectedScaleFactorForUnit_2 = Unexpected scale factor {1,number} for unit of measurement \u201c{0}\u201d.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
index b93ab77..305e55d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
@@ -76,7 +76,6 @@
ForbiddenProperty_1 = La propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019est pas autoris\u00e9e.
IllegalArgumentClass_2 = L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{1}\u2019.
IllegalArgumentClass_3 = L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{2}\u2019. Une instance de \u2018{1}\u2019 ou d\u2019un type d\u00e9riv\u00e9 \u00e9tait attendue.
-IllegalArgumentField_4 = L\u2019argument \u2018{0}\u2019 n\u2019accepte pas la valeur \u00ab\u202f{1}\u202f\u00bb parce que le champs \u2018{2}\u2019 ne peut pas prendre la valeur \u00ab\u202f{3}\u202f\u00bb.
IllegalArgumentValue_2 = L\u2019argument \u2018{0}\u2019 n\u2019accepte pas la valeur \u00ab\u202f{1}\u202f\u00bb.
IllegalBitsPattern_1 = Pattern de bits invalide\u00a0: {0}.
IllegalClass_2 = La classe \u2018{1}\u2019 est ill\u00e9gale. Il doit s\u2019agir d\u2019une classe \u2018{0}\u2019 ou d\u00e9riv\u00e9e.
@@ -95,6 +94,7 @@
IllegalPropertyValueClass_2 = La propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019accepte pas les valeurs de type \u2018{1}\u2019.
IllegalPropertyValueClass_3 = Une instance \u2018{1}\u2019 \u00e9tait attendue pour la propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb, mais la valeur donn\u00e9e est une instance de \u2018{2}\u2019.
IllegalRange_2 = La plage [{0} \u2026 {1}] n\u2019est pas valide.
+IllegalSexagesimalField_3 = L\u2019angle sexag\u00e9simal {0,number} est invalide parce que le champs des {1,choice,0#minutes|1#secondes} ne peut pas prendre la valeur {2,number}.
IllegalUnicodeCodePoint_2 = La valeur {1} de \u00ab\u202f{0}\u202f\u00bb n\u2019est pas un code Unicode valide.
IllegalValueForProperty_2 = Valeur ill\u00e9gale pour la propri\u00e9t\u00e9 \u00ab\u202f{1}\u202f\u00bb dans \u00ab\u202f{0}\u202f\u00bb.
IncompatibleFormat_2 = Le format {1} ne s\u2019applique pas \u00e0 \u00ab\u202f{0}\u202f\u00bb.
@@ -103,7 +103,6 @@
IncompatibleUnits_2 = Les unit\u00e9s \u00ab\u202f{0}\u202f\u00bb et \u00ab\u202f{1}\u202f\u00bb ne sont pas compatibles.
IncompatibleUnitDimension_5 = L\u2019unit\u00e9 de mesure \u00ab\u202f{0}\u202f\u00bb a la dimension de \u2018{1}\u2019 ({2}). Elle est incompatible avec la dimension de \u2018{3}\u2019 ({4}).
InconsistentAttribute_2 = La valeur \u00ab\u202f{1}\u202f\u00bb de l\u2019attribut \u2018{0}\u2019 n\u2019est pas coh\u00e9rente avec celles des autres attributs.
-InconsistentNamespace_2 = L\u2019espace de nom \u201c{0}\u201d \u00e9tait attendu pour \u201c{1}\u201d.
InconsistentTableColumns = Les colonnes des tables ne sont pas coh\u00e9rentes.
InconsistentUnitsForCS_1 = L\u2019unit\u00e9 de mesure \u00ab\u202f{0}\u202f\u00bb n\u2019est pas coh\u00e9rente avec les axes du syst\u00e8me de coordonn\u00e9es.
IndexOutOfBounds_1 = L\u2019index {0} est en dehors des limites permises.
@@ -186,6 +185,7 @@
UnexpectedEndOfFile_1 = Fin de fichier inattendue lors de la lecture de \u00ab\u202f{0}\u202f\u00bb.
UnexpectedEndOfString_1 = D\u2019autres caract\u00e8res \u00e9taient attendus \u00e0 la fin du texte \u00ab\u202f{0}\u202f\u00bb.
UnexpectedFileFormat_2 = Le fichier \u00ab\u202f{1}\u202f\u00bb semble \u00eatre encod\u00e9 dans un autre format que {0}.
+UnexpectedNamespace_2 = Le nom \u201c{1}\u201d n\u2019est pas valide dans ce contexte, parce que l\u2019espace de nom \u201c{0}\u201d \u00e9tait attendu.
UnexpectedParameter_1 = Le param\u00e8tre \u00ab\u202f{0}\u202f\u00bb est inattendu.
UnexpectedProperty_2 = La propri\u00e9t\u00e9 \u00ab\u202f{1}\u202f\u00bb est inattendue dans \u00ab\u202f{0}\u202f\u00bb.
UnexpectedScaleFactorForUnit_2 = Le facteur d\u2019\u00e9chelle {1,number} est inattendu pour l\u2019unit\u00e9 de mesure \u00ab\u202f{0}\u202f\u00bb.
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 f7f2fe3..2bbe399 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
@@ -1155,6 +1155,11 @@
public static final short SpatialRepresentation = 184;
/**
+ * Sphere
+ */
+ public static final short Sphere = 271;
+
+ /**
* Standard deviation
*/
public static final short StandardDeviation = 185;
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 1ad786a..21efb2b 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
@@ -234,6 +234,7 @@
Source = Source
SouthBound = South bound
SpatialRepresentation = Spatial representation
+Sphere = Sphere
StandardDeviation = Standard deviation
StartDate = Start date
StartPoint = Start point
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 4bff86e..39059bf 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
@@ -241,6 +241,7 @@
Source = Source
SouthBound = Limite sud
SpatialRepresentation = Repr\u00e9sentation spatiale
+Sphere = Sph\u00e8re
StandardDeviation = \u00c9cart type
StartDate = Date de d\u00e9part
StartPoint = Point de d\u00e9part
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java
index 22965fa..c4facb3 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java
@@ -27,7 +27,7 @@
* Tests {@link DefinitionURI}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.4
* @module
*/
@@ -188,11 +188,12 @@
}
/**
- * Tests {@link DefinitionURI#codeOf(String, String, String)} with URI like {@code "EPSG:4326"}.
+ * Tests {@link DefinitionURI#codeOf(String, String, String)}
+ * with URI like {@code "EPSG:4326"}.
*/
@Test
public void testCodeOfEPSG() {
- assertEquals("4326", DefinitionURI.codeOf("crs", "EPSG", "4326"));
+ assertNull ( DefinitionURI.codeOf("crs", "EPSG", "4326"));
assertEquals("4326", DefinitionURI.codeOf("crs", "EPSG", "EPSG:4326"));
assertEquals("4326", DefinitionURI.codeOf("crs", "EPSG", "EPSG::4326"));
assertNull ( DefinitionURI.codeOf("crs", "EPSG", "EPSG:::4326"));
@@ -203,8 +204,8 @@
}
/**
- * Tests {@link DefinitionURI#codeOf(String, String, String)} with URN like
- * {@code "urn:ogc:def:crs:EPSG::4326"}.
+ * Tests {@link DefinitionURI#codeOf(String, String, String)}
+ * with URN like {@code "urn:ogc:def:crs:EPSG::4326"}.
*/
@Test
public void testCodeOfURN() {
@@ -214,16 +215,26 @@
assertEquals("4326", DefinitionURI.codeOf("crs", "EPSG", "urn:x-ogc:def:crs:EPSG::4326"));
assertNull ( DefinitionURI.codeOf("crs", "EPSG", "urn:n-ogc:def:crs:EPSG::4326"));
assertEquals("4326", DefinitionURI.codeOf("crs", "EPSG", " urn : ogc : def : crs : epsg : : 4326"));
- assertNull ( DefinitionURI.codeOf("crs", "EPSG", "urn:ogc:def:uom:EPSG:9102"));
- assertEquals("9102", DefinitionURI.codeOf("uom", "EPSG", "urn:ogc:def:uom:EPSG:9102"));
+ assertNull ( DefinitionURI.codeOf("crs", "EPSG", "urn:ogc:def:uom:EPSG::9102"));
+ assertEquals("9102", DefinitionURI.codeOf("uom", "EPSG", "urn:ogc:def:uom:EPSG::9102"));
assertNull ( DefinitionURI.codeOf("crs", "EPSG", "urn:ogc:def:crs:OGC:1.3:CRS84"));
assertEquals("CRS84", DefinitionURI.codeOf("crs", "OGC", "urn:ogc:def:crs:OGC:1.3:CRS84"));
assertNull ( DefinitionURI.codeOf("crs", "OGC", "urn:ogc:def:crs:OGC:1.3:AUTO42003:1:-100:45"));
}
/**
- * Tests {@link DefinitionURI#codeOf(String, String, String)} with URL like
- * {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}.
+ * Tests {@link DefinitionURI#codeOf(String, String, String)}
+ * with URL like {@code "http://www.opengis.net/def/crs/EPSG/0/4326"}.
+ */
+ @Test
+ public void testCodeOfDefinitionServer() {
+ assertEquals("4326", DefinitionURI.codeOf("crs", "EPSG", "http://www.opengis.net/def/crs/EPSG/0/4326"));
+ assertEquals("9102", DefinitionURI.codeOf("uom", "EPSG", "http://www.opengis.net/def/uom/EPSG/0/9102"));
+ }
+
+ /**
+ * Tests {@link DefinitionURI#codeOf(String, String, String)}
+ * with URL like {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}.
*/
@Test
public void testCodeOfGML() {
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/XPathsTest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/util/XPathsTest.java
deleted file mode 100644
index fe27718..0000000
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/XPathsTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.internal.util;
-
-import org.apache.sis.util.Characters;
-import org.apache.sis.test.TestCase;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-
-/**
- * Tests {@link XPaths}.
- *
- * @author Martin Desruisseaux (Geomatys)
- * @version 1.2
- * @since 0.4
- * @module
- */
-public final strictfp class XPathsTest extends TestCase {
- /**
- * Tests the {@link XPaths#endOfURI(CharSequence, int)} method.
- */
- @Test
- public void testEndOfURI() {
- assertEquals(26, XPaths.endOfURI("urn:ogc:def:uom:EPSG::9001", 0));
- assertEquals(80, XPaths.endOfURI("http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])", 0));
- assertEquals(97, XPaths.endOfURI("http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])", 0));
- assertEquals(-1, XPaths.endOfURI("m/s", 0));
- assertEquals(-1, XPaths.endOfURI("m.s", 0));
- assertEquals(11, XPaths.endOfURI("EPSG" + Characters.NO_BREAK_SPACE + ": 9001", 0));
- }
-
- /**
- * Tests {@link XPaths#split(String)}.
- */
- @Test
- public void testSplit() {
- assertNull(XPaths.split("property"));
- assertArrayEquals(new String[] {"/property"}, XPaths.split("/property").toArray());
- assertArrayEquals(new String[] {"Feature", "property", "child"}, XPaths.split("Feature/property/child").toArray());
- assertArrayEquals(new String[] {"/Feature", "property"}, XPaths.split("/Feature/property").toArray());
- }
-}
diff --git a/core/sis-utility/src/test/java/org/apache/sis/io/AppenderTestCase.java b/core/sis-utility/src/test/java/org/apache/sis/io/AppenderTestCase.java
index 46a8d8c..9b5cbc8 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/io/AppenderTestCase.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/io/AppenderTestCase.java
@@ -67,7 +67,7 @@
abstract void run(final String lineSeparator) throws IOException;
/**
- * Ensures that the buffer content is equals to the given string.
+ * Ensures that the buffer content is equal to the given string.
*
* @param expected the expected content.
* @throws IOException should never happen since the tests will write in a buffer.
diff --git a/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java b/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java
index 041dfd5..fa5d2f3 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java
@@ -30,7 +30,7 @@
* Test the {@link SexagesimalConverter} class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -93,6 +93,22 @@
}
/**
+ * Tests the error message on attempt to convert an illegal value.
+ */
+ @Test
+ public void testErrorMessage() {
+ final UnitConverter converter = DMS.getConverterTo(Units.DEGREE);
+ assertEquals(10.5, converter.convert(10.3), STRICT);
+ try {
+ converter.convert(10.7);
+ fail("Conversion of illegal value should not be allowed.");
+ } catch (IllegalArgumentException e) {
+ final String message = e.getMessage();
+ assertNotNull(message); // Can not test message content because it is locale-sensitive.
+ }
+ }
+
+ /**
* Tests the fix for rounding error in conversion of 46°57'8.66".
* This fix is necessary for avoiding a 4 cm error with Apache SIS
* construction of EPSG:2056 projected CRS.
diff --git a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
index e5a88a3..3e6e0e2 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
@@ -39,7 +39,7 @@
*
* @author Martin Desruisseaux (Geomatys)
* @author Alexis Manin (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.8
* @module
*/
@@ -428,9 +428,9 @@
@Test
public void testParseEPSG() {
final UnitFormat f = new UnitFormat(Locale.UK);
+ assertSame(Units.METRE, f.parse("EPSG:9001"));
assertSame(Units.METRE, f.parse("urn:ogc:def:uom:EPSG::9001"));
assertSame(Units.METRES_PER_SECOND, f.parse("urn:ogc:def:uom:EPSG::1026"));
- assertSame(Units.METRE, f.parse("http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
}
/**
diff --git a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
index 81134e3..4554079 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
@@ -35,15 +35,14 @@
*
* @author Martin Desruisseaux (Geomatys)
* @author Alexis Manin (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.3
* @module
*/
@DependsOn({
UnitFormatTest.class,
SexagesimalConverterTest.class,
- org.apache.sis.internal.util.DefinitionURITest.class,
- org.apache.sis.internal.util.XPointerTest.class
+ org.apache.sis.internal.util.DefinitionURITest.class
})
public final strictfp class UnitsTest extends TestCase {
/**
@@ -365,19 +364,23 @@
}
/**
+ * Tests {@link Units#valueOf(String)} with a URN syntax.
+ */
+ @Test
+ public void testValueOfURN() {
+ assertSame(METRE, valueOf("EPSG:9001"));
+ assertSame(DEGREE, valueOf(" epsg : 9102"));
+ assertSame(DEGREE, valueOf("urn:ogc:def:uom:EPSG::9102"));
+ }
+
+ /**
* Tests {@link Units#valueOfEPSG(int)} and {@link Units#valueOf(String)} with a {@code "EPSG:####"} syntax.
*/
@Test
public void testValueOfEPSG() {
- assertSame(METRE, valueOfEPSG(9001));
- assertSame(DEGREE, valueOfEPSG(9102)); // Used in prime meridian and operation parameters.
- assertSame(DEGREE, valueOfEPSG(9122)); // Used in coordinate system axes.
- assertSame(METRE, valueOf("EPSG:9001"));
- assertSame(DEGREE, valueOf(" epsg : 9102"));
- assertSame(DEGREE, valueOf("urn:ogc:def:uom:EPSG::9102"));
- assertSame(METRE, valueOf("http://www.isotc211.org/2005/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
- assertSame(METRE, valueOf("gmxUom.xml#m"));
-
+ assertSame(METRE, valueOfEPSG(9001));
+ assertSame(DEGREE, valueOfEPSG(9102)); // Used in prime meridian and operation parameters.
+ assertSame(DEGREE, valueOfEPSG(9122)); // Used in coordinate system axes.
assertSame(TROPICAL_YEAR, valueOfEPSG(1029));
assertSame(SECOND, valueOfEPSG(1040));
assertSame(FOOT, valueOfEPSG(9002));
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java b/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java
index 11acd94..4708536 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java
@@ -311,7 +311,7 @@
/**
* Serializes the given object in memory, deserializes it and ensures that the deserialized
- * object is equals to the original one. This method does not write anything to the disk.
+ * object is equal to the original one. This method does not write anything to the disk.
*
* <p>If the serialization fails, then this method throws an {@link AssertionError}
* as do the other JUnit assertion methods.</p>
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java b/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
index 4e81d87..bb83fbe 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
@@ -25,7 +25,7 @@
* All tests from the {@code sis-utility} module, in rough dependency order.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -87,8 +87,6 @@
// GeoAPI most basic types.
org.apache.sis.internal.util.DefinitionURITest.class,
- org.apache.sis.internal.util.XPathsTest.class,
- org.apache.sis.internal.util.XPointerTest.class,
org.apache.sis.util.SimpleInternationalStringTest.class,
org.apache.sis.util.DefaultInternationalStringTest.class,
org.apache.sis.internal.util.LocalizedParseExceptionTest.class,
diff --git a/pom.xml b/pom.xml
index 477f9af..0aa13ae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,7 +39,7 @@
<parent>
<groupId>org.apache</groupId>
<artifactId>apache</artifactId>
- <version>26</version>
+ <version>27</version>
</parent>
@@ -444,7 +444,7 @@
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
- <version>1.18.2</version>
+ <version>1.19.0</version>
<optional>true</optional>
</dependency>
<dependency>
@@ -492,19 +492,19 @@
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
- <version>2.6.1</version>
+ <version>2.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
- <version>2.1.212</version>
+ <version>2.1.214</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
- <version>42.3.5</version>
+ <version>42.4.1</version>
<scope>test</scope>
</dependency>
@@ -621,7 +621,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
- <version>3.0.0</version>
+ <version>3.1.0</version>
<executions>
<execution>
<id>enforce</id>
@@ -683,7 +683,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <version>3.0.0-M6</version>
+ <version>3.0.0-M7</version>
<configuration>
<trimStackTrace>false</trimStackTrace>
<includes>
@@ -737,7 +737,7 @@
<!-- Set "*-source-release.zip" filename prefix to "sis-*" instead of "parent-*" -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
- <version>3.3.0</version>
+ <version>3.4.2</version>
<executions>
<execution>
<id>source-release-assembly</id>
@@ -968,7 +968,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
- <version>3.0.0-M2</version>
+ <version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java
index e81c9ef..8ec93cd 100644
--- a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java
+++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java
@@ -37,7 +37,7 @@
import org.apache.sis.internal.netcdf.VariableRole;
import org.apache.sis.internal.netcdf.Linearizer;
import org.apache.sis.internal.netcdf.Node;
-import org.apache.sis.internal.referencing.provider.Sinusoidal;
+import org.apache.sis.internal.referencing.provider.PseudoSinusoidal;
import org.apache.sis.internal.referencing.provider.Equirectangular;
import org.apache.sis.internal.referencing.provider.PolarStereographicA;
import org.apache.sis.referencing.operation.transform.TransferFunction;
@@ -117,7 +117,7 @@
*
* @author Alexis Manin (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see <a href="http://global.jaxa.jp/projects/sat/gcom_c/">SHIKISAI (GCOM-C) on JAXA</a>
* @see <a href="https://en.wikipedia.org/wiki/Global_Change_Observation_Mission">GCOM on Wikipedia</a>
@@ -365,7 +365,7 @@
final int s = name.indexOf(' ');
final String code = (s >= 0) ? name.substring(0, s) : name;
if (code.equalsIgnoreCase("EQA")) {
- method = Sinusoidal.NAME;
+ method = PseudoSinusoidal.NAME;
} else if (code.equalsIgnoreCase("EQR")) {
method = Equirectangular.NAME;
} else if (code.equalsIgnoreCase("PS")) {
diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/package-info.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/package-info.java
index 1381a2a..e0f420d 100644
--- a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/package-info.java
+++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/package-info.java
@@ -21,7 +21,7 @@
*
* @author Alexis Manin (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 1.0
* @module
*/
diff --git a/src/main/javadoc/sis.css b/src/main/javadoc/sis.css
index e9f2278..cc771d6 100644
--- a/src/main/javadoc/sis.css
+++ b/src/main/javadoc/sis.css
@@ -262,37 +262,3 @@
:not(td) > div.block {
text-align: justify;
}
-
-
-
-/* ----------------------------------------------------------------------
- * End of SIS-specific part. The remaining of this file overwrite some
- * aspects of the Javadoc default stylesheet.
- */
-body, div.block {
- color: black;
- font-family: Helvetica, Arial, sans-serif;
-}
-
-.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
- color: #353833;
- font-family: Helvetica, Arial, sans-serif;
- margin-left: 40px;
-}
-
-pre, div.block pre, code, tt, dt code, table tr td dt code {
- font-family: Andale Mono, Courier New, monospace;
-}
-
-div.block pre, code, tt, dt code, table tr td dt code {
- line-height: 1em;
- font-size: 1em;
-}
-
-/* Appareance of links in the "Description" column of class and package summaries.
- * JDK style uses bold characters for the left column, which contains the class and
- * package names. But we do not want those bold characters to apply to the descriptions.
- */
-td.colLast div.block a:link {
- font-weight: normal;
-}
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
index 6869cf1..7d684e8 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
@@ -56,7 +56,9 @@
import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.util.collection.BackingStoreException;
import org.apache.sis.util.collection.TreeTable;
+import org.apache.sis.util.iso.DefaultNameSpace;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
/**
@@ -65,6 +67,7 @@
* @author Rémi Maréchal (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @author Thi Phuong Hao Nguyen (VNSC)
+ * @author Alexis Manin (Geomatys)
* @version 1.3
* @since 0.8
* @module
@@ -466,6 +469,7 @@
/**
* Returns the image at the given index. Images numbering starts at 1.
+ * If the given string has a scope (e.g. "filename:1"), then the scope
*
* @param sequence string representation of the image index, starting at 1.
* @return image at the given index.
@@ -473,22 +477,50 @@
*/
@Override
public synchronized GridCoverageResource findResource(final String sequence) throws DataStoreException {
- Exception cause;
- int index;
- try {
- index = Integer.parseInt(sequence);
- cause = null;
- } catch (NumberFormatException e) {
- index = 0;
- cause = e;
- }
- if (index > 0) try {
- GridCoverageResource image = reader().getImage(index - 1);
+ ArgumentChecks.ensureNonNull("sequence", sequence);
+ final int index = parseImageIndex(sequence);
+ if (index >= 0) try {
+ final GridCoverageResource image = reader().getImage(index - 1);
if (image != null) return image;
} catch (IOException e) {
throw errorIO(e);
}
- throw new IllegalNameException(StoreUtilities.resourceNotFound(this, sequence), cause);
+ throw new IllegalNameException(StoreUtilities.resourceNotFound(this, sequence));
+ }
+
+ /**
+ * Validates input resource name and extracts the image index it should contain.
+ * The resource name may be of the form "1" or "filename:1". We verify that:
+ *
+ * <ul>
+ * <li>Input tip (last name part) is a parsable integer.</li>
+ * <li>If input provides more than a tip, all test before the tip matches this datastore namespace
+ * (should be the name of the Geotiff file without its extension).</li>
+ * </ul>
+ *
+ * @param sequence a string representing the name of a resource present in this datastore.
+ * @return the index of the Geotiff image matching the requested resource.
+ * There is no verification that the returned index is valid.
+ * @throws IllegalNameException if the argument use an invalid namespace or if the tip is not an integer.
+ */
+ private int parseImageIndex(String sequence) throws IllegalNameException {
+ final NameSpace namespace = namespace();
+ final String separator = DefaultNameSpace.getSeparator(namespace, false);
+ final int s = sequence.lastIndexOf(separator);
+ if (s >= 0) {
+ if (namespace != null) {
+ final String expected = namespace.name().toString();
+ if (!sequence.substring(0, s).equals(expected)) {
+ throw new IllegalNameException(errors().getString(Errors.Keys.UnexpectedNamespace_2, expected, sequence));
+ }
+ }
+ sequence = sequence.substring(s + separator.length());
+ }
+ try {
+ return Integer.parseInt(sequence);
+ } catch (NumberFormatException e) {
+ throw new IllegalNameException(StoreUtilities.resourceNotFound(this, sequence), e);
+ }
}
/**
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index 001f40e..e5b35f9 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -459,6 +459,13 @@
}
/**
+ * Returns the image index used in the default identifier.
+ */
+ final String getImageIndex() {
+ return String.valueOf(index + 1);
+ }
+
+ /**
* Returns the identifier in the namespace of the {@link GeoTiffStore}.
* The first image has the sequence number "1", optionally customized.
* If this image is an overview, then its namespace should be the name of the base image
@@ -477,8 +484,8 @@
// Should not happen because `setOverviewIdentifier(…)` should have been invoked.
return Optional.empty();
}
- final String id = String.valueOf(index + 1);
- final GenericName name = reader.nameFactory.createLocalName(reader.store.namespace(), id);
+ GenericName name = reader.nameFactory.createLocalName(reader.store.namespace(), getImageIndex());
+ name = name.toFullyQualifiedName(); // Because "1" alone is not very informative.
identifier = reader.store.customizer.customize(index, name);
if (identifier == null) identifier = name;
}
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageMetadataBuilder.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageMetadataBuilder.java
index 8870d00..157a2d8 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageMetadataBuilder.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageMetadataBuilder.java
@@ -39,7 +39,7 @@
* discard them (which save a little bit of space) when no longer needed.</div>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.2
* @module
*/
@@ -170,7 +170,11 @@
* @throws DataStoreException if an error occurred while reading metadata from the data store.
*/
void finish(final ImageFileDirectory image, final StoreListeners listeners) throws DataStoreException {
- image.getIdentifier().ifPresent((id) -> addTitle(id.toString()));
+ image.getIdentifier().ifPresent((id) -> {
+ if (!image.getImageIndex().equals(id.tip().toString())) {
+ addTitle(id.toString());
+ }
+ });
/*
* Add information about the file format.
*
diff --git a/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/SelfConsistencyTest.java b/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/SelfConsistencyTest.java
index bd9e820..48ad7fb 100644
--- a/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/SelfConsistencyTest.java
+++ b/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/SelfConsistencyTest.java
@@ -16,15 +16,21 @@
*/
package org.apache.sis.storage.geotiff;
+import java.util.List;
import java.util.Optional;
import java.nio.file.Path;
+import org.opengis.util.GenericName;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.IllegalNameException;
import org.apache.sis.storage.StorageConnector;
import org.apache.sis.test.OptionalTestData;
import org.apache.sis.test.storage.CoverageReadConsistency;
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
import static org.junit.Assume.assumeNotNull;
@@ -36,7 +42,8 @@
* a subset of data.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @author Alexis Manin (Geomatys)
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -82,4 +89,32 @@
public SelfConsistencyTest() throws DataStoreException {
super(store.components().iterator().next());
}
+
+ /**
+ * Verifies that {@link GeoTiffStore#findResource(String)} returns the resource when using
+ * either the full name or only its tip.
+ *
+ * @throws DataStoreException if an error occurred while reading the file.
+ */
+ @Test
+ public void findResourceByName() throws DataStoreException {
+ final List<GridCoverageResource> datasets = store.components();
+ assertFalse(datasets.isEmpty());
+ for (GridCoverageResource dataset : datasets) {
+ final GenericName name = dataset.getIdentifier()
+ .orElseThrow(() -> new AssertionError("A component of the GeoTiff datastore is unnamed"));
+ GridCoverageResource foundResource = store.findResource(name.toString());
+ assertSame(dataset, foundResource);
+ foundResource = store.findResource(name.tip().toString());
+ assertSame(dataset, foundResource);
+ }
+ try {
+ final GridCoverageResource r = store.findResource("a_wrong_namespace:1");
+ fail("No dataset should be returned when user specify the wrong namespace. However, the datastore returned " + r);
+ } catch (IllegalNameException e) {
+ // Expected behaviour.
+ final String message = e.getMessage();
+ assertTrue(message, message.contains("a_wrong_namespace:1"));
+ }
+ }
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java
index 1fb3e5d..c162ec9 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSBuilder.java
@@ -449,6 +449,7 @@
if (range.getMinDouble() >= 0 && range.getMaxDouble() > axis.getMaximumValue()) {
referenceSystem = (SingleCRS) AbstractCRS.castOrCopy(referenceSystem)
.forConvention(AxesConvention.POSITIVE_RANGE);
+ coordinateSystem = null;
break;
}
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSMerger.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSMerger.java
new file mode 100644
index 0000000..80c0153
--- /dev/null
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/CRSMerger.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.netcdf;
+
+import org.opengis.util.FactoryException;
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.internal.referencing.AxisDirections;
+import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
+import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.referencing.crs.AbstractCRS;
+import org.apache.sis.util.Utilities;
+
+
+/**
+ * Merges the CRS declared in grid mapping attributes with the CRS inferred from coordinate variables.
+ * The former (called "explicit CRS") may have map projection parameters that are difficult to infer
+ * from the coordinate variables. The latter (called "implicit CRS") have better name and all required
+ * dimensions, while the explicit CRS often has only the horizontal dimensions.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 1.3
+ * @module
+ */
+final class CRSMerger extends GeodeticObjectBuilder {
+ /**
+ * Creates a new builder for the given netCDF reader.
+ */
+ CRSMerger(final Decoder decoder) {
+ super(decoder, decoder.listeners.getLocale());
+ }
+
+ /**
+ * Replaces the component starting at given index by the given component, possibly with adjusted longitude range.
+ * The implicit CRS has been inferred from coordinate variables, while the explicit CRS has been inferred from
+ * the grid mapping attributes. The explicit CRS is the one to use, but its longitude range is the default one
+ * because thar range depends on the coordinate variable, which was inspected by the implicit CRS.
+ *
+ * @param implicit the coordinate reference system in which to replace a component.
+ * @param firstDimension index of the first dimension to replace.
+ * @param explicit the component to insert in place of the CRS component at given index.
+ * @return a CRS with the component replaced.
+ * @throws FactoryException if the object creation failed.
+ */
+ @Override
+ public CoordinateReferenceSystem replaceComponent(final CoordinateReferenceSystem implicit,
+ final int firstDimension, CoordinateReferenceSystem explicit) throws FactoryException
+ {
+ final CoordinateSystem cs = implicit.getCoordinateSystem();
+ if (cs instanceof EllipsoidalCS) {
+ final int i = AxisDirections.indexOfColinear(cs, AxisDirection.EAST);
+ if (i >= 0 && cs.getAxis(i).getMinimumValue() >= 0) { // The `i >= 0` check is paranoiac.
+ explicit = AbstractCRS.castOrCopy(explicit).forConvention(AxesConvention.POSITIVE_RANGE);
+ }
+ }
+ final CoordinateReferenceSystem result = super.replaceComponent(implicit, firstDimension, explicit);
+ return Utilities.equalsIgnoreMetadata(implicit, result) ? implicit : result;
+ }
+}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
index f14865a..67ea796 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
@@ -459,6 +459,10 @@
* <td>{@link Number} or {@code double[]}</td>
* <td>Map projection parameter values</td>
* </tr><tr>
+ * <td>{@value CF#SEMI_MAJOR_AXIS} and {@value CF#SEMI_MINOR_AXIS}</td>
+ * <td>{@link Number}</td>
+ * <td>Ellipsoid axis lengths.</td>
+ * </tr><tr>
* <td>{@value #TOWGS84}</td>
* <td>{@link BursaWolfParameters}</td>
* <td>Datum shift information.</td>
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
index 71af070..0438456 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
@@ -48,7 +48,7 @@
* if a variable dimensions should considered as bands instead of spatiotemporal dimensions.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @see Decoder#getGridCandidates()
*
@@ -144,21 +144,18 @@
* This is the number of dimensions of the <em>grid</em>.
* It should be equal to the size of {@link #getDimensions()} list.
*
+ * <h4>Note on target dimensions</h4>
+ * A {@code getTargetDimensions()} method would return the number of dimensions of the
+ * <em>coordinate reference system</em>, which is the target of the <cite>"grid to CRS"</cite> conversion.
+ * However we do not provide that method because, while it should be equal to {@code getAxes(decoder).length},
+ * it sometime differs because {@link #getAxes(Decoder)} may exclude axis with zero dimensions.
+ * The latter method should be used as the authoritative one.
+ *
* @return number of grid dimensions.
*/
public abstract int getSourceDimensions();
/**
- * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion.
- * This is the number of dimensions of the <em>coordinate reference system</em>.
- * It should be equal to the length of the array returned by {@link #getAxes(Decoder)},
- * but caller should be robust to inconsistencies.
- *
- * @return number of CRS dimensions.
- */
- public abstract int getTargetDimensions();
-
- /**
* Returns the dimensions of this grid, in netCDF (reverse of "natural") order. Each element in the list
* contains the number of cells in the dimension, together with implementation-specific information.
* The list length should be equal to {@link #getSourceDimensions()}.
@@ -182,10 +179,8 @@
protected abstract List<Dimension> getDimensions();
/**
- * Returns the axes of the coordinate reference system. The size of this array is expected equals to the
- * value returned by {@link #getTargetDimensions()}, but the caller should be robust to inconsistencies.
- * The axis order is CRS order (reverse of netCDF order) for consistency with the common practice in the
- * {@code "coordinates"} attribute.
+ * Returns the axes of the coordinate reference system. The axis order is CRS order (reverse of netCDF order)
+ * for consistency with the common practice in the {@code "coordinates"} attribute.
*
* <p>This method returns a direct reference to the cached array; do not modify.</p>
*
@@ -397,9 +392,9 @@
* (the source) +1, and the number of rows is the number of dimensions in the CRS (the target) +1.
* The order of dimensions in the transform is the reverse of the netCDF dimension order.
*/
- int lastSrcDim = getSourceDimensions(); // Will be decremented later, then kept final.
- int lastTgtDim = getTargetDimensions();
- final int[] deferred = new int[axes.length]; // Indices of axes that have been deferred.
+ int lastSrcDim = getSourceDimensions(); // Will be decremented later, then kept final.
+ int lastTgtDim = axes.length; // Should be `getTargetDimensions()` but some axes may have been excluded.
+ final int[] deferred = new int[axes.length]; // Indices of axes that have been deferred.
final List<MathTransform> nonLinears = new ArrayList<>(axes.length);
final Matrix affine = Matrices.createZero(lastTgtDim + 1, lastSrcDim + 1);
affine.setElement(lastTgtDim--, lastSrcDim--, 1);
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridMapping.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridMapping.java
index a8235ba..c01d491 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridMapping.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridMapping.java
@@ -21,9 +21,15 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Collections;
+import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.LogRecord;
+import java.util.function.Supplier;
+import java.text.NumberFormat;
+import java.text.FieldPosition;
import java.text.ParseException;
+import javax.measure.Unit;
+import javax.measure.quantity.Length;
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterValueGroup;
@@ -57,7 +63,6 @@
import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridExtent;
-import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
import org.apache.sis.internal.referencing.provider.PseudoPlateCarree;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.internal.util.Constants;
@@ -82,7 +87,7 @@
* which creates Coordinate Reference Systems by inspecting coordinate system axes.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see <a href="http://cfconventions.org/cf-conventions/cf-conventions.html#grid-mappings-and-projections">CF-conventions</a>
*
@@ -91,8 +96,9 @@
*/
final class GridMapping {
/**
- * The Coordinate Reference System, or {@code null} if none. This CRS can be constructed from Well Known Text
- * or EPSG codes declared in {@code "spatial_ref"}, {@code "ESRI_pe_string"} or {@code "EPSG_code"} attributes.
+ * The Coordinate Reference System inferred from grid mapping attribute values, or {@code null} if none.
+ * This CRS may have been constructed from Well Known Text or EPSG codes declared in {@code "spatial_ref"},
+ * {@code "ESRI_pe_string"} or {@code "EPSG_code"} attributes.
*
* <div class="note"><b>Note:</b> this come from different information than the one used by {@link CRSBuilder},
* which creates CRS by inspection of coordinate system axes.</div>
@@ -106,21 +112,27 @@
private final MathTransform gridToCRS;
/**
- * Whether the {@link #crs} where defined by an EPSG code.
+ * Whether the {@link #crs} was defined by a WKT string.
*/
- private final boolean isEPSG;
+ private final boolean isWKT;
/**
* Creates an instance for the given {@link #crs} and {@link #gridToCRS} values.
+ *
+ * @param crs CRS inferred from grid mapping attribute values, or {@code null} if none.
+ * @param gridToCRS transform from GDAL conventions, or {@code null} if none.
+ * @param isWKT wether the {@code crs} was defined by a WKT string.
*/
- private GridMapping(final CoordinateReferenceSystem crs, final MathTransform gridToCRS, final boolean isEPSG) {
+ private GridMapping(final CoordinateReferenceSystem crs, final MathTransform gridToCRS, final boolean isWKT) {
this.crs = crs;
this.gridToCRS = gridToCRS;
- this.isEPSG = isEPSG;
+ this.isWKT = isWKT;
}
/**
* Fetches grid geometry information from attributes associated to the given variable.
+ * This method should be invoked only once per variable, but may return a shared {@code GridMapping} instance
+ * for all variables because there is typically only one set of grid mapping attributes for the whole file.
*
* @param variable the variable for which to create a grid geometry.
*/
@@ -304,25 +316,49 @@
final PrimeMeridian meridian;
if (greenwichLongitude instanceof Number) {
final double longitude = ((Number) greenwichLongitude).doubleValue();
- final Map<String,?> properties = properties(definition, Convention.PRIME_MERIDIAN_NAME, null);
+ final Map<String,?> properties = properties(definition,
+ Convention.PRIME_MERIDIAN_NAME, (longitude == 0) ? "Greenwich" : null);
meridian = datumFactory.createPrimeMeridian(properties, longitude, Units.DEGREE);
isSpecified = true;
} else {
meridian = defaultDefinitions.primeMeridian();
}
/*
- * Ellipsoid built from "semi_major_axis", "semi_minor_axis", etc.
+ * Ellipsoid built from "semi_major_axis" and "semi_minor_axis" parameters. Note that it is okay
+ * to use the OGC name (e.g. "semi_major") instead of the netCDF name (e.g. ""semi_major_axis").
+ * The Apache SIS implementation of parameter value group understands the aliases. Using the OGC
+ * names is safer because they should be understood by most map projection implementations.
*/
Ellipsoid ellipsoid;
try {
- final double semiMajor = parameters.parameter(Constants.SEMI_MAJOR).doubleValue();
- final Map<String,?> properties = properties(definition, Convention.ELLIPSOID_NAME, null);
- if (parameters.parameter(Constants.IS_IVF_DEFINITIVE).booleanValue()) {
- final double ivf = parameters.parameter(Constants.INVERSE_FLATTENING).doubleValue();
- ellipsoid = datumFactory.createFlattenedSphere(properties, semiMajor, ivf, Units.METRE);
+ final ParameterValue<?> p = parameters.parameter(Constants.SEMI_MAJOR);
+ final Unit<Length> axisUnit = p.getUnit().asType(Length.class);
+ final double semiMajor = p.doubleValue();
+ final double secondDefiningParameter;
+ final boolean isSphere;
+ final boolean isIvfDefinitive = parameters.parameter(Constants.IS_IVF_DEFINITIVE).booleanValue();
+ if (isIvfDefinitive) {
+ secondDefiningParameter = parameters.parameter(Constants.INVERSE_FLATTENING).doubleValue();
+ isSphere = (secondDefiningParameter == 0) || Double.isInfinite(secondDefiningParameter);
} else {
- final double semiMinor = parameters.parameter(Constants.SEMI_MINOR).doubleValue();
- ellipsoid = datumFactory.createEllipsoid(properties, semiMajor, semiMinor, Units.METRE);
+ secondDefiningParameter = parameters.parameter(Constants.SEMI_MINOR).doubleValue(axisUnit);
+ isSphere = secondDefiningParameter == semiMajor;
+ }
+ final Supplier<Object> fallback = () -> { // Default ellipsoid name if not specified.
+ final Locale locale = decoder.listeners.getLocale();
+ final NumberFormat f = NumberFormat.getNumberInstance(locale);
+ f.setMaximumFractionDigits(5); // Centimetric precision.
+ final double km = axisUnit.getConverterTo(Units.KILOMETRE).convert(semiMajor);
+ final StringBuffer b = new StringBuffer()
+ .append(Vocabulary.getResources(locale).getString(isSphere ? Vocabulary.Keys.Sphere : Vocabulary.Keys.Ellipsoid))
+ .append(isSphere ? " R=" : " a=");
+ return f.format(km, b, new FieldPosition(0)).append(" km").toString();
+ };
+ final Map<String,?> properties = properties(definition, Convention.ELLIPSOID_NAME, fallback);
+ if (isIvfDefinitive) {
+ ellipsoid = datumFactory.createFlattenedSphere(properties, semiMajor, secondDefiningParameter, axisUnit);
+ } else {
+ ellipsoid = datumFactory.createEllipsoid(properties, semiMajor, secondDefiningParameter, axisUnit);
}
isSpecified = true;
} catch (ParameterNotFoundException | IllegalStateException e) {
@@ -370,13 +406,15 @@
private static Map<String,Object> properties(final Map<String,Object> definition, final String nameAttribute, final Object fallback) {
Object name = definition.remove(nameAttribute);
if (name == null) {
- if (fallback instanceof IdentifiedObject) {
- name = ((IdentifiedObject) fallback).getName();
- } else if (fallback != null) {
- name = fallback.toString();
- } else {
- name = Vocabulary.format(Vocabulary.Keys.Unnamed);
+ if (fallback == null) {
// Note: IdentifiedObject.name does not accept InternationalString.
+ name = Vocabulary.format(Vocabulary.Keys.Unnamed);
+ } else if (fallback instanceof IdentifiedObject) {
+ name = ((IdentifiedObject) fallback).getName();
+ } else if (fallback instanceof Supplier<?>) {
+ name = ((Supplier<?>) fallback).get();
+ } else {
+ name = fallback.toString();
}
}
return Collections.singletonMap(IdentifiedObject.NAME_KEY, name);
@@ -423,7 +461,7 @@
} catch (ParseException | NumberFormatException e) {
canNotCreate(mapping, message, e);
}
- return new GridMapping(crs, gridToCRS, false);
+ return new GridMapping(crs, gridToCRS, wkt != null);
}
/**
@@ -443,14 +481,13 @@
* @return whether this method found grid geometry attributes.
*/
private static GridMapping parseNonStandard(final Node variable) {
- boolean isEPSG = false;
String code = variable.getAttributeAsString("ESRI_pe_string");
- if (code == null) {
+ final boolean isWKT = (code != null);
+ if (!isWKT) {
code = variable.getAttributeAsString("EPSG_code");
if (code == null) {
return null;
}
- isEPSG = true;
}
/*
* The Coordinate Reference System stored in those attributes often use the GeoTIFF flavor of EPSG codes,
@@ -461,16 +498,16 @@
*/
CoordinateReferenceSystem crs;
try {
- if (isEPSG) {
- crs = CRS.forCode(Constants.EPSG + ':' + isEPSG);
- } else {
+ if (isWKT) {
crs = createFromWKT(variable, code);
+ } else {
+ crs = CRS.forCode(Constants.EPSG + ':' + code);
}
} catch (FactoryException | ParseException | ClassCastException e) {
canNotCreate(variable, Resources.Keys.CanNotCreateCRS_3, e);
crs = null;
}
- return new GridMapping(crs, null, isEPSG);
+ return new GridMapping(crs, null, isWKT);
}
/**
@@ -511,10 +548,12 @@
}
/**
- * Creates a new grid geometry for the given extent.
- * This method should be invoked only when no existing {@link GridGeometry} can be used as template.
+ * Creates a new grid geometry with the extent of the given variable and a potentially null CRS.
+ * This method should be invoked only as a fallback when no existing {@link GridGeometry} can be used.
+ * The CRS and "grid to CRS" transform are null, unless some partial information was found for example
+ * as WKT string.
*/
- GridGeometry createGridCRS(final Variable variable) {
+ final GridGeometry createGridCRS(final Variable variable) {
final List<Dimension> dimensions = variable.getGridDimensions();
final long[] upper = new long[dimensions.size()];
for (int i=0; i<upper.length; i++) {
@@ -525,42 +564,48 @@
}
/**
- * Creates the grid geometry from the {@link #crs} and {@link #gridToCRS} field,
- * completing missing information with the given template.
+ * Creates the grid geometry from the {@link #crs} and {@link #gridToCRS} fields,
+ * completing missing information with the implicit grid geometry derived from coordinate variables.
+ * For example {@code GridMapping} may contain information only about the horizontal dimensions, so
+ * the given {@code implicit} geometry is used for completing with vertical and temporal dimensions.
*
* @param variable the variable for which to create a grid geometry.
- * @param template template to use for completing missing information.
+ * @param implicit template to use for completing missing information.
* @param anchor whether we computed "grid to CRS" transform relative to pixel center or pixel corner.
* @return the grid geometry with modified CRS and "grid to CRS" transform, or {@code null} in case of failure.
*/
- GridGeometry adaptGridCRS(final Variable variable, final GridGeometry template, final PixelInCell anchor) {
- CoordinateReferenceSystem givenCRS = crs;
+ final GridGeometry adaptGridCRS(final Variable variable, final GridGeometry implicit, final PixelInCell anchor) {
+ /*
+ * The CRS and grid geometry built from grid mapping attributes are called "explicit" in this method.
+ * This is by contrast with CRS derived from coordinate variables, which is only implicit.
+ */
+ CoordinateReferenceSystem explicitCRS = crs;
int firstAffectedCoordinate = 0;
boolean isSameGrid = true;
- if (template.isDefined(GridGeometry.CRS)) {
- final CoordinateReferenceSystem templateCRS = template.getCoordinateReferenceSystem();
- if (givenCRS == null) {
- givenCRS = templateCRS;
+ if (implicit.isDefined(GridGeometry.CRS)) {
+ final CoordinateReferenceSystem implicitCRS = implicit.getCoordinateReferenceSystem();
+ if (explicitCRS == null) {
+ explicitCRS = implicitCRS;
} else {
/*
- * The CRS built by Grid may have a different axis order than the CRS specified by grid mapping attributes.
- * Check which axis order seems to fit, then replace grid CRS by given CRS (potentially with swapped axes).
- * This is where the potential difference between EPSG axis order and grid axis order is handled. If we can
- * not find where to substitute the CRS, assume that the given CRS describes the first dimensions. We have
- * no guarantees that this later assumption is right, but it seems to match common practice.
+ * The CRS built by the `Grid` class (based on an inspection of coordinate variables)
+ * may have a different axis order than the CRS specified by grid mapping attributes
+ * (the CRS built by this class). This block checks which axis order seems to fit,
+ * then potentially replaces `Grid` implicit CRS by `GridMapping` explicit CRS.
+ *
+ * This is where the potential difference between EPSG axis order and grid axis order is handled.
+ * If we can not find which component to replace, assume that grid mapping describes the first dimensions.
+ * We have no guarantees that this latter assumption is right, but it seems to match common practice.
*/
- final CoordinateSystem cs = templateCRS.getCoordinateSystem();
- CoordinateSystem subCS = givenCRS.getCoordinateSystem();
- firstAffectedCoordinate = AxisDirections.indexOfColinear(cs, subCS);
+ final CoordinateSystem cs = implicitCRS.getCoordinateSystem();
+ firstAffectedCoordinate = AxisDirections.indexOfColinear(cs, explicitCRS.getCoordinateSystem());
if (firstAffectedCoordinate < 0) {
- givenCRS = AbstractCRS.castOrCopy(givenCRS).forConvention(AxesConvention.RIGHT_HANDED);
- subCS = givenCRS.getCoordinateSystem();
- firstAffectedCoordinate = AxisDirections.indexOfColinear(cs, subCS);
+ explicitCRS = AbstractCRS.castOrCopy(explicitCRS).forConvention(AxesConvention.RIGHT_HANDED);
+ firstAffectedCoordinate = AxisDirections.indexOfColinear(cs, explicitCRS.getCoordinateSystem());
if (firstAffectedCoordinate < 0) {
firstAffectedCoordinate = 0;
- if (!isEPSG) {
- givenCRS = crs; // If specified by WKT, use the given CRS verbatim.
- subCS = givenCRS.getCoordinateSystem();
+ if (isWKT && crs != null) {
+ explicitCRS = crs; // If specified by WKT, use the CRS verbatim.
}
}
}
@@ -569,15 +614,15 @@
* axis order. If the grid CRS contains more axes (for example elevation or time axis), we try to keep them.
*/
try {
- givenCRS = new GeodeticObjectBuilder(variable.decoder, variable.decoder.listeners.getLocale())
- .replaceComponent(templateCRS, firstAffectedCoordinate, givenCRS);
+ explicitCRS = new CRSMerger(variable.decoder)
+ .replaceComponent(implicitCRS, firstAffectedCoordinate, explicitCRS);
} catch (FactoryException e) {
canNotCreate(variable, Resources.Keys.CanNotCreateCRS_3, e);
return null;
}
- isSameGrid = templateCRS.equals(givenCRS);
+ isSameGrid = implicitCRS.equals(explicitCRS);
if (isSameGrid) {
- givenCRS = templateCRS; // Keep existing instance if appropriate.
+ explicitCRS = implicitCRS; // Keep existing instance if appropriate.
}
}
}
@@ -587,31 +632,31 @@
* then we need to perform selection in target dimensions (not source dimensions) because the first affected
* coordinate computed above is in CRS dimension, which is the target of "grid to CRS" transform.
*/
- MathTransform givenG2C = gridToCRS;
- if (template.isDefined(GridGeometry.GRID_TO_CRS)) {
- final MathTransform templateG2C = template.getGridToCRS(anchor);
- if (givenG2C == null) {
- givenG2C = templateG2C;
+ MathTransform explicitG2C = gridToCRS;
+ if (implicit.isDefined(GridGeometry.GRID_TO_CRS)) {
+ final MathTransform implicitG2C = implicit.getGridToCRS(anchor);
+ if (explicitG2C == null) {
+ explicitG2C = implicitG2C;
} else try {
int count = 0;
MathTransform[] components = new MathTransform[3];
- final TransformSeparator sep = new TransformSeparator(templateG2C, variable.decoder.getMathTransformFactory());
+ final TransformSeparator sep = new TransformSeparator(implicitG2C, variable.decoder.getMathTransformFactory());
if (firstAffectedCoordinate != 0) {
sep.addTargetDimensionRange(0, firstAffectedCoordinate);
components[count++] = sep.separate();
sep.clear();
}
- components[count++] = givenG2C;
- final int next = firstAffectedCoordinate + givenG2C.getTargetDimensions();
- final int upper = templateG2C.getTargetDimensions();
+ components[count++] = explicitG2C;
+ final int next = firstAffectedCoordinate + explicitG2C.getTargetDimensions();
+ final int upper = implicitG2C.getTargetDimensions();
if (next != upper) {
sep.addTargetDimensionRange(next, upper);
components[count++] = sep.separate();
}
components = ArraysExt.resize(components, count);
- givenG2C = MathTransforms.compound(components);
- if (templateG2C.equals(givenG2C)) {
- givenG2C = templateG2C; // Keep using existing instance if appropriate.
+ explicitG2C = MathTransforms.compound(components);
+ if (implicitG2C.equals(explicitG2C)) {
+ explicitG2C = implicitG2C; // Keep using existing instance if appropriate.
} else {
isSameGrid = false;
}
@@ -625,9 +670,9 @@
* If any of them have changed, create the new grid geometry.
*/
if (isSameGrid) {
- return template;
+ return implicit;
} else {
- return new GridGeometry(template.getExtent(), anchor, givenG2C, givenCRS);
+ return new GridGeometry(implicit.getExtent(), anchor, explicitG2C, explicitCRS);
}
}
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
index 6bbb896..4305b22 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
@@ -48,13 +48,15 @@
import ucar.nc2.constants.CDM; // We use only String constants.
import ucar.nc2.constants.CF;
+import static org.apache.sis.internal.storage.StoreUtilities.ALLOW_LAST_RESORT_STATISTICS;
+
/**
* A netCDF variable created by {@link Decoder}.
*
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -851,6 +853,12 @@
NumberRange<?> range = decoder.convention().validRange(this);
if (range == null) {
range = getRangeFallback();
+ if (ALLOW_LAST_RESORT_STATISTICS && range == null) try {
+ range = read().range();
+ } catch (DataStoreException | IOException e) {
+ // It should be a fatal error, but maybe the user wants only metadata.
+ error(Variable.class, "getValidRange", e, Errors.Keys.CanNotRead_1, getName());
+ }
}
return range;
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
index 27c97fd..f41c864 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
@@ -42,7 +42,7 @@
*
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -120,16 +120,15 @@
return domain.length;
}
- /**
- * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion.
- * This is the number of dimensions of the <em>coordinate reference system</em>.
- * It should be equal to the size of the array returned by {@link #getAxes(Decoder)},
- * but caller should be robust to inconsistencies.
+ /*
+ * A `getTargetDimensions()` method would be like below, but is
+ * excluded because `getAxes(…).length` is the authoritative value:
+ *
+ * @Override
+ * public int getTargetDimensions() {
+ * return range.length;
+ * }
*/
- @Override
- public int getTargetDimensions() {
- return range.length;
- }
/**
* Returns the dimensions of this grid, in netCDF (reverse of "natural") order.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java
index 2319110..c44733a 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java
@@ -30,7 +30,7 @@
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.3
* @module
*/
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
index 2d0cde9..2eb9b2a 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
@@ -45,7 +45,7 @@
* Many netCDF variables may be associated to the same {@code GridWrapper} instance.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -193,16 +193,15 @@
return netcdfCS.getRankDomain();
}
- /**
- * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion.
- * This is the number of dimensions of the <em>coordinate reference system</em>.
- * It should be equal to the length of the array returned by {@link #getAxes(Decoder)},
- * but caller should be robust to inconsistencies.
+ /*
+ * A `getTargetDimensions()` method would be like below, but is
+ * excluded because `getAxes(…).length` is the authoritative value:
+ *
+ * @Override
+ * public int getTargetDimensions() {
+ * return netcdfCS.getRankRange();
+ * }
*/
- @Override
- public int getTargetDimensions() {
- return netcdfCS.getRankRange();
- }
/**
* Returns the dimensions of this grid, in netCDF (reverse of "natural") order.
@@ -257,9 +256,9 @@
* In this method, `sourceDim` and `targetDim` are relative to "grid to CRS" conversion.
* So `sourceDim` is the grid (domain) dimension and `targetDim` is the CRS (range) dimension.
*/
+ int axisCount = 0;
int targetDim = range.size();
final Axis[] axes = new Axis[targetDim];
- final int lastDim = targetDim - 1;
while (--targetDim >= 0) {
final CoordinateAxis axis = range.get(targetDim);
final Variable wrapper = ((DecoderWrapper) decoder).getWrapperFor(axis);
@@ -307,9 +306,11 @@
* package, we can proceed as if the dimension does not exist (`i` not incremented).
*/
}
- axes[lastDim - targetDim] = new Axis(abbreviation, axis.getPositive(),
- ArraysExt.resize(indices, i), ArraysExt.resize(sizes, i), wrapper);
+ if (i != 0) { // Variables with 0 dimensions sometime happen.
+ axes[axisCount++] = new Axis(abbreviation, axis.getPositive(),
+ ArraysExt.resize(indices, i), ArraysExt.resize(sizes, i), wrapper);
+ }
}
- return axes;
+ return ArraysExt.resize(axes, axisCount);
}
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
index c4a2b35..031866e 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -112,7 +112,7 @@
* @author Martin Desruisseaux (Geomatys)
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Alexis Manin (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -678,17 +678,13 @@
/**
* Adds information about axes and cell geometry.
* This is the {@code <mdb:spatialRepresentationInfo>} element in XML.
+ * We work on grid axes instead of Coordinate Reference System axes because
+ * {@code metadata/spatialRepresentationInfo/axisDimensionProperties/dimensionSize} seems to imply that.
*
* @param cs the grid geometry (related to the netCDF coordinate system).
* @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE}, or other overflow occurs.
*/
- private void addSpatialRepresentationInfo(final Grid cs) throws IOException, DataStoreException {
- /*
- * We work on grid axes instead of Coordinate Reference System axes because
- * `metadata/spatialRepresentationInfo/axisDimensionProperties/dimensionSize`
- * seems to imply that.
- */
- final Axis[] axes = cs.getAxes(decoder);
+ private void addSpatialRepresentationInfo(final Axis[] axes) throws IOException, DataStoreException {
for (int i=0; i<axes.length; i++) {
final Axis axis = axes[i];
/*
@@ -1053,10 +1049,11 @@
* is built from the netCDF CoordinateSystem objects.
*/
for (final Grid cs : decoder.getGridCandidates()) {
- if (cs.getSourceDimensions() >= Grid.MIN_DIMENSION &&
- cs.getTargetDimensions() >= Grid.MIN_DIMENSION)
- {
- addSpatialRepresentationInfo(cs);
+ if (cs.getSourceDimensions() >= Grid.MIN_DIMENSION) {
+ final Axis[] axes = cs.getAxes(decoder);
+ if (axes.length >= Grid.MIN_DIMENSION) {
+ addSpatialRepresentationInfo(axes);
+ }
}
}
setISOStandards(hasGridCoverages);
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java
index 5688f63..286a8e5 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridTest.java
@@ -62,7 +62,7 @@
}
/**
- * Tests {@link Grid#getSourceDimensions()} and {@link Grid#getTargetDimensions()}.
+ * Tests {@link Grid#getSourceDimensions()} and {@code Grid.getTargetDimensions()}.
*
* @throws IOException if an I/O error occurred while opening the file.
* @throws DataStoreException if a logical error occurred.
@@ -71,12 +71,12 @@
public void testDimensions() throws IOException, DataStoreException {
Grid geometry = getSingleton(filter(selectDataset(TestData.NETCDF_2D_GEOGRAPHIC).getGridCandidates()));
assertEquals("getSourceDimensions()", 2, geometry.getSourceDimensions());
- assertEquals("getTargetDimensions()", 2, geometry.getTargetDimensions());
+ assertEquals("getTargetDimensions()", 2, geometry.getAxes(decoder()).length);
final int n = includeRuntimeDimension ? 5 : 4;
geometry = getSingleton(filter(selectDataset(TestData.NETCDF_4D_PROJECTED).getGridCandidates()));
assertEquals("getSourceDimensions()", 4, geometry.getSourceDimensions());
- assertEquals("getTargetDimensions()", n, geometry.getTargetDimensions());
+ assertEquals("getTargetDimensions()", n, geometry.getAxes(decoder()).length);
}
/**
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
index 176e845..43c0374 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
@@ -212,7 +212,7 @@
}
/**
- * Asserts that the textual value of the named attribute is equals to the expected value.
+ * Asserts that the textual value of the named attribute is equal to the expected value.
* The {@link #selectDataset(TestData)} method must be invoked at least once before this method.
*
* @param expected the expected attribute value.
@@ -224,7 +224,7 @@
}
/**
- * Asserts that the numeric value of the named attribute is equals to the expected value.
+ * Asserts that the numeric value of the named attribute is equal to the expected value.
* The {@link #selectDataset(TestData)} method must be invoked at least once before this method.
*
* @param expected the expected attribute value.
@@ -236,7 +236,7 @@
}
/**
- * Asserts that the temporal value of the named attribute is equals to the expected value.
+ * Asserts that the temporal value of the named attribute is equal to the expected value.
* The {@link #selectDataset(TestData)} method must be invoked at least once before this method.
*
* @param expected the expected attribute value.
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java
index 97d2a32..dbc4087 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/GridInfoTest.java
@@ -34,7 +34,7 @@
* passed.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.3
* @module
*/
@@ -70,7 +70,7 @@
final Grid[] copy = new Grid[geometries.length];
int count = 0;
for (final Grid geometry : geometries) {
- if (geometry.getSourceDimensions() != 1 || geometry.getTargetDimensions() != 1) {
+ if (geometry.getSourceDimensions() != 1) {
copy[count++] = geometry;
}
}
diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java
index 3abf514..2c8f587 100644
--- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java
+++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java
@@ -731,7 +731,7 @@
*/
protected final void log(final LogRecord record) {
record.setSourceClassName(SQLStore.class.getName());
- record.setSourceMethodName("components"); // Main public API trigging the database analysis.
+ record.setSourceMethodName("components"); // Main public API triggering the database analysis.
record.setLoggerName(Modules.SQL);
listeners.warning(record);
}
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java
index ab3a861..ac16d00 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java
@@ -63,12 +63,23 @@
* Some methods may also move in public API if we feel confident enough.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.0
* @module
*/
public final class StoreUtilities extends Static {
/**
+ * Whether to allow computation of statistics when no minimum/maximum values can be determined.
+ * This is a costly operation because it requires loading all data, so any code enabled by this
+ * flag should be executed in last resort only.
+ *
+ * <p>This flag can be set to {@code true} for exploring data that we can not visualize otherwise.
+ * But it should generally stay to {@code false}, because otherwise browsing resource metadata can
+ * become as costly (slow and high memory usage) as visualizing the full raster.</p>
+ */
+ public static final boolean ALLOW_LAST_RESORT_STATISTICS = false;
+
+ /**
* Logger for the {@value Modules#STORAGE} module. This is used when no more specific logger is available,
* or if the more specific logger is not appropriate (e.g. because the log message come from base class).
*/
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureBuilder.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureBuilder.java
index c7a5a9c..e6d1170 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureBuilder.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureBuilder.java
@@ -229,7 +229,7 @@
}
/*
* At this point we have a non-empty valid sequence of coordinate values. If the first point of current
- * vector is equals to the last point of previous vector, assume that they form a continuous polyline.
+ * vector is equal to the last point of previous vector, assume that they form a continuous polyline.
*/
if (previous != null) {
if (equals(previous, v, dimension)) {
@@ -280,7 +280,7 @@
}
/**
- * Returns {@code true} if the last coordinate of the {@code previous} vector is equals to the first
+ * Returns {@code true} if the last coordinate of the {@code previous} vector is equal to the first
* coordinate of the {@code next} vector.
*
* @param previous the previous vector.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
index 5720c0d..09fd319 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
@@ -309,7 +309,7 @@
/**
* Moves the reader position to beginning of file, if possible. We try to use the mark defined by the constructor,
* which is set after the last header line. If the mark is no longer valid, then we have to create a new line reader.
- * In this later case, we have to skip the header lines (i.e. we reproduce the constructor loop, but without parsing
+ * In this latter case, we have to skip the header lines (i.e. we reproduce the constructor loop, but without parsing
* metadata).
*
* @todo Not yet used. This is planned for a future version of {@link #features(boolean)} method implementation.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileResource.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileResource.java
index 8c2f9e5..887d162 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileResource.java
@@ -26,7 +26,6 @@
import javax.imageio.ImageReader;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageTypeSpecifier;
-import org.opengis.util.LocalName;
import org.opengis.util.GenericName;
import org.opengis.util.InternationalString;
import org.apache.sis.image.ImageProcessor;
@@ -58,7 +57,7 @@
* A single image in a {@link WorldFileStore}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.2
* @module
*/
@@ -89,7 +88,7 @@
*
* @see #getIdentifier()
*/
- private LocalName identifier;
+ private GenericName identifier;
/**
* The grid geometry of this resource. The grid extent is the image size.
@@ -188,7 +187,7 @@
if (store.suffix != null) {
filename = IOUtilities.filenameWithoutExtension(filename);
}
- identifier = Names.createLocalName(filename, null, id);
+ identifier = Names.createLocalName(filename, null, id).toFullyQualifiedName();
}
return Optional.of(identifier);
}
@@ -362,7 +361,7 @@
final void dispose() {
if (identifier != null) {
// For information purpose but not really used.
- store.identifiers.put(identifier.toString(), Boolean.FALSE);
+ store.identifiers.put(identifier.tip().toString(), Boolean.FALSE);
}
store = null;
identifier = null;
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java
index 84244c6..4fd5592 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java
@@ -682,7 +682,7 @@
/**
* Writes fully the buffer content from its position to its limit.
- * After this method call, the buffer position is equals to its limit.
+ * After this method call, the buffer position is equal to its limit.
*
* @throws IOException if an error occurred while writing to the channel.
*/
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java
index d07eeac..a110dc7 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java
@@ -25,7 +25,7 @@
*
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.4
* @module
*/
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/WorldFileStoreTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/WorldFileStoreTest.java
index 3ab1853..aac0db2 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/WorldFileStoreTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/WorldFileStoreTest.java
@@ -43,7 +43,7 @@
* Tests {@link WorldFileStore} and {@link WorldFileStoreProvider}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.2
* @module
*/
@@ -124,7 +124,7 @@
try (WorldFileStore source = provider.open(testData())) {
assertFalse(source instanceof WritableStore);
final GridCoverageResource resource = getSingleton(source.components());
- assertEquals("identifier", "1", resource.getIdentifier().get().toString());
+ assertEquals("identifier", "gradient:1", resource.getIdentifier().get().toString());
/*
* Above `resource` is the content of "gradient.png" file.
* Write the resource in a new file using a different format.
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelDataOutputTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelDataOutputTest.java
index 5a42216..6c86ccb 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelDataOutputTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelDataOutputTest.java
@@ -113,7 +113,7 @@
}
/**
- * Asserts that the content of {@link #testedStream} is equals to the content of {@link #referenceStream}.
+ * Asserts that the content of {@link #testedStream} is equal to the content of {@link #referenceStream}.
* This method closes the reference stream before to perform the comparison.
*/
final void assertStreamContentEquals() throws IOException {
diff --git a/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/storage/gpx/ReaderTest.java b/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/storage/gpx/ReaderTest.java
index d1868ff..74d7d33 100644
--- a/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/storage/gpx/ReaderTest.java
+++ b/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/storage/gpx/ReaderTest.java
@@ -122,7 +122,7 @@
}
/**
- * Asserts that the string value of {@code actual} is equals to the expected value.
+ * Asserts that the string value of {@code actual} is equal to the expected value.
*
* @param expected the expected value (can be {@code null}).
* @param actual the actual value (can be {@code null}).