Skip to content
Permalink
Browse files
GEOMETRY-118: adding component-specific transform methods to AffineTr…
…ansformMatrixXD classes
  • Loading branch information
darkma773r committed Apr 21, 2021
1 parent 2afc52f commit 5e24ed416613b10916255066b8d44e5214e0bae1
Showing 9 changed files with 742 additions and 54 deletions.
@@ -18,7 +18,6 @@

import java.util.function.UnaryOperator;

import org.apache.commons.geometry.core.internal.DoubleFunction1N;
import org.apache.commons.geometry.euclidean.AbstractAffineTransformMatrix;
import org.apache.commons.geometry.euclidean.internal.Matrices;
import org.apache.commons.geometry.euclidean.internal.Vectors;
@@ -83,27 +82,43 @@ public double[] toArray() {
/** {@inheritDoc} */
@Override
public Vector1D apply(final Vector1D vec) {
final double x = vec.getX();

final double resultX = (m00 * x) + m01;
return Vector1D.of(applyX(vec.getX()));
}

return Vector1D.of(resultX);
/** Apply this transform to the given point coordinate and return the transformed
* x value. The return value is equal to <code>(x * m<sub>00</sub>) + m<sub>01</sub></code>.
* @param x x coordinate value
* @return transformed x coordinate value
* @see #apply(Vector1D)
*/
public double applyX(final double x) {
return applyVectorX(x) + m01;
}

/** {@inheritDoc}
* @see #applyDirection(Vector1D)
*/
@Override
public Vector1D applyVector(final Vector1D vec) {
return applyVector(vec, Vector1D::of);
return Vector1D.of(applyVectorX(vec.getX()));
}

/** Apply this transform to the given vector coordinate, ignoring translations, and
* return the transformed x value. The return value is equal to <code>x * m<sub>00</sub></code>.
* @param x x coordinate value
* @return transformed x coordinate value
* @see #applyVector(Vector1D)
*/
public double applyVectorX(final double x) {
return x * m00;
}

/** {@inheritDoc}
* @see #applyVector(Vector1D)
*/
@Override
public Vector1D.Unit applyDirection(final Vector1D vec) {
return applyVector(vec, Vector1D.Unit::from);
return Vector1D.Unit.from(applyVectorX(vec.getX()));
}

/** {@inheritDoc} */
@@ -292,19 +307,6 @@ public String toString() {
return sb.toString();
}

/** Multiplies the given vector by the scaling component of this transform.
* The computed coordinate is passed to the given factory function.
* @param <T> factory output type
* @param vec the vector to transform
* @param factory the factory instance that will be passed the transformed coordinate
* @return the factory return value
*/
private <T> T applyVector(final Vector1D vec, final DoubleFunction1N<T> factory) {
final double resultX = m00 * vec.getX();

return factory.apply(resultX);
}

/** Get a new transform with the given matrix elements. The array must contain 2 elements.
* The first element in the array represents the scale factor for the transform and the
* second represents the translation.
@@ -160,11 +160,49 @@ public Vector3D apply(final Vector3D pt) {
final double y = pt.getY();
final double z = pt.getZ();

final double resultX = LinearCombination.value(m00, x, m01, y, m02, z) + m03;
final double resultY = LinearCombination.value(m10, x, m11, y, m12, z) + m13;
final double resultZ = LinearCombination.value(m20, x, m21, y, m22, z) + m23;

return Vector3D.of(resultX, resultY, resultZ);
return Vector3D.of(
applyX(x, y, z),
applyY(x, y, z),
applyZ(x, y, z));
}

/** Apply this transform to the given point coordinates and return the transformed
* x value. The return value is equal to
* <code>(x * m<sub>00</sub>) + (y * m<sub>01</sub>) + (z * m<sub>02</sub>) + m<sub>03</sub></code>.
* @param x x coordinate value
* @param y y coordinate value
* @param z z coordinate value
* @return transformed x coordinate value
* @see #apply(Vector3D)
*/
public double applyX(final double x, final double y, final double z) {
return applyVectorX(x, y, z) + m03;
}

/** Apply this transform to the given point coordinates and return the transformed
* y value. The return value is equal to
* <code>(x * m<sub>10</sub>) + (y * m<sub>11</sub>) + (z * m<sub>12</sub>) + m<sub>13</sub></code>.
* @param x x coordinate value
* @param y y coordinate value
* @param z z coordinate value
* @return transformed y coordinate value
* @see #apply(Vector3D)
*/
public double applyY(final double x, final double y, final double z) {
return applyVectorY(x, y, z) + m13;
}

/** Apply this transform to the given point coordinates and return the transformed
* z value. The return value is equal to
* <code>(x * m<sub>20</sub>) + (y * m<sub>21</sub>) + (z * m<sub>22</sub>) + m<sub>23</sub></code>.
* @param x x coordinate value
* @param y y coordinate value
* @param z z coordinate value
* @return transformed z coordinate value
* @see #apply(Vector3D)
*/
public double applyZ(final double x, final double y, final double z) {
return applyVectorZ(x, y, z) + m23;
}

/** {@inheritDoc}
@@ -187,6 +225,45 @@ public Vector3D applyVector(final Vector3D vec) {
return applyVector(vec, Vector3D::of);
}

/** Apply this transform to the given vector coordinates, ignoring translations, and
* return the transformed x value. The return value is equal to
* <code>(x * m<sub>00</sub>) + (y * m<sub>01</sub>) + (z * m<sub>02</sub>)</code>.
* @param x x coordinate value
* @param y y coordinate value
* @param z z coordinate value
* @return transformed x coordinate value
* @see #applyVector(Vector3D)
*/
public double applyVectorX(final double x, final double y, final double z) {
return LinearCombination.value(m00, x, m01, y, m02, z);
}

/** Apply this transform to the given vector coordinates, ignoring translations, and
* return the transformed y value. The return value is equal to
* <code>(x * m<sub>10</sub>) + (y * m<sub>11</sub>) + (z * m<sub>12</sub>)</code>.
* @param x x coordinate value
* @param y y coordinate value
* @param z z coordinate value
* @return transformed y coordinate value
* @see #applyVector(Vector3D)
*/
public double applyVectorY(final double x, final double y, final double z) {
return LinearCombination.value(m10, x, m11, y, m12, z);
}

/** Apply this transform to the given vector coordinates, ignoring translations, and
* return the transformed z value. The return value is equal to
* <code>(x * m<sub>20</sub>) + (y * m<sub>21</sub>) + (z * m<sub>22</sub>)</code>.
* @param x x coordinate value
* @param y y coordinate value
* @param z z coordinate value
* @return transformed z coordinate value
* @see #applyVector(Vector3D)
*/
public double applyVectorZ(final double x, final double y, final double z) {
return LinearCombination.value(m20, x, m21, y, m22, z);
}

/** {@inheritDoc}
* @see #applyVector(Vector3D)
*/
@@ -509,11 +586,10 @@ private <T> T applyVector(final Vector3D vec, final DoubleFunction3N<T> factory)
final double y = vec.getY();
final double z = vec.getZ();

final double resultX = LinearCombination.value(m00, x, m01, y, m02, z);
final double resultY = LinearCombination.value(m10, x, m11, y, m12, z);
final double resultZ = LinearCombination.value(m20, x, m21, y, m22, z);

return factory.apply(resultX, resultY, resultZ);
return factory.apply(
applyVectorX(x, y, z),
applyVectorY(x, y, z),
applyVectorZ(x, y, z));
}

