FieldVector2D.java

  1. /*
  2.  * Licensed to the Hipparchus project 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 Hipparchus project 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.  *      https://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.hipparchus.geometry.euclidean.twod;

  18. import java.text.NumberFormat;

  19. import org.hipparchus.Field;
  20. import org.hipparchus.CalculusFieldElement;
  21. import org.hipparchus.exception.LocalizedCoreFormats;
  22. import org.hipparchus.exception.MathIllegalArgumentException;
  23. import org.hipparchus.exception.MathRuntimeException;
  24. import org.hipparchus.geometry.LocalizedGeometryFormats;
  25. import org.hipparchus.util.FastMath;
  26. import org.hipparchus.util.MathArrays;

  27. /**
  28.  * This class is a re-implementation of {@link Vector2D} using {@link CalculusFieldElement}.
  29.  * <p>Instance of this class are guaranteed to be immutable.</p>
  30.  * @param <T> the type of the field elements
  31.  * @since 1.6
  32.  */
  33. public class FieldVector2D<T extends CalculusFieldElement<T>> {

  34.     /** Abscissa. */
  35.     private final T x;

  36.     /** Ordinate. */
  37.     private final T y;

  38.     /** Simple constructor.
  39.      * Build a vector from its coordinates
  40.      * @param x abscissa
  41.      * @param y ordinate
  42.      * @see #getX()
  43.      * @see #getY()
  44.      */
  45.     public FieldVector2D(final T x, final T y) {
  46.         this.x = x;
  47.         this.y = y;
  48.     }

  49.     /** Simple constructor.
  50.      * Build a vector from its coordinates
  51.      * @param v coordinates array
  52.      * @exception MathIllegalArgumentException if array does not have 2 elements
  53.      * @see #toArray()
  54.      */
  55.     public FieldVector2D(final T[] v) throws MathIllegalArgumentException {
  56.         if (v.length != 2) {
  57.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  58.                                                    v.length, 2);
  59.         }
  60.         this.x = v[0];
  61.         this.y = v[1];
  62.     }

  63.     /** Multiplicative constructor
  64.      * Build a vector from another one and a scale factor.
  65.      * The vector built will be a * u
  66.      * @param a scale factor
  67.      * @param u base (unscaled) vector
  68.      */
  69.     public FieldVector2D(final T a, final FieldVector2D<T> u) {
  70.         this.x = a.multiply(u.x);
  71.         this.y = a.multiply(u.y);
  72.     }

  73.     /** Multiplicative constructor
  74.      * Build a vector from another one and a scale factor.
  75.      * The vector built will be a * u
  76.      * @param a scale factor
  77.      * @param u base (unscaled) vector
  78.      */
  79.     public FieldVector2D(final T a, final Vector2D u) {
  80.         this.x = a.multiply(u.getX());
  81.         this.y = a.multiply(u.getY());
  82.     }

  83.     /** Multiplicative constructor
  84.      * Build a vector from another one and a scale factor.
  85.      * The vector built will be a * u
  86.      * @param a scale factor
  87.      * @param u base (unscaled) vector
  88.      */
  89.     public FieldVector2D(final double a, final FieldVector2D<T> u) {
  90.         this.x = u.x.multiply(a);
  91.         this.y = u.y.multiply(a);
  92.     }

  93.     /** Linear constructor
  94.      * Build a vector from two other ones and corresponding scale factors.
  95.      * The vector built will be a1 * u1 + a2 * u2
  96.      * @param a1 first scale factor
  97.      * @param u1 first base (unscaled) vector
  98.      * @param a2 second scale factor
  99.      * @param u2 second base (unscaled) vector
  100.      */
  101.     public FieldVector2D(final T a1, final FieldVector2D<T> u1, final T a2, final FieldVector2D<T> u2) {
  102.         final T prototype = a1;
  103.         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX());
  104.         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY());
  105.     }

  106.     /** Linear constructor.
  107.      * Build a vector from two other ones and corresponding scale factors.
  108.      * The vector built will be a1 * u1 + a2 * u2
  109.      * @param a1 first scale factor
  110.      * @param u1 first base (unscaled) vector
  111.      * @param a2 second scale factor
  112.      * @param u2 second base (unscaled) vector
  113.      */
  114.     public FieldVector2D(final T a1, final Vector2D u1,
  115.                          final T a2, final Vector2D u2) {
  116.         final T prototype = a1;
  117.         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2);
  118.         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2);
  119.     }

  120.     /** Linear constructor.
  121.      * Build a vector from two other ones and corresponding scale factors.
  122.      * The vector built will be a1 * u1 + a2 * u2
  123.      * @param a1 first scale factor
  124.      * @param u1 first base (unscaled) vector
  125.      * @param a2 second scale factor
  126.      * @param u2 second base (unscaled) vector
  127.      */
  128.     public FieldVector2D(final double a1, final FieldVector2D<T> u1,
  129.                          final double a2, final FieldVector2D<T> u2) {
  130.         final T prototype = u1.getX();
  131.         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX());
  132.         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY());
  133.     }

  134.     /** Linear constructor.
  135.      * Build a vector from three other ones and corresponding scale factors.
  136.      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
  137.      * @param a1 first scale factor
  138.      * @param u1 first base (unscaled) vector
  139.      * @param a2 second scale factor
  140.      * @param u2 second base (unscaled) vector
  141.      * @param a3 third scale factor
  142.      * @param u3 third base (unscaled) vector
  143.      */
  144.     public FieldVector2D(final T a1, final FieldVector2D<T> u1,
  145.                          final T a2, final FieldVector2D<T> u2,
  146.                          final T a3, final FieldVector2D<T> u3) {
  147.         final T prototype = a1;
  148.         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX());
  149.         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY());
  150.     }

  151.     /** Linear constructor.
  152.      * Build a vector from three other ones and corresponding scale factors.
  153.      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
  154.      * @param a1 first scale factor
  155.      * @param u1 first base (unscaled) vector
  156.      * @param a2 second scale factor
  157.      * @param u2 second base (unscaled) vector
  158.      * @param a3 third scale factor
  159.      * @param u3 third base (unscaled) vector
  160.      */
  161.     public FieldVector2D(final T a1, final Vector2D u1,
  162.                          final T a2, final Vector2D u2,
  163.                          final T a3, final Vector2D u3) {
  164.         final T prototype = a1;
  165.         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2, u3.getX(), a3);
  166.         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2, u3.getY(), a3);
  167.     }

  168.     /** Linear constructor.
  169.      * Build a vector from three other ones and corresponding scale factors.
  170.      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
  171.      * @param a1 first scale factor
  172.      * @param u1 first base (unscaled) vector
  173.      * @param a2 second scale factor
  174.      * @param u2 second base (unscaled) vector
  175.      * @param a3 third scale factor
  176.      * @param u3 third base (unscaled) vector
  177.      */
  178.     public FieldVector2D(final double a1, final FieldVector2D<T> u1,
  179.                          final double a2, final FieldVector2D<T> u2,
  180.                          final double a3, final FieldVector2D<T> u3) {
  181.         final T prototype = u1.getX();
  182.         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX());
  183.         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY());
  184.     }

  185.     /** Linear constructor.
  186.      * Build a vector from four other ones and corresponding scale factors.
  187.      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
  188.      * @param a1 first scale factor
  189.      * @param u1 first base (unscaled) vector
  190.      * @param a2 second scale factor
  191.      * @param u2 second base (unscaled) vector
  192.      * @param a3 third scale factor
  193.      * @param u3 third base (unscaled) vector
  194.      * @param a4 fourth scale factor
  195.      * @param u4 fourth base (unscaled) vector
  196.      */
  197.     public FieldVector2D(final T a1, final FieldVector2D<T> u1,
  198.                          final T a2, final FieldVector2D<T> u2,
  199.                          final T a3, final FieldVector2D<T> u3,
  200.                          final T a4, final FieldVector2D<T> u4) {
  201.         final T prototype = a1;
  202.         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX(), a4, u4.getX());
  203.         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY(), a4, u4.getY());
  204.     }

  205.     /** Linear constructor.
  206.      * Build a vector from four other ones and corresponding scale factors.
  207.      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
  208.      * @param a1 first scale factor
  209.      * @param u1 first base (unscaled) vector
  210.      * @param a2 second scale factor
  211.      * @param u2 second base (unscaled) vector
  212.      * @param a3 third scale factor
  213.      * @param u3 third base (unscaled) vector
  214.      * @param a4 fourth scale factor
  215.      * @param u4 fourth base (unscaled) vector
  216.      */
  217.     public FieldVector2D(final T a1, final Vector2D u1,
  218.                          final T a2, final Vector2D u2,
  219.                          final T a3, final Vector2D u3,
  220.                          final T a4, final Vector2D u4) {
  221.         final T prototype = a1;
  222.         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2, u3.getX(), a3, u4.getX(), a4);
  223.         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2, u3.getY(), a3, u4.getY(), a4);
  224.     }

  225.     /** Linear constructor.
  226.      * Build a vector from four other ones and corresponding scale factors.
  227.      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
  228.      * @param a1 first scale factor
  229.      * @param u1 first base (unscaled) vector
  230.      * @param a2 second scale factor
  231.      * @param u2 second base (unscaled) vector
  232.      * @param a3 third scale factor
  233.      * @param u3 third base (unscaled) vector
  234.      * @param a4 fourth scale factor
  235.      * @param u4 fourth base (unscaled) vector
  236.      */
  237.     public FieldVector2D(final double a1, final FieldVector2D<T> u1,
  238.                          final double a2, final FieldVector2D<T> u2,
  239.                          final double a3, final FieldVector2D<T> u3,
  240.                          final double a4, final FieldVector2D<T> u4) {
  241.         final T prototype = u1.getX();
  242.         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX(), a4, u4.getX());
  243.         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY(), a4, u4.getY());
  244.     }

  245.     /** Build a {@link FieldVector2D} from a {@link Vector2D}.
  246.      * @param field field for the components
  247.      * @param v vector to convert
  248.      */
  249.     public FieldVector2D(final Field<T> field, final Vector2D v) {
  250.         this.x = field.getZero().add(v.getX());
  251.         this.y = field.getZero().add(v.getY());
  252.     }

  253.     /** Get null vector (coordinates: 0, 0).
  254.      * @param field field for the components
  255.      * @return a new vector
  256.      * @param <T> the type of the field elements
  257.      */
  258.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getZero(final Field<T> field) {
  259.         return new FieldVector2D<>(field, Vector2D.ZERO);
  260.     }

  261.     /** Get first canonical vector (coordinates: 1, 0).
  262.      * @param field field for the components
  263.      * @return a new vector
  264.      * @param <T> the type of the field elements
  265.      */
  266.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getPlusI(final Field<T> field) {
  267.         return new FieldVector2D<>(field, Vector2D.PLUS_I);
  268.     }

  269.     /** Get opposite of the first canonical vector (coordinates: -1).
  270.      * @param field field for the components
  271.      * @return a new vector
  272.      * @param <T> the type of the field elements
  273.      */
  274.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getMinusI(final Field<T> field) {
  275.         return new FieldVector2D<>(field, Vector2D.MINUS_I);
  276.     }

  277.     /** Get second canonical vector (coordinates: 0, 1).
  278.      * @param field field for the components
  279.      * @return a new vector
  280.      * @param <T> the type of the field elements
  281.      */
  282.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getPlusJ(final Field<T> field) {
  283.         return new FieldVector2D<>(field, Vector2D.PLUS_J);
  284.     }

  285.     /** Get opposite of the second canonical vector (coordinates: 0, -1).
  286.      * @param field field for the components
  287.      * @return a new vector
  288.      * @param <T> the type of the field elements
  289.      */
  290.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getMinusJ(final Field<T> field) {
  291.         return new FieldVector2D<>(field, Vector2D.MINUS_J);
  292.     }

  293.     /** Get a vector with all coordinates set to NaN.
  294.      * @param field field for the components
  295.      * @return a new vector
  296.      * @param <T> the type of the field elements
  297.      */
  298.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getNaN(final Field<T> field) {
  299.         return new FieldVector2D<>(field, Vector2D.NaN);
  300.     }

  301.     /** Get a vector with all coordinates set to positive infinity.
  302.      * @param field field for the components
  303.      * @return a new vector
  304.      * @param <T> the type of the field elements
  305.      */
  306.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getPositiveInfinity(final Field<T> field) {
  307.         return new FieldVector2D<>(field, Vector2D.POSITIVE_INFINITY);
  308.     }

  309.     /** Get a vector with all coordinates set to negative infinity.
  310.      * @param field field for the components
  311.      * @return a new vector
  312.      * @param <T> the type of the field elements
  313.      */
  314.     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getNegativeInfinity(final Field<T> field) {
  315.         return new FieldVector2D<>(field, Vector2D.NEGATIVE_INFINITY);
  316.     }

  317.     /** Get the abscissa of the vector.
  318.      * @return abscissa of the vector
  319.      * @see #FieldVector2D(CalculusFieldElement, CalculusFieldElement)
  320.      */
  321.     public T getX() {
  322.         return x;
  323.     }

  324.     /** Get the ordinate of the vector.
  325.      * @return ordinate of the vector
  326.     * @see #FieldVector2D(CalculusFieldElement, CalculusFieldElement)
  327.      */
  328.     public T getY() {
  329.         return y;
  330.     }

  331.     /** Get the vector coordinates as a dimension 2 array.
  332.      * @return vector coordinates
  333.      * @see #FieldVector2D(CalculusFieldElement[])
  334.      */
  335.     public T[] toArray() {
  336.         final T[] array = MathArrays.buildArray(x.getField(), 2);
  337.         array[0] = x;
  338.         array[1] = y;
  339.         return array;
  340.     }

  341.     /** Convert to a constant vector without extra field parts.
  342.      * @return a constant vector
  343.      */
  344.     public Vector2D toVector2D() {
  345.         return new Vector2D(x.getReal(), y.getReal());
  346.     }

  347.     /** Get the L<sub>1</sub> norm for the vector.
  348.      * @return L<sub>1</sub> norm for the vector
  349.      */
  350.     public T getNorm1() {
  351.         return x.abs().add(y.abs());
  352.     }

  353.     /** Get the L<sub>2</sub> norm for the vector.
  354.      * @return Euclidean norm for the vector
  355.      */
  356.     public T getNorm() {
  357.         // there are no cancellation problems here, so we use the straightforward formula
  358.         return x.square().add(y.square()).sqrt();
  359.     }

  360.     /** Get the square of the norm for the vector.
  361.      * @return square of the Euclidean norm for the vector
  362.      */
  363.     public T getNormSq() {
  364.         // there are no cancellation problems here, so we use the straightforward formula
  365.         return x.square().add(y.square());
  366.     }

  367.     /** Get the L<sub>&infin;</sub> norm for the vector.
  368.      * @return L<sub>&infin;</sub> norm for the vector
  369.      */
  370.     public T getNormInf() {
  371.         return FastMath.max(FastMath.abs(x), FastMath.abs(y));
  372.     }

  373.     /** Add a vector to the instance.
  374.      * @param v vector to add
  375.      * @return a new vector
  376.      */
  377.     public FieldVector2D<T> add(final FieldVector2D<T> v) {
  378.         return new FieldVector2D<>(x.add(v.x), y.add(v.y));
  379.     }

  380.     /** Add a vector to the instance.
  381.      * @param v vector to add
  382.      * @return a new vector
  383.      */
  384.     public FieldVector2D<T> add(final Vector2D v) {
  385.         return new FieldVector2D<>(x.add(v.getX()), y.add(v.getY()));
  386.     }

  387.     /** Add a scaled vector to the instance.
  388.      * @param factor scale factor to apply to v before adding it
  389.      * @param v vector to add
  390.      * @return a new vector
  391.      */
  392.     public FieldVector2D<T> add(final T factor, final FieldVector2D<T> v) {
  393.         return new FieldVector2D<>(x.getField().getOne(), this, factor, v);
  394.     }

  395.     /** Add a scaled vector to the instance.
  396.      * @param factor scale factor to apply to v before adding it
  397.      * @param v vector to add
  398.      * @return a new vector
  399.      */
  400.     public FieldVector2D<T> add(final T factor, final Vector2D v) {
  401.         return new FieldVector2D<>(x.add(factor.multiply(v.getX())),
  402.                                    y.add(factor.multiply(v.getY())));
  403.     }

  404.     /** Add a scaled vector to the instance.
  405.      * @param factor scale factor to apply to v before adding it
  406.      * @param v vector to add
  407.      * @return a new vector
  408.      */
  409.     public FieldVector2D<T> add(final double factor, final FieldVector2D<T> v) {
  410.         return new FieldVector2D<>(1.0, this, factor, v);
  411.     }

  412.     /** Add a scaled vector to the instance.
  413.      * @param factor scale factor to apply to v before adding it
  414.      * @param v vector to add
  415.      * @return a new vector
  416.      */
  417.     public FieldVector2D<T> add(final double factor, final Vector2D v) {
  418.         return new FieldVector2D<>(x.add(factor * v.getX()),
  419.                                    y.add(factor * v.getY()));
  420.     }

  421.     /** Subtract a vector from the instance.
  422.      * @param v vector to subtract
  423.      * @return a new vector
  424.      */
  425.     public FieldVector2D<T> subtract(final FieldVector2D<T> v) {
  426.         return new FieldVector2D<>(x.subtract(v.x), y.subtract(v.y));
  427.     }

  428.     /** Subtract a vector from the instance.
  429.      * @param v vector to subtract
  430.      * @return a new vector
  431.      */
  432.     public FieldVector2D<T> subtract(final Vector2D v) {
  433.         return new FieldVector2D<>(x.subtract(v.getX()), y.subtract(v.getY()));
  434.     }

  435.     /** Subtract a scaled vector from the instance.
  436.      * @param factor scale factor to apply to v before subtracting it
  437.      * @param v vector to subtract
  438.      * @return a new vector
  439.      */
  440.     public FieldVector2D<T> subtract(final T factor, final FieldVector2D<T> v) {
  441.         return new FieldVector2D<>(x.getField().getOne(), this, factor.negate(), v);
  442.     }

  443.     /** Subtract a scaled vector from the instance.
  444.      * @param factor scale factor to apply to v before subtracting it
  445.      * @param v vector to subtract
  446.      * @return a new vector
  447.      */
  448.     public FieldVector2D<T> subtract(final T factor, final Vector2D v) {
  449.         return new FieldVector2D<>(x.subtract(factor.multiply(v.getX())),
  450.                                    y.subtract(factor.multiply(v.getY())));
  451.     }

  452.     /** Subtract a scaled vector from the instance.
  453.      * @param factor scale factor to apply to v before subtracting it
  454.      * @param v vector to subtract
  455.      * @return a new vector
  456.      */
  457.     public FieldVector2D<T> subtract(final double factor, final FieldVector2D<T> v) {
  458.         return new FieldVector2D<>(1.0, this, -factor, v);
  459.     }

  460.     /** Subtract a scaled vector from the instance.
  461.      * @param factor scale factor to apply to v before subtracting it
  462.      * @param v vector to subtract
  463.      * @return a new vector
  464.      */
  465.     public FieldVector2D<T> subtract(final double factor, final Vector2D v) {
  466.         return new FieldVector2D<>(x.subtract(factor * v.getX()),
  467.                                    y.subtract(factor * v.getY()));
  468.     }

  469.     /** Get a normalized vector aligned with the instance.
  470.      * @return a new normalized vector
  471.      * @exception MathRuntimeException if the norm is zero
  472.      */
  473.     public FieldVector2D<T> normalize() throws MathRuntimeException {
  474.         final T s = getNorm();
  475.         if (s.getReal() == 0) {
  476.             throw new MathRuntimeException(LocalizedGeometryFormats.CANNOT_NORMALIZE_A_ZERO_NORM_VECTOR);
  477.         }
  478.         return scalarMultiply(s.reciprocal());
  479.     }

  480.     /** Compute the angular separation between two vectors.
  481.      * <p>This method computes the angular separation between two
  482.      * vectors using the dot product for well separated vectors and the
  483.      * cross product for almost aligned vectors. This allows to have a
  484.      * good accuracy in all cases, even for vectors very close to each
  485.      * other.</p>
  486.      * @param v1 first vector
  487.      * @param v2 second vector
  488.      * @param <T> the type of the field elements
  489.      * @return angular separation between v1 and v2
  490.      * @exception MathRuntimeException if either vector has a null norm
  491.      */
  492.     public static <T extends CalculusFieldElement<T>> T angle(final FieldVector2D<T> v1, final FieldVector2D<T> v2)
  493.         throws MathRuntimeException {

  494.         final T normProduct = v1.getNorm().multiply(v2.getNorm());
  495.         if (normProduct.getReal() == 0) {
  496.             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_NORM);
  497.         }

  498.         final T dot = v1.dotProduct(v2);
  499.         final double threshold = normProduct.getReal() * 0.9999;
  500.         if (FastMath.abs(dot.getReal()) > threshold) {
  501.             // the vectors are almost aligned, compute using the sine
  502.             final T n = FastMath.abs(dot.linearCombination(v1.x, v2.y, v1.y.negate(), v2.x));
  503.             if (dot.getReal() >= 0) {
  504.                 return FastMath.asin(n.divide(normProduct));
  505.             }
  506.             return FastMath.asin(n.divide(normProduct)).negate().add(dot.getPi());
  507.         }

  508.         // the vectors are sufficiently separated to use the cosine
  509.         return FastMath.acos(dot.divide(normProduct));

  510.     }

  511.     /** Compute the angular separation between two vectors.
  512.      * <p>This method computes the angular separation between two
  513.      * vectors using the dot product for well separated vectors and the
  514.      * cross product for almost aligned vectors. This allows to have a
  515.      * good accuracy in all cases, even for vectors very close to each
  516.      * other.</p>
  517.      * @param v1 first vector
  518.      * @param v2 second vector
  519.      * @param <T> the type of the field elements
  520.      * @return angular separation between v1 and v2
  521.      * @exception MathRuntimeException if either vector has a null norm
  522.      */
  523.     public static <T extends CalculusFieldElement<T>> T angle(final FieldVector2D<T> v1, final Vector2D v2)
  524.         throws MathRuntimeException {

  525.         final T normProduct = v1.getNorm().multiply(v2.getNorm());
  526.         if (normProduct.getReal() == 0) {
  527.             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_NORM);
  528.         }

  529.         final T dot = v1.dotProduct(v2);
  530.         final double threshold = normProduct.getReal() * 0.9999;
  531.         if (FastMath.abs(dot.getReal()) > threshold) {
  532.             // the vectors are almost aligned, compute using the sine
  533.             final T n = FastMath.abs(dot.linearCombination(v2.getY(), v1.x, v2.getX(), v1.y.negate()));
  534.             if (dot.getReal() >= 0) {
  535.                 return FastMath.asin(n.divide(normProduct));
  536.             }
  537.             return FastMath.asin(n.divide(normProduct)).negate().add(dot.getPi());
  538.         }

  539.         // the vectors are sufficiently separated to use the cosine
  540.         return FastMath.acos(dot.divide(normProduct));

  541.     }

  542.     /** Compute the angular separation between two vectors.
  543.      * <p>This method computes the angular separation between two
  544.      * vectors using the dot product for well separated vectors and the
  545.      * cross product for almost aligned vectors. This allows to have a
  546.      * good accuracy in all cases, even for vectors very close to each
  547.      * other.</p>
  548.      * @param v1 first vector
  549.      * @param v2 second vector
  550.      * @param <T> the type of the field elements
  551.      * @return angular separation between v1 and v2
  552.      * @exception MathRuntimeException if either vector has a null norm
  553.      */
  554.     public static <T extends CalculusFieldElement<T>> T angle(final Vector2D v1, final FieldVector2D<T> v2)
  555.         throws MathRuntimeException {
  556.         return angle(v2, v1);
  557.     }

  558.     /** Get the opposite of the instance.
  559.      * @return a new vector which is opposite to the instance
  560.      */
  561.     public FieldVector2D<T> negate() {
  562.         return new FieldVector2D<>(x.negate(), y.negate());
  563.     }

  564.     /** Multiply the instance by a scalar.
  565.      * @param a scalar
  566.      * @return a new vector
  567.      */
  568.     public FieldVector2D<T> scalarMultiply(final T a) {
  569.         return new FieldVector2D<>(x.multiply(a), y.multiply(a));
  570.     }

  571.     /** Multiply the instance by a scalar.
  572.      * @param a scalar
  573.      * @return a new vector
  574.      */
  575.     public FieldVector2D<T> scalarMultiply(final double a) {
  576.         return new FieldVector2D<>(x.multiply(a), y.multiply(a));
  577.     }

  578.     /**
  579.      * Returns true if any coordinate of this vector is NaN; false otherwise
  580.      * @return  true if any coordinate of this vector is NaN; false otherwise
  581.      */
  582.     public boolean isNaN() {
  583.         return Double.isNaN(x.getReal()) || Double.isNaN(y.getReal());
  584.     }

  585.     /**
  586.      * Returns true if any coordinate of this vector is infinite and none are NaN;
  587.      * false otherwise
  588.      * @return  true if any coordinate of this vector is infinite and none are NaN;
  589.      * false otherwise
  590.      */
  591.     public boolean isInfinite() {
  592.         return !isNaN() && (Double.isInfinite(x.getReal()) || Double.isInfinite(y.getReal()));
  593.     }

  594.     /**
  595.      * Test for the equality of two 2D vectors.
  596.      * <p>
  597.      * If all coordinates of two 2D vectors are exactly the same, and none of their
  598.      * {@link CalculusFieldElement#getReal() real part} are <code>NaN</code>, the
  599.      * two 2D vectors are considered to be equal.
  600.      * </p>
  601.      * <p>
  602.      * <code>NaN</code> coordinates are considered to affect globally the vector
  603.      * and be equals to each other - i.e, if either (or all) real part of the
  604.      * coordinates of the 3D vector are <code>NaN</code>, the 2D vector is <code>NaN</code>.
  605.      * </p>
  606.      *
  607.      * @param other Object to test for equality to this
  608.      * @return true if two 2D vector objects are equal, false if
  609.      *         object is null, not an instance of FieldVector2D, or
  610.      *         not equal to this FieldVector2D instance
  611.      *
  612.      */
  613.     @Override
  614.     public boolean equals(Object other) {

  615.         if (this == other) {
  616.             return true;
  617.         }

  618.         if (other instanceof FieldVector2D) {
  619.             @SuppressWarnings("unchecked")
  620.             final FieldVector2D<T> rhs = (FieldVector2D<T>) other;
  621.             if (rhs.isNaN()) {
  622.                 return this.isNaN();
  623.             }

  624.             return x.equals(rhs.x) && y.equals(rhs.y);

  625.         }
  626.         return false;
  627.     }

  628.     /**
  629.      * Get a hashCode for the 3D vector.
  630.      * <p>
  631.      * All NaN values have the same hash code.</p>
  632.      *
  633.      * @return a hash code value for this object
  634.      */
  635.     @Override
  636.     public int hashCode() {
  637.         if (isNaN()) {
  638.             return 542;
  639.         }
  640.         return 122 * (76 * x.hashCode() +  y.hashCode());
  641.     }

  642.     /** Compute the distance between the instance and another vector according to the L<sub>1</sub> norm.
  643.      * <p>Calling this method is equivalent to calling:
  644.      * <code>q.subtract(p).getNorm1()</code> except that no intermediate
  645.      * vector is built</p>
  646.      * @param v second vector
  647.      * @return the distance between the instance and p according to the L<sub>1</sub> norm
  648.      */
  649.     public T distance1(final FieldVector2D<T> v) {
  650.         final T dx = v.x.subtract(x).abs();
  651.         final T dy = v.y.subtract(y).abs();
  652.         return dx.add(dy);
  653.     }

  654.     /** Compute the distance between the instance and another vector according to the L<sub>1</sub> norm.
  655.      * <p>Calling this method is equivalent to calling:
  656.      * <code>q.subtract(p).getNorm1()</code> except that no intermediate
  657.      * vector is built</p>
  658.      * @param v second vector
  659.      * @return the distance between the instance and p according to the L<sub>1</sub> norm
  660.      */
  661.     public T distance1(final Vector2D v) {
  662.         final T dx = x.subtract(v.getX()).abs();
  663.         final T dy = y.subtract(v.getY()).abs();
  664.         return dx.add(dy);
  665.     }

  666.     /** Compute the distance between the instance and another vector according to the L<sub>2</sub> norm.
  667.      * <p>Calling this method is equivalent to calling:
  668.      * <code>q.subtract(p).getNorm()</code> except that no intermediate
  669.      * vector is built</p>
  670.      * @param v second vector
  671.      * @return the distance between the instance and p according to the L<sub>2</sub> norm
  672.      */
  673.     public T distance(final FieldVector2D<T> v) {
  674.         final T dx = v.x.subtract(x);
  675.         final T dy = v.y.subtract(y);
  676.         return dx.square().add(dy.square()).sqrt();
  677.     }

  678.     /** Compute the distance between the instance and another vector according to the L<sub>2</sub> norm.
  679.      * <p>Calling this method is equivalent to calling:
  680.      * <code>q.subtract(p).getNorm()</code> except that no intermediate
  681.      * vector is built</p>
  682.      * @param v second vector
  683.      * @return the distance between the instance and p according to the L<sub>2</sub> norm
  684.      */
  685.     public T distance(final Vector2D v) {
  686.         final T dx = x.subtract(v.getX());
  687.         final T dy = y.subtract(v.getY());
  688.         return dx.square().add(dy.square()).sqrt();
  689.     }

  690.     /** Compute the distance between the instance and another vector according to the L<sub>&infin;</sub> norm.
  691.      * <p>Calling this method is equivalent to calling:
  692.      * <code>q.subtract(p).getNormInf()</code> except that no intermediate
  693.      * vector is built</p>
  694.      * @param v second vector
  695.      * @return the distance between the instance and p according to the L<sub>&infin;</sub> norm
  696.      */
  697.     public T distanceInf(final FieldVector2D<T> v) {
  698.         final T dx = FastMath.abs(x.subtract(v.x));
  699.         final T dy = FastMath.abs(y.subtract(v.y));
  700.         return FastMath.max(dx, dy);
  701.     }

  702.     /** Compute the distance between the instance and another vector according to the L<sub>&infin;</sub> norm.
  703.      * <p>Calling this method is equivalent to calling:
  704.      * <code>q.subtract(p).getNormInf()</code> except that no intermediate
  705.      * vector is built</p>
  706.      * @param v second vector
  707.      * @return the distance between the instance and p according to the L<sub>&infin;</sub> norm
  708.      */
  709.     public T distanceInf(final Vector2D v) {
  710.         final T dx = FastMath.abs(x.subtract(v.getX()));
  711.         final T dy = FastMath.abs(y.subtract(v.getY()));
  712.         return FastMath.max(dx, dy);
  713.     }

  714.     /** Compute the square of the distance between the instance and another vector.
  715.      * <p>Calling this method is equivalent to calling:
  716.      * <code>q.subtract(p).getNormSq()</code> except that no intermediate
  717.      * vector is built</p>
  718.      * @param v second vector
  719.      * @return the square of the distance between the instance and p
  720.      */
  721.     public T distanceSq(final FieldVector2D<T> v) {
  722.         final T dx = v.x.subtract(x);
  723.         final T dy = v.y.subtract(y);
  724.         return dx.square().add(dy.square());
  725.     }

  726.     /** Compute the square of the distance between the instance and another vector.
  727.      * <p>Calling this method is equivalent to calling:
  728.      * <code>q.subtract(p).getNormSq()</code> except that no intermediate
  729.      * vector is built</p>
  730.      * @param v second vector
  731.      * @return the square of the distance between the instance and p
  732.      */
  733.     public T distanceSq(final Vector2D v) {
  734.         final T dx = x.subtract(v.getX());
  735.         final T dy = y.subtract(v.getY());
  736.         return dx.square().add(dy.square());
  737.     }


  738.     /** Compute the dot-product of the instance and another vector.
  739.      * <p>
  740.      * The implementation uses specific multiplication and addition
  741.      * algorithms to preserve accuracy and reduce cancellation effects.
  742.      * It should be very accurate even for nearly orthogonal vectors.
  743.      * </p>
  744.      * @see MathArrays#linearCombination(double, double, double, double, double, double)
  745.      * @param v second vector
  746.      * @return the dot product this.v
  747.      */
  748.     public T dotProduct(final FieldVector2D<T> v) {
  749.         return x.linearCombination(x, v.getX(), y, v.getY());
  750.     }

  751.     /** Compute the dot-product of the instance and another vector.
  752.      * <p>
  753.      * The implementation uses specific multiplication and addition
  754.      * algorithms to preserve accuracy and reduce cancellation effects.
  755.      * It should be very accurate even for nearly orthogonal vectors.
  756.      * </p>
  757.      * @see MathArrays#linearCombination(double, double, double, double, double, double)
  758.      * @param v second vector
  759.      * @return the dot product this.v
  760.      */
  761.     public T dotProduct(final Vector2D v) {
  762.         return x.linearCombination(v.getX(), x, v.getY(), y);
  763.     }

  764.     /**
  765.      * Compute the cross-product of the instance and the given points.
  766.      * <p>
  767.      * The cross product can be used to determine the location of a point
  768.      * with regard to the line formed by (p1, p2) and is calculated as:
  769.      * \[
  770.      *    P = (x_2 - x_1)(y_3 - y_1) - (y_2 - y_1)(x_3 - x_1)
  771.      * \]
  772.      * with \(p3 = (x_3, y_3)\) being this instance.
  773.      * <p>
  774.      * If the result is 0, the points are collinear, i.e. lie on a single straight line L;
  775.      * if it is positive, this point lies to the left, otherwise to the right of the line
  776.      * formed by (p1, p2).
  777.      *
  778.      * @param p1 first point of the line
  779.      * @param p2 second point of the line
  780.      * @return the cross-product
  781.      *
  782.      * @see <a href="http://en.wikipedia.org/wiki/Cross_product">Cross product (Wikipedia)</a>
  783.      */
  784.     public T crossProduct(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
  785.         final T x1  = p2.getX().subtract(p1.getX());
  786.         final T y1  = getY().subtract(p1.getY());
  787.         final T mx2 = p1.getX().subtract(getX());
  788.         final T y2  = p2.getY().subtract(p1.getY());
  789.         return x1.linearCombination(x1, y1, mx2, y2);
  790.     }

  791.     /**
  792.      * Compute the cross-product of the instance and the given points.
  793.      * <p>
  794.      * The cross product can be used to determine the location of a point
  795.      * with regard to the line formed by (p1, p2) and is calculated as:
  796.      * \[
  797.      *    P = (x_2 - x_1)(y_3 - y_1) - (y_2 - y_1)(x_3 - x_1)
  798.      * \]
  799.      * with \(p3 = (x_3, y_3)\) being this instance.
  800.      * <p>
  801.      * If the result is 0, the points are collinear, i.e. lie on a single straight line L;
  802.      * if it is positive, this point lies to the left, otherwise to the right of the line
  803.      * formed by (p1, p2).
  804.      *
  805.      * @param p1 first point of the line
  806.      * @param p2 second point of the line
  807.      * @return the cross-product
  808.      *
  809.      * @see <a href="http://en.wikipedia.org/wiki/Cross_product">Cross product (Wikipedia)</a>
  810.      */
  811.     public T crossProduct(final Vector2D p1, final Vector2D p2) {
  812.         final double x1  = p2.getX() - p1.getX();
  813.         final T      y1  = getY().subtract(p1.getY());
  814.         final T      x2 = getX().subtract(p1.getX());
  815.         final double y2  = p2.getY() - p1.getY();
  816.         return y1.linearCombination(x1, y1, -y2, x2);
  817.     }

  818.     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
  819.      * <p>Calling this method is equivalent to calling:
  820.      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
  821.      * vector is built</p>
  822.      * @param p1 first vector
  823.      * @param p2 second vector
  824.      * @param <T> the type of the field elements
  825.      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
  826.      */
  827.     public static <T extends CalculusFieldElement<T>> T  distance1(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
  828.         return p1.distance1(p2);
  829.     }

  830.     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
  831.      * <p>Calling this method is equivalent to calling:
  832.      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
  833.      * vector is built</p>
  834.      * @param p1 first vector
  835.      * @param p2 second vector
  836.      * @param <T> the type of the field elements
  837.      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
  838.      */
  839.     public static <T extends CalculusFieldElement<T>> T  distance1(final FieldVector2D<T> p1, final Vector2D p2) {
  840.         return p1.distance1(p2);
  841.     }

  842.     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
  843.      * <p>Calling this method is equivalent to calling:
  844.      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
  845.      * vector is built</p>
  846.      * @param p1 first vector
  847.      * @param p2 second vector
  848.      * @param <T> the type of the field elements
  849.      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
  850.      */
  851.     public static <T extends CalculusFieldElement<T>> T  distance1(final Vector2D p1, final FieldVector2D<T> p2) {
  852.         return p2.distance1(p1);
  853.     }

  854.     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
  855.      * <p>Calling this method is equivalent to calling:
  856.      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
  857.      * vector is built</p>
  858.      * @param p1 first vector
  859.      * @param p2 second vector
  860.      * @param <T> the type of the field elements
  861.      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
  862.      */
  863.     public static <T extends CalculusFieldElement<T>> T distance(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
  864.         return p1.distance(p2);
  865.     }

  866.     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
  867.      * <p>Calling this method is equivalent to calling:
  868.      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
  869.      * vector is built</p>
  870.      * @param p1 first vector
  871.      * @param p2 second vector
  872.      * @param <T> the type of the field elements
  873.      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
  874.      */
  875.     public static <T extends CalculusFieldElement<T>> T distance(final FieldVector2D<T> p1, final Vector2D p2) {
  876.         return p1.distance(p2);
  877.     }

  878.     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
  879.      * <p>Calling this method is equivalent to calling:
  880.      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
  881.      * vector is built</p>
  882.      * @param p1 first vector
  883.      * @param p2 second vector
  884.      * @param <T> the type of the field elements
  885.      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
  886.      */
  887.     public static <T extends CalculusFieldElement<T>> T distance( final Vector2D p1, final FieldVector2D<T> p2) {
  888.         return p2.distance(p1);
  889.     }

  890.     /** Compute the distance between two vectors according to the L<sub>&infin;</sub> norm.
  891.      * <p>Calling this method is equivalent to calling:
  892.      * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
  893.      * vector is built</p>
  894.      * @param p1 first vector
  895.      * @param p2 second vector
  896.      * @param <T> the type of the field elements
  897.      * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
  898.      */
  899.     public static <T extends CalculusFieldElement<T>> T distanceInf(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
  900.         return p1.distanceInf(p2);
  901.     }

  902.     /** Compute the distance between two vectors according to the L<sub>&infin;</sub> norm.
  903.      * <p>Calling this method is equivalent to calling:
  904.      * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
  905.      * vector is built</p>
  906.      * @param p1 first vector
  907.      * @param p2 second vector
  908.      * @param <T> the type of the field elements
  909.      * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
  910.      */
  911.     public static <T extends CalculusFieldElement<T>> T distanceInf(final FieldVector2D<T> p1, final Vector2D p2) {
  912.         return p1.distanceInf(p2);
  913.     }

  914.     /** Compute the distance between two vectors according to the L<sub>&infin;</sub> norm.
  915.      * <p>Calling this method is equivalent to calling:
  916.      * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
  917.      * vector is built</p>
  918.      * @param p1 first vector
  919.      * @param p2 second vector
  920.      * @param <T> the type of the field elements
  921.      * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
  922.      */
  923.     public static <T extends CalculusFieldElement<T>> T distanceInf(final Vector2D p1, final FieldVector2D<T> p2) {
  924.         return p2.distanceInf(p1);
  925.     }

  926.     /** Compute the square of the distance between two vectors.
  927.      * <p>Calling this method is equivalent to calling:
  928.      * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
  929.      * vector is built</p>
  930.      * @param p1 first vector
  931.      * @param p2 second vector
  932.      * @param <T> the type of the field elements
  933.      * @return the square of the distance between p1 and p2
  934.      */
  935.     public static <T extends CalculusFieldElement<T>> T distanceSq(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
  936.         return p1.distanceSq(p2);
  937.     }

  938.     /** Compute the square of the distance between two vectors.
  939.      * <p>Calling this method is equivalent to calling:
  940.      * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
  941.      * vector is built</p>
  942.      * @param p1 first vector
  943.      * @param p2 second vector
  944.      * @param <T> the type of the field elements
  945.      * @return the square of the distance between p1 and p2
  946.      */
  947.     public static <T extends CalculusFieldElement<T>> T distanceSq(final FieldVector2D<T> p1, final Vector2D p2) {
  948.         return p1.distanceSq(p2);
  949.     }

  950.     /** Compute the square of the distance between two vectors.
  951.      * <p>Calling this method is equivalent to calling:
  952.      * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
  953.      * vector is built</p>
  954.      * @param p1 first vector
  955.      * @param p2 second vector
  956.      * @param <T> the type of the field elements
  957.      * @return the square of the distance between p1 and p2
  958.      */
  959.     public static <T extends CalculusFieldElement<T>> T distanceSq(final Vector2D p1, final FieldVector2D<T> p2) {
  960.         return p2.distanceSq(p1);
  961.     }

  962.     /** Compute the orientation of a triplet of points.
  963.      * @param p first vector of the triplet
  964.      * @param q second vector of the triplet
  965.      * @param r third vector of the triplet
  966.      * @param <T> the type of the field elements
  967.      * @return a positive value if (p, q, r) defines a counterclockwise oriented
  968.      * triangle, a negative value if (p, q, r) defines a clockwise oriented
  969.      * triangle, and 0 if (p, q, r) are collinear or some points are equal
  970.      * @since 1.2
  971.      */
  972.     public static <T extends CalculusFieldElement<T>> T orientation(final FieldVector2D<T> p, final FieldVector2D<T> q, final FieldVector2D<T> r) {
  973.         final T prototype = p.getX();
  974.         final T[] a = MathArrays.buildArray(prototype.getField(), 6);
  975.         a[0] = p.getX();
  976.         a[1] = p.getX().negate();
  977.         a[2] = q.getX();
  978.         a[3] = q.getX().negate();
  979.         a[4] = r.getX();
  980.         a[5] = r.getX().negate();
  981.         final T[] b = MathArrays.buildArray(prototype.getField(), 6);
  982.         b[0] = q.getY();
  983.         b[1] = r.getY();
  984.         b[2] = r.getY();
  985.         b[3] = p.getY();
  986.         b[4] = p.getY();
  987.         b[5] = q.getY();
  988.         return prototype.linearCombination(a, b);
  989.     }

  990.     /** Get a string representation of this vector.
  991.      * @return a string representation of this vector
  992.      */
  993.     @Override
  994.     public String toString() {
  995.         return Vector2DFormat.getVector2DFormat().format(toVector2D());
  996.     }

  997.     /** Get a string representation of this vector.
  998.      * @param format the custom format for components
  999.      * @return a string representation of this vector
  1000.      */
  1001.     public String toString(final NumberFormat format) {
  1002.         return new Vector2DFormat(format).format(toVector2D());
  1003.     }

  1004. }