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 2016/04/06 00:24:21 UTC
svn commit: r1737889 - in /sis/branches/JDK8/core:
sis-metadata/src/main/java/org/apache/sis/internal/metadata/
sis-metadata/src/main/java/org/apache/sis/io/wkt/
sis-referencing/src/main/java/org/apache/sis/internal/referencing/
sis-referencing/src/mai...
Author: desruisseaux
Date: Tue Apr 5 22:24:20 2016
New Revision: 1737889
URL: http://svn.apache.org/viewvc?rev=1737889&view=rev
Log:
Begin support of coordinate operation between CompoundCRS instances (still a work in progress).
Added:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java (with props)
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -111,13 +111,23 @@ public class ReferencingServices extends
public static final String OPERATION_TYPE_KEY = "operationType";
/**
- * The key for specifying a {@linkplain org.opengis.referencing.operation.MathTransformFactory}
- * instance to use for the construction of a geodetic object. This is usually not needed for CRS
- * construction, except in the special case of a derived CRS created from a defining conversion.
+ * The key for specifying a {@link MathTransformFactory} instance to use for geodetic object constructions.
+ * This is usually not needed for CRS construction, except in the special case of a derived CRS created
+ * from a defining conversion.
*/
public static final String MT_FACTORY = "mtFactory";
/**
+ * The key for specifying a {@link CRSFactory} instance to use for geodetic object constructions.
+ */
+ public static final String CRS_FACTORY = "crsFactory";
+
+ /**
+ * The key for specifying a {@link CSFactory} instance to use for geodetic object constructions.
+ */
+ public static final String CS_FACTORY = "csFactory";
+
+ /**
* The separator character between an identifier and its namespace in the argument given to
* {@link #getOperationMethod(String)}. For example this is the separator in {@code "EPSG:9807"}.
*
@@ -553,11 +563,15 @@ public class ReferencingServices extends
*
* @param properties The default properties.
* @param mtFactory The math transform factory to use.
+ * @param crsFactory The factory to use if the operation factory needs to create CRS for intermediate steps.
+ * @param csFactory The factory to use if the operation factory needs to create CS for intermediate steps.
* @return The coordinate operation factory to use.
*
- * @since 0.6
+ * @since 0.7
*/
- public CoordinateOperationFactory getCoordinateOperationFactory(Map<String,?> properties, MathTransformFactory mtFactory) {
+ public CoordinateOperationFactory getCoordinateOperationFactory(Map<String,?> properties,
+ final MathTransformFactory mtFactory, final CRSFactory crsFactory, final CSFactory csFactory)
+ {
/*
* The check for 'properties' and 'mtFactory' is performed by the ServicesForMetadata subclass. If this code is
* executed, this means that the "sis-referencing" module is not on the classpath, in which case we do not know
Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -203,7 +203,7 @@ final class GeodeticObjectParser extends
csFactory = (CSFactory) factories;
datumFactory = (DatumFactory) factories;
referencing = ReferencingServices.getInstance();
- opFactory = referencing.getCoordinateOperationFactory(defaultProperties, mtFactory);
+ opFactory = referencing.getCoordinateOperationFactory(defaultProperties, mtFactory, crsFactory, csFactory);
transliterator = Transliterator.DEFAULT;
usesCommonUnits = false;
ignoreAxes = false;
@@ -240,7 +240,7 @@ final class GeodeticObjectParser extends
if (f != null) {
opFactory = (CoordinateOperationFactory) f;
} else {
- opFactory = referencing.getCoordinateOperationFactory(null, mtFactory);
+ opFactory = referencing.getCoordinateOperationFactory(null, mtFactory, crsFactory, csFactory);
factories.put(CoordinateOperationFactory.class, opFactory);
}
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -17,8 +17,10 @@
package org.apache.sis.internal.referencing;
import java.util.Map;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.Collection;
+import java.util.Collections;
import java.util.Locale;
import javax.measure.unit.Unit;
import javax.measure.quantity.Length;
@@ -34,6 +36,8 @@ import org.opengis.referencing.crs.Tempo
import org.opengis.referencing.crs.VerticalCRS;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.CRSFactory;
+import org.opengis.referencing.cs.CSFactory;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.CoordinateSystem;
@@ -623,17 +627,30 @@ public final class ServicesForMetadata e
*
* @param properties The default properties.
* @param mtFactory The math transform factory to use.
+ * @param crsFactory The factory to use if the operation factory needs to create CRS for intermediate steps.
+ * @param csFactory The factory to use if the operation factory needs to create CS for intermediate steps.
* @return The coordinate operation factory to use.
*
- * @since 0.6
+ * @since 0.7
*/
@Override
- public CoordinateOperationFactory getCoordinateOperationFactory(Map<String,?> properties, MathTransformFactory mtFactory) {
- if (Containers.isNullOrEmpty(properties) && DefaultFactories.isDefaultInstance(MathTransformFactory.class, mtFactory)) {
- return CoordinateOperations.factory();
- } else {
- return new DefaultCoordinateOperationFactory(properties, mtFactory);
+ public CoordinateOperationFactory getCoordinateOperationFactory(Map<String,?> properties,
+ final MathTransformFactory mtFactory, final CRSFactory crsFactory, final CSFactory csFactory)
+ {
+ if (Containers.isNullOrEmpty(properties)) {
+ if (DefaultFactories.isDefaultInstance(MathTransformFactory.class, mtFactory) &&
+ DefaultFactories.isDefaultInstance(CRSFactory.class, crsFactory) &&
+ DefaultFactories.isDefaultInstance(CSFactory.class, csFactory))
+ {
+ return CoordinateOperations.factory();
+ }
+ properties = Collections.emptyMap();
}
+ final HashMap<String,Object> p = new HashMap<>(properties);
+ p.putIfAbsent(CRS_FACTORY, crsFactory);
+ p.putIfAbsent(CS_FACTORY, csFactory);
+ properties = p;
+ return new DefaultCoordinateOperationFactory(properties, mtFactory);
}
/**
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -18,6 +18,7 @@ package org.apache.sis.referencing.opera
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.IdentifiedObject;
+import org.apache.sis.referencing.AbstractIdentifiedObject;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.Classes;
@@ -78,24 +79,36 @@ final class CRSPair {
}
/**
- * Returns a name for the given object, truncating it if needed.
+ * Returns the name of the GeoAPI interface implemented by the specified object,
+ * followed by the name between brackets.
*/
- static String shortName(final IdentifiedObject object) {
- String name = IdentifiedObjects.getName(object, null);
- if (name == null) {
- name = Classes.getShortClassName(object);
+ static String label(final IdentifiedObject object) {
+ if (object == null) {
+ return null;
+ }
+ Class<?> type;
+ if (object instanceof AbstractIdentifiedObject) {
+ type = ((AbstractIdentifiedObject) object).getInterface();
} else {
- int i = 30; // Arbitrary length threshold.
+ type = object.getClass();
+ final Class<?>[] c = Classes.getLeafInterfaces(type, IdentifiedObject.class);
+ if (c.length != 0) type = c[0];
+ }
+ String label = Classes.getShortName(type);
+ String name = IdentifiedObjects.getName(object, null);
+ if (name != null) {
+ int i = 30; // Arbitrary length threshold.
if (name.length() >= i) {
- while (i > 15) { // Arbitrary minimal length.
+ while (i > 15) { // Arbitrary minimal length.
final int c = name.codePointBefore(i);
if (Character.isSpaceChar(c)) break;
i -= Character.charCount(c);
}
name = CharSequences.trimWhitespaces(name, 0, i).toString() + '…';
}
+ label = label + "[“" + name + "”]";
}
- return name;
+ return label;
}
/**
@@ -103,6 +116,6 @@ final class CRSPair {
*/
@Override
public String toString() {
- return shortName(sourceCRS) + " → " + shortName(targetCRS);
+ return label(sourceCRS) + " → " + label(targetCRS);
}
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -18,6 +18,7 @@ package org.apache.sis.referencing.opera
import java.util.Map;
import java.util.HashMap;
+import java.util.List;
import java.util.Collections;
import javax.measure.unit.Unit;
import javax.measure.quantity.Duration;
@@ -56,9 +57,6 @@ import org.apache.sis.referencing.Common
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.referencing.NamedIdentifier;
import org.apache.sis.referencing.cs.CoordinateSystems;
-import org.apache.sis.referencing.cs.DefaultVerticalCS;
-import org.apache.sis.referencing.crs.DefaultVerticalCRS;
-import org.apache.sis.referencing.crs.DefaultGeographicCRS;
import org.apache.sis.referencing.datum.BursaWolfParameters;
import org.apache.sis.referencing.datum.DefaultGeodeticDatum;
import org.apache.sis.referencing.operation.matrix.Matrices;
@@ -177,6 +175,21 @@ public class CoordinateOperationInferenc
private double desiredAccuracy;
/**
+ * Identifiers used as the basis for identifier of CRS used as an intermediate step.
+ * The values can be of two kinds:
+ *
+ * <ul>
+ * <li>If the value is an instance of {@link Integer}, then this is the number
+ * of identifiers derived from the identifier associated to the key.</li>
+ * <li>Otherwise the key is itself an {@link Indentifier} derived from another
+ * identifier, and the value is that identifier.</li>
+ * </ul>
+ *
+ * @see #derivedFrom(IdentifiedObject)
+ */
+ private final Map<Identifier,Object> identifierOfStepCRS;
+
+ /**
* The pair of source and target CRS for which we already searched a coordinate operation.
* This is used as a safety against infinite recursivity.
*/
@@ -200,7 +213,8 @@ public class CoordinateOperationInferenc
desiredAccuracy = context.getDesiredAccuracy();
bbox = context.getGeographicBoundingBox();
}
- previousSearches = new HashMap<>(4);
+ identifierOfStepCRS = new HashMap<>(8);
+ previousSearches = new HashMap<>(8);
}
/**
@@ -235,29 +249,6 @@ public class CoordinateOperationInferenc
}
////////////////////////////////////////////////////////////////////////////////
//// ////
- //// Compound → various CRS ////
- //// ////
- //// We check CompoundCRS first because experience shows that it produces ////
- //// simpler transformation chains than if we check them last. ////
- //// ////
- ////////////////////////////////////////////////////////////////////////////////
- if (sourceCRS instanceof CompoundCRS) {
- final CompoundCRS source = (CompoundCRS) sourceCRS;
- if (targetCRS instanceof CompoundCRS) {
-// return createOperationStep(source, (CompoundCRS) targetCRS);
- }
- if (targetCRS instanceof SingleCRS) {
-// return createOperationStep(source, (SingleCRS) targetCRS);
- }
- }
- if (targetCRS instanceof CompoundCRS) {
- final CompoundCRS target = (CompoundCRS) targetCRS;
- if (sourceCRS instanceof SingleCRS) {
-// return createOperationStep((SingleCRS) sourceCRS, target);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //// ////
//// Derived → any Single CRS ////
//// ////
////////////////////////////////////////////////////////////////////////////////
@@ -317,6 +308,14 @@ public class CoordinateOperationInferenc
return createOperationStep(source, (TemporalCRS) targetCRS);
}
}
+ ////////////////////////////////////////////////////////////////////////////////
+ //// ////
+ //// Compound ↔ various CRS ////
+ //// ////
+ ////////////////////////////////////////////////////////////////////////////////
+ if (sourceCRS instanceof CompoundCRS || targetCRS instanceof CompoundCRS) {
+ return decompose(sourceCRS, targetCRS);
+ }
throw new OperationNotFoundException(notFoundMessage(sourceCRS, targetCRS));
}
@@ -585,7 +584,8 @@ public class CoordinateOperationInferenc
if (!(interpolationCS instanceof EllipsoidalCS)) {
final EllipsoidalCS cs = CommonCRS.WGS84.geographic3D().getCoordinateSystem();
if (!equalsIgnoreMetadata(interpolationCS, cs)) {
- step1 = createOperation(sourceCRS, new DefaultGeographicCRS(sameNameAs(sourceCRS), sourceCRS.getDatum(), cs));
+ step1 = createOperation(sourceCRS, factorySIS.getCRSFactory()
+ .createGeographicCRS(derivedFrom(sourceCRS), sourceCRS.getDatum(), cs));
interpolationCRS = step1.getTargetCRS();
interpolationCS = interpolationCRS.getCoordinateSystem();
}
@@ -614,11 +614,12 @@ public class CoordinateOperationInferenc
heightCS = heightCRS.getCoordinateSystem();
isEllipsoidalHeight = equalsIgnoreMetadata(heightCS.getAxis(0), expectedAxis);
if (!isEllipsoidalHeight) {
- heightCS = new DefaultVerticalCS(sameNameAs(heightCS), expectedAxis);
+ heightCS = factorySIS.getCSFactory().createVerticalCS(derivedFrom(heightCS), expectedAxis);
}
}
if (!isEllipsoidalHeight) { // 'false' if we need to change datum, unit or axis direction.
- heightCRS = new DefaultVerticalCRS(sameNameAs(heightCRS), CommonCRS.Vertical.ELLIPSOIDAL.datum(), heightCS);
+ heightCRS = factorySIS.getCRSFactory()
+ .createVerticalCRS(derivedFrom(heightCRS), CommonCRS.Vertical.ELLIPSOIDAL.datum(), heightCS);
}
if (heightCRS != targetCRS) {
step3 = createOperation(heightCRS, targetCRS); // May need interpolationCRS for performing datum change.
@@ -726,6 +727,55 @@ public class CoordinateOperationInferenc
}
/**
+ * Creates an operation between at least one {@code CompoundCRS} (usually the source) and an arbitrary CRS.
+ * The default implementation tries to invoke the {@link #createOperation createOperation(…)} method with
+ * various combinations of source and target components. A preference is given for components of the same
+ * type (e.g. source {@link GeodeticCRS} with target {@code GeodeticCRS}, <i>etc.</i>).
+ *
+ * @param sourceCRS input coordinate reference system.
+ * @param targetCRS output coordinate reference system.
+ * @return a coordinate operation from {@code sourceCRS} to {@code targetCRS}.
+ * @throws FactoryException if the operation can not be constructed.
+ */
+ private CoordinateOperation decompose(final CoordinateReferenceSystem sourceCRS,
+ final CoordinateReferenceSystem targetCRS)
+ throws FactoryException
+ {
+ final List<SingleCRS> sources = CRS.getSingleComponents(sourceCRS);
+ final List<SingleCRS> targets = CRS.getSingleComponents(targetCRS);
+ final SourceComponent[] infos = new SourceComponent[targets.size()];
+ final boolean[] sourceIsUsed = new boolean[sources.size()];
+ /*
+ * Operations found are stored in 'infos', but are not yet wrapped in PassThroughOperations.
+ * We need to know first if some ordinate values need reordering for matching the target CRS
+ * order. We also need to know if any source ordinates should be dropped.
+ */
+ for (int i=0; i<infos.length; i++) {
+ if ((infos[i] = SourceComponent.create(this, sourceIsUsed, sources, targets.get(i))) == null) {
+ throw new OperationNotFoundException(notFoundMessage(sourceCRS, targetCRS));
+ }
+ }
+ /*
+ * A coordinate operation has been found for every target component CRS.
+ * Some reordering of ordinate values may be needed, and some coordinates may need to be dropped.
+ */
+ final Matrix select = SourceComponent.sourceToSelected(sourceCRS.getCoordinateSystem().getDimension(), infos);
+ throw new UnsupportedOperationException(); // TODO continue work from here.
+ }
+
+
+
+
+
+ /////////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////////
+ //////////// ////////////
+ //////////// M I S C E L L A N E O U S ////////////
+ //////////// ////////////
+ /////////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////////
+
+ /**
* Creates a coordinate operation from a matrix, which usually describes an affine transform.
* A default {@link OperationMethod} object is given to this transform. In the special case
* where the {@code name} identifier is {@link #DATUM_SHIFT} or {@link #ELLIPSOID_CHANGE},
@@ -996,28 +1046,46 @@ public class CoordinateOperationInferenc
}
/**
- * Returns the name of the given object in a singleton map.
- */
- private static Map<String,?> sameNameAs(final IdentifiedObject object) {
- return Collections.singletonMap(IdentifiedObject.NAME_KEY, object.getName());
+ * Returns a name for an object derived from the specified one.
+ * This method builds a name of the form "{@literal <original identifier>} (step 1)"
+ * where "(step 1)" may be replaced by "(step 2)", "(step 3)", <i>etc.</i> if this
+ * method has already been invoked for the same identifier (directly or indirectly).
+ */
+ private Map<String,?> derivedFrom(final IdentifiedObject object) {
+ Identifier oldID = object.getName();
+ Object p = identifierOfStepCRS.get(oldID);
+ if (p instanceof Identifier) {
+ oldID = (Identifier) p;
+ p = identifierOfStepCRS.get(oldID);
+ }
+ final int count = (p != null) ? (Integer) p + 1 : 1;
+ final Identifier newID = new NamedIdentifier(Citations.SIS, oldID.getCode() + " (step " + count + ')');
+ identifierOfStepCRS.put(newID, oldID);
+ identifierOfStepCRS.put(oldID, count);
+
+ final Map<String,Object> properties = new HashMap<>(4);
+ properties.put(IdentifiedObject.NAME_KEY, newID);
+ properties.put(IdentifiedObject.REMARKS_KEY, Vocabulary.formatInternational(
+ Vocabulary.Keys.DerivedFrom_1, CRSPair.label(object)));
+ return properties;
}
/**
* Returns a name for a transformation between two CRS.
*/
private static Map<String,?> defaultName(CoordinateReferenceSystem source, CoordinateReferenceSystem target) {
- return properties(CRSPair.shortName(source) + " → " + CRSPair.shortName(target));
+ return properties(CRSPair.label(source) + " → " + CRSPair.label(target));
}
/**
* Returns an error message for "No path found from sourceCRS to targetCRS".
* This is used for the construction of {@link OperationNotFoundException}.
*
- * @param source The source CRS.
- * @param target The target CRS.
+ * @param source the source CRS.
+ * @param target the target CRS.
* @return A default error message.
*/
private static String notFoundMessage(final IdentifiedObject source, final IdentifiedObject target) {
- return Errors.format(Errors.Keys.CoordinateOperationNotFound_2, CRSPair.shortName(source), CRSPair.shortName(target));
+ return Errors.format(Errors.Keys.CoordinateOperationNotFound_2, CRSPair.label(source), CRSPair.label(target));
}
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -30,6 +30,8 @@ import org.opengis.referencing.crs.Coord
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.crs.SingleCRS;
+import org.opengis.referencing.crs.CRSFactory;
+import org.opengis.referencing.cs.CSFactory;
import org.opengis.referencing.datum.Datum;
import org.apache.sis.internal.referencing.MergedProperties;
import org.apache.sis.internal.metadata.ReferencingServices;
@@ -44,6 +46,7 @@ import org.apache.sis.util.iso.AbstractF
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.Classes;
import org.apache.sis.util.NullArgumentException;
import org.apache.sis.util.Utilities;
@@ -85,6 +88,22 @@ public class DefaultCoordinateOperationF
private final Map<String,?> defaultProperties;
/**
+ * The factory to use if {@link CoordinateOperationInference} needs to create CRS for intermediate steps.
+ * Will be created only when first needed.
+ *
+ * @see #getCRSFactory()
+ */
+ private volatile CRSFactory crsFactory;
+
+ /**
+ * The factory to use if {@link CoordinateOperationInference} needs to create CS for intermediate steps.
+ * Will be created only when first needed.
+ *
+ * @see #getCSFactory()
+ */
+ private volatile CSFactory csFactory;
+
+ /**
* The math transform factory. Will be created only when first needed.
*
* @see #getMathTransformFactory()
@@ -101,8 +120,7 @@ public class DefaultCoordinateOperationF
* Constructs a factory with no default properties.
*/
public DefaultCoordinateOperationFactory() {
- defaultProperties = Collections.emptyMap();
- pool = new WeakHashSet<>(IdentifiedObject.class);
+ this(null, null);
}
/**
@@ -110,19 +128,36 @@ public class DefaultCoordinateOperationF
* {@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.
*
- * @param properties The default properties, or {@code null} if none.
- * @param mtFactory The factory to use for creating
+ * @param properties the default properties, or {@code null} if none.
+ * @param factory the factory to use for creating
* {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform math transforms},
* or {@code null} for the default factory.
*/
- public DefaultCoordinateOperationFactory(Map<String,?> properties, final MathTransformFactory mtFactory) {
+ public DefaultCoordinateOperationFactory(Map<String,?> properties, final MathTransformFactory factory) {
if (properties == null || properties.isEmpty()) {
properties = Collections.emptyMap();
} else {
- properties = CollectionsExt.compact(new HashMap<String,Object>(properties));
+ String key = null;
+ Object value = null;
+ properties = new HashMap<>(properties);
+ /*
+ * Following use of properties is an undocumented feature for now. Current version documents only
+ * MathTransformFactory because math transforms are intimately related to coordinate operations.
+ */
+ try {
+ crsFactory = (CRSFactory) (value = properties.remove(key = ReferencingServices.CRS_FACTORY));
+ csFactory = (CSFactory) (value = properties.remove(key = ReferencingServices.CS_FACTORY));
+ mtFactory = (MathTransformFactory) (value = properties.remove(key = ReferencingServices.MT_FACTORY));
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException(Errors.getResources(properties)
+ .getString(Errors.Keys.IllegalPropertyClass_2, key, Classes.getClass(value)));
+ }
+ properties = CollectionsExt.compact(properties);
}
defaultProperties = properties;
- this.mtFactory = mtFactory;
+ if (factory != null) {
+ mtFactory = factory;
+ }
pool = new WeakHashSet<>(IdentifiedObject.class);
}
@@ -148,6 +183,28 @@ public class DefaultCoordinateOperationF
}
/**
+ * Returns the factory to use if {@link CoordinateOperationInference} needs to create CRS for intermediate steps.
+ */
+ final CRSFactory getCRSFactory() {
+ CRSFactory factory = crsFactory;
+ if (factory == null) {
+ crsFactory = factory = DefaultFactories.forBuildin(CRSFactory.class);
+ }
+ return factory;
+ }
+
+ /**
+ * Returns the factory to use if {@link CoordinateOperationInference} needs to create CS for intermediate steps.
+ */
+ final CSFactory getCSFactory() {
+ CSFactory factory = csFactory;
+ if (factory == null) {
+ csFactory = factory = DefaultFactories.forBuildin(CSFactory.class);
+ }
+ return factory;
+ }
+
+ /**
* Returns the underlying math transform factory. This factory is used for constructing {@link MathTransform}
* dependencies for all {@linkplain AbstractCoordinateOperation coordinate operations} instances.
*
Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java?rev=1737889&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -0,0 +1,188 @@
+/*
+ * 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.operation;
+
+import java.util.List;
+import org.opengis.referencing.crs.*;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.OperationNotFoundException;
+import org.opengis.util.FactoryException;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+
+
+/**
+ * Information about the relationship between a source component and a target component
+ * in {@code CompoundCRS} instances.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.7
+ * @version 0.7
+ * @module
+ */
+final class SourceComponent {
+ /**
+ * Types of target CRS, together with the type of CRS that may be used as the source for that target.
+ * For each array {@code COMPATIBLE_TYPES[i]}, the first element (i.e. {@code COMPATIBLE_TYPES[i][0]})
+ * is the target CRS and the whole array (including the first element) gives the valid source CRS type,
+ * if preference order.
+ *
+ * <div class="note"><b>Example:</b>
+ * if a target CRS is of type {@link VerticalCRS}, then the source CRS may be another {@code VerticalCRS}
+ * or a {@link GeodeticCRS}. The geodetic CRS is possible because it may be three-dimensional.</div>
+ *
+ * {@link ProjectedCRS} and {@link DerivedCRS} are not in this list because we rather use their base CRS
+ * as the criterion for determining their type.
+ */
+ private static final Class<?>[][] COMPATIBLE_TYPES = {
+ {GeodeticCRS.class},
+ {VerticalCRS.class, GeodeticCRS.class},
+ {TemporalCRS.class},
+ {ParametricCRS.class},
+ {EngineeringCRS.class},
+ {ImageCRS.class}
+ };
+
+ /**
+ * Returns the class of the given CRS after unwrapping derived and projected CRS.
+ * The returned type is for use with {@link #COMPATIBLE_TYPES}.
+ */
+ private static Class<?> type(SingleCRS crs) {
+ while (crs instanceof GeneralDerivedCRS) {
+ crs = ((GeneralDerivedCRS) crs).getBaseCRS();
+ }
+ return crs.getClass();
+ }
+
+ /**
+ * The coordinate operation between a source component and a target component.
+ */
+ final CoordinateOperation operation;
+
+ /**
+ * Returns the first dimension (inclusive) where the source component CRS begins in the source compound CRS.
+ */
+ private final int startAtDimension;
+
+ /**
+ * Returns the last dimension (exclusive) where the source component CRS ends in the source compound CRS.
+ */
+ private final int endAtDimension;
+
+ /**
+ * Creates a new instance containing the given information.
+ */
+ private SourceComponent(final CoordinateOperation operation, final int startAtDimension, final int endAtDimension) {
+ this.operation = operation;
+ this.startAtDimension = startAtDimension;
+ this.endAtDimension = endAtDimension;
+ }
+
+ /**
+ * Searches in given list of source components for an operation capable to convert or transform coordinates
+ * to the given target CRS. If no such operation can be found, then this method returns {@code null}.
+ *
+ * @param caller the object which is inferring a coordinate operation.
+ * @param sourceIsUsed flags for keeping trace of which source has been used.
+ * @param sources all components of the source CRS.
+ * @param target one component of the target CRS.
+ * @return information about a coordinate operation from a source CRS to the given target CRS, or {@code null}.
+ * @throws FactoryException if an error occurred while grabbing a coordinate operation.
+ */
+ static SourceComponent create(final CoordinateOperationInference caller, final boolean[] sourceIsUsed,
+ final List<SingleCRS> sources, final SingleCRS target) throws FactoryException
+ {
+ OperationNotFoundException failure = null;
+ final Class<?> targetType = type(target);
+ for (final Class<?>[] sourceTypes : COMPATIBLE_TYPES) {
+ if (sourceTypes[0].isAssignableFrom(targetType)) {
+ int startAtDimension;
+ int endAtDimension = 0;
+ for (final Class<?> sourceType : sourceTypes) {
+ for (int i=0; i<sourceIsUsed.length; i++) {
+ final SingleCRS source = sources.get(i);
+ startAtDimension = endAtDimension;
+ endAtDimension += source.getCoordinateSystem().getDimension();
+ if (!sourceIsUsed[i] && sourceType.isInstance(source)) {
+ final CoordinateOperation operation;
+ try {
+ operation = caller.createOperation(source, target);
+ } catch (OperationNotFoundException exception) {
+ if (failure == null) {
+ failure = exception;
+ } else {
+ failure.addSuppressed(exception);
+ }
+ continue;
+ }
+ /*
+ * Found an operation. Remove the source component from the list because each source
+ * should be used at most once by SourceComponent. Note that the same source may still
+ * be used again in another context if that source is also an interpolation CRS.
+ *
+ * EXAMPLE: consider a coordinate operation from (GeodeticCRS₁, VerticalCRS₁) source
+ * to (GeodeticCRS₂, VerticalCRS₂) target. The source GeodeticCRS₁ should be mapped
+ * to exactly one target component (which is GeodeticCRS₂) and VerticalCRS₁ mapped
+ * to VerticalCRS₂. But the operation on vertical coordinates may need GeodeticCRS₁
+ * for doing its work, so GeodeticCRS₁ is needed twice. However when needed for the
+ * vertical coordinate operation, the GeodeticCRS₁ is used as an "interpolation CRS".
+ * Interpolation CRS are handled in other code paths; it is not the business of this
+ * SourceComponent class to care about them. From the point of view of this class,
+ * GeodeticCRS₁ is used only once.
+ */
+ sourceIsUsed[i] = true;
+ if (failure != null) {
+ Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
+ CoordinateOperationInference.class, "decompose", failure);
+ }
+ return new SourceComponent(operation, startAtDimension, endAtDimension);
+ }
+ }
+ }
+ }
+ }
+ if (failure != null) {
+ throw failure;
+ }
+ return null;
+ }
+
+ /**
+ * Returns a matrix for an affine transform from all source coordinates to the coordinates of the
+ * source components selected for participating in the coordinate operation.
+ *
+ * @param sourceDimensions number of dimension of the source {@code CompoundCRS}.
+ * @param selected all {@code SourceComponent} instances needed for the target {@code CompoundCRS}.
+ */
+ static Matrix sourceToSelected(final int sourceDimensions, final SourceComponent[] selected) {
+ int selectedDimensions = 0;
+ for (final SourceComponent component : selected) {
+ selectedDimensions += component.endAtDimension - component.startAtDimension;
+ }
+ final Matrix select = Matrices.createZero(selectedDimensions + 1, sourceDimensions + 1);
+ select.setElement(selectedDimensions, sourceDimensions, 1);
+ int j = 0;
+ for (final SourceComponent component : selected) {
+ for (int i=component.startAtDimension; i<component.endAtDimension; i++) {
+ select.setElement(j++, i, 1);
+ }
+ }
+ return select;
+ }
+}
Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -370,10 +370,10 @@ next: for (final Class<?> candidat
for (int i=0; i<count; i++) {
final Class<?> old = types[i];
if (candidate.isAssignableFrom(old)) {
- continue next; // A more specialized interface already exists.
+ continue next; // A more specialized interface already exists.
}
if (old.isAssignableFrom(candidate)) {
- types[i] = candidate; // This interface specializes a previous interface.
+ types[i] = candidate; // This interface specializes a previous interface.
continue next;
}
}
@@ -501,14 +501,14 @@ next: for (final Class<?> candidat
*/
public static Set<Class<?>> findCommonInterfaces(final Class<?> c1, final Class<?> c2) {
final Set<Class<?>> interfaces = getInterfaceSet(c1);
- final Set<Class<?>> buffer = getInterfaceSet(c2); // To be recycled.
+ final Set<Class<?>> buffer = getInterfaceSet(c2); // To be recycled.
if (interfaces == null || buffer == null) {
return Collections.emptySet();
}
interfaces.retainAll(buffer);
for (Iterator<Class<?>> it=interfaces.iterator(); it.hasNext();) {
final Class<?> candidate = it.next();
- buffer.clear(); // Safe because the buffer can not be Collections.EMPTY_SET at this point.
+ buffer.clear(); // Safe because the buffer can not be Collections.EMPTY_SET at this point.
getInterfaceSet(candidate, buffer);
if (interfaces.removeAll(buffer)) {
it = interfaces.iterator();
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java [UTF-8] Tue Apr 5 22:24:20 2016
@@ -191,6 +191,11 @@ public final class Vocabulary extends In
public static final short DefaultValue = 71;
/**
+ * Derived from {0}
+ */
+ public static final short DerivedFrom_1 = 108;
+
+ /**
* Description
*/
public static final short Description = 75;
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties [ISO-8859-1] Tue Apr 5 22:24:20 2016
@@ -41,6 +41,7 @@ Datum = Datum
DatumShift = Datum shift
DaylightTime = Daylight time
DefaultValue = Default value
+DerivedFrom_1 = Derived from {0}
Description = Description
Destination = Destination
Dimensions = Dimensions
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties?rev=1737889&r1=1737888&r2=1737889&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties [ISO-8859-1] Tue Apr 5 22:24:20 2016
@@ -48,6 +48,7 @@ Datum = R\u00e9f\u00e9
DatumShift = Changement de r\u00e9f\u00e9rentiel
DaylightTime = Heure normale
DefaultValue = Valeur par d\u00e9faut
+DerivedFrom_1 = D\u00e9riv\u00e9 de {0}
Description = Description
Destination = Destination
Dimensions = Dimensions