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 MutableCoordinate implements Serializable {
13 public static final MutableCoordinate NUL = new MutableCoordinate(0,0,0,0);
14 public static final MutableCoordinate NaN = new MutableCoordinate(Double.NaN,Double.NaN,
15 Double.NaN,Double.NaN);
16 public static final double COMPARISON_DELTA = 0.000001;
18 private double weight;
21 /* Count and report the number of times a Coordinate is constructed: */
22 // private static int count=0;
25 // if ((count % 1000) == 0) {
26 // System.out.println("Coordinate instantiated "+count+" times");
31 public MutableCoordinate() {
38 public MutableCoordinate(double x) {
45 public MutableCoordinate(double x, double y) {
52 public MutableCoordinate(double x, double y, double z) {
58 public MutableCoordinate(double x, double y, double z, double w) {
66 public boolean isWeighted() {
70 public boolean isNaN() {
71 return Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z) || Double.isNaN(weight);
74 public MutableCoordinate setX(double x) {
75 return new MutableCoordinate(x,this.y,this.z,this.weight);
78 public MutableCoordinate setY(double y) {
79 return new MutableCoordinate(this.x,y,this.z,this.weight);
82 public MutableCoordinate setZ(double z) {
83 return new MutableCoordinate(this.x,this.y,z,this.weight);
86 public MutableCoordinate setWeight(double weight) {
87 return new MutableCoordinate(this.x, this.y, this.z, weight);
90 public MutableCoordinate setXYZ(MutableCoordinate c) {
91 return new MutableCoordinate(c.x, c.y, c.z, this.weight);
94 public double getX() {
97 public double getY() {
100 public double getZ() {
106 * Add the coordinate and weight of two coordinates.
108 * @param other the other <code>Coordinate</code>
109 * @return the sum of the coordinates
111 public MutableCoordinate add(MutableCoordinate other) {
115 this.weight += other.weight;
119 public MutableCoordinate add(double x, double y, double z) {
126 public MutableCoordinate add(double x, double y, double z, double weight) {
127 return new MutableCoordinate(this.x+x, this.y+y, this.z+z, this.weight+weight);
131 * Subtract a Coordinate from this Coordinate. The weight of the resulting Coordinate
132 * is the same as of this Coordinate, the weight of the argument is ignored.
134 * @param other Coordinate to subtract from this.
137 public MutableCoordinate sub(MutableCoordinate other) {
138 return new MutableCoordinate(this.x-other.x, this.y-other.y, this.z-other.z, this.weight);
142 * Subtract the specified values from this Coordinate. The weight of the result
143 * is the same as the weight of this Coordinate.
145 * @param x x value to subtract
146 * @param y y value to subtract
147 * @param z z value to subtract
148 * @return the result.
150 public MutableCoordinate sub(double x, double y, double z) {
151 return new MutableCoordinate(this.x - x, this.y - y, this.z - z, this.weight);
156 * Multiply the <code>Coordinate</code> with a scalar. All coordinates and the
157 * weight are multiplied by the given scalar.
159 * @param m Factor to multiply by.
160 * @return The product.
162 public MutableCoordinate multiply(double m) {
163 return new MutableCoordinate(this.x*m, this.y*m, this.z*m, this.weight*m);
167 * Dot product of two Coordinates, taken as vectors. Equal to
169 * @param other Coordinate to take product with.
170 * @return The dot product.
172 public double dot(MutableCoordinate other) {
173 return this.x*other.x + this.y*other.y + this.z*other.z;
176 * Dot product of two Coordinates.
178 public static double dot(MutableCoordinate v1, MutableCoordinate v2) {
179 return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
183 * Distance from the origin to the Coordinate.
185 public double length() {
186 return Math.sqrt(x*x+y*y+z*z);
190 * Square of the distance from the origin to the Coordinate.
192 public double length2() {
197 * Returns a new coordinate which has the same direction from the origin as this
198 * coordinate but is at a distance of one. If this coordinate is the origin,
199 * this method throws an <code>IllegalStateException</code>. The weight of the
200 * coordinate is unchanged.
202 * @return the coordinate normalized to distance one of the origin.
203 * @throws IllegalStateException if this coordinate is the origin.
205 public MutableCoordinate normalize() {
208 throw new IllegalStateException("Cannot normalize zero coordinate");
210 return new MutableCoordinate(x/l, y/l, z/l, weight);
217 * Weighted average of two coordinates. If either of the weights are positive,
218 * the result is the weighted average of the coordinates and the weight is the sum
219 * of the original weights. If the sum of the weights is zero (and especially if
220 * both of the weights are zero), the result is the unweighted average of the
221 * coordinates with weight zero.
223 * If <code>other</code> is <code>null</code> then this <code>Coordinate</code> is
226 public MutableCoordinate average(MutableCoordinate other) {
232 w = this.weight + other.weight;
233 if (MathUtil.equals(w, 0)) {
234 x = (this.x+other.x)/2;
235 y = (this.y+other.y)/2;
236 z = (this.z+other.z)/2;
239 x = (this.x*this.weight + other.x*other.weight)/w;
240 y = (this.y*this.weight + other.y*other.weight)/w;
241 z = (this.z*this.weight + other.z*other.weight)/w;
243 return new MutableCoordinate(x,y,z,w);
248 * Tests whether the coordinates (not weight!) are the same.
250 * Compares only the (x,y,z) coordinates, NOT the weight. Coordinate comparison is
251 * done to the precision of COMPARISON_DELTA.
253 * @param other Coordinate to compare to.
254 * @return true if the coordinates are equal
257 public boolean equals(Object other) {
258 if (!(other instanceof MutableCoordinate))
261 final MutableCoordinate c = (MutableCoordinate)other;
262 return (MathUtil.equals(this.x, c.x) &&
263 MathUtil.equals(this.y, c.y) &&
264 MathUtil.equals(this.z, c.z));
268 * Hash code method compatible with {@link #equals(Object)}.
271 public int hashCode() {
272 return (int)((x+y+z)*100000);
277 public String toString() {
279 return String.format("(%.3f,%.3f,%.3f,w=%.3f)", x,y,z,weight);
281 return String.format("(%.3f,%.3f,%.3f)", x,y,z);
286 public static void main(String[] arg) {
293 t1 = System.nanoTime();
294 for (int i=0; i < 100000000; i++) {
297 t2 = System.nanoTime();
298 System.out.println("Value: "+x);
299 System.out.println("Plain addition: "+ ((t2-t1+500000)/1000000) + " ms");
301 c = MutableCoordinate.NUL;
302 t1 = System.nanoTime();
303 for (int i=0; i < 100000000; i++) {
306 t2 = System.nanoTime();
307 System.out.println("Value: "+c.x);
308 System.out.println("Coordinate addition: "+ ((t2-t1+500000)/1000000) + " ms");