This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 03e05e5 Allow `ResampledGridCoverage` to work (under some conditions)
even if the coordinate operation can not be reduced to 2 dimensions.
03e05e5 is described below
commit 03e05e58c5b5b7c93e41d843b3591e2f2900ef5b
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu May 28 14:10:04 2020 +0200
Allow `ResampledGridCoverage` to work (under some conditions) even if the
coordinate operation can not be reduced to 2 dimensions.
---
.../sis/coverage/grid/ResampledGridCoverage.java | 42 ++++++++-
.../java/org/apache/sis/image/PixelIterator.java | 4 +
.../java/org/apache/sis/image/ResampledImage.java | 4 +
.../org/apache/sis/internal/feature/Resources.java | 10 ++
.../sis/internal/feature/Resources.properties | 2 +
.../sis/internal/feature/Resources_fr.properties | 2 +
.../coverage/grid/ResampledGridCoverageTest.java | 7 +-
.../referencing/factory/sql/EPSGDataAccess.java | 2 +-
.../operation/transform/TransformSeparator.java | 103 +++++++++++++++------
.../transform/TransformSeparatorTest.java | 12 +++
.../java/org/apache/sis/measure/AngleFormat.java | 4 +-
11 files changed, 158 insertions(+), 34 deletions(-)
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
index f63b4c1..0a171fb 100644
---
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
+++
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
@@ -31,6 +31,7 @@ import org.apache.sis.geometry.Envelopes;
import org.apache.sis.image.ImageProcessor;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.internal.feature.Resources;
import org.apache.sis.internal.util.DoubleDouble;
import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix;
import org.apache.sis.referencing.operation.transform.LinearTransform;
@@ -376,7 +377,7 @@ final class ResampledGridCoverage extends GridCoverage {
GeneralEnvelope bounds = new
GeneralEnvelope(resampled.getEnvelope());
bounds.intersect(target.getEnvelope());
bounds = Envelopes.transform(targetCornerToCRS.inverse(),
bounds);
- targetExtent = new GridExtent(bounds,
GridRoundingMode.ENCLOSING, null, targetExtent, null);
+ targetExtent = new GridExtent(bounds,
GridRoundingMode.NEAREST, null, targetExtent, null);
resampled = new GridGeometry(targetExtent,
PixelInCell.CELL_CENTER, targetCenterToCRS, targetCRS);
isGeometryExplicit = true;
}
@@ -456,7 +457,44 @@ final class ResampledGridCoverage extends GridCoverage {
final TransformSeparator sep = new
TransformSeparator(toSourceCenter);
sep.addSourceDimensions(resampledDimensions);
sep.addTargetDimensions(sourceDimensions);
- final MathTransform toSourceSlice = sep.separate();
+ sep.setSourceExpandable(true);
+ MathTransform toSourceSlice = sep.separate();
+ final int[] requiredSources = sep.getSourceDimensions();
+ if (requiredSources.length > BIDIMENSIONAL) {
+ /*
+ * If we enter in this block, TransformSeparator can not
create a MathTransform with only the 2
+ * requested source dimensions; it needs more sources. In such
case, if coordinates in missing
+ * dimensions can be set to constant values (grid low == grid
high), create a transform which
+ * will add new dimensions with coordinates set to those
constant values. The example below
+ * passes the two first dimensions as-is and set the third
dimensions to constant value 7:
+ *
+ * ┌ ┐ ┌ ┐┌ ┐
+ * │ x │ │ 1 0 0 ││ x │
+ * │ y │ = │ 0 1 0 ││ y │
+ * │ z │ │ 0 0 7 ││ 1 │
+ * │ 1 │ │ 0 0 1 │└ ┘
+ * └ ┘ └ ┘
+ */
+ final MatrixSIS m = Matrices.createZero(requiredSources.length
+ 1, BIDIMENSIONAL + 1);
+ m.setElement(requiredSources.length, BIDIMENSIONAL, 1);
+ for (int j=0; j < requiredSources.length; j++) {
+ final int r = requiredSources[j];
+ final int i = Arrays.binarySearch(resampledDimensions, r);
+ if (i >= 0) {
+ m.setElement(j, i, 1);
+ } else {
+ final long low = sliceExtent.getLow(r);
+ if (low == sliceExtent.getHigh(r)) {
+ m.setElement(j, BIDIMENSIONAL, low);
+ } else {
+ throw new CannotEvaluateException(Resources.format(
+
Resources.Keys.TransformDependsOnDimension_1,
+ sliceExtent.getAxisIdentification(r, r)));
+ }
+ }
+ }
+ toSourceSlice =
MathTransforms.concatenate(MathTransforms.linear(m), toSourceSlice);
+ }
/*
* `this.toSource` is a transform from source cell coordinates to
target cell coordinates.
* We need a transform from source pixel coordinates to target
pixel coordinates (in images).
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java
b/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java
index cbc7d48..f3e53fd 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java
@@ -36,6 +36,7 @@ import org.opengis.coverage.grid.SequenceType;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.measure.NumberRange;
+import org.apache.sis.internal.feature.Resources;
import static java.lang.Math.floorDiv;
import static org.apache.sis.internal.util.Numerics.ceilDiv;
@@ -185,6 +186,9 @@ public abstract class PixelIterator {
*/
private static Rectangle intersection(int x, int y, int width, int height,
Rectangle subArea, Dimension window) {
if (window != null) {
+ if (width <= 0 || height <= 0) {
+ throw new
IllegalArgumentException(Resources.format(Resources.Keys.EmptyImage));
+ }
ArgumentChecks.ensureBetween("window.width", 1, width,
window.width);
ArgumentChecks.ensureBetween("window.height", 1, height,
window.height);
width -= (window.width - 1);
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
b/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
index 6418239..ab915da 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
@@ -34,6 +34,7 @@ import org.opengis.referencing.operation.TransformException;
import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.internal.coverage.j2d.ImageLayout;
import org.apache.sis.internal.coverage.j2d.ImageUtilities;
+import org.apache.sis.internal.feature.Resources;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.ArgumentChecks;
@@ -144,6 +145,9 @@ public class ResampledImage extends ComputedImage {
final Interpolation interpolation, final Number[]
fillValues)
{
super(ImageLayout.DEFAULT.createCompatibleSampleModel(source, bounds),
source);
+ if (source.getWidth() <= 0 || source.getHeight() <= 0) {
+ throw new
IllegalArgumentException(Resources.format(Resources.Keys.EmptyImage));
+ }
ArgumentChecks.ensureNonNull("interpolation", interpolation);
ArgumentChecks.ensureStrictlyPositive("width", width = bounds.width);
ArgumentChecks.ensureStrictlyPositive("height", height =
bounds.height);
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
index 5a790bf..5a0b823 100644
---
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
+++
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
@@ -148,6 +148,11 @@ public final class Resources extends IndexedResourceBundle
{
public static final short DependencyNotFound_3 = 8;
/**
+ * Image has zero pixel.
+ */
+ public static final short EmptyImage = 73;
+
+ /**
* Empty tile or image region.
*/
public static final short EmptyTileOrImageRegion = 67;
@@ -360,6 +365,11 @@ public final class Resources extends IndexedResourceBundle
{
public static final short TooManyQualitatives = 48;
/**
+ * Coordinate operation depends on grid dimension {0}.
+ */
+ public static final short TransformDependsOnDimension_1 = 74;
+
+ /**
* The {0} geometry library is not available in current runtime
environment.
*/
public static final short UnavailableGeometryLibrary_1 = 21;
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
index 3cb001c..fa83b8a 100644
---
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
+++
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
@@ -37,6 +37,7 @@ CategoryRangeOverlap_4 = The two categories
\u201c{0}\u201d and \u201
CharacteristicsAlreadyExists_2 = Characteristics \u201c{1}\u201d already
exists in attribute \u201c{0}\u201d.
CharacteristicsNotFound_2 = No characteristics named \u201c{1}\u201d
has been found in \u201c{0}\u201d attribute.
DependencyNotFound_3 = Operation \u201c{0}\u201d requires a
\u201c{1}\u201d property, but no such property has been found in
\u201c{2}\u201d.
+EmptyImage = Image has zero pixel.
EmptyTileOrImageRegion = Empty tile or image region.
GridCoordinateOutsideCoverage_4 = Indices ({3}) are outside grid coverage.
The value in dimension {0} shall be between {1,number} and {2,number} inclusive.
GridEnvelopeMustBeNDimensional_1 = The grid envelope must have at least {0}
dimensions.
@@ -77,6 +78,7 @@ PropertyAlreadyExists_2 = Property \u201c{1}\u201d
already exists in f
PropertyNotFound_2 = No property named \u201c{1}\u201d has been
found in \u201c{0}\u201d feature.
TileErrorFlagSet_2 = Tile ({0}, {1}) has the error flag set.
TooManyQualitatives = Too many qualitative categories.
+TransformDependsOnDimension_1 = Coordinate operation depends on grid
dimension {0}.
UnavailableGeometryLibrary_1 = The {0} geometry library is not available
in current runtime environment.
UnconvertibleGridCoordinate_2 = Can not convert grid coordinate {1} to
type \u2018{0}\u2019.
UnexpectedNumberOfBands_2 = Expected {0} bands but got {1}.
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
index 324af81..0e78e35 100644
---
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
+++
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
@@ -42,6 +42,7 @@ CategoryRangeOverlap_4 = Les deux cat\u00e9gories
\u00ab\u202f{0}\u20
CharacteristicsAlreadyExists_2 = La caract\u00e9ristique
\u00ab\u202f{1}\u202f\u00bb existe d\u00e9j\u00e0 dans l\u2019attribut
\u00ab\u202f{0}\u202f\u00bb.
CharacteristicsNotFound_2 = Aucune caract\u00e9ristique nomm\u00e9e
\u00ab\u202f{1}\u202f\u00bb n\u2019a \u00e9t\u00e9 trouv\u00e9e dans
l\u2019attribut \u00ab\u202f{0}\u202f\u00bb.
DependencyNotFound_3 = L\u2019op\u00e9ration
\u00ab\u202f{0}\u202f\u00bb n\u00e9cessite une propri\u00e9t\u00e9
\u00ab\u202f{1}\u202f\u00bb, mais cette propri\u00e9t\u00e9 n\u2019a pas
\u00e9t\u00e9 trouv\u00e9e dans \u00ab\u202f{2}\u202f\u00bb.
+EmptyImage = L\u2019image a z\u00e9ro pixel.
EmptyTileOrImageRegion = La tuile ou la r\u00e9gion de l\u2019image
est vide.
GridCoordinateOutsideCoverage_4 = Les indices ({3}) sont en dehors du
domaine de la grille. La valeur dans la dimension {0} doit \u00eatre entre
{1,number} et {2,number} inclusivement.
GridEnvelopeMustBeNDimensional_1 = L\u2019enveloppe de la grille doit avoir
au moins {0} dimensions.
@@ -83,6 +84,7 @@ PropertyAlreadyExists_2 = La propri\u00e9t\u00e9
\u00ab\u202f{1}\u202f
PropertyNotFound_2 = Aucune propri\u00e9t\u00e9 nomm\u00e9e
\u00ab\u202f{1}\u202f\u00bb n\u2019a \u00e9t\u00e9 trouv\u00e9e dans
l\u2019entit\u00e9 \u00ab\u202f{0}\u202f\u00bb.
TileErrorFlagSet_2 = La tuile ({0}, {1}) est marqu\u00e9e comme
ayant une erreur.
TooManyQualitatives = Trop de cat\u00e9gories qualitatives.
+TransformDependsOnDimension_1 = L\u2019op\u00e9ration sur les
coordonn\u00e9es d\u00e9pend de la dimension {0} de la grille.
UnavailableGeometryLibrary_1 = La biblioth\u00e8que de
g\u00e9om\u00e9tries {0} n\u2019est pas disponible dans l\u2019environnement
d\u2019ex\u00e9cution actuel.
UnconvertibleGridCoordinate_2 = Ne peut pas convertir la coordonn\u00e9e
de grille {1} vers le type \u2018{0}\u2019.
UnexpectedNumberOfBands_2 = On attendait {0} bandes mais {1} ont
\u00e9t\u00e9 sp\u00e9cifi\u00e9es.
diff --git
a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
index 5459f18..ae250e7 100644
---
a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
+++
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
@@ -464,7 +464,6 @@ public final strictfp class ResampledGridCoverageTest
extends TestCase {
* @throws TransformException if some coordinates can not be transformed
to the target grid geometry.
*/
@Test
- @org.junit.Ignore("Needs more development")
public void testNonSeparableGridToCRS() throws TransformException {
final GridCoverage source = createCoverageND(false);
final MatrixSIS nonSeparableMatrix = Matrices.createDiagonal(4, 4);
@@ -489,14 +488,16 @@ public final strictfp class ResampledGridCoverageTest
extends TestCase {
}
}
final GridGeometry targetGeom = new GridGeometry(
- source.getGridGeometry().getExtent(),
+ null, // Let the resample operation compute the
extent automatically.
CELL_CENTER, nonSeparableG2C,
source.getCoordinateReferenceSystem());
/*
* Real test is below (above code was only initialization).
+ * The source image is 6×6 but the target image is 7×7 with
+ * the last row and column left black.
*/
final GridCoverage result = resample(source, targetGeom);
- assertPixelsEqual(source.render(null), null, result.render(null),
null);
+ assertPixelsEqual(source.render(null), null, result.render(null), new
Rectangle(2*QS, 2*QS));
}
/**
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 472bda7..7dc1e3b 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -428,7 +428,7 @@ public class EPSGDataAccess extends
GeodeticAuthorityFactory implements CRSAutho
try {
/*
* Get the most recent version number from the history table. We
get the date in local timezone
- * instead then UTC because the date is for information purpose
only, and the local timezone is
+ * instead than UTC because the date is for information purpose
only, and the local timezone is
* more likely to be shown nicely (without artificial hours) to
the user.
*/
final String query = translator.apply("SELECT VERSION_NUMBER,
VERSION_DATE FROM [Version History]" +
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
index 3e26722..72e38f8 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
@@ -49,7 +49,7 @@ import org.apache.sis.util.ArraysExt;
* The output dimensions can be verified with a call to {@link
#getTargetDimensions()}.</div>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
* @since 0.7
* @module
*/
@@ -97,6 +97,15 @@ public class TransformSeparator {
private final MathTransformsOrFactory factory;
/**
+ * Whether {@link #separate()} is allowed to add new dimensions in {@link
#sourceDimensions}
+ * if this is required for computing all values specified in {@link
#targetDimensions}.
+ *
+ * @see #isSourceExpandable()
+ * @see #setSourceExpandable(boolean)
+ */
+ private boolean isSourceExpandable;
+
+ /**
* Constructs a separator for the given transform.
*
* @param transform the transform to separate.
@@ -119,13 +128,15 @@ public class TransformSeparator {
/**
* Resets this transform separator in the same state than after
construction. This method clears any
- * {@linkplain #getSourceDimensions() source dimensions} and {@linkplain
#getTargetDimensions() target dimensions} settings.
+ * {@linkplain #getSourceDimensions() source} and {@linkplain
#getTargetDimensions() target dimensions}
+ * settings and disables {@linkplain #isSourceExpandable() source
expansion}.
* This method can be invoked when the same {@code MathTransform} needs to
be separated in more than one part,
* for example an horizontal and a vertical component.
*/
public void clear() {
- sourceDimensions = null;
- targetDimensions = null;
+ sourceDimensions = null;
+ targetDimensions = null;
+ isSourceExpandable = false;
}
/**
@@ -351,6 +362,37 @@ public class TransformSeparator {
}
/**
+ * Returns whether {@code separate()} is allowed to expand the list of
source dimensions.
+ * The default value is {@code false}, which means that {@link
#separate()} either returns
+ * a {@link MathTransform} having exactly the requested {@linkplain
#getSourceDimensions()
+ * source dimensions}, or throws a {@link FactoryException}.
+ *
+ * @return whether {@code separate()} is allowed to add new source
dimensions
+ * instead of throwing a {@link FactoryException}.
+ *
+ * @since 1.1
+ */
+ public boolean isSourceExpandable() {
+ return isSourceExpandable;
+ }
+
+ /**
+ * Sets whether {@code separate()} is allowed to expand the list of source
dimensions.
+ * The default value is {@code false}, which means that {@code separate()}
will throw a {@link FactoryException}
+ * if some {@linkplain #getTargetDimensions() target dimensions} can not
be computed without inputs that are not
+ * in the list of {@linkplain #getSourceDimensions() source dimensions}.
If this flag is set to {@code true},
+ * then {@link #separate()} will be allowed to augment the list of source
dimensions with any inputs that are
+ * essential for producing all requested outputs.
+ *
+ * @param enabled whether to allow source dimensions expansion.
+ *
+ * @since 1.1
+ */
+ public void setSourceExpandable(final boolean enabled) {
+ isSourceExpandable = enabled;
+ }
+
+ /**
* Separates the math transform specified at construction time for given
dimension indices.
* This method creates a math transform that use only the {@linkplain
#addSourceDimensions(int...) specified
* source dimensions} and return only the {@linkplain
#addTargetDimensions(int...) specified target dimensions}.
@@ -377,7 +419,10 @@ public class TransformSeparator {
*/
public MathTransform separate() throws FactoryException {
MathTransform tr = transform;
- final boolean isSourceSpecified = (sourceDimensions != null);
+ final int[] specifiedSources = sourceDimensions;
+ if (isSourceExpandable) {
+ sourceDimensions = null; // Take all
sources for now, will filter later.
+ }
if (sourceDimensions == null || containsAll(sourceDimensions, 0,
tr.getSourceDimensions())) {
if (targetDimensions != null && !containsAll(targetDimensions, 0,
tr.getTargetDimensions())) {
tr = filterTargetDimensions(tr, targetDimensions);
@@ -395,7 +440,7 @@ public class TransformSeparator {
*/
final int[] requested = targetDimensions;
tr = filterSourceDimensions(tr, sourceDimensions); //
May update targetDimensions.
- assert ArraysExt.isSorted(targetDimensions, true) :
"targetDimensions";
+ assert ArraysExt.isSorted(targetDimensions, true);
if (requested != null) {
final int[] inferred = targetDimensions;
targetDimensions = requested;
@@ -428,8 +473,8 @@ public class TransformSeparator {
expected = targetDimensions.length;
actual = tr.getTargetDimensions();
if (actual == expected) {
- if (!isSourceSpecified) {
- tr = removeUnusedSourceDimensions(tr);
+ if (specifiedSources == null || isSourceExpandable) {
+ tr = removeUnusedSourceDimensions(tr, specifiedSources);
}
return tr;
}
@@ -683,44 +728,50 @@ reduce: for (int j=0; j <= numTgt; j++) {
/**
* Removes the sources dimensions that are not required for computing the
target dimensions.
- * This method is invoked only if {@link #sourceDimensions} is non-null at
{@link #separate()} invocation time.
+ * This method is invoked only if {@link #sourceDimensions} is null at
{@link #separate()} invocation time.
* This method can operate only on the first transform of a transformation
chain.
* If this method succeed, then {@link #sourceDimensions} will be updated.
*
* <p>This method can process only linear transforms (potentially
indirectly through a concatenated transform).
* Actually it would be possible to also process pass-through transform
followed by a linear transform, but this
* case should have been optimized during transform concatenation. If it
is not the case, consider improving the
- * {@link PassThroughTransform#tryConcatenate(boolean, MathTransform,
MathTransformFactory)} method instead then
+ * {@link PassThroughTransform#tryConcatenate(boolean, MathTransform,
MathTransformFactory)} method instead than
* this one.</p>
*
- * @param head the first transform of a transformation chain.
+ * @param head the first transform of a transformation chain.
+ * @param required sources to keep even if not necessary, or {@code
null} if none.
* @return the reduced transform, or {@code head} if this method did not
reduced the transform.
*/
- private MathTransform removeUnusedSourceDimensions(final MathTransform
head) {
+ private MathTransform removeUnusedSourceDimensions(final MathTransform
head, final int[] required) {
Matrix m = MathTransforms.getMatrix(head);
if (m != null) {
- int[] retainedDimensions = ArraysExt.EMPTY_INT;
- final int dimension = m.getNumCol() - 1; // Number of
source dimensions (ignore translations column).
- final int numRows = m.getNumRow(); // Number of
target dimensions + 1.
+ final int numRows = m.getNumRow(); // Number of
target dimensions + 1.
+ final int dimension = m.getNumCol() - 1; // Number of
source dimensions (ignore translations column).
+ int retainedCount = 0; // Number of
source dimensions to keep.
+ int[] retainedDimensions = new int[dimension];
for (int i=0; i<dimension; i++) {
- for (int j=0; j<numRows; j++) {
- if (m.getElement(j,i) != 0) {
- // Found a source dimension which is required by
target dimension.
- final int length = retainedDimensions.length;
- retainedDimensions = Arrays.copyOf(retainedDimensions,
length+1);
- retainedDimensions[length] = i;
- break;
+ if (required != null && Arrays.binarySearch(required, i) >= 0)
{
+ // Dimension to retain unconditionally.
+ retainedDimensions[retainedCount++] = i;
+ } else {
+ for (int j=0; j<numRows; j++) {
+ if (m.getElement(j,i) != 0) {
+ // Found a source dimension which is required by
target dimension.
+ retainedDimensions[retainedCount++] = i;
+ break;
+ }
}
}
}
- if (retainedDimensions.length != dimension) {
+ if (retainedCount != dimension) {
+ retainedDimensions = Arrays.copyOf(retainedDimensions,
retainedCount);
/*
* If we do not retain all dimensions, remove the matrix
columns corresponding to the excluded
* source dimensions and create a new transform. We remove
consecutive columns in single calls
* to 'removeColumns', from 'lower' inclusive to 'upper'
exclusive.
*/
int upper = dimension;
- for (int i = retainedDimensions.length; --i >= -1;) {
+ for (int i = retainedCount; --i >= -1;) {
final int keep = (i >= 0) ? retainedDimensions[i] : -1;
final int lower = keep + 1;
// First column to exclude.
if (lower != upper) {
@@ -733,7 +784,7 @@ reduce: for (int j=0; j <= numTgt; j++) {
* If the user specified source dimensions, the indices need
to be adjusted.
* This loop has no effect if all source dimensions were kept
before this method call.
*/
- for (int i=0; i<retainedDimensions.length; i++) {
+ for (int i=0; i<retainedCount; i++) {
retainedDimensions[i] =
sourceDimensions[retainedDimensions[i]];
}
sourceDimensions = retainedDimensions;
@@ -741,7 +792,7 @@ reduce: for (int j=0; j <= numTgt; j++) {
}
} else if (head instanceof ConcatenatedTransform) {
final MathTransform transform1 = ((ConcatenatedTransform)
head).transform1;
- final MathTransform reduced =
removeUnusedSourceDimensions(transform1);
+ final MathTransform reduced =
removeUnusedSourceDimensions(transform1, required);
if (reduced != transform1) {
return MathTransforms.concatenate(reduced,
((ConcatenatedTransform) head).transform2);
}
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
index 806ecfb..fbc6664 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
@@ -186,6 +186,18 @@ public final strictfp class TransformSeparatorTest extends
TestCase {
// This is the expected exception.
assertNotNull(e.getMessage());
}
+ /*
+ * Try again, but allow TransformSeparator to expand the list of
source dimensions.
+ */
+ s.setSourceExpandable(true);
+ matrix = Matrices.create(3, 4, new double[] {
+ 2, 0, 0, 7,
+ 0, 5, 0, 6,
+ 0, 0, 0, 1
+ });
+ assertMatrixEquals("transform", matrix, ((LinearTransform)
s.separate()).getMatrix(), STRICT);
+ assertArrayEquals("sourceDimensions", new int[] {0, 1, 2},
s.getSourceDimensions());
+ assertArrayEquals("targetDimensions", new int[] {0, 1},
s.getTargetDimensions());
}
/**
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
b/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
index c09d269..2e49157 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
@@ -1531,7 +1531,7 @@ BigBoss: switch (skipSuffix(source, pos,
DEGREES_FIELD)) {
/* ------------------------------------------
* STRING ANALYSIS FOLLOWING PRESUMED DEGREES
* ------------------------------------------
- * Found the seconds suffix instead then the degrees suffix.
Move 'degrees'
+ * Found the seconds suffix instead than the degrees suffix.
Move 'degrees'
* value to 'seconds' and stop parsing, since seconds are the
last field.
*/
case SECONDS_FIELD: {
@@ -1585,7 +1585,7 @@ BigBoss: switch (skipSuffix(source, pos,
DEGREES_FIELD)) {
/* ------------------------------------------
* STRING ANALYSIS FOLLOWING PRESUMED MINUTES
* ------------------------------------------
- * Found the seconds suffix instead then the minutes
suffix. Move 'minutes'
+ * Found the seconds suffix instead than the minutes
suffix. Move 'minutes'
* value to 'seconds' and stop parsing, since seconds
are the last field.
*/
case SECONDS_FIELD: {