Skip to content

Commit

Permalink
GEOMETRY-150: implemented a way to check if 2 vectors are codirectional
Browse files Browse the repository at this point in the history
  • Loading branch information
orionlibs committed Jul 14, 2023
1 parent c3e08ed commit d65fb01
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,13 @@ public interface Vector<V extends Vector<V>> extends Spatial {
* @throws IllegalArgumentException if either vector has a zero, NaN, or infinite norm
*/
double angle(V v);

/** Checks if the two vectors point at the same direction.
* This means that each vector can be obtained from the other by multiplying by a positive scalar.
* Any vector is considered as codirectional to a zero vector.
* @param v other vector
* @return {@code true} if both vectors point at the same direction.
* @throws IllegalArgumentException if either vector has a zero, NaN, or infinite norm
*/
boolean isCodirectionalTo(V v);
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,18 @@ public double angle(final Vector1D v) {
return (sig1 == sig2) ? 0.0 : Math.PI;
}


/**
* {@inheritDoc}
*/
@Override public boolean isCodirectionalTo(Vector1D v) {
// validate the norm values
getCheckedNorm();
v.getCheckedNorm();
return v.x / x > 0.0;
}


/** Convenience method to apply a function to this vector. This
* can be used to transform the vector inline with other methods.
* @param fn the function to apply
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.commons.geometry.euclidean.EuclideanVectorSum;
import org.apache.commons.geometry.euclidean.MultiDimensionalEuclideanVector;
import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
import org.apache.commons.numbers.core.Precision;

/** This class represents vectors and points in three-dimensional Euclidean space.
Expand Down Expand Up @@ -320,6 +321,28 @@ public double angle(final Vector3D v) {
return Math.acos(dot / normProduct);
}


/**
* {@inheritDoc}
*/
@Override public boolean isCodirectionalTo(Vector3D v) {
// validate the norm values
double magnitudeOfThis = getCheckedNorm();
double magnitudeOfV = v.getCheckedNorm();
// Handle zero vectors: consider any vector as codirectional to a zero vector
if ((x == 0 && y == 0 && z == 0) || (v.x == 0 && v.y == 0 && v.z == 0)) {
return true;
}

// If the ratios are equal, the vectors are codirectional.
double ratioX = x / v.x;
double ratioY = y / v.y;
double ratioZ = z / v.z;
// use a tolerance due to floating point inaccuracies
return Math.abs(ratioX - ratioY) < 0.000001 && Math.abs(ratioY - ratioZ) < 0.000001;
}


/** {@inheritDoc} */
@Override
public Vector3D project(final Vector3D base) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,26 @@ public double angle(final Vector2D v) {
return Math.acos(dot / normProduct);
}


/**
* {@inheritDoc}
*/
@Override public boolean isCodirectionalTo(Vector2D v) {
// validate the norm values
double magnitudeOfThis = getCheckedNorm();
double magnitudeOfV = v.getCheckedNorm();
// Handle zero vectors: consider any vector as codirectional to a zero vector
if ((x == 0 && y == 0) || (v.x == 0 && v.y == 0)) {
return true;
}

// If the ratios are equal, the vectors are codirectional.
double ratio = x / v.x;
// use a tolerance due to floating point inaccuracies
return Math.abs(ratio - (y / v.y)) < 0.000001;
}


/** {@inheritDoc} */
@Override
public Vector2D project(final Vector2D base) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,21 @@ void testUnitFactoryOptimization() {
Assertions.assertSame(v, v.normalize());
}

@Test
void testIsCodirectionalTo() {
final Vector1D v1 = Vector1D.of(1);
final Vector1D v2 = Vector1D.of(4);
Assertions.assertTrue(v1.isCodirectionalTo(v2));
Assertions.assertTrue(v2.isCodirectionalTo(v1));

final Vector1D v3 = Vector1D.of(-1);
final Vector1D v4 = Vector1D.of(-4);
Assertions.assertTrue(v3.isCodirectionalTo(v4));
Assertions.assertTrue(v3.isCodirectionalTo(v4));

Assertions.assertFalse(v1.isCodirectionalTo(v3));
}

private void checkVector(final Vector1D v, final double x) {
Assertions.assertEquals(x, v.getX(), TEST_TOLERANCE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.geometry.euclidean.oned.Vector1D;
import org.apache.commons.numbers.angle.Angle;
import org.apache.commons.numbers.core.Precision;
import org.apache.commons.rng.UniformRandomProvider;
Expand Down Expand Up @@ -1368,6 +1369,27 @@ void testUnitFactoryOptimization() {
Assertions.assertSame(v, v.normalize());
}

@Test
void testIsCodirectionalTo() {
final Vector3D v1 = Vector3D.of(2, 2, 2);
final Vector3D v2 = Vector3D.of(1, 1, 1);
final Vector3D v3 = Vector3D.of(-2, -2, -2);
final Vector3D v4 = Vector3D.of(2, -2, 2);

// Test codirectional vectors (same direction)
Assertions.assertTrue(v1.isCodirectionalTo(v2));
Assertions.assertTrue(v2.isCodirectionalTo(v1));

// Test codirectional vectors (opposite direction)
Assertions.assertTrue(v1.isCodirectionalTo(v3));
Assertions.assertTrue(v3.isCodirectionalTo(v1));

// Test non-codirectional vectors
Assertions.assertFalse(v1.isCodirectionalTo(v4));
Assertions.assertFalse(v4.isCodirectionalTo(v1));

}

private void checkVector(final Vector3D v, final double x, final double y, final double z) {
Assertions.assertEquals(x, v.getX(), EPS);
Assertions.assertEquals(y, v.getY(), EPS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.geometry.euclidean.oned.Vector1D;
import org.apache.commons.numbers.angle.Angle;
import org.apache.commons.numbers.core.Precision;
import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -1169,6 +1170,26 @@ void testUnitFactoryOptimization() {
Assertions.assertSame(v, v.normalize());
}

@Test
void testIsCodirectionalTo() {
final Vector2D v1 = Vector2D.of(2, 2);
final Vector2D v2 = Vector2D.of(1, 1);
final Vector2D v3 = Vector2D.of(-2, -2);
final Vector2D v4 = Vector2D.of(2, -2);

// Test codirectional vectors (same direction)
Assertions.assertTrue(v1.isCodirectionalTo(v2));
Assertions.assertTrue(v2.isCodirectionalTo(v1));

// Test codirectional vectors (opposite direction)
Assertions.assertTrue(v1.isCodirectionalTo(v3));
Assertions.assertTrue(v3.isCodirectionalTo(v1));

// Test non-codirectional vectors
Assertions.assertFalse(v1.isCodirectionalTo(v4));
Assertions.assertFalse(v4.isCodirectionalTo(v1));
}

private void checkVector(final Vector2D v, final double x, final double y) {
checkVector(v, x, y, EPS);
}
Expand Down

0 comments on commit d65fb01

Please sign in to comment.