~ubuntu-branches/ubuntu/quantal/commons-math/quantal

« back to all changes in this revision

Viewing changes to src/java/org/apache/commons/math/geometry/Vector3D.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-03-15 20:20:21 UTC
  • Revision ID: james.westby@ubuntu.com-20090315202021-zto3nmvqgcf3ami4
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) 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 ASF 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
 *      http://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
 
 
18
package org.apache.commons.math.geometry;
 
19
 
 
20
import java.io.Serializable;
 
21
 
 
22
/** 
 
23
 * This class implements vectors in a three-dimensional space.
 
24
 * <p>Instance of this class are guaranteed to be immutable.</p>
 
25
 * @version $Revision: 627998 $ $Date: 2008-02-15 03:24:50 -0700 (Fri, 15 Feb 2008) $
 
26
 * @since 1.2
 
27
 */
 
28
 
 
29
public class Vector3D
 
30
  implements Serializable {
 
31
 
 
32
  /** First canonical vector (coordinates: 1, 0, 0). */
 
33
  public static final Vector3D plusI = new Vector3D(1, 0, 0);
 
34
 
 
35
  /** Opposite of the first canonical vector (coordinates: -1, 0, 0). */
 
36
  public static final Vector3D minusI = new Vector3D(-1, 0, 0);
 
37
 
 
38
  /** Second canonical vector (coordinates: 0, 1, 0). */
 
39
  public static final Vector3D plusJ = new Vector3D(0, 1, 0);
 
40
 
 
41
  /** Opposite of the second canonical vector (coordinates: 0, -1, 0). */
 
42
  public static final Vector3D minusJ = new Vector3D(0, -1, 0);
 
43
 
 
44
  /** Third canonical vector (coordinates: 0, 0, 1). */
 
45
  public static final Vector3D plusK = new Vector3D(0, 0, 1);
 
46
 
 
47
  /** Opposite of the third canonical vector (coordinates: 0, 0, -1).  */
 
48
  public static final Vector3D minusK = new Vector3D(0, 0, -1);
 
49
 
 
50
  /** Null vector (coordinates: 0, 0, 0). */
 
51
  public static final Vector3D zero   = new Vector3D(0, 0, 0);
 
52
 
 
53
  /** Simple constructor.
 
54
   * Build a null vector.
 
55
   */
 
56
  public Vector3D() {
 
57
    x = 0;
 
58
    y = 0;
 
59
    z = 0;
 
60
  }
 
61
 
 
62
  /** Simple constructor.
 
63
   * Build a vector from its coordinates
 
64
   * @param x abscissa
 
65
   * @param y ordinate
 
66
   * @param z height
 
67
   * @see #getX()
 
68
   * @see #getY()
 
69
   * @see #getZ()
 
70
   */
 
71
  public Vector3D(double x, double y, double z) {
 
72
    this.x = x;
 
73
    this.y = y;
 
74
    this.z = z;
 
75
  }
 
76
 
 
77
  /** Simple constructor.
 
78
   * Build a vector from its azimuthal coordinates
 
79
   * @param alpha azimuth (&alpha;) around Z
 
80
   *              (0 is +X, &pi;/2 is +Y, &pi; is -X and 3&pi;/2 is -Y)
 
81
   * @param delta elevation (&delta;) above (XY) plane, from -&pi;/2 to +&pi;/2
 
82
   * @see #getAlpha()
 
83
   * @see #getDelta()
 
84
   */
 
85
  public Vector3D(double alpha, double delta) {
 
86
    double cosDelta = Math.cos(delta);
 
87
    this.x = Math.cos(alpha) * cosDelta;
 
88
    this.y = Math.sin(alpha) * cosDelta;
 
89
    this.z = Math.sin(delta);
 
90
  }
 
91
 
 
92
  /** Multiplicative constructor
 
93
   * Build a vector from another one and a scale factor. 
 
94
   * The vector built will be a * u
 
95
   * @param a scale factor
 
96
   * @param u base (unscaled) vector
 
97
   */
 
98
  public Vector3D(double a, Vector3D u) {
 
99
    this.x = a * u.x;
 
100
    this.y = a * u.y;
 
101
    this.z = a * u.z;
 
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 Vector3D(double a1, Vector3D u1, double a2, Vector3D u2) {
 
113
    this.x = a1 * u1.x + a2 * u2.x;
 
114
    this.y = a1 * u1.y + a2 * u2.y;
 
115
    this.z = a1 * u1.z + a2 * u2.z;
 
116
  }
 
117
 
 
118
  /** Linear constructor
 
119
   * Build a vector from three other ones and corresponding scale factors.
 
120
   * The vector built will be a1 * u1 + a2 * u2 + a3 * u3
 
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
   * @param a3 third scale factor
 
126
   * @param u3 third base (unscaled) vector
 
127
   */
 
128
  public Vector3D(double a1, Vector3D u1, double a2, Vector3D u2,
 
129
                  double a3, Vector3D u3) {
 
130
    this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x;
 
131
    this.y = a1 * u1.y + a2 * u2.y + a3 * u3.y;
 
132
    this.z = a1 * u1.z + a2 * u2.z + a3 * u3.z;
 
133
  }
 
134
 
 
135
  /** Linear constructor
 
136
   * Build a vector from four other ones and corresponding scale factors.
 
137
   * The vector built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4
 
138
   * @param a1 first scale factor
 
139
   * @param u1 first base (unscaled) vector
 
140
   * @param a2 second scale factor
 
141
   * @param u2 second base (unscaled) vector
 
142
   * @param a3 third scale factor
 
143
   * @param u3 third base (unscaled) vector
 
144
   * @param a4 fourth scale factor
 
145
   * @param u4 fourth base (unscaled) vector
 
146
   */
 
147
  public Vector3D(double a1, Vector3D u1, double a2, Vector3D u2,
 
148
                  double a3, Vector3D u3, double a4, Vector3D u4) {
 
149
    this.x = a1 * u1.x + a2 * u2.x + a3 * u3.x + a4 * u4.x;
 
150
    this.y = a1 * u1.y + a2 * u2.y + a3 * u3.y + a4 * u4.y;
 
151
    this.z = a1 * u1.z + a2 * u2.z + a3 * u3.z + a4 * u4.z;
 
152
  }
 
153
 
 
154
  /** Get the abscissa of the vector.
 
155
   * @return abscissa of the vector
 
156
   * @see #Vector3D(double, double, double)
 
157
   */
 
158
  public double getX() {
 
159
    return x;
 
160
  }
 
161
 
 
162
  /** Get the ordinate of the vector.
 
163
   * @return ordinate of the vector
 
164
   * @see #Vector3D(double, double, double)
 
165
   */
 
166
  public double getY() {
 
167
    return y;
 
168
  }
 
169
 
 
170
  /** Get the height of the vector.
 
171
   * @return height of the vector
 
172
   * @see #Vector3D(double, double, double)
 
173
   */
 
174
  public double getZ() {
 
175
    return z;
 
176
  }
 
177
 
 
178
  /** Get the norm for the vector.
 
179
   * @return euclidian norm for the vector
 
180
   */
 
181
  public double getNorm() {
 
182
    return Math.sqrt (x * x + y * y + z * z);
 
183
  }
 
184
 
 
185
  /** Get the azimuth of the vector.
 
186
   * @return azimuth (&alpha;) of the vector, between -&pi; and +&pi;
 
187
   * @see #Vector3D(double, double)
 
188
   */
 
189
  public double getAlpha() {
 
190
    return Math.atan2(y, x);
 
191
  }
 
192
 
 
193
  /** Get the elevation of the vector.
 
194
   * @return elevation (&delta;) of the vector, between -&pi;/2 and +&pi;/2
 
195
   * @see #Vector3D(double, double)
 
196
   */
 
197
  public double getDelta() {
 
198
    return Math.asin(z / getNorm());
 
199
  }
 
200
 
 
201
  /** Add a vector to the instance.
 
202
   * @param v vector to add
 
203
   * @return a new vector
 
204
   */
 
205
  public Vector3D add(Vector3D v) {
 
206
    return new Vector3D(x + v.x, y + v.y, z + v.z);
 
207
  }
 
208
 
 
209
  /** Add a scaled vector to the instance.
 
210
   * @param factor scale factor to apply to v before adding it
 
211
   * @param v vector to add
 
212
   * @return a new vector
 
213
   */
 
214
  public Vector3D add(double factor, Vector3D v) {
 
215
    return new Vector3D(x + factor * v.x, y + factor * v.y, z + factor * v.z);
 
216
  }
 
217
 
 
218
  /** Subtract a vector from the instance.
 
219
   * @param v vector to subtract
 
220
   * @return a new vector
 
221
   */
 
222
  public Vector3D subtract(Vector3D v) {
 
223
    return new Vector3D(x - v.x, y - v.y, z - v.z);
 
224
  }
 
225
 
 
226
  /** Subtract a scaled vector from the instance.
 
227
   * @param factor scale factor to apply to v before subtracting it
 
228
   * @param v vector to subtract
 
229
   * @return a new vector
 
230
   */
 
231
  public Vector3D subtract(double factor, Vector3D v) {
 
232
    return new Vector3D(x - factor * v.x, y - factor * v.y, z - factor * v.z);
 
233
  }
 
234
 
 
235
  /** Get a normalized vector aligned with the instance.
 
236
   * @return a new normalized vector
 
237
   * @exception ArithmeticException if the norm is zero
 
238
   */
 
239
  public Vector3D normalize() {
 
240
    double s = getNorm();
 
241
    if (s == 0) {
 
242
      throw new ArithmeticException("cannot normalize a zero norm vector");
 
243
    }
 
244
    return scalarMultiply(1 / s);
 
245
  }
 
246
 
 
247
  /** Get a vector orthogonal to the instance.
 
248
   * <p>There are an infinite number of normalized vectors orthogonal
 
249
   * to the instance. This method picks up one of them almost
 
250
   * arbitrarily. It is useful when one needs to compute a reference
 
251
   * frame with one of the axes in a predefined direction. The
 
252
   * following example shows how to build a frame having the k axis
 
253
   * aligned with the known vector u :
 
254
   * <pre><code>
 
255
   *   Vector3D k = u.normalize();
 
256
   *   Vector3D i = k.orthogonal();
 
257
   *   Vector3D j = Vector3D.crossProduct(k, i);
 
258
   * </code></pre></p>
 
259
   * @return a new normalized vector orthogonal to the instance
 
260
   * @exception ArithmeticException if the norm of the instance is null
 
261
   */
 
262
  public Vector3D orthogonal() {
 
263
 
 
264
    double threshold = 0.6 * getNorm();
 
265
    if (threshold == 0) {
 
266
      throw new ArithmeticException("null norm");
 
267
    }
 
268
 
 
269
    if ((x >= -threshold) && (x <= threshold)) {
 
270
      double inverse  = 1 / Math.sqrt(y * y + z * z);
 
271
      return new Vector3D(0, inverse * z, -inverse * y);
 
272
    } else if ((y >= -threshold) && (y <= threshold)) {
 
273
      double inverse  = 1 / Math.sqrt(x * x + z * z);
 
274
      return new Vector3D(-inverse * z, 0, inverse * x);
 
275
    }
 
276
    double inverse  = 1 / Math.sqrt(x * x + y * y);
 
277
    return new Vector3D(inverse * y, -inverse * x, 0);
 
278
 
 
279
  }
 
280
 
 
281
  /** Compute the angular separation between two vectors.
 
282
   * <p>This method computes the angular separation between two
 
283
   * vectors using the dot product for well separated vectors and the
 
284
   * cross product for almost aligned vectors. This allow to have a
 
285
   * good accuracy in all cases, even for vectors very close to each
 
286
   * other.</p>
 
287
   * @param v1 first vector
 
288
   * @param v2 second vector
 
289
   * @return angular separation between v1 and v2
 
290
   * @exception ArithmeticException if either vector has a null norm
 
291
   */
 
292
  public static double angle(Vector3D v1, Vector3D v2) {
 
293
 
 
294
    double normProduct = v1.getNorm() * v2.getNorm();
 
295
    if (normProduct == 0) {
 
296
      throw new ArithmeticException("null norm");
 
297
    }
 
298
 
 
299
    double dot = dotProduct(v1, v2);
 
300
    double threshold = normProduct * 0.9999;
 
301
    if ((dot < -threshold) || (dot > threshold)) {
 
302
      // the vectors are almost aligned, compute using the sine
 
303
      Vector3D v3 = crossProduct(v1, v2);
 
304
      if (dot >= 0) {
 
305
        return Math.asin(v3.getNorm() / normProduct);
 
306
      }
 
307
      return Math.PI - Math.asin(v3.getNorm() / normProduct);
 
308
    }
 
309
    
 
310
    // the vectors are sufficiently separated to use the cosine
 
311
    return Math.acos(dot / normProduct);
 
312
 
 
313
  }
 
314
 
 
315
  /** Get the opposite of the instance.
 
316
   * @return a new vector which is opposite to the instance
 
317
   */
 
318
  public Vector3D negate() {
 
319
    return new Vector3D(-x, -y, -z);
 
320
  }
 
321
 
 
322
  /** Multiply the instance by a scalar
 
323
   * @param a scalar
 
324
   * @return a new vector
 
325
   */
 
326
  public Vector3D scalarMultiply(double a) {
 
327
    return new Vector3D(a * x, a * y, a * z);
 
328
  }
 
329
 
 
330
  /** Compute the dot-product of two vectors.
 
331
   * @param v1 first vector
 
332
   * @param v2 second vector
 
333
   * @return the dot product v1.v2
 
334
   */
 
335
  public static double dotProduct(Vector3D v1, Vector3D v2) {
 
336
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
 
337
  }
 
338
 
 
339
  /** Compute the cross-product of two vectors.
 
340
   * @param v1 first vector
 
341
   * @param v2 second vector
 
342
   * @return the cross product v1 ^ v2 as a new Vector
 
343
   */
 
344
  public static Vector3D crossProduct(Vector3D v1, Vector3D v2) {
 
345
    return new Vector3D(v1.y * v2.z - v1.z * v2.y,
 
346
                        v1.z * v2.x - v1.x * v2.z,
 
347
                        v1.x * v2.y - v1.y * v2.x);
 
348
  }
 
349
 
 
350
  /** Abscissa. */
 
351
  private final double x;
 
352
 
 
353
  /** Ordinate. */
 
354
  private final double y;
 
355
 
 
356
  /** Height. */
 
357
  private final double z;
 
358
 
 
359
  /** Serializable version identifier */
 
360
  private static final long serialVersionUID = -5721105387745193385L;
 
361
 
 
362
 
 
363
}