Class Vector2D

  1 /*
  2  * Copyright (c) 2016 Martin Davis.
  3  *
  4  * All rights reserved. This program and the accompanying materials
  5  * are made available under the terms of the Eclipse Public License 2.0
  6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  8  * and the Eclipse Distribution License is available at
  9  *
 10  * http://www.eclipse.org/org/documents/edl-v10.php.
 11  */
 12 package org.locationtech.jts.math;
 13  
 14 import org.locationtech.jts.algorithm.Angle;
 15 import org.locationtech.jts.algorithm.CGAlgorithmsDD;
 16 import org.locationtech.jts.geom.Coordinate;
 17 import org.locationtech.jts.util.Assert;
 18  
 19 /**
 20  * A 2-dimensional mathematical vector represented by double-precision X and Y components.
 21  * 
 22  * @author mbdavis
 23  * 
 24  */
 25 public class Vector2D {
 26   /**
 27    * Creates a new vector with given X and Y components.
 28    * 
 29    * @param x the x component
 30    * @param y the y component
 31    * @return a new vector
 32    */
 33     public static Vector2D create(double x, double y) {
 34         return new Vector2D(x, y);
 35     }
 36  
 37   /**
 38    * Creates a new vector from an existing one.
 39    * 
 40    * @param v the vector to copy
 41    * @return a new vector
 42    */
 43     public static Vector2D create(Vector2D v) {
 44         return new Vector2D(v);
 45     }
 46  
 47   /**
 48    * Creates a vector from a {@link Coordinate}. 
 49    * 
 50    * @param coord the Coordinate to copy
 51    * @return a new vector
 52    */
 53     public static Vector2D create(Coordinate coord) {
 54         return new Vector2D(coord);
 55     }
 56  
 57   /**
 58    * Creates a vector with the direction and magnitude
 59    * of the difference between the 
 60    * <tt>to</tt> and <tt>from</tt> {@link Coordinate}s.
 61    * 
 62    * @param from the origin Coordinate
 63    * @param to the destination Coordinate
 64    * @return a new vector
 65    */
 66     public static Vector2D create(Coordinate from, Coordinate to) {
 67         return new Vector2D(from, to);
 68     }
 69  
 70     /**
 71      * The X component of this vector.
 72      */
 73     private double x;
 74  
 75     /**
 76      * The Y component of this vector.
 77      */
 78     private double y;
 79  
 80     public Vector2D() {
 81         this(0.00.0);
 82     }
 83  
 84     public Vector2D(double x, double y) {
 85         this.x = x;
 86         this.y = y;
 87     }
 88  
 89     public Vector2D(Vector2D v) {
 90         x = v.x;
 91         y = v.y;
 92     }
 93  
 94     public Vector2D(Coordinate from, Coordinate to) {
 95         x = to.x - from.x;
 96         y = to.y - from.y;
 97     }
 98  
 99     public Vector2D(Coordinate v) {
100         x = v.x;
101         y = v.y;
102     }
103  
104     public double getX() {
105         return x;
106     }
107  
108     public double getY() {
109         return y;
110     }
111  
112     public double getComponent(int index) {
113         if (index == 0)
114             return x;
115         return y;
116     }
117  
118     public Vector2D add(Vector2D v) {
119         return create(x + v.x, y + v.y);
120     }
121  
122     public Vector2D subtract(Vector2D v) {
123         return create(x - v.x, y - v.y);
124     }
125  
126   /**
127    * Multiplies the vector by a scalar value.
128    * 
129    * @param d the value to multiply by
130    * @return a new vector with the value v * d
131    */
132     public Vector2D multiply(double d) {
133         return create(x * d, y * d);
134     }
135  
136   /**
137    * Divides the vector by a scalar value.
138    * 
139    * @param d the value to divide by
140    * @return a new vector with the value v / d
141    */
142     public Vector2D divide(double d) {
143         return create(x / d, y / d);
144     }
145  
146     public Vector2D negate() {
147         return create(-x , -y);
148     }
149  
150     public double length() {
151         return Math.sqrt(x * x + y * y);
152     }
153  
154     public double lengthSquared() {
155         return x * x + y * y;
156     }
157  
158     public Vector2D normalize() {
159         double length = length();
160         if (length > 0.0)
161             return divide(length);
162         return create(0.00.0);
163     }
164  
165     public Vector2D average(Vector2D v) {
166         return weightedSum(v, 0.5);
167     }
168   
169     /**
170      * Computes the weighted sum of this vector
171      * with another vector,
172      * with this vector contributing a fraction
173      * of <tt>frac</tt> to the total.
174      * <p>
175      * In other words, 
176      * <pre>
177      * sum = frac * this + (1 - frac) * v
178      * </pre>
179      * 
180      * @param v the vector to sum
181      * @param frac the fraction of the total contributed by this vector
182      * @return the weighted sum of the two vectors
183      */
184     public Vector2D weightedSum(Vector2D v, double frac) {
185         return create(
186                 frac * x + (1.0 - frac) * v.x, 
187                 frac * y + (1.0 - frac) * v.y);
188     }
189  
190   /**
191    * Computes the distance between this vector and another one.
192    * @param v a vector
193    * @return the distance between the vectors
194    */
195   public double distance(Vector2D v)
196   {
197     double delx = v.x - x;
198     double dely = v.y - y;
199     return Math.sqrt(delx * delx + dely * dely);
200   }
201   
202     /**
203      * Computes the dot-product of two vectors
204      * 
205      * @param v a vector
206      * @return the dot product of the vectors
207      */
208     public double dot(Vector2D v) {
209         return x * v.x + y * v.y;
210     }
211  
212     public double angle()
213     {
214         return Math.atan2(y, x);
215     }
216     
217   public double angle(Vector2D v)
218   {
219     return Angle.diff(v.angle(), angle());
220   }
221   
222   public double angleTo(Vector2D v)
223   {
224     double a1 = angle();
225     double a2 = v.angle();
226     double angDel = a2 - a1;
227     
228     // normalize, maintaining orientation
229     if (angDel <= -Math.PI)
230       return angDel + Angle.PI_TIMES_2;
231     if (angDel > Math.PI)
232       return angDel - Angle.PI_TIMES_2;
233     return angDel;
234   }
235   
236     public Vector2D rotate(double angle)
237     {
238         double cos = Math.cos(angle);
239         double sin = Math.sin(angle);
240         return create(
241                 x * cos - y * sin,
242                 x * sin + y * cos
243                 );
244     }
245     
246     /**
247      * Rotates a vector by a given number of quarter-circles (i.e. multiples of 90
248      * degrees or Pi/2 radians). A positive number rotates counter-clockwise, a
249      * negative number rotates clockwise. Under this operation the magnitude of
250      * the vector and the absolute values of the ordinates do not change, only
251      * their sign and ordinate index.
252      * 
253      * @param numQuarters
254      *          the number of quarter-circles to rotate by
255      * @return the rotated vector.
256      */
257     public Vector2D rotateByQuarterCircle(int numQuarters) {
258         int nQuad = numQuarters % 4;
259         if (numQuarters < 0 && nQuad != 0) {
260             nQuad = nQuad + 4;
261         }
262         switch (nQuad) {
263         case 0:
264             return create(x, y);
265         case 1:
266             return create(-y, x);
267         case 2:
268             return create(-x, -y);
269         case 3:
270             return create(y, -x);
271         }
272         Assert.shouldNeverReachHere();
273         return null;
274     }
275  
276   public boolean isParallel(Vector2D v)
277   {
278     return 0.0 == CGAlgorithmsDD.signOfDet2x2(x, y, v.x, v.y);
279   }
280   
281     public Coordinate translate(Coordinate coord) {
282         return new Coordinate(x + coord.x, y + coord.y);
283     }
284  
285     public Coordinate toCoordinate() {
286         return new Coordinate(x, y);
287     }
288  
289   /**
290    * Creates a copy of this vector
291    * 
292    * @return a copy of this vector
293    */
294   public Object clone()
295   {
296     return new Vector2D(this);
297   }
298   
299   /**
300    * Gets a string representation of this vector
301    * 
302    * @return a string representing this vector
303    */
304     public String toString() {
305         return "[" + x + ", " + y + "]";
306     }
307     
308     /**
309      * Tests if a vector <tt>o</tt> has the same values for the x and y
310      * components.
311      * 
312      * @param o
313      *          a <tt>Vector2D</tt> with which to do the comparison.
314      * @return true if <tt>other</tt> is a <tt>Vector2D</tt> with the same
315      *         values for the x and y components.
316      */
317     public boolean equals(Object o) {
318         if (!(o instanceof Vector2D)) {
319             return false;
320         }
321         Vector2D v = (Vector2D) o;
322         return x == v.x && y == v.y;
323     }
324  
325     /**
326      * Gets a hashcode for this vector.
327      * 
328      * @return a hashcode for this vector
329      */
330     public int hashCode() {
331         // Algorithm from Effective Java by Joshua Bloch
332         int result = 17;
333         result = 37 * result + Coordinate.hashCode(x);
334         result = 37 * result + Coordinate.hashCode(y);
335         return result;
336     }
337  
338  
339 }
340