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 2f44549329dd91bc08438766cc426ba42741a9a6 Author: Matt Juntunen <[email protected]> AuthorDate: Sun Sep 2 22:36:54 2018 -0400 GEOMETRY-9: adding static project and reject methods --- .../geometry/euclidean/threed/Vector3D.java | 86 +++++++++++++-------- .../commons/geometry/euclidean/twod/Vector2D.java | 84 +++++++++++++-------- .../geometry/euclidean/threed/Vector3DTest.java | 88 ++++++++++++++++++++++ .../geometry/euclidean/twod/Vector2DTest.java | 54 +++++++++++++ 4 files changed, 249 insertions(+), 63 deletions(-) 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 62856a3..a84f3d7 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 @@ -337,38 +337,6 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point return getComponent(base, true); } - /** Returns a component of the current instance relative to the given base - * vector. If {@code reject} is true, the vector rejection is returned; otherwise, - * the projection is returned. - * @param base The base vector - * @param reject If true, the rejection of this instance from {@code base} is - * returned. If false, the projection of this instance onto {@code base} - * is returned. - * @return The projection or rejection of this instance relative to {@code base}, - * depending on the value of {@code reject}. - * @throws IllegalStateException if {@code base} has a zero norm - */ - private Vector3D getComponent(Vector3D base, boolean reject) throws IllegalStateException { - final double aDotB = dotProduct(base); - - final double baseMagSq = base.getNormSq(); - if (baseMagSq == 0.0) { - throw new IllegalStateException("Invalid base vector: norm is zero"); - } - - final double scale = aDotB / baseMagSq; - - final double projX = scale * base.getX(); - final double projY = scale * base.getY(); - final double projZ = scale * base.getZ(); - - if (reject) { - return new Vector3D(getX() - projX, getY() - projY, getZ() - projZ); - } - - return new Vector3D(projX, projY, projZ); - } - /** * Get a hashCode for the vector. * <p>All NaN values have the same hash code.</p> @@ -432,6 +400,38 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point return n; } + /** Returns a component of the current instance relative to the given base + * vector. If {@code reject} is true, the vector rejection is returned; otherwise, + * the projection is returned. + * @param base The base vector + * @param reject If true, the rejection of this instance from {@code base} is + * returned. If false, the projection of this instance onto {@code base} + * is returned. + * @return The projection or rejection of this instance relative to {@code base}, + * depending on the value of {@code reject}. + * @throws IllegalStateException if {@code base} has a zero norm + */ + private Vector3D getComponent(Vector3D base, boolean reject) throws IllegalStateException { + final double aDotB = dotProduct(base); + + final double baseMagSq = base.getNormSq(); + if (baseMagSq == 0.0) { + throw new IllegalStateException("Invalid base vector: norm is zero"); + } + + final double scale = aDotB / baseMagSq; + + final double projX = scale * base.getX(); + final double projY = scale * base.getY(); + final double projZ = scale * base.getZ(); + + if (reject) { + return new Vector3D(getX() - projX, getY() - projY, getZ() - projZ); + } + + return new Vector3D(projX, projY, projZ); + } + /** Computes the dot product between to vectors. This method simply * calls {@code v1.dotProduct(v2)}. * @param v1 first vector @@ -454,6 +454,28 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point return v1.angle(v2); } + /** Projects the given vector onto {@code base}. This method simply + * calls {@code v.project(base)}. + * @param v vector to project + * @param base the base vector to project onto + * @return the projected vector + * @see #project(Vector3D) + */ + public static Vector3D project(Vector3D v, Vector3D base) { + return v.project(base); + } + + /** Returns the vector rejection of {@code v} from {@code base}. This + * method simply calls {@code v.reject(base)}. + * @param v vector to reject + * @param base the base vector to reject from + * @return the vector rejection + * @see #reject(Vector3D) + */ + public static Vector3D reject(Vector3D v, Vector3D base) { + return v.reject(base); + } + /** Computes the cross product between two vectors. This method simply * calls {@code v1.crossProduct(v2)}. * @param v1 first vector 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 004b6c3..2f39b06 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 @@ -228,37 +228,6 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point return getComponent(base, true); } - /** Returns a component of the current instance relative to the given base - * vector. If {@code reject} is true, the vector rejection is returned; otherwise, - * the projection is returned. - * @param base The base vector - * @param reject If true, the rejection of this instance from {@code base} is - * returned. If false, the projection of this instance onto {@code base} - * is returned. - * @return The projection or rejection of this instance relative to {@code base}, - * depending on the value of {@code reject}. - * @throws IllegalStateException if {@code base} has a zero norm - */ - private Vector2D getComponent(Vector2D base, boolean reject) throws IllegalStateException { - final double aDotB = dotProduct(base); - - final double baseMagSq = base.getNormSq(); - if (baseMagSq == 0.0) { - throw new IllegalStateException("Invalid base vector: norm is zero"); - } - - final double scale = aDotB / baseMagSq; - - final double projX = scale * base.getX(); - final double projY = scale * base.getY(); - - if (reject) { - return new Vector2D(getX() - projX, getY() - projY); - } - - return new Vector2D(projX, projY); - } - /** {@inheritDoc} * <p>This method computes the angular separation between the two * vectors using the dot product for well separated vectors and the @@ -377,6 +346,37 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point return n; } + /** Returns a component of the current instance relative to the given base + * vector. If {@code reject} is true, the vector rejection is returned; otherwise, + * the projection is returned. + * @param base The base vector + * @param reject If true, the rejection of this instance from {@code base} is + * returned. If false, the projection of this instance onto {@code base} + * is returned. + * @return The projection or rejection of this instance relative to {@code base}, + * depending on the value of {@code reject}. + * @throws IllegalStateException if {@code base} has a zero norm + */ + private Vector2D getComponent(Vector2D base, boolean reject) throws IllegalStateException { + final double aDotB = dotProduct(base); + + final double baseMagSq = base.getNormSq(); + if (baseMagSq == 0.0) { + throw new IllegalStateException("Invalid base vector: norm is zero"); + } + + final double scale = aDotB / baseMagSq; + + final double projX = scale * base.getX(); + final double projY = scale * base.getY(); + + if (reject) { + return new Vector2D(getX() - projX, getY() - projY); + } + + return new Vector2D(projX, projY); + } + /** Computes the dot product between to vectors. This method simply * calls {@code v1.dotProduct(v2)}. * @param v1 first vector @@ -388,6 +388,28 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point return v1.dotProduct(v2); } + /** Projects the given vector onto {@code base}. This method simply + * calls {@code v.project(base)}. + * @param v vector to project + * @param base the base vector to project onto + * @return the projected vector + * @see #project(Vector2D) + */ + public static Vector2D project(Vector2D v, Vector2D base) { + return v.project(base); + } + + /** Returns the vector rejection of {@code v} from {@code base}. This + * method simply calls {@code v.reject(base)}. + * @param v vector to reject + * @param base the base vector to reject from + * @return the vector rejection + * @see #reject(Vector2D) + */ + public static Vector2D reject(Vector2D v, Vector2D base) { + return v.reject(base); + } + /** Computes the angle in radians between two vectors. This method * simply calls {@code v1.angle(v2)}. * @param v1 first vector 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 834b472..2abc8f5 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 @@ -623,6 +623,8 @@ public class Vector3DTest { Vector3D v2 = Vector3D.of(-5.0, -6.0, -7.0); // act/assert + checkVector(Vector3D.ZERO.project(Vector3D.PLUS_X), 0.0, 0.0, 0.0); + checkVector(v1.project(Vector3D.PLUS_X), 2.0, 0.0, 0.0); checkVector(v1.project(Vector3D.MINUS_X), 2.0, 0.0, 0.0); checkVector(v1.project(Vector3D.PLUS_Y), 0.0, 3.0, 0.0); @@ -644,6 +646,48 @@ public class Vector3DTest { checkVector(v2.project(Vector3D.of(-1.0, -1.0, -1.0)), -6.0, -6.0, -6.0); } + @Test(expected = IllegalStateException.class) + public void testProject_baseHasZeroNorm() { + // act/assert + Vector3D.of(1.0, 1.0, 1.0).project(Vector3D.ZERO); + } + + @Test + public void testProject_static() { + // arrange + Vector3D v1 = Vector3D.of(2.0, 3.0, 4.0); + Vector3D v2 = Vector3D.of(-5.0, -6.0, -7.0); + + // act/assert + checkVector(Vector3D.project(Vector3D.ZERO, Vector3D.PLUS_X), 0.0, 0.0, 0.0); + + checkVector(Vector3D.project(v1, Vector3D.PLUS_X), 2.0, 0.0, 0.0); + checkVector(Vector3D.project(v1, Vector3D.MINUS_X), 2.0, 0.0, 0.0); + checkVector(Vector3D.project(v1, Vector3D.PLUS_Y), 0.0, 3.0, 0.0); + checkVector(Vector3D.project(v1, Vector3D.MINUS_Y), 0.0, 3.0, 0.0); + checkVector(Vector3D.project(v1, Vector3D.PLUS_Z), 0.0, 0.0, 4.0); + checkVector(Vector3D.project(v1, Vector3D.MINUS_Z), 0.0, 0.0, 4.0); + + checkVector(Vector3D.project(v2, Vector3D.PLUS_X), -5.0, 0.0, 0.0); + checkVector(Vector3D.project(v2, Vector3D.MINUS_X), -5.0, 0.0, 0.0); + checkVector(Vector3D.project(v2, Vector3D.PLUS_Y), 0.0, -6.0, 0.0); + checkVector(Vector3D.project(v2, Vector3D.MINUS_Y), 0.0, -6.0, 0.0); + checkVector(Vector3D.project(v2, Vector3D.PLUS_Z), 0.0, 0.0, -7.0); + checkVector(Vector3D.project(v2, Vector3D.MINUS_Z), 0.0, 0.0, -7.0); + + checkVector(Vector3D.project(v1, Vector3D.of(1.0, 1.0, 1.0)), 3.0, 3.0, 3.0); + checkVector(Vector3D.project(v1, Vector3D.of(-1.0, -1.0, -1.0)), 3.0, 3.0, 3.0); + + checkVector(Vector3D.project(v2, Vector3D.of(1.0, 1.0, 1.0)), -6.0, -6.0, -6.0); + checkVector(Vector3D.project(v2, Vector3D.of(-1.0, -1.0, -1.0)), -6.0, -6.0, -6.0); + } + + @Test(expected = IllegalStateException.class) + public void testProject_baseHasZeroNorm_static() { + // act/assert + Vector3D.project(Vector3D.of(1.0, 1.0, 1.0), Vector3D.ZERO); + } + @Test public void testReject() { // arrange @@ -651,6 +695,8 @@ public class Vector3DTest { Vector3D v2 = Vector3D.of(-5.0, -6.0, -7.0); // act/assert + checkVector(Vector3D.ZERO.reject(Vector3D.PLUS_X), 0.0, 0.0, 0.0); + checkVector(v1.reject(Vector3D.PLUS_X), 0.0, 3.0, 4.0); checkVector(v1.reject(Vector3D.MINUS_X), 0.0, 3.0, 4.0); checkVector(v1.reject(Vector3D.PLUS_Y), 2.0, 0.0, 4.0); @@ -672,6 +718,48 @@ public class Vector3DTest { checkVector(v2.reject(Vector3D.of(-1.0, -1.0, -1.0)), 1.0, 0.0, -1.0); } + @Test(expected = IllegalStateException.class) + public void testReject_baseHasZeroNorm() { + // act/assert + Vector3D.of(1.0, 1.0, 1.0).reject(Vector3D.ZERO); + } + + @Test + public void testReject_static() { + // arrange + Vector3D v1 = Vector3D.of(2.0, 3.0, 4.0); + Vector3D v2 = Vector3D.of(-5.0, -6.0, -7.0); + + // act/assert + checkVector(Vector3D.reject(Vector3D.ZERO, Vector3D.PLUS_X), 0.0, 0.0, 0.0); + + checkVector(Vector3D.reject(v1, Vector3D.PLUS_X), 0.0, 3.0, 4.0); + checkVector(Vector3D.reject(v1, Vector3D.MINUS_X), 0.0, 3.0, 4.0); + checkVector(Vector3D.reject(v1, Vector3D.PLUS_Y), 2.0, 0.0, 4.0); + checkVector(Vector3D.reject(v1, Vector3D.MINUS_Y), 2.0, 0.0, 4.0); + checkVector(Vector3D.reject(v1, Vector3D.PLUS_Z), 2.0, 3.0, 0.0); + checkVector(Vector3D.reject(v1, Vector3D.MINUS_Z), 2.0, 3.0, 0.0); + + checkVector(Vector3D.reject(v2, Vector3D.PLUS_X), 0.0, -6.0, -7.0); + checkVector(Vector3D.reject(v2, Vector3D.MINUS_X), 0.0, -6.0, -7.0); + checkVector(Vector3D.reject(v2, Vector3D.PLUS_Y), -5.0, 0.0, -7.0); + checkVector(Vector3D.reject(v2, Vector3D.MINUS_Y), -5.0, 0.0, -7.0); + checkVector(Vector3D.reject(v2, Vector3D.PLUS_Z), -5.0, -6.0, 0.0); + checkVector(Vector3D.reject(v2, Vector3D.MINUS_Z), -5.0, -6.0, 0.0); + + checkVector(Vector3D.reject(v1, Vector3D.of(1.0, 1.0, 1.0)), -1.0, 0.0, 1.0); + checkVector(Vector3D.reject(v1, Vector3D.of(-1.0, -1.0, -1.0)), -1.0, 0.0, 1.0); + + checkVector(Vector3D.reject(v2, Vector3D.of(1.0, 1.0, 1.0)), 1.0, 0.0, -1.0); + checkVector(Vector3D.reject(v2, Vector3D.of(-1.0, -1.0, -1.0)), 1.0, 0.0, -1.0); + } + + @Test(expected = IllegalStateException.class) + public void testReject_baseHasZeroNorm_static() { + // act/assert + Vector3D.reject(Vector3D.of(1.0, 1.0, 1.0), Vector3D.ZERO); + } + @Test public void testProjectAndReject_areComplementary() { // arrange 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 7c31092..3da0318 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 @@ -464,6 +464,33 @@ public class Vector2DTest { } @Test + public void testProject_static() { + // arrange + Vector2D v1 = Vector2D.of(3.0, 4.0); + Vector2D v2 = Vector2D.of(1.0, 4.0); + + // act/assert + checkVector(Vector2D.project(Vector2D.ZERO, v1), 0.0, 0.0); + + checkVector(Vector2D.project(v1, v1), 3.0, 4.0); + checkVector(Vector2D.project(v1, v1.negate()), 3.0, 4.0); + + checkVector(Vector2D.project(v1, Vector2D.PLUS_X), 3.0, 0.0); + checkVector(Vector2D.project(v1, Vector2D.MINUS_X), 3.0, 0.0); + + checkVector(Vector2D.project(v1, Vector2D.PLUS_Y), 0.0, 4.0); + checkVector(Vector2D.project(v1, Vector2D.MINUS_Y), 0.0, 4.0); + + checkVector(Vector2D.project(v2, v1), (19.0 / 25.0) * 3.0, (19.0 / 25.0) * 4.0); + } + + @Test(expected = IllegalStateException.class) + public void testProject_baseHasZeroNorm_static() { + // act/assert + Vector2D.project(Vector2D.of(1.0, 1.0), Vector2D.ZERO); + } + + @Test public void testReject() { // arrange Vector2D v1 = Vector2D.of(3.0, 4.0); @@ -491,6 +518,33 @@ public class Vector2DTest { } @Test + public void testReject_static() { + // arrange + Vector2D v1 = Vector2D.of(3.0, 4.0); + Vector2D v2 = Vector2D.of(1.0, 4.0); + + // act/assert + checkVector(Vector2D.ZERO.reject(v1), 0.0, 0.0); + + checkVector(Vector2D.reject(v1, v1), 0.0, 0.0); + checkVector(Vector2D.reject(v1, v1.negate()), 0.0, 0.0); + + checkVector(Vector2D.reject(v1, Vector2D.PLUS_X), 0.0, 4.0); + checkVector(Vector2D.reject(v1, Vector2D.MINUS_X), 0.0, 4.0); + + checkVector(Vector2D.reject(v1, Vector2D.PLUS_Y), 3.0, 0.0); + checkVector(Vector2D.reject(v1, Vector2D.MINUS_Y), 3.0, 0.0); + + checkVector(Vector2D.reject(v2, v1), (-32.0 / 25.0), (6.0 / 25.0) * 4.0); + } + + @Test(expected = IllegalStateException.class) + public void testReject_baseHasZeroNorm_static() { + // act/assert + Vector2D.reject(Vector2D.of(1.0, 1.0), Vector2D.ZERO); + } + + @Test public void testProjectAndReject_areComplementary() { // arrange double eps = 1e-12;
