package wblut.geom; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import wblut.WB_Epsilon; // TODO: Auto-generated Javadoc /** * The Class WB_AABB. * * @param <T> the generic type */ public class WB_AABB<T extends WB_Point3d> { /** The _min. */ protected double[] _min; /** The _max. */ protected double[] _max; /** The _data. */ private HashMap<String, Object> _data; /** The _id. */ int _id; /** * Instantiates a new wb aabb. * * @param p the p */ public WB_AABB(final T p) { _min = new double[3]; _max = new double[3]; setToNull(); expandToInclude(p); } /** * Instantiates a new wb aabb. * * @param points point cloud */ public WB_AABB(final T[] points) { if (points == null) { throw new NullPointerException("Array not initialized."); } if (points.length == 0) { throw new IllegalArgumentException("Array has zero size."); } WB_Point3d point = points[0]; if (point == null) { throw new NullPointerException("Array point not initialized."); } init(); for (int i = 0; i < points.length; i++) { for (int j = 0; j < 3; j++) { point = points[i]; if (point == null) { throw new NullPointerException( "Array point not initialized."); } if (_min[j] > point.get(j)) { _min[j] = point.get(j); } if (_max[j] < point.get(j)) { _max[j] = point.get(j); } } } } /** * Instantiates a new wb aabb. * * @param points the points */ public WB_AABB(final Collection<T> points) { if (points == null) { throw new IllegalArgumentException("Collection not initialized."); } if (points.size() == 0) { throw new IllegalArgumentException("Collection has zero size."); } WB_Point3d fpoint = points.iterator().next(); if (fpoint == null) { throw new NullPointerException("Collection point not initialized."); } init(); for (WB_Point3d point : points) { if (point == null) { throw new NullPointerException( "Collection point not initialized."); } for (int j = 0; j < 3; j++) { if (_min[j] > point.get(j)) { _min[j] = point.get(j); } if (_max[j] < point.get(j)) { _max[j] = point.get(j); } } } } /** * Instantiates a new wb aabb. * * @param min minimum values as double[3] * @param max maximum values as double[3] */ public WB_AABB(final double[] min, final double[] max) { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { if (min[i] < max[i]) { _min[i] = min[i]; _max[i] = max[i]; } else { _min[i] = max[i]; _max[i] = min[i]; } } } /** * Instantiates a new wb aabb. * * @param min minimum values as float[3] * @param max maximum values as float[3] */ public WB_AABB(final float[] min, final float[] max) { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { if (min[i] < max[i]) { _min[i] = min[i]; _max[i] = max[i]; } else { _min[i] = max[i]; _max[i] = min[i]; } } } /** * Instantiates a new wb aabb. * * @param min minimum values as int[3] * @param max maximum values as int[3] */ public WB_AABB(final int[] min, final int[] max) { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { if (min[i] < max[i]) { _min[i] = min[i]; _max[i] = max[i]; } else { _min[i] = max[i]; _max[i] = min[i]; } } } /** * Instantiates a new wb aabb. * * @param min minimum values as WB_XY * @param max maximum values as WB_XY */ public WB_AABB(final WB_Point3d min, final WB_Point3d max) { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { if (min.get(i) < max.get(i)) { _min[i] = min.get(i); _max[i] = max.get(i); } else { _min[i] = max.get(i); _max[i] = min.get(i); } } } /** * Instantiates a new WB_AABB. * * @param values the values */ public WB_AABB(final Double... values) { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { _min[i] = values[i]; _max[i] = values[i + 3]; } } /** * Instantiates a new wb aabb. * * @param values the values */ public WB_AABB(final Integer... values) { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { _min[i] = values[i]; _max[i] = values[i + 3]; } } /** * Instantiates a new wb aabb. * * @param values the values */ public WB_AABB(final Float... values) { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { _min[i] = values[i]; _max[i] = values[i + 3]; } } /** * Gets the size. * * @param i the i * @return the size */ public double getSize(final int i) { if (isNull()) { return 0; } return _max[i] - _min[i]; } /** * Gets the min. * * @param i the i * @return the min */ public double getMin(final int i) { return _min[i]; } /** * Gets the max. * * @param i the i * @return the max */ public double getMax(final int i) { return _max[i]; } /** * Min ordinate. * * @return the int */ public int minOrdinate() { if (isNull()) { return 0; } double res = Double.POSITIVE_INFINITY; int ord = 0; for (int i = 0; i < 3; i++) { double w = getSize(i); if (res > w) { res = w; ord = i; } } return ord; } /** * Max ordinate. * * @return the int */ public int maxOrdinate() { if (isNull()) { return 0; } double res = Double.NEGATIVE_INFINITY; int ord = 0; for (int i = 0; i < 3; i++) { double w = getSize(i); if (res < w) { res = w; ord = i; } } return ord; } /** * Expand to include. * * @param p the p */ public void expandToInclude(final WB_Point3d p) { expandToInclude(p.coords()); } /** * Expand by. * * @param distance the distance */ public void expandBy(final double distance) { if (isNull()) { return; } for (int i = 0; i < 3; i++) { _min[i] -= distance; _max[i] += distance; if (_min[i] > _max[i]) { setToNull(); return; } } } /** * Expand by. * * @param delta the delta */ public void expandBy(final double[] delta) { if (isNull()) { return; } for (int i = 0; i < 3; i++) { _min[i] -= delta[i]; _max[i] += delta[i]; if (_min[i] > _max[i]) { setToNull(); return; } } } /** * Expand to include. * * @param p the p */ public void expandToInclude(final double[] p) { if (isNull()) { for (int i = 0; i < 3; i++) { _min[i] = p[i]; _max[i] = p[i]; } } else { for (int i = 0; i < 3; i++) { if (p[i] < _min[i]) { _min[i] = p[i]; } if (p[i] > _max[i]) { _max[i] = p[i]; } } } } /** * Expand to include. * * @param other the other */ public void expandToInclude(final WB_AABB<T> other) { expandToInclude(other._min); expandToInclude(other._max); } /** * Translate. * * @param d the d */ public void translate(final double[] d) { if (isNull()) { return; } for (int i = 0; i < 3; i++) { _min[i] += d[i]; _max[i] += d[i]; } } /** * Center. * * @return the double[] */ @Deprecated public double[] center() { return getCenter(); } /** * Intersects. * * @param other the other * @return true, if successful */ public boolean intersects(final WB_AABB<T> other) { if (isNull() || other.isNull()) { return false; } for (int i = 0; i < 3; i++) { if (other._min[i] > _max[i]) { return false; } if (other._max[i] < _min[i]) { return false; } } return true; } /** * Intersects. * * @param p the p * @return true, if successful */ public boolean intersects(final WB_Point3d p) { return intersects(p.coords()); } /** * Intersects. * * @param x the x * @return true, if successful */ public boolean intersects(final double[] x) { if (isNull()) { return false; } for (int i = 0; i < 3; i++) { if (x[i] > _max[i]) { return false; } if (x[i] < _min[i]) { return false; } } return true; } /** * Contains. * * @param other the other * @return true, if successful */ public boolean contains(final WB_AABB<T> other) { return covers(other); } /** * Contains. * * @param p the p * @return true, if successful */ public boolean contains(final WB_Point3d p) { return covers(p); } /** * Contains. * * @param x the x * @return true, if successful */ public boolean contains(final double[] x) { return covers(x); } /** * Covers. * * @param x the x * @return true, if successful */ public boolean covers(final double[] x) { if (isNull()) { return false; } for (int i = 0; i < 3; i++) { if (x[i] > _max[i]) { return false; } if (x[i] < _min[i]) { return false; } } return true; } /** * Covers. * * @param p the p * @return true, if successful */ public boolean covers(final WB_Point3d p) { return covers(p.coords()); } /** * Covers. * * @param other the other * @return true, if successful */ public boolean covers(final WB_AABB<T> other) { if (isNull() || other.isNull()) { return false; } for (int i = 0; i < 3; i++) { if (other._max[i] > _max[i]) { return false; } if (other._min[i] < _min[i]) { return false; } } return true; } /** * Gets the distance. * * @param other the other * @return the distance */ public double getDistance(final WB_AABB<T> other) { if (intersects(other)) { return 0; } double dx = 0; double sqr = 0; for (int i = 0; i < 3; i++) { if (_max[i] < other._min[i]) { dx = other._min[i] - _max[i]; } else if (_min[i] > other._max[i]) { dx = _min[i] - other._max[i]; } sqr += dx * dx; } return Math.sqrt(sqr); } /** * Gets the distance square. * * @param other the other * @return the distance square */ public double getDistanceSquare(final WB_AABB<T> other) { if (intersects(other)) { return 0; } double dx = 0; double sqr = 0; for (int i = 0; i < 3; i++) { if (_max[i] < other._min[i]) { dx = other._min[i] - _max[i]; } else if (_min[i] > other._max[i]) { dx = _min[i] - other._max[i]; } sqr += dx * dx; } return sqr; } /** * Gets the distance. * * @param tuple the tuple * @return the distance */ public double getDistance(final WB_Point3d tuple) { double dx = 0; double sqr = 0; for (int i = 0; i < 3; i++) { if (_max[i] < tuple.get(i)) { sqr += (dx = tuple.get(i) - _max[i]) * dx; } else if (_min[i] > tuple.get(i)) { sqr += (dx = _min[i] - tuple.get(i)) * dx; } } return Math.sqrt(sqr); } /** * Gets the distance square. * * @param tuple the tuple * @return the distance square */ public double getDistanceSquare(final WB_Point3d tuple) { double dx = 0; double sqr = 0; for (int i = 0; i < 3; i++) { if (_max[i] < tuple.get(i)) { sqr += (dx = tuple.get(i) - _max[i]) * dx; } else if (_min[i] > tuple.get(i)) { sqr += (dx = _min[i] - tuple.get(i)) * dx; } } return sqr; } /** * Equals. * * @param other the other * @return true, if successful */ public boolean equals(final WB_AABB<T> other) { if (isNull()) { return other.isNull(); } for (int i = 0; i < 3; i++) { if (other._max[i] != _max[i]) { return false; } if (other._min[i] != _min[i]) { return false; } } return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { String string = "WB_AABB ["; int i = 0; for (i = 0; i < 3 - 1; i++) { string += _min[0] + ":" + _max[0] + ", "; } string += _min[i] + ":" + _max[i] + "]"; return string; } /** * Number of points. * * @return the int */ public int numberOfPoints() { if (isNull()) { return 0; } return 8; } /** * Number of segments. * * @return the int */ public int numberOfSegments() { if (isNull()) { return 0; } return 12; } /** * Number of triangles. * * @return the int */ public int numberOfTriangles() { if (isNull()) { return 0; } return 12; } /** * Number of faces. * * @return the int */ public int numberOfFaces() { if (isNull()) { return 0; } return 6; } /** * Gets the coords. * * @return the coords */ public List<double[]> getCoords() { if (isNull()) { return null; } int n = numberOfPoints(); List<double[]> points = new ArrayList<double[]>(n); double[] values; for (int i = 0; i < n; i++) { values = new double[3]; int disc = 1; for (int j = 0; j < 3; j++) { if (((i / disc) % 2) == 0) { values[j] = _min[j]; } else { values[j] = _max[j]; } disc *= 2; } points.add(values); } return points; } /** * Gets the coord. * * @param i the i * @return the coord */ public double[] getCoord(final int i) { double[] values = new double[3]; int disc = 1; for (int j = 0; j < 3; j++) { if (((i / disc) % 2) == 0) { values[j] = _min[j]; } else { values[j] = _max[j]; } disc *= 2; } return (values); } /** * Gets the segments. * * @return the segments */ public List<int[]> getSegments() { List<double[]> points = getCoords(); List<int[]> segments = new ArrayList<int[]>(numberOfSegments()); for (int i = 0; i < points.size(); i++) { for (int j = i + 1; j < points.size(); j++) { int comp = 0; for (int k = 0; k < 3; k++) { if (points.get(i)[k] != points.get(j)[k]) { comp++; } if (comp > 1) { break; } } if (comp == 1) { int[] seg = { i, j }; segments.add(seg); } } } return segments; } /** * Sets the data. * * @param s the s * @param o the o */ public void setData(final String s, final Object o) { if (_data == null) { _data = new HashMap<String, Object>(); } _data.put(s, o); } /** * Gets the data. * * @param s the s * @return the data */ public Object getData(final String s) { return _data.get(s); } /** * Gets the id. * * @return the id */ public int getId() { return _id; } /** * Sets the id. * * @param id the new id */ public void setId(final int id) { _id = id; } /** * Checks if is degenerate. * * @return true, if is degenerate */ public boolean isDegenerate() { return ((getTrueDim() < 3) && (getTrueDim() > -1)); } /** * Sets the. * * @param src the src */ public void set(final WB_AABB<T> src) { System.arraycopy(src._min, 0, _min, 0, 3); System.arraycopy(src._max, 0, _max, 0, 3); } /** * Inits the. */ private void init() { _min = new double[3]; _max = new double[3]; for (int i = 0; i < 3; i++) { _min[i] = Double.POSITIVE_INFINITY; _max[i] = Double.NEGATIVE_INFINITY; } } /** * Gets the. * * @return the wb aabb */ public WB_AABB<T> get() { return new WB_AABB<T>(_min, _max); } /** * Union. * * @param aabb the aabb * @return the wb aabb */ public WB_AABB union(final WB_AABB<T> aabb) { double[] newmin = new double[3]; double[] newmax = new double[3]; for (int i = 0; i < 3; i++) { newmin[i] = Math.min(_min[i], aabb._min[i]); newmax[i] = Math.max(_max[i], aabb._max[i]); } return new WB_AABB(newmin, newmax); } /** * Intersection. * * @param other the other * @return the wb aabb */ public WB_AABB intersection(final WB_AABB<T> other) { if (isNull() || other.isNull() || !intersects(other)) { return null; } double[] newmin = new double[3]; double[] newmax = new double[3]; for (int i = 0; i < 3; i++) { newmin[i] = Math.max(_min[i], other._min[i]); newmax[i] = Math.min(_max[i], other._max[i]); } return new WB_AABB(newmin, newmax); } /** * Intersects. * * @param p1 the p1 * @param p2 the p2 * @param q the q * @return true, if successful */ public static boolean intersects(final WB_Point3d p1, final WB_Point3d p2, final WB_Point3d q) { if (((q.x >= (p1.x < p2.x ? p1.x : p2.x)) && (q.x <= (p1.x > p2.x ? p1.x : p2.x))) && ((q.y >= (p1.y < p2.y ? p1.y : p2.y)) && (q.y <= (p1.y > p2.y ? p1.y : p2.y))) && ((q.z >= (p1.z < p2.z ? p1.z : p2.z)) && (q.z <= (p1.z > p2.z ? p1.y : p2.z)))) { return true; } return false; } /** * Intersects. * * @param p1 the p1 * @param p2 the p2 * @param q1 the q1 * @param q2 the q2 * @return true, if successful */ public static boolean intersects(final WB_Point3d p1, final WB_Point3d p2, final WB_Point3d q1, final WB_Point3d q2) { double minq = Math.min(q1.x, q2.x); double maxq = Math.max(q1.x, q2.x); double minp = Math.min(p1.x, p2.x); double maxp = Math.max(p1.x, p2.x); if (minp > maxq) { return false; } if (maxp < minq) { return false; } minq = Math.min(q1.y, q2.y); maxq = Math.max(q1.y, q2.y); minp = Math.min(p1.y, p2.y); maxp = Math.max(p1.y, p2.y); if (minp > maxq) { return false; } if (maxp < minq) { return false; } minq = Math.min(q1.z, q2.z); maxq = Math.max(q1.z, q2.z); minp = Math.min(p1.z, p2.z); maxp = Math.max(p1.z, p2.z); if (minp > maxq) { return false; } if (maxp < minq) { return false; } return true; } /** * Gets the center. * * @return the center */ public double[] getCenter() { double[] center = new double[3]; for (int i = 0; i < 3; i++) { center[i] = 0.5 * (_min[i] + _max[i]); } return center; } /** * Gets the width. * * @return the width */ public double getWidth() { return getSize(0); } /** * Gets the height. * * @return the height */ public double getHeight() { return getSize(1); } /** * Gets the depth. * * @return the depth */ public double getDepth() { return getSize(2); } /** * Gets the min x. * * @return the min x */ public double getMinX() { return _min[0]; } /** * Gets the max x. * * @return the max x */ public double getMaxX() { return _max[0]; } /** * Gets the min y. * * @return the min y */ public double getMinY() { return _min[1]; } /** * Gets the max y. * * @return the max y */ public double getMaxY() { return _max[1]; } /** * Gets the min z. * * @return the min z */ public double getMinZ() { return _min[2]; } /** * Gets the max z. * * @return the max z */ public double getMaxZ() { return _max[2]; } /** * Gets the area. * * @return the area */ public double getArea() { return getWidth() * getHeight() * getDepth(); } /** * Min extent. * * @return the double */ public double minExtent() { if (isNull()) { return 0.0; } double w = getWidth(); double h = getHeight(); double d = getDepth(); if (w < h) { return (w < d) ? w : d; } return (h < d) ? h : d; } /** * Max extent. * * @return the double */ public double maxExtent() { if (isNull()) { return 0.0; } double w = getWidth(); double h = getHeight(); double d = getDepth(); if (w > h) { return (w > d) ? w : d; } return (h > d) ? h : d; } /** * Translate. * * @param x the x * @param y the y * @param z the z */ public void translate(final double x, final double y, final double z) { if (isNull()) { return; } _min[0] += x; _max[0] += x; _min[1] += y; _max[1] += y; _min[2] += z; _max[2] += z; } /** * Gets the triangles. * * @return the triangles */ public List<int[]> getTriangles() { List<int[]> tris = new ArrayList<int[]>(); int[] tri01 = { 4, 5, 6 }; int[] tri02 = { 5, 7, 6 }; tris.add(tri01); tris.add(tri02); int[] tri11 = { 0, 2, 1 }; int[] tri12 = { 2, 3, 1 }; tris.add(tri11); tris.add(tri12); int[] tri21 = { 0, 1, 4 }; int[] tri22 = { 1, 5, 4 }; tris.add(tri21); tris.add(tri22); int[] tri31 = { 3, 2, 7 }; int[] tri32 = { 2, 6, 7 }; tris.add(tri31); tris.add(tri32); int[] tri41 = { 0, 4, 2 }; int[] tri42 = { 4, 6, 2 }; tris.add(tri41); tris.add(tri42); int[] tri51 = { 1, 3, 5 }; int[] tri52 = { 3, 7, 5 }; tris.add(tri51); tris.add(tri52); return tris; } /** * Gets the faces. * * @return the faces */ public List<int[]> getFaces() { List<int[]> faces = new ArrayList<int[]>(); int[] face0 = { 4, 5, 7, 6 }; faces.add(face0); int[] face1 = { 0, 2, 3, 1 }; faces.add(face1); int[] face2 = { 0, 1, 5, 4 }; faces.add(face2); int[] face3 = { 3, 2, 6, 7 }; faces.add(face3); int[] face4 = { 0, 4, 6, 2 }; faces.add(face4); int[] face5 = { 1, 3, 7, 5 }; faces.add(face5); return faces; } /** * Gets the min. * * @return the min */ public double[] getMin() { return _min; } /** * Gets the max. * * @return the max */ public double[] getMax() { return _max; } /** * Gets the dim. * * @return the dim */ public int getDim() { return 3; } /** * Gets the true dim. * * @return the true dim */ public int getTrueDim() { if (!isValid()) { return -1; } int dim = 0; for (int i = 0; i < 3; i++) { if ((_max[i] - _min[i]) >= WB_Epsilon.EPSILON) { dim++; } } return dim; } /** * Pad. * * @param factor the factor */ public void pad(final double factor) { final double[] c = getCenter(); for (int i = 0; i < 3; i++) { _min[i] = c[i] + (factor + 1.0) * (_min[i] - c[i]); _max[i] = c[i] + (factor + 1.0) * (_max[i] - c[i]); } } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ public int hashCode() { int result = 17; for (int i = 0; i < 3; i++) { result = 37 * result + WB_Point3d.hashCode(_min[i]); result = 37 * result + WB_Point3d.hashCode(_max[i]); } return result; } /** * Sets the to null. */ public void setToNull() { for (int i = 0; i < 3; i++) { _min[i] = 0; _max[i] = -1; } } /** * Checks if is null. * * @return true, if is null */ public boolean isNull() { return _max[0] < _min[0]; } /** * Checks if is valid. * * @return true, if is valid */ public boolean isValid() { return !isNull(); } }