1 package net.sf.openrocket.util;
3 import java.io.Serializable;
6 * An immutable class of weighted coordinates. The weights are non-negative.
8 * Can also be used as non-weighted coordinates with weight=0.
10 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
12 public final class Coordinate implements Serializable {
14 //////// Debug section
16 * Debugging info. If openrocket.debug.coordinatecount is defined, a line is
17 * printed every 1000000 instantiations (or as many as defined).
19 private static final boolean COUNT_DEBUG;
20 private static final int COUNT_DIFF;
22 String str = System.getProperty("openrocket.debug.coordinatecount", null);
30 diff = Integer.parseInt(str);
31 } catch (NumberFormatException ignore) { }
38 private static int count = 0;
43 if ((count % COUNT_DIFF) == 0) {
44 System.out.println("Coordinate instantiated " + count + " times.");
49 //////// End debug section
54 public static final Coordinate NUL = new Coordinate(0,0,0,0);
55 public static final Coordinate NaN = new Coordinate(Double.NaN,Double.NaN,
56 Double.NaN,Double.NaN);
58 public final double x,y,z;
59 public final double weight;
62 private double length = -1; /* Cached when calculated */
71 public Coordinate(double x) {
75 public Coordinate(double x, double y) {
79 public Coordinate(double x, double y, double z) {
82 public Coordinate(double x, double y, double z, double w) {
91 public boolean isWeighted() {
95 public boolean isNaN() {
96 return Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z) || Double.isNaN(weight);
99 public Coordinate setX(double x) {
100 return new Coordinate(x,this.y,this.z,this.weight);
103 public Coordinate setY(double y) {
104 return new Coordinate(this.x,y,this.z,this.weight);
107 public Coordinate setZ(double z) {
108 return new Coordinate(this.x,this.y,z,this.weight);
111 public Coordinate setWeight(double weight) {
112 return new Coordinate(this.x, this.y, this.z, weight);
115 public Coordinate setXYZ(Coordinate c) {
116 return new Coordinate(c.x, c.y, c.z, this.weight);
121 * Add the coordinate and weight of two coordinates.
123 * @param other the other <code>Coordinate</code>
124 * @return the sum of the coordinates
126 public Coordinate add(Coordinate other) {
127 return new Coordinate(this.x+other.x, this.y+other.y, this.z+other.z,
128 this.weight+other.weight);
131 public Coordinate add(double x, double y, double z) {
132 return new Coordinate(this.x+x, this.y+y, this.z+z, this.weight);
135 public Coordinate add(double x, double y, double z, double weight) {
136 return new Coordinate(this.x+x, this.y+y, this.z+z, this.weight+weight);
140 * Subtract a Coordinate from this Coordinate. The weight of the resulting Coordinate
141 * is the same as of this Coordinate, the weight of the argument is ignored.
143 * @param other Coordinate to subtract from this.
146 public Coordinate sub(Coordinate other) {
147 return new Coordinate(this.x-other.x, this.y-other.y, this.z-other.z, this.weight);
151 * Subtract the specified values from this Coordinate. The weight of the result
152 * is the same as the weight of this Coordinate.
154 * @param x x value to subtract
155 * @param y y value to subtract
156 * @param z z value to subtract
157 * @return the result.
159 public Coordinate sub(double x, double y, double z) {
160 return new Coordinate(this.x - x, this.y - y, this.z - z, this.weight);
165 * Multiply the <code>Coordinate</code> with a scalar. All coordinates and the
166 * weight are multiplied by the given scalar.
168 * @param m Factor to multiply by.
169 * @return The product.
171 public Coordinate multiply(double m) {
172 return new Coordinate(this.x*m, this.y*m, this.z*m, this.weight*m);
176 * Dot product of two Coordinates, taken as vectors. Equal to
178 * @param other Coordinate to take product with.
179 * @return The dot product.
181 public double dot(Coordinate other) {
182 return this.x*other.x + this.y*other.y + this.z*other.z;
185 * Dot product of two Coordinates.
187 public static double dot(Coordinate v1, Coordinate v2) {
188 return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
192 * Distance from the origin to the Coordinate.
194 public double length() {
196 length = Math.sqrt(x*x+y*y+z*z);
202 * Square of the distance from the origin to the Coordinate.
204 public double length2() {
209 * Returns a new coordinate which has the same direction from the origin as this
210 * coordinate but is at a distance of one. If this coordinate is the origin,
211 * this method throws an <code>IllegalStateException</code>. The weight of the
212 * coordinate is unchanged.
214 * @return the coordinate normalized to distance one of the origin.
215 * @throws IllegalStateException if this coordinate is the origin.
217 public Coordinate normalize() {
220 throw new IllegalStateException("Cannot normalize zero coordinate");
222 return new Coordinate(x/l, y/l, z/l, weight);
229 * Weighted average of two coordinates. If either of the weights are positive,
230 * the result is the weighted average of the coordinates and the weight is the sum
231 * of the original weights. If the sum of the weights is zero (and especially if
232 * both of the weights are zero), the result is the unweighted average of the
233 * coordinates with weight zero.
235 * If <code>other</code> is <code>null</code> then this <code>Coordinate</code> is
238 public Coordinate average(Coordinate other) {
244 w = this.weight + other.weight;
245 if (Math.abs(w) < MathUtil.pow2(MathUtil.EPSILON)) {
246 x = (this.x+other.x)/2;
247 y = (this.y+other.y)/2;
248 z = (this.z+other.z)/2;
251 x = (this.x*this.weight + other.x*other.weight)/w;
252 y = (this.y*this.weight + other.y*other.weight)/w;
253 z = (this.z*this.weight + other.z*other.weight)/w;
255 return new Coordinate(x,y,z,w);
260 * Tests whether the coordinates (not weight!) are the same.
262 * Compares only the (x,y,z) coordinates, NOT the weight. Coordinate comparison is
263 * done to the precision of COMPARISON_DELTA.
265 * @param other Coordinate to compare to.
266 * @return true if the coordinates are equal
269 public boolean equals(Object other) {
270 if (!(other instanceof Coordinate))
273 final Coordinate c = (Coordinate)other;
274 return (MathUtil.equals(this.x, c.x) &&
275 MathUtil.equals(this.y, c.y) &&
276 MathUtil.equals(this.z, c.z));
280 * Hash code method compatible with {@link #equals(Object)}.
283 public int hashCode() {
284 return (int)((x+y+z)*100000);
289 public String toString() {
291 return String.format("(%.3f,%.3f,%.3f,w=%.3f)", x,y,z,weight);
293 return String.format("(%.3f,%.3f,%.3f)", x,y,z);