/* * $Id$ * * Copyright (C) 2010-2013 Stephane GALLAND. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * This program is free software; you can redistribute it and/or modify */ package org.arakhne.afc.math.geometry.d3.continuous; import org.arakhne.afc.math.MathUtil; import org.arakhne.afc.math.geometry.d3.Point3D; import org.eclipse.xtext.xbase.lib.Pure; /** 3D axis-aligned box with floating-point points. * * @author $Author: sgalland$ * @author $Author: hjaffali$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public class AlignedBox3f extends AbstractBoxedShape3F<AlignedBox3f> { private static final long serialVersionUID = 6839969099242151134L; /** Replies the point on the shape that is closest to the given point. * * @param minx x coordinate of the lower point of the box. * @param miny y coordinate of the lower point of the box. * @param minz z coordinate of the lower point of the box. * @param maxx x coordinate of the upper point of the box. * @param maxy y coordinate of the upper point of the box. * @param maxz z coordinate of the upper point of the box. * @param x x coordinate of the point. * @param y y coordinate of the point. * @param z z coordinate of the point. * @return the closest point on the shape; or the point itself * if it is inside the shape. */ @Pure public static Point3f computeClosestPoint( double minx, double miny, double minz, double maxx, double maxy, double maxz, double x, double y, double z) { Point3f closest = new Point3f(); if (x < minx) { closest.setX(minx); } else if (x > maxx) { closest.setX(maxx); } else { closest.setX(x); } if (y < miny) { closest.setY(miny); } else if (y > maxy) { closest.setY(maxy); } else { closest.setY(y); } if (z < minz) { closest.setZ(minz); } else if (z > maxz) { closest.setZ(maxz); } else { closest.setZ(z); } return closest; } /** * Tests if the two 3D axis-aligned boxes are intersecting. * <p> * This function is assuming that <var>lx1</var> is lower * or equal to <var>ux1</var>, <var>ly1</var> is lower * or equal to <var>uy1</var>, and so on. * * @param lower1x coordinates of the lowest point of the first box. * @param lower1y coordinates of the lowest point of the first box. * @param lower1z coordinates of the lowest point of the first box. * @param upper1x coordinates of the uppermost point of the first box. * @param upper1y coordinates of the uppermost point of the first box. * @param upper1z coordinates of the uppermost point of the first box. * @param lower2x coordinates of the lowest point of the second box. * @param lower2y coordinates of the lowest point of the second box. * @param lower2z coordinates of the lowest point of the second box. * @param upper2x coordinates of the uppermost point of the second box. * @param upper2y coordinates of the uppermost point of the second box. * @param upper2z coordinates of the uppermost point of the second box. * @return <code>true</code> if the two 3D boxes intersect each * other; <code>false</code> otherwise. */ @Pure public static boolean intersectsAlignedBoxAlignedBox( double lower1x, double lower1y, double lower1z, double upper1x, double upper1y, double upper1z, double lower2x, double lower2y, double lower2z, double upper2x, double upper2y, double upper2z) { assert(lower1x<=upper1x); assert(lower1y<=upper1y); assert(lower1z<=upper1z); assert(lower2x<=upper2x); assert(lower2y<=upper2y); assert(lower2z<=upper2z); boolean intersects; if (lower1x<lower2x) intersects = upper1x>lower2x; else intersects = upper2x>lower1x; if (intersects) { if (lower1y<lower2y) intersects = upper1y>lower2y; else intersects = upper2y>lower1y; if (intersects) { if (lower1z<lower2z) intersects = upper1z>lower2z; else intersects = upper2z>lower1z; } } return intersects; } /** Replies if the given point is inside this shape. * * @param minx coordinates of the lowest point of the box. * @param miny coordinates of the lowest point of the box. * @param minz coordinates of the lowest point of the box. * @param maxx coordinates of the uppermost point of the box. * @param maxy coordinates of the uppermost point of the box. * @param maxz coordinates of the uppermost point of the box. * @param px x coordinate of the point. * @param py y coordinate of the point. * @param pz z coordinate of the point. * @return <code>true</code> if the given point is inside this * shape, otherwise <code>false</code>. */ @Pure public static boolean containsAlignedBoxPoint( double minx, double miny, double minz, double maxx, double maxy, double maxz, double px, double py, double pz) { return (minx<=px && px<=maxx && miny<=py && py<=maxy && minz<=pz && pz<=maxz); } /** Lowest x-coordinate covered by this rectangular shape. */ protected double minx; /** Lowest y-coordinate covered by this rectangular shape. */ protected double miny ; /** Lowest z-coordinate covered by this rectangular shape. */ protected double minz; /** Highest x-coordinate covered by this rectangular shape. */ protected double maxx; /** Highest y-coordinate covered by this rectangular shape. */ protected double maxy; /** Highest z-coordinate covered by this rectangular shape. */ protected double maxz; /** */ public AlignedBox3f() { this.minx = 0f; this.miny = 0f; this.minz = 0f; this.maxx = 0f; this.maxy = 0f; this.maxz = 0f; } /** * @param min is the min corner of the box. * @param max is the max corner of the box. */ public AlignedBox3f(Point3f min, Point3f max) { setFromCorners( min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ()); } /** * @param x * @param y * @param z * @param sizex * @param sizey * @param sizez */ public AlignedBox3f(double x, double y, double z, double sizex, double sizey, double sizez) { setFromCorners(x, y, z, x+sizex, y+sizey, z+sizez); } /** * @param s */ public AlignedBox3f(AbstractBoxedShape3F<?> s) { this.minx = s.getMinX(); this.miny = s.getMinY(); this.minz = s.getMinZ(); this.maxx = s.getMaxX(); this.maxy = s.getMaxY(); this.maxz = s.getMaxZ(); } /** Change the frame of the box. * * @param x * @param y * @param z * @param sizex * @param sizey * @param sizez */ @Override public void set(double x, double y, double z, double sizex, double sizey, double sizez) { setFromCorners(x, y, z, x+sizex, y+sizey, z+sizez); } /** Change the frame of the box. * * @param min is the min corner of the box. * @param max is the max corner of the box. */ @Override public void set(Point3D min, Point3D max) { setFromCorners( min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ()); } /** Change the X-size of the box, not the min corner. * * @param size */ @Override public void setSizeX(double size) { this.maxx = this.minx + Math.max(0f, size); } /** Change the Y-size of the box, not the min corner. * * @param size */ @Override public void setSizeY(double size) { this.maxy = this.miny + Math.max(0f, size); } /** Change the Z-size of the box, not the min corner. * * @param size */ @Override public void setSizeZ(double size) { this.maxz = this.minz + Math.max(0f, size); } /** Change the frame of the box. * * @param p1 is the coordinate of the first corner. * @param p2 is the coordinate of the second corner. */ @Override public void setFromCorners(Point3D p1, Point3D p2) { setFromCorners( p1.getX(), p1.getY(), p1.getZ(), p2.getX(), p2.getY(), p2.getZ()); } /** Change the frame of the box. * * @param x1 is the coordinate of the first corner. * @param y1 is the coordinate of the first corner. * @param z1 is the coordinate of the first corner. * @param x2 is the coordinate of the second corner. * @param y2 is the coordinate of the second corner. * @param z2 is the coordinate of the second corner. */ @Override public void setFromCorners(double x1, double y1, double z1, double x2, double y2, double z2) { if (x1<x2) { this.minx = x1; this.maxx = x2; } else { this.minx = x2; this.maxx = x1; } if (y1<y2) { this.miny = y1; this.maxy = y2; } else { this.miny = y2; this.maxy = y1; } if (z1<z2) { this.minz = z1; this.maxz = z2; } else { this.minz = z2; this.maxz = z1; } } /** * Sets the framing box of this <code>Shape</code> * based on the specified center point coordinates and corner point * coordinates. The framing box is used by the subclasses of * <code>BoxedShape</code> to define their geometry. * * @param centerX the X coordinate of the specified center point * @param centerY the Y coordinate of the specified center point * @param centerZ the Z coordinate of the specified center point * @param cornerX the X coordinate of the specified corner point * @param cornerY the Y coordinate of the specified corner point * @param cornerZ the Z coordinate of the specified corner point */ @Override public void setFromCenter(double centerX, double centerY, double centerZ, double cornerX, double cornerY, double cornerZ) { double dx = centerX - cornerX; double dy = centerY - cornerY; double dz = centerZ - cornerZ; setFromCorners(cornerX, cornerY, cornerZ, centerX + dx, centerY + dy, centerZ + dz); } /** Replies the min point. * * @return the min point. */ @Pure @Override public Point3f getMin() { return new Point3f(this.minx, this.miny, this.minz); } /** Replies the min point. * * @return the min point. */ @Pure @Override public Point3f getMax() { return new Point3f(this.maxx, this.maxy, this.maxz); } /** Replies the center point. * * @return the center point. */ @Pure @Override public Point3f getCenter() { return new Point3f( (this.minx + this.maxx) / 2., (this.miny + this.maxy) / 2., (this.minz + this.maxz) / 2.); } /** Replies the min X. * * @return the min x. */ @Pure @Override public double getMinX() { return this.minx; } /** Set the min X. * * @param x the min x. */ @Override public void setMinX(double x) { double o = this.maxx; if (o<x) { this.minx = o; this.maxx = x; } else { this.minx = x; } } /** Replies the center x. * * @return the center x. */ @Pure @Override public double getCenterX() { return (this.minx + this.maxx) / 2f; } /** Replies the max x. * * @return the max x. */ @Pure @Override public double getMaxX() { return this.maxx; } /** Set the max X. * * @param x the max x. */ @Override public void setMaxX(double x) { double o = this.minx; if (o>x) { this.maxx = o; this.minx = x; } else { this.maxx = x; } } /** Replies the min y. * * @return the min y. */ @Pure @Override public double getMinY() { return this.miny; } /** Set the min Y. * * @param y the min y. */ @Override public void setMinY(double y) { double o = this.maxy; if (o<y) { this.miny = o; this.maxy = y; } else { this.miny = y; } } /** Replies the center y. * * @return the center y. */ @Pure @Override public double getCenterY() { return (this.miny + this.maxy) / 2f; } /** Replies the max y. * * @return the max y. */ @Pure @Override public double getMaxY() { return this.maxy; } /** Set the max Y. * * @param y the max y. */ @Override public void setMaxY(double y) { double o = this.miny; if (o>y) { this.maxy = o; this.miny = y; } else { this.maxy = y; } } /** Replies the min z. * * @return the min z. */ @Pure @Override public double getMinZ() { return this.minz; } /** Set the min Z. * * @param z the min z. */ @Override public void setMinZ(double z) { double o = this.maxz; if (o<z) { this.minz = o; this.maxz = z; } else { this.minz = z; } } /** Replies the center z. * * @return the center z. */ @Pure @Override public double getCenterZ() { return (this.minz + this.maxz) / 2f; } /** Replies the max z. * * @return the max z. */ @Pure @Override public double getMaxZ() { return this.maxz; } /** Set the max Z. * * @param z the max z. */ @Override public void setMaxZ(double z) { double o = this.minz; if (o>z) { this.maxz = o; this.minz = z; } else { this.maxz = z; } } /** Replies the x-size. * * @return the x-size. */ @Pure @Override public double getSizeX() { return this.maxx - this.minx; } /** Replies the y-size. * * @return the y-size. */ @Pure @Override public double getSizeY() { return this.maxy - this.miny; } /** Replies the z-size. * * @return the z-size. */ @Pure @Override public double getSizeZ() { return this.maxz - this.minz; } /** Set the x bounds of the box. * * @param min the min value for the x axis. * @param max the max value for the x axis. */ @Override public void setX(double min, double max) { if (min <= max) { this.minx = min; this.maxx = max; } else { this.minx = max; this.maxx = min; } } /** Set the y bounds of the box. * * @param min the min value for the y axis. * @param max the max value for the y axis. */ @Override public void setY(double min, double max) { if (min <= max) { this.miny = min; this.maxy = max; } else { this.miny = max; this.maxy = min; } } /** Set the z bounds of the box. * * @param min the min value for the z axis. * @param max the max value for the z axis. */ @Override public void setZ(double min, double max) { if (min <= max) { this.minz = min; this.maxz = max; } else { this.minz = max; this.maxz = min; } } /** {@inheritDoc} */ @Pure @Override public AlignedBox3f toBoundingBox() { return this; } @Pure @Override public double distanceSquared(Point3D p) { double d1 = 0; if (p.getX()<this.minx) { d1 = this.minx - p.getX(); d1 = d1*d1; } else if (p.getX()>this.maxx) { d1 = p.getX() - this.maxx; d1 = d1*d1; } double d2 = 0; if (p.getY()<this.miny) { d2 = this.miny - p.getY(); d2 = d2*d2; } else if (p.getY()>this.maxy) { d2 = p.getY() - this.maxy; d2 = d2*d2; } double d3 = 0; if (p.getZ()<this.minz) { d3 = this.minz - p.getZ(); d3 = d3*d3; } else if (p.getZ()>this.maxz) { d3 = p.getZ() - this.maxz; d3 = d3*d3; } return d1+d2+d3; } @Pure @Override public double distanceL1(Point3D p) { double d1 = 0; if (p.getX()<this.minx) { d1 = this.minx - p.getX(); } else if (p.getX()>this.maxx) { d1 = p.getX() - this.maxx; } double d2 = 0; if (p.getY()<this.miny) { d2 = this.miny - p.getY(); } else if (p.getY()>this.maxy) { d2 = p.getY() - this.maxy; } double d3 = 0; if (p.getZ()<this.minz) { d3 = this.minz - p.getZ(); } else if (p.getZ()>this.maxz) { d3 = p.getZ() - this.maxz; } return d1+d2+d3; } @Pure @Override public double distanceLinf(Point3D p) { double d1 = 0; if (p.getX()<this.minx) { d1 = this.minx - p.getX(); } else if (p.getX()>this.maxx) { d1 = p.getX() - this.maxx; } double d2 = 0; if (p.getY()<this.miny) { d2 = this.miny - p.getY(); } else if (p.getY()>this.maxy) { d2 = p.getY() - this.maxy; } double d3 = 0; if (p.getZ()<this.minz) { d3 = this.minz - p.getZ(); } else if (p.getZ()>this.maxz) { d3 = p.getZ() - this.maxz; } return MathUtil.max(d1, d2, d3); } @Pure @Override public boolean contains(double x, double y, double z) { return containsAlignedBoxPoint( this.minx, this.miny, this.minz, this.maxx, this.maxy, this.maxz, x, y, z); } @Pure @Override public boolean intersects(AbstractBoxedShape3F<?> s) { return intersectsAlignedBoxAlignedBox( getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ(), s.getMinX(), s.getMinY(), s.getMinZ(), s.getMaxX(), s.getMaxY(), s.getMaxZ()); } @Pure @Override public boolean intersects(AbstractSphere3F s) { return AbstractSphere3F.intersectsSolidSphereSolidAlignedBox( s.getX(), s.getY(), s.getZ(), s.getRadius(), getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ()); } @Pure @Override public boolean intersects(AbstractSegment3F s) { return AbstractSegment3F.intersectsSegmentAlignedBox( s.getX1(), s.getY1(), s.getZ1(), s.getX2(), s.getY2(), s.getZ2(), getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ()); } @Pure @Override public boolean intersects(AbstractTriangle3F s) { return AbstractTriangle3F.intersectsTriangleAlignedBox( s.getX1(), s.getY1(), s.getZ1(), s.getX2(), s.getY2(), s.getZ2(), s.getX3(), s.getY3(), s.getZ3(), getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ()); } @Pure @Override public boolean intersects(AbstractCapsule3F s) { return AbstractCapsule3F.intersectsCapsuleAlignedBox( s.getMedialX1(), s.getMedialY1(), s.getMedialY1(), s.getMedialX2(), s.getMedialY2(), s.getMedialY2(), s.getRadius(), getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ()); } @Pure @Override public boolean intersects(AbstractOrientedBox3F s) { return AbstractOrientedBox3F.intersectsOrientedBoxAlignedBox( s.getCenterX(), s.getCenterY(), s.getCenterZ(), s.getFirstAxisX(), s.getFirstAxisY(), s.getFirstAxisZ(), s.getSecondAxisX(), s.getSecondAxisY(), s.getSecondAxisZ(), s.getThirdAxisX(), s.getThirdAxisY(), s.getThirdAxisZ(), s.getFirstAxisExtent(), s.getSecondAxisExtent(), s.getThirdAxisExtent(), getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ()); } @Pure @Override public boolean intersects(Plane3D<?> p) { return p.intersects(this); } @Pure @Override public boolean intersects(Path3f s) { return s.intersects(this); } @Pure @Override public boolean intersects(Path3d s) { return s.intersects(this); } @Pure @Override public Point3D getClosestPointTo(Point3D p) { return computeClosestPoint( getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ(), p.getX(), p.getY(), p.getZ()); } @Pure @Override public Point3D getFarthestPointTo(Point3D p) { Point3f farthest = new Point3f(); if (p.getX()<this.minx) { farthest.setX(this.maxx); } else if (p.getX()>this.maxx) { farthest.setX(this.minx); } else { double dl = Math.abs(p.getX()-this.minx); double du = Math.abs(p.getX()-this.maxx); if (dl>du) { farthest.setX(this.minx); } else { farthest.setX(this.maxx); } } if (p.getY()<this.miny) { farthest.setY(this.maxy); } else if (p.getY()>this.maxy) { farthest.setY(this.miny); } else { double dl = Math.abs(p.getY()-this.miny); double du = Math.abs(p.getY()-this.maxy); if (dl>du) { farthest.setY(this.miny); } else { farthest.setY(this.maxy); } } if (p.getZ()<this.minz) { farthest.setZ(this.maxz); } else if (p.getZ()>this.maxz) { farthest.setZ(this.minz); } else { double dl = Math.abs(p.getZ()-this.minz); double du = Math.abs(p.getZ()-this.maxz); if (dl>du) { farthest.setZ(this.minz); } else { farthest.setZ(this.maxz); } } return farthest; } @Override public void set(Shape3F s) { s.toBoundingBox(this); } @Pure @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof AbstractBoxedShape3F) { AlignedBox3f ab3f = (AlignedBox3f) obj; return ((getMinX() == ab3f.getMinX()) && (getMinY() == ab3f.getMinY()) && (getMinZ() == ab3f.getMinZ()) && (getMaxX() == ab3f.getMaxX()) && (getMaxY() == ab3f.getMaxY()) && (getMaxZ() == ab3f.getMaxZ())); } return false; } @Pure @Override public int hashCode() { long bits = 1L; bits = 31L * bits + doubleToLongBits(getMinX()); bits = 31L * bits + doubleToLongBits(getMinY()); bits = 31L * bits + doubleToLongBits(getMinZ()); bits = 31L * bits + doubleToLongBits(getMaxX()); bits = 31L * bits + doubleToLongBits(getMaxY()); bits = 31L * bits + doubleToLongBits(getMaxZ()); return (int) (bits ^ (bits >> 32)); } @Override public PathIterator3f getPathIterator(Transform3D transform) { // TODO Auto-generated method stub return null; } @Override public PathIterator3d getPathIteratorProperty(Transform3D transform) { // TODO Auto-generated method stub return null; } }