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.square().add(y.square()).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.square().add(y.square());
401 }
402
403 /** Get the L<sub>∞</sub> norm for the vector.
404 * @return L<sub>∞</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.square().add(dy.square()).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.square().add(dy.square()).sqrt();
764 }
765
766 /** Compute the distance between the instance and another vector according to the L<sub>∞</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>∞</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>∞</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>∞</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.square().add(dy.square());
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.square().add(dy.square());
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>∞</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>∞</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>∞</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>∞</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>∞</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>∞</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 }