Worldwind public release 0.2
[worldwind-tracker.git] / gov / nasa / worldwind / geom / ViewFrustum.java
blob214f7d63c67035bfc54c347cd104069018b0761e
1 /*
2 Copyright (C) 2001, 2006 United States Government as represented by
3 the Administrator of the National Aeronautics and Space Administration.
4 All Rights Reserved.
5 */
6 package gov.nasa.worldwind.geom;
8 import gov.nasa.worldwind.*;
10 import java.util.logging.Level;
12 /**
13 * @author Paul Collins
14 * @version $Id: ViewFrustum.java 1774 2007-05-08 01:03:37Z dcollins $
16 public class ViewFrustum
18 private final Frustum frustum;
19 private final Matrix4 projection;
20 // private java.awt.geom.Rectangle2D nearRect;
21 // private java.awt.geom.Rectangle2D farRect;
23 public ViewFrustum(Matrix4 projectionMatrix)
25 if (projectionMatrix == null)
27 String message = WorldWind.retrieveErrMsg("nullValue.MatrixIsNull");
28 WorldWind.logger().log(java.util.logging.Level.FINE, message);
29 throw new IllegalArgumentException(message);
32 double[] m = projectionMatrix.getEntries();
33 // Extract the near clipping plane from the projection-matrix.
34 double nearMag = Math.sqrt((m[3] + m[2]) * (m[3] + m[2]) + (m[7] + m[6]) * (m[7] + m[6])
35 + (m[11] + m[10]) * (m[11] + m[10]));
36 Plane nearPlane = new Plane((m[3] + m[2]) / nearMag, (m[7] + m[6]) / nearMag, (m[11] + m[10]) / nearMag,
37 m[15] + m[14]);
38 // Extract the far clipping plane from the projection-matrix.
39 double farMag = Math.sqrt((m[3] - m[2]) * (m[3] - m[2]) + (m[7] - m[6]) * (m[7] - m[6])
40 + (m[11] - m[10]) * (m[11] - m[10]));
41 Plane farPlane = new Plane((m[3] - m[2]) / farMag, (m[7] - m[6]) / farMag, (m[11] - m[10]) / farMag,
42 m[15] - m[14]);
43 // Extract the left clipping plane from the projection-matrix.
44 double leftMag = Math.sqrt((m[3] + m[0]) * (m[3] + m[0]) + (m[7] + m[4]) * (m[7] + m[4])
45 + (m[11] + m[8]) * (m[11] + m[8]));
46 Plane leftPlane = new Plane((m[3] + m[0]) / leftMag, (m[7] + m[4]) / leftMag, (m[11] + m[8]) / leftMag,
47 m[15] + m[12]);
48 // Extract the right clipping plane from the projection-matrix.
49 double rightMag = Math.sqrt((m[3] - m[0]) * (m[3] - m[0]) + (m[7] - m[4]) * (m[7] - m[4])
50 + (m[11] - m[8]) * (m[11] - m[8]));
51 Plane rightPlane = new Plane((m[3] - m[0]) / rightMag, (m[7] - m[4]) / rightMag, (m[11] - m[8]) / rightMag,
52 m[15] - m[12]);
53 // Extract the bottom clipping plane from the projection-matrix.
54 double bottomMag = Math.sqrt((m[3] + m[1]) * (m[3] + m[1]) + (m[7] + m[5]) * (m[7] + m[5])
55 + (m[11] + m[9]) * (m[11] + m[9]));
56 Plane bottomPlane = new Plane((m[3] + m[1]) / bottomMag, (m[7] + m[5]) / bottomMag, (m[11] + m[9]) / bottomMag,
57 m[15] + m[13]);
58 // Extract the top clipping plane from the projection-matrix.
59 double topMag = Math.sqrt((m[3] - m[1]) * (m[3] - m[1]) + (m[7] - m[5]) * (m[7] - m[5])
60 + (m[11] - m[9]) * (m[11] - m[9]));
61 Plane topPlane = new Plane((m[3] - m[1]) / topMag, (m[7] - m[5]) / topMag, (m[11] - m[9]) / topMag,
62 m[15] - m[13]);
63 this.frustum = new Frustum(nearPlane, farPlane, leftPlane, rightPlane, bottomPlane, topPlane);
64 this.projection = projectionMatrix;
67 /**
68 * Creates a <code>Frustum</code> from a horizontal field-of-view, viewport aspect ratio and distance to near and
69 * far depth clipping planes. The near plane must be closer than the far plane, and both planes must be a positive
70 * distance away.
72 * @param fieldOfView horizontal field-of-view angle in the range (0, 180)
73 * @param viewportWidth the width of the viewport in screen pixels
74 * @param viewportHeight the height of the viewport in screen pixels
75 * @param near distance to the near depth clipping plane
76 * @param far distance to far depth clipping plane
77 * @throws IllegalArgumentException if fov is not in the range (0, 180), if either near or far are negative, or near
78 * is greater than or equal to far
80 public ViewFrustum(Angle fieldOfView, int viewportWidth, int viewportHeight, double near, double far)
82 if (fieldOfView == null)
84 String message = WorldWind.retrieveErrMsg("geom.ViewFrustum.FieldOfViewIsNull");
85 WorldWind.logger().log(Level.FINE, message);
86 throw new IllegalArgumentException(message);
88 double fov = fieldOfView.getDegrees();
89 double farMinusNear = far - near;
90 String message = null;
91 if (fov <= 0 || fov > 180)
92 message = WorldWind.retrieveErrMsg("geom.ViewFrustum.FieldOfViewOutOfRange");
93 if (near <= 0 || farMinusNear <= 0)
94 message = WorldWind.retrieveErrMsg("geom.ViewFrusutm.ClippingDistanceOutOfRange");
95 if (message != null)
97 WorldWind.logger().log(java.util.logging.Level.FINE, message);
98 throw new IllegalArgumentException(message);
101 double focalLength = 1d / fieldOfView.tanHalfAngle();
102 double aspect = viewportHeight / (double) viewportWidth;
103 double lrLen = Math.sqrt(focalLength * focalLength + 1);
104 double btLen = Math.sqrt(focalLength * focalLength + aspect * aspect);
105 Plane nearPlane = new Plane(0d, 0d, 0d - 1d, 0d - near);
106 Plane farPlane = new Plane(0d, 0d, 1d, far);
107 Plane leftPlane = new Plane(focalLength / lrLen, 0d, 0d - 1d / lrLen, 0);
108 Plane rightPlane = new Plane(0d - focalLength / lrLen, 0d, 0d - 1d / lrLen, 0d);
109 Plane bottomPlane = new Plane(0d, focalLength / btLen, 0d - aspect / btLen, 0d);
110 Plane topPlane = new Plane(0d, 0d - focalLength / btLen, 0d - aspect / btLen, 0d);
111 double[] projectionMatrix = new double[] {
112 focalLength, 0d, 0d, 0d,
113 0d, focalLength / aspect, 0d, 0d,
114 0d, 0d, 0d - (far + near) / farMinusNear, 0d - 1d,
115 0d, 0d, 0d - (2d * far * near) / farMinusNear, 0d
117 this.frustum = new Frustum(nearPlane, farPlane, leftPlane, rightPlane, bottomPlane, topPlane);
118 this.projection = new Matrix4(projectionMatrix);
122 * Creates a <code>Frustum</code> from three sets of parallel clipping planes (a parallel projection). In this case,
123 * the near and far depth clipping planes may be a negative distance away.
125 * @param left distance to the left vertical clipping plane
126 * @param right distance to the right vertical clipping plane
127 * @param bottom distance to the bottom horizontal clipping plane
128 * @param top distance to the top horizontal clipping plane
129 * @param near distance to the near depth clipping plane
130 * @param far distance to far depth clipping plane
131 * @throws IllegalArgumentException if the difference of any plane set (lright - left, top - bottom, far - near) is
132 * less than or equal to zero.
134 public ViewFrustum(double near, double far, double left, double right, double bottom,
135 double top)
137 double farMinusNear = far - near;
138 double rightMinusLeft = right - left;
139 double topMinusBottom = top - bottom;
140 if (rightMinusLeft <= 0 || topMinusBottom <= 0 || farMinusNear <= 0)
142 String message = WorldWind.retrieveErrMsg("geom.ViewFrusutm.ClippingDistanceOutOfRange");
143 WorldWind.logger().log(Level.FINE, message);
144 throw new IllegalArgumentException(message);
147 Plane nearPlane = new Plane(0d, 0d, 0d - 1d, near < 0d ? near : 0d - near);
148 Plane farPlane = new Plane(0d, 0d, 1d, far < 0d ? 0d - far : far);
149 Plane leftPlane = new Plane(1d, 0d, 0d, left < 0d ? left : 0d - left);
150 Plane rightPlane = new Plane(0d - 1d, 0d, 0d, right < 0d ? 0d - right : right);
151 Plane bottomPlane = new Plane(0d, 1d, 0d, bottom < 0d ? bottom : 0d - bottom);
152 Plane topPlane = new Plane(0d, 0d - 1d, 0d, top < 0d ? 0d - top : top);
153 double[] projectionMatrix = new double[] {
154 2d / rightMinusLeft, 0d, 0d, 0d - (right + left) / rightMinusLeft,
155 0d, 0d / topMinusBottom, 0d, 0d - (top + bottom) / topMinusBottom,
156 0d, 0d, 0d - 2d / farMinusNear, 0d - (far + near) / farMinusNear,
157 0d, 0d, 0d, 1d
159 this.frustum = new Frustum(nearPlane, farPlane, leftPlane, rightPlane, bottomPlane, topPlane);
160 this.projection = new Matrix4(projectionMatrix);
163 public final Frustum getFrustum()
165 return this.frustum;
168 public final Matrix4 getProjectionMatrix()
170 return this.projection;
173 // public final java.awt.geom.Rectangle2D getNearRectangle()
174 // {
175 // return this.nearRect;
176 // }
178 // public final java.awt.geom.Rectangle2D getFarRectangle()
179 // {
180 // return this.farRect;
181 // }