Rotation2D.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.euclidean.twod.rotation;
- import org.apache.commons.geometry.euclidean.EuclideanTransform;
- import org.apache.commons.geometry.euclidean.internal.Vectors;
- import org.apache.commons.geometry.euclidean.twod.AffineTransformMatrix2D;
- import org.apache.commons.geometry.euclidean.twod.Vector2D;
- /** Class representing a rotation in 2 dimensional Euclidean space. Positive
- * rotations are in a <em>counter-clockwise</em> direction.
- */
- public final class Rotation2D implements EuclideanTransform<Vector2D> {
- /** Instance representing a rotation of zero radians. */
- private static final Rotation2D IDENTITY = new Rotation2D(0);
- /** The angle of the rotation in radians. */
- private final double angle;
- /** The cosine of the angle of rotation, cached to avoid repeated computation. */
- private final double cosAngle;
- /** The sine of the angle of rotation, cached to avoid repeated computation. */
- private final double sinAngle;
- /** Create a new instance representing the given angle.
- * @param angle the angle of rotation, in radians
- */
- private Rotation2D(final double angle) {
- this.angle = angle;
- this.cosAngle = Math.cos(angle);
- this.sinAngle = Math.sin(angle);
- }
- /** Get the angle of rotation in radians.
- * @return the angle of rotation in radians
- */
- public double getAngle() {
- return angle;
- }
- /** {@inheritDoc} */
- @Override
- public Rotation2D inverse() {
- return new Rotation2D(-angle);
- }
- /** {@inheritDoc}
- *
- * <p>This method simply returns true since rotations always preserve the orientation
- * of the space.</p>
- */
- @Override
- public boolean preservesOrientation() {
- return true;
- }
- /** {@inheritDoc} */
- @Override
- public Vector2D apply(final Vector2D pt) {
- final double x = pt.getX();
- final double y = pt.getY();
- return Vector2D.of(
- (x * cosAngle) - (y * sinAngle),
- (x * sinAngle) + (y * cosAngle)
- );
- }
- /** {@inheritDoc}
- *
- * <p>This method simply calls {@code apply(vec)} since rotations treat
- * points and vectors similarly.</p>
- * */
- @Override
- public Vector2D applyVector(final Vector2D vec) {
- return apply(vec);
- }
- /** Return an {@link AffineTransformMatrix2D} representing the same rotation
- * as this instance.
- * @return a transform matrix representing the same rotation
- */
- public AffineTransformMatrix2D toMatrix() {
- return AffineTransformMatrix2D.of(
- cosAngle, -sinAngle, 0.0,
- sinAngle, cosAngle, 0.0
- );
- }
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return Double.hashCode(angle);
- }
- /** {@inheritDoc} */
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof Rotation2D)) {
- return false;
- }
- final Rotation2D other = (Rotation2D) obj;
- return Double.compare(this.angle, other.angle) == 0;
- }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append(this.getClass().getSimpleName())
- .append("[angle=")
- .append(angle)
- .append(']');
- return sb.toString();
- }
- /** Create a new instance with the given angle of rotation.
- * @param angle the angle of rotation in radians
- * @return a new instance with the given angle of rotation
- */
- public static Rotation2D of(final double angle) {
- return new Rotation2D(angle);
- }
- /** Return an instance representing the identity rotation, ie a rotation
- * of zero radians.
- * @return an instance representing a rotation of zero radians
- */
- public static Rotation2D identity() {
- return IDENTITY;
- }
- /** Create a rotation instance that rotates the vector {@code u} to point in the direction of
- * vector {@code v}.
- * @param u input vector
- * @param v target vector
- * @return a rotation instance that rotates {@code u} to point in the direction of {@code v}
- * @throws IllegalArgumentException if either vector cannot be normalized
- */
- public static Rotation2D createVectorRotation(final Vector2D u, final Vector2D v) {
- // make sure that the vectors are real-valued and of non-zero length; we don't
- // actually need to use the norm value; we just need to check its properties
- Vectors.checkedNorm(u);
- Vectors.checkedNorm(v);
- final double uAzimuth = Math.atan2(u.getY(), u.getX());
- final double vAzimuth = Math.atan2(v.getY(), v.getX());
- return of(vAzimuth - uAzimuth);
- }
- }