/** Get a new transform with the given matrix elements. The array must contain 12 elements.
@@ -128,10 +128,33 @@ public Vector2D apply(final Vector2D pt) {
final double x = pt.getX();
final double y = pt.getY();

final double resultX = LinearCombination.value(m00, x, m01, y) + m02;
final double resultY = LinearCombination.value(m10, x, m11, y) + m12;
return Vector2D.of(
applyX(x, y),
applyY(x, y));
}

return Vector2D.of(resultX, resultY);
/** Apply this transform to the given point coordinates and return the transformed
* x value. The return value is equal to
* <code>(x * m<sub>00</sub>) + (y * m<sub>01</sub>) + m<sub>02</sub></code>.
* @param x x coordinate value
* @param y y coordinate value
* @return transformed x coordinate value
* @see #apply(Vector2D)
*/
public double applyX(final double x, final double y) {
return applyVectorX(x, y) + m02;
}

/** Apply this transform to the given point coordinates and return the transformed
* y value. The return value is equal to
* <code>(x * m<sub>10</sub>) + (y * m<sub>11</sub>) + m<sub>12</sub></code>.
* @param x x coordinate value
* @param y y coordinate value
* @return transformed y coordinate value
* @see #apply(Vector2D)
*/
public double applyY(final double x, final double y) {
return applyVectorY(x, y) + m12;
}

/** {@inheritDoc}
@@ -153,6 +176,30 @@ public Vector2D applyVector(final Vector2D vec) {
return applyVector(vec, Vector2D::of);
}

/** Apply this transform to the given vector coordinates, ignoring translations, and
* return the transformed x value. The return value is equal to
* <code>(x * m<sub>00</sub>) + (y * m<sub>01</sub>)</code>.
* @param x x coordinate value
* @param y y coordinate value
* @return transformed x coordinate value
* @see #applyVector(Vector2D)
*/
public double applyVectorX(final double x, final double y) {
return LinearCombination.value(m00, x, m01, y);
}

