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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 7bd94f14bb feat(Vector): add method to convert between lat/lon and 
unit vector
7bd94f14bb is described below

commit 7bd94f14bb869d23df224c8b56794d7eb130f214
Author: jsorel <[email protected]>
AuthorDate: Wed Aug 5 14:25:39 2026 +0200

    feat(Vector): add method to convert between lat/lon and unit vector
---
 .../org/apache/sis/geometries/math/Vector3D.java   |  29 ++++++
 .../apache/sis/geometries/math/Vector3DTest.java   | 108 +++++++++++++++++++++
 2 files changed, 137 insertions(+)

diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/math/Vector3D.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/math/Vector3D.java
index bef1424d78..4e15b1f316 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/math/Vector3D.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/math/Vector3D.java
@@ -94,6 +94,35 @@ public abstract class Vector3D<T extends Vector3D<T>> 
extends AbstractTuple<T> i
         return (T) this;
     }
 
+    /**
+     * Convert latitude/longitude radian angles to a unit vector
+     * and store the values in this vector.
+     *
+     * @param latRad in range [-PI/2 .. +PI/2]
+     * @param lonRad in range [-PI .. +PI]
+     * @return this vector
+     */
+    public T setFromLatLon(double latRad, double lonRad) {
+        double cosLat = Math.cos(latRad);
+        set(0, cosLat * Math.cos(lonRad));
+        set(1, cosLat * Math.sin(lonRad));
+        set(2,          Math.sin(latRad));
+        return (T) this;
+    }
+
+    /**
+     * Convert this vector to latitude/longitude radian angles.
+     * This vector is expected to be a unit vector.
+     *
+     * @return latitude/longitude in radians
+     */
+    public double[] toLatLon() {
+        final double latRad = Math.asin(Maths.clamp(get(2), -1, 1));
+        final double lonRad = Math.atan2(get(1), get(0));
+        return new double[]{latRad, lonRad};
+    }
+
+
     @Override
     public final int getDimension() {
         return 3;
diff --git 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/math/Vector3DTest.java
 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/math/Vector3DTest.java
new file mode 100644
index 0000000000..710858392b
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/math/Vector3DTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.geometries.math;
+
+// Test dependencies
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * Tests for {@link Vector3D#setFromLatLon(double, double) } and
+ * {@link Vector3D#toLatLon() }.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public class Vector3DTest {
+
+    private static final double TOLERANCE = 1e-12;
+    private static final double HALF_SQRT2 = Math.sqrt(2) / 2;
+
+    /**
+     * setFromLatLon test on remarkable points : equator/meridian origin,
+     * poles, and a quadrant point.
+     */
+    @Test
+    public void setFromLatLonTest() {
+        Vector3D.Double v = new Vector3D.Double();
+
+        v.setFromLatLon(0, 0);
+        assertArrayEquals(new double[]{1, 0, 0}, v.toArrayDouble(), TOLERANCE);
+
+        v.setFromLatLon(0, Math.PI / 2);
+        assertArrayEquals(new double[]{0, 1, 0}, v.toArrayDouble(), TOLERANCE);
+
+        v.setFromLatLon(0, Math.PI);
+        assertArrayEquals(new double[]{-1, 0, 0}, v.toArrayDouble(), 
TOLERANCE);
+
+        v.setFromLatLon(Math.PI / 2, 0);
+        assertArrayEquals(new double[]{0, 0, 1}, v.toArrayDouble(), TOLERANCE);
+
+        v.setFromLatLon(-Math.PI / 2, 0);
+        assertArrayEquals(new double[]{0, 0, -1}, v.toArrayDouble(), 
TOLERANCE);
+
+        v.setFromLatLon(Math.PI / 4, Math.PI / 4);
+        assertArrayEquals(new double[]{0.5, 0.5, HALF_SQRT2}, 
v.toArrayDouble(), TOLERANCE);
+    }
+
+    /**
+     * toLatLon test on remarkable unit vectors : axis directions and a
+     * quadrant point.
+     */
+    @Test
+    public void toLatLonTest() {
+        assertArrayEquals(new double[]{0, 0},
+                new Vector3D.Double(1, 0, 0).toLatLon(), TOLERANCE);
+
+        assertArrayEquals(new double[]{0, Math.PI / 2},
+                new Vector3D.Double(0, 1, 0).toLatLon(), TOLERANCE);
+
+        assertArrayEquals(new double[]{0, Math.PI},
+                new Vector3D.Double(-1, 0, 0).toLatLon(), TOLERANCE);
+
+        assertArrayEquals(new double[]{Math.PI / 2, 0},
+                new Vector3D.Double(0, 0, 1).toLatLon(), TOLERANCE);
+
+        assertArrayEquals(new double[]{-Math.PI / 2, 0},
+                new Vector3D.Double(0, 0, -1).toLatLon(), TOLERANCE);
+
+        assertArrayEquals(new double[]{Math.PI / 4, Math.PI / 4},
+                new Vector3D.Double(0.5, 0.5, HALF_SQRT2).toLatLon(), 
TOLERANCE);
+    }
+
+    /**
+     * Round trip test : converting latitude/longitude to a vector and back
+     * must return the original angles, for a set of angles away from the
+     * poles where longitude stays well defined.
+     */
+    @Test
+    public void latLonRoundTripTest() {
+        final double[] latitudes = {-Math.PI / 3, -Math.PI / 6, 0, Math.PI / 
6, Math.PI / 3};
+        final double[] longitudes = {-3 * Math.PI / 4, -Math.PI / 3, 0, 
Math.PI / 3, 3 * Math.PI / 4};
+
+        final Vector3D.Double v = new Vector3D.Double();
+        for (double lat : latitudes) {
+            for (double lon : longitudes) {
+                v.setFromLatLon(lat, lon);
+                final double[] latLon = v.toLatLon();
+                assertEquals(lat, latLon[0], TOLERANCE);
+                assertEquals(lon, latLon[1], TOLERANCE);
+            }
+        }
+    }
+
+}

Reply via email to