Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -25,16 +25,20 @@ import org.opengis.util.NoSuchIdentifier import org.opengis.parameter.ParameterValueGroup; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.referencing.operation.*; +import org.opengis.referencing.AuthorityFactory; import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.crs.CoordinateReferenceSystem; 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; 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.referencing.CRS; import org.apache.sis.referencing.factory.InvalidGeodeticParameterException; import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory; @@ -44,6 +48,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; @@ -77,6 +82,12 @@ import org.apache.sis.util.Utilities; */ public class DefaultCoordinateOperationFactory extends AbstractFactory implements CoordinateOperationFactory { /** + * Whether this class is allowed to use the EPSG authority factory for searching coordinate operation paths. + * This flag should always be {@code true}, except temporarily for testing purposes. + */ + static final boolean USE_EPSG_FACTORY = true; + + /** * The default properties, or an empty map if none. This map shall not change after construction in * order to allow usage without synchronization in multi-thread context. But we do not need to wrap * in a unmodifiable map since {@code DefaultCoordinateOperationFactory} does not provide public @@ -85,6 +96,22 @@ public class DefaultCoordinateOperationF private final Map<String,?> defaultProperties; /** + * The factory to use if {@link CoordinateOperationFinder} 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 CoordinateOperationFinder} 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 +128,7 @@ public class DefaultCoordinateOperationF * Constructs a factory with no default properties. */ public DefaultCoordinateOperationFactory() { - defaultProperties = Collections.emptyMap(); - pool = new WeakHashSet<IdentifiedObject>(IdentifiedObject.class); + this(null, null); } /** @@ -110,19 +136,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<String,Object>(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.IllegalPropertyValueClass_2, key, Classes.getClass(value))); + } + properties = CollectionsExt.compact(properties); } defaultProperties = properties; - this.mtFactory = mtFactory; + if (factory != null) { + mtFactory = factory; + } pool = new WeakHashSet<IdentifiedObject>(IdentifiedObject.class); } @@ -148,6 +191,28 @@ public class DefaultCoordinateOperationF } /** + * Returns the factory to use if {@link CoordinateOperationFinder} 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 CoordinateOperationFinder} 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. * @@ -485,7 +550,7 @@ next: for (int i=components.size(); -- } /* * Now create the coordinate operation of the requested type. If we can not find a concrete class for the - * requested type, we will instantiate an SingleOperation in last resort. The later action is a departure + * requested type, we will instantiate a SingleOperation in last resort. The later action is a departure * from ISO 19111 since 'SingleOperation' is conceptually abstract. But we do that as a way to said that * we are missing this important piece of information but still go ahead. * @@ -565,6 +630,9 @@ next: for (int i=components.size(); -- public CoordinateOperation createConcatenatedOperation(final Map<String,?> properties, final CoordinateOperation... operations) throws FactoryException { + if (operations != null && operations.length == 1) { + return operations[0]; + } final CoordinateOperation op; try { op = new DefaultConcatenatedOperation(properties, operations, getMathTransformFactory()); @@ -602,14 +670,16 @@ next: for (int i=components.size(); -- * widest intersection between its {@linkplain AbstractCoordinateOperation#getDomainOfValidity() domain of * validity} and the {@linkplain CoordinateOperationContext#getAreaOfInterest() area of interest} is returned. * - * <p>The default implementation is as below:</p> + * <p>The default implementation is equivalent to the following code + * (omitting the {@code registry} type check and cast for brevity):</p> * * {@preformat java - * return new CoordinateOperationInference(this, context).createOperation(sourceCRS, targetCRS); + * CoordinateOperationAuthorityFactory registry = CRS.getAuthorityFactory("EPSG"); // Actually needs cast + * return new CoordinateOperationFinder(registry, this, context).createOperation(sourceCRS, targetCRS); * } * * Subclasses can override this method if they need, for example, to use a custom - * {@link CoordinateOperationInference} implementation. + * {@link CoordinateOperationFinder} implementation. * * @param sourceCRS input coordinate reference system. * @param targetCRS output coordinate reference system. @@ -618,7 +688,7 @@ next: for (int i=components.size(); -- * @throws OperationNotFoundException if no operation path was found from {@code sourceCRS} to {@code targetCRS}. * @throws FactoryException if the operation creation failed for some other reason. * - * @see CoordinateOperationInference + * @see CoordinateOperationFinder * * @since 0.7 */ @@ -627,7 +697,9 @@ next: for (int i=components.size(); -- final CoordinateOperationContext context) throws OperationNotFoundException, FactoryException { - return new CoordinateOperationInference(this, context).createOperation(sourceCRS, targetCRS); + final AuthorityFactory registry = USE_EPSG_FACTORY ? CRS.getAuthorityFactory(Constants.EPSG) : null; + return new CoordinateOperationFinder((registry instanceof CoordinateOperationAuthorityFactory) ? + (CoordinateOperationAuthorityFactory) registry : null, this, context).createOperation(sourceCRS, targetCRS); } /**
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -259,7 +259,7 @@ public class DefaultOperationMethod exte formula = new DefaultFormula((CharSequence) value); } else { throw new IllegalArgumentException(Errors.getResources(properties) - .getString(Errors.Keys.IllegalPropertyClass_2, FORMULA_KEY, value.getClass())); + .getString(Errors.Keys.IllegalPropertyValueClass_2, FORMULA_KEY, value.getClass())); } this.parameters = parameters; this.sourceDimensions = sourceDimensions; Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -34,6 +34,8 @@ import org.apache.sis.util.UnsupportedIm import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.ComparisonMode; import org.apache.sis.util.resources.Errors; +import org.apache.sis.io.wkt.FormattableObject; +import org.apache.sis.io.wkt.Formatter; import static org.apache.sis.util.Utilities.deepEquals; @@ -280,6 +282,33 @@ public class DefaultPassThroughOperation return super.computeHashCode() + 31 * operation.hashCode(); } + /** + * Formats this coordinate operation in a pseudo-Well Known Text (WKT) format. + * Current format is specific to Apache SIS and may change in any future version + * if a standard format for pass through operations is defined. + * + * @param formatter The formatter to use. + * @return Currently {@code "PassThroughOperation"} (may change in any future version). + * + * @since 0.7 + */ + @Override + protected String formatTo(final Formatter formatter) { + super.formatTo(formatter); + formatter.append(new FormattableObject() { + @Override protected String formatTo(final Formatter formatter) { + for (final int i : getModifiedCoordinates()) { + formatter.append(i); + } + return "ModifiedCoordinates"; + } + }); + formatter.newLine(); + formatter.append(castOrCopy(getOperation())); + formatter.setInvalidWKT(this, null); + return "PassThroughOperation"; + } + Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -19,13 +19,23 @@ package org.apache.sis.referencing.opera import java.util.Map; import java.util.HashMap; import javax.xml.bind.annotation.XmlTransient; +import javax.measure.unit.Unit; +import org.opengis.util.InternationalString; +import org.opengis.parameter.ParameterValue; +import org.opengis.parameter.ParameterValueGroup; +import org.opengis.parameter.ParameterDescriptor; +import org.opengis.parameter.GeneralParameterValue; +import org.opengis.parameter.GeneralParameterDescriptor; import org.opengis.referencing.operation.OperationMethod; +import org.opengis.referencing.operation.SingleOperation; +import org.apache.sis.internal.metadata.ReferencingServices; +import org.apache.sis.internal.referencing.SignReversalComment; import org.apache.sis.internal.referencing.provider.AbstractProvider; import org.apache.sis.metadata.iso.ImmutableIdentifier; import org.apache.sis.util.Deprecable; // Branch-dependent imports -import org.opengis.referencing.ReferenceIdentifier; +import org.opengis.metadata.Identifier; /** @@ -58,24 +68,92 @@ final class InverseOperationMethod exten } /** - * Returns or create the inverse of the given operation method. + * Returns {@code true} if the given method flags itself as invertible. + */ + private static boolean isInvertible(final OperationMethod method) { + return method instanceof AbstractProvider && ((AbstractProvider) method).isInvertible(); + } + + /** + * Returns or create the inverse of the given operation method. If the same operation method can be used + * for the inverse operation either with the exact same parameter values or with the sign of some values + * reversed, then the given method is returned as-is. Otherwise a synthetic method is created. */ static OperationMethod create(final OperationMethod method) { if (method instanceof InverseOperationMethod) { return ((InverseOperationMethod) method).inverse; } - if (method instanceof AbstractProvider && ((AbstractProvider) method).isInvertible()) { - return method; + if (!isInvertible(method)) { + boolean useSameParameters = false; + for (final GeneralParameterDescriptor descriptor : method.getParameters().descriptors()) { + useSameParameters = (descriptor.getRemarks() instanceof SignReversalComment); + if (!useSameParameters) break; + } + if (!useSameParameters) { + Identifier name = method.getName(); + name = new ImmutableIdentifier(null, null, "Inverse of " + name.getCode()); + final Map<String,Object> properties = new HashMap<String,Object>(6); + properties.put(NAME_KEY, name); + properties.put(FORMULA_KEY, method.getFormula()); + properties.put(REMARKS_KEY, method.getRemarks()); + if (method instanceof Deprecable) { + properties.put(DEPRECATED_KEY, ((Deprecable) method).isDeprecated()); + } + return new InverseOperationMethod(properties, method); + } } - ReferenceIdentifier name = method.getName(); - name = new ImmutableIdentifier(null, name.getCodeSpace(), "Inverse " + name.getCode()); - final Map<String,Object> properties = new HashMap<String,Object>(6); - properties.put(NAME_KEY, name); - properties.put(FORMULA_KEY, method.getFormula()); - properties.put(REMARKS_KEY, method.getRemarks()); - if (method instanceof Deprecable) { - properties.put(DEPRECATED_KEY, ((Deprecable) method).isDeprecated()); + return method; + } + + /** + * If the inverse of the given operation can be represented by inverting the sign of all numerical + * parameter values, copies those parameters in a {@code "parameters"} entry in the given map. + * Otherwise does nothing. + * + * @param source the operation for which to get the inverse parameters. + * @param target where to store the inverse parameters. + */ + static void putParameters(final SingleOperation source, final Map<String,Object> target) { + final boolean isInvertible = isInvertible(source.getMethod()); + final ParameterValueGroup parameters = source.getParameterValues(); + final ParameterValueGroup copy = parameters.getDescriptor().createValue(); + for (final GeneralParameterValue gp : parameters.values()) { + if (gp instanceof ParameterValue<?>) { + final ParameterValue<?> src = (ParameterValue<?>) gp; + final Object value = src.getValue(); + if (value instanceof Number) { + final ParameterDescriptor<?> descriptor = src.getDescriptor(); + final InternationalString remarks = descriptor.getRemarks(); + if (remarks != SignReversalComment.SAME) { + boolean isOpposite = (remarks == SignReversalComment.OPPOSITE); + if (!isOpposite) { + /* + * If the parameter descriptor does not contain an information about whether the + * inverse operation uses values of opposite sign or not, use heuristic rules. + */ + if (!isInvertible) { + return; // Can not create inverse parameter values - abandon. + } + final Comparable<?> minimum = descriptor.getMinimumValue(); + isOpposite = (minimum == null || (minimum instanceof Number && ((Number) minimum).doubleValue() < 0)); + } + if (isOpposite) { + final ParameterValue<?> tgt = copy.parameter(descriptor.getName().getCode()); + final Unit<?> unit = src.getUnit(); + if (unit != null) { + tgt.setValue(-src.doubleValue(), unit); + } else if (value instanceof Integer || value instanceof Short || value instanceof Byte) { + tgt.setValue(-src.intValue()); + } else { + tgt.setValue(-src.doubleValue()); + } + continue; + } + } + } + } + copy.values().add(gp); } - return new InverseOperationMethod(properties, method); + target.put(ReferencingServices.PARAMETERS_KEY, copy); } } Copied: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java (from r1740152, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java) URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java?p2=sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java&p1=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java&r1=1740152&r2=1740177&rev=1740177&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -26,6 +26,9 @@ import org.apache.sis.util.logging.Loggi import org.apache.sis.internal.system.Loggers; import org.apache.sis.referencing.operation.matrix.Matrices; +// Branch-dependent imports +import org.apache.sis.referencing.crs.DefaultParametricCRS; + /** * Information about the relationship between a source component and a target component @@ -54,7 +57,7 @@ final class SubOperationInfo { {GeodeticCRS.class}, {VerticalCRS.class, GeodeticCRS.class}, {TemporalCRS.class}, - {ParametricCRS.class}, + {DefaultParametricCRS.class}, {EngineeringCRS.class}, {ImageCRS.class} }; @@ -65,7 +68,7 @@ final class SubOperationInfo { */ private static Class<?> type(SingleCRS crs) { while (crs instanceof GeneralDerivedCRS) { - crs = ((GeneralDerivedCRS) crs).getBaseCRS(); + crs = (SingleCRS) ((GeneralDerivedCRS) crs).getBaseCRS(); } return crs.getClass(); } @@ -127,7 +130,7 @@ final class SubOperationInfo { if (failure == null) { failure = exception; } else { - failure.addSuppressed(exception); + // failure.addSuppressed(exception); } continue; } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/AffineTransforms2D.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/AffineTransforms2D.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/AffineTransforms2D.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/AffineTransforms2D.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -178,7 +178,7 @@ public final class AffineTransforms2D ex * * @return The direct transform of the {@code bounds} rectangle, or {@code null} if {@code bounds} was null. * - * @see org.apache.sis.referencing.CRS#transform(MathTransform2D, Rectangle2D, Rectangle2D) + * @see org.apache.sis.geometry.Envelopes#transform(MathTransform2D, Rectangle2D, Rectangle2D) */ public static Rectangle2D transform(final AffineTransform transform, final Rectangle2D bounds, final Rectangle2D dest) Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -29,6 +29,7 @@ import org.apache.sis.util.ComparisonMod import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.resources.Errors; import org.apache.sis.internal.util.Numerics; +import org.apache.sis.internal.util.DoubleDouble; import org.apache.sis.internal.metadata.AxisDirections; import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix; @@ -559,8 +560,9 @@ public final class Matrices extends Stat * * <p>The given sub-matrix shall have the following properties:</p> * <ul> - * <li>The last column contains translation terms, except in the last row.</li> - * <li>The last row often (but not necessarily) contains 0 values except in the last column.</li> + * <li>The last row often (but not necessarily) contains 0 values everywhere except in the last column.</li> + * <li>Values in the last column are translation terms, except in the last row.</li> + * <li>All other values are scale or shear terms.</li> * </ul> * * A square matrix complying with the above conditions is often {@linkplain #isAffine(Matrix) affine}, @@ -608,22 +610,34 @@ public final class Matrices extends Stat * @param firstAffectedOrdinate The lowest index of the affected ordinates. * @param subMatrix The matrix to use for affected ordinates. * @param numTrailingOrdinates Number of trailing ordinates to pass through. - * @return A matrix + * @return A matrix for the same transform than the given matrix, + * augmented with leading and trailing pass-through coordinates. * * @see org.apache.sis.referencing.operation.DefaultMathTransformFactory#createPassThroughTransform(int, MathTransform, int) */ public static MatrixSIS createPassThrough(final int firstAffectedOrdinate, final Matrix subMatrix, final int numTrailingOrdinates) { + ArgumentChecks.ensureNonNull ("subMatrix", subMatrix); ArgumentChecks.ensurePositive("firstAffectedOrdinate", firstAffectedOrdinate); ArgumentChecks.ensurePositive("numTrailingOrdinates", numTrailingOrdinates); final int expansion = firstAffectedOrdinate + numTrailingOrdinates; - int sourceDimensions = subMatrix.getNumCol(); + int sourceDimensions = subMatrix.getNumCol(); // Will become the number of dimensions later. int targetDimensions = subMatrix.getNumRow(); + /* + * Get data from the source matrix, together with the error terms if present. + * The 'stride' and 'length' values will be used for computing indices in that array. + * The DoubleDouble temporary object is used only if the array contains error terms. + */ + final int stride = sourceDimensions; + final int length = sourceDimensions * targetDimensions; + final double[] sources = getExtendedElements(subMatrix); + final DoubleDouble transfer = (sources.length > length) ? new DoubleDouble() : null; final MatrixSIS matrix = createZero(targetDimensions-- + expansion, - sourceDimensions-- + expansion); + sourceDimensions-- + expansion, + transfer != null); /* - * Following code process for upper row to lower row. + * Following code processes from upper row to lower row. * First, set the diagonal elements on leading new dimensions. */ for (int j=0; j<firstAffectedOrdinate; j++) { @@ -634,12 +648,14 @@ public final class Matrices extends Stat * which are unconditionally stored in the last column. */ final int lastColumn = sourceDimensions + expansion; - for (int j=0; j<targetDimensions; j++) { - for (int i=0; i<sourceDimensions; i++) { - matrix.setElement(firstAffectedOrdinate + j, firstAffectedOrdinate + i, subMatrix.getElement(j, i)); - } - matrix.setElement(firstAffectedOrdinate + j, lastColumn, subMatrix.getElement(j, sourceDimensions)); - } + matrix.setElements(sources, length, stride, transfer, + 0, 0, // Source (row, colum) + firstAffectedOrdinate, firstAffectedOrdinate, // Target (row, column) + targetDimensions, sourceDimensions); // Number of rows and columns to copy. + matrix.setElements(sources, length, stride, transfer, + 0, sourceDimensions, // Source (row, colum): last column + firstAffectedOrdinate, lastColumn, // Target (row, column): part of last column + targetDimensions, 1); // Copy some rows of only 1 column. /* * Set the pseudo-diagonal elements on the trailing new dimensions. * 'diff' is zero for a square matrix and non-zero for rectangular matrix. @@ -653,14 +669,70 @@ public final class Matrices extends Stat * this row contains only 0 element except for the last one, which is 1. */ final int lastRow = targetDimensions + expansion; - for (int i=0; i<sourceDimensions; i++) { - matrix.setElement(lastRow, i + firstAffectedOrdinate, subMatrix.getElement(targetDimensions, i)); - } - matrix.setElement(lastRow, lastColumn, subMatrix.getElement(targetDimensions, sourceDimensions)); + matrix.setElements(sources, length, stride, transfer, + targetDimensions, 0, // Source (row, colum): last row + lastRow, firstAffectedOrdinate, // Target (row, column): part of last row + 1, sourceDimensions); // Copy some columns of only 1 row. + matrix.setElements(sources, length, stride, transfer, + targetDimensions, sourceDimensions, + lastRow, lastColumn, + 1, 1); return matrix; } /** + * Returns a matrix with the same content than the given matrix but a different size, assuming an affine transform. + * This method can be invoked for adding or removing the <strong>last</strong> dimensions of an affine transform. + * More specifically: + * + * <ul class="verbose"> + * <li>If the given {@code numCol} is <var>n</var> less than the number of columns in the given matrix, + * then the <var>n</var> columns <em>before the last column</em> are removed. + * The last column is left unchanged because it is assumed to contain the translation terms.</li> + * <li>If the given {@code numCol} is <var>n</var> more than the number of columns in the given matrix, + * then <var>n</var> columns are inserted <em>before the last column</em>. + * All values in the new columns will be zero.</li> + * <li>If the given {@code numRow} is <var>n</var> less than the number of rows in the given matrix, + * then the <var>n</var> rows <em>before the last row</em> are removed. + * The last row is left unchanged because it is assumed to contain the usual [0 0 0 … 1] terms.</li> + * <li>If the given {@code numRow} is <var>n</var> more than the number of rows in the given matrix, + * then <var>n</var> rows are inserted <em>before the last row</em>. + * The corresponding offset and scale factors will be 0 and 1 respectively. + * In other words, new dimensions are propagated unchanged.</li> + * </ul> + * + * @param matrix the matrix to resize. This matrix will never be changed. + * @param numRow the new number of rows. This is equal to the desired number of target dimensions plus 1. + * @param numCol the new number of columns. This is equal to the desired number of source dimensions plus 1. + * @return a new matrix of the given size, or the given {@code matrix} if no resizing was needed. + */ + public static Matrix resizeAffine(final Matrix matrix, int numRow, int numCol) { + ArgumentChecks.ensureNonNull ("matrix", matrix); + ArgumentChecks.ensureStrictlyPositive("numRow", numRow); + ArgumentChecks.ensureStrictlyPositive("numCol", numCol); + int srcRow = matrix.getNumRow(); + int srcCol = matrix.getNumCol(); + if (numRow == srcRow && numCol == srcCol) { + return matrix; + } + final int stride = srcCol; + final int length = srcCol * srcRow; + final double[] sources = getExtendedElements(matrix); + final DoubleDouble transfer = (sources.length > length) ? new DoubleDouble() : null; + final MatrixSIS resized = createZero(numRow, numCol, transfer != null); + final int copyRow = Math.min(--numRow, --srcRow); + final int copyCol = Math.min(--numCol, --srcCol); + for (int j=copyRow; j<numRow; j++) { + resized.setElement(j, j, 1); + } + resized.setElements(sources, length, stride, transfer, 0, 0, 0, 0, copyRow, copyCol); // Shear and scale terms. + resized.setElements(sources, length, stride, transfer, 0, srcCol, 0, numCol, copyRow, 1); // Translation column. + resized.setElements(sources, length, stride, transfer, srcRow, 0, numRow, 0, 1, copyCol); // Last row. + resized.setElements(sources, length, stride, transfer, srcRow, srcCol, numRow, numCol, 1, 1); // Last row. + return resized; + } + + /** * Returns {@code true} if the given matrix is likely to use extended precision. * A value of {@code true} is not a guarantee that the matrix uses extended precision, * but a value of {@code false} is a guarantee that it does not. @@ -671,6 +743,17 @@ public final class Matrices extends Stat } /** + * Returns the elements of the given matrix, together with error terms if available. + */ + private static double[] getExtendedElements(final Matrix matrix) { + if (matrix instanceof ExtendedPrecisionMatrix) { + return ((ExtendedPrecisionMatrix) matrix).getExtendedElements(); + } else { + return MatrixSIS.castOrCopy(matrix).getElements(); + } + } + + /** * Creates a new matrix which is a copy of the given matrix. * * <div class="note"><b>Implementation note:</b> Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -249,6 +249,41 @@ public abstract class MatrixSIS implemen public abstract void setElements(final double[] elements); /** + * Sets elements in a sub-region of this matrix, optionally including error terms. + * + * @param source Row-major values as given by {@link ExtendedPrecisionMatrix#getExtendedElements()}. + * @param length Number of elements ({@code numRow} × {@code numCol}) in the source matrix, not including error terms. + * @param stride Number of columns in the source matrix, used for computing indices in {@code source} array. + * @param srcRow Index of the first row from the {@code source} to copy in {@code this}. + * @param srcCol Index of the first column from the {@code source} to copy in {@code this}. + * @param dstRow Index of the first row in {@code this} where to copy the {@code source} values. + * @param dstCol Index of the first column in {@code this} where to copy the {@code source} values. + * @param numRow Number of rows to copy. + * @param numCol Number of columns to copy. + * @param transfer If both {@code source} and {@code this} use extended precision, + * the temporary object to use for transferring values. Otherwise {@code null}. + */ + final void setElements(final double[] source, final int length, final int stride, final DoubleDouble transfer, + int srcRow, final int srcCol, + int dstRow, final int dstCol, + int numRow, final int numCol) + { + while (--numRow >= 0) { + final int valueOffset = srcRow*stride + srcCol; + for (int i=0; i<numCol; i++) { + if (transfer != null) { + transfer.setFrom(source, valueOffset + i, length); + set(dstRow, dstCol + i, transfer); + } else { + setElement(dstRow, dstCol + i, source[valueOffset + i]); + } + } + srcRow++; + dstRow++; + } + } + + /** * Sets this matrix to the values of another matrix. * The given matrix must have the same size. * Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -56,7 +56,7 @@ * <div class="section"><cite>Early binding</cite> versus <cite>late binding</cite> implementations</div> * There is sometime multiple ways of transforming coordinates for a given pair of source and target CRS. * For example the {@linkplain org.apache.sis.referencing.datum.BursaWolfParameters Bursa-Wolf parameters} - * may vary depending on the area of interest, like in the transformations from NAD27 to NAD83. + * may vary depending on the area of interest, like in the transformations from NAD27 to WGS84. * Even for a fixed set of Bursa-Wolf parameter, there is various ways to use them (<cite>Molodensky</cite>, * <cite>Abridged Molodensky</cite>, <cite>Geocentric translation</cite>, <cite>etc.</cite>). * @@ -86,7 +86,7 @@ * exists in the form of the {@link org.apache.sis.referencing.datum.DefaultGeodeticDatum#getBursaWolfParameters()} * method for those who really need it. This means that when searching for a coordinate operation between a given * pair of CRS, Apache SIS will query {@link org.apache.sis.referencing.factory.sql.EPSGFactory} before to try to - * {@linkplain org.apache.sis.referencing.operation.CoordinateOperationInference infer the operation path by itelf}. + * {@linkplain org.apache.sis.referencing.operation.CoordinateOperationFinder infer the operation path by itelf}. * The {@link org.apache.sis.referencing.operation.CoordinateOperationContext} can be used for further refinements, * for example by specifying the area of interest. * Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -150,4 +150,82 @@ public abstract class AbstractMathTransf public MathTransform1D inverse() throws NoninvertibleTransformException { return (MathTransform1D) super.inverse(); } + + /** + * Base class for implementation of inverse math transforms. + * This inner class is the inverse of the enclosing {@link AbstractMathTransform1D}. + * + * <div class="section">Serialization</div> + * Instances of this class are serializable only if the enclosing math transform is also serializable. + * Serialized math transforms are not guaranteed to be compatible with future SIS versions. + * Serialization, if allowed, should be used only for short term storage or RMI between applications + * running the same SIS version. + * + * @author Martin Desruisseaux (Geomatys) + * @since 0.7 + * @version 0.7 + * @module + */ + protected abstract class Inverse extends AbstractMathTransform.Inverse implements MathTransform1D { + /** + * Serial number for inter-operability with different versions. + */ + private static final long serialVersionUID = 2018412413506158560L; + + /** + * Constructs an inverse math transform. + */ + protected Inverse() { + AbstractMathTransform1D.this.super(); + } + + /** + * Returns the enclosing math transform. + */ + @Override + public MathTransform1D inverse() { + return (MathTransform1D) super.inverse(); + } + + /** + * Transforms a single point in the given array and opportunistically computes its derivative if requested. + * The default implementation delegates to {@link #transform(double)} and potentially to {@link #derivative(double)}. + * Subclasses may override this method for performance reason. + * + * @return {@inheritDoc} + * @throws TransformException {@inheritDoc} + */ + @Override + public Matrix transform(final double[] srcPts, final int srcOff, + final double[] dstPts, final int dstOff, + final boolean derivate) throws TransformException + { + final double ordinate = srcPts[srcOff]; + if (dstPts != null) { + dstPts[dstOff] = transform(ordinate); + } + return derivate ? new Matrix1(derivative(ordinate)) : null; + } + + /** + * Gets the derivative of this transform at a point. The default implementation ensures that + * {@code point} is one-dimensional, then delegates to {@link #derivative(double)}. + * + * @param point The coordinate point where to evaluate the derivative, or {@code null}. + * @return The derivative at the specified point (never {@code null}). + * @throws MismatchedDimensionException if {@code point} does not have the expected dimension. + * @throws TransformException if the derivative can not be evaluated at the specified point. + */ + @Override + public Matrix derivative(final DirectPosition point) throws TransformException { + final double ordinate; + if (point == null) { + ordinate = Double.NaN; + } else { + ensureDimensionMatches("point", 1, point); + ordinate = point.getOrdinate(0); + } + return new Matrix1(derivative(ordinate)); + } + } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -61,6 +61,7 @@ import org.apache.sis.internal.referenci import org.apache.sis.internal.referencing.j2d.ParameterizedAffine; 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.system.Loggers; import org.apache.sis.metadata.iso.citation.Citations; import org.apache.sis.parameter.DefaultParameterValueGroup; @@ -270,7 +271,7 @@ public class DefaultMathTransformFactory * * Wrapping the ServiceLoader in a LazySet avoid this issue. */ - this(new LazySet<OperationMethod>(ServiceLoader.load(OperationMethod.class))); + this(new Providers()); } /** @@ -387,7 +388,10 @@ public class DefaultMathTransformFactory ArgumentChecks.ensureNonEmpty("identifier", identifier); OperationMethod method = methodsByName.get(identifier); if (method == null) { - method = ReferencingServices.getInstance().getOperationMethod(methods, identifier); + final ReferencingServices services = ReferencingServices.getInstance(); + synchronized (methods) { + method = services.getOperationMethod(methods, identifier); + } if (method == null) { throw new NoSuchIdentifierException(Errors.format(Errors.Keys.NoSuchOperationMethod_1, identifier), identifier); } @@ -845,25 +849,60 @@ public class DefaultMathTransformFactory * if available. This method writes semi-major and semi-minor parameter values only if they do not * already exists in the given parameters. * + * <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. * @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. * @throws IllegalArgumentException if the operation fails because a parameter has a unrecognized name or an * illegal value. + * + * @see #getCompletedParameters() */ - final RuntimeException setEllipsoids(final OperationMethod method) throws IllegalArgumentException { - ensureCompatibleParameters(false); + @SuppressWarnings("null") + final RuntimeException completeParameters(OperationMethod method, final ParameterValueGroup userParams) + throws IllegalArgumentException + { + provider = method; + parameters = userParams; + /* + * Get the operation method for the appropriate number of dimensions. For example the default Molodensky + * operation expects two-dimensional source and target CRS. If a given CRS is three-dimensional, we need + * a provider variant which will not concatenate a "geographic 3D to 2D" operation before the Molodensky + * one. It is worth to perform this check only if the provider is a subclass of DefaultOperationMethod, + * since it needs to override the 'redimension(int, int)' method. + */ + if (method instanceof DefaultOperationMethod && method.getClass() != DefaultOperationMethod.class) { + final Integer sourceDim = (sourceCS != null) ? sourceCS.getDimension() : method.getSourceDimensions(); + final Integer targetDim = (targetCS != null) ? targetCS.getDimension() : method.getTargetDimensions(); + if (sourceDim != null && targetDim != null) { + method = ((DefaultOperationMethod) method).redimension(sourceDim, targetDim); + if (method instanceof MathTransformProvider) { + provider = method; + } + } + } + ensureCompatibleParameters(false); // Invoke only after we set 'provider' to its final instance. + /* + * Get a mask telling us if we need to set parameters for the source and/or target ellipsoid. + * This information should preferably be given by the provider. But if the given provider is + * not a SIS implementation, use as a fallback whether ellipsoids are provided. This fallback + * may be less reliable. + */ int n; - if (method instanceof AbstractProvider) { - n = ((AbstractProvider) method).getEllipsoidsMask(); + if (provider instanceof AbstractProvider) { + n = ((AbstractProvider) provider).getEllipsoidsMask(); } else { - // Fallback used only when the information is not available in - // a more reliable way from AbstractProvider.getEllipsoidsMask(). n = 0; if (sourceEllipsoid != null) n = 1; 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. + */ switch (n) { case 0: return null; case 1: return setEllipsoid(getSourceEllipsoid(), Constants.SEMI_MAJOR, Constants.SEMI_MINOR, true, null); @@ -872,7 +911,7 @@ public class DefaultMathTransformFactory RuntimeException failure = null; if (sourceCS != null) try { ensureCompatibleParameters(true); - final ParameterValue<?> p = parameters.parameter("dim"); + final ParameterValue<?> p = parameters.parameter("dim"); // Really 'parameters', not 'userParams'. if (p.getValue() == null) { p.setValue(sourceCS.getDimension()); } @@ -987,10 +1026,9 @@ public class DefaultMathTransformFactory * since the standard place where to provide this information is in the ellipsoid object. */ if (context != null) { - context.provider = method; - context.parameters = parameters; - failure = context.setEllipsoids(method); + failure = context.completeParameters(method, parameters); parameters = context.parameters; + method = context.provider; } transform = ((MathTransformProvider) method).createMathTransform(this, parameters); } catch (RuntimeException exception) { // (IllegalArgumentException | IllegalStateException) on the JDK7 branch. @@ -1389,9 +1427,9 @@ public class DefaultMathTransformFactory public void reload() { synchronized (methods) { methodsByName.clear(); - Iterable<? extends OperationMethod> m = methods; + final Iterable<? extends OperationMethod> m = methods; if (m instanceof LazySet<?>) { // Workaround for JDK bug. See DefaultMathTransformFactory() constructor. - m = ((LazySet<? extends OperationMethod>) m).reload(); + ((LazySet<? extends OperationMethod>) m).reload(); } if (m instanceof ServiceLoader<?>) { ((ServiceLoader<?>) m).reload(); Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -47,7 +47,7 @@ import static java.lang.Double.doubleToR * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.5 - * @version 0.6 + * @version 0.7 * @module * * @see LogarithmicTransform1D @@ -60,6 +60,11 @@ class LinearTransform1D extends Abstract private static final long serialVersionUID = -7595037195668813000L; /** + * A transform that just reverse the sign of input values. + */ + static final LinearTransform1D NEGATE = new LinearTransform1D(-1, 0); + + /** * The value which is multiplied to input values. */ final double scale; @@ -99,8 +104,9 @@ class LinearTransform1D extends Abstract * @see MathTransforms#linear(double, double) */ public static LinearTransform1D create(final double scale, final double offset) { - if (offset == 0 && scale == 1) { - return IdentityTransform1D.INSTANCE; + if (offset == 0) { + if (scale == +1) return IdentityTransform1D.INSTANCE; + if (scale == -1) return NEGATE; } if (scale == 0) { if (offset == 0) return ConstantTransform1D.ZERO; @@ -111,6 +117,19 @@ class LinearTransform1D extends Abstract } /** + * Creates a constant function having value <var>y</var>, and for which the inverse is <var>x</var>. + * + * @since 0.7 + */ + static LinearTransform1D constant(final double x, final double y) { + final LinearTransform1D tr = create(0, y); + if (!Double.isNaN(x)) { + tr.inverse = create(0, x); + } + return tr; + } + + /** * Returns the parameter descriptors for this math transform. */ @Override Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -147,6 +147,33 @@ public final class MathTransforms extend } /** + * Creates a transform for the <i>y=f(x)</i> function where <var>y</var> are computed by a linear interpolation. + * Both {@code preimage} (the <var>x</var>) and {@code values} (the <var>y</var>) arguments can be null: + * + * <ul> + * <li>If both {@code preimage} and {@code values} arrays are non-null, then the must have the same length.</li> + * <li>If both {@code preimage} and {@code values} arrays are null, then this method returns the identity transform.</li> + * <li>If only {@code preimage} is null, then the <var>x</var> values are taken as {0, 1, 2, …, {@code values.length} - 1}.</li> + * <li>If only {@code values} is null, then the <var>y</var> values are taken as {0, 1, 2, …, {@code preimage.length} - 1}.</li> + * </ul> + * + * All {@code preimage} elements shall be real numbers (not NaN) sorted in increasing or decreasing order. + * Elements in the {@code values} array do not need to be ordered, but the returned transform will be invertible + * only if all values are real numbers sorted in increasing or decreasing order. + * Furthermore the returned transform is affine (i.e. implement the {@link LinearTransform} interface) + * if the interval between each {@code preimage} and {@code values} element is constant. + * + * @param preimage the input values (<var>x</var>) in the function domain, or {@code null}. + * @param values the output values (<var>y</var>) in the function range, or {@code null}. + * @return the <i>y=f(x)</i> function. + * + * @since 0.7 + */ + public static MathTransform1D interpolate(final double[] preimage, final double[] values) { + return LinearInterpolator1D.create(preimage, values); + } + + /** * Puts together a list of independent math transforms, each of them operating on a subset of ordinate values. * This method is often used for defining 4-dimensional (<var>x</var>,<var>y</var>,<var>z</var>,<var>t</var>) * transform as an aggregation of 3 simpler transforms operating on (<var>x</var>,<var>y</var>), (<var>z</var>) Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -26,19 +26,41 @@ * postal address. This package is the root for both kinds, with an emphasis on the one for coordinates.</p> * * <div class="section">Fetching geodetic object instances</div> - * Geodetic objects can be instantiated either directly by specifying all information to a factory method - * or constructor, or indirectly by specifying the identifier of an entry in a database. In particular, - * the <a href="http://www.epsg.org">EPSG</a> database provides definitions for many geodetic objects, + * Geodetic objects can be instantiated either + * {@linkplain org.apache.sis.referencing.factory.GeodeticObjectFactory directly by specifying all information to a factory method or constructor}, or + * {@linkplain org.apache.sis.referencing.factory.GeodeticAuthorityFactory indirectly by specifying the identifier of an entry in a database}. + * In particular, the <a href="http://www.epsg.org">EPSG</a> database provides definitions for many geodetic objects, * and Apache SIS provides convenience shortcuts for some of them in the - * {@link org.apache.sis.referencing.CommonCRS} enumerations. + * {@link org.apache.sis.referencing.CommonCRS} enumerations. Other convenience methods are + * {@link org.apache.sis.referencing.CRS#forCode(String)}, + * {@link org.apache.sis.referencing.CRS#fromWKT(String)} and + * {@link org.apache.sis.referencing.CRS#fromXML(String)} + * + * <div class="section">Usage example</div> + * The following example projects a (<var>latitude</var>, <var>longitude</var>) coordinate to + * a <cite>Universal Transverse Mercator</cite> projection in the zone of the coordinate: + * + * {@preformat java + * GeographicCRS source = CommonCRS.WGS84.geographic(); + * ProjectedCRS target = CommonCRS.WGS84.UTM(20, 30); // 20°N 30°E (watch out axis order!) + * CoordinateOperation operation = CRS.findOperation(source, target, null); + * if (CRS.getLinearAccuracy(operation) > 100) { + * // If the accuracy is coarser than 100 metres (or any other threshold at application choice) + * // maybe the operation is not suitable. Decide here what to do (throw an exception, etc). + * } + * MathTransform mt = operation.getMathTransform(); + * DirectPosition position = new DirectPosition2D(20, 30); // 20°N 30°E (watch out axis order!) + * position = mt.transform(position, position); + * System.out.println(position); + * } * * <div class="section">The EPSG database</div> * The EPSG geodetic parameter dataset is a structured database required to: * * <ul> - * <li>define {@linkplain org.opengis.referencing.crs.CoordinateReferenceSystem Coordinate Reference Systems} + * <li>define {@linkplain org.apache.sis.referencing.crs.AbstractCRS Coordinate Reference Systems} * (CRS) such that coordinates describe positions unambiguously;</li> - * <li>define {@linkplain org.opengis.referencing.operation.CoordinateOperation Coordinate Operations} + * <li>define {@linkplain org.apache.sis.referencing.operation.AbstractCoordinateOperation Coordinate Operations} * that allow coordinates to be changed from one CRS to another CRS.</li> * </ul> * Modified: sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod [UTF-8] Wed Apr 20 17:40:11 2016 @@ -2,6 +2,7 @@ # Heavier classes (e.g. having more dependencies) or classes less likely to be used, should be last. org.apache.sis.internal.referencing.provider.Affine org.apache.sis.internal.referencing.provider.Geographic3Dto2D +org.apache.sis.internal.referencing.provider.Geographic2Dto3D org.apache.sis.internal.referencing.provider.GeographicOffsets org.apache.sis.internal.referencing.provider.GeographicOffsets2D org.apache.sis.internal.referencing.provider.VerticalOffset @@ -11,12 +12,12 @@ org.apache.sis.internal.referencing.prov org.apache.sis.internal.referencing.provider.CoordinateFrameRotation org.apache.sis.internal.referencing.provider.GeographicToGeocentric org.apache.sis.internal.referencing.provider.GeocentricToGeographic -org.apache.sis.internal.referencing.provider.GeocentricTranslation2D org.apache.sis.internal.referencing.provider.GeocentricTranslation3D -org.apache.sis.internal.referencing.provider.PositionVector7Param2D +org.apache.sis.internal.referencing.provider.GeocentricTranslation2D org.apache.sis.internal.referencing.provider.PositionVector7Param3D -org.apache.sis.internal.referencing.provider.CoordinateFrameRotation2D +org.apache.sis.internal.referencing.provider.PositionVector7Param2D org.apache.sis.internal.referencing.provider.CoordinateFrameRotation3D +org.apache.sis.internal.referencing.provider.CoordinateFrameRotation2D org.apache.sis.internal.referencing.provider.Molodensky org.apache.sis.internal.referencing.provider.AbridgedMolodensky org.apache.sis.internal.referencing.provider.Equirectangular @@ -42,3 +43,4 @@ org.apache.sis.internal.referencing.prov org.apache.sis.internal.referencing.provider.NTv2 org.apache.sis.internal.referencing.provider.NADCON org.apache.sis.internal.referencing.provider.FranceGeocentricInterpolation +org.apache.sis.internal.referencing.provider.Interpolation1D Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -90,8 +90,9 @@ public final strictfp class ReferencingU */ @Test public void testGetPropertiesForModifiedCRS() { - assertEquals("WGS 84", getPropertiesForModifiedCRS(HardCodedCRS.WGS84_3D).get(IdentifiedObject.NAME_KEY)); - assertEquals("WGS 84", getPropertiesForModifiedCRS(HardCodedCRS.GEOID_4D).get(IdentifiedObject.NAME_KEY)); + assertEquals("WGS 84", getPropertiesForModifiedCRS(HardCodedCRS.WGS84_3D).get(IdentifiedObject.NAME_KEY)); + assertEquals("WGS 84", getPropertiesForModifiedCRS(HardCodedCRS.GEOID_4D).get(IdentifiedObject.NAME_KEY)); + assertEquals("NTF (Paris)", getPropertiesForModifiedCRS(HardCodedCRS.NTF) .get(IdentifiedObject.NAME_KEY)); } /** Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PoleRotationMock.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PoleRotationMock.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PoleRotationMock.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PoleRotationMock.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -36,7 +36,7 @@ import org.apache.sis.parameter.Paramete * @module */ @SuppressWarnings("serial") -public final strictfp class PoleRotationMock extends MockProvider { +public final strictfp class PoleRotationMock extends ProviderMock { /** * The group of all parameters expected by this coordinate operation. */ Copied: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java (from r1740152, sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java) URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java?p2=sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java&p1=sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java&r1=1740152&r2=1740177&rev=1740177&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -126,10 +126,10 @@ public final strictfp class ProvidersTes * Ensures that every parameter instance is unique. Actually this test is not strong requirement. * This is only for sharing existing resources by avoiding unnecessary objects duplication. * - * @throws ReflectiveOperationException if the instantiation of a service provider failed. + * @throws Exception if the instantiation of a service provider failed. */ @Test - public void ensureParameterUniqueness() throws ReflectiveOperationException { + public void ensureParameterUniqueness() throws Exception { final Map<GeneralParameterDescriptor, String> groupNames = new IdentityHashMap<GeneralParameterDescriptor, String>(); final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> parameters = new HashMap<GeneralParameterDescriptor, GeneralParameterDescriptor>(); final Map<Object, Object> namesAndIdentifiers = new HashMap<Object, Object>(); Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/SeismicBinGridMock.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -38,7 +38,7 @@ import org.apache.sis.parameter.Paramete * @module */ @SuppressWarnings("serial") -public final strictfp class SeismicBinGridMock extends MockProvider { +public final strictfp class SeismicBinGridMock extends ProviderMock { /** * The group of all parameters expected by this coordinate operation. */ Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -36,7 +36,7 @@ import org.apache.sis.parameter.Paramete * @module */ @SuppressWarnings("serial") -public final strictfp class TopocentricConversionMock extends MockProvider { +public final strictfp class TopocentricConversionMock extends ProviderMock { /** * The group of all parameters expected by this coordinate operation. */ Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -91,14 +91,14 @@ public final strictfp class GeodeticObje } /** - * Parses the given text. + * Parses the given text. It is caller's responsibility to verify if some warnings have been emitted. * * @param type The expected object type. * @param text The WKT string to parse. * @return The parsed object. * @throws ParseException if an error occurred during the parsing. */ - private <T> T parse(final Class<T> type, final String text) throws ParseException { + private <T> T parseIgnoreWarnings(final Class<T> type, final String text) throws ParseException { if (parser == null) { newParser(Convention.DEFAULT); } @@ -106,13 +106,26 @@ public final strictfp class GeodeticObje final Object obj = parser.parseObject(text, position); assertEquals("errorIndex", -1, position.getErrorIndex()); assertEquals("index", text.length(), position.getIndex()); - assertNull("warnings", parser.getAndClearWarnings(obj)); - assertTrue("ignoredElements", parser.ignoredElements.isEmpty()); assertInstanceOf("GeodeticObjectParser.parseObject", type, obj); return type.cast(obj); } /** + * Parses the given text and ensure that no warnings have been emitted. + * + * @param type The expected object type. + * @param text The WKT string to parse. + * @return The parsed object. + * @throws ParseException if an error occurred during the parsing. + */ + private <T> T parse(final Class<T> type, final String text) throws ParseException { + final T obj = parseIgnoreWarnings(type, text); + assertNull("warnings", parser.getAndClearWarnings(obj)); + assertTrue("ignoredElements", parser.ignoredElements.isEmpty()); + return obj; + } + + /** * Asserts that the name and (optionally) the EPSG identifier of the given object are equal to the given strings. * As a special case if the given EPSG code is 0, then this method verifies that the given object has no identifier. * @@ -438,6 +451,48 @@ public final strictfp class GeodeticObje } /** + * Tests parsing of a CRS with a prime meridian having implicit unit in grads but axes having explicit unit + * in degrees. The specification in §8.2.2 (ii) said: + * + * "(snip) the prime meridian’s {@literal <irm longitude>} value shall be given in + * the same angular units as those for the horizontal axes of the geographic CRS." + * + * Consequently we expect the prime meridian to be in decimal degrees even if the WKT used in this test has + * an {@code Unit[“grade”, 0.015707963267948967]} element, because this WK also declare the axis as being in + * degrees. Since this can be confusing, we expect the parser to emit a warning. + * + * @throws ParseException if the parsing failed. + */ + @Test + @DependsOnMethod("testGeographicWithParisMeridian") + public void testMismatchedAngularUnits() throws ParseException { + String wkt = "GeodeticCRS[“NTF (Paris)”,\n" + + " Datum[“Nouvelle Triangulation Française (Paris)”,\n" + + " Ellipsoid[“Clarke 1880 (IGN)”, 6378249.2, 293.4660212936269]],\n" + + " PrimeMeridian[“Paris”, 2.33722917],\n" + // In units of the longitude axis. + " CS[ellipsoidal, 2],\n" + + " Axis[“Latitude (φ)”, NORTH, Unit[“degree”, 0.017453292519943295]],\n" + + " Axis[“Longitude (λ)”, EAST, Unit[“degree”, 0.017453292519943295]],\n" + + " Unit[“grade”, 0.015707963267948967]\n," + // Inconsistent with axis units. + " Id[“EPSG”, 4807]]"; + + GeographicCRS crs = parseIgnoreWarnings(GeographicCRS.class, wkt); + final Warnings warnings = parser.getAndClearWarnings(crs); + assertTrue("ignoredElements", parser.ignoredElements.isEmpty()); + assertNotNull("warnings", warnings); + assertEquals("warnings.numMessages", 1, warnings.getNumMessages()); + + assertNameAndIdentifierEqual("NTF (Paris)", 4807, crs); + PrimeMeridian pm = crs.getDatum().getPrimeMeridian(); + assertEquals("angularUnit", NonSI.DEGREE_ANGLE, pm.getAngularUnit()); + assertEquals("greenwichLongitude", 2.33722917, pm.getGreenwichLongitude(), STRICT); + EllipsoidalCS cs = crs.getCoordinateSystem(); + assertEquals("dimension", 2, cs.getDimension()); + assertAxisEquals(AxisNames.GEODETIC_LATITUDE, "φ", AxisDirection.NORTH, -90, +90, NonSI.DEGREE_ANGLE, RangeMeaning.EXACT, cs.getAxis(0)); + assertAxisEquals(AxisNames.GEODETIC_LONGITUDE, "λ", AxisDirection.EAST, -180, +180, NonSI.DEGREE_ANGLE, RangeMeaning.WRAPAROUND, cs.getAxis(1)); + } + + /** * Implementation of {@link #testGeographicCRS()} and {@link #testWithAxisSwapping()}. * This test expects no {@code AUTHORITY} element on any component. * @@ -1041,17 +1096,14 @@ public final strictfp class GeodeticObje @Test @DependsOnMethod("testGeographicWithImplicitAxes") public void testWarnings() throws ParseException { - newParser(Convention.DEFAULT); - final ParsePosition position = new ParsePosition(0); - final GeographicCRS crs = (GeographicCRS) parser.parseObject( + final GeographicCRS crs = parseIgnoreWarnings(GeographicCRS.class, "GEOGCS[“WGS 84”,\n" + " DATUM[“World Geodetic System 1984”,\n" + " SPHEROID[“WGS84”, 6378137.0, 298.257223563, Ext1[“foo”], Ext2[“bla”]]],\n" + " PRIMEM[“Greenwich”, 0.0, Intruder[“unknown”]],\n" + - " UNIT[“degree”, 0.017453292519943295], Intruder[“foo”]]", position); + " UNIT[“degree”, 0.017453292519943295], Intruder[“foo”]]"); verifyGeographicCRS(0, crs); - assertEquals("errorIndex", -1, position.getErrorIndex()); final Warnings warnings = parser.getAndClearWarnings(crs); assertNotNull("warnings", warnings); Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -29,6 +29,7 @@ import org.opengis.parameter.ParameterVa import org.apache.sis.metadata.iso.citation.Citations; import org.apache.sis.referencing.CommonCRS; import org.apache.sis.referencing.cs.HardCodedCS; +import org.apache.sis.referencing.factory.InvalidGeodeticParameterException; import org.apache.sis.internal.referencing.GeodeticObjectBuilder; import org.apache.sis.internal.util.Constants; import org.apache.sis.internal.system.Loggers; @@ -88,6 +89,25 @@ public final strictfp class DefaultProje private static final String XML_FILE = "ProjectedCRS.xml"; /** + * Creates a projected CRS and verifies its parameters. + * Verifies also that the constructor does not accept invalid base CRS. + * + * @throws FactoryException if the CRS creation failed. + */ + @Test + public void testConstructor() throws FactoryException { + final ProjectedCRS crs = create(HardCodedCRS.NTF); + verifyParameters(crs.getConversionFromBase().getParameterValues()); + try { + create(HardCodedCRS.WGS84_3D); + fail("Should not accept a three-dimensional base geodetic CRS."); + } catch (InvalidGeodeticParameterException e) { + final String message = e.getMessage(); + assertTrue(message, message.contains("Lambert Conic Conformal (1SP)")); + } + } + + /** * Creates the "NTF (Paris) / Lambert zone II" CRS. The prime meridian is always in grades, * but the axes can be in degrees or in grades depending if the {@code baseCRS} argument is * {@link HardCodedCRS.NTF_NORMALIZED_AXES} or {@link HardCodedCRS.NTF} respectively. @@ -109,11 +129,24 @@ public final strictfp class DefaultProje } /** + * Verifies the parameters of a {@code ProjectedCRS} created by the {@link #create(GeographicCRS)} method + * or something equivalent. + */ + private static void verifyParameters(final ParameterValueGroup pg) { + assertEquals("Latitude of natural origin", 52, pg.parameter("Latitude of natural origin") .doubleValue(NonSI.GRADE), STRICT); + assertEquals("Longitude of natural origin", 0, pg.parameter("Longitude of natural origin") .doubleValue(NonSI.GRADE), STRICT); + assertEquals("Scale factor at natural origin", 0.99987742, pg.parameter("Scale factor at natural origin").doubleValue(), STRICT); + assertEquals("False easting", 600000, pg.parameter("False easting") .doubleValue(SI.METRE), STRICT); + assertEquals("False northing", 2200000, pg.parameter("False northing") .doubleValue(SI.METRE), STRICT); + } + + /** * Tests WKT 1 formatting. * * @throws FactoryException if the CRS creation failed. */ @Test + @DependsOnMethod("testConstructor") public void testWKT1() throws FactoryException { final ProjectedCRS crs = create(HardCodedCRS.NTF); assertWktEquals(Convention.WKT1, @@ -447,16 +480,10 @@ public final strictfp class DefaultProje assertAxisDirectionsEqual("coordinateSystem", crs.getCoordinateSystem(), AxisDirection.EAST, AxisDirection.NORTH); final Projection conversion = crs.getConversionFromBase(); - final ParameterValueGroup pg = conversion.getParameterValues(); assertEpsgNameAndIdentifierEqual("Lambert zone II", 18082, conversion); assertEpsgNameAndIdentifierEqual("Lambert Conic Conformal (1SP)", 9801, conversion.getMethod()); - assertEquals("Latitude of natural origin", 52, pg.parameter("Latitude of natural origin") .doubleValue(NonSI.GRADE), STRICT); - assertEquals("Longitude of natural origin", 0, pg.parameter("Longitude of natural origin") .doubleValue(NonSI.GRADE), STRICT); - assertEquals("Scale factor at natural origin", 0.99987742, pg.parameter("Scale factor at natural origin").doubleValue(), STRICT); - assertEquals("False easting", 600000, pg.parameter("False easting") .doubleValue(SI.METRE), STRICT); - assertEquals("False northing", 2200000, pg.parameter("False northing") .doubleValue(SI.METRE), STRICT); - assertNotNull("conversion.mathTransform", conversion.getMathTransform()); + verifyParameters(conversion.getParameterValues()); /* * Test marshalling and compare with the original file. The comparison ignores the <gml:name> nodes because the * marshalled CRS contains many operation method and parameter aliases which were not in the original XML file. Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java?rev=1740177&r1=1740176&r2=1740177&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java [UTF-8] Wed Apr 20 17:40:11 2016 @@ -36,7 +36,7 @@ import static org.apache.sis.referencing * * @author Martin Desruisseaux (Geomatys) * @since 0.4 - * @version 0.5 + * @version 0.7 * @module */ public final strictfp class HardCodedCRS { @@ -109,6 +109,38 @@ public final strictfp class HardCodedCRS HardCodedDatum.NTF, HardCodedCS.GEODETIC_2D); /** + * A three-dimensional geographic coordinate reference system using the Tokyo datum. + * This CRS uses (<var>longitude</var>, <var>latitude</var>, <var>height</var>) ordinates + * with longitude values increasing towards the East, latitude values increasing towards + * the North and ellipsoidal eight increasing toward up. + * The angular units are decimal degrees and the linear units are metres. + * + * <p>This CRS is equivalent to {@code EPSG:4301} except for axis order and the addition + * of ellipsoidal height.</p> + * + * @since 0.7 + */ + public static final DefaultGeographicCRS TOKYO = new DefaultGeographicCRS( + Collections.singletonMap(DefaultGeographicCRS.NAME_KEY, "Tokyo"), + HardCodedDatum.TOKYO, HardCodedCS.GEODETIC_3D); + + /** + * A two-dimensional geographic coordinate reference system using the JGD2000 datum. + * This CRS uses (<var>longitude</var>, <var>latitude</var>, <var>height</var>) ordinates + * with longitude values increasing towards the East, latitude values increasing towards + * the North and ellipsoidal eight increasing toward up. + * The angular units are decimal degrees and the linear units are metres. + * + * <p>This CRS is equivalent to {@code EPSG:4612} except for axis order and the addition + * of ellipsoidal height.</p> + * + * @since 0.7 + */ + public static final DefaultGeographicCRS JGD2000 = new DefaultGeographicCRS( + Collections.singletonMap(DefaultGeographicCRS.NAME_KEY, "JGD2000"), + HardCodedDatum.JGD2000, HardCodedCS.GEODETIC_3D); + + /** * A two-dimensional geographic coordinate reference system using a spherical datum. * This CRS uses (<var>longitude</var>, <var>latitude</var>) ordinates with longitude values * increasing towards the East and latitude values increasing towards the North. @@ -161,6 +193,18 @@ public final strictfp class HardCodedCRS getProperties(HardCodedCS.ELLIPSOIDAL_HEIGHT), HardCodedDatum.ELLIPSOID, HardCodedCS.ELLIPSOIDAL_HEIGHT); /** + * A vertical coordinate reference system using ellipsoidal datum. + * Ellipsoidal heights are measured along the normal to the ellipsoid used in the definition of horizontal datum. + * + * <p>This is not a valid vertical CRS according ISO 19111. + * This CRS is used by Apache SIS for internal calculation.</p> + * + * @since 0.7 + */ + public static final DefaultVerticalCRS ELLIPSOIDAL_HEIGHT_cm = new DefaultVerticalCRS( + getProperties(HardCodedCS.ELLIPSOIDAL_HEIGHT_cm), HardCodedDatum.ELLIPSOID, HardCodedCS.ELLIPSOIDAL_HEIGHT_cm); + + /** * A vertical coordinate reference system using Mean Sea Level datum. */ public static final DefaultVerticalCRS GRAVITY_RELATED_HEIGHT = new DefaultVerticalCRS(
