Author: desruisseaux Date: Thu Mar 1 22:28:30 2018 New Revision: 1825688 URL: http://svn.apache.org/viewvc?rev=1825688&view=rev Log: Avoid OutOfMemoryException when tie points in a GeoTIFF images are not distributed on a regular grid. https://issues.apache.org/jira/browse/SIS-407
Initial version of a SpecializableTransform for handling the case where a localization grid needs to be splitted in two parts. https://issues.apache.org/jira/browse/SIS-408 Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java (with props) sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java (with props) Modified: sis/branches/JDK8/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java Modified: sis/branches/JDK8/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java [UTF-8] (original) +++ sis/branches/JDK8/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -586,7 +586,7 @@ final class TransformCommand extends For if (toDomainOfValidity != null && (bbox = CRS.getGeographicBoundingBox(operation)) != null) { domainOfValidity = new ImmutableEnvelope(bbox); domainCoordinate = new double[toDomainOfValidity.getTargetDimensions()]; - positionInDomain = new DirectPositionView(domainCoordinate, 0, domainCoordinate.length); + positionInDomain = new DirectPositionView.Double(domainCoordinate, 0, domainCoordinate.length); } else { domainOfValidity = null; domainCoordinate = null; Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -131,7 +131,8 @@ public final class Envelopes extends Sta return ((AbstractMathTransform) transform).transform(srcPts, 0, dstPts, dstOff, derivate); } // Derivative must be calculated before to transform the coordinate. - final Matrix derivative = derivate ? transform.derivative(new DirectPositionView(srcPts, 0, transform.getSourceDimensions())) : null; + final Matrix derivative = derivate ? transform.derivative( + new DirectPositionView.Double(srcPts, 0, transform.getSourceDimensions())) : null; transform.transform(srcPts, 0, dstPts, dstOff, 1); return derivative; } @@ -265,7 +266,7 @@ public final class Envelopes extends Sta sourcePt[i] = envelope.getMinimum(i); } // A window over a single coordinate in the 'ordinates' array. - final DirectPositionView ordinatesView = new DirectPositionView(ordinates, 0, targetDim); + final DirectPositionView ordinatesView = new DirectPositionView.Double(ordinates, 0, targetDim); /* * Iterates over every minimal, maximal and median ordinate values (3 points) along each * dimension. The total number of iterations is 3 ^ (number of source dimensions). @@ -339,7 +340,7 @@ public final class Envelopes extends Sta * to avoid the need for storage. */ DirectPosition temporary = null; - final DirectPositionView sourceView = new DirectPositionView(sourcePt, 0, sourceDim); + final DirectPositionView sourceView = new DirectPositionView.Double(sourcePt, 0, sourceDim); final CurveExtremum extremum = new CurveExtremum(); for (pointIndex=0; pointIndex < derivatives.length; pointIndex++) { final Matrix D1 = derivatives[pointIndex]; Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -17,8 +17,8 @@ package org.apache.sis.internal.referencing; import java.util.Arrays; -import org.opengis.geometry.DirectPosition; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.apache.sis.geometry.AbstractDirectPosition; // Branch-dependent imports import org.opengis.geometry.UnmodifiableGeometryException; @@ -29,19 +29,13 @@ import org.opengis.geometry.Unmodifiable * This class shall be used for temporary objects only (it is not serializable for this reason). * * @author Martin Desruisseaux (Geomatys) - * @version 0.5 + * @version 1.0 * @since 0.5 * @module */ -public final class DirectPositionView implements DirectPosition { +public abstract class DirectPositionView extends AbstractDirectPosition { /** - * The ordinate values. This is a direct reference to the array given to the constructor. - * The length of this array may be greater then the number of dimensions. - */ - private final double[] ordinates; - - /** - * The index of the first value in the {@linkplain #ordinates} array. + * The index of the first value in the ordinates array. * This field is non-final in order to allow the caller to move the view over an array of coordinates. */ public int offset; @@ -49,70 +43,129 @@ public final class DirectPositionView im /** * The number of valid ordinate values. */ - private final int dimension; + final int dimension; /** * Creates a new direct position wrapping the given array. * - * @param ordinates the ordinate values. * @param offset the first value index in the ordinates array. * @param dimension the number of valid ordinate values. */ - public DirectPositionView(final double[] ordinates, final int offset, final int dimension) { - this.ordinates = ordinates; + DirectPositionView(final int offset, final int dimension) { this.offset = offset; this.dimension = dimension; } /** * Returns {@code null} since there is no CRS associated with this position. + * + * @return {@code null}. */ @Override - public CoordinateReferenceSystem getCoordinateReferenceSystem() { + public final CoordinateReferenceSystem getCoordinateReferenceSystem() { return null; } /** * Returns the dimension given at construction time. - */ - @Override - public int getDimension() { - return dimension; - } - - /** - * Returns all ordinate values. - */ - @Override - public double[] getCoordinate() { - return Arrays.copyOfRange(ordinates, offset, offset + dimension); - } - - /** - * Returns the ordinate at the given index. - * <strong>This implementation does not check index validity</strong>, unless assertions are enabled. * - * @param dim the dimension of the ordinate to get fetch. + * @return number of dimensions. */ @Override - public double getOrdinate(final int dim) { - assert dim >= 0 && dim < dimension : dim; - return ordinates[offset + dim]; + public final int getDimension() { + return dimension; } /** * Do not allow any change. + * + * @param dimension ignored. + * @param value ignored. */ @Override - public void setOrdinate(final int dimension, final double value) { + public final void setOrdinate(final int dimension, final double value) { throw new UnmodifiableGeometryException(); } /** - * Returns the direct position, which is {@code this}. + * The double-precision version of {@link DirectPositionView}. */ - @Override - public DirectPosition getDirectPosition() { - return this; + public static final class Double extends DirectPositionView { + /** + * The ordinate values. This is a direct reference to the array given to the constructor. + * The length of this array may be greater then the number of dimensions. + */ + private final double[] ordinates; + + /** + * Creates a new direct position wrapping the given array. + * + * @param ordinates the ordinate values. + * @param offset the first value index in the ordinates array. + * @param dimension the number of valid ordinate values. + */ + public Double(final double[] ordinates, final int offset, final int dimension) { + super(offset, dimension); + this.ordinates = ordinates; + } + + /** + * Returns the ordinate at the given index. + * <strong>This implementation does not check index validity</strong>, unless assertions are enabled. + * + * @param dim the dimension of the ordinate to get fetch. + * @return the coordinate value at the given dimension. + */ + @Override + public double getOrdinate(final int dim) { + assert dim >= 0 && dim < dimension : dim; + return ordinates[offset + dim]; + } + + /** + * Returns all ordinate values. + * + * @return all coordinate values. + */ + @Override + public double[] getCoordinate() { + return Arrays.copyOfRange(ordinates, offset, offset + dimension); + } + } + + /** + * The single-precision version of {@link DirectPositionView}. + */ + public static final class Float extends DirectPositionView { + /** + * The ordinate values. This is a direct reference to the array given to the constructor. + * The length of this array may be greater then the number of dimensions. + */ + private final float[] ordinates; + + /** + * Creates a new direct position wrapping the given array. + * + * @param ordinates the ordinate values. + * @param offset the first value index in the ordinates array. + * @param dimension the number of valid ordinate values. + */ + public Float(final float[] ordinates, final int offset, final int dimension) { + super(offset, dimension); + this.ordinates = ordinates; + } + + /** + * Returns the ordinate at the given index. + * <strong>This implementation does not check index validity</strong>, unless assertions are enabled. + * + * @param dim the dimension of the ordinate to get fetch. + * @return the coordinate value at the given dimension. + */ + @Override + public double getOrdinate(final int dim) { + assert dim >= 0 && dim < dimension : dim; + return ordinates[offset + dim]; + } } } Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -322,6 +322,11 @@ public final class Resources extends Ind public static final short MissingValueForParameter_1 = 44; /** + * The localization grid still have some undefined source or target coordinates. + */ + public static final short MissingValuesInLocalizationGrid = 81; + + /** * No vertical dimension found in “{0}” */ public static final short MissingVerticalDimension_1 = 45; Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties [ISO-8859-1] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties [ISO-8859-1] Thu Mar 1 22:28:30 2018 @@ -80,6 +80,7 @@ MissingTemporalDimension_1 = No t MissingSpatioTemporalDimension_1 = No spatial or temporal dimension found in \u201c{0}\u201d MissingParameterValues_1 = Missing parameter values for \u201c{0}\u201d coordinate operation. MissingValueForParameter_1 = Missing value for \u201c{0}\u201d parameter. +MissingValuesInLocalizationGrid = The localization grid still have some undefined source or target coordinates. NoConvergence = No convergence. NoConvergenceForPoints_2 = No convergence for points {0} and {1}. NonHorizontalCRS_1 = No horizontal component found in the \u201c{0}\u201d coordinate reference system. Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties [ISO-8859-1] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties [ISO-8859-1] Thu Mar 1 22:28:30 2018 @@ -85,6 +85,7 @@ MissingTemporalDimension_1 = Aucu MissingSpatioTemporalDimension_1 = Aucune dimension spatiale ou temporelle n\u2019a \u00e9t\u00e9 trouv\u00e9e dans \u00ab\u202f{0}\u202f\u00bb. MissingParameterValues_1 = Il manque les valeurs des param\u00e8tres pour l\u2019op\u00e9ration \u00ab\u202f{0}\u202f\u00bb. MissingValueForParameter_1 = Aucune valeur n\u2019a \u00e9t\u00e9 d\u00e9finie pour le param\u00e8tre \u00ab\u202f{0}\u202f\u00bb. +MissingValuesInLocalizationGrid = Il manque encore des coordonn\u00e9es sources ou destinations dans la grille de localisation. NoConvergence = Le calcul ne converge pas. NoConvergenceForPoints_2 = Le calcul ne converge pas pour les points {0} et {1}. NonHorizontalCRS_1 = Aucune composante horizontale n\u2019a \u00e9t\u00e9 trouv\u00e9e dans le syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es \u00ab\u202f{0}\u202f\u00bb. Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -24,7 +24,7 @@ * may change in incompatible ways in any future version without notice. * * @author Martin Desruisseaux (Geomatys) - * @version 0.3 + * @version 1.0 * @since 0.3 * @module */ Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -32,7 +32,9 @@ import org.apache.sis.math.Vector; import org.apache.sis.referencing.operation.matrix.Matrices; import org.apache.sis.referencing.operation.matrix.MatrixSIS; import org.apache.sis.referencing.operation.transform.LinearTransform; +import org.apache.sis.referencing.factory.InvalidGeodeticParameterException; import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix; +import org.apache.sis.internal.referencing.Resources; import org.apache.sis.util.resources.Vocabulary; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.ArgumentChecks; @@ -53,7 +55,7 @@ import org.apache.sis.util.Debug; * with the assumption that source positions are exact and all the uncertainty is in the target positions.</p> * * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.0 * * @see LocalizationGridBuilder * @see LinearTransform @@ -302,7 +304,7 @@ search: for (int j=0; j<numPoints; j++) * Returns the error message to be given to {@link IllegalStateException} when there is no data. */ private static String noData() { - return Errors.format(Errors.Keys.MissingValueForProperty_1, "sourceToTarget"); + return Resources.format(Resources.Keys.MissingValuesInLocalizationGrid); } /** @@ -610,7 +612,7 @@ search: for (int j=0; j<numPoints; j++) c = plan.fit(gridSize[0], gridSize[1], Vector.create(targets[j], false)); } catch (IllegalArgumentException e) { // This may happen if the z vector still contain some "NaN" values. - throw new FactoryException(noData(), e); + throw new InvalidGeodeticParameterException(noData(), e); } break; } Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -27,7 +27,7 @@ import org.apache.sis.referencing.operat import org.apache.sis.referencing.operation.transform.LinearTransform; import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.referencing.operation.matrix.MatrixSIS; -import org.apache.sis.referencing.operation.matrix.Matrices; +import org.apache.sis.referencing.operation.matrix.Matrix3; import org.apache.sis.referencing.datum.DatumShiftGrid; import org.apache.sis.internal.referencing.Resources; import org.apache.sis.geometry.DirectPosition2D; @@ -58,7 +58,7 @@ import org.apache.sis.math.Vector; * </ol> * * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.0 * * @see InterpolatedTransform * @see LinearTransform @@ -128,7 +128,7 @@ public class LocalizationGridBuilder ext * @throws ArithmeticException if this constructor can not infer a reasonable grid size from the given vectors. */ public LocalizationGridBuilder(final Vector sourceX, final Vector sourceY) { - final Matrix fromGrid = Matrices.createDiagonal(3,3); + final Matrix fromGrid = new Matrix3(); linear = new LinearTransformBuilder(infer(sourceX, fromGrid, 0), infer(sourceY, fromGrid, 1)); try { sourceToGrid = MathTransforms.linear(fromGrid).inverse(); @@ -171,10 +171,16 @@ public class LocalizationGridBuilder ext } } } + /* + * Compute the size from the increment that we found. If the size is larger than the vector length, + * consider as too large. The rational is that attempt to create a localization grid with that size + * would fail anyway, because it would contain holes where no value is defined. A limit is important + * for preventing useless allocation of large arrays - https://issues.apache.org/jira/browse/SIS-407 + */ fromGrid.setElement(dim, dim, inc); fromGrid.setElement(dim, 2, min); final double n = span / inc; - if (n > 0.5 && n < 0.5 + Short.MAX_VALUE) { + if (n >= 0.5 && n < source.size() - 0.5) { // Compare as 'double' in case the value is large. return ((int) Math.round(n)) + 1; } throw new ArithmeticException(Resources.format(Resources.Keys.CanNotInferGridSizeFromValues_1, range)); Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -30,8 +30,8 @@ * convenience.</p> * * @author Martin Desruisseaux (Geomatys) - * @version 0.5 - * @since 0.8 + * @version 1.0 + * @since 0.5 * @module */ package org.apache.sis.referencing.operation.builder; Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -876,7 +876,7 @@ next: while (--numPts >= 0) { dstPts[dstOff+1] = point[1]; } // We need to keep h during matrix inversion because (λ,φ,h) values are not independent. - Matrix matrix = EllipsoidToCentricTransform.this.derivative(new DirectPositionView(point, offset, 3)); + Matrix matrix = EllipsoidToCentricTransform.this.derivative(new DirectPositionView.Double(point, offset, 3)); matrix = Matrices.inverse(matrix); if (!withHeight) { matrix = MatrixSIS.castOrCopy(matrix).removeRows(2, 3); // Drop height only after matrix inversion is done. Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -488,7 +488,7 @@ public class InterpolatedTransform exten dstPts[dstOff+1] = yi; if (derivate) { return Matrices.inverse(InterpolatedTransform.this.derivative( - new DirectPositionView(dstPts, dstOff, dimension))); + new DirectPositionView.Double(dstPts, dstOff, dimension))); } return null; } Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -95,7 +95,7 @@ public enum IterationStrategy { DESCENDING(false), /** - * Copies the points to transform in a temporary array before to apply the transform. + * Copy the points to transform in a temporary array before to apply the transform. * The temporary array will be used for fetching the source ordinates. * * <p>This algorithm can be used as a fallback for any unknown enumeration.</p> @@ -103,7 +103,7 @@ public enum IterationStrategy { BUFFER_SOURCE(true), /** - * Writes the transformed points in a temporary array and copies them to the + * Write the transformed points in a temporary array and copies them to the * destination subarray when the transformation is finished. * * <p>Developers are allowed to ignore this value and fallback on the same algorithm Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -445,7 +445,8 @@ public final class MathTransforms extend return ((AbstractMathTransform) transform).transform(srcPts, srcOff, dstPts, dstOff, true); } // Must be calculated before to transform the coordinate. - final Matrix derivative = transform.derivative(new DirectPositionView(srcPts, srcOff, transform.getSourceDimensions())); + final Matrix derivative = transform.derivative( + new DirectPositionView.Double(srcPts, srcOff, transform.getSourceDimensions())); if (dstPts != null) { transform.transform(srcPts, srcOff, dstPts, dstOff, 1); } Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -318,7 +318,7 @@ public class PassThroughTransform extend { Matrix derivative = null; if (derivate) { - derivative = derivative(new DirectPositionView(srcPts, srcOff, getSourceDimensions())); + derivative = derivative(new DirectPositionView.Double(srcPts, srcOff, getSourceDimensions())); } if (dstPts != null) { transform(srcPts, srcOff, dstPts, dstOff, 1); Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java?rev=1825688&view=auto ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java (added) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -0,0 +1,497 @@ +/* + * 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.transform; + +import java.util.Map; +import java.util.Arrays; +import java.util.Objects; +import org.opengis.geometry.Envelope; +import org.opengis.geometry.DirectPosition; +import org.opengis.referencing.operation.Matrix; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.apache.sis.referencing.factory.InvalidGeodeticParameterException; +import org.apache.sis.internal.referencing.DirectPositionView; +import org.apache.sis.internal.referencing.Resources; +import org.apache.sis.geometry.GeneralEnvelope; +import org.apache.sis.io.wkt.Formatter; +import org.apache.sis.util.resources.Errors; +import org.apache.sis.util.ComparisonMode; +import org.apache.sis.util.Utilities; +import org.apache.sis.util.ArraysExt; + + +/** + * A transform having sub-areas where more accurate transforms can be used. + * The general transform must be a reasonable approximation of the specialized transforms. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.0 + * @since 1.0 + * @module + */ +class SpecializableTransform extends AbstractMathTransform { + /** + * The generic transform to use if there is no suitable specialization. + */ + private final MathTransform generic; + + /** + * The region where a transform is valid, together with the transform. + * Contains also a chain of {@code SubArea}s fully included in this area. + * Shall be unmodified after {@link SpecializableTransform} construction. + */ + private static final class SubArea extends GeneralEnvelope { + /** + * The transform to apply in this area. + */ + final MathTransform transform; + + /** + * Specialization, or {@code null} if none. If non-null, that sub-area shall be fully included + * in this {@code SubArea}. The specialization may itself contain another specialization. This + * form a chain from this wider area to smallest area, where each step is a smaller area. + * + * <p>Note that this is note a substitute for an R-Tree. This is an optimization for the common + * case where coordinates are close to each other (e.g. when iterating in a geometry), in which + * case we can check immediately for inclusion in smaller areas before to check the wider area.</p> + */ + private SubArea specialization; + + /** + * Creates a new area where a transform is valid. + */ + SubArea(final Envelope area, final MathTransform transform) { + super(area); + this.transform = transform; + } + + /** + * Tries to add a nested sub-area (a specialization of a specialization). + * + * @return whether the given area has been added. + */ + boolean addSpecialization(final SubArea candidate) { + if (specialization == null) { + if (!contains(candidate)) { + return false; + } + } else if (!candidate.addSpecialization(specialization)) { + return specialization.addSpecialization(candidate); + } + specialization = candidate; + return true; + } + + /** + * Sets the CRS of all given ares to a common value. An exception is thrown if incompatible CRS are found. + * This method does not verify the number of dimensions; this check should have been done by the caller. + */ + static void uniformize(final SubArea[] domains) throws InvalidGeodeticParameterException { + CoordinateReferenceSystem common = null; + for (SubArea area : domains) { + do { + final CoordinateReferenceSystem crs = area.getCoordinateReferenceSystem(); + if (common == null) { + common = crs; + } else if (crs != null && !Utilities.equalsIgnoreMetadata(common, crs)) { + throw new InvalidGeodeticParameterException(Errors.format(Errors.Keys.MismatchedCRS)); + } + } while ((area = area.specialization) != null); + } + for (SubArea area : domains) { + do area.setCoordinateReferenceSystem(common); + while ((area = area.specialization) != null); + } + } + + /** + * Returns the area that contains the given position, or {@code null} if none. + * This method may be replaced by an R-Tree in a future Apache SIS version. + */ + static SubArea find(final SubArea[] domains, final DirectPosition pos) { + for (SubArea area : domains) { + if (area.contains(pos)) { + SubArea next = area.specialization; + while (next != null && next.contains(pos)) { + area = next; + next = next.specialization; + } + return area; + } + } + return null; + } + + /** + * Returns the area that contains the given position, looking only in the given area or its specializations. + * Returns {@code null} if no area has been found. + */ + static SubArea find(SubArea area, final DirectPosition pos) { + SubArea found = null; + while (area.contains(pos)) { + found = area; + area = area.specialization; + } + return found; + } + + /** + * For {@link SpecializableTransform#computeHashCode()} implementation. + */ + @Override + public int hashCode() { + int code = super.hashCode() ^ transform.hashCode(); + if (specialization != null) { + code += 37 * specialization.hashCode(); + } + return code; + } + + /** + * For {@link SpecializableTransform#equals(Object)} implementation. + */ + @Override + public boolean equals(final Object obj) { + if (super.equals(obj)) { + final SubArea other = (SubArea) obj; + return transform.equals(other.transform) && Objects.equals(specialization, other.specialization); + } + return false; + } + } + + /** + * Domains where specialized transforms are valid. The array should be very small. + * In current implementation, elements in this array shall not overlap. + * This array may be replaced by an R-Tree in a future Apache SIS version. + */ + private final SubArea[] domains; + + /** + * Creates a new transform with the given generic transform and some amount of specializations. + */ + SpecializableTransform(final MathTransform generic, final Map<Envelope,MathTransform> specializations) + throws InvalidGeodeticParameterException + { + this.generic = generic; + final int sourceDim = generic.getSourceDimensions(); + final int targetDim = generic.getTargetDimensions(); + int n = 0; + final SubArea[] areas = new SubArea[specializations.size()]; +next: for (final Map.Entry<Envelope,MathTransform> e : specializations.entrySet()) { + final MathTransform tr = e.getValue(); + ensureDimensionMatches(0, sourceDim, tr.getSourceDimensions()); + ensureDimensionMatches(1, targetDim, tr.getTargetDimensions()); + final SubArea area = new SubArea(e.getKey(), tr); + if (area.getDimension() != sourceDim) { + throw new InvalidGeodeticParameterException(Errors.format(Errors.Keys.MismatchedDimension_3, + "envelope", sourceDim, area.getDimension())); + } + for (int i=0; i<n; i++) { + if (areas[i].addSpecialization(area)) { + continue next; + } + } + for (int i=0; i<n; i++) { + if (area.intersects(areas[n])) { + // Pending implementation of R-Tree in Apache SIS. + throw new InvalidGeodeticParameterException("Current implementation does not accept overlapping envelopes."); + } + } + areas[n++] = area; + } + domains = ArraysExt.resize(areas, n); + SubArea.uniformize(domains); + } + + /** + * Helper method for verifying transform dimension consistency. + * + * @param type 0 if verifying source dimension, or 1 if verifying target dimension. + */ + private static void ensureDimensionMatches(final int type, final int expected, final int actual) + throws InvalidGeodeticParameterException + { + if (expected != actual) { + throw new InvalidGeodeticParameterException(Resources.format( + Resources.Keys.MismatchedTransformDimension_3, type, expected, actual)); + } + } + + /** + * Gets the dimension of input points. + */ + @Override + public final int getSourceDimensions() { + return generic.getSourceDimensions(); + } + + /** + * Gets the dimension of output points. + */ + @Override + public final int getTargetDimensions() { + return generic.getTargetDimensions(); + } + + /** + * Returns the transform to use for the given domain. + */ + private MathTransform forDomain(final SubArea domain) { + return (domain != null) ? domain.transform : generic; + } + + /** + * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}. + * This method delegates to the most specialized transform. + */ + @Override + public final DirectPosition transform(final DirectPosition ptSrc, DirectPosition ptDst) throws TransformException { + return forDomain(SubArea.find(domains, ptSrc)).transform(ptSrc, ptDst); + } + + /** + * Gets the derivative of this transform at a point. + * This method delegates to the most specialized transform. + */ + @Override + public final Matrix derivative(final DirectPosition point) throws TransformException { + return forDomain(SubArea.find(domains, point)).derivative(point); + } + + /** + * Transforms a single coordinate point in an array, and optionally computes the transform + * derivative at that location. This method delegates to the most specialized transform. + */ + @Override + public final Matrix transform(final double[] srcPts, final int srcOff, + final double[] dstPts, final int dstOff, + boolean derivate) throws TransformException + { + final DirectPositionView pos = new DirectPositionView.Double(srcPts, srcOff, generic.getSourceDimensions()); + final MathTransform tr = forDomain(SubArea.find(domains, pos)); + if (tr instanceof AbstractMathTransform) { + return ((AbstractMathTransform) tr).transform(srcPts, srcOff, dstPts, dstOff, derivate); + } else { + tr.transform(srcPts, srcOff, dstPts, dstOff, 1); + return derivate ? tr.derivative(pos) : null; + } + } + + /** + * Call of a {@code MathTransform.transform(…)} method with source and target arrays fixed at + * {@code TransformCall} creation time. This is used for allowing the same implementation to + * be shared by most {@code transform(…)} methods in {@link SpecializableTransform}. + */ + @FunctionalInterface + private interface TransformCall { + /** Performs the transform at the given offsets. */ + void apply(MathTransform tr, int srcOff, int dstOff, int numPts) throws TransformException; + } + + /** + * Transforms a list of coordinate points. This method delegates to the most specialized transform, + * with single {@code transform(…)} calls for coordinate sequences as long as possible. + * + * @param transform caller for a {@code MathTransform.transform(…)} method. + * @param src a window over the source points. May be backed by a {@code float[]} or {@code double[]} array. + * @param dstOff where to write the first coordinate in the target array. + * @param srcInc the source dimension, negative if we must iterate backward. + * @param dstInc the target dimension, negative if we must iterate backward. + * @param numPts number of points to transform. + */ + private void transform(final TransformCall transform, final DirectPositionView src, + int dstOff, int srcInc, int dstInc, int numPts) throws TransformException + { + final boolean downard = (srcInc < 0); + SubArea domain = SubArea.find(domains, src); + while (numPts > 0) { + int srcOff = src.offset; + final MathTransform tr; + if (domain == null) { + tr = generic; // The transform to apply when no specialization is found. + do { // Count how many points will use that transform. + src.offset += srcInc; + if (--numPts <= 0) break; + domain = SubArea.find(domains, src); // More expansive check than the case where domain is non-null. + } while (domain == null); + } else { + final SubArea previous = domain; + tr = domain.transform; // The specialized transform to apply. + do { // Count how many points will use that transform. + src.offset += srcInc; + if (--numPts <= 0) break; + domain = SubArea.find(domain, src); // Cheaper check compared to the case where domain is null. + } while (domain == previous); + if (domain == null) { + domain = SubArea.find(domains, src); // Need to update with the more expansive check. + } + } + final int num = (src.offset - srcOff) / srcInc; + int dstLow = dstOff; + dstOff += dstInc * num; + if (downard) { + srcOff = src.offset - srcInc; + dstLow = dstOff - dstInc; + } + transform.apply(tr, srcOff, dstLow, num); + } + } + + /** + * Transforms a list of coordinate points. + * This method delegates to the most specialized transform. + */ + @Override + public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts) + throws TransformException + { + int srcInc = getSourceDimensions(); + int dstInc = getTargetDimensions(); + if (srcPts == dstPts) { + switch (IterationStrategy.suggest(srcOff, srcInc, dstOff, dstInc, numPts)) { + case ASCENDING: { + break; + } + case DESCENDING: { + srcOff += (numPts-1) * srcInc; srcInc = -srcInc; + dstOff += (numPts-1) * dstInc; dstInc = -dstInc; + break; + } + default: { + srcPts = Arrays.copyOfRange(srcPts, srcOff, srcOff + numPts*srcInc); + srcOff = 0; + break; + } + } + } + final double[] refPts = srcPts; + transform((tr, src, dst, num) -> tr.transform(refPts, src, dstPts, dst, num), + new DirectPositionView.Double(srcPts, srcOff, Math.abs(srcInc)), + dstOff, srcInc, dstInc, numPts); + } + + /** + * Transforms a list of coordinate points. + * This method delegates to the most specialized transform. + */ + @Override + public void transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts) + throws TransformException + { + int srcInc = getSourceDimensions(); + int dstInc = getTargetDimensions(); + if (srcPts == dstPts) { + switch (IterationStrategy.suggest(srcOff, srcInc, dstOff, dstInc, numPts)) { + case ASCENDING: { + break; + } + case DESCENDING: { + srcOff += (numPts-1) * srcInc; srcInc = -srcInc; + dstOff += (numPts-1) * dstInc; dstInc = -dstInc; + break; + } + default: { + srcPts = Arrays.copyOfRange(srcPts, srcOff, srcOff + numPts*srcInc); + srcOff = 0; + break; + } + } + } + final float[] refPts = srcPts; + transform((tr, src, dst, num) -> tr.transform(refPts, src, dstPts, dst, num), + new DirectPositionView.Float(srcPts, srcOff, Math.abs(srcInc)), + dstOff, srcInc, dstInc, numPts); + } + + /** + * Transforms a list of coordinate points. This method delegates to the most specialized transform, + * with single {@code transform(…)} calls for coordinate sequences as long as possible. + */ + @Override + public void transform(final double[] srcPts, int srcOff, + final float [] dstPts, int dstOff, int numPts) throws TransformException + { + final int srcDim = getSourceDimensions(); + final int dstDim = getTargetDimensions(); + transform((tr, src, dst, num) -> tr.transform(srcPts, src, dstPts, dst, num), + new DirectPositionView.Double(srcPts, srcOff, srcDim), + dstOff, srcDim, dstDim, numPts); + } + + /** + * Transforms a list of coordinate points. This method delegates to the most specialized transform, + * with single {@code transform(…)} calls for coordinate sequences as long as possible. + */ + @Override + public void transform(final float [] srcPts, int srcOff, + final double[] dstPts, int dstOff, int numPts) + throws TransformException + { + final int srcDim = getSourceDimensions(); + final int dstDim = getTargetDimensions(); + transform((tr, src, dst, num) -> tr.transform(srcPts, src, dstPts, dst, num), + new DirectPositionView.Float(srcPts, srcOff, srcDim), + dstOff, srcDim, dstDim, numPts); + } + + /** + * Computes a hash value for this transform. + * This method is invoked by {@link #hashCode()} when first needed. + */ + @Override + protected int computeHashCode() { + return super.computeHashCode() + 7*generic.hashCode() ^ Arrays.hashCode(domains); + } + + /** + * Compares the specified object with this math transform for equality. + */ + @Override + public boolean equals(final Object object, final ComparisonMode mode) { + if (super.equals(object, mode)) { + final SpecializableTransform other = (SpecializableTransform) object; + return Utilities.deepEquals(generic, other.generic, mode) && + Utilities.deepEquals(domains, other.domains, mode); + } + return false; + } + + /** + * Formats the inner part of a <cite>Well Known Text</cite> version 1 (WKT 1) element. + * + * <div class="note"><b>Compatibility note:</b> + * The {@code SPECIALIZABLE_MT} element formatted here is an Apache SIS-specific extension.</div> + * + * @param formatter the formatter to use. + * @return the WKT element name, which is {@code "Specializable_MT"}. + */ + @Override + protected String formatTo(final Formatter formatter) { + for (final SubArea domain : domains) { + formatter.newLine(); + formatter.append(generic); + formatter.newLine(); + // TODO: format BBOX. + formatter.append(domain.transform); + } + formatter.setInvalidWKT(SpecializableTransform.class, null); + return "Specializable_MT"; + } +} Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java ------------------------------------------------------------------------------ svn:mime-type = text/plain;charset=UTF-8 Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -61,7 +61,7 @@ * * @author Martin Desruisseaux (IRD, Geomatys) * @author Adrian Custer (Geomatys) - * @version 0.7 + * @version 1.0 * @since 0.5 * @module */ Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -96,7 +96,7 @@ strictfp class PseudoTransform extends A final boolean derivate) throws TransformException { final Matrix derivative = derivate ? derivative( - new DirectPositionView(srcPts, srcOff, getSourceDimensions())) : null; + new DirectPositionView.Double(srcPts, srcOff, getSourceDimensions())) : null; System.arraycopy(srcPts, srcOff, buffer, 0, sourceDimension); for (int i=0; i<targetDimension; i++) { double v = buffer[i % sourceDimension]; Added: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java?rev=1825688&view=auto ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java (added) +++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -0,0 +1,74 @@ +/* + * 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.transform; + +import java.util.Map; +import java.util.HashMap; +import org.opengis.geometry.Envelope; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; +import org.apache.sis.referencing.factory.InvalidGeodeticParameterException; +import org.apache.sis.internal.referencing.j2d.AffineTransform2D; +import org.apache.sis.geometry.Envelope2D; +import org.junit.Test; + +import static org.junit.Assert.*; + + +/** + * Tests {@link SpecializableTransform}. This test use a simple affine transform that multiply + * coordinate values by 10, except in specialized sub-areas in which case a small translation is added. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.0 + * @since 1.0 + * @module + */ +public final strictfp class SpecializableTransformTest extends MathTransformTestCase { + /** + * Creates a transform scaling the coordinate values by 10, then applying the given translation. + */ + private static MathTransform translation(final double t) { + return new AffineTransform2D(10, 0, 0, 10, t, t); + } + + /** + * Creates a transform to test. + * + * @throws InvalidGeodeticParameterException if {@link SpecializableTransform} constructor reject a parameter. + */ + private static SpecializableTransform create() throws InvalidGeodeticParameterException { + final Map<Envelope,MathTransform> specializations = new HashMap<>(4); + assertNull(specializations.put(new Envelope2D(null, -5, -4, 10, 7), translation(0.1))); + assertNull(specializations.put(new Envelope2D(null, -3, -1, 5, 2), translation(0.2))); + return new SpecializableTransform(translation(0), specializations); + } + + /** + * Tests consistency between different {@code transform(…)} methods. + * + * @throws InvalidGeodeticParameterException if {@link SpecializableTransform} constructor reject a parameter. + * @throws TransformException if a transformation failed. + */ + @Test + public void testConsistency() throws InvalidGeodeticParameterException, TransformException { + transform = create(); + isDerivativeSupported = false; // Actually supported, but our test transform has discontinuities. + isInverseTransformSupported = false; + verifyInDomain(CoordinateDomain.RANGE_10, -672445632505596619L); + } +} Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain;charset=UTF-8 Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -25,7 +25,7 @@ import org.junit.BeforeClass; * All tests from the {@code sis-referencing} module, in approximative dependency order. * * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.0 * @since 0.3 * @module */ @@ -131,6 +131,7 @@ import org.junit.BeforeClass; org.apache.sis.referencing.operation.transform.PolarToCartesianTest.class, org.apache.sis.referencing.operation.transform.CartesianToPolarTest.class, org.apache.sis.referencing.operation.transform.CoordinateSystemTransformTest.class, + org.apache.sis.referencing.operation.transform.SpecializableTransformTest.class, org.apache.sis.referencing.operation.DefaultFormulaTest.class, org.apache.sis.referencing.operation.DefaultOperationMethodTest.class, org.apache.sis.referencing.operation.AbstractSingleOperationTest.class, Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java?rev=1825688&r1=1825687&r2=1825688&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] Thu Mar 1 22:28:30 2018 @@ -41,6 +41,8 @@ import org.apache.sis.util.CharSequences import org.apache.sis.util.logging.Logging; import org.apache.sis.internal.system.Loggers; import org.apache.sis.internal.util.MetadataServices; +import org.apache.sis.measure.RangeFormat; +import org.apache.sis.measure.Range; /** @@ -69,7 +71,7 @@ import org.apache.sis.internal.util.Meta * multiple threads. * * @author Martin Desruisseaux (IRD, Geomatys) - * @version 0.8 + * @version 1.0 * @since 0.3 * @module */ @@ -419,6 +421,9 @@ public class IndexedResourceBundle exten replacement = Classes.getShortName(getPublicType((Class<?>) element)); } else if (element instanceof ControlledVocabulary) { replacement = MetadataServices.getInstance().getCodeTitle((ControlledVocabulary) element, getLocale()); + } else if (element instanceof Range<?>) { + final Range<?> range = (Range<?>) element; + replacement = new RangeFormat(getLocale(), range.getElementType()).format(range); } /* * No need to check for Numbers or Dates instances, since they are
