/* 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; /** MutableInt2D is largely a class identical to java.awt.Point, except that it is hash-equivalent to Int2D. It is used internally in SparseGrid2D and Continuous2D to do neighborhood lookups without having to create an Int2D every time (which causes lots of garbage collection). <p>You use MutableInt2D as a STORED hash key at your peril: it has the same misfeature as Point, and you should read the warning in Int2D. However, you can look up Int2D-keyed objects in a hash table by passing in a MutableInt2D instead. */ public class MutableInt2D implements java.io.Serializable, Cloneable { private static final long serialVersionUID = 1; public int x; public int y; public MutableInt2D() { x = 0; y = 0; } public MutableInt2D(final java.awt.Point p) { x = p.x; y = p.y; } public MutableInt2D(final Int2D p) { x = p.x; y = p.y; } public MutableInt2D(final int x, final int y) { this.x = x; this.y = y; } public final int getX() { return x; } public final int getY() { return y; } public final void setX(int val) { x = val; } public final void setY(int val) { y = val; } public void setTo(int x, int y) { this.x = x; this.y = y; } public void setTo(java.awt.Point p) { x = p.x; y = p.y; } public void setTo(Int2D p) { x = p.x; y = p.y; } public void setTo(MutableInt2D p) { x = p.x; y = p.y; } /** @deprecated use setTo */ public void setLocation(int x, int y) { this.x = x; this.y = y; } /** @deprecated use setTo */ public void setLocation(java.awt.Point p) { x = p.x; y = p.y; } /** @deprecated use setTo */ public void setLocation(Int2D p) { x = p.x; y = p.y; } /** @deprecated use setTo */ public void setLocation(MutableInt2D p) { x = p.x; y = p.y; } public java.awt.geom.Point2D.Double toPoint2D() { return new java.awt.geom.Point2D.Double(x,y); } public java.awt.Point toPoint() { return new java.awt.Point(x,y); } public String toString() { return "MutableInt2D["+x+","+y+"]"; } public String toCoordinates() { return "(" + x + ", " + y + ")"; } public Object clone() { try { return super.clone(); } catch(CloneNotSupportedException e) { return null; // never happens } } public final int hashCode() { int y = this.y; // basically we need to randomly disperse <int,int> --> int // I do that 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 // 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 MutableInt2D, Int3D, Double2D, 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 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; } // can't have separate equals(...) methods as the // argument isn't virtual public final boolean equals(Object obj) { if (obj==null) return false; else if (obj instanceof Int2D) // do Int2D first { 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 if (obj instanceof Double2D) { Double2D other = (Double2D) obj; return (other.x == x && other.y == y); } else if (obj instanceof MutableDouble2D) { MutableDouble2D other = (MutableDouble2D) obj; return (other.x == x && other.y == y); } else return false; } /** Returns the distance FROM this MutableInt2D 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 MutableInt2D 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 MutableInt2D 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 MutableInt2D 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 MutableInt2D 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 squared distance FROM this MutableInt2D 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 squared distance FROM this MutableInt2D 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 squared distance FROM this MutableInt2D 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 squared distance FROM this MutableInt2D 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 squared distance FROM this MutableInt2D 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 manhattan distance FROM this MutableInt2D TO the specified point. */ public long manhattanDistance(final int x, final int y) { return Math.abs((long)this.x-x) + Math.abs((long)this.y-y); } /** Returns the manhattan distance FROM this MutableInt2D TO the specified point. */ public long manhattanDistance(final MutableInt2D p) { return Math.abs((long)this.x-p.x) + Math.abs((long)this.y-p.y); } /** Returns the manhattan distance FROM this MutableInt2D TO the specified point. */ public long manhattanDistance(final Int2D p) { return Math.abs((long)this.x-p.x) + Math.abs((long)this.y-p.y); } /** Returns the manhattan distance FROM this Int2D TO the specified point. */ public long manhattanDistance(final java.awt.Point p) { return Math.abs((long)this.x-p.x) + Math.abs((long)this.y-p.y); } }