View Javadoc
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  
19  import java.text.NumberFormat;
20  
21  import org.hipparchus.Field;
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.exception.LocalizedCoreFormats;
24  import org.hipparchus.exception.MathIllegalArgumentException;
25  import org.hipparchus.exception.MathRuntimeException;
26  import org.hipparchus.geometry.LocalizedGeometryFormats;
27  import org.hipparchus.util.FastMath;
28  import org.hipparchus.util.MathArrays;
29  
30  /**
31   * This class is a re-implementation of {@link Vector2D} using {@link CalculusFieldElement}.
32   * <p>Instance of this class are guaranteed to be immutable.</p>
33   * @param <T> the type of the field elements
34   * @since 1.6
35   */
36  public class FieldVector2D<T extends CalculusFieldElement<T>> {
37  
38      /** Abscissa. */
39      private final T x;
40  
41      /** Ordinate. */
42      private final T y;
43  
44      /** Simple constructor.
45       * Build a vector from its coordinates
46       * @param x abscissa
47       * @param y ordinate
48       * @see #getX()
49       * @see #getY()
50       */
51      public FieldVector2D(final T x, final T y) {
52          this.x = x;
53          this.y = y;
54      }
55  
56      /** Simple constructor.
57       * Build a vector from its coordinates
58       * @param v coordinates array
59       * @exception MathIllegalArgumentException if array does not have 2 elements
60       * @see #toArray()
61       */
62      public FieldVector2D(final T[] v) throws MathIllegalArgumentException {
63          if (v.length != 2) {
64              throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
65                                                     v.length, 2);
66          }
67          this.x = v[0];
68          this.y = v[1];
69      }
70  
71      /** Multiplicative constructor
72       * Build a vector from another one and a scale factor.
73       * The vector built will be a * u
74       * @param a scale factor
75       * @param u base (unscaled) vector
76       */
77      public FieldVector2D(final T a, final FieldVector2D<T> u) {
78          this.x = a.multiply(u.x);
79          this.y = a.multiply(u.y);
80      }
81  
82      /** Multiplicative constructor
83       * Build a vector from another one and a scale factor.
84       * The vector built will be a * u
85       * @param a scale factor
86       * @param u base (unscaled) vector
87       */
88      public FieldVector2D(final T a, final Vector2D u) {
89          this.x = a.multiply(u.getX());
90          this.y = a.multiply(u.getY());
91      }
92  
93      /** Multiplicative constructor
94       * Build a vector from another one and a scale factor.
95       * The vector built will be a * u
96       * @param a scale factor
97       * @param u base (unscaled) vector
98       */
99      public FieldVector2D(final double a, final FieldVector2D<T> u) {
100         this.x = u.x.multiply(a);
101         this.y = u.y.multiply(a);
102     }
103 
104     /** Linear constructor
105      * Build a vector from two other ones and corresponding scale factors.
106      * The vector built will be a1 * u1 + a2 * u2
107      * @param a1 first scale factor
108      * @param u1 first base (unscaled) vector
109      * @param a2 second scale factor
110      * @param u2 second base (unscaled) vector
111      */
112     public FieldVector2D(final T a1, final FieldVector2D<T> u1, final T a2, final FieldVector2D<T> u2) {
113         final T prototype = a1;
114         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX());
115         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY());
116     }
117 
118     /** Linear constructor.
119      * Build a vector from two other ones and corresponding scale factors.
120      * The vector built will be a1 * u1 + a2 * u2
121      * @param a1 first scale factor
122      * @param u1 first base (unscaled) vector
123      * @param a2 second scale factor
124      * @param u2 second base (unscaled) vector
125      */
126     public FieldVector2D(final T a1, final Vector2D u1,
127                          final T a2, final Vector2D u2) {
128         final T prototype = a1;
129         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2);
130         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2);
131     }
132 
133     /** Linear constructor.
134      * Build a vector from two other ones and corresponding scale factors.
135      * The vector built will be a1 * u1 + a2 * u2
136      * @param a1 first scale factor
137      * @param u1 first base (unscaled) vector
138      * @param a2 second scale factor
139      * @param u2 second base (unscaled) vector
140      */
141     public FieldVector2D(final double a1, final FieldVector2D<T> u1,
142                          final double a2, final FieldVector2D<T> u2) {
143         final T prototype = u1.getX();
144         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX());
145         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY());
146     }
147 
148     /** Linear constructor.
149      * Build a vector from three other ones and corresponding scale factors.
150      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
151      * @param a1 first scale factor
152      * @param u1 first base (unscaled) vector
153      * @param a2 second scale factor
154      * @param u2 second base (unscaled) vector
155      * @param a3 third scale factor
156      * @param u3 third base (unscaled) vector
157      */
158     public FieldVector2D(final T a1, final FieldVector2D<T> u1,
159                          final T a2, final FieldVector2D<T> u2,
160                          final T a3, final FieldVector2D<T> u3) {
161         final T prototype = a1;
162         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX());
163         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY());
164     }
165 
166     /** Linear constructor.
167      * Build a vector from three other ones and corresponding scale factors.
168      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
169      * @param a1 first scale factor
170      * @param u1 first base (unscaled) vector
171      * @param a2 second scale factor
172      * @param u2 second base (unscaled) vector
173      * @param a3 third scale factor
174      * @param u3 third base (unscaled) vector
175      */
176     public FieldVector2D(final T a1, final Vector2D u1,
177                          final T a2, final Vector2D u2,
178                          final T a3, final Vector2D u3) {
179         final T prototype = a1;
180         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2, u3.getX(), a3);
181         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2, u3.getY(), a3);
182     }
183 
184     /** Linear constructor.
185      * Build a vector from three other ones and corresponding scale factors.
186      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
187      * @param a1 first scale factor
188      * @param u1 first base (unscaled) vector
189      * @param a2 second scale factor
190      * @param u2 second base (unscaled) vector
191      * @param a3 third scale factor
192      * @param u3 third base (unscaled) vector
193      */
194     public FieldVector2D(final double a1, final FieldVector2D<T> u1,
195                          final double a2, final FieldVector2D<T> u2,
196                          final double a3, final FieldVector2D<T> u3) {
197         final T prototype = u1.getX();
198         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX());
199         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY());
200     }
201 
202     /** Linear constructor.
203      * Build a vector from four other ones and corresponding scale factors.
204      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
205      * @param a1 first scale factor
206      * @param u1 first base (unscaled) vector
207      * @param a2 second scale factor
208      * @param u2 second base (unscaled) vector
209      * @param a3 third scale factor
210      * @param u3 third base (unscaled) vector
211      * @param a4 fourth scale factor
212      * @param u4 fourth base (unscaled) vector
213      */
214     public FieldVector2D(final T a1, final FieldVector2D<T> u1,
215                          final T a2, final FieldVector2D<T> u2,
216                          final T a3, final FieldVector2D<T> u3,
217                          final T a4, final FieldVector2D<T> u4) {
218         final T prototype = a1;
219         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX(), a4, u4.getX());
220         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY(), a4, u4.getY());
221     }
222 
223     /** Linear constructor.
224      * Build a vector from four other ones and corresponding scale factors.
225      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
226      * @param a1 first scale factor
227      * @param u1 first base (unscaled) vector
228      * @param a2 second scale factor
229      * @param u2 second base (unscaled) vector
230      * @param a3 third scale factor
231      * @param u3 third base (unscaled) vector
232      * @param a4 fourth scale factor
233      * @param u4 fourth base (unscaled) vector
234      */
235     public FieldVector2D(final T a1, final Vector2D u1,
236                          final T a2, final Vector2D u2,
237                          final T a3, final Vector2D u3,
238                          final T a4, final Vector2D u4) {
239         final T prototype = a1;
240         this.x = prototype.linearCombination(u1.getX(), a1, u2.getX(), a2, u3.getX(), a3, u4.getX(), a4);
241         this.y = prototype.linearCombination(u1.getY(), a1, u2.getY(), a2, u3.getY(), a3, u4.getY(), a4);
242     }
243 
244     /** Linear constructor.
245      * Build a vector from four other ones and corresponding scale factors.
246      * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
247      * @param a1 first scale factor
248      * @param u1 first base (unscaled) vector
249      * @param a2 second scale factor
250      * @param u2 second base (unscaled) vector
251      * @param a3 third scale factor
252      * @param u3 third base (unscaled) vector
253      * @param a4 fourth scale factor
254      * @param u4 fourth base (unscaled) vector
255      */
256     public FieldVector2D(final double a1, final FieldVector2D<T> u1,
257                          final double a2, final FieldVector2D<T> u2,
258                          final double a3, final FieldVector2D<T> u3,
259                          final double a4, final FieldVector2D<T> u4) {
260         final T prototype = u1.getX();
261         this.x = prototype.linearCombination(a1, u1.getX(), a2, u2.getX(), a3, u3.getX(), a4, u4.getX());
262         this.y = prototype.linearCombination(a1, u1.getY(), a2, u2.getY(), a3, u3.getY(), a4, u4.getY());
263     }
264 
265     /** Build a {@link FieldVector2D} from a {@link Vector2D}.
266      * @param field field for the components
267      * @param v vector to convert
268      */
269     public FieldVector2D(final Field<T> field, final Vector2D v) {
270         this.x = field.getZero().add(v.getX());
271         this.y = field.getZero().add(v.getY());
272     }
273 
274     /** Get null vector (coordinates: 0, 0).
275      * @param field field for the components
276      * @return a new vector
277      * @param <T> the type of the field elements
278      */
279     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getZero(final Field<T> field) {
280         return new FieldVector2D<>(field, Vector2D.ZERO);
281     }
282 
283     /** Get first canonical vector (coordinates: 1, 0).
284      * @param field field for the components
285      * @return a new vector
286      * @param <T> the type of the field elements
287      */
288     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getPlusI(final Field<T> field) {
289         return new FieldVector2D<>(field, Vector2D.PLUS_I);
290     }
291 
292     /** Get opposite of the first canonical vector (coordinates: -1).
293      * @param field field for the components
294      * @return a new vector
295      * @param <T> the type of the field elements
296      */
297     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getMinusI(final Field<T> field) {
298         return new FieldVector2D<>(field, Vector2D.MINUS_I);
299     }
300 
301     /** Get second canonical vector (coordinates: 0, 1).
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> getPlusJ(final Field<T> field) {
307         return new FieldVector2D<>(field, Vector2D.PLUS_J);
308     }
309 
310     /** Get opposite of the second canonical vector (coordinates: 0, -1).
311      * @param field field for the components
312      * @return a new vector
313      * @param <T> the type of the field elements
314      */
315     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getMinusJ(final Field<T> field) {
316         return new FieldVector2D<>(field, Vector2D.MINUS_J);
317     }
318 
319     /** Get a vector with all coordinates set to NaN.
320      * @param field field for the components
321      * @return a new vector
322      * @param <T> the type of the field elements
323      */
324     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getNaN(final Field<T> field) {
325         return new FieldVector2D<>(field, Vector2D.NaN);
326     }
327 
328     /** Get a vector with all coordinates set to positive infinity.
329      * @param field field for the components
330      * @return a new vector
331      * @param <T> the type of the field elements
332      */
333     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getPositiveInfinity(final Field<T> field) {
334         return new FieldVector2D<>(field, Vector2D.POSITIVE_INFINITY);
335     }
336 
337     /** Get a vector with all coordinates set to negative infinity.
338      * @param field field for the components
339      * @return a new vector
340      * @param <T> the type of the field elements
341      */
342     public static <T extends CalculusFieldElement<T>> FieldVector2D<T> getNegativeInfinity(final Field<T> field) {
343         return new FieldVector2D<>(field, Vector2D.NEGATIVE_INFINITY);
344     }
345 
346     /** Get the abscissa of the vector.
347      * @return abscissa of the vector
348      * @see #FieldVector2D(CalculusFieldElement, CalculusFieldElement)
349      */
350     public T getX() {
351         return x;
352     }
353 
354     /** Get the ordinate of the vector.
355      * @return ordinate of the vector
356     * @see #FieldVector2D(CalculusFieldElement, CalculusFieldElement)
357      */
358     public T getY() {
359         return y;
360     }
361 
362     /** Get the vector coordinates as a dimension 2 array.
363      * @return vector coordinates
364      * @see #FieldVector2D(CalculusFieldElement[])
365      */
366     public T[] toArray() {
367         final T[] array = MathArrays.buildArray(x.getField(), 2);
368         array[0] = x;
369         array[1] = y;
370         return array;
371     }
372 
373     /** Convert to a constant vector without extra field parts.
374      * @return a constant vector
375      */
376     public Vector2D toVector2D() {
377         return new Vector2D(x.getReal(), y.getReal());
378     }
379 
380     /** Get the L<sub>1</sub> norm for the vector.
381      * @return L<sub>1</sub> norm for the vector
382      */
383     public T getNorm1() {
384         return x.abs().add(y.abs());
385     }
386 
387     /** Get the L<sub>2</sub> norm for the vector.
388      * @return Euclidean norm for the vector
389      */
390     public T getNorm() {
391         // there are no cancellation problems here, so we use the straightforward formula
392         return x.multiply(x).add(y.multiply(y)).sqrt();
393     }
394 
395     /** Get the square of the norm for the vector.
396      * @return square of the Euclidean norm for the vector
397      */
398     public T getNormSq() {
399         // there are no cancellation problems here, so we use the straightforward formula
400         return x.multiply(x).add(y.multiply(y));
401     }
402 
403     /** Get the L<sub>&infin;</sub> norm for the vector.
404      * @return L<sub>&infin;</sub> norm for the vector
405      */
406     public T getNormInf() {
407         return FastMath.max(FastMath.abs(x), FastMath.abs(y));
408     }
409 
410     /** Add a vector to the instance.
411      * @param v vector to add
412      * @return a new vector
413      */
414     public FieldVector2D<T> add(final FieldVector2D<T> v) {
415         return new FieldVector2D<>(x.add(v.x), y.add(v.y));
416     }
417 
418     /** Add a vector to the instance.
419      * @param v vector to add
420      * @return a new vector
421      */
422     public FieldVector2D<T> add(final Vector2D v) {
423         return new FieldVector2D<>(x.add(v.getX()), y.add(v.getY()));
424     }
425 
426     /** Add a scaled vector to the instance.
427      * @param factor scale factor to apply to v before adding it
428      * @param v vector to add
429      * @return a new vector
430      */
431     public FieldVector2D<T> add(final T factor, final FieldVector2D<T> v) {
432         return new FieldVector2D<>(x.getField().getOne(), this, factor, v);
433     }
434 
435     /** Add a scaled vector to the instance.
436      * @param factor scale factor to apply to v before adding it
437      * @param v vector to add
438      * @return a new vector
439      */
440     public FieldVector2D<T> add(final T factor, final Vector2D v) {
441         return new FieldVector2D<>(x.add(factor.multiply(v.getX())),
442                                    y.add(factor.multiply(v.getY())));
443     }
444 
445     /** Add a scaled vector to the instance.
446      * @param factor scale factor to apply to v before adding it
447      * @param v vector to add
448      * @return a new vector
449      */
450     public FieldVector2D<T> add(final double factor, final FieldVector2D<T> v) {
451         return new FieldVector2D<>(1.0, this, factor, v);
452     }
453 
454     /** Add a scaled vector to the instance.
455      * @param factor scale factor to apply to v before adding it
456      * @param v vector to add
457      * @return a new vector
458      */
459     public FieldVector2D<T> add(final double factor, final Vector2D v) {
460         return new FieldVector2D<>(x.add(factor * v.getX()),
461                                    y.add(factor * v.getY()));
462     }
463 
464     /** Subtract a vector from the instance.
465      * @param v vector to subtract
466      * @return a new vector
467      */
468     public FieldVector2D<T> subtract(final FieldVector2D<T> v) {
469         return new FieldVector2D<>(x.subtract(v.x), y.subtract(v.y));
470     }
471 
472     /** Subtract a vector from the instance.
473      * @param v vector to subtract
474      * @return a new vector
475      */
476     public FieldVector2D<T> subtract(final Vector2D v) {
477         return new FieldVector2D<>(x.subtract(v.getX()), y.subtract(v.getY()));
478     }
479 
480     /** Subtract a scaled vector from the instance.
481      * @param factor scale factor to apply to v before subtracting it
482      * @param v vector to subtract
483      * @return a new vector
484      */
485     public FieldVector2D<T> subtract(final T factor, final FieldVector2D<T> v) {
486         return new FieldVector2D<>(x.getField().getOne(), this, factor.negate(), v);
487     }
488 
489     /** Subtract a scaled vector from the instance.
490      * @param factor scale factor to apply to v before subtracting it
491      * @param v vector to subtract
492      * @return a new vector
493      */
494     public FieldVector2D<T> subtract(final T factor, final Vector2D v) {
495         return new FieldVector2D<>(x.subtract(factor.multiply(v.getX())),
496                                    y.subtract(factor.multiply(v.getY())));
497     }
498 
499     /** Subtract a scaled vector from the instance.
500      * @param factor scale factor to apply to v before subtracting it
501      * @param v vector to subtract
502      * @return a new vector
503      */
504     public FieldVector2D<T> subtract(final double factor, final FieldVector2D<T> v) {
505         return new FieldVector2D<>(1.0, this, -factor, v);
506     }
507 
508     /** Subtract a scaled vector from the instance.
509      * @param factor scale factor to apply to v before subtracting it
510      * @param v vector to subtract
511      * @return a new vector
512      */
513     public FieldVector2D<T> subtract(final double factor, final Vector2D v) {
514         return new FieldVector2D<>(x.subtract(factor * v.getX()),
515                                    y.subtract(factor * v.getY()));
516     }
517 
518     /** Get a normalized vector aligned with the instance.
519      * @return a new normalized vector
520      * @exception MathRuntimeException if the norm is zero
521      */
522     public FieldVector2D<T> normalize() throws MathRuntimeException {
523         final T s = getNorm();
524         if (s.getReal() == 0) {
525             throw new MathRuntimeException(LocalizedGeometryFormats.CANNOT_NORMALIZE_A_ZERO_NORM_VECTOR);
526         }
527         return scalarMultiply(s.reciprocal());
528     }
529 
530     /** Compute the angular separation between two vectors.
531      * <p>This method computes the angular separation between two
532      * vectors using the dot product for well separated vectors and the
533      * cross product for almost aligned vectors. This allows to have a
534      * good accuracy in all cases, even for vectors very close to each
535      * other.</p>
536      * @param v1 first vector
537      * @param v2 second vector
538      * @param <T> the type of the field elements
539      * @return angular separation between v1 and v2
540      * @exception MathRuntimeException if either vector has a null norm
541      */
542     public static <T extends CalculusFieldElement<T>> T angle(final FieldVector2D<T> v1, final FieldVector2D<T> v2)
543         throws MathRuntimeException {
544 
545         final T normProduct = v1.getNorm().multiply(v2.getNorm());
546         if (normProduct.getReal() == 0) {
547             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_NORM);
548         }
549 
550         final T dot = v1.dotProduct(v2);
551         final double threshold = normProduct.getReal() * 0.9999;
552         if (FastMath.abs(dot.getReal()) > threshold) {
553             // the vectors are almost aligned, compute using the sine
554             final T n = FastMath.abs(dot.linearCombination(v1.x, v2.y, v1.y.negate(), v2.x));
555             if (dot.getReal() >= 0) {
556                 return FastMath.asin(n.divide(normProduct));
557             }
558             return FastMath.asin(n.divide(normProduct)).negate().add(dot.getPi());
559         }
560 
561         // the vectors are sufficiently separated to use the cosine
562         return FastMath.acos(dot.divide(normProduct));
563 
564     }
565 
566     /** Compute the angular separation between two vectors.
567      * <p>This method computes the angular separation between two
568      * vectors using the dot product for well separated vectors and the
569      * cross product for almost aligned vectors. This allows to have a
570      * good accuracy in all cases, even for vectors very close to each
571      * other.</p>
572      * @param v1 first vector
573      * @param v2 second vector
574      * @param <T> the type of the field elements
575      * @return angular separation between v1 and v2
576      * @exception MathRuntimeException if either vector has a null norm
577      */
578     public static <T extends CalculusFieldElement<T>> T angle(final FieldVector2D<T> v1, final Vector2D v2)
579         throws MathRuntimeException {
580 
581         final T normProduct = v1.getNorm().multiply(v2.getNorm());
582         if (normProduct.getReal() == 0) {
583             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_NORM);
584         }
585 
586         final T dot = v1.dotProduct(v2);
587         final double threshold = normProduct.getReal() * 0.9999;
588         if (FastMath.abs(dot.getReal()) > threshold) {
589             // the vectors are almost aligned, compute using the sine
590             final T n = FastMath.abs(dot.linearCombination(v2.getY(), v1.x, v2.getX(), v1.y.negate()));
591             if (dot.getReal() >= 0) {
592                 return FastMath.asin(n.divide(normProduct));
593             }
594             return FastMath.asin(n.divide(normProduct)).negate().add(dot.getPi());
595         }
596 
597         // the vectors are sufficiently separated to use the cosine
598         return FastMath.acos(dot.divide(normProduct));
599 
600     }
601 
602     /** Compute the angular separation between two vectors.
603      * <p>This method computes the angular separation between two
604      * vectors using the dot product for well separated vectors and the
605      * cross product for almost aligned vectors. This allows to have a
606      * good accuracy in all cases, even for vectors very close to each
607      * other.</p>
608      * @param v1 first vector
609      * @param v2 second vector
610      * @param <T> the type of the field elements
611      * @return angular separation between v1 and v2
612      * @exception MathRuntimeException if either vector has a null norm
613      */
614     public static <T extends CalculusFieldElement<T>> T angle(final Vector2D v1, final FieldVector2D<T> v2)
615         throws MathRuntimeException {
616         return angle(v2, v1);
617     }
618 
619     /** Get the opposite of the instance.
620      * @return a new vector which is opposite to the instance
621      */
622     public FieldVector2D<T> negate() {
623         return new FieldVector2D<>(x.negate(), y.negate());
624     }
625 
626     /** Multiply the instance by a scalar.
627      * @param a scalar
628      * @return a new vector
629      */
630     public FieldVector2D<T> scalarMultiply(final T a) {
631         return new FieldVector2D<>(x.multiply(a), y.multiply(a));
632     }
633 
634     /** Multiply the instance by a scalar.
635      * @param a scalar
636      * @return a new vector
637      */
638     public FieldVector2D<T> scalarMultiply(final double a) {
639         return new FieldVector2D<>(x.multiply(a), y.multiply(a));
640     }
641 
642     /**
643      * Returns true if any coordinate of this vector is NaN; false otherwise
644      * @return  true if any coordinate of this vector is NaN; false otherwise
645      */
646     public boolean isNaN() {
647         return Double.isNaN(x.getReal()) || Double.isNaN(y.getReal());
648     }
649 
650     /**
651      * Returns true if any coordinate of this vector is infinite and none are NaN;
652      * false otherwise
653      * @return  true if any coordinate of this vector is infinite and none are NaN;
654      * false otherwise
655      */
656     public boolean isInfinite() {
657         return !isNaN() && (Double.isInfinite(x.getReal()) || Double.isInfinite(y.getReal()));
658     }
659 
660     /**
661      * Test for the equality of two 2D vectors.
662      * <p>
663      * If all coordinates of two 2D vectors are exactly the same, and none of their
664      * {@link CalculusFieldElement#getReal() real part} are <code>NaN</code>, the
665      * two 2D vectors are considered to be equal.
666      * </p>
667      * <p>
668      * <code>NaN</code> coordinates are considered to affect globally the vector
669      * and be equals to each other - i.e, if either (or all) real part of the
670      * coordinates of the 3D vector are <code>NaN</code>, the 2D vector is <code>NaN</code>.
671      * </p>
672      *
673      * @param other Object to test for equality to this
674      * @return true if two 2D vector objects are equal, false if
675      *         object is null, not an instance of FieldVector2D, or
676      *         not equal to this FieldVector2D instance
677      *
678      */
679     @Override
680     public boolean equals(Object other) {
681 
682         if (this == other) {
683             return true;
684         }
685 
686         if (other instanceof FieldVector2D) {
687             @SuppressWarnings("unchecked")
688             final FieldVector2D<T> rhs = (FieldVector2D<T>) other;
689             if (rhs.isNaN()) {
690                 return this.isNaN();
691             }
692 
693             return x.equals(rhs.x) && y.equals(rhs.y);
694 
695         }
696         return false;
697     }
698 
699     /**
700      * Get a hashCode for the 3D vector.
701      * <p>
702      * All NaN values have the same hash code.</p>
703      *
704      * @return a hash code value for this object
705      */
706     @Override
707     public int hashCode() {
708         if (isNaN()) {
709             return 542;
710         }
711         return 122 * (76 * x.hashCode() +  y.hashCode());
712     }
713 
714     /** Compute the distance between the instance and another vector according to the L<sub>1</sub> norm.
715      * <p>Calling this method is equivalent to calling:
716      * <code>q.subtract(p).getNorm1()</code> except that no intermediate
717      * vector is built</p>
718      * @param v second vector
719      * @return the distance between the instance and p according to the L<sub>1</sub> norm
720      */
721     public T distance1(final FieldVector2D<T> v) {
722         final T dx = v.x.subtract(x).abs();
723         final T dy = v.y.subtract(y).abs();
724         return dx.add(dy);
725     }
726 
727     /** Compute the distance between the instance and another vector according to the L<sub>1</sub> norm.
728      * <p>Calling this method is equivalent to calling:
729      * <code>q.subtract(p).getNorm1()</code> except that no intermediate
730      * vector is built</p>
731      * @param v second vector
732      * @return the distance between the instance and p according to the L<sub>1</sub> norm
733      */
734     public T distance1(final Vector2D v) {
735         final T dx = x.subtract(v.getX()).abs();
736         final T dy = y.subtract(v.getY()).abs();
737         return dx.add(dy);
738     }
739 
740     /** Compute the distance between the instance and another vector according to the L<sub>2</sub> norm.
741      * <p>Calling this method is equivalent to calling:
742      * <code>q.subtract(p).getNorm()</code> except that no intermediate
743      * vector is built</p>
744      * @param v second vector
745      * @return the distance between the instance and p according to the L<sub>2</sub> norm
746      */
747     public T distance(final FieldVector2D<T> v) {
748         final T dx = v.x.subtract(x);
749         final T dy = v.y.subtract(y);
750         return dx.multiply(dx).add(dy.multiply(dy)).sqrt();
751     }
752 
753     /** Compute the distance between the instance and another vector according to the L<sub>2</sub> norm.
754      * <p>Calling this method is equivalent to calling:
755      * <code>q.subtract(p).getNorm()</code> except that no intermediate
756      * vector is built</p>
757      * @param v second vector
758      * @return the distance between the instance and p according to the L<sub>2</sub> norm
759      */
760     public T distance(final Vector2D v) {
761         final T dx = x.subtract(v.getX());
762         final T dy = y.subtract(v.getY());
763         return dx.multiply(dx).add(dy.multiply(dy)).sqrt();
764     }
765 
766     /** Compute the distance between the instance and another vector according to the L<sub>&infin;</sub> norm.
767      * <p>Calling this method is equivalent to calling:
768      * <code>q.subtract(p).getNormInf()</code> except that no intermediate
769      * vector is built</p>
770      * @param v second vector
771      * @return the distance between the instance and p according to the L<sub>&infin;</sub> norm
772      */
773     public T distanceInf(final FieldVector2D<T> v) {
774         final T dx = FastMath.abs(x.subtract(v.x));
775         final T dy = FastMath.abs(y.subtract(v.y));
776         return FastMath.max(dx, dy);
777     }
778 
779     /** Compute the distance between the instance and another vector according to the L<sub>&infin;</sub> norm.
780      * <p>Calling this method is equivalent to calling:
781      * <code>q.subtract(p).getNormInf()</code> except that no intermediate
782      * vector is built</p>
783      * @param v second vector
784      * @return the distance between the instance and p according to the L<sub>&infin;</sub> norm
785      */
786     public T distanceInf(final Vector2D v) {
787         final T dx = FastMath.abs(x.subtract(v.getX()));
788         final T dy = FastMath.abs(y.subtract(v.getY()));
789         return FastMath.max(dx, dy);
790     }
791 
792     /** Compute the square of the distance between the instance and another vector.
793      * <p>Calling this method is equivalent to calling:
794      * <code>q.subtract(p).getNormSq()</code> except that no intermediate
795      * vector is built</p>
796      * @param v second vector
797      * @return the square of the distance between the instance and p
798      */
799     public T distanceSq(final FieldVector2D<T> v) {
800         final T dx = v.x.subtract(x);
801         final T dy = v.y.subtract(y);
802         return dx.multiply(dx).add(dy.multiply(dy));
803     }
804 
805     /** Compute the square of the distance between the instance and another vector.
806      * <p>Calling this method is equivalent to calling:
807      * <code>q.subtract(p).getNormSq()</code> except that no intermediate
808      * vector is built</p>
809      * @param v second vector
810      * @return the square of the distance between the instance and p
811      */
812     public T distanceSq(final Vector2D v) {
813         final T dx = x.subtract(v.getX());
814         final T dy = y.subtract(v.getY());
815         return dx.multiply(dx).add(dy.multiply(dy));
816     }
817 
818 
819     /** Compute the dot-product of the instance and another vector.
820      * <p>
821      * The implementation uses specific multiplication and addition
822      * algorithms to preserve accuracy and reduce cancellation effects.
823      * It should be very accurate even for nearly orthogonal vectors.
824      * </p>
825      * @see MathArrays#linearCombination(double, double, double, double, double, double)
826      * @param v second vector
827      * @return the dot product this.v
828      */
829     public T dotProduct(final FieldVector2D<T> v) {
830         return x.linearCombination(x, v.getX(), y, v.getY());
831     }
832 
833     /** Compute the dot-product of the instance and another vector.
834      * <p>
835      * The implementation uses specific multiplication and addition
836      * algorithms to preserve accuracy and reduce cancellation effects.
837      * It should be very accurate even for nearly orthogonal vectors.
838      * </p>
839      * @see MathArrays#linearCombination(double, double, double, double, double, double)
840      * @param v second vector
841      * @return the dot product this.v
842      */
843     public T dotProduct(final Vector2D v) {
844         return x.linearCombination(v.getX(), x, v.getY(), y);
845     }
846 
847     /**
848      * Compute the cross-product of the instance and the given points.
849      * <p>
850      * The cross product can be used to determine the location of a point
851      * with regard to the line formed by (p1, p2) and is calculated as:
852      * \[
853      *    P = (x_2 - x_1)(y_3 - y_1) - (y_2 - y_1)(x_3 - x_1)
854      * \]
855      * with \(p3 = (x_3, y_3)\) being this instance.
856      * <p>
857      * If the result is 0, the points are collinear, i.e. lie on a single straight line L;
858      * if it is positive, this point lies to the left, otherwise to the right of the line
859      * formed by (p1, p2).
860      *
861      * @param p1 first point of the line
862      * @param p2 second point of the line
863      * @return the cross-product
864      *
865      * @see <a href="http://en.wikipedia.org/wiki/Cross_product">Cross product (Wikipedia)</a>
866      */
867     public T crossProduct(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
868         final T x1  = p2.getX().subtract(p1.getX());
869         final T y1  = getY().subtract(p1.getY());
870         final T mx2 = p1.getX().subtract(getX());
871         final T y2  = p2.getY().subtract(p1.getY());
872         return x1.linearCombination(x1, y1, mx2, y2);
873     }
874 
875     /**
876      * Compute the cross-product of the instance and the given points.
877      * <p>
878      * The cross product can be used to determine the location of a point
879      * with regard to the line formed by (p1, p2) and is calculated as:
880      * \[
881      *    P = (x_2 - x_1)(y_3 - y_1) - (y_2 - y_1)(x_3 - x_1)
882      * \]
883      * with \(p3 = (x_3, y_3)\) being this instance.
884      * <p>
885      * If the result is 0, the points are collinear, i.e. lie on a single straight line L;
886      * if it is positive, this point lies to the left, otherwise to the right of the line
887      * formed by (p1, p2).
888      *
889      * @param p1 first point of the line
890      * @param p2 second point of the line
891      * @return the cross-product
892      *
893      * @see <a href="http://en.wikipedia.org/wiki/Cross_product">Cross product (Wikipedia)</a>
894      */
895     public T crossProduct(final Vector2D p1, final Vector2D p2) {
896         final double x1  = p2.getX() - p1.getX();
897         final T      y1  = getY().subtract(p1.getY());
898         final T      x2 = getX().subtract(p1.getX());
899         final double y2  = p2.getY() - p1.getY();
900         return y1.linearCombination(x1, y1, -y2, x2);
901     }
902 
903     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
904      * <p>Calling this method is equivalent to calling:
905      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
906      * vector is built</p>
907      * @param p1 first vector
908      * @param p2 second vector
909      * @param <T> the type of the field elements
910      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
911      */
912     public static <T extends CalculusFieldElement<T>> T  distance1(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
913         return p1.distance1(p2);
914     }
915 
916     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
917      * <p>Calling this method is equivalent to calling:
918      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
919      * vector is built</p>
920      * @param p1 first vector
921      * @param p2 second vector
922      * @param <T> the type of the field elements
923      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
924      */
925     public static <T extends CalculusFieldElement<T>> T  distance1(final FieldVector2D<T> p1, final Vector2D p2) {
926         return p1.distance1(p2);
927     }
928 
929     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
930      * <p>Calling this method is equivalent to calling:
931      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
932      * vector is built</p>
933      * @param p1 first vector
934      * @param p2 second vector
935      * @param <T> the type of the field elements
936      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
937      */
938     public static <T extends CalculusFieldElement<T>> T  distance1(final Vector2D p1, final FieldVector2D<T> p2) {
939         return p2.distance1(p1);
940     }
941 
942     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
943      * <p>Calling this method is equivalent to calling:
944      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
945      * vector is built</p>
946      * @param p1 first vector
947      * @param p2 second vector
948      * @param <T> the type of the field elements
949      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
950      */
951     public static <T extends CalculusFieldElement<T>> T distance(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
952         return p1.distance(p2);
953     }
954 
955     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
956      * <p>Calling this method is equivalent to calling:
957      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
958      * vector is built</p>
959      * @param p1 first vector
960      * @param p2 second vector
961      * @param <T> the type of the field elements
962      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
963      */
964     public static <T extends CalculusFieldElement<T>> T distance(final FieldVector2D<T> p1, final Vector2D p2) {
965         return p1.distance(p2);
966     }
967 
968     /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
969      * <p>Calling this method is equivalent to calling:
970      * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
971      * vector is built</p>
972      * @param p1 first vector
973      * @param p2 second vector
974      * @param <T> the type of the field elements
975      * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
976      */
977     public static <T extends CalculusFieldElement<T>> T distance( final Vector2D p1, final FieldVector2D<T> p2) {
978         return p2.distance(p1);
979     }
980 
981     /** Compute the distance between two vectors according to the L<sub>&infin;</sub> norm.
982      * <p>Calling this method is equivalent to calling:
983      * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
984      * vector is built</p>
985      * @param p1 first vector
986      * @param p2 second vector
987      * @param <T> the type of the field elements
988      * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
989      */
990     public static <T extends CalculusFieldElement<T>> T distanceInf(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
991         return p1.distanceInf(p2);
992     }
993 
994     /** Compute the distance between two vectors according to the L<sub>&infin;</sub> norm.
995      * <p>Calling this method is equivalent to calling:
996      * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
997      * vector is built</p>
998      * @param p1 first vector
999      * @param p2 second vector
1000      * @param <T> the type of the field elements
1001      * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
1002      */
1003     public static <T extends CalculusFieldElement<T>> T distanceInf(final FieldVector2D<T> p1, final Vector2D p2) {
1004         return p1.distanceInf(p2);
1005     }
1006 
1007     /** Compute the distance between two vectors according to the L<sub>&infin;</sub> norm.
1008      * <p>Calling this method is equivalent to calling:
1009      * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
1010      * vector is built</p>
1011      * @param p1 first vector
1012      * @param p2 second vector
1013      * @param <T> the type of the field elements
1014      * @return the distance between p1 and p2 according to the L<sub>&infin;</sub> norm
1015      */
1016     public static <T extends CalculusFieldElement<T>> T distanceInf(final Vector2D p1, final FieldVector2D<T> p2) {
1017         return p2.distanceInf(p1);
1018     }
1019 
1020     /** Compute the square of the distance between two vectors.
1021      * <p>Calling this method is equivalent to calling:
1022      * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
1023      * vector is built</p>
1024      * @param p1 first vector
1025      * @param p2 second vector
1026      * @param <T> the type of the field elements
1027      * @return the square of the distance between p1 and p2
1028      */
1029     public static <T extends CalculusFieldElement<T>> T distanceSq(final FieldVector2D<T> p1, final FieldVector2D<T> p2) {
1030         return p1.distanceSq(p2);
1031     }
1032 
1033     /** Compute the square of the distance between two vectors.
1034      * <p>Calling this method is equivalent to calling:
1035      * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
1036      * vector is built</p>
1037      * @param p1 first vector
1038      * @param p2 second vector
1039      * @param <T> the type of the field elements
1040      * @return the square of the distance between p1 and p2
1041      */
1042     public static <T extends CalculusFieldElement<T>> T distanceSq(final FieldVector2D<T> p1, final Vector2D p2) {
1043         return p1.distanceSq(p2);
1044     }
1045 
1046     /** Compute the square of the distance between two vectors.
1047      * <p>Calling this method is equivalent to calling:
1048      * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
1049      * vector is built</p>
1050      * @param p1 first vector
1051      * @param p2 second vector
1052      * @param <T> the type of the field elements
1053      * @return the square of the distance between p1 and p2
1054      */
1055     public static <T extends CalculusFieldElement<T>> T distanceSq(final Vector2D p1, final FieldVector2D<T> p2) {
1056         return p2.distanceSq(p1);
1057     }
1058 
1059     /** Compute the orientation of a triplet of points.
1060      * @param p first vector of the triplet
1061      * @param q second vector of the triplet
1062      * @param r third vector of the triplet
1063      * @param <T> the type of the field elements
1064      * @return a positive value if (p, q, r) defines a counterclockwise oriented
1065      * triangle, a negative value if (p, q, r) defines a clockwise oriented
1066      * triangle, and 0 if (p, q, r) are collinear or some points are equal
1067      * @since 1.2
1068      */
1069     public static <T extends CalculusFieldElement<T>> T orientation(final FieldVector2D<T> p, final FieldVector2D<T> q, final FieldVector2D<T> r) {
1070         final T prototype = p.getX();
1071         final T[] a = MathArrays.buildArray(prototype.getField(), 6);
1072         a[0] = p.getX();
1073         a[1] = p.getX().negate();
1074         a[2] = q.getX();
1075         a[3] = q.getX().negate();
1076         a[4] = r.getX();
1077         a[5] = r.getX().negate();
1078         final T[] b = MathArrays.buildArray(prototype.getField(), 6);
1079         b[0] = q.getY();
1080         b[1] = r.getY();
1081         b[2] = r.getY();
1082         b[3] = p.getY();
1083         b[4] = p.getY();
1084         b[5] = q.getY();
1085         return prototype.linearCombination(a, b);
1086     }
1087 
1088     /** Get a string representation of this vector.
1089      * @return a string representation of this vector
1090      */
1091     @Override
1092     public String toString() {
1093         return Vector2DFormat.getVector2DFormat().format(toVector2D());
1094     }
1095 
1096     /** Get a string representation of this vector.
1097      * @param format the custom format for components
1098      * @return a string representation of this vector
1099      */
1100     public String toString(final NumberFormat format) {
1101         return new Vector2DFormat(format).format(toVector2D());
1102     }
1103 
1104 }