Vector1D.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.euclidean.oned;

  18. import java.util.Comparator;
  19. import java.util.function.UnaryOperator;

  20. import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
  21. import org.apache.commons.geometry.euclidean.EuclideanVector;
  22. import org.apache.commons.geometry.euclidean.EuclideanVectorSum;
  23. import org.apache.commons.geometry.euclidean.internal.Vectors;
  24. import org.apache.commons.numbers.core.Precision;

  25. /** This class represents vectors and points in one-dimensional Euclidean space.
  26.  * Instances of this class are guaranteed to be immutable.
  27.  */
  28. public class Vector1D extends EuclideanVector<Vector1D> {

  29.     /** Zero vector (coordinates: 0). */
  30.     public static final Vector1D ZERO = new Vector1D(0.0);

  31.     /** A vector with all coordinates set to NaN. */
  32.     public static final Vector1D NaN = new Vector1D(Double.NaN);

  33.     /** A vector with all coordinates set to positive infinity. */
  34.     public static final Vector1D POSITIVE_INFINITY =
  35.         new Vector1D(Double.POSITIVE_INFINITY);

  36.     /** A vector with all coordinates set to negative infinity. */
  37.     public static final Vector1D NEGATIVE_INFINITY =
  38.         new Vector1D(Double.NEGATIVE_INFINITY);

  39.     /** Comparator that sorts vectors in component-wise ascending order.
  40.      * Vectors are only considered equal if their coordinates match exactly.
  41.      * Null arguments are evaluated as being greater than non-null arguments.
  42.      */
  43.     public static final Comparator<Vector1D> COORDINATE_ASCENDING_ORDER = (a, b) -> {
  44.         int cmp = 0;

  45.         if (a != null && b != null) {
  46.             cmp = Double.compare(a.getX(), b.getX());
  47.         } else if (a != null) {
  48.             cmp = -1;
  49.         } else if (b != null) {
  50.             cmp = 1;
  51.         }

  52.         return cmp;
  53.     };

  54.     /** Abscissa (coordinate value). */
  55.     private final double x;

  56.     /** Simple constructor.
  57.      * @param x abscissa (coordinate value)
  58.      */
  59.     private Vector1D(final double x) {
  60.         this.x = x;
  61.     }

  62.     /**
  63.      * Returns the abscissa (coordinate value) of the instance.
  64.      * @return the abscissa value
  65.      */
  66.     public double getX() {
  67.         return x;
  68.     }

  69.     /** {@inheritDoc} */
  70.     @Override
  71.     public int getDimension() {
  72.         return 1;
  73.     }

  74.     /** {@inheritDoc} */
  75.     @Override
  76.     public boolean isNaN() {
  77.         return Double.isNaN(x);
  78.     }

  79.     /** {@inheritDoc} */
  80.     @Override
  81.     public boolean isInfinite() {
  82.         return !isNaN() && Double.isInfinite(x);
  83.     }

  84.     /** {@inheritDoc} */
  85.     @Override
  86.     public boolean isFinite() {
  87.         return Double.isFinite(x);
  88.     }

  89.     /** {@inheritDoc} */
  90.     @Override
  91.     public Vector1D vectorTo(final Vector1D v) {
  92.         return v.subtract(this);
  93.     }

  94.     /** {@inheritDoc} */
  95.     @Override
  96.     public Unit directionTo(final Vector1D v) {
  97.         return vectorTo(v).normalize();
  98.     }

  99.     /** {@inheritDoc} */
  100.     @Override
  101.     public Vector1D lerp(final Vector1D p, final double t) {
  102.         return Sum.create()
  103.                 .addScaled(1.0 - t, this)
  104.                 .addScaled(t, p).get();
  105.     }

  106.     /** {@inheritDoc} */
  107.     @Override
  108.     public Vector1D getZero() {
  109.         return ZERO;
  110.     }

  111.     /** {@inheritDoc} */
  112.     @Override
  113.     public double norm() {
  114.         return Vectors.norm(x);
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public double normSq() {
  119.         return Vectors.normSq(x);
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     public Vector1D withNorm(final double magnitude) {
  124.         getCheckedNorm(); // validate our norm value
  125.         return (x > 0.0) ? new Vector1D(magnitude) : new Vector1D(-magnitude);
  126.     }

  127.     /** {@inheritDoc} */
  128.     @Override
  129.     public Vector1D add(final Vector1D v) {
  130.         return new Vector1D(x + v.x);
  131.     }

  132.     /** {@inheritDoc} */
  133.     @Override
  134.     public Vector1D add(final double factor, final Vector1D v) {
  135.         return new Vector1D(x + (factor * v.x));
  136.     }

  137.     /** {@inheritDoc} */
  138.     @Override
  139.     public Vector1D subtract(final Vector1D v) {
  140.         return new Vector1D(x - v.x);
  141.     }

  142.     /** {@inheritDoc} */
  143.     @Override
  144.     public Vector1D subtract(final double factor, final Vector1D v) {
  145.         return new Vector1D(x - (factor * v.x));
  146.     }

  147.     /** {@inheritDoc} */
  148.     @Override
  149.     public Vector1D negate() {
  150.         return new Vector1D(-x);
  151.     }

  152.     /** {@inheritDoc} */
  153.     @Override
  154.     public Unit normalize() {
  155.         return Unit.from(x);
  156.     }

  157.     /** {@inheritDoc} */
  158.     @Override
  159.     public Unit normalizeOrNull() {
  160.         return Unit.tryCreateNormalized(x, false);
  161.     }

  162.     /** {@inheritDoc} */
  163.     @Override
  164.     public Vector1D multiply(final double a) {
  165.         return new Vector1D(a * x);
  166.     }

  167.     /** {@inheritDoc} */
  168.     @Override
  169.     public double distance(final Vector1D v) {
  170.         return Vectors.norm(x - v.x);
  171.     }

  172.     /** {@inheritDoc} */
  173.     @Override
  174.     public double distanceSq(final Vector1D v) {
  175.         return Vectors.normSq(x - v.x);
  176.     }

  177.     /** {@inheritDoc} */
  178.     @Override
  179.     public double dot(final Vector1D v) {
  180.         return x * v.x;
  181.     }

  182.     /** {@inheritDoc}
  183.      * <p>For the one-dimensional case, this method returns 0 if the vector x values have
  184.      * the same sign and {@code pi} if they are opposite.</p>
  185.      */
  186.     @Override
  187.     public double angle(final Vector1D v) {
  188.         // validate the norm values
  189.         getCheckedNorm();
  190.         v.getCheckedNorm();

  191.         final double sig1 = Math.signum(x);
  192.         final double sig2 = Math.signum(v.x);

  193.         // the angle is 0 if the x value signs are the same and pi if not
  194.         return (sig1 == sig2) ? 0.0 : Math.PI;
  195.     }

  196.     /** Convenience method to apply a function to this vector. This
  197.      * can be used to transform the vector inline with other methods.
  198.      * @param fn the function to apply
  199.      * @return the transformed vector
  200.      */
  201.     public Vector1D transform(final UnaryOperator<Vector1D> fn) {
  202.         return fn.apply(this);
  203.     }

  204.     /** {@inheritDoc} */
  205.     @Override
  206.     public boolean eq(final Vector1D vec, final Precision.DoubleEquivalence precision) {
  207.         return precision.eq(x, vec.x);
  208.     }

  209.     /**
  210.      * Get a hashCode for the vector.
  211.      * <p>All NaN values have the same hash code.</p>
  212.      *
  213.      * @return a hash code value for this object
  214.      */
  215.     @Override
  216.     public int hashCode() {
  217.         if (isNaN()) {
  218.             return 857;
  219.         }
  220.         return 403 * Double.hashCode(x);
  221.     }

  222.     /**
  223.      * Test for the equality of two vectors.
  224.      * <p>
  225.      * If all coordinates of two vectors are exactly the same, and none are
  226.      * <code>Double.NaN</code>, the two vectors are considered to be equal.
  227.      * </p>
  228.      * <p>
  229.      * <code>NaN</code> coordinates are considered to globally affect the vector
  230.      * and be equal to each other - i.e, if either (or all) coordinates of the
  231.      * vector are equal to <code>Double.NaN</code>, the vector is equal to
  232.      * {@link #NaN}.
  233.      * </p>
  234.      *
  235.      * @param other Object to test for equality to this
  236.      * @return true if two vector objects are equal, false if
  237.      *         object is null, not an instance of Vector1D, or
  238.      *         not equal to this Vector1D instance
  239.      *
  240.      */
  241.     @Override
  242.     public boolean equals(final Object other) {
  243.         if (this == other) {
  244.             return true;
  245.         }
  246.         if (other instanceof Vector1D) {
  247.             final Vector1D rhs = (Vector1D) other;
  248.             if (rhs.isNaN()) {
  249.                 return this.isNaN();
  250.             }

  251.             return Double.compare(x, rhs.x) == 0;
  252.         }
  253.         return false;
  254.     }

  255.     /** {@inheritDoc} */
  256.     @Override
  257.     public String toString() {
  258.         return SimpleTupleFormat.getDefault().format(x);
  259.     }

  260.     /** Returns a vector with the given coordinate value.
  261.      * @param x vector coordinate
  262.      * @return vector instance
  263.      */
  264.     public static Vector1D of(final double x) {
  265.         return new Vector1D(x);
  266.     }

  267.     /** Parses the given string and returns a new vector instance. The expected string
  268.      * format is the same as that returned by {@link #toString()}.
  269.      * @param str the string to parse
  270.      * @return vector instance represented by the string
  271.      * @throws IllegalArgumentException if the given string has an invalid format
  272.      */
  273.     public static Vector1D parse(final String str) {
  274.         return SimpleTupleFormat.getDefault().parse(str, Vector1D::new);
  275.     }

  276.     /**
  277.      * Represent unit vectors.
  278.      * This allows optimizations to be performed for certain operations.
  279.      */
  280.     public static final class Unit extends Vector1D {
  281.         /** Unit vector (coordinates: 1). */
  282.         public static final Unit PLUS  = new Unit(1d);
  283.         /** Negation of unit vector (coordinates: -1). */
  284.         public static final Unit MINUS = new Unit(-1d);

  285.         /** Simple constructor. Callers are responsible for ensuring that the given
  286.          * values represent a normalized vector.
  287.          * @param x abscissa (first coordinate value)
  288.          */
  289.         private Unit(final double x) {
  290.             super(x);
  291.         }

  292.         /** {@inheritDoc} */
  293.         @Override
  294.         public double norm() {
  295.             return 1;
  296.         }

  297.         /** {@inheritDoc} */
  298.         @Override
  299.         public double normSq() {
  300.             return 1;
  301.         }

  302.         /** {@inheritDoc} */
  303.         @Override
  304.         public Unit normalize() {
  305.             return this;
  306.         }

  307.         /** {@inheritDoc} */
  308.         @Override
  309.         public Unit normalizeOrNull() {
  310.             return this;
  311.         }

  312.         /** {@inheritDoc} */
  313.         @Override
  314.         public Vector1D withNorm(final double mag) {
  315.             return multiply(mag);
  316.         }

  317.         /** {@inheritDoc} */
  318.         @Override
  319.         public Vector1D negate() {
  320.             return this == PLUS ? MINUS : PLUS;
  321.         }

  322.         /** Create a normalized vector.
  323.          * @param x Vector coordinate.
  324.          * @return a vector whose norm is 1.
  325.          * @throws IllegalArgumentException if the norm of the given value is zero, NaN, or infinite
  326.          */
  327.         public static Unit from(final double x) {
  328.             return tryCreateNormalized(x, true);
  329.         }

  330.         /** Create a normalized vector.
  331.          * @param v Vector.
  332.          * @return a vector whose norm is 1.
  333.          * @throws IllegalArgumentException if the norm of the given value is zero, NaN, or infinite
  334.          */
  335.         public static Unit from(final Vector1D v) {
  336.             return v instanceof Unit ?
  337.                 (Unit) v :
  338.                 from(v.getX());
  339.         }

  340.         /** Attempt to create a normalized vector from the given coordinate values. If {@code throwOnFailure}
  341.          * is true, an exception is thrown if a normalized vector cannot be created. Otherwise, null
  342.          * is returned.
  343.          * @param x x coordinate
  344.          * @param throwOnFailure if true, an exception will be thrown if a normalized vector cannot be created
  345.          * @return normalized vector or null if one cannot be created and {@code throwOnFailure}
  346.          *      is false
  347.          * @throws IllegalArgumentException if the computed norm is zero, NaN, or infinite
  348.          */
  349.         private static Unit tryCreateNormalized(final double x, final boolean throwOnFailure) {
  350.             final double norm = Vectors.norm(x);

  351.             if (Vectors.isRealNonZero(norm)) {
  352.                 return x > 0 ? PLUS : MINUS;
  353.             } else if (throwOnFailure) {
  354.                 throw Vectors.illegalNorm(norm);
  355.             }
  356.             return null;
  357.         }
  358.     }

  359.     /** Class used to create high-accuracy sums of vectors. Each vector component is
  360.      * summed using an instance of {@link org.apache.commons.numbers.core.Sum}.
  361.     *
  362.     * <p>This class is mutable and not thread-safe.
  363.     * @see org.apache.commons.numbers.core.Sum
  364.     */
  365.     public static final class Sum extends EuclideanVectorSum<Vector1D> {

  366.         /** X component sum. */
  367.         private final org.apache.commons.numbers.core.Sum xsum;

  368.         /** Construct a new instance with the given initial value.
  369.          * @param initial initial value
  370.          */
  371.         Sum(final Vector1D initial) {
  372.             this.xsum = org.apache.commons.numbers.core.Sum.of(initial.x);
  373.         }

  374.         /** {@inheritDoc} */
  375.         @Override
  376.         public Sum add(final Vector1D vec) {
  377.             xsum.add(vec.x);
  378.             return this;
  379.         }

  380.         /** {@inheritDoc} */
  381.         @Override
  382.         public Sum addScaled(final double scale, final Vector1D vec) {
  383.             xsum.addProduct(scale, vec.x);
  384.             return this;
  385.         }

  386.         /** {@inheritDoc} */
  387.         @Override
  388.         public Vector1D get() {
  389.             return Vector1D.of(xsum.getAsDouble());
  390.         }

  391.         /** Create a new instance with an initial value set to the {@link Vector1D#ZERO zero vector}.
  392.          * @return new instance set to zero
  393.          */
  394.         public static Sum create() {
  395.             return new Sum(Vector1D.ZERO);
  396.         }

  397.         /** Construct a new instance with an initial value set to the argument.
  398.          * @param initial initial sum value
  399.          * @return new instance
  400.          */
  401.         public static Sum of(final Vector1D initial) {
  402.             return new Sum(initial);
  403.         }

  404.         /** Construct a new instance from multiple values.
  405.          * @param first first vector
  406.          * @param more additional vectors
  407.          * @return new instance
  408.          */
  409.         public static Sum of(final Vector1D first, final Vector1D... more) {
  410.             final Sum s = new Sum(first);
  411.             for (final Vector1D v : more) {
  412.                 s.add(v);
  413.             }
  414.             return s;
  415.         }
  416.     }
  417. }