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 1f863a3c4f Be more conservative when analyzing the matrix for
pass-through coordinates during the concatenation of two `MathTransform`
instances.
1f863a3c4f is described below
commit 1f863a3c4ff409d8e69ccebd9a0def6a8637333b
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Jun 21 11:37:34 2025 +0200
Be more conservative when analyzing the matrix for pass-through coordinates
during the concatenation of two `MathTransform` instances.
---
.../operation/transform/TransformJoiner.java | 55 ++++++++++++++++++++--
1 file changed, 50 insertions(+), 5 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/TransformJoiner.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/TransformJoiner.java
index f4a0a49ca2..1c8a886b55 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/TransformJoiner.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/TransformJoiner.java
@@ -486,7 +486,7 @@ valid: if (i >= 0 && i < steps.size()) {
*/
public boolean replacePassThrough(Map<Integer,Integer> dimensions) throws
FactoryException {
Matrix before, after;
- if ((before = getMatrix(-1)) == null || (after = getMatrix(+1)) ==
null) {
+ if (!isAffine(before = getMatrix(-1)) || !isAffine(after =
getMatrix(+1))) {
return false;
}
/*
@@ -498,13 +498,20 @@ valid: if (i >= 0 && i < steps.size()) {
final var sourceToTarget = new LinkedHashMap<>(dimensions);
final var targetToSource = new LinkedHashMap<Integer,Integer>();
final MathTransform tr = steps.get(replaceIndex);
- sourceToTarget.putIfAbsent(tr.getSourceDimensions(),
- tr.getTargetDimensions()); // For the
last row and the translation column in matrices.
- sourceToTarget.forEach((source, target) -> {
+ sourceToTarget.put(tr.getSourceDimensions(),
+ tr.getTargetDimensions()); // For the last row
and the translation column in matrices.
+ for (final var it = sourceToTarget.entrySet().iterator();
it.hasNext();) {
+ final Map.Entry<Integer, Integer> entry = it.next();
+ final Integer source = entry.getKey();
+ final Integer target = entry.getValue();
if (targetToSource.put(target, source) != null) {
throw new
IllegalArgumentException(Errors.format(Errors.Keys.DuplicatedNumber_1, target));
}
- });
+ // See the "Invariants: When `moveFromBeforeToAfter` = true"
comment below in this method.
+ if (source >= before.getNumCol()) {
+ it.remove();
+ }
+ }
/*
* Modify the maps for keeping only the dimensions that we can move.
Then, choose which matrix
* to partially simplify in order to get a matrix as close as possible
to an identity matrix:
@@ -542,6 +549,24 @@ valid: if (i >= 0 && i < steps.size()) {
/*
* Creates a copy of the matrix which will contain the remaining
elements after the moves.
* Create an initially empty matrix which will contain the elements
that have been moved.
+ * Invariants:
+ *
+ * When `moveFromBeforeToAfter` = true:
+ * Simplify `before` and will prepend `moved` before `after`.
+ * simplified.numRow = before.numRow ≥ (srcRow =
dimensions.key) ⟶ SAFE
+ * simplified.numCol = before.numCol (unrelated to
keys) ⟶ UNSAFE
+ * moved.numRow = after.numcol ≥ (tgtRow =
dimensions.values) ⟶ SAFE
+ * moved.numCol = after.numcol ≥ (tgtCol =
dimensions.values) ⟶ SAFE
+ *
+ * When `moveFromBeforeToAfter` = false:
+ * Simplify `after` and will append `moved` after `before`.
+ * simplified.numRow = after.numRow (unrelated to
keys) ⟶ UNSAFE
+ * simplified.numCol = after.numCol ≥ (srcCol =
dimensions.keys) ⟶ SAFE
+ * moved.numRow = before.numRow ≥ (tgtRow =
dimensions.values) ⟶ SAFE
+ * moved.numCol = before.numRow ≥ (tgtCol =
dimensions.values) ⟶ SAFE
+ *
+ * The unsafe case of the latter is excluded in the following loop.
+ * The unsafe case of the former was handled in code above by removing
the keys that are too large.
*/
final MatrixSIS simplified = Matrices.copy(moveFromBeforeToAfter ?
before : after);
final int dim = moveFromBeforeToAfter ? after.getNumCol() :
before.getNumRow();
@@ -853,6 +878,26 @@ valid: if (i >= 0 && i < steps.size()) {
return null;
}
+ /**
+ * Returns whether the last row contains only zeros except the last
element which shall be 1.
+ * This method differs from {@link Matrices#isAffine(Matrix)} in that it
returns {@code false}
+ * if the given argument is {@code null} and does not require the matrix
to square.
+ */
+ private static boolean isAffine(final Matrix matrix) {
+ if (matrix == null) {
+ return false;
+ }
+ double e = 1;
+ final int j = matrix.getNumRow() - 1;
+ for (int i = matrix.getNumCol(); --i >= 0;) {
+ if (matrix.getElement(j, i) != e) {
+ return false;
+ }
+ e = 0;
+ }
+ return true;
+ }
+
/**
* Returns {@code true} if {@code tr1} is the inverse of {@code tr2}.
* If this method is unsure, it conservatively returns {@code false}.