You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2017/07/26 16:14:14 UTC
svn commit: r1803070 [10/20] - in /sis/branches/JDK9: ./
application/sis-console/src/main/java/org/apache/sis/console/
core/sis-build-helper/
core/sis-build-helper/src/main/java/org/apache/sis/internal/book/
core/sis-build-helper/src/main/java/org/apac...
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -81,8 +81,11 @@
* @author Jody Garnett (Refractions)
* @author Didier Richard (IGN)
* @author John Grange
- * @version 0.7
- * @since 0.7
+ * @version 0.8
+ *
+ * @see org.apache.sis.metadata.sql
+ *
+ * @since 0.7
* @module
*/
package org.apache.sis.referencing.factory.sql;
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -41,6 +41,7 @@ import org.apache.sis.internal.referenci
import org.apache.sis.internal.referencing.provider.GeographicToGeocentric;
import org.apache.sis.internal.referencing.provider.GeocentricToGeographic;
import org.apache.sis.internal.referencing.provider.GeocentricAffine;
+import org.apache.sis.internal.referencing.SpecializedOperationFactory;
import org.apache.sis.internal.referencing.Resources;
import org.apache.sis.internal.util.Constants;
import org.apache.sis.measure.Units;
@@ -118,8 +119,8 @@ public class CoordinateOperationFinder e
* The accuracy threshold (in metres) for allowing the use of Molodensky approximation instead than the
* Geocentric Translation method. The accuracy of datum shifts with Molodensky approximation is about 5
* or 10 metres. However for this constant, we are not interested in absolute accuracy but rather in the
- * difference between Molodensky and Geocentric Translation methods, which is much lower. We nevertheless
- * use a relatively high threshold as a conservative approach.
+ * difference between Molodensky and Geocentric Translation methods, which is much lower (less than 1 m).
+ * We nevertheless use a relatively high threshold as a conservative approach.
*
* @see #desiredAccuracy
*/
@@ -221,6 +222,17 @@ public class CoordinateOperationFinder e
throw new FactoryException(Resources.format(Resources.Keys.RecursiveCreateCallForCode_2, CoordinateOperation.class, key));
}
/*
+ * Verify if some extension module handles this pair of CRS in a special way. For example it may
+ * be the "sis-gdal" module checking if the given CRS are wrappers around Proj.4 data structure.
+ */
+ for (final SpecializedOperationFactory sp : factorySIS.getSpecializedFactories()) {
+ for (final CoordinateOperation op : sp.findOperations(sourceCRS, targetCRS)) {
+ if (filter(op)) {
+ return op;
+ }
+ }
+ }
+ /*
* If the user did not specified an area of interest, use the domain of validity of the CRS.
* Then verify in the EPSG dataset if the operation is explicitely defined by an authority.
*/
@@ -501,8 +513,8 @@ public class CoordinateOperationFinder e
if (parameters == null) {
parameters = TensorParameters.WKT1.createValueGroup(properties(Constants.AFFINE), datumShift);
final CoordinateSystem normalized = CommonCRS.WGS84.geocentric().getCoordinateSystem();
- before = mtFactory.createCoordinateSystemChange(sourceCS, normalized);
- after = mtFactory.createCoordinateSystemChange(normalized, targetCS);
+ before = mtFactory.createCoordinateSystemChange(sourceCS, normalized, sourceDatum.getEllipsoid());
+ after = mtFactory.createCoordinateSystemChange(normalized, targetCS, targetDatum.getEllipsoid());
context.setSource(normalized);
context.setTarget(normalized);
}
@@ -522,7 +534,13 @@ public class CoordinateOperationFinder e
parameters = TensorParameters.WKT1.createValueGroup(properties(Constants.AFFINE)); // Initialized to identity.
parameters.parameter(Constants.NUM_COL).setValue(targetDim + 1);
parameters.parameter(Constants.NUM_ROW).setValue(targetDim + 1);
- before = mtFactory.createCoordinateSystemChange(sourceCS, targetCS);
+ /*
+ * createCoordinateSystemChange(…) needs the ellipsoid associated to the ellipsoidal coordinate system,
+ * if any. If none or both coordinate systems are ellipsoidal, then the ellipsoid will be ignored (see
+ * createCoordinateSystemChange(…) javadoc for the rational) so it does not matter which one we pick.
+ */
+ before = mtFactory.createCoordinateSystemChange(sourceCS, targetCS,
+ (sourceCS instanceof EllipsoidalCS ? sourceDatum : targetDatum).getEllipsoid());
context.setSource(targetCS);
}
}
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -18,10 +18,10 @@ package org.apache.sis.referencing.opera
import java.util.Map;
import java.util.HashMap;
-import java.util.Set;
import java.util.List;
import java.util.ListIterator;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import java.util.logging.Level;
@@ -59,11 +59,13 @@ import org.apache.sis.referencing.factor
import org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException;
import org.apache.sis.metadata.iso.extent.Extents;
import org.apache.sis.internal.referencing.CoordinateOperations;
+import org.apache.sis.internal.referencing.DeferredCoordinateOperation;
import org.apache.sis.internal.referencing.PositionalAccuracyConstant;
import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.referencing.provider.Affine;
import org.apache.sis.internal.referencing.Resources;
import org.apache.sis.internal.metadata.ReferencingServices;
+import org.apache.sis.internal.system.Semaphores;
import org.apache.sis.internal.system.Loggers;
import org.apache.sis.internal.util.Citations;
import org.apache.sis.util.ArgumentChecks;
@@ -385,97 +387,90 @@ class CoordinateOperationRegistry {
return null;
}
final boolean inverse;
- Set<CoordinateOperation> operations;
+ Collection<CoordinateOperation> operations;
+ boolean mdOnly = Semaphores.queryAndSet(Semaphores.METADATA_ONLY); // See comment for the same call inside the loop.
try {
- operations = registry.createFromCoordinateReferenceSystemCodes(sourceID, targetID);
- inverse = Containers.isNullOrEmpty(operations);
- if (inverse) {
- /*
- * No operation from 'source' to 'target' available. But maybe there is an inverse operation.
- * This is typically the case when the user wants to convert from a projected to a geographic CRS.
- * The EPSG database usually contains transformation paths for geographic to projected CRS only.
- */
- operations = registry.createFromCoordinateReferenceSystemCodes(targetID, sourceID);
- if (Containers.isNullOrEmpty(operations)) {
- return null;
+ try {
+ operations = registry.createFromCoordinateReferenceSystemCodes(sourceID, targetID);
+ inverse = Containers.isNullOrEmpty(operations);
+ if (inverse) {
+ /*
+ * No operation from 'source' to 'target' available. But maybe there is an inverse operation.
+ * This is typically the case when the user wants to convert from a projected to a geographic CRS.
+ * The EPSG database usually contains transformation paths for geographic to projected CRS only.
+ */
+ operations = registry.createFromCoordinateReferenceSystemCodes(targetID, sourceID);
+ if (Containers.isNullOrEmpty(operations)) {
+ return null;
+ }
+ }
+ } finally {
+ if (!mdOnly) {
+ Semaphores.clear(Semaphores.METADATA_ONLY);
}
}
- } catch (NoSuchAuthorityCodeException | MissingFactoryResourceException exception) {
+ } catch (NoSuchAuthorityCodeException | MissingFactoryResourceException e) {
/*
* sourceCode or targetCode is unknown to the underlying authority factory.
* Ignores the exception and fallback on the generic algorithm provided by
* CoordinateOperationFinder.
*/
- log(exception);
+ log(null, e);
return null;
}
/*
- * We will loop over all coordinate operations and select the one having the largest intersection
- * with the area of interest. Note that if the user did not specified an area of interest himself,
- * then we need to get one from the CRS. This is necessary for preventing the transformation from
- * NAD27 to NAD83 in Idaho to select the transform for Alaska (since the later has a larger area).
+ * This outer loop is executed exactly once in most case. It may be executed more than once if an
+ * ignoreable error occurred while creating the CoordinateOperation, in which case we will fallback
+ * on the next best choice until we succeed.
*/
- double largestArea = 0;
- double finestAccuracy = Double.POSITIVE_INFINITY;
- CoordinateOperation bestChoice = null;
- boolean stopAtFirstDeprecated = false;
- for (final Iterator<CoordinateOperation> it=operations.iterator(); it.hasNext();) {
- CoordinateOperation candidate;
- try {
- candidate = it.next();
- } catch (BackingStoreException exception) {
- FactoryException cause = exception.unwrapOrRethrow(FactoryException.class);
- if (cause instanceof MissingFactoryResourceException) {
- log(cause);
- continue;
- }
- throw cause;
- }
- if (candidate != null) {
+ CoordinateOperation bestChoice;
+ while (true) {
+ /*
+ * We will loop over all coordinate operations and select the one having the largest intersection
+ * with the area of interest. Note that if the user did not specified an area of interest himself,
+ * then we need to get one from the CRS. This is necessary for preventing the transformation from
+ * NAD27 to NAD83 in Idaho to select the transform for Alaska (since the later has a larger area).
+ */
+ bestChoice = null;
+ double largestArea = 0;
+ double finestAccuracy = Double.POSITIVE_INFINITY;
+ boolean stopAtFirstDeprecated = false;
+ for (final Iterator<CoordinateOperation> it=operations.iterator();;) {
+ CoordinateOperation candidate;
/*
- * If we found at least one non-deprecated operation, we will stop the search at
- * the first deprecated one (assuming that deprecated operations are sorted last).
+ * Some pair of CRS have a lot of coordinate operations backed by datum shift grids.
+ * We do not want to load all of them until we found the right coordinate operation.
+ * The non-public Semaphores.METADATA_ONLY mechanism instructs EPSGDataAccess to
+ * instantiate DeferredCoordinateOperation instead of full coordinate operations.
*/
- final boolean isDeprecated = (candidate instanceof Deprecable) && ((Deprecable) candidate).isDeprecated();
- if (isDeprecated && stopAtFirstDeprecated) {
- break;
- }
- final double area = Extents.area(Extents.intersection(
- Extents.getGeographicBoundingBox(areaOfInterest),
- Extents.getGeographicBoundingBox(candidate.getDomainOfValidity())));
- if (bestChoice == null || area >= largestArea) {
- final double accuracy = CRS.getLinearAccuracy(candidate);
- if (bestChoice == null || area != largestArea || accuracy < finestAccuracy) {
- /*
- * Inverse the operation only after we verified the metadata (domain of validity,
- * accuracy, etc.) since the creation of inverse operation is not guaranteed to
- * preserve all metadata.
- */
- if (inverse) try {
- candidate = inverse(candidate);
- } catch (NoninvertibleTransformException exception) {
- // It may be a normal failure - the operation is not required to be invertible.
- Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
- CoordinateOperationRegistry.class, "createOperation", exception);
- continue;
- } catch (MissingFactoryResourceException e) {
- log(e);
- continue;
+ mdOnly = Semaphores.queryAndSet(Semaphores.METADATA_ONLY);
+ try {
+ try {
+ if (!it.hasNext()) break;
+ candidate = it.next();
+ } finally {
+ if (!mdOnly) {
+ Semaphores.clear(Semaphores.METADATA_ONLY);
}
- /*
- * It is possible that the CRS given to this method were not quite right. For example the user
- * may have created his CRS from a WKT using a different axis order than the order specified by
- * the authority and still (wrongly) call those CRS "EPSG:xxxx". So we check if the source and
- * target CRS for the operation we just created are equivalent to the CRS specified by the user.
- *
- * NOTE: FactoryException may be thrown if we failed to create a transform from the user-provided
- * CRS to the authority-provided CRS. That transform should have been only an identity transform,
- * or a simple affine transform if the user specified wrong CRS as explained in above paragraph.
- * If we failed here, we are likely to fail for all other transforms. So we are better to let
- * the FactoryException propagate.
- */
- candidate = complete(candidate, sourceCRS, targetCRS);
- if (filter == null || filter.test(candidate)) {
+ }
+ } catch (BackingStoreException exception) {
+ throw exception.unwrapOrRethrow(FactoryException.class);
+ }
+ if (candidate != null) {
+ /*
+ * If we found at least one non-deprecated operation, we will stop the search at
+ * the first deprecated one (assuming that deprecated operations are sorted last).
+ */
+ final boolean isDeprecated = (candidate instanceof Deprecable) && ((Deprecable) candidate).isDeprecated();
+ if (isDeprecated && stopAtFirstDeprecated) {
+ break;
+ }
+ final double area = Extents.area(Extents.intersection(
+ Extents.getGeographicBoundingBox(areaOfInterest),
+ Extents.getGeographicBoundingBox(candidate.getDomainOfValidity())));
+ if (bestChoice == null || area >= largestArea) {
+ final double accuracy = CRS.getLinearAccuracy(candidate);
+ if (bestChoice == null || area != largestArea || accuracy < finestAccuracy) {
bestChoice = candidate;
if (!Double.isNaN(area)) {
largestArea = area;
@@ -486,11 +481,79 @@ class CoordinateOperationRegistry {
}
}
}
+ /*
+ * At this point we filtered a CoordinateOperation by looking only at its metadata.
+ * Code following this point will need the full coordinate operation, including its
+ * MathTransform. So if we got a deferred operation, we need to resolve it now.
+ * Conversely, we should not use metadata below this point because the call to
+ * inverse(CoordinateOperation) is not guaranteed to preserve all metadata.
+ */
+ if (bestChoice == null) break;
+ final CoordinateOperation deferred = bestChoice;
+ try {
+ if (bestChoice instanceof DeferredCoordinateOperation) {
+ bestChoice = ((DeferredCoordinateOperation) bestChoice).create();
+ }
+ if (bestChoice instanceof SingleOperation && bestChoice.getMathTransform() == null) {
+ bestChoice = fromDefiningConversion((SingleOperation) bestChoice,
+ inverse ? targetCRS : sourceCRS,
+ inverse ? sourceCRS : targetCRS);
+ if (bestChoice == null) {
+ return null;
+ }
+ }
+ if (inverse) {
+ bestChoice = inverse(bestChoice);
+ }
+ } catch (NoninvertibleTransformException | MissingFactoryResourceException e) {
+ /*
+ * If we failed to get the real CoordinateOperation instance, remove it from the collection
+ * and try again in order to get the next best choice. The Apache SIS implementation allows
+ * to remove directly from the Set<CoordinateOperation>, but that removal may fail with non-SIS
+ * implementations, in which case we copy the CoordinateOperation in a temporary list before
+ * removal. We do not perform that copy unconditionally in order to avoid lazy initialization
+ * of unneeded CoordinateOperations like the deprecated ones.
+ */
+ boolean removed;
+ try {
+ removed = operations.remove(deferred);
+ } catch (UnsupportedOperationException ignored) {
+ operations = new ArrayList<>(operations);
+ removed = operations.remove(deferred);
+ }
+ if (removed) {
+ log(null, e);
+ continue; // Try again with the next best case.
+ }
+ // Should never happen, but if happen anyway we should fail for avoiding never-ending loop.
+ throw (e instanceof FactoryException) ? (FactoryException) e : new FactoryException(e);
+ }
+ /*
+ * It is possible that the CRS given to this method were not quite right. For example the user
+ * may have created his CRS from a WKT using a different axis order than the order specified by
+ * the authority and still (wrongly) call those CRS "EPSG:xxxx". So we check if the source and
+ * target CRS for the operation we just created are equivalent to the CRS specified by the user.
+ *
+ * NOTE: FactoryException may be thrown if we fail to create a transform from the user-provided
+ * CRS to the authority-provided CRS. That transform should have been only an identity transform,
+ * or a simple affine transform if the user specified wrong CRS as explained in above paragraph.
+ * If we fail here, we are likely to fail for all other transforms. So we are better to let the
+ * FactoryException propagate.
+ */
+ bestChoice = complete(bestChoice, sourceCRS, targetCRS);
+ if (filter(bestChoice)) break;
}
return bestChoice;
}
/**
+ * Returns {@code true} if the given operation can be accepted.
+ */
+ final boolean filter(final CoordinateOperation op) {
+ return filter == null || filter.test(op);
+ }
+
+ /**
* Creates the inverse of the given single operation.
* If this operation succeed, then the returned coordinate operations has the following properties:
*
@@ -610,6 +673,12 @@ class CoordinateOperationRegistry {
final MathTransformFactory mtFactory)
throws IllegalArgumentException, IncommensurableException, FactoryException
{
+ /*
+ * Assertion: source and target CRS must be equals, ignoring change in axis order or units.
+ * The first line is for disabling this check if the number of dimensions are not the same
+ * (e.g. as in the "geographic 3D to geographic 2D" conversion) because ALLOW_VARIANT mode
+ * still requires a matching number of dimensions.
+ */
assert ReferencingUtilities.getDimension(sourceCRS) != ReferencingUtilities.getDimension(targetCRS)
|| Utilities.deepEquals(sourceCRS, targetCRS, ComparisonMode.ALLOW_VARIANT);
final Matrix m = CoordinateSystems.swapAndScaleAxes(sourceCRS.getCoordinateSystem(), targetCRS.getCoordinateSystem());
@@ -752,6 +821,42 @@ class CoordinateOperationRegistry {
}
/**
+ * Creates a complete coordinate operation from a defining conversion. Defining conversions usually have
+ * null source and target CRS, but this method nevertheless checks that, in order to reuse the operation
+ * CRS if it happens to have some.
+ *
+ * @param operation the operation specified by the authority.
+ * @param sourceCRS the source CRS specified by the user.
+ * @param targetCRS the target CRS specified by the user
+ * @return a new operation from the given source CRS to target CRS.
+ * @throws FactoryException if an error occurred while creating the new operation.
+ */
+ private CoordinateOperation fromDefiningConversion(final SingleOperation operation,
+ CoordinateReferenceSystem sourceCRS,
+ CoordinateReferenceSystem targetCRS)
+ throws FactoryException
+ {
+ final ParameterValueGroup parameters = operation.getParameterValues();
+ if (parameters != null) {
+ CoordinateReferenceSystem crs;
+ if (Utilities.equalsApproximatively(sourceCRS, crs = operation.getSourceCRS())) sourceCRS = crs;
+ if (Utilities.equalsApproximatively(targetCRS, crs = operation.getTargetCRS())) targetCRS = crs;
+ final MathTransformFactory mtFactory = factorySIS.getMathTransformFactory();
+ if (mtFactory instanceof DefaultMathTransformFactory) {
+ MathTransform mt = ((DefaultMathTransformFactory) mtFactory).createParameterizedTransform(
+ parameters, ReferencingUtilities.createTransformContext(sourceCRS, targetCRS, null));
+ return factorySIS.createSingleOperation(IdentifiedObjects.getProperties(operation),
+ sourceCRS, targetCRS, null, operation.getMethod(), mt);
+ }
+ } else {
+ // Should never happen because parameters are mandatory, but let be safe.
+ log(Resources.forLocale(null).getLogRecord(Level.WARNING, Resources.Keys.MissingParameterValues_1,
+ IdentifiedObjects.getIdentifierOrName(operation)), null);
+ }
+ return null;
+ }
+
+ /**
* Returns a new coordinate operation with the ellipsoidal height added either in the source coordinates,
* in the target coordinates or both. If there is an ellipsoidal transform, then this method updates the
* transforms in order to use the ellipsoidal height (it has an impact on the transformed values).
@@ -861,7 +966,7 @@ class CoordinateOperationRegistry {
((SingleOperation) op).getParameterValues(),
ReferencingUtilities.createTransformContext(sourceCRS, targetCRS, null));
} catch (InvalidGeodeticParameterException e) {
- log(e);
+ log(null, e);
break;
}
operations.set(recreate(op, sourceCRS, targetCRS, mt, mtFactory.getLastMethodUsed()));
@@ -1077,11 +1182,23 @@ class CoordinateOperationRegistry {
* come from {@link CoordinateOperationFinder} since this is the public API which
* use this {@code CoordinateOperationRegistry} class.
*
- * @param exception the exception which occurred.
+ * @param record the record to log, or {@code null} for creating from the exception.
+ * @param exception the exception which occurred, or {@code null} if a {@code record} is specified instead.
*/
- private static void log(final FactoryException exception) {
- final LogRecord record = new LogRecord(Level.WARNING, exception.getLocalizedMessage());
+ private static void log(LogRecord record, final Exception exception) {
+ if (record == null) {
+ record = new LogRecord(Level.WARNING, exception.getLocalizedMessage());
+ }
record.setLoggerName(Loggers.COORDINATE_OPERATION);
+ /*
+ * We usually do not log the stack trace since this method should be invoked only for exceptions
+ * like NoSuchAuthorityCodeException or MissingFactoryResourceException, for which the message
+ * is descriptive enough. But we make a special case for NoninvertibleTransformException since
+ * its cause may have deeper root.
+ */
+ if (exception instanceof NoninvertibleTransformException) {
+ record.setThrown(exception);
+ }
Logging.log(CoordinateOperationFinder.class, "createOperation", record);
}
}
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -104,19 +104,22 @@ final class DefaultConcatenatedOperation
* @param mtFactory the math transform factory to use for math transforms concatenation.
* @throws FactoryException if the factory can not concatenate the math transforms.
*/
- @SuppressWarnings("PublicConstructorInNonPublicClass")
public DefaultConcatenatedOperation(final Map<String,?> properties, CoordinateOperation[] operations,
final MathTransformFactory mtFactory) throws FactoryException
{
super(properties);
ArgumentChecks.ensureNonNull("operations", operations);
- final List<CoordinateOperation> flattened = new ArrayList<>(operations.length);
- initialize(properties, operations, flattened, mtFactory,
- (coordinateOperationAccuracy == null), (domainOfValidity == null));
- if (flattened.size() < 2) {
+ if (operations.length < 2) {
throw new IllegalArgumentException(Errors.getResources(properties).getString(
Errors.Keys.TooFewOccurrences_2, 2, CoordinateOperation.class));
}
+ final List<CoordinateOperation> flattened = new ArrayList<>(operations.length);
+ initialize(properties, operations, flattened, mtFactory,
+ (coordinateOperationAccuracy == null), (domainOfValidity == null));
+ /*
+ * At this point we should have flattened.size() >= 2, except if some operations
+ * were omitted because their associated math transform were identity operation.
+ */
operations = flattened.toArray(new CoordinateOperation[flattened.size()]);
this.operations = UnmodifiableArrayList.wrap(operations);
this.sourceCRS = operations[0].getSourceCRS();
@@ -190,7 +193,7 @@ final class DefaultConcatenatedOperation
}
}
}
- previous = op.getTargetCRS(); // For next iteration cycle.
+ previous = op.getTargetCRS(); // For next iteration cycle.
/*
* Now that we have verified the CRS dimensions, we should be able to concatenate the transforms.
* If an operation is a nested ConcatenatedOperation (not allowed by ISO 19111, but we try to be
@@ -205,7 +208,7 @@ final class DefaultConcatenatedOperation
@SuppressWarnings("SuspiciousToArrayCall")
final CoordinateOperation[] asArray = children.toArray(new CoordinateOperation[children.size()]);
initialize(properties, asArray, flattened, (step == null) ? mtFactory : null, setAccuracy, setDomain);
- } else {
+ } else if (!step.isIdentity()) {
flattened.add(op);
}
if (mtFactory != null) {
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -20,6 +20,7 @@ import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
+import java.util.ServiceLoader;
import org.opengis.util.FactoryException;
import org.opengis.util.NoSuchIdentifierException;
import org.opengis.parameter.ParameterValueGroup;
@@ -36,10 +37,12 @@ import org.opengis.referencing.cs.CSFact
import org.opengis.referencing.datum.Datum;
import org.apache.sis.internal.referencing.Resources;
import org.apache.sis.internal.referencing.MergedProperties;
+import org.apache.sis.internal.referencing.SpecializedOperationFactory;
import org.apache.sis.internal.metadata.ReferencingServices;
import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.internal.util.CollectionsExt;
import org.apache.sis.internal.util.Constants;
+import org.apache.sis.internal.util.LazySet;
import org.apache.sis.referencing.CRS;
import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
import org.apache.sis.referencing.operation.transform.AbstractMathTransform;
@@ -122,6 +125,17 @@ public class DefaultCoordinateOperationF
private volatile MathTransformFactory mtFactory;
/**
+ * Factories specialized to some particular pair of CRS. For example a module doing the bindings between
+ * Apache SIS and another map projection library may create wrappers around the transformation method of
+ * that other library when {@code SpecializedOperationFactory.tryCreateOperation(…)} recognizes the given
+ * CRS as wrappers around their data structures.
+ *
+ * <p>This array is created when first needed. After creation, the array shall not be modified anymore.</p>
+ */
+ @SuppressWarnings("VolatileArrayField")
+ private volatile SpecializedOperationFactory[] specializedFactories;
+
+ /**
* Weak references to existing objects.
* This set is used in order to return a pre-existing object instead of creating a new one.
* This applies to objects created explicitly, not to coordinate operations inferred by a
@@ -147,8 +161,8 @@ public class DefaultCoordinateOperationF
/**
* Constructs a factory with the given default properties.
- * {@code DefaultCoordinateOperationFactory} will fallback on the map given to this constructor
- * for any property not present in the map provided to a {@code createFoo(Map<String,?>, …)} method.
+ * The new factory will fallback on the map given to this constructor
+ * for any property not present in the map given to a {@code createFoo(Map<String,?>, …)} method.
*
* @param properties the default properties, or {@code null} if none.
* @param factory the factory to use for creating {@linkplain AbstractMathTransform math transforms},
@@ -174,6 +188,7 @@ public class DefaultCoordinateOperationF
throw new IllegalArgumentException(Errors.getResources(properties)
.getString(Errors.Keys.IllegalPropertyValueClass_2, key, Classes.getClass(value)));
}
+ properties.remove(ReferencingServices.DATUM_FACTORY);
properties = CollectionsExt.compact(properties);
}
defaultProperties = properties;
@@ -254,6 +269,20 @@ public class DefaultCoordinateOperationF
}
/**
+ * Returns all known factories specialized in the creation of coordinate operations between some particular
+ * pairs of CRS.
+ */
+ final SpecializedOperationFactory[] getSpecializedFactories() {
+ SpecializedOperationFactory[] factories = specializedFactories;
+ if (factories == null) {
+ final LazySet<SpecializedOperationFactory> set =
+ new LazySet<>(ServiceLoader.load(SpecializedOperationFactory.class).iterator());
+ specializedFactories = factories = set.toArray(new SpecializedOperationFactory[set.size()]);
+ }
+ return factories;
+ }
+
+ /**
* Returns the operation method of the given name. The given argument shall be either a method
* {@linkplain DefaultOperationMethod#getName() name} (e.g. <cite>"Transverse Mercator"</cite>)
* or one of its {@linkplain DefaultOperationMethod#getIdentifiers() identifiers} (e.g. {@code "EPSG:9807"}).
@@ -513,7 +542,7 @@ next: for (int i=components.size(); --
if (parameters == null) {
throw new NullArgumentException(Errors.format(Errors.Keys.NullArgument_1, "transform"));
}
- transform = mtFactory.createBaseToDerived(sourceCRS, parameters, targetCRS.getCoordinateSystem());
+ transform = getMathTransformFactory().createBaseToDerived(sourceCRS, parameters, targetCRS.getCoordinateSystem());
}
/*
* The "operationType" property is currently undocumented. The intend is to help this factory method in
@@ -650,12 +679,22 @@ next: for (int i=components.size(); --
if (operations != null && operations.length == 1) {
return operations[0];
}
- final CoordinateOperation op;
+ final ConcatenatedOperation op;
try {
op = new DefaultConcatenatedOperation(properties, operations, getMathTransformFactory());
} catch (IllegalArgumentException exception) {
throw new InvalidGeodeticParameterException(exception.getLocalizedMessage(), exception);
}
+ /*
+ * Verifies again the number of single operations. We may have a singleton if some operations
+ * were omitted because their associated math transform were identity. This happen for example
+ * if a "Geographic 3D to 2D conversion" as been redimensioned to a "3D to 3D" operation.
+ */
+ final List<? extends CoordinateOperation> co = op.getOperations();
+ if (co.size() == 1) {
+ assert op.getMathTransform().equals(co.get(0).getMathTransform()) : op;
+ return co.get(0);
+ }
return pool.unique(op);
}
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -18,18 +18,24 @@ package org.apache.sis.referencing.opera
import org.opengis.util.FactoryException;
import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
import org.apache.sis.referencing.operation.transform.InterpolatedTransform;
import org.apache.sis.referencing.operation.transform.LinearTransform;
import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.datum.DatumShiftGrid;
import org.apache.sis.internal.referencing.Resources;
import org.apache.sis.geometry.DirectPosition2D;
+import org.apache.sis.internal.util.Numerics;
import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.measure.NumberRange;
import org.apache.sis.math.MathFunctions;
+import org.apache.sis.math.Vector;
/**
@@ -63,6 +69,11 @@ import org.apache.sis.math.MathFunctions
*/
public class LocalizationGridBuilder extends TransformBuilder {
/**
+ * Tolerance threshold for comparing pixel coordinates relative to integer values.
+ */
+ private static final double EPS = Numerics.COMPARISON_THRESHOLD;
+
+ /**
* The transform for the linear part.
*/
private final LinearTransformBuilder linear;
@@ -71,7 +82,7 @@ public class LocalizationGridBuilder ext
* A temporary array for two-dimensional source coordinates.
* Used for reducing object allocations.
*/
- private final int[] tmp;
+ private final int[] tmp = new int[2];
/**
* Conversions from source real-world coordinates to grid indices before interpolation.
@@ -90,18 +101,86 @@ public class LocalizationGridBuilder ext
static final double DEFAULT_PRECISION = 1E-7;
/**
- * Creates a new, initially empty, builder.
+ * Creates a new, initially empty, builder for a localization grid of the given size.
*
* @param width the number of columns in the grid of target positions.
* @param height the number of rows in the grid of target positions.
*/
public LocalizationGridBuilder(final int width, final int height) {
linear = new LinearTransformBuilder(width, height);
- tmp = new int[2];
sourceToGrid = MathTransforms.identity(2);
}
/**
+ * Creates a new, initially empty, builder for a localization grid of a size inferred from the given points.
+ * This constructor uses the given vectors for computing a grid size and the following initial conversion:
+ *
+ * <blockquote>({@code sourceX}, {@code sourceY}) → ({@code gridX}, {@code gridY})</blockquote>
+ *
+ * Above conversion can be obtained by {@link #getSourceToGrid()}.
+ *
+ * <p>Values in the given vectors should be integers, but this constructor is tolerant to non-integer values
+ * if they have a constant offset (typically 0.5) relative to integer values. The two vectors do not need to
+ * have the same length (i.e. {@code sourceX[i]} are not necessarily related to {@code sourceY[i]}).</p>
+ *
+ * @param sourceX all possible <var>x</var> inputs before conversion to grid coordinates.
+ * @param sourceY all possible <var>y</var> inputs before conversion to grid coordinates.
+ * @throws ArithmeticException if this constructor can not infer a reasonable grid size from the given vectors.
+ */
+ public LocalizationGridBuilder(final Vector sourceX, final Vector sourceY) {
+ final Matrix fromGrid = Matrices.createDiagonal(3,3);
+ linear = new LinearTransformBuilder(infer(sourceX, fromGrid, 0), infer(sourceY, fromGrid, 1));
+ try {
+ sourceToGrid = MathTransforms.linear(fromGrid).inverse();
+ } catch (NoninvertibleTransformException e) {
+ // Should not happen because infer(…) verified that the coefficients are okay.
+ throw (ArithmeticException) new ArithmeticException(e.getLocalizedMessage()).initCause(e);
+ }
+ }
+
+ /**
+ * Infers a grid size by searching for the greatest common divisor (GCD) for values in the given vector.
+ * The vector values should be integers, but this method is tolerant to constant offsets (typically 0.5).
+ * The GCD is taken as a "grid to source" scale factor and the minimal value as the translation term.
+ * Those two values are stored in the {@code dim} row of the given matrix.
+ *
+ * @param source the vector of values for which to get the GCD and minimum value.
+ * @param fromGrid matrix where to store the minimum value and the GCD.
+ * @param dim index of the matrix row to update.
+ * @return grid size.
+ */
+ private static int infer(final Vector source, final Matrix fromGrid, final int dim) {
+ final NumberRange<?> range = source.range();
+ final double min = range.getMinDouble(true);
+ final double span = range.getMaxDouble(true) - min;
+ final Number increment = source.increment(EPS * span);
+ double inc;
+ if (increment != null) {
+ inc = increment.doubleValue();
+ } else {
+ inc = span;
+ final int size = source.size();
+ for (int i=0; i<size; i++) {
+ double v = source.doubleValue(i) - min;
+ if (Math.abs(v % inc) > EPS) {
+ do {
+ final double r = (inc % v); // Both 'inc' and 'v' are positive, so 'r' will be positive too.
+ inc = v;
+ v = r;
+ } while (Math.abs(v) > EPS);
+ }
+ }
+ }
+ fromGrid.setElement(dim, dim, inc);
+ fromGrid.setElement(dim, 2, min);
+ final double n = span / inc;
+ if (n > 0.5 && n < 0.5 + Short.MAX_VALUE) {
+ return ((int) Math.round(n)) + 1;
+ }
+ throw new ArithmeticException(Resources.format(Resources.Keys.CanNotInferGridSizeFromValues_1, range));
+ }
+
+ /**
* Sets the desired precision of <em>inverse</em> transformations, in units of source coordinates.
* If a conversion from "real world" to grid coordinates {@linkplain #setSourceToGrid has been specified},
* then the given precision is in "real world" units. Otherwise the precision is in units of grid cells.
@@ -122,6 +201,16 @@ public class LocalizationGridBuilder ext
}
/**
+ * Returns the desired precision of <em>inverse</em> transformations, in units of source coordinates.
+ * This is the precision sets by the last call to {@link #setDesiredPrecision(double)}.
+ *
+ * @return desired precision of the results of inverse transformations.
+ */
+ public double getDesiredPrecision() {
+ return precision;
+ }
+
+ /**
* Defines relationship between "real-world" source coordinates and grid coordinates.
* The given transform is usually two-dimensional, in which case conversions from (<var>x</var>,<var>y</var>)
* source coordinates to ({@code gridX}, {@code gridY}) indices can be done with the following formulas:
@@ -173,9 +262,25 @@ public class LocalizationGridBuilder ext
}
/**
+ * Returns the current relationship between "real-world" source coordinates and grid coordinates.
+ * This is the value set by the last call to {@link #setSourceToGrid(LinearTransform)}.
+ * If that setter method has never been invoked, then this is an automatically computed transform
+ * if the grid coordinates {@linkplain #LocalizationGridBuilder(Vector, Vector) have been specified
+ * to the constructor}, or the identity transform {@linkplain #LocalizationGridBuilder(int, int) otherwise}.
+ *
+ * @return the current relationship between "real-world" source coordinates and grid coordinates.
+ */
+ public LinearTransform getSourceToGrid() {
+ return sourceToGrid;
+ }
+
+ /**
* Sets a single matching control point pair. Source position is assumed precise and target position is assumed uncertain.
* If the given source position was already associated with another target position, then the old target position is discarded.
*
+ * <p>If a {@linkplain #getSourceToGrid() source to grid} conversion exists, it shall have been applied
+ * by the caller for computing the ({@code gridX}, {@code gridY}) coordinates given to this method.</p>
+ *
* @param gridX the column index in the grid where to store the given target position.
* @param gridY the row index in the grid where to store the given target position.
* @param target the target coordinates, assumed uncertain.
@@ -231,7 +336,7 @@ public class LocalizationGridBuilder ext
}
}
if (isExact) {
- return gridToCoord;
+ return MathTransforms.concatenate(sourceToGrid, gridToCoord);
}
final int width = linear.gridSize(0);
final int height = linear.gridSize(1);
@@ -282,7 +387,7 @@ public class LocalizationGridBuilder ext
throw new FactoryException(e); // Should never happen.
}
if (isLinear) {
- return gridToCoord;
+ return MathTransforms.concatenate(sourceToGrid, gridToCoord);
}
return InterpolatedTransform.createGeodeticTransformation(nonNull(factory),
new ResidualGrid(sourceToGrid, gridToCoord, width, height, tgtDim, residual,
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -628,7 +628,7 @@ public class TransverseMercator extends
final double tanφ = sinφ / cosφ;
final double B = cosφ * sinλ;
/*
- * Using Snyder's equation for calculating y, instead of the one used in Proj4.
+ * Using Snyder's equation for calculating y, instead of the one used in Proj.4.
* Potential problems when y and x = 90 degrees, but behaves ok in tests.
*/
if (dstPts != null) {
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -792,7 +792,7 @@ public abstract class AbstractMathTransf
}
/**
- * Concatenates in an optimized way this math transform with the given one.
+ * Concatenates or pre-concatenates in an optimized way this math transform with the given one.
* A new math transform is created to perform the combined transformation.
* The {@code applyOtherFirst} value determines the transformation order as bellow:
*
@@ -810,16 +810,20 @@ public abstract class AbstractMathTransf
* {@link ConcatenatedTransform}.
*
* <p>The default implementation always returns {@code null}. This method is ought to be overridden
- * by subclasses capable of concatenating some combination of transforms in a special way.
- * Examples are {@link ExponentialTransform1D} and {@link LogarithmicTransform1D}.</p>
+ * by subclasses capable of concatenating some combination of transforms in a special way.</p>
*
- * @param other the math transform to apply.
* @param applyOtherFirst {@code true} if the transformation order is {@code other} followed by {@code this}, or
* {@code false} if the transformation order is {@code this} followed by {@code other}.
+ * @param other the other math transform to (pre-)concatenate with this transform.
* @param factory the factory which is (indirectly) invoking this method, or {@code null} if none.
* @return the combined math transform, or {@code null} if no optimized combined transform is available.
+ * @throws FactoryException if an error occurred while combining the transforms.
+ *
+ * @see DefaultMathTransformFactory#createConcatenatedTransform(MathTransform, MathTransform)
+ *
+ * @since 0.8
*/
- MathTransform concatenate(MathTransform other, boolean applyOtherFirst, MathTransformFactory factory)
+ protected MathTransform tryConcatenate(boolean applyOtherFirst, MathTransform other, MathTransformFactory factory)
throws FactoryException
{
return null;
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -330,13 +330,13 @@ class ConcatenatedTransform extends Abst
* The main use case is Logarithmic vs Exponential transforms.
*/
if (tr1 instanceof AbstractMathTransform) {
- final MathTransform optimized = ((AbstractMathTransform) tr1).concatenate(tr2, false, factory);
+ final MathTransform optimized = ((AbstractMathTransform) tr1).tryConcatenate(false, tr2, factory);
if (optimized != null) {
return optimized;
}
}
if (tr2 instanceof AbstractMathTransform) {
- final MathTransform optimized = ((AbstractMathTransform) tr2).concatenate(tr1, true, factory);
+ final MathTransform optimized = ((AbstractMathTransform) tr2).tryConcatenate(true, tr1, factory);
if (optimized != null) {
return optimized;
}
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -42,6 +42,7 @@ import org.opengis.parameter.InvalidPara
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
@@ -61,6 +62,8 @@ import org.apache.sis.internal.referenci
import org.apache.sis.internal.referencing.provider.AbstractProvider;
import org.apache.sis.internal.referencing.provider.VerticalOffset;
import org.apache.sis.internal.referencing.provider.Providers;
+import org.apache.sis.internal.referencing.provider.GeographicToGeocentric;
+import org.apache.sis.internal.referencing.provider.GeocentricToGeographic;
import org.apache.sis.internal.referencing.Resources;
import org.apache.sis.internal.system.Loggers;
import org.apache.sis.metadata.iso.citation.Citations;
@@ -848,7 +851,8 @@ public class DefaultMathTransformFactory
* <p>The given method and parameters are stored in the {@link #provider} and {@link #parameters}
* fields respectively. The actual stored values may differ from the values given to this method.</p>
*
- * @param method description of the transform to be created, or {@code null} if unknown.
+ * @param factory the enclosing factory.
+ * @param method description of the transform to be created, or {@code null} if unknown.
* @return the exception if the operation failed, or {@code null} if none. This exception is not thrown now
* because the caller may succeed in creating the transform anyway, or otherwise may produce a more
* informative exception.
@@ -858,9 +862,23 @@ public class DefaultMathTransformFactory
* @see #getCompletedParameters()
*/
@SuppressWarnings("null")
- final RuntimeException completeParameters(OperationMethod method, final ParameterValueGroup userParams)
- throws IllegalArgumentException
+ final RuntimeException completeParameters(final DefaultMathTransformFactory factory, OperationMethod method,
+ final ParameterValueGroup userParams) throws FactoryException, IllegalArgumentException
{
+ /*
+ * The "Geographic/geocentric conversions" conversion (EPSG:9602) can be either:
+ *
+ * - "Ellipsoid_To_Geocentric"
+ * - "Geocentric_To_Ellipsoid"
+ *
+ * EPSG defines both by a single operation, but Apache SIS needs to distinguish them.
+ */
+ if (method instanceof AbstractProvider) {
+ final String alt = ((AbstractProvider) method).resolveAmbiguity(this);
+ if (alt != null) {
+ method = factory.getOperationMethod(alt);
+ }
+ }
provider = method;
parameters = userParams;
/*
@@ -896,8 +914,8 @@ public class DefaultMathTransformFactory
if (targetEllipsoid != null) n |= 2;
}
/*
- * Set the ellipsoid axis-length parameter values. Those parameters may appear in the source
- * ellipsoid, in the target ellipsoid or in both ellipsoids.
+ * 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;
@@ -1020,7 +1038,7 @@ public class DefaultMathTransformFactory
* since the standard place where to provide this information is in the ellipsoid object.
*/
if (context != null) {
- failure = context.completeParameters(method, parameters);
+ failure = context.completeParameters(this, method, parameters);
parameters = context.parameters;
method = context.provider;
}
@@ -1048,8 +1066,10 @@ public class DefaultMathTransformFactory
lastMethod.set(method); // May be null in case of failure, which is intended.
if (context != null) {
context.provider = null;
- // For now we conservatively reset the provider information to null. But if we choose to make
- // that information public in a future SIS version, then we would remove this code.
+ /*
+ * For now we conservatively reset the provider information to null. But if we choose to
+ * make that information public in a future SIS version, then we would remove this code.
+ */
}
}
return transform;
@@ -1190,13 +1210,71 @@ public class DefaultMathTransformFactory
* @return a conversion from the given source to the given target coordinate system.
* @throws FactoryException if the conversion can not be created.
*
+ * @deprecated Replaced by {@link #createCoordinateSystemChange(CoordinateSystem, CoordinateSystem, Ellipsoid)}
+ *
* @since 0.7
*/
+ @Deprecated
public MathTransform createCoordinateSystemChange(final CoordinateSystem source, final CoordinateSystem target)
throws FactoryException
{
+ return createCoordinateSystemChange(source, target, null);
+ }
+
+ /**
+ * Creates a math transform that represent a change of coordinate system. If exactly one argument is
+ * an {@linkplain org.apache.sis.referencing.cs.DefaultEllipsoidalCS ellipsoidal coordinate systems},
+ * then the {@code ellipsoid} argument is mandatory. In all other cases (including the case where both
+ * coordinate systems are ellipsoidal), the ellipsoid argument is ignored and can be {@code null}.
+ *
+ * <div class="note"><b>Design note:</b>
+ * this method does not accept separated ellipsoid arguments for {@code source} and {@code target} because
+ * this method should not be used for datum shifts. If the two given coordinate systems are ellipsoidal,
+ * then they are assumed to use the same ellipsoid. If different ellipsoids are desired, then a
+ * {@linkplain #createParameterizedTransform parameterized transform} like <cite>"Molodensky"</cite>,
+ * <cite>"Geocentric translations"</cite>, <cite>"Coordinate Frame Rotation"</cite> or
+ * <cite>"Position Vector transformation"</cite> should be used instead.</div>
+ *
+ * @param source the source coordinate system.
+ * @param target the target coordinate system.
+ * @param ellipsoid the ellipsoid of {@code EllipsoidalCS}, or {@code null} if none.
+ * @return a conversion from the given source to the given target coordinate system.
+ * @throws FactoryException if the conversion can not be created.
+ *
+ * @since 0.8
+ */
+ public MathTransform createCoordinateSystemChange(final CoordinateSystem source, final CoordinateSystem target,
+ final Ellipsoid ellipsoid) throws FactoryException
+ {
ArgumentChecks.ensureNonNull("source", source);
ArgumentChecks.ensureNonNull("target", target);
+ if (ellipsoid != null) {
+ final boolean isEllipsoidalSource = (source instanceof EllipsoidalCS);
+ if (isEllipsoidalSource != (target instanceof EllipsoidalCS)) {
+ /*
+ * For now we support only conversion between EllipsoidalCS and CartesianCS.
+ * But future Apache SIS versions could add support for conversions between
+ * EllipsoidalCS and SphericalCS or other coordinate systems.
+ */
+ if ((isEllipsoidalSource ? target : source) instanceof CartesianCS) {
+ final Context context = new Context();
+ final EllipsoidalCS cs;
+ final String operation;
+ if (isEllipsoidalSource) {
+ operation = GeographicToGeocentric.NAME;
+ context.setSource(cs = (EllipsoidalCS) source, ellipsoid);
+ context.setTarget(target);
+ } else {
+ operation = GeocentricToGeographic.NAME;
+ context.setSource(source);
+ context.setTarget(cs = (EllipsoidalCS) target, ellipsoid);
+ }
+ final ParameterValueGroup pg = getDefaultParameters(operation);
+ if (cs.getDimension() < 3) pg.parameter("dim").setValue(2); // Apache SIS specific parameter.
+ return createParameterizedTransform(pg, context);
+ }
+ }
+ }
return CoordinateSystemTransform.create(this, source, target);
// No need to use unique(…) here.
}
@@ -1313,6 +1391,9 @@ public class DefaultMathTransformFactory
* Creates a math transform object from a
* <a href="http://www.geoapi.org/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
* Known Text</cite> (WKT)</a>.
+ * If the given text contains non-fatal anomalies (unknown or unsupported WKT elements,
+ * inconsistent unit definitions, <i>etc.</i>), warnings may be reported in a
+ * {@linkplain java.util.logging.Logger logger} named {@code "org.apache.sis.io.wkt"}.
*
* @param text math transform encoded in Well-Known Text format.
* @return the math transform (never {@code null}).
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -915,7 +915,7 @@ next: while (--numPts >= 0) {
* </ul>
*/
@Override
- final MathTransform concatenate(final MathTransform other, final boolean applyOtherFirst,
+ protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
final MathTransformFactory factory) throws FactoryException
{
if (!applyOtherFirst && withHeight && other instanceof LinearTransform && other.getTargetDimensions() == 2) {
@@ -937,7 +937,7 @@ next: while (--numPts >= 0) {
}
}
}
- return super.concatenate(other, applyOtherFirst, factory);
+ return super.tryConcatenate(applyOtherFirst, other, factory);
}
/**
@@ -993,9 +993,12 @@ next: while (--numPts >= 0) {
* <li>Allow use of the more efficient {@link java.awt.geom.AffineTransform} before this transform
* instead than a transform based on a matrix of size 4×3.</li>
* </ul>
+ *
+ * @return the combined math transform, or {@code null} if no optimized combined transform is available.
+ * @throws FactoryException if an error occurred while combining the transforms.
*/
@Override
- final MathTransform concatenate(final MathTransform other, final boolean applyOtherFirst,
+ protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
final MathTransformFactory factory) throws FactoryException
{
if (applyOtherFirst && withHeight && other instanceof LinearTransform && other.getSourceDimensions() == 2) {
@@ -1017,7 +1020,7 @@ next: while (--numPts >= 0) {
}
}
}
- return super.concatenate(other, applyOtherFirst, factory);
+ return super.tryConcatenate(applyOtherFirst, other, factory);
}
/**
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1D.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1D.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1D.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -217,14 +217,14 @@ final class ExponentialTransform1D exten
* {@code MathTransform}. This implementation can optimize some concatenation with
* {@link LinearTransform1D} and {@link LogarithmicTransform1D}.
*
- * @param other the math transform to apply.
* @param applyOtherFirst {@code true} if the transformation order is {@code other} followed by {@code this}, or
* {@code false} if the transformation order is {@code this} followed by {@code other}.
+ * @param other the other math transform to (pre-)concatenate with this transform.
* @param factory the factory which is (indirectly) invoking this method, or {@code null} if none.
* @return the combined math transform, or {@code null} if no optimized combined transform is available.
*/
@Override
- final MathTransform concatenate(final MathTransform other, final boolean applyOtherFirst,
+ protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
final MathTransformFactory factory) throws FactoryException
{
if (other instanceof LinearTransform) {
@@ -243,7 +243,7 @@ final class ExponentialTransform1D exten
} else if (other instanceof LogarithmicTransform1D) {
return concatenateLog((LogarithmicTransform1D) other, applyOtherFirst);
}
- return super.concatenate(other, applyOtherFirst, factory);
+ return super.tryConcatenate(applyOtherFirst, other, factory);
}
/**
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1D.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1D.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1D.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -113,14 +113,14 @@ class LogarithmicTransform1D extends Abs
* {@code MathTransform}. This implementation can optimize some concatenation with
* {@link LinearTransform1D} and {@link ExponentialTransform1D}.
*
- * @param other the math transform to apply.
* @param applyOtherFirst {@code true} if the transformation order is {@code other} followed by {@code this}, or
* {@code false} if the transformation order is {@code this} followed by {@code other}.
+ * @param other the other math transform to (pre-)concatenate with this transform.
* @param factory the factory which is (indirectly) invoking this method, or {@code null} if none.
* @return the combined math transform, or {@code null} if no optimized combined transform is available.
*/
@Override
- final MathTransform concatenate(final MathTransform other, final boolean applyOtherFirst,
+ protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
final MathTransformFactory factory) throws FactoryException
{
if (other instanceof LinearTransform1D) {
@@ -138,7 +138,7 @@ class LogarithmicTransform1D extends Abs
} else if (other instanceof ExponentialTransform1D) {
return ((ExponentialTransform1D) other).concatenateLog(this, !applyOtherFirst);
}
- return super.concatenate(other, applyOtherFirst, factory);
+ return super.tryConcatenate(applyOtherFirst, other, factory);
}
/**
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -31,7 +31,7 @@ import org.apache.sis.util.ComparisonMod
* Future version may expand on that.
*
* <p>Before to make this class public (if we do), we need to revisit the class name, define parameters
- * and improve the {@link #concatenate(MathTransform, boolean, MathTransformFactory)} method.</p>
+ * and improve the {@link #tryConcatenate(boolean, MathTransform, MathTransformFactory)} method.</p>
*
* <div class="section">Serialization</div>
* Serialized instances of this class are not guaranteed to be compatible with future SIS versions.
@@ -171,21 +171,22 @@ final class PowerTransform1D extends Abs
/**
* Concatenates in an optimized way a {@link MathTransform} {@code other} to this {@code MathTransform}.
*
- * @param other the math transform to apply.
* @param applyOtherFirst {@code true} if the transformation order is {@code other} followed by {@code this},
* or {@code false} if the transformation order is {@code this} followed by {@code other}.
+ * @param other the other math transform to (pre-)concatenate with this transform.
* @param factory the factory which is (indirectly) invoking this method, or {@code null} if none.
* @return the combined math transform, or {@code null} if no optimized combined transform is available.
*/
@Override
- final MathTransform concatenate(final MathTransform other, final boolean applyOtherFirst,
+ protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
final MathTransformFactory factory) throws FactoryException
{
if (other instanceof PowerTransform1D) {
+ // Valid for both concatenation and pre-concatenation.
return create(power + ((PowerTransform1D) other).power);
}
// TODO: more optimization could go here for logarithmic and exponential cases.
- return super.concatenate(other, applyOtherFirst, factory);
+ return super.tryConcatenate(applyOtherFirst, other, factory);
}
/**
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -541,7 +541,7 @@ public class TransformSeparator {
* not accept arbitrary index for modified ordinates.
*/
if (containsAll(dimensions, lower, subLower) && containsAll(dimensions, subUpper, upper)) {
- return factory.createPassThroughTransform(subLower - lower, subTransform, upper - subUpper);
+ return factory.createPassThroughTransform(subLower - lower, subTransform, Math.max(0, upper - subUpper));
}
}
/*
@@ -679,7 +679,7 @@ reduce: for (int j=0; j <= numTgt; j
* @return {@code true} if the full range was found in the sequence.
*/
private static boolean containsAll(final int[] sequence, final int lower, int upper) {
- if (lower == upper) {
+ if (lower >= upper) {
return true;
}
if (sequence != null) {
Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -110,6 +110,34 @@ public final strictfp class AxisDirectio
}
/**
+ * Tests {@link AxisDirections#isCardinal(AxisDirection)}.
+ *
+ * @since 0.8
+ */
+ @Test
+ public void testIsCardinal() {
+ assertTrue (AxisDirections.isCardinal(NORTH));
+ assertFalse(AxisDirections.isCardinal(NORTH_NORTH_EAST));
+ assertFalse(AxisDirections.isCardinal(NORTH_EAST));
+ assertFalse(AxisDirections.isCardinal(EAST_NORTH_EAST));
+ assertTrue (AxisDirections.isCardinal(EAST));
+ assertFalse(AxisDirections.isCardinal(EAST_SOUTH_EAST));
+ assertFalse(AxisDirections.isCardinal(SOUTH_EAST));
+ assertFalse(AxisDirections.isCardinal(SOUTH_SOUTH_EAST));
+ assertTrue (AxisDirections.isCardinal(SOUTH));
+ assertFalse(AxisDirections.isCardinal(SOUTH_SOUTH_WEST));
+ assertFalse(AxisDirections.isCardinal(SOUTH_WEST));
+ assertFalse(AxisDirections.isCardinal(WEST_SOUTH_WEST));
+ assertTrue (AxisDirections.isCardinal(WEST));
+ assertFalse(AxisDirections.isCardinal(WEST_NORTH_WEST));
+ assertFalse(AxisDirections.isCardinal(NORTH_WEST));
+ assertFalse(AxisDirections.isCardinal(NORTH_NORTH_WEST));
+ assertFalse(AxisDirections.isCardinal(UP));
+ assertFalse(AxisDirections.isCardinal(FUTURE));
+ assertFalse(AxisDirections.isCardinal(OTHER));
+ }
+
+ /**
* Tests {@link AxisDirections#isIntercardinal(AxisDirection)}.
*/
@Test
Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolationTest.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolationTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolationTest.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -16,7 +16,6 @@
*/
package org.apache.sis.internal.referencing.provider;
-import java.net.URL;
import java.net.URISyntaxException;
import java.io.BufferedReader;
import java.io.IOException;
@@ -29,7 +28,6 @@ import org.opengis.geometry.Envelope;
import org.opengis.util.FactoryException;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.test.DependsOnMethod;
-import org.apache.sis.test.TestCase;
import org.apache.sis.test.TestStep;
import org.junit.Test;
@@ -48,7 +46,7 @@ import static org.opengis.test.Assert.*;
* @since 0.7
* @module
*/
-public final strictfp class FranceGeocentricInterpolationTest extends TestCase {
+public final strictfp class FranceGeocentricInterpolationTest extends DatumShiftTestCase {
/**
* Name of the file containing a small extract of the "{@code GR3DF97A.txt}" file.
* The amount of data in this test file is less than 0.14% of the original file.
@@ -140,9 +138,7 @@ public final strictfp class FranceGeocen
private static DatumShiftGridFile<Angle,Length> testGridAsFloats()
throws URISyntaxException, IOException, FactoryException, TransformException
{
- final URL url = FranceGeocentricInterpolationTest.class.getResource(TEST_FILE);
- assertNotNull("Test file \"" + TEST_FILE + "\" not found.", url);
- final Path file = Paths.get(url.toURI());
+ final Path file = getResource(TEST_FILE);
final DatumShiftGridFile.Float<Angle,Length> grid;
try (BufferedReader in = Files.newBufferedReader(file)) {
grid = FranceGeocentricInterpolation.load(in, file);
@@ -233,17 +229,15 @@ public final strictfp class FranceGeocen
@Test
@DependsOnMethod("testGrid")
public void testGetOrLoad() throws URISyntaxException, FactoryException, TransformException {
- final URL file = FranceGeocentricInterpolationTest.class.getResource(TEST_FILE);
- assertNotNull("Test file \"" + TEST_FILE + "\" not found.", file);
final DatumShiftGridFile<Angle,Length> grid = FranceGeocentricInterpolation.getOrLoad(
- Paths.get(file.toURI()), new double[] {
+ getResource(TEST_FILE), new double[] {
FranceGeocentricInterpolation.TX,
FranceGeocentricInterpolation.TY,
FranceGeocentricInterpolation.TZ},
FranceGeocentricInterpolation.PRECISION);
verifyGrid(grid);
assertSame("Expected a cached value.", grid, FranceGeocentricInterpolation.getOrLoad(
- Paths.get(file.toURI()), new double[] {
+ getResource(TEST_FILE), new double[] {
FranceGeocentricInterpolation.TX,
FranceGeocentricInterpolation.TY,
FranceGeocentricInterpolation.TZ},
Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -34,7 +34,7 @@ import static org.opengis.test.Assert.*;
* Tests the {@link Geographic3Dto2D} class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 0.8
* @since 0.7
* @module
*/
@@ -69,6 +69,18 @@ public final strictfp class Geographic3D
}
/**
+ * Tests {@link Geographic3Dto2D#redimension(int, int)}.
+ */
+ @Test
+ public void testRedimension() {
+ final Geographic3Dto2D provider = new Geographic3Dto2D();
+ assertSame ("3 → 2", provider, provider.redimension(3, 2));
+ assertEquals("2 → 3", Geographic2Dto3D.class, provider.redimension(2, 3).getClass());
+ assertEquals("3 → 3", GeographicRedimension.class, provider.redimension(3, 3).getClass());
+ assertEquals("2 → 2", GeographicRedimension.class, provider.redimension(2, 2).getClass());
+ }
+
+ /**
* Creates a "Geographic 2D to 3D → Geocentric → Affine → Geographic → Geographic 3D to 2D" chain.
* This method is used for integration tests.
*
Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -19,10 +19,8 @@ package org.apache.sis.internal.referenc
import java.util.Locale;
import java.io.BufferedWriter;
import java.io.IOException;
-import java.net.URL;
import java.net.URISyntaxException;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.nio.file.Files;
import javax.measure.quantity.Angle;
import org.opengis.geometry.Envelope;
@@ -32,7 +30,6 @@ import org.apache.sis.referencing.operat
import org.apache.sis.geometry.Envelope2D;
import org.apache.sis.geometry.Envelopes;
import org.apache.sis.measure.Units;
-import org.apache.sis.test.TestCase;
import org.junit.Test;
import static org.opengis.test.Assert.*;
@@ -47,7 +44,7 @@ import static org.opengis.test.Assert.*;
* @since 0.7
* @module
*/
-public final strictfp class NADCONTest extends TestCase {
+public final strictfp class NADCONTest extends DatumShiftTestCase {
/**
* Returns the sample point for a step in the transformation from NAD27 to NAD83.
* The sample point is the coordinate of Meades Ranch station, which was the point
@@ -102,12 +99,8 @@ public final strictfp class NADCONTest e
*/
@Test
public void testLoader() throws URISyntaxException, IOException, FactoryException, TransformException {
- final URL latitudeShifts = NADCONTest.class.getResource(TEST_FILE + ".laa");
- final URL longitudeShifts = NADCONTest.class.getResource(TEST_FILE + ".loa");
- assertNotNull("Test file \"" + TEST_FILE + ".laa\" not found.", latitudeShifts);
- assertNotNull("Test file \"" + TEST_FILE + ".loa\" not found.", longitudeShifts);
- testNADCON(Paths.get(latitudeShifts.toURI()),
- Paths.get(longitudeShifts.toURI()),
+ testNADCON(getResource(TEST_FILE + ".laa"), // Latitude shifts
+ getResource(TEST_FILE + ".loa"), // Longitude shifts
-99.75, -98.0, 37.5, 39.75);
}