You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2018/09/14 00:20:40 UTC

[commons-geometry] 07/14: GEOMETRY-9: adding lerp method to Euclidean points and vectors

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

erans pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-geometry.git

commit 43cbc50bae35be37f19f9c955a90803e08af7fa2
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sun Sep 2 23:27:19 2018 -0400

    GEOMETRY-9: adding lerp method to Euclidean points and vectors
---
 .../commons/geometry/euclidean/EuclideanPoint.java | 10 +++++
 .../geometry/euclidean/EuclideanVector.java        | 10 +++++
 .../commons/geometry/euclidean/oned/Point1D.java   | 18 ++++++++
 .../commons/geometry/euclidean/oned/Vector1D.java  | 18 ++++++++
 .../commons/geometry/euclidean/threed/Point3D.java | 18 ++++++++
 .../geometry/euclidean/threed/Vector3D.java        | 18 ++++++++
 .../commons/geometry/euclidean/twod/Point2D.java   | 18 ++++++++
 .../commons/geometry/euclidean/twod/Vector2D.java  | 18 ++++++++
 .../geometry/euclidean/oned/Point1DTest.java       | 52 ++++++++++++++++++++++
 .../geometry/euclidean/oned/Vector1DTest.java      | 52 ++++++++++++++++++++++
 .../geometry/euclidean/threed/Point3DTest.java     | 52 ++++++++++++++++++++++
 .../geometry/euclidean/threed/Vector3DTest.java    | 52 ++++++++++++++++++++++
 .../geometry/euclidean/twod/Point2DTest.java       | 52 ++++++++++++++++++++++
 .../geometry/euclidean/twod/Vector2DTest.java      | 52 ++++++++++++++++++++++
 14 files changed, 440 insertions(+)

diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanPoint.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanPoint.java
index 033b6bd..4941306 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanPoint.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanPoint.java
@@ -40,4 +40,14 @@ public interface EuclideanPoint<P extends EuclideanPoint<P, V>, V extends Euclid
      * @return vector representing the displacement <em>from</em> this point <em>to</em> the given point
      */
     V vectorTo(P p);
+
+    /** Linearly interpolates between this point and the given point using the equation
+     * {@code P = (1 - t)*A + t*B}, where {@code A} is the current point and {@code B}
+     * is the given point. This means that if {@code t = 0}, a point equal to the current
+     * point will be returned. If {@code t = 1}, a point equal to the argument will be returned.
+     * @param p other point
+     * @param t interpolation parameter
+     * @return interpolated point
+     */
+    P lerp(P p, double t);
 }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanVector.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanVector.java
index 0622c89..923df74 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanVector.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanVector.java
@@ -32,4 +32,14 @@ public interface EuclideanVector<P extends EuclideanPoint<P, V>, V extends Eucli
      * @return point with the same coordinates as this vector
      */
     P asPoint();
+
+    /** Linearly interpolates between this vector and the given vector using the equation
+     * {@code V = (1 - t)*A + t*B}, where {@code A} is the current vector and {@code B}
+     * is the given vector. This means that if {@code t = 0}, a vector equal to the current
+     * vector will be returned. If {@code t = 1}, a vector equal to the argument will be returned.
+     * @param v other vector
+     * @param t interpolation parameter
+     * @return interpolated vector
+     */
+    V lerp(V p, double t);
 }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
index af324c1..b304014 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Point1D.java
@@ -94,6 +94,12 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
 
     /** {@inheritDoc} */
     @Override
