Transform2S.java
- /*
- * 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.spherical.twod;
- import org.apache.commons.geometry.core.Transform;
- import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
- import org.apache.commons.geometry.euclidean.threed.Vector3D;
- import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
- /** Implementation of the {@link Transform} interface for spherical 2D points.
- *
- * <p>This class uses an {@link AffineTransformMatrix3D} to perform spherical point transforms
- * in Euclidean 3D space.</p>
- *
- * <p>Instances of this class are guaranteed to be immutable.</p>
- */
- public final class Transform2S implements Transform<Point2S> {
- /** Static instance representing the identity transform. */
- private static final Transform2S IDENTITY = new Transform2S(AffineTransformMatrix3D.identity());
- /** Static transform instance that reflects across the x-y plane. */
- private static final AffineTransformMatrix3D XY_PLANE_REFLECTION = AffineTransformMatrix3D.createScale(1, 1, -1);
- /** Euclidean transform matrix underlying the spherical transform. */
- private final AffineTransformMatrix3D euclideanTransform;
- /** Construct a new instance from its underlying Euclidean transform.
- * @param euclideanTransform underlying Euclidean transform
- */
- private Transform2S(final AffineTransformMatrix3D euclideanTransform) {
- this.euclideanTransform = euclideanTransform;
- }
- /** Get the Euclidean transform matrix underlying the spherical transform.
- * @return the Euclidean transform matrix underlying the spherical transform
- */
- public AffineTransformMatrix3D getEuclideanTransform() {
- return euclideanTransform;
- }
- /** {@inheritDoc} */
- @Override
- public Point2S apply(final Point2S pt) {
- final Vector3D vec = pt.getVector();
- return Point2S.from(euclideanTransform.apply(vec));
- }
- /** {@inheritDoc} */
- @Override
- public boolean preservesOrientation() {
- return euclideanTransform.preservesOrientation();
- }
- /** {@inheritDoc} */
- @Override
- public Transform2S inverse() {
- return new Transform2S(euclideanTransform.inverse());
- }
- /** Apply a rotation of {@code angle} radians around the given point to this instance.
- * @param pt point to rotate around
- * @param angle rotation angle in radians
- * @return transform resulting from applying the specified rotation to this instance
- */
- public Transform2S rotate(final Point2S pt, final double angle) {
- return premultiply(createRotation(pt, angle));
- }
- /** Apply a rotation of {@code angle} radians around the given 3D axis to this instance.
- * @param axis 3D axis of rotation
- * @param angle rotation angle in radians
- * @return transform resulting from applying the specified rotation to this instance
- */
- public Transform2S rotate(final Vector3D axis, final double angle) {
- return premultiply(createRotation(axis, angle));
- }
- /** Apply the given quaternion rotation to this instance.
- * @param quaternion quaternion rotation to apply
- * @return transform resulting from applying the specified rotation to this instance
- */
- public Transform2S rotate(final QuaternionRotation quaternion) {
- return premultiply(createRotation(quaternion));
- }
- /** Apply a reflection across the equatorial plane defined by the given pole point
- * to this instance.
- * @param pole pole point defining the equatorial reflection plane
- * @return transform resulting from applying the specified reflection to this instance
- */
- public Transform2S reflect(final Point2S pole) {
- return premultiply(createReflection(pole));
- }
- /** Apply a reflection across the equatorial plane defined by the given pole vector
- * to this instance.
- * @param poleVector pole vector defining the equatorial reflection plane
- * @return transform resulting from applying the specified reflection to this instance
- */
- public Transform2S reflect(final Vector3D poleVector) {
- return premultiply(createReflection(poleVector));
- }
- /** Multiply the underlying Euclidean transform of this instance by that of the argument, eg,
- * {@code other * this}. The returned transform performs the equivalent of
- * {@code other} followed by {@code this}.
- * @param other transform to multiply with
- * @return a new transform computed by multiplying the matrix of this
- * instance by that of the argument
- * @see AffineTransformMatrix3D#multiply(AffineTransformMatrix3D)
- */
- public Transform2S multiply(final Transform2S other) {
- return multiply(this, other);
- }
- /** Multiply the underlying Euclidean transform matrix of the argument by that of this instance, eg,
- * {@code this * other}. The returned transform performs the equivalent of {@code this}
- * followed by {@code other}.
- * @param other transform to multiply with
- * @return a new transform computed by multiplying the matrix of the
- * argument by that of this instance
- * @see AffineTransformMatrix3D#premultiply(AffineTransformMatrix3D)
- */
- public Transform2S premultiply(final Transform2S other) {
- return multiply(other, this);
- }
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return euclideanTransform.hashCode();
- }
- /**
- * Return true if the given object is an instance of {@link Transform2S}
- * and the underlying Euclidean transform matrices are exactly equal.
- * @param obj object to test for equality with the current instance
- * @return true if the underlying transform matrices are exactly equal
- */
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof Transform2S)) {
- return false;
- }
- final Transform2S other = (Transform2S) obj;
- return euclideanTransform.equals(other.euclideanTransform);
- }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append(this.getClass().getSimpleName())
- .append("[euclideanTransform= ")
- .append(getEuclideanTransform())
- .append(']');
- return sb.toString();
- }
- /** Return an instance representing the identity transform. This transform is guaranteed
- * to return an <em>equivalent</em> (ie, co-located) point for any input point. However, the
- * points are not guaranteed to contain exactly equal coordinates. For example, at the poles, an
- * infinite number of points exist that vary only in the azimuth coordinate. When one of these
- * points is transformed by this identity transform, the returned point may contain a different
- * azimuth value from the input, but it will still represent the same location in space.
- * @return an instance representing the identity transform
- */
- public static Transform2S identity() {
- return IDENTITY;
- }
- /** Create a transform that rotates the given angle around {@code pt}.
- * @param pt point to rotate around
- * @param angle angle of rotation in radians
- * @return a transform that rotates the given angle around {@code pt}
- */
- public static Transform2S createRotation(final Point2S pt, final double angle) {
- return createRotation(pt.getVector(), angle);
- }
- /** Create a transform that rotates the given angle around {@code axis}.
- * @param axis 3D axis of rotation
- * @param angle angle of rotation in radians
- * @return a transform that rotates the given angle {@code axis}
- */
- public static Transform2S createRotation(final Vector3D axis, final double angle) {
- return createRotation(QuaternionRotation.fromAxisAngle(axis, angle));
- }
- /** Create a transform that performs the given 3D rotation.
- * @param quaternion quaternion instance representing the 3D rotation
- * @return a transform that performs the given 3D rotation
- */
- public static Transform2S createRotation(final QuaternionRotation quaternion) {
- return new Transform2S(quaternion.toMatrix());
- }
- /** Create a transform that performs a reflection across the equatorial plane
- * defined by the given pole point.
- * @param pole pole point defining the equatorial reflection plane
- * @return a transform that performs a reflection across the equatorial plane
- * defined by the given pole point
- */
- public static Transform2S createReflection(final Point2S pole) {
- return createReflection(pole.getVector());
- }
- /** Create a transform that performs a reflection across the equatorial plane
- * defined by the given pole point.
- * @param poleVector pole vector defining the equatorial reflection plane
- * @return a transform that performs a reflection across the equatorial plane
- * defined by the given pole point
- */
- public static Transform2S createReflection(final Vector3D poleVector) {
- final QuaternionRotation quat = QuaternionRotation.createVectorRotation(poleVector, Vector3D.Unit.PLUS_Z);
- final AffineTransformMatrix3D matrix = quat.toMatrix()
- .premultiply(XY_PLANE_REFLECTION)
- .premultiply(quat.inverse().toMatrix());
- return new Transform2S(matrix);
- }
- /** Multiply the Euclidean transform matrices of the arguments together.
- * @param a first transform
- * @param b second transform
- * @return the transform computed as {@code a x b}
- */
- private static Transform2S multiply(final Transform2S a, final Transform2S b) {
- return new Transform2S(a.euclideanTransform.multiply(b.euclideanTransform));
- }
- }