This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 3cb482cd8e35814b93712a05db5501fc05c554ae
Author: jsorel <[email protected]>
AuthorDate: Thu Oct 15 09:41:46 2026 +0200

    feat(Math): add Vector.copy(DataType) and Vector.perpendicular(Vector n)
---
 .../main/org/apache/sis/maths/ReadOnly.java        | 15 ++++++--
 .../main/org/apache/sis/maths/Vector.java          | 17 +++++++--
 .../main/org/apache/sis/maths/Vectors.java         | 40 ----------------------
 .../org/apache/sis/maths/AbstractVectorTest.java   | 40 ++++++++++++++++++++++
 4 files changed, 66 insertions(+), 46 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ReadOnly.java 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ReadOnly.java
index 2ba2034c93..33d3a4db8d 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ReadOnly.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ReadOnly.java
@@ -186,9 +186,18 @@ public final class ReadOnly {
          * @return tuple copy.
          */
         default org.apache.sis.maths.Vector<?> copy() {
-            org.apache.sis.maths.Vector<?> tuple = 
Vectors.create(getSampleSystem(), getDataType());
-            tuple.set(this);
-            return tuple;
+            return Vectors.create(getSampleSystem(), getDataType()).set(this);
+        }
+
+        /**
+         * Create a copy of this tuple, with values stored in the given data 
type.
+         * The copy has the same sample system as this tuple.
+         *
+         * @param  dataType  data type of the copy values.
+         * @return tuple copy.
+         */
+        default org.apache.sis.maths.Vector<?> copy(DataType dataType) {
+            return Vectors.create(getSampleSystem(), dataType).set(this);
         }
 
         /**
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vector.java 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vector.java
index 0e31d4ef6e..8cd77b98a0 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vector.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vector.java
@@ -174,9 +174,7 @@ public interface Vector<T extends Vector <T>> extends 
ReadOnly.Vector<T>{
      * @return tuple copy.
      */
     default T copy() {
-        T tuple = (T) Vectors.create(getSampleSystem(), getDataType());
-        tuple.set(this);
-        return tuple;
+        return (T) ReadOnly.Vector.super.copy();
     }
 
     /**
@@ -245,6 +243,19 @@ public interface Vector<T extends Vector <T>> extends 
ReadOnly.Vector<T>{
         return (T) this;
     }
 
+    /**
+     * Remove from this vector its component along the given unit vector.
+     * The result is the projection of this vector on the hyperplane 
perpendicular to the given vector.
+     *
+     * @param unit unit vector, of length 1
+     * @return this vector
+     */
+    default T perpendicular(ReadOnly.Vector<?> unit) {
+        final double[] u = unit.toArrayDouble();
+        set( Vectors.subtract(toArrayDouble(), Vectors.scale(u, dot(unit))));
+        return (T) this;
+    }
+
     /**
      * Linear interpolation from this vector to the other vector : 
(1-ratio)*this + ratio*other.
      *
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vectors.java 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vectors.java
index a6e539a091..1fced5a5e6 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vectors.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/Vectors.java
@@ -232,46 +232,6 @@ public final class Vectors {
         return new VectorUnmodifiable(tuple);
     }
 
-    private static class WrapTuple extends AbstractVector<WrapTuple> 
implements Vector<WrapTuple> {
-
-        private final Vector<?> pos;
-
-        public WrapTuple(Vector<?> pos, int size) {
-            super(size);
-            this.pos = pos;
-        }
-
-        public WrapTuple(Vector<?> pos) {
-            super(pos.getSampleSystem());
-            this.pos = pos;
-        }
-
-        @Override
-        public DataType getDataType() {
-            return pos.getDataType();
-        }
-
-        @Override
-        public double get(int indice) {
-            return pos.get(indice);
-        }
-
-        @Override
-        public void set(int indice, double value) {
-            pos.set(indice, value);
-        }
-
-        @Override
-        public int getDimension() {
-            return pos.getDimension();
-        }
-
-        @Override
-        public WrapTuple copy() {
-            return super.copy();
-        }
-    }
-
     private static class WrapDirectPostion extends 
AbstractVector<WrapDirectPostion> implements Vector<WrapDirectPostion> {
 
         private final DirectPosition pos;
diff --git 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/maths/AbstractVectorTest.java
 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/maths/AbstractVectorTest.java
index 9a6a5779ff..e61ef375c6 100644
--- 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/maths/AbstractVectorTest.java
+++ 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/maths/AbstractVectorTest.java
@@ -67,6 +67,7 @@ public abstract class AbstractVectorTest {
         testCellGetSet(tuple);
         testToArray(tuple);
         testEquality(tuple);
+        testCopyDataType(tuple);
 
         switch (tuple.getDataType()) {
             case BYTE :
@@ -101,6 +102,7 @@ public abstract class AbstractVectorTest {
         testAdd(tuple);
         testSubtract(tuple);
         testScale(tuple);
+        testPerpendicular(tuple);
         testCross(tuple);
         testDot(tuple);
     }
@@ -245,6 +247,24 @@ public abstract class AbstractVectorTest {
 
     }
 
+    /**
+     * Test copy in another data type.
+     */
+    private void testCopyDataType(Vector<?> tuple) {
+        for (int i = 0; i < tuple.getDimension(); i++) {
+            tuple.set(i, i+1);
+        }
+        for (final DataType dataType : new DataType[] {DataType.DOUBLE, 
DataType.FLOAT, DataType.SHORT}) {
+            final Vector<?> copy = tuple.copy(dataType);
+            assertEquals(dataType, copy.getDataType());
+            assertEquals(tuple.getSampleSystem(), copy.getSampleSystem());
+            assertArrayEquals(tuple.toArrayDouble(), copy.toArrayDouble(), 
TOLERANCE);
+            //the copy is independent of the original tuple
+            copy.set(0, 100);
+            assertEquals(1, tuple.get(0), TOLERANCE);
+        }
+    }
+
     private void testExtremum(Vector<?> tuple, double value) {
 
         for (int i=0;i<tuple.getDimension();i++) {
@@ -365,6 +385,26 @@ public abstract class AbstractVectorTest {
         assertArrayEquals(expected, vector.toArrayDouble(), TOLERANCE);
     }
 
+    /**
+     * Test removal of the component along a unit vector.
+     * The unit vector is along the first axis, so the result is exact for all 
data types.
+     */
+    private void testPerpendicular(Vector<?> vector) {
+        final int dim = vector.getDimension();
+
+        final Vector<?> unit = Vectors.createDouble(dim);
+        unit.set(0, 1);
+        for (int i = 0; i < dim; i++) {
+            vector.set(i, i+1);
+        }
+
+        final double[] expected = vector.toArrayDouble();
+        expected[0] = 0;
+        vector.perpendicular(unit);
+        assertArrayEquals(expected, vector.toArrayDouble(), TOLERANCE);
+        assertEquals(0, vector.dot(unit), TOLERANCE);
+    }
+
     /**
      * Test vector cross product.
      * Only tested if vector size is 3.

Reply via email to