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

commit b1182eb2d140e9802bad7283160ec3c661f59e3a
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Thu Feb 17 11:56:06 2022 +0100

    Fix ClassCastException when showing a GeoTIFF image with anchor points.
---
 .../apache/sis/internal/referencing/RTreeNode.java | 26 +++++++++++++---------
 .../transform/SpecializableTransform.java          | 11 ++++-----
 2 files changed, 21 insertions(+), 16 deletions(-)

diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/RTreeNode.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/RTreeNode.java
index 2ba0e4d..0c28dcb 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/RTreeNode.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/RTreeNode.java
@@ -194,14 +194,17 @@ detach: for (RTreeNode next; node != null; node = next) {
     }
 
     /**
-     * Finishes the construction of the tree. This methods sets the CRS of all 
nodes 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.
+     * Finishes the construction of the tree. This method should be invoked 
only on the instance
+     * on which {@link #addNode(RTreeNode)} has been invoked. It performs the 
following tasks:
      *
-     * <p>This method should be invoked only on the instance on which {@link 
#addNode(RTreeNode)} has been
-     * invoked.</p>
+     * <ol>
+     *   <li>Verify that all nodes have the same CRS or null CRS. 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.</li>
+     *   <li>Set the CRS of all nodes to the common value found in previous 
step.</li>
+     *   <li>Ensure that the tree has a single root, by creating a synthetic 
parent if necessary.</li>
+     * </ol>
      *
-     * @return the root of the tree (may be {@code this}).
+     * @return the root of the tree, which is {@code this} if this node has no 
sibling.
      */
     public final RTreeNode finish() {
         final Uniformizer action = new Uniformizer();
@@ -214,8 +217,9 @@ detach: for (RTreeNode next; node != null; node = next) {
         }
         /*
          * If there is more than one node, create a synthetic parent 
containing them all.
-         * We do not need to traverse all node for this task; only the 
immediate children
-         * of the new parent.
+         * We do not need to traverse all nodes for this task; only the 
immediate children
+         * of the new parent. The purpose of the synthetic parent is to have a 
single root
+         * (i.e. no sibling).
          */
         parent = new RTreeNode(this);
         parent.firstChild = this;
@@ -263,12 +267,12 @@ detach: for (RTreeNode next; node != null; node = next) {
      * to give to this method the most recently used node.</p>
      *
      * @param  node  any node in the tree. Should be node most likely to 
contain the position.
-     * @param  pos   the position of the node to locate.
-     * @return the smallest node containing the given position.
+     * @param  pos   the position of the node to locate, or {@code null} if 
none.
+     * @return the smallest node containing the given position, or {@code 
null} if none.
      */
     public static RTreeNode locate(RTreeNode node, final DirectPosition pos) {
         RTreeNode skip = null;      // For avoiding to invoke `contains(pos)` 
twice on the same mode.
-        do {
+        if (node != null) do {
             if (node.contains(pos)) {
                 /*
                  * Before to return the node we just found, check if a child 
contains the point.
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
index 9567bfc..25cd5b8 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
@@ -42,7 +42,7 @@ import org.apache.sis.util.Utilities;
  * The lower and upper values of given envelopes are inclusive.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
  *
  * @see MathTransforms#specialize(MathTransform, Map)
  *
@@ -132,6 +132,7 @@ class SpecializableTransform extends AbstractMathTransform 
implements Serializab
 
     /**
      * Domains where specialized transforms are valid. This is the root of an 
R-Tree.
+     * May be {@code null} if there is no R-Tree, in which case {@link 
#global} should be used instead.
      */
     private final RTreeNode domains;
 
@@ -255,7 +256,7 @@ class SpecializableTransform extends AbstractMathTransform 
implements Serializab
      */
     private MathTransform forDomain(final DirectPosition pos) {
         final RTreeNode domain = RTreeNode.locate(domains, pos);
-        return (domain != null) ? ((SubArea) domain).transform : global;
+        return (domain instanceof SubArea) ? ((SubArea) domain).transform : 
global;
     }
 
     /**
@@ -343,7 +344,7 @@ class SpecializableTransform extends AbstractMathTransform 
implements Serializab
                     if (--numPts <= 0) break;
                     next = SubArea.locate(domain, src);     // Cheaper check 
compared to the case where domain is null.
                 } while (next == domain);
-                domain = (SubArea) next;
+                domain = (next instanceof SubArea) ? (SubArea) next : null;
             }
             final int num = (src.offset - srcOff) / srcInc;
             int dstLow = dstOff;
@@ -460,7 +461,7 @@ class SpecializableTransform extends AbstractMathTransform 
implements Serializab
      */
     @Override
     protected final int computeHashCode() {
-        return super.computeHashCode() + 7*global.hashCode() ^ 
domains.hashCode();
+        return super.computeHashCode() + 7*global.hashCode() ^ 
Objects.hashCode(domains);
     }
 
     /**
@@ -652,7 +653,7 @@ class SpecializableTransform extends AbstractMathTransform 
implements Serializab
                     } while (next == domain);                       // 
Continue until we find a change of specialized transform.
                     num = (dst.offset - dstOff) / dstInc;           // Number 
of points to transform.
                     transform.apply(domain.inverse, srcOff, dstOff, num);
-                    domain = (SubArea) next;
+                    domain = (next instanceof SubArea) ? (SubArea) next : null;
                     srcOff += srcInc * num;
                     dstOff = dst.offset;
                 } while (domain != null);

Reply via email to