001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math3.geometry.euclidean.twod;
018
019 import java.text.NumberFormat;
020
021 import org.apache.commons.math3.exception.DimensionMismatchException;
022 import org.apache.commons.math3.exception.MathArithmeticException;
023 import org.apache.commons.math3.exception.util.LocalizedFormats;
024 import org.apache.commons.math3.geometry.Space;
025 import org.apache.commons.math3.geometry.Vector;
026 import org.apache.commons.math3.util.FastMath;
027 import org.apache.commons.math3.util.MathUtils;
028
029 /** This class represents a 2D vector.
030 * <p>Instances of this class are guaranteed to be immutable.</p>
031 * @version $Id: Vector2D.java 1416643 2012-12-03 19:37:14Z tn $
032 * @since 3.0
033 */
034 public class Vector2D implements Vector<Euclidean2D> {
035
036 /** Origin (coordinates: 0, 0). */
037 public static final Vector2D ZERO = new Vector2D(0, 0);
038
039 // CHECKSTYLE: stop ConstantName
040 /** A vector with all coordinates set to NaN. */
041 public static final Vector2D NaN = new Vector2D(Double.NaN, Double.NaN);
042 // CHECKSTYLE: resume ConstantName
043
044 /** A vector with all coordinates set to positive infinity. */
045 public static final Vector2D POSITIVE_INFINITY =
046 new Vector2D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
047
048 /** A vector with all coordinates set to negative infinity. */
049 public static final Vector2D NEGATIVE_INFINITY =
050 new Vector2D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
051
052 /** Serializable UID. */
053 private static final long serialVersionUID = 266938651998679754L;
054
055 /** Abscissa. */
056 private final double x;
057
058 /** Ordinate. */
059 private final double y;
060
061 /** Simple constructor.
062 * Build a vector from its coordinates
063 * @param x abscissa
064 * @param y ordinate
065 * @see #getX()
066 * @see #getY()
067 */
068 public Vector2D(double x, double y) {
069 this.x = x;
070 this.y = y;
071 }
072
073 /** Simple constructor.
074 * Build a vector from its coordinates
075 * @param v coordinates array
076 * @exception DimensionMismatchException if array does not have 2 elements
077 * @see #toArray()
078 */
079 public Vector2D(double[] v) throws DimensionMismatchException {
080 if (v.length != 2) {
081 throw new DimensionMismatchException(v.length, 2);
082 }
083 this.x = v[0];
084 this.y = v[1];
085 }
086
087 /** Multiplicative constructor
088 * Build a vector from another one and a scale factor.
089 * The vector built will be a * u
090 * @param a scale factor
091 * @param u base (unscaled) vector
092 */
093 public Vector2D(double a, Vector2D u) {
094 this.x = a * u.x;
095 this.y = a * u.y;
096 }
097
098 /** Linear constructor
099 * Build a vector from two other ones and corresponding scale factors.
100 * The vector built will be a1 * u1 + a2 * u2
101 * @param a1 first scale factor
102 * @param u1 first base (unscaled) vector
103 * @param a2 second scale factor
104 * @param u2 second base (unscaled) vector
105 */
106 public Vector2D(double a1, Vector2D u1, double a2, Vector2D u2) {
107 this.x = a1 * u1.x + a2 * u2.x;
108 this.y = a1 * u1.y + a2 * u2.y;
109 }
110
111 /** Linear constructor
112 * Build a vector from three other ones and corresponding scale factors.
113 * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
114 * @param a1 first scale factor
115 * @param u1 first base (unscaled) vector
116 * @param a2 second scale factor
117 * @param u2 second base (unscaled) vector
118 * @param a3 third scale factor
119 * @param u3 third base (unscaled) vector
120 */
121 public Vector2D(double a1, Vector2D u1, double a2, Vector2D u2,
122 double a3, Vector2D u3) {
123 this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x;
124 this.y = a1 * u1.y + a2 * u2.y + a3 * u3.y;
125 }
126
127 /** Linear constructor
128 * Build a vector from four other ones and corresponding scale factors.
129 * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
130 * @param a1 first scale factor
131 * @param u1 first base (unscaled) vector
132 * @param a2 second scale factor
133 * @param u2 second base (unscaled) vector
134 * @param a3 third scale factor
135 * @param u3 third base (unscaled) vector
136 * @param a4 fourth scale factor
137 * @param u4 fourth base (unscaled) vector
138 */
139 public Vector2D(double a1, Vector2D u1, double a2, Vector2D u2,
140 double a3, Vector2D u3, double a4, Vector2D u4) {
141 this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x + a4 * u4.x;
142 this.y = a1 * u1.y + a2 * u2.y + a3 * u3.y + a4 * u4.y;
143 }
144
145 /** Get the abscissa of the vector.
146 * @return abscissa of the vector
147 * @see #Vector2D(double, double)
148 */
149 public double getX() {
150 return x;
151 }
152
153 /** Get the ordinate of the vector.
154 * @return ordinate of the vector
155 * @see #Vector2D(double, double)
156 */
157 public double getY() {
158 return y;
159 }
160
161 /** Get the vector coordinates as a dimension 2 array.
162 * @return vector coordinates
163 * @see #Vector2D(double[])
164 */
165 public double[] toArray() {
166 return new double[] { x, y };
167 }
168
169 /** {@inheritDoc} */
170 public Space getSpace() {
171 return Euclidean2D.getInstance();
172 }
173
174 /** {@inheritDoc} */
175 public Vector2D getZero() {
176 return ZERO;
177 }
178
179 /** {@inheritDoc} */
180 public double getNorm1() {
181 return FastMath.abs(x) + FastMath.abs(y);
182 }
183
184 /** {@inheritDoc} */
185 public double getNorm() {
186 return FastMath.sqrt (x * x + y * y);
187 }
188
189 /** {@inheritDoc} */
190 public double getNormSq() {
191 return x * x + y * y;
192 }
193
194 /** {@inheritDoc} */
195 public double getNormInf() {
196 return FastMath.max(FastMath.abs(x), FastMath.abs(y));
197 }
198
199 /** {@inheritDoc} */
200 public Vector2D add(Vector<Euclidean2D> v) {
201 Vector2D v2 = (Vector2D) v;
202 return new Vector2D(x + v2.getX(), y + v2.getY());
203 }
204
205 /** {@inheritDoc} */
206 public Vector2D add(double factor, Vector<Euclidean2D> v) {
207 Vector2D v2 = (Vector2D) v;
208 return new Vector2D(x + factor * v2.getX(), y + factor * v2.getY());
209 }
210
211 /** {@inheritDoc} */
212 public Vector2D subtract(Vector<Euclidean2D> p) {
213 Vector2D p3 = (Vector2D) p;
214 return new Vector2D(x - p3.x, y - p3.y);
215 }
216
217 /** {@inheritDoc} */
218 public Vector2D subtract(double factor, Vector<Euclidean2D> v) {
219 Vector2D v2 = (Vector2D) v;
220 return new Vector2D(x - factor * v2.getX(), y - factor * v2.getY());
221 }
222
223 /** {@inheritDoc} */
224 public Vector2D normalize() throws MathArithmeticException {
225 double s = getNorm();
226 if (s == 0) {
227 throw new MathArithmeticException(LocalizedFormats.CANNOT_NORMALIZE_A_ZERO_NORM_VECTOR);
228 }
229 return scalarMultiply(1 / s);
230 }
231 /** {@inheritDoc} */
232 public Vector2D negate() {
233 return new Vector2D(-x, -y);
234 }
235
236 /** {@inheritDoc} */
237 public Vector2D scalarMultiply(double a) {
238 return new Vector2D(a * x, a * y);
239 }
240
241 /** {@inheritDoc} */
242 public boolean isNaN() {
243 return Double.isNaN(x) || Double.isNaN(y);
244 }
245
246 /** {@inheritDoc} */
247 public boolean isInfinite() {
248 return !isNaN() && (Double.isInfinite(x) || Double.isInfinite(y));
249 }
250
251 /** {@inheritDoc} */
252 public double distance1(Vector<Euclidean2D> p) {
253 Vector2D p3 = (Vector2D) p;
254 final double dx = FastMath.abs(p3.x - x);
255 final double dy = FastMath.abs(p3.y - y);
256 return dx + dy;
257 }
258
259 /** {@inheritDoc} */
260 public double distance(Vector<Euclidean2D> p) {
261 Vector2D p3 = (Vector2D) p;
262 final double dx = p3.x - x;
263 final double dy = p3.y - y;
264 return FastMath.sqrt(dx * dx + dy * dy);
265 }
266
267 /** {@inheritDoc} */
268 public double distanceInf(Vector<Euclidean2D> p) {
269 Vector2D p3 = (Vector2D) p;
270 final double dx = FastMath.abs(p3.x - x);
271 final double dy = FastMath.abs(p3.y - y);
272 return FastMath.max(dx, dy);
273 }
274
275 /** {@inheritDoc} */
276 public double distanceSq(Vector<Euclidean2D> p) {
277 Vector2D p3 = (Vector2D) p;
278 final double dx = p3.x - x;
279 final double dy = p3.y - y;
280 return dx * dx + dy * dy;
281 }
282
283 /** {@inheritDoc} */
284 public double dotProduct(final Vector<Euclidean2D> v) {
285 final Vector2D v2 = (Vector2D) v;
286 return x * v2.x + y * v2.y;
287 }
288
289 /** Compute the distance between two vectors according to the L<sub>2</sub> norm.
290 * <p>Calling this method is equivalent to calling:
291 * <code>p1.subtract(p2).getNorm()</code> except that no intermediate
292 * vector is built</p>
293 * @param p1 first vector
294 * @param p2 second vector
295 * @return the distance between p1 and p2 according to the L<sub>2</sub> norm
296 */
297 public static double distance(Vector2D p1, Vector2D p2) {
298 return p1.distance(p2);
299 }
300
301 /** Compute the distance between two vectors according to the L<sub>∞</sub> norm.
302 * <p>Calling this method is equivalent to calling:
303 * <code>p1.subtract(p2).getNormInf()</code> except that no intermediate
304 * vector is built</p>
305 * @param p1 first vector
306 * @param p2 second vector
307 * @return the distance between p1 and p2 according to the L<sub>∞</sub> norm
308 */
309 public static double distanceInf(Vector2D p1, Vector2D p2) {
310 return p1.distanceInf(p2);
311 }
312
313 /** Compute the square of the distance between two vectors.
314 * <p>Calling this method is equivalent to calling:
315 * <code>p1.subtract(p2).getNormSq()</code> except that no intermediate
316 * vector is built</p>
317 * @param p1 first vector
318 * @param p2 second vector
319 * @return the square of the distance between p1 and p2
320 */
321 public static double distanceSq(Vector2D p1, Vector2D p2) {
322 return p1.distanceSq(p2);
323 }
324
325 /**
326 * Test for the equality of two 2D vectors.
327 * <p>
328 * If all coordinates of two 2D vectors are exactly the same, and none are
329 * <code>Double.NaN</code>, the two 2D vectors are considered to be equal.
330 * </p>
331 * <p>
332 * <code>NaN</code> coordinates are considered to affect globally the vector
333 * and be equals to each other - i.e, if either (or all) coordinates of the
334 * 2D vector are equal to <code>Double.NaN</code>, the 2D vector is equal to
335 * {@link #NaN}.
336 * </p>
337 *
338 * @param other Object to test for equality to this
339 * @return true if two 2D vector objects are equal, false if
340 * object is null, not an instance of Vector2D, or
341 * not equal to this Vector2D instance
342 *
343 */
344 @Override
345 public boolean equals(Object other) {
346
347 if (this == other) {
348 return true;
349 }
350
351 if (other instanceof Vector2D) {
352 final Vector2D rhs = (Vector2D)other;
353 if (rhs.isNaN()) {
354 return this.isNaN();
355 }
356
357 return (x == rhs.x) && (y == rhs.y);
358 }
359 return false;
360 }
361
362 /**
363 * Get a hashCode for the 2D vector.
364 * <p>
365 * All NaN values have the same hash code.</p>
366 *
367 * @return a hash code value for this object
368 */
369 @Override
370 public int hashCode() {
371 if (isNaN()) {
372 return 542;
373 }
374 return 122 * (76 * MathUtils.hash(x) + MathUtils.hash(y));
375 }
376
377 /** Get a string representation of this vector.
378 * @return a string representation of this vector
379 */
380 @Override
381 public String toString() {
382 return Vector2DFormat.getInstance().format(this);
383 }
384
385 /** {@inheritDoc} */
386 public String toString(final NumberFormat format) {
387 return new Vector2DFormat(format).format(this);
388 }
389
390 }