001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.geometry.euclidean;
018
019import org.apache.commons.geometry.core.Point;
020import org.apache.commons.geometry.core.Vector;
021import org.apache.commons.geometry.euclidean.internal.Vectors;
022import org.apache.commons.numbers.core.Precision;
023
024/** Abstract base class for Euclidean vectors <em>and</em> points. See
025 * {@link org.apache.commons.geometry.euclidean here} for a discussion
026 * of the combination of point and vector functionality into a single
027 * class hierarchy.
028 *
029 * @param <V> Vector implementation type
030 */
031public abstract class EuclideanVector<V extends EuclideanVector<V>>
032    implements Vector<V>, Point<V> {
033
034    /** Return the vector representing the displacement from this vector
035     * to the given vector. This is exactly equivalent to {@code v.subtract(thisVector)}
036     * but with a method name that is much easier to visualize.
037     * @param v the vector that the returned vector will be directed toward
038     * @return vector representing the displacement <em>from</em> this vector <em>to</em> the given vector
039     */
040    public abstract V vectorTo(V v);
041
042    /** Return the unit vector representing the direction of displacement from this
043     * vector to the given vector. This is exactly equivalent to {@code v.subtract(thisVector).normalize()}
044     * but without the intermediate vector instance.
045     * @param v the vector that the returned vector will be directed toward
046     * @return unit vector representing the direction of displacement <em>from</em> this vector
047     *      <em>to</em> the given vector
048     * @throws IllegalArgumentException if the norm of the vector pointing
049     *      from this instance to {@code v} is zero, NaN, or infinite
050     */
051    public abstract V directionTo(V v);
052
053    /** Get a vector constructed by linearly interpolating between this vector and the given vector.
054     * The vector coordinates are generated by the equation {@code V = (1 - t)*A + t*B}, where {@code A}
055     * is the current vector and {@code B} is the given vector. This means that if {@code t = 0}, a
056     * vector equal to the current vector will be returned. If {@code t = 1}, a vector equal to the
057     * argument will be returned. The {@code t} parameter is not constrained to the range {@code [0, 1]},
058     * meaning that linear extrapolation can also be performed with this method.
059     * @param v other vector
060     * @param t interpolation parameter
061     * @return interpolated or extrapolated vector
062     */
063    public abstract V lerp(V v, double t);
064
065    /** Return true if the current instance and given vector are considered equal as evaluated by the
066     * given precision context.
067     *
068     * <p>Equality is determined by comparing each pair of components in turn from the two
069     * vectors. If all components evaluate as equal, then the vectors are considered equal. If any are
070     * not equal, then the vectors are not considered equal. Note that this approach means that the
071     * calculated distance between two "equal" vectors may be as much as <code>&radic;(n * eps<sup>2</sup>)</code>,
072     * where {@code n} is the number of components in the vector and {@code eps} is the maximum epsilon
073     * value allowed by the precision context.
074     * @param v vector to check for equality
075     * @param precision precision context used to determine floating point equality
076     * @return true if the current instance is considered equal to the given vector when using
077     *      the given precision context; otherwise false
078     */
079    public abstract boolean eq(V v, Precision.DoubleEquivalence precision);
080
081    /** Return true if the current instance is considered equal to the zero vector as evaluated by the
082     * given precision context. This is a convenience method equivalent to
083     * {@code vec.equals(vec.getZero(), precision)}.
084     *
085     * @param precision precision context used to determine floating point equality
086     * @return true if the current instance is considered equal to the zero vector when using
087     *      the given precision context; otherwise false
088     * @see #eq(EuclideanVector, Precision.DoubleEquivalence)
089     */
090    public boolean isZero(final Precision.DoubleEquivalence precision) {
091        return eq(getZero(), precision);
092    }
093
094    /** Return the vector norm value, throwing an {@link IllegalArgumentException} if the value is not real
095     * (ie, NaN or infinite) or zero.
096     * @return the vector norm value, guaranteed to be real and non-zero
097     * @throws IllegalArgumentException if the vector norm is zero, NaN, or infinite
098     */
099    protected double getCheckedNorm() {
100        return Vectors.checkedNorm(this);
101    }
102}