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 2020/01/21 09:32:07 UTC
[commons-geometry] branch master updated: GEOMETRY-80: simplifying
Transform class hierarchy; improving documentation
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
The following commit(s) were added to refs/heads/master by this push:
new 56df5b5 GEOMETRY-80: simplifying Transform class hierarchy; improving documentation
new f8127fc Merge branch 'GEOMETRY-80__Matt'
56df5b5 is described below
commit 56df5b50dfd7eba1ba2377f9a7a92242a082be98
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Mon Jan 20 10:44:14 2020 -0500
GEOMETRY-80: simplifying Transform class hierarchy; improving documentation
---
.../org/apache/commons/geometry/core/Region.java | 5 +-
.../apache/commons/geometry/core/Transform.java | 53 +++---
.../core/partition/test/TestTransform2D.java | 6 +
.../euclidean/AbstractAffineTransformMatrix.java | 38 ----
.../geometry/euclidean/EuclideanTransform.java | 6 +-
.../geometry/euclidean/internal/Matrices.java | 39 +++++
.../euclidean/oned/AffineTransformMatrix1D.java | 54 ++++--
.../euclidean/oned/FunctionTransform1D.java | 95 ----------
.../geometry/euclidean/oned/Transform1D.java | 50 ------
.../commons/geometry/euclidean/oned/Vector1D.java | 2 +-
.../euclidean/threed/AffineTransformMatrix3D.java | 59 +++++--
.../euclidean/threed/FunctionTransform3D.java | 107 ------------
.../euclidean/threed/SphericalCoordinates.java | 2 +-
.../geometry/euclidean/threed/Transform3D.java | 50 ------
.../threed/rotation/QuaternionRotation.java | 6 +-
.../euclidean/threed/rotation/Rotation3D.java | 15 +-
.../euclidean/twod/AffineTransformMatrix2D.java | 55 ++++--
.../euclidean/twod/FunctionTransform2D.java | 103 -----------
.../commons/geometry/euclidean/twod/Segment.java | 4 +-
.../geometry/euclidean/twod/Transform2D.java | 50 ------
.../euclidean/DocumentationExamplesTest.java | 9 +-
.../geometry/euclidean/internal/MatricesTest.java | 53 ++++++
.../oned/AffineTransformMatrix1DTest.java | 47 +++--
.../euclidean/oned/FunctionTransform1DTest.java | 177 -------------------
.../geometry/euclidean/oned/IntervalTest.java | 4 +-
.../geometry/euclidean/oned/OrientedPointTest.java | 2 +-
.../euclidean/oned/RegionBSPTree1DTest.java | 8 +-
.../threed/AffineTransformMatrix3DTest.java | 58 +++++--
.../geometry/euclidean/threed/FacetTest.java | 2 +-
.../euclidean/threed/FunctionTransform3DTest.java | 193 ---------------------
.../geometry/euclidean/threed/Line3DTest.java | 6 +-
.../geometry/euclidean/threed/PlaneTest.java | 6 +-
.../geometry/euclidean/threed/SubLine3DTest.java | 2 +-
.../twod/AbstractSegmentConnectorTest.java | 2 +-
.../twod/AffineTransformMatrix2DTest.java | 54 ++++--
.../geometry/euclidean/twod/ConvexAreaTest.java | 2 +-
.../euclidean/twod/FunctionTransform2DTest.java | 186 --------------------
.../twod/InteriorAngleSegmentConnectorTest.java | 2 +-
.../geometry/euclidean/twod/PolylineTest.java | 6 +-
.../euclidean/twod/RegionBSPTree2DTest.java | 4 +-
.../geometry/euclidean/twod/SegmentTest.java | 41 ++---
.../geometry/spherical/oned/Transform1S.java | 6 +-
.../geometry/spherical/twod/Transform2S.java | 6 +-
src/site/xdoc/index.xml | 4 +-
src/site/xdoc/userguide/index.xml | 69 ++++----
45 files changed, 460 insertions(+), 1288 deletions(-)
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java
index 2c15111..16da017 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java
@@ -49,8 +49,9 @@ public interface Region<P extends Point<P>> {
*/
double getBoundarySize();
- /** Get the barycenter of the region or null if no single, unique barycenter exists.
- * A barycenter will not exist for empty or infinite regions.
+ /** Get the barycenter of the region or null if no barycenter exists or
+ * one exists but is not unique. A barycenter will not exist for empty or
+ * infinite regions.
* @return the barycenter of the region or null if none exists
*/
P getBarycenter();
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Transform.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Transform.java
index 0dc1d12..a34a69a 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Transform.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Transform.java
@@ -18,35 +18,48 @@ package org.apache.commons.geometry.core;
import java.util.function.UnaryOperator;
-/** This interface represents an <em>inversible affine transform</em> in a space.
- * Common examples of this type of transform in Euclidean space include
- * scalings, translations, and rotations.
+/** Interface representing geometric transforms in a space, i.e. mappings from points to points.
+ * Implementations <em>must</em> fulfill a set of requirements, listed below, that preserve the
+ * consistency of partitionings on the space. Transforms that do not meet these requirements, while
+ * potentially valid mathematically, cannot be expected to produce correct results with algorithms
+ * that use this interface.
*
- * <h2>Implementation Note</h2>
- * <p>Implementations are responsible for ensuring that they meet the geometric
- * requirements outlined above. These are:
* <ol>
- * <li>The transform must be <a href="https://en.wikipedia.org/wiki/Affine_transformation">affine</a>.
- * In basic terms, this means that the transform must retain the "straightness" and "parallelness" of
- * lines and planes (or whatever is an equivalent concept for the space). For example, a translation or
- * rotation in Euclidean 3D space meets this requirement because all lines that are parallel before the
- * transform remain parallel afterwards. However, a projective transform that causes previously parallel
- * lines to meet at a single point does not.
- * </li>
- * <li>The transform must be <em>inversible</em>. An inverse transform must exist that will return
- * the original point if given the transformed point. In other words, for a transform {@code t}, there
- * must exist an inverse {@code inv} such that {@code inv.apply(t.apply(pt))} returns a point equal to
- * the input point {@code pt}.
+ * <li>Transforms must represent functions that are <em>one-to-one</em> and <em>onto</em> (i.e.
+ * <a href="https://en.wikipedia.org/wiki/Bijection">bijections</a>). This means that every point
+ * in the space must be mapped to exactly one other point in the space. This also implies that the
+ * function is invertible.</li>
+ * <li>Transforms must preserve <a href="https://en.wikipedia.org/wiki/Collinearity">collinearity</a>.
+ * This means that if a set of points lie on a common hyperplane before the transform, then they must
+ * also lie on a common hyperplane after the transform. For example, if the Euclidean 2D points {@code a},
+ * {@code b}, and {@code c} lie on line {@code L}, then the transformed points {@code a'}, {@code b'}, and
+ * {@code c'} must lie on line {@code L'}, where {@code L'} is the transformed form of the line.</li>
+ * <li>Transforms must preserve the concept of
+ * <a href="https://en.wikipedia.org/wiki/Parallel_(geometry)">parallelism</a> defined for the space.
+ * This means that hyperplanes that are parallel before the transformation must remain parallel afterwards,
+ * and hyperplanes that intersect must also intersect afterwards. For example, a transform that causes parallel
+ * lines to converge to a single point in Euclidean space (such as the projective transforms used to create
+ * perspective viewpoints in 3D graphics) would not meet this requirement. However, a transform that turns
+ * a square into a rhombus with no right angles would fulfill the requirement, since the two pairs of parallel
+ * lines forming the square remain parallel after the transformation.
* </li>
* </ol>
- * Implementations that do not meet these requirements cannot be expected to produce correct results in
- * algorithms that use this interface.
+ *
+ * <p>Transforms that meet the above requirements in Euclidean space (and other affine spaces) are known as
+ * <a href="https://en.wikipedia.org/wiki/Affine_transformation">affine transforms</a>. Common affine transforms
+ * include translation, scaling, rotation, reflection, and any compositions thereof.
+ * </p>
*
* @param <P> Point implementation type
- * @see <a href="https://en.wikipedia.org/wiki/Affine_transformation">Affine Space</a>
+ * @see <a href="https://en.wikipedia.org/wiki/Geometric_transformation">Geometric Transformation</a>
*/
public interface Transform<P extends Point<P>> extends UnaryOperator<P> {
+ /** Get an instance representing the inverse transform.
+ * @return an instance representing the inverse transform
+ */
+ Transform<P> inverse();
+
/** Return true if the transform preserves the orientation of the space.
* For example, in Euclidean 2D space, this will be true for translations,
* rotations, and scalings but will be false for reflections.
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestTransform2D.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestTransform2D.java
index 0321da2..738e90b 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestTransform2D.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestTransform2D.java
@@ -57,4 +57,10 @@ public class TestTransform2D implements Transform<TestPoint2D> {
public boolean preservesOrientation() {
return preservesHandedness;
}
+
+ /** {@inheritDoc} */
+ @Override
+ public Transform<TestPoint2D> inverse() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/AbstractAffineTransformMatrix.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/AbstractAffineTransformMatrix.java
index 476d11a..9674517 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/AbstractAffineTransformMatrix.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/AbstractAffineTransformMatrix.java
@@ -16,8 +16,6 @@
*/
package org.apache.commons.geometry.euclidean;
-import org.apache.commons.geometry.euclidean.internal.Vectors;
-
/** Base class for affine transform matrices in Euclidean space.
*
* @param <V> Vector/point implementation type defining the space.
@@ -49,40 +47,4 @@ public abstract class AbstractAffineTransformMatrix<V extends EuclideanVector<V>
public boolean preservesOrientation() {
return determinant() > 0.0;
}
-
- /** Get the determinant of the instance for use in calculating the matrix
- * inverse. An {@link IllegalStateException} is thrown if the determinant is
- * NaN, infinite, or zero.
- * @return the determinant of the matrix
- * @throws IllegalStateException if the matrix determinant value is NaN, infinite,
- * or zero
- */
- protected double getDeterminantForInverse() {
- final double det = determinant();
- if (!Vectors.isRealNonZero(det)) {
- throw nonInvertibleTransform("matrix determinant is " + det);
- }
- return det;
- }
-
- /** Check that the given matrix element is valid for use in calculation of
- * a matrix inverse, throwing an {@link IllegalStateException} if not.
- * @param element matrix entry to check
- * @throws IllegalStateException if the element is not valid for use
- * in calculating a matrix inverse, ie if it is NaN or infinite.
- */
- protected void validateElementForInverse(final double element) {
- if (!Double.isFinite(element)) {
- throw nonInvertibleTransform("invalid matrix element: " + element);
- }
- }
-
- /** Create an exception indicating that the instance is not able to be inverted.
- * @param msg message containing the specific reason that the matrix cannot
- * be inverted
- * @return IllegalStateException containing the given error message
- */
- protected IllegalStateException nonInvertibleTransform(final String msg) {
- return new IllegalStateException("Transform is not invertible; " + msg);
- }
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanTransform.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanTransform.java
index 0a76f37..b9ab17c 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanTransform.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanTransform.java
@@ -18,10 +18,12 @@ package org.apache.commons.geometry.euclidean;
import org.apache.commons.geometry.core.Transform;
-/** Extension transform interface for Euclidean space. This interface provides an additional method
- * for transforming vectors as opposed to points.
+/** Interface representing affine transforms in Euclidean space. An affine transform is one that preserves
+ * points, straight lines, planes, and sets of parallel lines. Common affine transforms include translation,
+ * rotation, scaling, reflection and any compositions thereof.
*
* @param <V> Vector implementation type
+ * @see <a href="https://en.wikipedia.org/wiki/Affine_transformation">Affine Transformation</a>
*/
public interface EuclideanTransform<V extends EuclideanVector<V>> extends Transform<V> {
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Matrices.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Matrices.java
index 51ff088..6e09e7e 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Matrices.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Matrices.java
@@ -59,4 +59,43 @@ public final class Matrices {
return ((a00 * a11 * a22) + (a01 * a12 * a20) + (a02 * a10 * a21)) -
((a00 * a12 * a21) + (a01 * a10 * a22) + (a02 * a11 * a20));
}
+
+ /** Check that the given determinant is valid for use in calculating a matrix
+ * inverse. An {@link IllegalStateException} is thrown if the determinant is
+ * NaN, infinite, or zero.
+ * @param det the determinant to check
+ * @return the checked determinant
+ * @throws IllegalStateException if the matrix determinant value is NaN, infinite,
+ * or zero
+ */
+ public static double checkDeterminantForInverse(double det) {
+ if (!Vectors.isRealNonZero(det)) {
+ throw nonInvertibleTransform("matrix determinant is " + det);
+ }
+ return det;
+ }
+
+ /** Check that the given matrix element is valid for use in calculation of
+ * a matrix inverse, throwing an {@link IllegalStateException} if not.
+ * @param element matrix entry to check
+ * @return the checked element
+ * @throws IllegalStateException if the element is not valid for use
+ * in calculating a matrix inverse, ie if it is NaN or infinite.
+ */
+ public static double checkElementForInverse(final double element) {
+ if (!Double.isFinite(element)) {
+ throw nonInvertibleTransform("invalid matrix element: " + element);
+ }
+
+ return element;
+ }
+
+ /** Create an exception indicating that a matrix is not able to be inverted.
+ * @param msg message containing the specific reason that the matrix cannot
+ * be inverted
+ * @return IllegalStateException containing the given error message
+ */
+ private static IllegalStateException nonInvertibleTransform(final String msg) {
+ return new IllegalStateException("Matrix is not invertible; " + msg);
+ }
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1D.java
index 13d9255..66cfd36 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1D.java
@@ -16,9 +16,12 @@
*/
package org.apache.commons.geometry.euclidean.oned;
+import java.util.function.UnaryOperator;
+
import org.apache.commons.geometry.core.internal.DoubleFunction1N;
import org.apache.commons.geometry.euclidean.AbstractAffineTransformMatrix;
-import org.apache.commons.numbers.core.Precision;
+import org.apache.commons.geometry.euclidean.internal.Matrices;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
/** Class using a matrix to represent affine transformations in 1 dimensional Euclidean space.
*
@@ -28,8 +31,7 @@ import org.apache.commons.numbers.core.Precision;
* use arrays containing 2 elements, instead of 4.
* </p>
*/
-public final class AffineTransformMatrix1D extends AbstractAffineTransformMatrix<Vector1D>
- implements Transform1D {
+public final class AffineTransformMatrix1D extends AbstractAffineTransformMatrix<Vector1D> {
/** The number of internal matrix elements. */
private static final int NUM_ELEMENTS = 2;
@@ -110,15 +112,6 @@ public final class AffineTransformMatrix1D extends AbstractAffineTransformMatrix
return m00;
}
- /** {@inheritDoc}
- *
- * <p>This simply returns the current instance.</p>
- */
- @Override
- public AffineTransformMatrix1D toMatrix() {
- return this;
- }
-
/** Get a new transform containing the result of applying a translation logically after
* the transformation represented by the current instance. This is achieved by
* creating a new translation transform and pre-multiplying it with the current
@@ -205,15 +198,16 @@ public final class AffineTransformMatrix1D extends AbstractAffineTransformMatrix
return multiply(m, this);
}
- /** Get a new transform representing the inverse of the current instance.
- * @return inverse transform
+ /** {@inheritDoc}
+ *
* @throws IllegalStateException if the transform matrix cannot be inverted
*/
+ @Override
public AffineTransformMatrix1D inverse() {
- final double det = getDeterminantForInverse();
+ final double det = Matrices.checkDeterminantForInverse(determinant());
- validateElementForInverse(m01);
+ Matrices.checkElementForInverse(m01);
final double invDet = 1.0 / det;
@@ -251,8 +245,8 @@ public final class AffineTransformMatrix1D extends AbstractAffineTransformMatrix
}
final AffineTransformMatrix1D other = (AffineTransformMatrix1D) obj;
- return Precision.equals(this.m00, other.m00) &&
- Precision.equals(this.m01, other.m01);
+ return Double.compare(this.m00, other.m00) == 0 &&
+ Double.compare(this.m01, other.m01) == 0;
}
/** {@inheritDoc} */
@@ -300,6 +294,30 @@ public final class AffineTransformMatrix1D extends AbstractAffineTransformMatrix
return new AffineTransformMatrix1D(arr[0], arr[1]);
}
+ /** Construct a new transform representing the given function. The function is sampled at
+ * the points zero and one and a matrix is created to perform the transformation.
+ * @param fn function to create a transform matrix from
+ * @return a transform matrix representing the given function
+ * @throws IllegalArgumentException if the given function does not represent a valid
+ * affine transform
+ */
+ public static AffineTransformMatrix1D from(final UnaryOperator<Vector1D> fn) {
+ final Vector1D tOne = fn.apply(Vector1D.Unit.PLUS);
+ final Vector1D tZero = fn.apply(Vector1D.ZERO);
+
+ final double scale = tOne.subtract(tZero).getX();
+ final double translate = tZero.getX();
+
+ final AffineTransformMatrix1D mat = AffineTransformMatrix1D.of(scale, translate);
+
+ final double det = mat.determinant();
+ if (!Vectors.isRealNonZero(det)) {
+ throw new IllegalArgumentException("Transform function is invalid: matrix determinant is " + det);
+ }
+
+ return mat;
+ }
+
/** Get the transform representing the identity matrix. This transform does not
* modify point or vector values when applied.
* @return transform representing the identity matrix
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/FunctionTransform1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/FunctionTransform1D.java
deleted file mode 100644
index e63cc43..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/FunctionTransform1D.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.oned;
-
-import java.util.function.UnaryOperator;
-
-/** Class that wraps a {@link UnaryOperator} with the {@link Transform1D} interface.
- */
-final class FunctionTransform1D implements Transform1D {
-
- /** Static instance representing the identity transform. */
- private static final FunctionTransform1D IDENTITY =
- new FunctionTransform1D(UnaryOperator.identity(), true, Vector1D.ZERO);
-
- /** The underlying function for the transform. */
- private final UnaryOperator<Vector1D> fn;
-
- /** True if the transform preserves spatial orientation. */
- private final boolean preservesOrientation;
-
- /** The translation component of the transform. */
- private final Vector1D translation;
-
- /** Construct a new instance from its component parts. No validation of the input is performed.
- * @param fn the underlying function for the transform
- * @param preservesOrientation true if the transform preserves spatial orientation
- * @param translation the translation component of the transform
- */
- private FunctionTransform1D(final UnaryOperator<Vector1D> fn, final boolean preservesOrientation,
- final Vector1D translation) {
- this.fn = fn;
- this.preservesOrientation = preservesOrientation;
- this.translation = translation;
- }
-
- /** {@inheritDoc} */
- @Override
- public Vector1D apply(final Vector1D pt) {
- return fn.apply(pt);
- }
-
- /** {@inheritDoc} */
- @Override
- public Vector1D applyVector(final Vector1D vec) {
- return apply(vec).subtract(translation);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean preservesOrientation() {
- return preservesOrientation;
- }
-
- /** {@inheritDoc} */
- @Override
- public AffineTransformMatrix1D toMatrix() {
- final Vector1D tOne = applyVector(Vector1D.Unit.PLUS);
-
- return AffineTransformMatrix1D.of(tOne.getX(), translation.getX());
- }
-
- /** Return an instance representing the identity transform.
- * @return an instance representing the identity transform
- */
- static FunctionTransform1D identity() {
- return IDENTITY;
- }
-
- /** Construct a new transform instance from the given function.
- * @param fn the function to use for the transform
- * @return a new transform instance using the given function
- */
- static FunctionTransform1D from(final UnaryOperator<Vector1D> fn) {
- final Vector1D tOne = fn.apply(Vector1D.Unit.PLUS);
- final Vector1D tZero = fn.apply(Vector1D.ZERO);
-
- final boolean preservesOrientation = tOne.getX() > 0.0;
-
- return new FunctionTransform1D(fn, preservesOrientation, tZero);
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Transform1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Transform1D.java
deleted file mode 100644
index a85b4ca..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Transform1D.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.oned;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.EuclideanTransform;
-
-/** Extension of the {@link EuclideanTransform} interface for 1D space.
- */
-public interface Transform1D extends EuclideanTransform<Vector1D> {
-
- /** Return an affine transform matrix representing the same transform
- * as this instance.
- * @return an affine tranform matrix representing the same transform
- * as this instance
- */
- AffineTransformMatrix1D toMatrix();
-
- /** Return a transform representing the identity transform.
- * @return a transform representing the identity transform
- */
- static Transform1D identity() {
- return FunctionTransform1D.identity();
- }
-
- /** Construct a transform instance from the given function. Callers are responsible for
- * ensuring that the given function meets all the requirements for
- * {@link org.apache.commons.geometry.core.Transform Transform} instances.
- * @param fn the function to use for the transform
- * @return a new transform instance using the given function
- */
- static Transform1D from(final UnaryOperator<Vector1D> fn) {
- return FunctionTransform1D.from(fn);
- }
-}
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 ba05189..0206f7d 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
@@ -19,11 +19,11 @@ package org.apache.commons.geometry.euclidean.oned;
import java.util.Comparator;
import java.util.function.UnaryOperator;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.euclidean.EuclideanVector;
import org.apache.commons.geometry.euclidean.internal.Vectors;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.numbers.arrays.LinearCombination;
/** This class represents vectors and points in one-dimensional Euclidean space.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java
index bbcef53..a0fcf21 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java
@@ -16,9 +16,12 @@
*/
package org.apache.commons.geometry.euclidean.threed;
+import java.util.function.UnaryOperator;
+
import org.apache.commons.geometry.core.internal.DoubleFunction3N;
import org.apache.commons.geometry.euclidean.AbstractAffineTransformMatrix;
import org.apache.commons.geometry.euclidean.internal.Matrices;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
import org.apache.commons.numbers.arrays.LinearCombination;
import org.apache.commons.numbers.core.Precision;
@@ -31,8 +34,7 @@ import org.apache.commons.numbers.core.Precision;
* use arrays containing 12 elements, instead of 16.
* </p>
*/
-public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix<Vector3D>
- implements Transform3D {
+public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix<Vector3D> {
/** The number of internal matrix elements. */
private static final int NUM_ELEMENTS = 12;
@@ -204,15 +206,6 @@ public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix
);
}
- /** {@inheritDoc}
- *
- * <p>This simply returns the current instance.</p>
- */
- @Override
- public AffineTransformMatrix3D toMatrix() {
- return this;
- }
-
/** Apply a translation to the current instance, returning the result as a new transform.
* @param translation vector containing the translation values for each axis
* @return a new transform containing the result of applying a translation to
@@ -323,21 +316,22 @@ public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix
return multiply(m, this);
}
- /** Get a new transform representing the inverse of the current instance.
- * @return inverse transform
- * @throws IllegalStateException if the transform matrix cannot be inverted
- */
+ /** {@inheritDoc}
+ *
+ * @throws IllegalStateException if the transform matrix cannot be inverted
+ */
+ @Override
public AffineTransformMatrix3D inverse() {
// Our full matrix is 4x4 but we can significantly reduce the amount of computations
// needed here since we know that our last row is [0 0 0 1].
- final double det = getDeterminantForInverse();
+ final double det = Matrices.checkDeterminantForInverse(determinant());
// validate the remaining matrix elements that were not part of the determinant
- validateElementForInverse(m03);
- validateElementForInverse(m13);
- validateElementForInverse(m23);
+ Matrices.checkElementForInverse(m03);
+ Matrices.checkElementForInverse(m13);
+ Matrices.checkElementForInverse(m23);
// compute the necessary elements of the cofactor matrix
// (we need all but the last column)
@@ -505,6 +499,33 @@ public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix
);
}
+ /** Construct a new transform representing the given function. The function is sampled at
+ * the origin and along each axis and a matrix is created to perform the transformation.
+ * @param fn function to create a transform matrix from
+ * @return a transform matrix representing the given function
+ * @throws IllegalArgumentException if the given function does not represent a valid
+ * affine transform
+ */
+ public static AffineTransformMatrix3D from(final UnaryOperator<Vector3D> fn) {
+ final Vector3D tPlusX = fn.apply(Vector3D.Unit.PLUS_X);
+ final Vector3D tPlusY = fn.apply(Vector3D.Unit.PLUS_Y);
+ final Vector3D tPlusZ = fn.apply(Vector3D.Unit.PLUS_Z);
+ final Vector3D tZero = fn.apply(Vector3D.ZERO);
+
+ final Vector3D u = tPlusX.subtract(tZero);
+ final Vector3D v = tPlusY.subtract(tZero);
+ final Vector3D w = tPlusZ.subtract(tZero);
+
+ final AffineTransformMatrix3D mat = AffineTransformMatrix3D.fromColumnVectors(u, v, w, tZero);
+
+ final double det = mat.determinant();
+ if (!Vectors.isRealNonZero(det)) {
+ throw new IllegalArgumentException("Transform function is invalid: matrix determinant is " + det);
+ }
+
+ return mat;
+ }
+
/** Get a new transform create from the given column vectors. The returned transform
* does not include any translation component.
* @param u first column vector; this corresponds to the first basis vector
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/FunctionTransform3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/FunctionTransform3D.java
deleted file mode 100644
index 2cc52cd..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/FunctionTransform3D.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.threed;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.internal.Matrices;
-
-/** Class that wraps a {@link UnaryOperator} with the {@link Transform3D} interface.
- */
-final class FunctionTransform3D implements Transform3D {
-
- /** Static instance representing the identity transform. */
- private static final FunctionTransform3D IDENTITY =
- new FunctionTransform3D(UnaryOperator.identity(), true, Vector3D.ZERO);
-
- /** The underlying function for the transform. */
- private final UnaryOperator<Vector3D> fn;
-
- /** True if the transform preserves spatial orientation. */
- private final boolean preservesOrientation;
-
- /** The translation component of the transform. */
- private final Vector3D translation;
-
- /** Construct a new instance from its component parts. No validation of the input is performed.
- * @param fn the underlying function for the transform
- * @param preservesOrientation true if the transform preserves spatial orientation
- * @param translation the translation component of the transform
- */
- private FunctionTransform3D(final UnaryOperator<Vector3D> fn, final boolean preservesOrientation,
- final Vector3D translation) {
- this.fn = fn;
- this.preservesOrientation = preservesOrientation;
- this.translation = translation;
- }
-
- /** {@inheritDoc} */
- @Override
- public Vector3D apply(final Vector3D pt) {
- return fn.apply(pt);
- }
-
- /** {@inheritDoc} */
- @Override
- public Vector3D applyVector(final Vector3D vec) {
- return apply(vec).subtract(translation);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean preservesOrientation() {
- return preservesOrientation;
- }
-
- /** {@inheritDoc} */
- @Override
- public AffineTransformMatrix3D toMatrix() {
- final Vector3D u = applyVector(Vector3D.Unit.PLUS_X);
- final Vector3D v = applyVector(Vector3D.Unit.PLUS_Y);
- final Vector3D w = applyVector(Vector3D.Unit.PLUS_Z);
-
- return AffineTransformMatrix3D.fromColumnVectors(u, v, w, translation);
- }
-
- /** Return an instance representing the identity transform.
- * @return an instance representing the identity transform
- */
- static FunctionTransform3D identity() {
- return IDENTITY;
- }
-
- /** Construct a new transform instance from the given function.
- * @param fn the function to use for the transform
- * @return a new transform instance using the given function
- */
- static FunctionTransform3D from(final UnaryOperator<Vector3D> fn) {
- final Vector3D tPlusX = fn.apply(Vector3D.Unit.PLUS_X);
- final Vector3D tPlusY = fn.apply(Vector3D.Unit.PLUS_Y);
- final Vector3D tPlusZ = fn.apply(Vector3D.Unit.PLUS_Z);
-
- final Vector3D tZero = fn.apply(Vector3D.ZERO);
-
- final double det = Matrices.determinant(
- tPlusX.getX(), tPlusY.getX(), tPlusZ.getX(),
- tPlusX.getY(), tPlusY.getY(), tPlusZ.getY(),
- tPlusX.getZ(), tPlusY.getZ(), tPlusZ.getZ()
- );
- final boolean preservesOrientation = det > 0;
-
- return new FunctionTransform3D(fn, preservesOrientation, tZero);
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates.java
index 39acef9..cac6182 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates.java
@@ -16,11 +16,11 @@
*/
package org.apache.commons.geometry.euclidean.threed;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.geometry.core.Spatial;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.geometry.euclidean.twod.PolarCoordinates;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
/** Class representing <a href="https://en.wikipedia.org/wiki/Spherical_coordinate_system">spherical coordinates</a>
* in 3 dimensional Euclidean space.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Transform3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Transform3D.java
deleted file mode 100644
index 20bbcdb..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Transform3D.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.threed;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.EuclideanTransform;
-
-/** Extension of the {@link EuclideanTransform} interface for 3D points.
- */
-public interface Transform3D extends EuclideanTransform<Vector3D> {
-
- /** Return an affine transform matrix representing the same transform
- * as this instance.
- * @return an affine tranform matrix representing the same transform
- * as this instance
- */
- AffineTransformMatrix3D toMatrix();
-
- /** Return a transform representing the identity transform.
- * @return a transform representing the identity transform
- */
- static Transform3D identity() {
- return FunctionTransform3D.identity();
- }
-
- /** Construct a transform instance from the given function. Callers are responsible for
- * ensuring that the given function meets all the requirements for
- * {@link org.apache.commons.geometry.core.Transform Transform} instances.
- * @param fn the function to use for the transform
- * @return a new transform instance using the given function
- */
- static Transform3D from(final UnaryOperator<Vector3D> fn) {
- return FunctionTransform3D.from(fn);
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java
index 460852e..dc351ed 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java
@@ -165,8 +165,10 @@ public final class QuaternionRotation implements Rotation3D {
return true;
}
- /** {@inheritDoc} */
- @Override
+ /** Return an {@link AffineTransformMatrix3D} representing the same rotation as this
+ * instance.
+ * @return a transform matrix representing the same rotation as this instance
+ */
public AffineTransformMatrix3D toMatrix() {
final double qw = quat.getW();
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/Rotation3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/Rotation3D.java
index 395f9f0..6b56212 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/Rotation3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/Rotation3D.java
@@ -16,13 +16,13 @@
*/
package org.apache.commons.geometry.euclidean.threed.rotation;
-import org.apache.commons.geometry.euclidean.threed.Transform3D;
+import org.apache.commons.geometry.euclidean.EuclideanTransform;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
/** Interface representing a generic rotation in 3-dimensional Euclidean
* space.
*/
-public interface Rotation3D extends Transform3D {
+public interface Rotation3D extends EuclideanTransform<Vector3D> {
/** Apply this rotation to the given argument. Since rotations do
* not affect vector magnitudes, this method can be applied to
@@ -33,6 +33,12 @@ public interface Rotation3D extends Transform3D {
@Override
Vector3D apply(Vector3D vec);
+ /** Get the inverse rotation.
+ * @return the inverse rotation.
+ */
+ @Override
+ Rotation3D inverse();
+
/** Get the axis of rotation as a normalized {@link Vector3D}.
*
* <p>All 3-dimensional rotations and sequences of rotations can be reduced
@@ -53,9 +59,4 @@ public interface Rotation3D extends Transform3D {
* @see #getAxis()
*/
double getAngle();
-
- /** Get the inverse rotation.
- * @return the inverse rotation.
- */
- Rotation3D inverse();
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
index df0ad11..a311fa2 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
@@ -16,9 +16,12 @@
*/
package org.apache.commons.geometry.euclidean.twod;
+import java.util.function.UnaryOperator;
+
import org.apache.commons.geometry.core.internal.DoubleFunction2N;
import org.apache.commons.geometry.euclidean.AbstractAffineTransformMatrix;
import org.apache.commons.geometry.euclidean.internal.Matrices;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.numbers.arrays.LinearCombination;
import org.apache.commons.numbers.core.Precision;
@@ -30,8 +33,7 @@ import org.apache.commons.numbers.core.Precision;
* use arrays containing 6 elements, instead of 9.
* </p>
*/
-public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix<Vector2D>
- implements Transform2D {
+public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix<Vector2D> {
/** The number of internal matrix elements. */
private static final int NUM_ELEMENTS = 6;
@@ -168,15 +170,6 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
);
}
- /** {@inheritDoc}
- *
- * <p>This simply returns the current instance.</p>
- */
- @Override
- public AffineTransformMatrix2D toMatrix() {
- return this;
- }
-
/** Apply a translation to the current instance, returning the result as a new transform.
* @param translation vector containing the translation values for each axis
* @return a new transform containing the result of applying a translation to
@@ -282,20 +275,21 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
return multiply(m, this);
}
- /** Get a new transform representing the inverse of the current instance.
- * @return inverse transform
- * @throws IllegalStateException if the transform matrix cannot be inverted
- */
+ /** {@inheritDoc}
+ *
+ * @throws IllegalStateException if the transform matrix cannot be inverted
+ */
+ @Override
public AffineTransformMatrix2D inverse() {
// Our full matrix is 3x3 but we can significantly reduce the amount of computations
// needed here since we know that our last row is [0 0 1].
- final double det = getDeterminantForInverse();
+ final double det = Matrices.checkDeterminantForInverse(determinant());
// validate the remaining matrix elements that were not part of the determinant
- validateElementForInverse(m02);
- validateElementForInverse(m12);
+ Matrices.checkElementForInverse(m02);
+ Matrices.checkElementForInverse(m12);
// compute the necessary elements of the cofactor matrix
// (we need all but the last column)
@@ -416,6 +410,31 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
);
}
+ /** Construct a new transform representing the given function. The function is sampled at
+ * the origin and along each axis and a matrix is created to perform the transformation.
+ * @param fn function to create a transform matrix from
+ * @return a transform matrix representing the given function
+ * @throws IllegalArgumentException if the given function does not represent a valid
+ * affine transform
+ */
+ public static AffineTransformMatrix2D from(final UnaryOperator<Vector2D> fn) {
+ final Vector2D tPlusX = fn.apply(Vector2D.Unit.PLUS_X);
+ final Vector2D tPlusY = fn.apply(Vector2D.Unit.PLUS_Y);
+ final Vector2D tZero = fn.apply(Vector2D.ZERO);
+
+ final Vector2D u = tPlusX.subtract(tZero);
+ final Vector2D v = tPlusY.subtract(tZero);
+
+ final AffineTransformMatrix2D mat = AffineTransformMatrix2D.fromColumnVectors(u, v, tZero);
+
+ final double det = mat.determinant();
+ if (!Vectors.isRealNonZero(det)) {
+ throw new IllegalArgumentException("Transform function is invalid: matrix determinant is " + det);
+ }
+
+ return mat;
+ }
+
/** Get a new transform create from the given column vectors. The returned transform
* does not include any translation component.
* @param u first column vector; this corresponds to the first basis vector
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/FunctionTransform2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/FunctionTransform2D.java
deleted file mode 100644
index 03ff639..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/FunctionTransform2D.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.twod;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.internal.Matrices;
-
-/** Class that wraps a {@link UnaryOperator} with the {@link Transform2D} interface.
- */
-final class FunctionTransform2D implements Transform2D {
-
- /** Static instance representing the identity transform. */
- private static final FunctionTransform2D IDENTITY =
- new FunctionTransform2D(UnaryOperator.identity(), true, Vector2D.ZERO);
-
- /** The underlying function for the transform. */
- private final UnaryOperator<Vector2D> fn;
-
- /** True if the transform preserves spatial orientation. */
- private final boolean preservesOrientation;
-
- /** The translation component of the transform. */
- private final Vector2D translation;
-
- /** Construct a new instance from its component parts. No validation of the input is performed.
- * @param fn the underlying function for the transform
- * @param preservesOrientation true if the transform preserves spatial orientation
- * @param translation the translation component of the transform
- */
- private FunctionTransform2D(final UnaryOperator<Vector2D> fn, final boolean preservesOrientation,
- final Vector2D translation) {
- this.fn = fn;
- this.preservesOrientation = preservesOrientation;
- this.translation = translation;
- }
-
- /** {@inheritDoc} */
- @Override
- public Vector2D apply(final Vector2D pt) {
- return fn.apply(pt);
- }
-
- /** {@inheritDoc} */
- @Override
- public Vector2D applyVector(final Vector2D vec) {
- return apply(vec).subtract(translation);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean preservesOrientation() {
- return preservesOrientation;
- }
-
- /** {@inheritDoc} */
- @Override
- public AffineTransformMatrix2D toMatrix() {
- final Vector2D u = applyVector(Vector2D.Unit.PLUS_X);
- final Vector2D v = applyVector(Vector2D.Unit.PLUS_Y);
-
- return AffineTransformMatrix2D.fromColumnVectors(u, v, translation);
- }
-
- /** Return an instance representing the identity transform.
- * @return an instance representing the identity transform
- */
- static FunctionTransform2D identity() {
- return IDENTITY;
- }
-
- /** Construct a new transform instance from the given function.
- * @param fn the function to use for the transform
- * @return a new transform instance using the given function
- */
- static FunctionTransform2D from(final UnaryOperator<Vector2D> fn) {
- final Vector2D tPlusX = fn.apply(Vector2D.Unit.PLUS_X);
- final Vector2D tPlusY = fn.apply(Vector2D.Unit.PLUS_Y);
- final Vector2D tZero = fn.apply(Vector2D.ZERO);
-
- final double det = Matrices.determinant(
- tPlusX.getX(), tPlusY.getX(),
- tPlusX.getY(), tPlusY.getY()
- );
- final boolean preservesOrientation = det > 0;
-
- return new FunctionTransform2D(fn, preservesOrientation, tZero);
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
index 756bdfe..2084714 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
@@ -24,8 +24,8 @@ import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.oned.AffineTransformMatrix1D;
import org.apache.commons.geometry.euclidean.oned.Interval;
-import org.apache.commons.geometry.euclidean.oned.Transform1D;
import org.apache.commons.geometry.euclidean.oned.Vector1D;
import org.apache.commons.geometry.euclidean.twod.Line.SubspaceTransform;
@@ -174,7 +174,7 @@ public final class Segment extends AbstractSubLine
/** {@inheritDoc} */
@Override
public Segment reverse() {
- final Interval reversedInterval = interval.transform(Transform1D.from(Vector1D::negate));
+ final Interval reversedInterval = interval.transform(AffineTransformMatrix1D.createScale(-1));
return fromInterval(getLine().reverse(), reversedInterval);
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Transform2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Transform2D.java
deleted file mode 100644
index b6c5da6..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Transform2D.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.twod;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.EuclideanTransform;
-
-/** Extension of the {@link EuclideanTransform} interface for 2D space.
- */
-public interface Transform2D extends EuclideanTransform<Vector2D> {
-
- /** Return an affine transform matrix representing the same transform
- * as this instance.
- * @return an affine tranform matrix representing the same transform
- * as this instance
- */
- AffineTransformMatrix2D toMatrix();
-
- /** Return a transform representing the identity transform.
- * @return a transform representing the identity transform
- */
- static Transform2D identity() {
- return FunctionTransform2D.identity();
- }
-
- /** Construct a transform instance from the given function. Callers are responsible for
- * ensuring that the given function meets all the requirements for
- * {@link org.apache.commons.geometry.core.Transform Transform} instances.
- * @param fn the function to use for the transform
- * @return a new transform instance using the given function
- */
- static Transform2D from(final UnaryOperator<Vector2D> fn) {
- return FunctionTransform2D.from(fn);
- }
-}
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/DocumentationExamplesTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/DocumentationExamplesTest.java
index 42f9c98..31eb242 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/DocumentationExamplesTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/DocumentationExamplesTest.java
@@ -33,7 +33,6 @@ import org.apache.commons.geometry.euclidean.threed.Line3D;
import org.apache.commons.geometry.euclidean.threed.LinecastPoint3D;
import org.apache.commons.geometry.euclidean.threed.Plane;
import org.apache.commons.geometry.euclidean.threed.RegionBSPTree3D;
-import org.apache.commons.geometry.euclidean.threed.Transform3D;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
import org.apache.commons.geometry.euclidean.threed.shapes.Parallelepiped;
@@ -43,7 +42,6 @@ import org.apache.commons.geometry.euclidean.twod.LinecastPoint2D;
import org.apache.commons.geometry.euclidean.twod.Polyline;
import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
import org.apache.commons.geometry.euclidean.twod.Segment;
-import org.apache.commons.geometry.euclidean.twod.Transform2D;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
import org.apache.commons.geometry.euclidean.twod.shapes.Parallelogram;
import org.apache.commons.numbers.angle.PlaneAngleRadians;
@@ -68,10 +66,8 @@ public class DocumentationExamplesTest {
Parallelepiped.axisAligned(Vector3D.of(-0.5, -0.5, -0.5), Vector3D.of(0.5, 0.5, 0.5), precision));
// create a rotated copy of the region
- Transform3D rotation = QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Z, 0.25 * Math.PI);
-
RegionBSPTree3D copy = region.copy();
- copy.transform(rotation);
+ copy.transform(QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Z, 0.25 * Math.PI));
// compute the intersection of the regions, storing the result back into the caller
// (the result could also have been placed into a third region)
@@ -290,8 +286,7 @@ public class DocumentationExamplesTest {
RegionBSPTree2D copy = tree.copy();
// translate the copy
- Vector2D translation = Vector2D.of(0.5, 0.5);
- copy.transform(Transform2D.from(v -> v.add(translation)));
+ copy.transform(AffineTransformMatrix2D.createTranslation(Vector2D.of(0.5, 0.5)));
// compute the union of the regions, storing the result back into the
// first tree
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java
index a60a1a3..6acb10a 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.commons.geometry.euclidean.internal;
+import org.apache.commons.geometry.core.GeometryTestUtils;
import org.junit.Assert;
import org.junit.Test;
@@ -80,4 +81,56 @@ public class MatricesTest {
-3, 4, 1
), EPS);
}
+
+ @Test
+ public void testCheckDeterminantForInverse() {
+ // act/assert
+ Assert.assertEquals(1.0, Matrices.checkDeterminantForInverse(1.0), EPS);
+ Assert.assertEquals(-1.0, Matrices.checkDeterminantForInverse(-1.0), EPS);
+ }
+
+ @Test
+ public void testCheckDeterminantForInverse_invalid() {
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> {
+ Matrices.checkDeterminantForInverse(0);
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is 0.0");
+
+ GeometryTestUtils.assertThrows(() -> {
+ Matrices.checkDeterminantForInverse(Double.NaN);
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is NaN");
+
+ GeometryTestUtils.assertThrows(() -> {
+ Matrices.checkDeterminantForInverse(Double.POSITIVE_INFINITY);
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is Infinity");
+
+ GeometryTestUtils.assertThrows(() -> {
+ Matrices.checkDeterminantForInverse(Double.NEGATIVE_INFINITY);
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is -Infinity");
+ }
+
+ @Test
+ public void testCheckElementForInverse() {
+ // act/assert
+ Assert.assertEquals(0.0, Matrices.checkElementForInverse(0.0), EPS);
+
+ Assert.assertEquals(1.0, Matrices.checkElementForInverse(1.0), EPS);
+ Assert.assertEquals(-1.0, Matrices.checkElementForInverse(-1.0), EPS);
+ }
+
+ @Test
+ public void testCheckElementForInverse_invalid() {
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> {
+ Matrices.checkElementForInverse(Double.NaN);
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: NaN");
+
+ GeometryTestUtils.assertThrows(() -> {
+ Matrices.checkElementForInverse(Double.POSITIVE_INFINITY);
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: Infinity");
+
+ GeometryTestUtils.assertThrows(() -> {
+ Matrices.checkElementForInverse(Double.NEGATIVE_INFINITY);
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: -Infinity");
+ }
}
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1DTest.java
index 7b9087e..28b6e98 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1DTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.commons.geometry.euclidean.oned;
+import java.util.function.UnaryOperator;
+
import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.numbers.angle.PlaneAngleRadians;
@@ -38,7 +40,6 @@ public class AffineTransformMatrix1DTest {
Assert.assertArrayEquals(new double[] {1, 2}, result, 0.0);
}
-
@Test
public void testOf_invalidDimensions() {
// act/assert
@@ -47,6 +48,27 @@ public class AffineTransformMatrix1DTest {
}
@Test
+ public void testFrom() {
+ // act/assert
+ Assert.assertArrayEquals(new double[] {1, 0},
+ AffineTransformMatrix1D.from(UnaryOperator.identity()).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {1, 2},
+ AffineTransformMatrix1D.from(v -> v.add(Vector1D.of(2))).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {3, 0},
+ AffineTransformMatrix1D.from(v -> v.multiply(3)).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {3, 6},
+ AffineTransformMatrix1D.from(v -> v.add(Vector1D.of(2)).multiply(3)).toArray(), EPS);
+ }
+
+ @Test
+ public void testFrom_invalidFunction() {
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> {
+ AffineTransformMatrix1D.from(v -> v.multiply(0));
+ }, IllegalArgumentException.class);
+ }
+
+ @Test
public void testIdentity() {
// act
AffineTransformMatrix1D transform = AffineTransformMatrix1D.identity();
@@ -427,15 +449,6 @@ public class AffineTransformMatrix1DTest {
}
@Test
- public void testToMatrix() {
- // arrange
- AffineTransformMatrix1D t = AffineTransformMatrix1D.of(1, 1);
-
- // act/assert
- Assert.assertSame(t, t.toMatrix());
- }
-
- @Test
public void testMultiply() {
// arrange
AffineTransformMatrix1D a = AffineTransformMatrix1D.of(2, 3);
@@ -599,31 +612,31 @@ public class AffineTransformMatrix1DTest {
// act/assert
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix1D.of(0, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is 0.0");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is 0.0");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix1D.of(Double.NaN, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix1D.of(Double.NEGATIVE_INFINITY, 0.0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is -Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is -Infinity");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix1D.of(Double.POSITIVE_INFINITY, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is Infinity");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix1D.of(1, Double.NaN).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix1D.of(1, Double.NEGATIVE_INFINITY).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: -Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: -Infinity");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix1D.of(1, Double.POSITIVE_INFINITY).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: Infinity");
}
@Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/FunctionTransform1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/FunctionTransform1DTest.java
deleted file mode 100644
index 01fb3a8..0000000
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/FunctionTransform1DTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.oned;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class FunctionTransform1DTest {
-
- private static final double TEST_EPS = 1e-15;
-
- @Test
- public void testIdentity() {
- // arrange
- Vector1D p0 = Vector1D.of(0);
- Vector1D p1 = Vector1D.of(1);
- Vector1D p2 = Vector1D.of(-1);
-
- // act
- Transform1D t = Transform1D.identity();
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p1, t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p2, t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_identity() {
- // arrange
- Vector1D p0 = Vector1D.of(0);
- Vector1D p1 = Vector1D.of(1);
- Vector1D p2 = Vector1D.of(-1);
-
- // act
- Transform1D t = Transform1D.from(UnaryOperator.identity());
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p1, t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p2, t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_scaleAndTranslate() {
- // arrange
- Vector1D p0 = Vector1D.of(0);
- Vector1D p1 = Vector1D.of(1);
- Vector1D p2 = Vector1D.of(-1);
-
- // act
- Transform1D t = Transform1D.from(v -> Vector1D.of((v.getX() + 2) * 3));
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(6), t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(9), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(3), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_reflection() {
- // arrange
- Vector1D p0 = Vector1D.of(0);
- Vector1D p1 = Vector1D.of(1);
- Vector1D p2 = Vector1D.of(-1);
-
- // act
- Transform1D t = Transform1D.from(Vector1D::negate);
-
- // assert
- Assert.assertFalse(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p2, t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p1, t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testApply() {
- // arrange
- Transform1D t = Transform1D.from(v -> {
- double x = v.getX();
- return Vector1D.of((-2 * x) + 1);
- });
-
- // act/assert
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), t.apply(Vector1D.ZERO), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(-1), t.apply(Vector1D.Unit.PLUS), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(-3), t.apply(Vector1D.of(2)), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(3), t.apply(Vector1D.of(-1)), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(5), t.apply(Vector1D.of(-2)), TEST_EPS);
- }
-
- @Test
- public void testApplyVector() {
- // arrange
- Transform1D t = Transform1D.from(v -> {
- double x = v.getX();
- return Vector1D.of((-2 * x) + 1);
- });
-
- // act/assert
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.ZERO, t.applyVector(Vector1D.ZERO), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(-2), t.applyVector(Vector1D.Unit.PLUS), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(-4), t.applyVector(Vector1D.of(2)), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(2), t.applyVector(Vector1D.of(-1)), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(4), t.applyVector(Vector1D.of(-2)), TEST_EPS);
- }
-
- @Test
- public void testToMatrix() {
- // act/assert
- Assert.assertArrayEquals(new double[] {1, 0},
- Transform1D.identity().toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {1, 2},
- Transform1D.from(v -> v.add(Vector1D.of(2))).toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {3, 0},
- Transform1D.from(v -> v.multiply(3)).toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {3, 6},
- Transform1D.from(v -> v.add(Vector1D.of(2)).multiply(3)).toMatrix().toArray(), TEST_EPS);
- }
-
- @Test
- public void testTransformRoundTrip() {
- // arrange
- double eps = 1e-8;
- double delta = 0.11;
-
- Vector1D p1 = Vector1D.of(1.1);
- Vector1D p2 = Vector1D.of(-5);
- Vector1D vec = p1.vectorTo(p2);
-
- EuclideanTestUtils.permuteSkipZero(-2, 2, delta, (translate, scale) -> {
-
- Transform1D t = Transform1D.from(v -> {
- return v.multiply(scale * 0.5)
- .add(Vector1D.of(translate))
- .multiply(scale * 1.5);
- });
-
- // act
- Vector1D t1 = t.apply(p1);
- Vector1D t2 = t.apply(p2);
- Vector1D tvec = t.applyVector(vec);
-
- Transform1D inverse = t.toMatrix().inverse();
-
- // assert
- EuclideanTestUtils.assertCoordinatesEqual(tvec, t1.vectorTo(t2), eps);
- EuclideanTestUtils.assertCoordinatesEqual(p1, inverse.apply(t1), eps);
- EuclideanTestUtils.assertCoordinatesEqual(p2, inverse.apply(t2), eps);
- });
- }
-}
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalTest.java
index 46ec589..bf58ecf 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalTest.java
@@ -621,7 +621,7 @@ public class IntervalTest {
@Test
public void testTransform() {
// arrange
- Transform1D transform = FunctionTransform1D.from(p -> Vector1D.of(2.0 * p.getX()));
+ AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(2);
// act/assert
checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 4);
@@ -639,7 +639,7 @@ public class IntervalTest {
@Test
public void testTransform_reflection() {
// arrange
- Transform1D transform = FunctionTransform1D.from(Vector1D::negate);
+ AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(-1);
// act/assert
checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 1);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
index a090e88..b82c117 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
@@ -97,7 +97,7 @@ public class OrientedPointTest {
OrientedPoint neg = OrientedPoint.createPositiveFacing(Double.NEGATIVE_INFINITY, TEST_PRECISION);
Transform<Vector1D> scaleAndTranslate = AffineTransformMatrix1D.identity().scale(10.0).translate(5.0);
- Transform<Vector1D> negate = FunctionTransform1D.from(Vector1D::negate);
+ Transform<Vector1D> negate = AffineTransformMatrix1D.from(Vector1D::negate);
// act/assert
assertOrientedPoint(pos.transform(scaleAndTranslate), Double.POSITIVE_INFINITY, false, TEST_PRECISION);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/RegionBSPTree1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/RegionBSPTree1DTest.java
index 54dd532..bcc4360 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/RegionBSPTree1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/RegionBSPTree1DTest.java
@@ -627,7 +627,7 @@ public class RegionBSPTree1DTest {
// arrange
RegionBSPTree1D tree = RegionBSPTree1D.full();
- Transform1D transform = AffineTransformMatrix1D.createScale(2);
+ AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(2);
// act
tree.transform(transform);
@@ -644,7 +644,7 @@ public class RegionBSPTree1DTest {
Interval.min(3, TEST_PRECISION)
);
- Transform1D transform = AffineTransformMatrix1D.createScale(2)
+ AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(2)
.translate(3);
// act
@@ -666,7 +666,7 @@ public class RegionBSPTree1DTest {
Interval.min(3, TEST_PRECISION)
);
- Transform1D transform = AffineTransformMatrix1D.createScale(-2)
+ AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(-2)
.translate(3);
// act
@@ -688,7 +688,7 @@ public class RegionBSPTree1DTest {
Interval.min(3, TEST_PRECISION)
);
- Transform1D transform = FunctionTransform1D.from(Vector1D::negate);
+ AffineTransformMatrix1D transform = AffineTransformMatrix1D.from(Vector1D::negate);
// act
tree.transform(transform);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3DTest.java
index f3f0c0e..05969bb 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3DTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.commons.geometry.euclidean.threed;
+import java.util.function.UnaryOperator;
+
import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils.PermuteCallback3D;
@@ -92,6 +94,39 @@ public class AffineTransformMatrix3DTest {
}
@Test
+ public void testFrom() {
+ // act/assert
+ Assert.assertArrayEquals(new double[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0
+ }, AffineTransformMatrix3D.from(UnaryOperator.identity()).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {
+ 1, 0, 0, 2,
+ 0, 1, 0, 3,
+ 0, 0, 1, -4
+ }, AffineTransformMatrix3D.from(v -> v.add(Vector3D.of(2, 3, -4))).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {
+ 3, 0, 0, 0,
+ 0, 3, 0, 0,
+ 0, 0, 3, 0
+ }, AffineTransformMatrix3D.from(v -> v.multiply(3)).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {
+ 3, 0, 0, 6,
+ 0, 3, 0, 9,
+ 0, 0, 3, 12
+ }, AffineTransformMatrix3D.from(v -> v.add(Vector3D.of(2, 3, 4)).multiply(3)).toArray(), EPS);
+ }
+
+ @Test
+ public void testFrom_invalidFunction() {
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> {
+ AffineTransformMatrix3D.from(v -> v.multiply(0));
+ }, IllegalArgumentException.class);
+ }
+
+ @Test
public void testIdentity() {
// act
AffineTransformMatrix3D transform = AffineTransformMatrix3D.identity();
@@ -731,15 +766,6 @@ public class AffineTransformMatrix3DTest {
}
@Test
- public void testToMatrix() {
- // arrange
- AffineTransformMatrix3D m = AffineTransformMatrix3D.createScale(3);
-
- // act/assert
- Assert.assertSame(m, m.toMatrix());
- }
-
- @Test
public void testMultiply_combinesTransformOperations() {
// arrange
Vector3D translation1 = Vector3D.of(1, 2, 3);
@@ -948,49 +974,49 @@ public class AffineTransformMatrix3DTest {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is 0.0");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is 0.0");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix3D.of(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, Double.NaN, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix3D.of(
1, 0, 0, 0,
0, Double.NEGATIVE_INFINITY, 0, 0,
0, 0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix3D.of(
Double.POSITIVE_INFINITY, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix3D.of(
1, 0, 0, Double.NaN,
0, 1, 0, 0,
0, 0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix3D.of(
1, 0, 0, 0,
0, 1, 0, Double.POSITIVE_INFINITY,
0, 0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: Infinity");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix3D.of(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, Double.NEGATIVE_INFINITY).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: -Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: -Infinity");
}
@Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/FacetTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/FacetTest.java
index ba6129e..8faa42c 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/FacetTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/FacetTest.java
@@ -19,7 +19,6 @@ package org.apache.commons.geometry.euclidean.threed;
import java.util.Arrays;
import java.util.List;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.Transform;
@@ -32,6 +31,7 @@ import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
import org.apache.commons.geometry.euclidean.twod.ConvexArea;
import org.apache.commons.geometry.euclidean.twod.Line;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.junit.Assert;
import org.junit.Test;
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/FunctionTransform3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/FunctionTransform3DTest.java
deleted file mode 100644
index 7a59b53..0000000
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/FunctionTransform3DTest.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.threed;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class FunctionTransform3DTest {
-
- private static final double TEST_EPS = 1e-15;
-
- @Test
- public void testIdentity() {
- // arrange
- Vector3D p0 = Vector3D.of(0, 0, 0);
- Vector3D p1 = Vector3D.of(1, 1, 1);
- Vector3D p2 = Vector3D.of(-1, -1, -1);
-
- // act
- Transform3D t = Transform3D.identity();
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p1, t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p2, t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_identity() {
- // arrange
- Vector3D p0 = Vector3D.of(0, 0, 0);
- Vector3D p1 = Vector3D.of(1, 1, 1);
- Vector3D p2 = Vector3D.of(-1, -1, -1);
-
- // act
- Transform3D t = Transform3D.from(UnaryOperator.identity());
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p1, t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p2, t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_scaleAndTranslate() {
- // arrange
- Vector3D p0 = Vector3D.of(0, 0, 0);
- Vector3D p1 = Vector3D.of(1, 2, 3);
- Vector3D p2 = Vector3D.of(-1, -2, -3);
-
- // act
- Transform3D t = Transform3D.from(v -> v.multiply(2).add(Vector3D.of(1, -1, 2)));
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, -1, 2), t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(3, 3, 8), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, -5, -4), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_reflection_singleAxis() {
- // arrange
- Vector3D p0 = Vector3D.of(0, 0, 0);
- Vector3D p1 = Vector3D.of(1, 2, 3);
- Vector3D p2 = Vector3D.of(-1, -2, -3);
-
- // act
- Transform3D t = Transform3D.from(v -> Vector3D.of(-v.getX(), v.getY(), v.getZ()));
-
- // assert
- Assert.assertFalse(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, 2, 3), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, -2, -3), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_reflection_twoAxes() {
- // arrange
- Vector3D p0 = Vector3D.of(0, 0, 0);
- Vector3D p1 = Vector3D.of(1, 2, 3);
- Vector3D p2 = Vector3D.of(-1, -2, -3);
-
- // act
- Transform3D t = Transform3D.from(v -> Vector3D.of(-v.getX(), -v.getY(), v.getZ()));
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, -2, 3), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 2, -3), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_reflection_allAxes() {
- // arrange
- Vector3D p0 = Vector3D.of(0, 0, 0);
- Vector3D p1 = Vector3D.of(1, 2, 3);
- Vector3D p2 = Vector3D.of(-1, -2, -3);
-
- // act
- Transform3D t = Transform3D.from(Vector3D::negate);
-
- // assert
- Assert.assertFalse(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, -2, -3), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 2, 3), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testToMatrix() {
- // act/assert
- Assert.assertArrayEquals(new double[] {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0
- }, Transform3D.identity().toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {
- 1, 0, 0, 2,
- 0, 1, 0, 3,
- 0, 0, 1, -4
- }, Transform3D.from(v -> v.add(Vector3D.of(2, 3, -4))).toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {
- 3, 0, 0, 0,
- 0, 3, 0, 0,
- 0, 0, 3, 0
- }, Transform3D.from(v -> v.multiply(3)).toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {
- 3, 0, 0, 6,
- 0, 3, 0, 9,
- 0, 0, 3, 12
- }, Transform3D.from(v -> v.add(Vector3D.of(2, 3, 4)).multiply(3)).toMatrix().toArray(), TEST_EPS);
- }
-
- @Test
- public void testTransformRoundTrip() {
- // arrange
- double eps = 1e-8;
- double delta = 0.11;
-
- Vector3D p1 = Vector3D.of(1.1, -3, 0);
- Vector3D p2 = Vector3D.of(-5, 0.2, 2);
- Vector3D vec = p1.vectorTo(p2);
-
- EuclideanTestUtils.permuteSkipZero(-2, 2, delta, (translate, scale) -> {
-
- Transform3D t = Transform3D.from(v -> {
- return v.multiply(scale * 0.5)
- .add(Vector3D.of(translate, 0.5 * translate, 0.25 * translate))
- .multiply(scale * 1.5);
- });
-
- // act
- Vector3D t1 = t.apply(p1);
- Vector3D t2 = t.apply(p2);
- Vector3D tvec = t.applyVector(vec);
-
- Transform3D inverse = t.toMatrix().inverse();
-
- // assert
- EuclideanTestUtils.assertCoordinatesEqual(tvec, t1.vectorTo(t2), eps);
- EuclideanTestUtils.assertCoordinatesEqual(p1, inverse.apply(t1), eps);
- EuclideanTestUtils.assertCoordinatesEqual(p2, inverse.apply(t2), eps);
- });
- }
-}
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Line3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Line3DTest.java
index 22df394..5e104a7 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Line3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Line3DTest.java
@@ -103,7 +103,7 @@ public class Line3DTest {
// arrange
Line3D line = Line3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 1), TEST_PRECISION);
- Transform3D transform = FunctionTransform3D.from(v -> Vector3D.of(v.getX(), v.getY(), -v.getZ()));
+ AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(v -> Vector3D.of(v.getX(), v.getY(), -v.getZ()));
// act
Line3D result = line.transform(transform);
@@ -118,7 +118,7 @@ public class Line3DTest {
// arrange
Line3D line = Line3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 1), TEST_PRECISION);
- Transform3D transform = FunctionTransform3D.from(v -> Vector3D.of(v.getX(), -v.getY(), -v.getZ()));
+ AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(v -> Vector3D.of(v.getX(), -v.getY(), -v.getZ()));
// act
Line3D result = line.transform(transform);
@@ -133,7 +133,7 @@ public class Line3DTest {
// arrange
Line3D line = Line3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 1), TEST_PRECISION);
- Transform3D transform = FunctionTransform3D.from(Vector3D::negate);
+ AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(Vector3D::negate);
// act
Line3D result = line.transform(transform);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
index a0e7044..84a542e 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
@@ -657,7 +657,7 @@ public class PlaneTest {
Vector3D pt = Vector3D.of(0, 0, 1);
Plane plane = Plane.fromPointAndPlaneVectors(pt, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y, TEST_PRECISION);
- Transform3D transform = FunctionTransform3D.from(v -> Vector3D.of(-v.getX(), v.getY(), v.getZ()));
+ AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(v -> Vector3D.of(-v.getX(), v.getY(), v.getZ()));
// act
Plane result = plane.transform(transform);
@@ -672,7 +672,7 @@ public class PlaneTest {
Vector3D pt = Vector3D.of(0, 0, 1);
Plane plane = Plane.fromPointAndPlaneVectors(pt, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y, TEST_PRECISION);
- Transform3D transform = FunctionTransform3D.from(v -> Vector3D.of(-v.getX(), -v.getY(), v.getZ()));
+ AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(v -> Vector3D.of(-v.getX(), -v.getY(), v.getZ()));
// act
Plane result = plane.transform(transform);
@@ -687,7 +687,7 @@ public class PlaneTest {
Vector3D pt = Vector3D.of(0, 0, 1);
Plane plane = Plane.fromPointAndPlaneVectors(pt, Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Y, TEST_PRECISION);
- Transform3D transform = FunctionTransform3D.from(Vector3D::negate);
+ AffineTransformMatrix3D transform = AffineTransformMatrix3D.from(Vector3D::negate);
// act
Plane result = plane.transform(transform);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLine3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLine3DTest.java
index 25e1ceb..0c3c86f 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLine3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLine3DTest.java
@@ -18,7 +18,6 @@ package org.apache.commons.geometry.euclidean.threed;
import java.util.List;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
@@ -26,6 +25,7 @@ import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.geometry.euclidean.oned.Interval;
import org.apache.commons.geometry.euclidean.oned.RegionBSPTree1D;
import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.junit.Assert;
import org.junit.Test;
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AbstractSegmentConnectorTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AbstractSegmentConnectorTest.java
index 0120706..e00e799 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AbstractSegmentConnectorTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AbstractSegmentConnectorTest.java
@@ -22,11 +22,11 @@ import java.util.Collections;
import java.util.List;
import java.util.Random;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.geometry.euclidean.twod.AbstractSegmentConnector.ConnectableSegment;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.junit.Assert;
import org.junit.Test;
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java
index 86f89cb..1ebf2be 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.commons.geometry.euclidean.twod;
+import java.util.function.UnaryOperator;
+
import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.numbers.angle.PlaneAngleRadians;
@@ -97,6 +99,35 @@ public class AffineTransformMatrix2DTest {
}
@Test
+ public void testFrom() {
+ // act/assert
+ Assert.assertArrayEquals(new double[] {
+ 1, 0, 0,
+ 0, 1, 0
+ }, AffineTransformMatrix2D.from(UnaryOperator.identity()).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {
+ 1, 0, 2,
+ 0, 1, 3
+ }, AffineTransformMatrix2D.from(v -> v.add(Vector2D.of(2, 3))).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {
+ 3, 0, 0,
+ 0, 3, 0
+ }, AffineTransformMatrix2D.from(v -> v.multiply(3)).toArray(), EPS);
+ Assert.assertArrayEquals(new double[] {
+ 3, 0, 6,
+ 0, 3, 9
+ }, AffineTransformMatrix2D.from(v -> v.add(Vector2D.of(2, 3)).multiply(3)).toArray(), EPS);
+ }
+
+ @Test
+ public void testFrom_invalidFunction() {
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> {
+ AffineTransformMatrix2D.from(v -> v.multiply(0));
+ }, IllegalArgumentException.class);
+ }
+
+ @Test
public void testCreateTranslation_xy() {
// act
AffineTransformMatrix2D transform = AffineTransformMatrix2D.createTranslation(2, 3);
@@ -675,15 +706,6 @@ public class AffineTransformMatrix2DTest {
}
@Test
- public void testToMatrix() {
- // arrange
- AffineTransformMatrix2D t = AffineTransformMatrix2D.createScale(2.0);
-
- // act/assert
- Assert.assertSame(t, t.toMatrix());
- }
-
- @Test
public void testMultiply() {
// arrange
AffineTransformMatrix2D a = AffineTransformMatrix2D.of(
@@ -919,43 +941,43 @@ public class AffineTransformMatrix2DTest {
AffineTransformMatrix2D.of(
0, 0, 0,
0, 0, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is 0.0");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is 0.0");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix2D.of(
1, 0, 0,
0, Double.NaN, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix2D.of(
1, 0, 0,
0, Double.NEGATIVE_INFINITY, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is -Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is -Infinity");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix2D.of(
Double.POSITIVE_INFINITY, 0, 0,
0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; matrix determinant is Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; matrix determinant is Infinity");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix2D.of(
1, 0, Double.NaN,
0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: NaN");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: NaN");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix2D.of(
1, 0, Double.POSITIVE_INFINITY,
0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: Infinity");
GeometryTestUtils.assertThrows(() -> {
AffineTransformMatrix2D.of(
1, 0, Double.NEGATIVE_INFINITY,
0, 1, 0).inverse();
- }, IllegalStateException.class, "Transform is not invertible; invalid matrix element: -Infinity");
+ }, IllegalStateException.class, "Matrix is not invertible; invalid matrix element: -Infinity");
}
@Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/ConvexAreaTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/ConvexAreaTest.java
index 2ed0e37..f04f186 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/ConvexAreaTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/ConvexAreaTest.java
@@ -104,7 +104,7 @@ public class ConvexAreaTest {
@Test
public void testTransform_full() {
// arrange
- Transform2D transform = FunctionTransform2D.from(v -> v.multiply(3));
+ AffineTransformMatrix2D transform = AffineTransformMatrix2D.createScale(3);
ConvexArea area = ConvexArea.full();
// act
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/FunctionTransform2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/FunctionTransform2DTest.java
deleted file mode 100644
index 99da23d..0000000
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/FunctionTransform2DTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.commons.geometry.euclidean.twod;
-
-import java.util.function.UnaryOperator;
-
-import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class FunctionTransform2DTest {
-
- private static final double TEST_EPS = 1e-15;
-
- @Test
- public void testIdentity() {
- // arrange
- Vector2D p0 = Vector2D.of(0, 0);
- Vector2D p1 = Vector2D.of(1, 1);
- Vector2D p2 = Vector2D.of(-1, -1);
-
- // act
- Transform2D t = Transform2D.identity();
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p1, t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p2, t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_identity() {
- // arrange
- Vector2D p0 = Vector2D.of(0, 0);
- Vector2D p1 = Vector2D.of(1, 1);
- Vector2D p2 = Vector2D.of(-1, -1);
-
- // act
- Transform2D t = Transform2D.from(UnaryOperator.identity());
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p1, t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(p2, t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_scaleAndTranslate() {
- // arrange
- Vector2D p0 = Vector2D.of(0, 0);
- Vector2D p1 = Vector2D.of(1, 2);
- Vector2D p2 = Vector2D.of(-1, -2);
-
- // act
- Transform2D t = Transform2D.from(v -> v.multiply(2).add(Vector2D.of(1, -1)));
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, -1), t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(3, 3), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-1, -5), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_reflection_singleAxis() {
- // arrange
- Vector2D p0 = Vector2D.of(0, 0);
- Vector2D p1 = Vector2D.of(1, 2);
- Vector2D p2 = Vector2D.of(-1, -2);
-
- // act
- Transform2D t = Transform2D.from(v -> Vector2D.of(-v.getX(), v.getY()));
-
- // assert
- Assert.assertFalse(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-1, 2), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, -2), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testFrom_reflection_bothAxes() {
- // arrange
- Vector2D p0 = Vector2D.of(0, 0);
- Vector2D p1 = Vector2D.of(1, 2);
- Vector2D p2 = Vector2D.of(-1, -2);
-
- // act
- Transform2D t = Transform2D.from(Vector2D::negate);
-
- // assert
- Assert.assertTrue(t.preservesOrientation());
-
- EuclideanTestUtils.assertCoordinatesEqual(p0, t.apply(p0), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-1, -2), t.apply(p1), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2), t.apply(p2), TEST_EPS);
- }
-
- @Test
- public void testApplyVector() {
- // arrange
- Transform2D t = Transform2D.from(v -> {
- return v.multiply(-2).add(Vector2D.of(4, 5));
- });
-
- // act/assert
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, t.applyVector(Vector2D.ZERO), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-2, 0), t.applyVector(Vector2D.Unit.PLUS_X), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-4, -4), t.applyVector(Vector2D.of(2, 2)), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2, 0), t.applyVector(Vector2D.of(-1, 0)), TEST_EPS);
- EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(4, 6), t.applyVector(Vector2D.of(-2, -3)), TEST_EPS);
- }
-
- @Test
- public void testToMatrix() {
- // act/assert
- Assert.assertArrayEquals(new double[] {
- 1, 0, 0,
- 0, 1, 0
- }, Transform2D.identity().toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {
- 1, 0, 2,
- 0, 1, 3
- }, Transform2D.from(v -> v.add(Vector2D.of(2, 3))).toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {
- 3, 0, 0,
- 0, 3, 0
- }, Transform2D.from(v -> v.multiply(3)).toMatrix().toArray(), TEST_EPS);
- Assert.assertArrayEquals(new double[] {
- 3, 0, 6,
- 0, 3, 9
- }, Transform2D.from(v -> v.add(Vector2D.of(2, 3)).multiply(3)).toMatrix().toArray(), TEST_EPS);
- }
-
- @Test
- public void testTransformRoundTrip() {
- // arrange
- double eps = 1e-8;
- double delta = 0.11;
-
- Vector2D p1 = Vector2D.of(1.1, -3);
- Vector2D p2 = Vector2D.of(-5, 0.2);
- Vector2D vec = p1.vectorTo(p2);
-
- EuclideanTestUtils.permuteSkipZero(-2, 2, delta, (translate, scale) -> {
-
- Transform2D t = Transform2D.from(v -> {
- return v.multiply(scale * 0.5)
- .add(Vector2D.of(translate, 0.5 * translate))
- .multiply(scale * 1.5);
- });
-
- // act
- Vector2D t1 = t.apply(p1);
- Vector2D t2 = t.apply(p2);
- Vector2D tvec = t.applyVector(vec);
-
- Transform2D inverse = t.toMatrix().inverse();
-
- // assert
- EuclideanTestUtils.assertCoordinatesEqual(tvec, t1.vectorTo(t2), eps);
- EuclideanTestUtils.assertCoordinatesEqual(p1, inverse.apply(t1), eps);
- EuclideanTestUtils.assertCoordinatesEqual(p2, inverse.apply(t2), eps);
- });
- }
-}
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/InteriorAngleSegmentConnectorTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/InteriorAngleSegmentConnectorTest.java
index 2853c57..3401b00 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/InteriorAngleSegmentConnectorTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/InteriorAngleSegmentConnectorTest.java
@@ -23,12 +23,12 @@ import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.geometry.euclidean.twod.InteriorAngleSegmentConnector.Maximize;
import org.apache.commons.geometry.euclidean.twod.InteriorAngleSegmentConnector.Minimize;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.junit.Assert;
import org.junit.Test;
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolylineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolylineTest.java
index f7af9c7..bf79809 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolylineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolylineTest.java
@@ -21,7 +21,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.partitioning.Split;
@@ -29,6 +28,7 @@ import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.geometry.euclidean.twod.Polyline.Builder;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.junit.Assert;
import org.junit.Test;
@@ -574,7 +574,7 @@ public class PolylineTest {
public void testTransform_empty() {
// arrange
Polyline path = Polyline.empty();
- FunctionTransform2D t = FunctionTransform2D.from(v -> v.add(Vector2D.Unit.PLUS_X));
+ AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.Unit.PLUS_X);
// act/assert
Assert.assertSame(path, path.transform(t));
@@ -614,7 +614,7 @@ public class PolylineTest {
Polyline path = Polyline.fromSegments(
Line.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_Y, TEST_PRECISION).span());
- FunctionTransform2D t = FunctionTransform2D.from(v -> v.add(Vector2D.Unit.PLUS_X));
+ AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.Unit.PLUS_X);
// act
Polyline result = path.transform(t);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2DTest.java
index a1f84d6..c44bbd3 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2DTest.java
@@ -1205,7 +1205,7 @@ public class RegionBSPTree2DTest {
// arrange
RegionBSPTree2D tree = Parallelogram.axisAligned(Vector2D.of(1, 1), Vector2D.of(2, 2), TEST_PRECISION).toTree();
- Transform2D transform = FunctionTransform2D.from(v -> Vector2D.of(-v.getX(), v.getY()));
+ AffineTransformMatrix2D transform = AffineTransformMatrix2D.from(v -> Vector2D.of(-v.getX(), v.getY()));
// act
tree.transform(transform);
@@ -1228,7 +1228,7 @@ public class RegionBSPTree2DTest {
RegionBSPTree2D tree = Parallelogram.axisAligned(
Vector2D.of(1, 1), Vector2D.of(2, 2), TEST_PRECISION).toTree();
- Transform2D transform = FunctionTransform2D.from(Vector2D::negate);
+ AffineTransformMatrix2D transform = AffineTransformMatrix2D.from(Vector2D::negate);
// act
tree.transform(transform);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
index d1a959d..60d9985 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
@@ -20,6 +20,7 @@ import java.util.List;
import org.apache.commons.geometry.core.GeometryTestUtils;
import org.apache.commons.geometry.core.RegionLocation;
+import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
@@ -409,10 +410,10 @@ public class SegmentTest {
// arrange
Segment segment = Segment.fromPoints(Vector2D.of(0, 1), Vector2D.of(2, 3), TEST_PRECISION);
- Transform2D translation = AffineTransformMatrix2D.createTranslation(-1, 1);
- Transform2D rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
- Transform2D scale = AffineTransformMatrix2D.createScale(2, 3);
- Transform2D reflect = FunctionTransform2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
+ Transform<Vector2D> translation = AffineTransformMatrix2D.createTranslation(-1, 1);
+ Transform<Vector2D> rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
+ Transform<Vector2D> scale = AffineTransformMatrix2D.createScale(2, 3);
+ Transform<Vector2D> reflect = AffineTransformMatrix2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
// act/assert
checkFiniteSegment(segment.transform(translation), Vector2D.of(-1, 2), Vector2D.of(1, 4));
@@ -427,10 +428,10 @@ public class SegmentTest {
Segment segment = Segment.fromInterval(Line.fromPoints(Vector2D.of(0, 1), Vector2D.of(1, 1), TEST_PRECISION),
Interval.point(0, TEST_PRECISION));
- Transform2D translation = AffineTransformMatrix2D.createTranslation(-1, 1);
- Transform2D rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
- Transform2D scale = AffineTransformMatrix2D.createScale(2, 3);
- Transform2D reflect = FunctionTransform2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
+ Transform<Vector2D> translation = AffineTransformMatrix2D.createTranslation(-1, 1);
+ Transform<Vector2D> rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
+ Transform<Vector2D> scale = AffineTransformMatrix2D.createScale(2, 3);
+ Transform<Vector2D> reflect = AffineTransformMatrix2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
// act/assert
checkFiniteSegment(segment.transform(translation), Vector2D.of(-1, 2), Vector2D.of(-1, 2));
@@ -445,10 +446,10 @@ public class SegmentTest {
Segment segment = Segment.fromInterval(Line.fromPoints(Vector2D.ZERO, Vector2D.of(2, 1), TEST_PRECISION),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
- Transform2D translation = AffineTransformMatrix2D.createTranslation(-1, 1);
- Transform2D rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
- Transform2D scale = AffineTransformMatrix2D.createScale(2, 3);
- Transform2D reflect = FunctionTransform2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
+ Transform<Vector2D> translation = AffineTransformMatrix2D.createTranslation(-1, 1);
+ Transform<Vector2D> rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
+ Transform<Vector2D> scale = AffineTransformMatrix2D.createScale(2, 3);
+ Transform<Vector2D> reflect = AffineTransformMatrix2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
// act/assert
Segment translated = segment.transform(translation);
@@ -486,10 +487,10 @@ public class SegmentTest {
Segment segment = Segment.fromInterval(Line.fromPoints(Vector2D.ZERO, Vector2D.of(2, 1), TEST_PRECISION),
0.0, Double.POSITIVE_INFINITY);
- Transform2D translation = AffineTransformMatrix2D.createTranslation(-1, 1);
- Transform2D rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
- Transform2D scale = AffineTransformMatrix2D.createScale(2, 3);
- Transform2D reflect = FunctionTransform2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
+ Transform<Vector2D> translation = AffineTransformMatrix2D.createTranslation(-1, 1);
+ Transform<Vector2D> rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
+ Transform<Vector2D> scale = AffineTransformMatrix2D.createScale(2, 3);
+ Transform<Vector2D> reflect = AffineTransformMatrix2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
// act/assert
Segment translated = segment.transform(translation);
@@ -527,10 +528,10 @@ public class SegmentTest {
Segment segment = Segment.fromInterval(Line.fromPoints(Vector2D.ZERO, Vector2D.of(2, 1), TEST_PRECISION),
Double.NEGATIVE_INFINITY, 0.0);
- Transform2D translation = AffineTransformMatrix2D.createTranslation(-1, 1);
- Transform2D rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
- Transform2D scale = AffineTransformMatrix2D.createScale(2, 3);
- Transform2D reflect = FunctionTransform2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
+ Transform<Vector2D> translation = AffineTransformMatrix2D.createTranslation(-1, 1);
+ Transform<Vector2D> rotation = AffineTransformMatrix2D.createRotation(PlaneAngleRadians.PI_OVER_TWO);
+ Transform<Vector2D> scale = AffineTransformMatrix2D.createScale(2, 3);
+ Transform<Vector2D> reflect = AffineTransformMatrix2D.from(pt -> Vector2D.of(pt.getX(), -pt.getY()));
// act/assert
Segment translated = segment.transform(translation);
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Transform1S.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Transform1S.java
index 5d2449d..fe8ad80 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Transform1S.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Transform1S.java
@@ -130,10 +130,8 @@ public final class Transform1S implements Transform<Point1S> {
return multiply(other, this);
}
- /** Return a transform that is the inverse of the current instance. The returned transform
- * will undo changes applied by this instance.
- * @return a transform that is the inverse of the current instance
- */
+ /** {@inheritDoc} */
+ @Override
public Transform1S inverse() {
final double invScale = 1.0 / scale;
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Transform2S.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Transform2S.java
index bb50fd0..6da7bfa 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Transform2S.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Transform2S.java
@@ -65,10 +65,8 @@ public final class Transform2S implements Transform<Point2S> {
return euclideanTransform.preservesOrientation();
}
- /** Return a new instance representing the inverse transform operation
- * of this instance.
- * @return a transform representing the inverse of this instance
- */
+ /** {@inheritDoc} */
+ @Override
public Transform2S inverse() {
return new Transform2S(euclideanTransform.inverse());
}
diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml
index 52d2095..fe959e8 100644
--- a/src/site/xdoc/index.xml
+++ b/src/site/xdoc/index.xml
@@ -51,10 +51,8 @@ RegionBSPTree3D region = RegionBSPTree3D.from(
Parallelepiped.axisAligned(Vector3D.of(-0.5, -0.5, -0.5), Vector3D.of(0.5, 0.5, 0.5), precision));
// create a rotated copy of the region
-Transform3D rotation = QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Z, 0.25 * Math.PI);
-
RegionBSPTree3D copy = region.copy();
-copy.transform(rotation);
+copy.transform(QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Z, 0.25 * Math.PI));
// compute the intersection of the regions, storing the result back into the caller
// (the result could also have been placed into a third region)
diff --git a/src/site/xdoc/userguide/index.xml b/src/site/xdoc/userguide/index.xml
index 6a06a1d..a7ebb6a 100644
--- a/src/site/xdoc/userguide/index.xml
+++ b/src/site/xdoc/userguide/index.xml
@@ -197,27 +197,40 @@ v1.eq(v3, precision); // true - approximately equal according to the given preci
<a class="code" href="../commons-geometry-core/apidocs/org/apache/commons/geometry/core/Transform.html">Transform</a>
interface. Useful implementations of this interface exist for each supported space
and dimension, so users should not need to implement their own. However, it is important to know that
- all implementations (and instances) of this interface <em>must</em> meet the following requirements:
+ all implementations of this interface <em>must</em> meet the requirements listed below. Transforms that do
+ not meet these requirements cannot be expected to produce correct results in algorithms that use this
+ interface.
</p>
<ol>
<li>
- The transform must be <strong><a href="https://en.wikipedia.org/wiki/Affine_transformation">affine</a></strong>.
- In basic terms, this means that the transform must retain the "straightness" and "parallelness" of
- lines and planes (or whatever is an equivalent concept for the space). For example, a translation or
- rotation in Euclidean 3D space meets this requirement because all lines that are parallel before the
- transform remain parallel afterwards. However, a projective transform that causes previously parallel
- lines to meet at a single point does not.
+ Transforms must represent functions that are <em>one-to-one</em> and <em>onto</em>
+ (i.e. <a href="https://en.wikipedia.org/wiki/Bijection">bijections</a>). This means that every point
+ in the space must be mapped to exactly one other point in the space. This also implies that the function
+ is invertible.
</li>
<li>
- The transform must be <strong>inversible</strong>. An inverse transform must exist that will return
- the original point if given the transformed point. In other words, for a transform <var>t</var>, there
- must exist an inverse <var>inv</var> such that <var>inv.apply(t.apply(pt))</var> returns a point equal to
- the input point <var>pt</var>.
+ Transforms must preserve <a href="https://en.wikipedia.org/wiki/Collinearity">collinearity</a>. This
+ means that if a set of points lie on a common hyperplane before the transform, then they must also lie
+ on a common hyperplane after the transform. For example, if the Euclidean 2D points <var>a</var>,
+ <var>b</var>, and <var>c</var> lie on line <var>L</var>, then the transformed points <var>a'</var>,
+ <var>b'</var>, and <var>c'</var> must lie on line <var>L'</var>, where <var>L'</var> is the transformed
+ form of the line.
+ </li>
+ <li>
+ Transforms must preserve the concept of
+ <a href="https://en.wikipedia.org/wiki/Parallel_(geometry)">parallelism</a> defined for the space.
+ This means that hyperplanes that are parallel before the transformation must remain parallel afterwards,
+ and hyperplanes that intersect must also intersect afterwards. For example, a transform that causes
+ parallel lines to converge to a single point in Euclidean space (such as the projective transforms used to
+ create perspective viewpoints in 3D graphics) would not meet this requirement. However, a transform that
+ turns a square into a rhombus with no right angles would fulfill the requirement, since the two pairs of
+ parallel lines forming the square remain parallel after the transformation.
</li>
</ol>
<p>
- Transforms that do not meet these requirements cannot be expected to produce correct results in
- algorithms that use this interface.
+ Transforms that meet the above requirements in Euclidean space (and other affine spaces) are known as
+ <a href="https://en.wikipedia.org/wiki/Affine_transformation">affine transforms</a> and include such common
+ operations as translation, rotation, reflection, scaling, and any combinations thereof.
</p>
</subsection>
@@ -413,7 +426,8 @@ tree.count(); // number of nodes in the tree = 7
</li>
<li>
<a class="code" href="../commons-geometry-core/apidocs/org/apache/commons/geometry/core/Transform.html">Transform</a> -
- Represents a mapping between points. Instances are used to transform points and other geometric primitives.
+ Represents an inversible mapping between points that preserves parallelism. Instances are used to transform
+ points and other geometric primitives.
</li>
</ul>
</li>
@@ -474,14 +488,8 @@ tree.count(); // number of nodes in the tree = 7
Transform
<ul>
<li>
- <a class="code" href="../commons-geometry-euclidean/apidocs/org/apache/commons/geometry/euclidean/oned/Transform1D.html">Transform1D</a> -
- Primary interface for 1D transforms. A utility method is also provided to construct transform instances
- from JDK <span class="code">Function</span>'s. Callers are responsible for ensuring that given functions
- meet the <a href="#transforms">requirements for transforms</a>.
- </li>
- <li>
<a class="code" href="../commons-geometry-euclidean/apidocs/org/apache/commons/geometry/euclidean/oned/AffineTransformMatrix1D.html">AffineTransformMatrix1D</a> -
- Represents transforms using a 2x2 matrix.
+ Represents affine transforms using a 2x2 matrix.
</li>
</ul>
@@ -565,14 +573,8 @@ List<Interval> intervals = tree.toIntervals(); // size = 2
Transform
<ul>
<li>
- <a class="code" href="../commons-geometry-euclidean/apidocs/org/apache/commons/geometry/euclidean/twod/Transform2D.html">Transform2D</a> -
- Primary interface for 2D transforms. A utility method is also provided to construct transform instances
- from JDK <span class="code">Function</span>'s. Callers are responsible for ensuring that given functions
- meet the <a href="#transforms">requirements for transforms</a>.
- </li>
- <li>
<a class="code" href="../commons-geometry-euclidean/apidocs/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.html">AffineTransformMatrix2D</a> -
- Represents transforms using a 3x3 matrix.
+ Represents affine transforms using a 3x3 matrix.
</li>
</ul>
</li>
@@ -637,8 +639,7 @@ RegionBSPTree2D tree = path.toTree();
RegionBSPTree2D copy = tree.copy();
// translate the copy
-Vector2D translation = Vector2D.of(0.5, 0.5);
-copy.transform(Transform2D.from(v -> v.add(translation)));
+copy.transform(AffineTransformMatrix2D.createTranslation(Vector2D.of(0.5, 0.5)));
// compute the union of the regions, storing the result back into the
// first tree
@@ -704,14 +705,8 @@ Vector2D normal = pt.getNormal(); // (1.0, 0.0)
Transform
<ul>
<li>
- <a class="code" href="../commons-geometry-euclidean/apidocs/org/apache/commons/geometry/euclidean/threed/Transform3D.html">Transform3D</a> -
- Primary interface for 3D transforms. A utility method is also provided to construct transform instances
- from JDK <span class="code">Function</span>'s. Callers are responsible for ensuring that given functions
- meet the <a href="#transforms">requirements for transforms</a>.
- </li>
- <li>
<a class="code" href="../commons-geometry-euclidean/apidocs/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.html">AffineTransformMatrix3D</a> -
- Represents transforms using a 4x4 matrix.
+ Represents affine transforms using a 4x4 matrix.
</li>
<li>
<a class="code" href="../commons-geometry-euclidean/apidocs/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.html">QuaternionRotation</a> -