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 
13 package org.locationtech.jts.math;
14 
15 import org.locationtech.jts.geom.Coordinate;
16 
17 /**
18  * Represents a vector in 3-dimensional Cartesian space.
19  *
20  * @author mdavis
21  *
22  */
23 public class Vector3D {
24 
25 	/**
26 	 * Computes the dot product of the 3D vectors AB and CD.
27 	 *
28 	 * @param A the start point of the first vector
29 	 * @param B the end point of the first vector
30 	 * @param C the start point of the second vector
31 	 * @param D the end point of the second vector
32 	 * @return the dot product
33 	 */
dot(Coordinate A, Coordinate B, Coordinate C, Coordinate D)34 	public static double dot(Coordinate A, Coordinate B, Coordinate C, Coordinate D)
35 	{
36 		double ABx = B.x - A.x;
37 		double ABy = B.y - A.y;
38 		double ABz = B.getZ() - A.getZ();
39 		double CDx = D.x - C.x;
40 		double CDy = D.y - C.y;
41 		double CDz = D.getZ() - C.getZ();
42 		return ABx*CDx + ABy*CDy + ABz*CDz;
43 	}
44 
45   /**
46    * Creates a new vector with given X, Y and Z components.
47    *
48    * @param x the X component
49    * @param y the Y component
50    * @param z the Z component
51    * @return a new vector
52    */
create(double x, double y, double z)53   public static Vector3D create(double x, double y, double z) {
54     return new Vector3D(x, y, z);
55   }
56 
57   /**
58    * Creates a vector from a 3D {@link Coordinate}.
59    * The coordinate should have the
60    * X,Y and Z ordinates specified.
61    *
62    * @param coord the Coordinate to copy
63    * @return a new vector
64    */
create(Coordinate coord)65   public static Vector3D create(Coordinate coord) {
66     return new Vector3D(coord);
67   }
68 
69 	/**
70 	 * Computes the 3D dot-product of two {@link Coordinate}s.
71 	 *
72    * @param v1 the first vector
73    * @param v2 the second vector
74 	 * @return the dot product of the vectors
75 	 */
dot(Coordinate v1, Coordinate v2)76 	public static double dot(Coordinate v1, Coordinate v2) {
77 		return v1.x * v2.x + v1.y * v2.y + v1.getZ() * v2.getZ();
78 	}
79 
80 	private double x;
81 	private double y;
82 	private double z;
83 
84   /**
85    * Creates a new 3D vector from a {@link Coordinate}. The coordinate should have
86    * the X,Y and Z ordinates specified.
87    *
88    * @param coord the Coordinate to copy
89    * @return a new vector
90    */
Vector3D(Coordinate v)91   public Vector3D(Coordinate v) {
92     x = v.x;
93     y = v.y;
94     z = v.getZ();
95   }
96 
97   /**
98    * Creates a vector with the direction and magnitude
99    * of the difference between the
100    * <tt>to</tt> and <tt>from</tt> {@link Coordinate}s.
101    *
102    * @param from the origin Coordinate
103    * @param to the destination Coordinate
104    * @return a new vector
105    */
Vector3D(Coordinate from, Coordinate to)106 	public Vector3D(Coordinate from, Coordinate to) {
107 		x = to.x - from.x;
108 		y = to.y - from.y;
109 		z = to.getZ() - from.getZ();
110 	}
111 
112 	/**
113 	 * Creates a vector with the givne components.
114 	 *
115 	 * @param x the X component
116 	 * @param y the Y component
117 	 * @param z the Z component
118 	 */
Vector3D(double x, double y, double z)119 	public Vector3D(double x, double y, double z) {
120 		this.x = x;
121 		this.y = y;
122 		this.z = z;
123 	}
124 
125 	/**
126 	 * Gets the X component of this vector.
127 	 *
128 	 * @return the value of the X component
129 	 */
getX()130 	public double getX() {
131 		return x;
132 	}
133 
134   /**
135    * Gets the Y component of this vector.
136    *
137    * @return the value of the Y component
138    */
getY()139 	public double getY() {
140 		return y;
141 	}
142 
143   /**
144    * Gets the Z component of this vector.
145    *
146    * @return the value of the Z component
147    */
getZ()148 	public double getZ() {
149 		return z;
150 	}
151 
152 	/**
153 	 * Computes a vector which is the sum
154 	 * of this vector and the given vector.
155 	 *
156 	 * @param v the vector to add
157 	 * @return the sum of this and <code>v</code>
158 	 */
add(Vector3D v)159 	public Vector3D add(Vector3D v) {
160 		return create(x + v.x, y + v.y, z + v.z);
161 	}
162 
163 	/**
164    * Computes a vector which is the difference
165    * of this vector and the given vector.
166    *
167    * @param v the vector to subtract
168    * @return the difference of this and <code>v</code>
169    */
subtract(Vector3D v)170 	public Vector3D subtract(Vector3D v) {
171 		return create(x - v.x, y - v.y, z - v.z);
172 	}
173 
174   /**
175    * Creates a new vector which has the same direction
176    * and with length equals to the length of this vector
177    * divided by the scalar value <code>d</code>.
178    *
179    * @param d the scalar divisor
180    * @return a new vector with divided length
181    */
divide(double d)182   public Vector3D divide(double d) {
183     return create(x / d, y / d, z / d);
184   }
185 
186   /**
187    * Computes the dot-product of two vectors
188    *
189    * @param v a vector
190    * @return the dot product of the vectors
191    */
dot(Vector3D v)192   public double dot(Vector3D v) {
193     return x * v.x + y * v.y + z * v.z;
194   }
195 
196 	/**
197    * Computes the length of this vector.
198    *
199    * @return the length of the vector
200    */
length()201 	public double length() {
202 		return Math.sqrt(x * x + y * y + z * z);
203 	}
204 
205 	/**
206 	 * Computes the length of a vector.
207 	 *
208 	 * @param v a coordinate representing a 3D vector
209 	 * @return the length of the vector
210 	 */
length(Coordinate v)211 	public static double length(Coordinate v) {
212 		return Math.sqrt(v.x * v.x + v.y * v.y + v.getZ() * v.getZ());
213 	}
214 
215   /**
216    * Computes a vector having identical direction
217    * but normalized to have length 1.
218    *
219    * @return a new normalized vector
220    */
normalize()221 	public Vector3D normalize() {
222 		double length = length();
223 		if (length > 0.0)
224 			return divide(length());
225 		return create(0.0, 0.0, 0.0);
226 	}
227 
228   /**
229    * Computes a vector having identical direction
230    * but normalized to have length 1.
231    *
232    * @param v a coordinate representing a 3D vector
233    * @return a coordinate representing the normalized vector
234    */
normalize(Coordinate v)235   public static Coordinate normalize(Coordinate v) {
236     double len = length(v);
237     return new Coordinate(v.x / len, v.y / len, v.getZ() / len);
238   }
239 
240   /**
241    * Gets a string representation of this vector
242    *
243    * @return a string representing this vector
244    */
toString()245   public String toString() {
246     return "[" + x + ", " + y + ", " + z + "]";
247   }
248 
249   /**
250    * Tests if a vector <tt>o</tt> has the same values for the components.
251    *
252    * @param o a <tt>Vector3D</tt> with which to do the comparison.
253    * @return true if <tt>other</tt> is a <tt>Vector3D</tt> with the same values
254    *         for the x and y components.
255    */
equals(Object o)256   public boolean equals(Object o) {
257     if ( !(o instanceof Vector3D) ) {
258       return false;
259     }
260     Vector3D v = (Vector3D) o;
261     return x == v.x && y == v.y && z == v.z;
262   }
263 
264   /**
265    * Gets a hashcode for this vector.
266    *
267    * @return a hashcode for this vector
268    */
hashCode()269   public int hashCode() {
270     // Algorithm from Effective Java by Joshua Bloch
271     int result = 17;
272     result = 37 * result + Coordinate.hashCode(x);
273     result = 37 * result + Coordinate.hashCode(y);
274     result = 37 * result + Coordinate.hashCode(z);
275     return result;
276   }
277 
278 }
279