sim.util.MutableDouble2D Maven / Gradle / Ivy
Show all versions of mason Show documentation
/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.util;
/**
MutableDouble2D is more or less the same class as java.awt.geom.Point2D.Double, except that it is hash-equivalent to Double2D.
Just as with MutableInt2D: you use MutableDouble2D as a STORED hash key at your peril: it has the same misfeature as
java.awt.geom.Point2D.Double, and you should read the warning in Double2D. However, you can look up Double2D-keyed
objects in a hash table by passing in a MutableDouble2D instead.
*/
public final class MutableDouble2D implements java.io.Serializable, Cloneable
{
private static final long serialVersionUID = 1;
public double x;
public double y;
public MutableDouble2D() { x = 0.0; y = 0.0; }
public MutableDouble2D(final Int2D p) { x = p.x; y = p.y; }
public MutableDouble2D(final MutableInt2D p) { x = p.x; y = p.y; }
public MutableDouble2D(final MutableDouble2D p) { x = p.x; y = p.y; }
public MutableDouble2D(final Double2D p) { x = p.x; y = p.y; }
public MutableDouble2D(final java.awt.Point p) { x = p.x; y = p.y; }
public MutableDouble2D(final java.awt.geom.Point2D.Double p) { x = p.x; y = p.y; }
public MutableDouble2D(final java.awt.geom.Point2D.Float p) { x = p.x; y = p.y; }
/** Only included for completeness' sakes, in case a new Point2D subclass is created in the future. */
public MutableDouble2D(final java.awt.geom.Point2D p) { x = p.getX(); y = p.getY(); }
public MutableDouble2D(final double x, final double y) { this.x = x; this.y = y; }
public final double getX() { return x; }
public final double getY() { return y; }
public final void setX(double val) { x = val; }
public final void setY(double val) { y = val; }
public final void setTo(final double bx, final double by) { x = bx; y = by; }
public final void setTo(final Int2D b) { x = b.x; y = b.y; }
public final void setTo(final Double2D b) { x = b.x; y = b.y; }
public final void setTo(final MutableInt2D b) { x = b.x; y = b.y; }
public final void setTo(final MutableDouble2D b) { x = b.x; y = b.y; }
public String toString() { return "MutableDouble2D["+x+","+y+"]"; }
public String toCoordinates() { return "(" + x + ", " + y + ")"; }
public java.awt.geom.Point2D.Double toPoint2D() { return new java.awt.geom.Point2D.Double(x,y); }
public Object clone()
{
try
{
return super.clone();
}
catch(CloneNotSupportedException e)
{
return null; // never happens
}
}
// identical to Double2D
public final int hashCode()
{
double x = this.x;
double y = this.y;
// push -0.0 to 0.0 for purposes of hashing. Note that equals() has also been modified
// to consider -0.0 to be equal to 0.0. Hopefully cute Java compilers won't try to optimize this out.
if (x == -0.0) x = 0.0;
if (y == -0.0) y = 0.0;
// so we hash to the same value as Int2D does, if we're ints.
if ((((int)x) == x) && ((int)y) == y)
//return Int2D.hashCodeFor((int)x,(int)y);
{
int y_ = (int)y;
int x_ = (int)x;
// copied from Int2D and inserted here because hashCodeFor can't be
// inlined and this saves us a fair chunk on some hash-heavy applications
y_ += ~(y_ << 15);
y_ ^= (y_ >>> 10);
y_ += (y_ << 3);
y_ ^= (y_ >>> 6);
y_ += ~(y_ << 11);
y_ ^= (y_ >>> 16);
// nifty! Now mix in x
return x_ ^ y_;
}
// I don't like Sun's simplistic approach to random shuffling. So...
// basically we need to randomly disperse --> int
// We do this by doing -> -> long -> int
// The first step is done with doubleToLongBits (not RawLongBits;
// we want all NaN to hash to the same thing). Then conversion to
// a single long is done by hashing (shuffling) y, then xoring it with x.
// So I need something that will hash y to a nicely random value.
// this taken from http://www.cris.com/~Ttwang/tech/inthash.htm
// Last we fold the long onto itself to form the int.
// Some further discussion. Sun's moved to a new hash table scheme
// which has (of all things!) tables with lengths that are powers of two!
// Normally hash table lengths should be prime numbers, in order to
// compensate for bad hashcodes. To fix matters, Sun now is
// pre-shuffling the hashcodes with the following algorithm (which
// is short but not too bad -- should we adopt it? Dunno). See
// http://developer.java.sun.com/developer/bugParade/bugs/4669519.html
// key += ~(key << 9);
// key ^= (key >>> 14);
// key += (key << 4);
// key ^= (key >>> 10);
// This is good for us because Int2D, Int3D, MutableDouble2D, and Double3D
// have hashcodes well distributed with regard to y and z, but when
// you mix in x, they're just linear in x. We could do a final
// shuffle I guess. In Java 1.3, they DON'T do a pre-shuffle, so
// it may be suboptimal. Since we're all moving to 1.4.x, it's not
// a big deal since 1.4.x is shuffling the final result using the
// Sun shuffler above. But I'd appreciate some tests on our method
// below, and suggestions as to whether or not we should adopt the
// shorter, likely suboptimal but faster Sun shuffler instead
// for y and z values. -- Sean
long key = Double.doubleToLongBits(y);
key += ~(key << 32);
key ^= (key >>> 22);
key += ~(key << 13);
key ^= (key >>> 8);
key += (key << 3);
key ^= (key >>> 15);
key += ~(key << 27);
key ^= (key >>> 31);
// nifty! Now mix in x
key ^= Double.doubleToLongBits(x);
// Last we fold on top of each other
return (int)(key ^ (key >> 32));
}
// can't have separate equals(...) methods as the
// argument isn't virtual
public final boolean equals(final Object obj)
{
if (obj==null) return false;
else if (obj instanceof Double2D) // do Double2D first
{
Double2D other = (Double2D) obj;
// Note: commented out because it can't handle 0.0 == -0.0, grrr
return ((x == other.x || (Double.isNaN(x) && Double.isNaN(other.x))) && // they're the same or they're both NaN
(y == other.y || (Double.isNaN(y) && Double.isNaN(other.y)))); // they're the same or they're both NaN
// can't just do other.x == x && other.y == y because we need to check for NaN
// return (Double.doubleToLongBits(other.x) == Double.doubleToLongBits(x) &&
// Double.doubleToLongBits(other.y) == Double.doubleToLongBits(y));
}
if (obj instanceof MutableDouble2D)
{
MutableDouble2D other = (MutableDouble2D) obj;
// Note: commented out because it can't handle 0.0 == -0.0, grrr
return ((x == other.x || (Double.isNaN(x) && Double.isNaN(other.x))) && // they're the same or they're both NaN
(y == other.y || (Double.isNaN(y) && Double.isNaN(other.y)))); // they're the same or they're both NaN
// can't just do other.x == x && other.y == y because we need to check for NaN
// return (Double.doubleToLongBits(other.x) == Double.doubleToLongBits(x) &&
// Double.doubleToLongBits(other.y) == Double.doubleToLongBits(y));
}
else if (obj instanceof Int2D)
{
Int2D other = (Int2D) obj;
return (other.x == x && other.y == y);
}
else if (obj instanceof MutableInt2D)
{
MutableInt2D other = (MutableInt2D) obj;
return (other.x == x && other.y == y);
}
else return false;
}
/** Returns the distance FROM this MutableDouble2D TO the specified point */
public double distance(final double x, final double y)
{
final double dx = (double)this.x - x;
final double dy = (double)this.y - y;
return Math.sqrt(dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distance(final MutableDouble2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return Math.sqrt(dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distance(final Double2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return Math.sqrt(dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distance(final Int2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return Math.sqrt(dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distance(final MutableInt2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return Math.sqrt(dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distance(final java.awt.geom.Point2D p)
{
final double dx = (double)this.x - p.getX();
final double dy = (double)this.y - p.getY();
return Math.sqrt(dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point */
public double distanceSq(final double x, final double y)
{
final double dx = (double)this.x - x;
final double dy = (double)this.y - y;
return (dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distanceSq(final Double2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return (dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distanceSq(final MutableDouble2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return (dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distanceSq(final Int2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return (dx*dx+dy*dy);
}
/** Returns the distance FROM this MutableDouble2D TO the specified point. */
public double distanceSq(final MutableInt2D p)
{
final double dx = (double)this.x - p.x;
final double dy = (double)this.y - p.y;
return (dx*dx+dy*dy);
}
/** Returns the distance FROM this Point2D TO the specified point */
public double distanceSq(final java.awt.geom.Point2D p)
{
final double dx = (double)this.x - p.getX();
final double dy = (double)this.y - p.getY();
return (dx*dx+dy*dy);
}
/** Returns the manhtattan distance FROM this MuableDouble2D TO the specified point */
public double manhattanDistance(final double x, final double y)
{
final double dx = Math.abs((double)this.x - x);
final double dy = Math.abs((double)this.y - y);
return dx + dy;
}
/** Returns the manhtattan distance FROM this MuableDouble2D TO the specified point */
public double manhattanDistance(final Double2D p)
{
final double dx = Math.abs((double)this.x - p.x);
final double dy = Math.abs((double)this.y - p.y);
return dx + dy;
}
/** Returns the manhtattan distance FROM this MuableDouble2D TO the specified point */
public double manhattanDistance(final Int2D p)
{
final double dx = Math.abs((double)this.x - p.x);
final double dy = Math.abs((double)this.y - p.y);
return dx + dy;
}
/** Returns the manhtattan distance FROM this MuableDouble2D TO the specified point */
public double manhattanDistance(final MutableDouble2D p)
{
final double dx = Math.abs((double)this.x - p.x);
final double dy = Math.abs((double)this.y - p.y);
return dx + dy;
}
/** Returns the manhtattan distance FROM this MuableDouble2D TO the specified point */
public double manhattanDistance(final MutableInt2D p)
{
final double dx = Math.abs((double)this.x - p.x);
final double dy = Math.abs((double)this.y - p.y);
return dx + dy;
}
/** Returns the manhtattan distance FROM this MuableDouble2D TO the specified point */
public double manhattanDistance(final java.awt.geom.Point2D p)
{
final double dx = Math.abs((double)this.x - p.getX());
final double dy = Math.abs((double)this.y - p.getY());
return dx + dy;
}
/** Adds other into me, returning me. */
public final MutableDouble2D addIn(final Double2D other)
{
x = other.x + x;
y = other.y + y;
return this;
}
/** Adds other into me, returning me. */
public final MutableDouble2D addIn(final MutableDouble2D other)
{
x = other.x + x;
y = other.y + y;
return this;
}
/** Adds the x and y values into my x and y values, returning me. */
public final MutableDouble2D addIn(final double x, final double y)
{
this.x += x;
this.y += y;
return this;
}
/** Sets me to the sum of other1 and other2, returning me. */
public final MutableDouble2D add(final MutableDouble2D other1, final MutableDouble2D other2)
{
x = other1.x + other2.x;
y = other1.y + other2.y;
return this;
}
/** Sets me to the sum of other1 and other2, returning me. */
public final MutableDouble2D add(final Double2D other1, final MutableDouble2D other2)
{
x = other1.x + other2.x;
y = other1.y + other2.y;
return this;
}
/** Sets me to the sum of other1 and other2, returning me. */
public final MutableDouble2D add(final MutableDouble2D other1, final Double2D other2)
{
x = other1.x + other2.x;
y = other1.y + other2.y;
return this;
}
/** Equivalent to (new MutableDouble2D(d)), but (d.dup()) shorter of course, but perhaps not quite as fast. */
public final MutableDouble2D dup()
{
return new MutableDouble2D(this);
}
/** Sets me to me minus other, returning me. */
public final MutableDouble2D subtractIn(Double2D other)
{
x = x - other.x;
y = y - other.y;
return this;
}
/** Sets me to me minus other, returning me. */
public final MutableDouble2D subtractIn(MutableDouble2D other)
{
x = x - other.x;
y = y - other.y;
return this;
}
/** Subtracts other2 from other1, setting me to the result and returning me. */
public final MutableDouble2D subtract(MutableDouble2D other1, MutableDouble2D other2)
{
x = other1.x - other2.x;
y = other1.y - other2.y;
return this;
}
/** Subtracts other2 from other1, setting me to the result and returning me. */
public final MutableDouble2D subtract(Double2D other1, MutableDouble2D other2)
{
x = other1.x - other2.x;
y = other1.y - other2.y;
return this;
}
/** Subtracts other2 from other1, setting me to the result and returning me. */
public final MutableDouble2D subtract(MutableDouble2D other1, Double2D other2)
{
x = other1.x - other2.x;
y = other1.y - other2.y;
return this;
}
/** Returns the length of the vector. */
public final double length()
{
return Math.sqrt(x * x + y * y);
}
/** Returns the square of the length of the MutableDouble2D. */
public final double lengthSq()
{
return x*x+y*y;
}
/** Returns the length of the vector between -Pi and Pi. */
public final double angle()
{
return Math.atan2(y,x);
}
/** Extends my length so that it is multiplied by val, and returns me. */
public final MutableDouble2D multiplyIn(final double val)
{
x = x * val;
y = y * val;
return this;
}
/** Multiplies other by val, setting me to the result and returning me. */
public final MutableDouble2D multiply(MutableDouble2D other, final double val)
{
x = other.x * val;
y = other.y * val;
return this;
}
/** Multiplies other by val, setting me to the result and returning me. */
public final MutableDouble2D multiply(Double2D other, final double val)
{
x = other.x * val;
y = other.y * val;
return this;
}
/** Normalizes me (sets my length to 1.0), returning me. Throws an error if my previous length was of length 0. */
static final double infinity = 1.0 / 0.0;
public final MutableDouble2D normalize()
{
final double invertedlen = 1.0 / Math.sqrt(x * x + y * y);
if (invertedlen == infinity || invertedlen == -infinity || invertedlen == 0 || invertedlen != invertedlen /* nan */)
throw new ArithmeticException("" + this + " length is " + Math.sqrt(x * x + y * y) + ", cannot normalize");
x = x * invertedlen;
y = y * invertedlen;
return this;
}
/** Sets my length, which should be >= 0.
@deprecated use resize instead [renaming]
*/
public final MutableDouble2D setLength(double val) { return resize(val); }
/** Sets my length, which should be >= 0. */
public final MutableDouble2D resize(double val)
{
if (val < 0)
throw new IllegalArgumentException("The argument to MutableDouble2D.setLength(...) must be zero or positive");
if (val == 0) x = y = 0;
else
{
final double len = Math.sqrt(x * x + y * y);
if (len != len || len == infinity || len == -infinity || len == 0)
throw new ArithmeticException("" + this + " length is "+ len + " cannot change its length");
final double invertedlen = val / len;
x = x * invertedlen;
y = y * invertedlen;
}
return this;
}
/** Rotates me by theta radians, returning me. */
public final MutableDouble2D rotate(double theta)
{
// Do the equivalent of multiplying by a 2D rotation
// matrix without the overhead of converting the Double2D into
// a matrix
final double sinTheta = Math.sin(theta);
final double cosTheta = Math.cos(theta);
final double x = this.x;
final double y = this.y;
this.x = cosTheta * x + -sinTheta * y;
this.y = sinTheta * x + cosTheta * y;
return this;
}
/** Returns the dot product of myself against other, that is me DOT other. */
public final double dot(MutableDouble2D other)
{
return other.x * x + other.y * y;
}
/** 2D version of the cross product: returns the dot product of me rotated 90 degrees dotted
against the other vector. Does not modify either vector. */
public double perpDot(MutableDouble2D other)
{
return (-this.y) * other.x + this.x * other.y;
}
/** Sets the values to 0 and returns it. */
public final MutableDouble2D zero()
{
this.x = 0;
this.y = 0;
return this;
}
/** Sets the values to the negation of the values in the provided MutableDouble2D */
public final MutableDouble2D setToMinus(final MutableDouble2D b)
{
x = -b.x;
y = -b.y;
return this;
}
/** Negates the MutableDouble2D's values and returns it. */
public final MutableDouble2D negate()
{
x = -x;
y = -y;
return this;
}
}