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 }