
pythagoras.f.Frustum Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pythagoras Show documentation
Show all versions of pythagoras Show documentation
A portable geometry library.
The newest version!
//
// Pythagoras - a collection of geometry classes
// http://github.com/samskivert/pythagoras
package pythagoras.f;
/**
* A pyramidal frustum.
*/
public class Frustum
{
/** Intersection types indicating that the frustum does not intersect, intersects, or fully
* contains, respectively, the parameter. */
public enum IntersectionType { NONE, INTERSECTS, CONTAINS }
/**
* Creates an empty (invalid) frustum.
*/
public Frustum () {
// initialize the vertices and planes of the frustum
for (int ii = 0; ii < 8; ii++) {
_vertices[ii] = new Vector3();
}
for (int ii = 0; ii < 6; ii++) {
_planes[ii] = new Plane();
}
}
/**
* Returns a reference to the frustum's array of vertices.
*/
public IVector3[] vertices () {
return _vertices;
}
/**
* Returns a reference to the bounds of this frustum.
*/
public Box bounds () {
return _bounds;
}
/**
* Sets this frustum to one pointing in the Z- direction with the specified parameters
* determining its size and shape (see the OpenGL documentation for
* gluPerspective
).
*
* @param fovy the vertical field of view, in radians.
* @param aspect the aspect ratio (width over height).
* @param znear the distance to the near clip plane.
* @param zfar the distance to the far clip plane.
* @return a reference to this frustum, for chaining.
*/
public Frustum setToPerspective (float fovy, float aspect, float znear, float zfar) {
float top = znear * FloatMath.tan(fovy / 2f), bottom = -top;
float right = top * aspect, left = -right;
return setToFrustum(left, right, bottom, top, znear, zfar);
}
/**
* Sets this frustum to one pointing in the Z- direction with the specified parameters
* determining its size and shape (see the OpenGL documentation for glFrustum
).
*
* @return a reference to this frustum, for chaining.
*/
public Frustum setToFrustum (
float left, float right, float bottom, float top, float near, float far) {
return setToProjection(left, right, bottom, top, near, far, Vector3.UNIT_Z, false, false);
}
/**
* Sets this frustum to an orthographic one pointing in the Z- direction with the specified
* parameters determining its size (see the OpenGL documentation for glOrtho
).
*
* @return a reference to this frustum, for chaining.
*/
public Frustum setToOrtho (
float left, float right, float bottom, float top, float near, float far) {
return setToProjection(left, right, bottom, top, near, far, Vector3.UNIT_Z, true, false);
}
/**
* Sets this frustum to a perspective or orthographic projection with the specified parameters
* determining its size and shape.
*
* @return a reference to this frustum, for chaining.
*/
public Frustum setToProjection (
float left, float right, float bottom, float top, float near,
float far, IVector3 nearFarNormal, boolean ortho, boolean mirrored) {
float nfnx = nearFarNormal.x(), nfny = nearFarNormal.y(), nfnz = nearFarNormal.z();
if (ortho) {
float nrz = -1f / nfnz;
float xl = nfnx*left*nrz, xr = nfnx*right*nrz;
float yb = nfny*bottom*nrz, yt = nfny*top*nrz;
_vertices[0].set(left, bottom, xl + yb - near);
_vertices[mirrored ? 3 : 1].set(right, bottom, xr + yb - near);
_vertices[2].set(right, top, xr + yt - near);
_vertices[mirrored ? 1 : 3].set(left, top, xl + yt - near);
_vertices[4].set(left, bottom, xl + yb - far);
_vertices[mirrored ? 7 : 5].set(right, bottom, xr + yb - far);
_vertices[6].set(right, top, xr + yt - far);
_vertices[mirrored ? 5 : 7].set(left, top, xl + yt - far);
} else {
float rn = 1f / near;
float lrn = left * rn, rrn = right * rn;
float brn = bottom * rn, trn = top * rn;
float nz = near * nfnz;
float z0 = nz / (nfnx*lrn + nfny*brn - nfnz);
_vertices[0].set(-z0*lrn, -z0*brn, z0);
float z1 = nz / (nfnx*rrn + nfny*brn - nfnz);
_vertices[mirrored ? 3 : 1].set(-z1*rrn, -z1*brn, z1);
float z2 = nz / (nfnx*rrn + nfny*trn - nfnz);
_vertices[2].set(-z2*rrn, -z2*trn, z2);
float z3 = nz / (nfnx*lrn + nfny*trn - nfnz);
_vertices[mirrored ? 1 : 3].set(-z3*lrn, -z3*trn, z3);
float fz = far * nfnz;
float z4 = fz / (nfnx*lrn + nfny*brn - nfnz);
_vertices[4].set(-z4*lrn, -z4*brn, z4);
float z5 = fz / (nfnx*rrn + nfny*brn - nfnz);
_vertices[mirrored ? 7 : 5].set(-z5*rrn, -z5*brn, z5);
float z6 = fz / (nfnx*rrn + nfny*trn - nfnz);
_vertices[6].set(-z6*rrn, -z6*trn, z6);
float z7 = fz / (nfnx*lrn + nfny*trn - nfnz);
_vertices[mirrored ? 5 : 7].set(-z7*lrn, -z7*trn, z7);
}
updateDerivedState();
return this;
}
// /**
// * Transforms this frustum in-place by the specified transformation.
// *
// * @return a reference to this frustum, for chaining.
// */
// public Frustum transformLocal (Transform3D transform)
// {
// return transform(transform, this);
// }
// /**
// * Transforms this frustum by the specified transformation.
// *
// * @return a new frustum containing the result.
// */
// public Frustum transform (Transform3D transform)
// {
// return transform(transform, new Frustum());
// }
// /**
// * Transforms this frustum by the specified transformation, placing the result in the object
// * provided.
// *
// * @return a reference to the result frustum, for chaining.
// */
// public Frustum transform (Transform3D transform, Frustum result)
// {
// // transform all of the vertices
// for (int ii = 0; ii < 8; ii++) {
// transform.transformPoint(_vertices[ii], result._vertices[ii]);
// }
// result.updateDerivedState();
// return result;
// }
/**
* Determines the maximum signed distance of the point from the planes of the frustum. If
* the distance is less than or equal to zero, the point lies inside the frustum.
*/
public float distance (Vector3 point) {
float distance = -Float.MAX_VALUE;
for (Plane plane : _planes) {
distance = Math.max(distance, plane.distance(point));
}
return distance;
}
/**
* Checks whether the frustum intersects the specified box.
*/
public IntersectionType intersectionType (Box box) {
// exit quickly in cases where the bounding boxes don't overlap (equivalent to a separating
// axis test using the axes of the box)
if (!_bounds.intersects(box)) {
return IntersectionType.NONE;
}
// consider each side of the frustum as a potential separating axis
int ccount = 0;
for (int ii = 0; ii < 6; ii++) {
// determine how many vertices fall inside/outside the plane
int inside = 0;
Plane plane = _planes[ii];
for (int jj = 0; jj < 8; jj++) {
if (plane.distance(box.vertex(jj, _vertex)) <= 0f) {
inside++;
}
}
if (inside == 0) {
return IntersectionType.NONE;
} else if (inside == 8) {
ccount++;
}
}
return (ccount == 6) ? IntersectionType.CONTAINS : IntersectionType.INTERSECTS;
}
/**
* Computes the bounds of the frustum under the supplied rotation and places the results in
* the box provided.
*
* @return a reference to the result box, for chaining.
*/
public Box boundsUnderRotation (Matrix3 matrix, Box result) {
result.setToEmpty();
for (Vector3 vertex : _vertices) {
result.addLocal(matrix.transform(vertex, _vertex));
}
return result;
}
/**
* Sets the planes and bounding box of the frustum based on its vertices.
*/
protected void updateDerivedState () {
_planes[0].fromPoints(_vertices[0], _vertices[1], _vertices[2]); // near
_planes[1].fromPoints(_vertices[5], _vertices[4], _vertices[7]); // far
_planes[2].fromPoints(_vertices[1], _vertices[5], _vertices[6]); // left
_planes[3].fromPoints(_vertices[4], _vertices[0], _vertices[3]); // right
_planes[4].fromPoints(_vertices[3], _vertices[2], _vertices[6]); // top
_planes[5].fromPoints(_vertices[4], _vertices[5], _vertices[1]); // bottom
_bounds.fromPoints(_vertices);
}
/** The vertices of the frustum. */
protected Vector3[] _vertices = new Vector3[8];
/** The planes of the frustum (as derived from the vertices). The plane normals point out of
* the frustum. */
protected Plane[] _planes = new Plane[6];
/** The frustum's bounding box (as derived from the vertices). */
protected Box _bounds = new Box();
/** A working vertex. */
protected static Vector3 _vertex = new Vector3();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy