Transform1S.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.geometry.spherical.oned;

  18. import org.apache.commons.geometry.core.Transform;

  19. /** Implementation of the {@link Transform} interface for spherical 1D points.
  20.  *
  21.  * <p>Similar to the Euclidean 1D
  22.  * {@link org.apache.commons.geometry.euclidean.oned.AffineTransformMatrix1D AffineTransformMatrix1D},
  23.  * this class performs transformations using an internal 1D affine transformation matrix. In the
  24.  * Euclidean case, the matrix contains a scale factor and a translation. Here, the matrix contains
  25.  * a scale/negation factor that takes the values -1 or +1, and a rotation value. This restriction on
  26.  * the allowed values in the matrix is required in order to fulfill the geometric requirements
  27.  * of the {@link Transform} interface. For example, if arbitrary scaling is allowed, the point {@code 0.5pi}
  28.  * could be scaled by 4 to {@code 2pi}, which is equivalent to {@code 0pi}. However, if the inverse scaling
  29.  * of {@code 1/4} is applied to {@code 0pi}, the result is {@code 0pi} and not {@code 0.5pi}. This breaks
  30.  * the {@link Transform} requirement that transforms be inversible.
  31.  * </p>
  32.  *
  33.  * <p>Instances of this class are guaranteed to be immutable.</p>
  34.  */
  35. public final class Transform1S implements Transform<Point1S> {
  36.     /** Static instance representing the identity transform. */
  37.     private static final Transform1S IDENTITY = new Transform1S(1, 0);

  38.     /** Static instance that negates azimuth values. */
  39.     private static final Transform1S NEGATION = new Transform1S(-1, 0);

  40.     /** Value to scale the point azimuth by. This will only be +1/-1. */
  41.     private final double scale;

  42.     /** Value to rotate the point azimuth by. */
  43.     private final double rotate;

  44.     /** Construct a new instance from its transform components.
  45.      * @param scale scale value for the transform; must only be +1 or -1
  46.      * @param rotate rotation value
  47.      */
  48.     private Transform1S(final double scale, final double rotate) {
  49.         this.scale = scale;
  50.         this.rotate = rotate;
  51.     }

  52.     /** Return true if the transform negates the azimuth values of transformed
  53.      * points, regardless of any rotation applied subsequently.
  54.      * @return true if the transform negates the azimuth values of transformed
  55.      *      points
  56.      * @see #preservesOrientation()
  57.      */
  58.     public boolean isNegation() {
  59.         return scale <= 0;
  60.     }

  61.     /** Get the rotation value applied by this instance, in radians.
  62.      * @return the rotation value applied by this instance, in radians.
  63.      */
  64.     public double getRotation() {
  65.         return rotate;
  66.     }

  67.     /** {@inheritDoc} */
  68.     @Override
  69.     public Point1S apply(final Point1S pt) {
  70.         final double az = pt.getAzimuth();
  71.         final double resultAz = (az * scale) + rotate;

  72.         return Point1S.of(resultAz);
  73.     }

  74.     /** {@inheritDoc} */
  75.     @Override
  76.     public boolean preservesOrientation() {
  77.         return !isNegation();
  78.     }

  79.     /** Return a new transform created by pre-multiplying this instance by a transform
  80.      * producing a rotation with the given angle.
  81.      * @param angle angle to rotate, in radians
  82.      * @return a new transform created by pre-multiplying this instance by a transform
  83.      *      producing a rotation with the given angle
  84.      * @see #createRotation(double)
  85.      */
  86.     public Transform1S rotate(final double angle) {
  87.         return premultiply(createRotation(angle));
  88.     }

  89.     /** Return a new transform created by pre-multiplying this instance by a transform
  90.      * that negates azimuth values.
  91.      * @return a new transform created by pre-multiplying this instance by a transform
  92.      *      that negates azimuth values
  93.      */
  94.     public Transform1S negate() {
  95.         return premultiply(createNegation());
  96.     }

  97.     /** Multiply the underlying matrix of this instance by that of the argument, eg,
  98.      * {@code other * this}. The returned transform performs the equivalent of
  99.      * {@code other} followed by {@code this}.
  100.      * @param other transform to multiply with
  101.      * @return a new transform computed by multiplying the matrix of this
  102.      *      instance by that of the argument
  103.      */
  104.     public Transform1S multiply(final Transform1S other) {
  105.         return multiply(this, other);
  106.     }

  107.     /** Multiply the underlying matrix of the argument by that of this instance, eg,
  108.      * {@code this * other}. The returned transform performs the equivalent of {@code this}
  109.      * followed by {@code other}.
  110.      * @param other transform to multiply with
  111.      * @return a new transform computed by multiplying the matrix of the
  112.      *      argument by that of this instance
  113.      */
  114.     public Transform1S premultiply(final Transform1S other) {
  115.         return multiply(other, this);
  116.     }

  117.     /** {@inheritDoc} */
  118.     @Override
  119.     public Transform1S inverse() {
  120.         final double invScale = 1.0 / scale;

  121.         final double resultRotate = -(rotate * invScale);

  122.         return new Transform1S(invScale, resultRotate);
  123.     }

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     public int hashCode() {
  127.         final int prime = 31;
  128.         int result = 1;

  129.         result = (result * prime) + Double.hashCode(scale);
  130.         result = (result * prime) + Double.hashCode(rotate);

  131.         return result;
  132.     }

  133.     /**
  134.      * Return true if the given object is an instance of {@link Transform1S}
  135.      * and all transform element values are exactly equal.
  136.      * @param obj object to test for equality with the current instance
  137.      * @return true if all transform elements are exactly equal; otherwise false
  138.      */
  139.     @Override
  140.     public boolean equals(final Object obj) {
  141.         if (this == obj) {
  142.             return true;
  143.         }
  144.         if (!(obj instanceof Transform1S)) {
  145.             return false;
  146.         }
  147.         final Transform1S other = (Transform1S) obj;

  148.         return Double.compare(scale, other.scale) == 0 &&
  149.                 Double.compare(rotate, other.rotate) == 0;
  150.     }

  151.     /** {@inheritDoc} */
  152.     @Override
  153.     public String toString() {
  154.         final StringBuilder sb = new StringBuilder();

  155.         sb.append(this.getClass().getSimpleName())
  156.             .append("[negate= ")
  157.             .append(isNegation())
  158.             .append(", rotate= ")
  159.             .append(getRotation())
  160.             .append(']');

  161.         return sb.toString();
  162.     }

  163.     /** Return a transform instance representing the identity transform.
  164.      * @return a transform instance representing the identity transform
  165.      */
  166.     public static Transform1S identity() {
  167.         return IDENTITY;
  168.     }

  169.     /** Return a transform instance that negates azimuth values.
  170.      * @return a transform instance that negates azimuth values.
  171.      */
  172.     public static Transform1S createNegation() {
  173.         return NEGATION;
  174.     }

  175.     /** Return a transform instance that performs a rotation with the given
  176.      * angle.
  177.      * @param angle angle of the rotation, in radians
  178.      * @return a transform instance that performs a rotation with the given
  179.      *      angle
  180.      */
  181.     public static Transform1S createRotation(final double angle) {
  182.         return new Transform1S(1, angle);
  183.     }

  184.     /** Multiply two transforms together as matrices.
  185.      * @param a first transform
  186.      * @param b second transform
  187.      * @return the transform computed as {@code a x b}
  188.      */
  189.     private static Transform1S multiply(final Transform1S a, final Transform1S b) {

  190.         // calculate the matrix elements
  191.         final double resultScale = a.scale * b.scale;
  192.         final double resultRotate = (a.scale * b.rotate) + a.rotate;

  193.         return new Transform1S(resultScale, resultRotate);
  194.     }
  195. }