+    public Point1D lerp(Point1D p, double t) {
+        return vectorCombination(1.0 - t, this, t, p);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public Point1D add(Vector1D v) {
         return new Point1D(getX() + v.getX());
     }
@@ -174,6 +180,18 @@ public final class Point1D extends Cartesian1D implements EuclideanPoint<Point1D
         return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
+    /** Linearly interpolates between the two given points. This methods simply
+     * calls {@code a.lerp(b, t)}.
+     * @param a first point
+     * @param b second point
+     * @param t interpolation parameter
+     * @return the interpolated point
+     * @see #lerp(Point1D, double)
+     */
+    public static Point1D lerp(Point1D a, Point1D b, double t) {
+        return a.lerp(b, t);
+    }
+
     /** Returns a point with coordinates calculated by multiplying each input coordinate
      * with its corresponding factor and adding the results.
      *
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
index 207f949..dea8636 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
@@ -80,6 +80,12 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
 
     /** {@inheritDoc} */
     @Override
+    public Vector1D lerp(Vector1D p, double t) {
+        return linearCombination(1.0 - t, this, t, p);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public Vector1D getZero() {
         return ZERO;
     }
@@ -281,6 +287,18 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
         return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
+    /** Linearly interpolates between the two given vectors. This methods simply
+     * calls {@code a.lerp(b, t)}.
+     * @param a first vector
+     * @param b second vector
+     * @param t interpolation parameter
+     * @return the interpolated vector
+     * @see #lerp(Vector1D, double)
+     */
+    public static Vector1D lerp(Vector1D a, Vector1D b, double t) {
+        return a.lerp(b, t);
+    }
+
     /** Returns a vector consisting of the linear combination of the inputs.
      * <p>
      * A linear combination is the sum of all of the inputs multiplied by their
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
index 92d861a..f8146a5 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
@@ -100,6 +100,12 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
 
     /** {@inheritDoc} */
     @Override
+    public Point3D lerp(Point3D p, double t) {
+        return vectorCombination(1.0 - t, this, t, p);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public Point3D add(Vector3D v) {
         return new Point3D(
                     getX() + v.getX(),
@@ -209,6 +215,18 @@ public final class Point3D extends Cartesian3D implements EuclideanPoint<Point3D
         return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
+    /** Linearly interpolates between the two given points. This methods simply
+     * calls {@code a.lerp(b, t)}.
+     * @param a first point
+     * @param b second point
+     * @param t interpolation parameter
+     * @return the interpolated point
+     * @see #lerp(Point3D, double)
+     */
+    public static Point3D lerp(Point3D a, Point3D b, double t) {
+        return a.lerp(b, t);
+    }
+
     /** Returns a point with coordinates calculated by multiplying each input coordinate
      * with its corresponding factor and adding the results.
      *
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
index a84f3d7..0f28c22 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
@@ -99,6 +99,12 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
 
     /** {@inheritDoc} */
     @Override
+    public Vector3D lerp(Vector3D p, double t) {
+        return linearCombination(1.0 - t, this, t, p);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public double getNorm1() {
         return Vectors.norm1(getX(), getY(), getZ());
     }
@@ -530,6 +536,18 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
         return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
+    /** Linearly interpolates between the two given vectors. This methods simply
+     * calls {@code a.lerp(b, t)}.
+     * @param a first vector
+     * @param b second vector
+     * @param t interpolation parameter
+     * @return the interpolated vector
+     * @see #lerp(Vector3D, double)
+     */
+    public static Vector3D lerp(Vector3D a, Vector3D b, double t) {
+        return a.lerp(b, t);
+    }
+
     /** Returns a vector consisting of the linear combination of the inputs.
      * <p>
      * A linear combination is the sum of all of the inputs multiplied by their
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
index a994c45..5f781d4 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
@@ -91,6 +91,12 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
 
     /** {@inheritDoc} */
     @Override
+    public Point2D lerp(Point2D p, double t) {
+        return vectorCombination(1.0 - t, this, t, p);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public Point2D add(Vector2D v) {
         return new Point2D(getX() + v.getX(), getY() + v.getY());
     }
@@ -192,6 +198,18 @@ public final class Point2D extends Cartesian2D implements EuclideanPoint<Point2D
         return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
+    /** Linearly interpolates between the two given points. This methods simply
+     * calls {@code a.lerp(b, t)}.
+     * @param a first point
+     * @param b second point
+     * @param t interpolation parameter
+     * @return the interpolated point
+     * @see #lerp(Point2D, double)
+     */
+    public static Point2D lerp(Point2D a, Point2D b, double t) {
+        return a.lerp(b, t);
+    }
+
     /** Returns a point with coordinates calculated by multiplying each input coordinate
      * with its corresponding factor and adding the results.
      *
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
index 2f39b06..bf2b691 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
@@ -93,6 +93,12 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
 
     /** {@inheritDoc} */
     @Override
+    public Vector2D lerp(Vector2D p, double t) {
+        return linearCombination(1.0 - t, this, t, p);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public Vector2D getZero() {
         return ZERO;
     }
@@ -461,6 +467,18 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
         return SimpleTupleFormat.getDefault().parse(str, FACTORY);
     }
 
+    /** Linearly interpolates between the two given vectors. This methods simply
+     * calls {@code a.lerp(b, t)}.
+     * @param a first vector
+     * @param b second vector
+     * @param t interpolation parameter
+     * @return the interpolated vector
+     * @see #lerp(Vector2D, double)
+     */
+    public static Vector2D lerp(Vector2D a, Vector2D b, double t) {
+        return a.lerp(b, t);
+    }
+
     /** Returns a vector consisting of the linear combination of the inputs.
      * <p>
      * A linear combination is the sum of all of the inputs multiplied by their
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
index 8233d1c..262204f 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Point1DTest.java
@@ -118,6 +118,58 @@ public class Point1DTest {
     }
 
     @Test
+    public void testLerp() {
+        // arrange
+        Point1D p1 = Point1D.of(1);
+        Point1D p2 = Point1D.of(-4);
+        Point1D p3 = Point1D.of(10);
+
+        // act/assert
+        checkPoint(p1.lerp(p1, 0), 1);
+        checkPoint(p1.lerp(p1, 1), 1);
+
+        checkPoint(p1.lerp(p2, -0.25), 2.25);
+        checkPoint(p1.lerp(p2, 0), 1);
+        checkPoint(p1.lerp(p2, 0.25), -0.25);
+        checkPoint(p1.lerp(p2, 0.5), -1.5);
+        checkPoint(p1.lerp(p2, 0.75), -2.75);
+        checkPoint(p1.lerp(p2, 1), -4);
+        checkPoint(p1.lerp(p2, 1.25), -5.25);
+
+        checkPoint(p1.lerp(p3, 0), 1);
+        checkPoint(p1.lerp(p3, 0.25), 3.25);
+        checkPoint(p1.lerp(p3, 0.5), 5.5);
+        checkPoint(p1.lerp(p3, 0.75), 7.75);
+        checkPoint(p1.lerp(p3, 1), 10);
+    }
+
+    @Test
+    public void testLerp_static() {
+        // arrange
+        Point1D p1 = Point1D.of(1);
+        Point1D p2 = Point1D.of(-4);
+        Point1D p3 = Point1D.of(10);
+
+        // act/assert
+        checkPoint(Point1D.lerp(p1, p1, 0), 1);
+        checkPoint(Point1D.lerp(p1, p1, 1), 1);
+
+        checkPoint(Point1D.lerp(p1, p2, -0.25), 2.25);
+        checkPoint(Point1D.lerp(p1, p2, 0), 1);
+        checkPoint(Point1D.lerp(p1, p2, 0.25), -0.25);
+        checkPoint(Point1D.lerp(p1, p2, 0.5), -1.5);
+        checkPoint(Point1D.lerp(p1, p2, 0.75), -2.75);
+        checkPoint(Point1D.lerp(p1, p2, 1), -4);
+        checkPoint(Point1D.lerp(p1, p2, 1.25), -5.25);
+
+        checkPoint(Point1D.lerp(p1, p3, 0), 1);
+        checkPoint(Point1D.lerp(p1, p3, 0.25), 3.25);
+        checkPoint(Point1D.lerp(p1, p3, 0.5), 5.5);
+        checkPoint(Point1D.lerp(p1, p3, 0.75), 7.75);
+        checkPoint(Point1D.lerp(p1, p3, 1), 10);
+    }
+
+    @Test
     public void testAdd() {
         // arrange
         Point1D p1 = Point1D.of(2.0);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
index 2ac2cc7..14b40b7 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
@@ -292,6 +292,58 @@ public class Vector1DTest {
     }
 
     @Test
+    public void testLerp() {
+        // arrange
+        Vector1D v1 = Vector1D.of(1);
+        Vector1D v2 = Vector1D.of(-4);
+        Vector1D v3 = Vector1D.of(10);
+
+        // act/assert
+        checkVector(v1.lerp(v1, 0), 1);
+        checkVector(v1.lerp(v1, 1), 1);
+
+        checkVector(v1.lerp(v2, -0.25), 2.25);
+        checkVector(v1.lerp(v2, 0), 1);
+        checkVector(v1.lerp(v2, 0.25), -0.25);
+        checkVector(v1.lerp(v2, 0.5), -1.5);
+        checkVector(v1.lerp(v2, 0.75), -2.75);
+        checkVector(v1.lerp(v2, 1), -4);
+        checkVector(v1.lerp(v2, 1.25), -5.25);
+
+        checkVector(v1.lerp(v3, 0), 1);
+        checkVector(v1.lerp(v3, 0.25), 3.25);
+        checkVector(v1.lerp(v3, 0.5), 5.5);
+        checkVector(v1.lerp(v3, 0.75), 7.75);
+        checkVector(v1.lerp(v3, 1), 10);
+    }
+
+    @Test
+    public void testLerp_static() {
+        // arrange
+        Vector1D v1 = Vector1D.of(1);
+        Vector1D v2 = Vector1D.of(-4);
+        Vector1D v3 = Vector1D.of(10);
+
+        // act/assert
+        checkVector(Vector1D.lerp(v1, v1, 0), 1);
+        checkVector(Vector1D.lerp(v1, v1, 1), 1);
+
+        checkVector(Vector1D.lerp(v1, v2, -0.25), 2.25);
+        checkVector(Vector1D.lerp(v1, v2, 0), 1);
+        checkVector(Vector1D.lerp(v1, v2, 0.25), -0.25);
+        checkVector(Vector1D.lerp(v1, v2, 0.5), -1.5);
+        checkVector(Vector1D.lerp(v1, v2, 0.75), -2.75);
+        checkVector(Vector1D.lerp(v1, v2, 1), -4);
+        checkVector(Vector1D.lerp(v1, v2, 1.25), -5.25);
+
+        checkVector(Vector1D.lerp(v1, v3, 0), 1);
+        checkVector(Vector1D.lerp(v1, v3, 0.25), 3.25);
+        checkVector(Vector1D.lerp(v1, v3, 0.5), 5.5);
+        checkVector(Vector1D.lerp(v1, v3, 0.75), 7.75);
+        checkVector(Vector1D.lerp(v1, v3, 1), 10);
+    }
+
+    @Test
     public void testHashCode() {
         // arrange
         Vector1D u = Vector1D.of(1);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
index b76cbda..17bfcb5 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Point3DTest.java
@@ -103,6 +103,58 @@ public class Point3DTest {
     }
 
     @Test
+    public void testLerp() {
+        // arrange
+        Point3D p1 = Point3D.of(1, -5, 2);
+        Point3D p2 = Point3D.of(-4, 0, 2);
+        Point3D p3 = Point3D.of(10, -4, 0);
+
+        // act/assert
+        checkPoint(p1.lerp(p1, 0), 1, -5, 2);
+        checkPoint(p1.lerp(p1, 1), 1, -5, 2);
+
+        checkPoint(p1.lerp(p2, -0.25), 2.25, -6.25, 2);
+        checkPoint(p1.lerp(p2, 0), 1, -5, 2);
+        checkPoint(p1.lerp(p2, 0.25), -0.25, -3.75, 2);
+        checkPoint(p1.lerp(p2, 0.5), -1.5, -2.5, 2);
+        checkPoint(p1.lerp(p2, 0.75), -2.75, -1.25, 2);
+        checkPoint(p1.lerp(p2, 1), -4, 0, 2);
+        checkPoint(p1.lerp(p2, 1.25), -5.25, 1.25, 2);
+
+        checkPoint(p1.lerp(p3, 0), 1, -5, 2);
+        checkPoint(p1.lerp(p3, 0.25), 3.25, -4.75, 1.5);
+        checkPoint(p1.lerp(p3, 0.5), 5.5, -4.5, 1);
+        checkPoint(p1.lerp(p3, 0.75), 7.75, -4.25, 0.5);
+        checkPoint(p1.lerp(p3, 1), 10, -4, 0);
+    }
+
+    @Test
+    public void testLerp_static() {
+        // arrange
+        Point3D p1 = Point3D.of(1, -5, 2);
+        Point3D p2 = Point3D.of(-4, 0, 2);
+        Point3D p3 = Point3D.of(10, -4, 0);
+
+        // act/assert
+        checkPoint(Point3D.lerp(p1, p1, 0), 1, -5, 2);
+        checkPoint(Point3D.lerp(p1, p1, 1), 1, -5, 2);
+
+        checkPoint(Point3D.lerp(p1, p2, -0.25), 2.25, -6.25, 2);
+        checkPoint(Point3D.lerp(p1, p2, 0), 1, -5, 2);
+        checkPoint(Point3D.lerp(p1, p2, 0.25), -0.25, -3.75, 2);
+        checkPoint(Point3D.lerp(p1, p2, 0.5), -1.5, -2.5, 2);
+        checkPoint(Point3D.lerp(p1, p2, 0.75), -2.75, -1.25, 2);
+        checkPoint(Point3D.lerp(p1, p2, 1), -4, 0, 2);
+        checkPoint(Point3D.lerp(p1, p2, 1.25), -5.25, 1.25, 2);
+
+        checkPoint(Point3D.lerp(p1, p3, 0), 1, -5, 2);
+        checkPoint(Point3D.lerp(p1, p3, 0.25), 3.25, -4.75, 1.5);
+        checkPoint(Point3D.lerp(p1, p3, 0.5), 5.5, -4.5, 1);
+        checkPoint(Point3D.lerp(p1, p3, 0.75), 7.75, -4.25, 0.5);
+        checkPoint(Point3D.lerp(p1, p3, 1), 10, -4, 0);
+    }
+
+    @Test
     public void testAdd() {
         // act/assert
         Point3D p1 = Point3D.of(1, 2, 3);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
index 2abc8f5..4febb3b 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
@@ -811,6 +811,58 @@ public class Vector3DTest {
     }
 
     @Test
+    public void testLerp() {
+        // arrange
+        Vector3D v1 = Vector3D.of(1, -5, 2);
+        Vector3D v2 = Vector3D.of(-4, 0, 2);
+        Vector3D v3 = Vector3D.of(10, -4, 0);
+
+        // act/assert
+        checkVector(v1.lerp(v1, 0), 1, -5, 2);
+        checkVector(v1.lerp(v1, 1), 1, -5, 2);
+
+        checkVector(v1.lerp(v2, -0.25), 2.25, -6.25, 2);
+        checkVector(v1.lerp(v2, 0), 1, -5, 2);
+        checkVector(v1.lerp(v2, 0.25), -0.25, -3.75, 2);
+        checkVector(v1.lerp(v2, 0.5), -1.5, -2.5, 2);
+        checkVector(v1.lerp(v2, 0.75), -2.75, -1.25, 2);
+        checkVector(v1.lerp(v2, 1), -4, 0, 2);
+        checkVector(v1.lerp(v2, 1.25), -5.25, 1.25, 2);
+
+        checkVector(v1.lerp(v3, 0), 1, -5, 2);
+        checkVector(v1.lerp(v3, 0.25), 3.25, -4.75, 1.5);
+        checkVector(v1.lerp(v3, 0.5), 5.5, -4.5, 1);
+        checkVector(v1.lerp(v3, 0.75), 7.75, -4.25, 0.5);
+        checkVector(v1.lerp(v3, 1), 10, -4, 0);
+    }
+
+    @Test
+    public void testLerp_static() {
+        // arrange
+        Vector3D v1 = Vector3D.of(1, -5, 2);
+        Vector3D v2 = Vector3D.of(-4, 0, 2);
+        Vector3D v3 = Vector3D.of(10, -4, 0);
+
+        // act/assert
+        checkVector(Vector3D.lerp(v1, v1, 0), 1, -5, 2);
+        checkVector(Vector3D.lerp(v1, v1, 1), 1, -5, 2);
+
+        checkVector(Vector3D.lerp(v1, v2, -0.25), 2.25, -6.25, 2);
+        checkVector(Vector3D.lerp(v1, v2, 0), 1, -5, 2);
+        checkVector(Vector3D.lerp(v1, v2, 0.25), -0.25, -3.75, 2);
+        checkVector(Vector3D.lerp(v1, v2, 0.5), -1.5, -2.5, 2);
+        checkVector(Vector3D.lerp(v1, v2, 0.75), -2.75, -1.25, 2);
+        checkVector(Vector3D.lerp(v1, v2, 1), -4, 0, 2);
+        checkVector(Vector3D.lerp(v1, v2, 1.25), -5.25, 1.25, 2);
+
+        checkVector(Vector3D.lerp(v1, v3, 0), 1, -5, 2);
+        checkVector(Vector3D.lerp(v1, v3, 0.25), 3.25, -4.75, 1.5);
+        checkVector(Vector3D.lerp(v1, v3, 0.5), 5.5, -4.5, 1);
+        checkVector(Vector3D.lerp(v1, v3, 0.75), 7.75, -4.25, 0.5);
+        checkVector(Vector3D.lerp(v1, v3, 1), 10, -4, 0);
+    }
+
+    @Test
     public void testHashCode() {
         // arrange
         double delta = 10 * Precision.EPSILON;
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
index 69c3aa3..b3582ea 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Point2DTest.java
@@ -94,6 +94,58 @@ public class Point2DTest {
     }
 
     @Test
+    public void testLerp() {
+        // arrange
+        Point2D p1 = Point2D.of(1, -5);
+        Point2D p2 = Point2D.of(-4, 0);
+        Point2D p3 = Point2D.of(10, -4);
+
+        // act/assert
+        checkPoint(p1.lerp(p1, 0), 1, -5);
+        checkPoint(p1.lerp(p1, 1), 1, -5);
+
+        checkPoint(p1.lerp(p2, -0.25), 2.25, -6.25);
+        checkPoint(p1.lerp(p2, 0), 1, -5);
+        checkPoint(p1.lerp(p2, 0.25), -0.25, -3.75);
+        checkPoint(p1.lerp(p2, 0.5), -1.5, -2.5);
+        checkPoint(p1.lerp(p2, 0.75), -2.75, -1.25);
+        checkPoint(p1.lerp(p2, 1), -4, 0);
+        checkPoint(p1.lerp(p2, 1.25), -5.25, 1.25);
+
+        checkPoint(p1.lerp(p3, 0), 1, -5);
+        checkPoint(p1.lerp(p3, 0.25), 3.25, -4.75);
+        checkPoint(p1.lerp(p3, 0.5), 5.5, -4.5);
+        checkPoint(p1.lerp(p3, 0.75), 7.75, -4.25);
+        checkPoint(p1.lerp(p3, 1), 10, -4);
+    }
+
+    @Test
+    public void testLerp_static() {
+        // arrange
+        Point2D p1 = Point2D.of(1, -5);
+        Point2D p2 = Point2D.of(-4, 0);
+        Point2D p3 = Point2D.of(10, -4);
+
+        // act/assert
+        checkPoint(Point2D.lerp(p1, p1, 0), 1, -5);
+        checkPoint(Point2D.lerp(p1, p1, 1), 1, -5);
+
+        checkPoint(Point2D.lerp(p1, p2, -0.25), 2.25, -6.25);
+        checkPoint(Point2D.lerp(p1, p2, 0), 1, -5);
+        checkPoint(Point2D.lerp(p1, p2, 0.25), -0.25, -3.75);
+        checkPoint(Point2D.lerp(p1, p2, 0.5), -1.5, -2.5);
+        checkPoint(Point2D.lerp(p1, p2, 0.75), -2.75, -1.25);
+        checkPoint(Point2D.lerp(p1, p2, 1), -4, 0);
+        checkPoint(Point2D.lerp(p1, p2, 1.25), -5.25, 1.25);
+
+        checkPoint(Point2D.lerp(p1, p3, 0), 1, -5);
+        checkPoint(Point2D.lerp(p1, p3, 0.25), 3.25, -4.75);
+        checkPoint(Point2D.lerp(p1, p3, 0.5), 5.5, -4.5);
+        checkPoint(Point2D.lerp(p1, p3, 0.75), 7.75, -4.25);
+        checkPoint(Point2D.lerp(p1, p3, 1), 10, -4);
+    }
+
+    @Test
     public void testAdd() {
         // arrange
         Point2D p1 = Point2D.of(1, 1);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
index 3da0318..2af7341 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
@@ -591,6 +591,58 @@ public class Vector2DTest {
     }
 
     @Test
+    public void testLerp() {
+        // arrange
+        Vector2D v1 = Vector2D.of(1, -5);
+        Vector2D v2 = Vector2D.of(-4, 0);
+        Vector2D v3 = Vector2D.of(10, -4);
+
+        // act/assert
+        checkVector(v1.lerp(v1, 0), 1, -5);
+        checkVector(v1.lerp(v1, 1), 1, -5);
+
+        checkVector(v1.lerp(v2, -0.25), 2.25, -6.25);
+        checkVector(v1.lerp(v2, 0), 1, -5);
+        checkVector(v1.lerp(v2, 0.25), -0.25, -3.75);
+        checkVector(v1.lerp(v2, 0.5), -1.5, -2.5);
+        checkVector(v1.lerp(v2, 0.75), -2.75, -1.25);
+        checkVector(v1.lerp(v2, 1), -4, 0);
+        checkVector(v1.lerp(v2, 1.25), -5.25, 1.25);
+
+        checkVector(v1.lerp(v3, 0), 1, -5);
+        checkVector(v1.lerp(v3, 0.25), 3.25, -4.75);
+        checkVector(v1.lerp(v3, 0.5), 5.5, -4.5);
+        checkVector(v1.lerp(v3, 0.75), 7.75, -4.25);
+        checkVector(v1.lerp(v3, 1), 10, -4);
+    }
+
+    @Test
+    public void testLerp_static() {
+        // arrange
+        Vector2D v1 = Vector2D.of(1, -5);
+        Vector2D v2 = Vector2D.of(-4, 0);
+        Vector2D v3 = Vector2D.of(10, -4);
+
+        // act/assert
+        checkVector(Vector2D.lerp(v1, v1, 0), 1, -5);
+        checkVector(Vector2D.lerp(v1, v1, 1), 1, -5);
+
+        checkVector(Vector2D.lerp(v1, v2, -0.25), 2.25, -6.25);
+        checkVector(Vector2D.lerp(v1, v2, 0), 1, -5);
+        checkVector(Vector2D.lerp(v1, v2, 0.25), -0.25, -3.75);
+        checkVector(Vector2D.lerp(v1, v2, 0.5), -1.5, -2.5);
+        checkVector(Vector2D.lerp(v1, v2, 0.75), -2.75, -1.25);
+        checkVector(Vector2D.lerp(v1, v2, 1), -4, 0);
+        checkVector(Vector2D.lerp(v1, v2, 1.25), -5.25, 1.25);
+
+        checkVector(Vector2D.lerp(v1, v3, 0), 1, -5);
+        checkVector(Vector2D.lerp(v1, v3, 0.25), 3.25, -4.75);
+        checkVector(Vector2D.lerp(v1, v3, 0.5), 5.5, -4.5);
+        checkVector(Vector2D.lerp(v1, v3, 0.75), 7.75, -4.25);
+        checkVector(Vector2D.lerp(v1, v3, 1), 10, -4);
+    }
+
+    @Test
     public void testHashCode() {
         // arrange
         Vector2D u = Vector2D.of(1, 1);