/** Apply this transform to the given vector coordinates, ignoring translations, and
* return the transformed y value. The return value is equal to
* <code>(x * m<sub>10</sub>) + (y * m<sub>11</sub>)</code>.
* @param x x coordinate value
* @param y y coordinate value
* @return transformed y coordinate value
* @see #applyVector(Vector2D)
*/
public double applyVectorY(final double x, final double y) {
return LinearCombination.value(m10, x, m11, y);
}

/** {@inheritDoc}
* @see #applyVector(Vector2D)
*/
@@ -454,10 +501,9 @@ private <T> T applyVector(final Vector2D vec, final DoubleFunction2N<T> factory)
final double x = vec.getX();
final double y = vec.getY();

final double resultX = LinearCombination.value(m00, x, m01, y);
final double resultY = LinearCombination.value(m10, x, m11, y);

return factory.apply(resultX, resultY);
return factory.apply(
applyVectorX(x, y),
applyVectorY(x, y));
}

/** Get a new transform with the given matrix elements. The array must contain 6 elements.
@@ -281,6 +281,24 @@ public void testApply_scaleThenTranslate() {
});
}

@Test
public void testApplyX() {
// arrange
final Vector1D translation = Vector1D.of(-2.0);
final Vector1D scale = Vector1D.of(5.0);

final AffineTransformMatrix1D transform = AffineTransformMatrix1D.identity()
.translate(translation)
.scale(scale);

// act/assert
runWithCoordinates(x -> {
final double expected = (x + translation.getX()) * scale.getX();

Assertions.assertEquals(expected, transform.applyX(x), EPS);
});
}

@Test
public void testApplyVector_identity() {
// arrange
@@ -351,6 +369,28 @@ public void testApplyVector_representsDisplacement() {
});
}

@Test
public void testApplyVectorX() {
// arrange
final Vector1D p1 = Vector1D.of(PlaneAngleRadians.PI);

final Vector1D translation = Vector1D.of(-2.0);
final Vector1D scale = Vector1D.of(5.0);

final AffineTransformMatrix1D transform = AffineTransformMatrix1D.identity()
.translate(translation)
.scale(scale);

// act/assert
runWithCoordinates(x -> {
final Vector1D p2 = p1.add(Vector1D.of(x));

final double expected = transform.apply(p1).vectorTo(transform.apply(p2)).getX();

Assertions.assertEquals(expected, transform.applyVectorX(x), EPS);
});
}

@Test
public void testApplyDirection_identity() {
// arrange
@@ -522,6 +522,28 @@ public void testApply_rotate_aroundCenter() {
});
}

@Test
public void testApplyXYZ() {
// arrange
final double scaleFactor = 2;
final Vector3D center = Vector3D.of(3, -4, 5);
final QuaternionRotation rotation = QuaternionRotation.fromAxisAngle(Vector3D.of(0.5, 1, 1), 2 * Math.PI / 3);

final AffineTransformMatrix3D transform = AffineTransformMatrix3D.identity()
.scale(scaleFactor)
.rotate(center, rotation);

// act/assert
runWithCoordinates((x, y, z) -> {
final Vector3D vec = Vector3D.of(x, y, z);
final Vector3D expectedVec = rotation.apply(vec.multiply(scaleFactor).subtract(center)).add(center);

Assertions.assertEquals(expectedVec.getX(), transform.applyX(x, y, z), EPS);
Assertions.assertEquals(expectedVec.getY(), transform.applyY(x, y, z), EPS);
Assertions.assertEquals(expectedVec.getZ(), transform.applyZ(x, y, z), EPS);
});
}

@Test
public void testApplyVector_identity() {
// arrange
@@ -590,6 +612,28 @@ public void testApplyVector_representsDisplacement() {
});
}

@Test
public void testApplyVectorXYZ() {
// arrange
final Vector3D p1 = Vector3D.of(1, 2, 3);

final AffineTransformMatrix3D transform = AffineTransformMatrix3D.identity()
.scale(1.5)
.translate(4, 6, 5)
.rotate(QuaternionRotation.fromAxisAngle(Vector3D.of(0.5, 1, 1), PlaneAngleRadians.PI_OVER_TWO));

// act/assert
runWithCoordinates((x, y, z) -> {
final Vector3D p2 = p1.add(Vector3D.of(x, y, z));

final Vector3D expected = transform.apply(p1).vectorTo(transform.apply(p2));

Assertions.assertEquals(expected.getX(), transform.applyVectorX(x, y, z), EPS);
Assertions.assertEquals(expected.getY(), transform.applyVectorY(x, y, z), EPS);
Assertions.assertEquals(expected.getZ(), transform.applyVectorZ(x, y, z), EPS);
});
}

@Test
public void testApplyDirection_identity() {
// arrange

0 comments on commit 5e24ed4

Please sign in to comment.