Worldwind public release 0.2
[worldwind-tracker.git] / gov / nasa / worldwind / layers / CompassLayer.java
blob1e36ee977a52a52aab82271690935ca4944aac6a
1 /*
2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
5 All Rights Reserved.
6 */
7 package gov.nasa.worldwind.layers;
9 import com.sun.opengl.util.texture.*;
10 import gov.nasa.worldwind.*;
11 import gov.nasa.worldwind.geom.*;
13 import javax.media.opengl.*;
14 import java.io.*;
16 /**
17 * @author tag
18 * @version $Id$
20 public class CompassLayer extends AbstractLayer
22 public final static String NORTHWEST = "gov.nasa.worldwind.CompassLayer.NorthWest";
23 public final static String SOUTHWEST = "gov.nasa.worldwind.CompassLayer.SouthWest";
24 public final static String NORTHEAST = "gov.nasa.worldwind.CompassLayer.NorthEast";
25 public final static String SOUTHEAST = "gov.nasa.worldwind.CompassLayer.SouthEast";
27 /**
28 * On window resize, scales the compass icon to occupy a constant relative size of the viewport.
30 public final static String RESIZE_STRETCH = "gov.nasa.worldwind.CompassLayer.ResizeStretch";
31 /**
32 * On window resize, scales the compass icon to occupy a constant relative size of the viewport, but not larger than
33 * the icon's inherent size scaled by the layer's icon scale factor.
35 public final static String RESIZE_SHRINK_ONLY = "gov.nasa.worldwind.CompassLayer.ResizeShrinkOnly";
36 /**
37 * Does not modify the compass icon size when the window changes size.
39 public final static String RESIZE_KEEP_FIXED_SIZE = "gov.nasa.worldwind.CompassLayer.ResizeKeepFixedSize";
41 private String iconFilePath = "images/notched-compass.png"; // TODO: make configurable
42 private double compassToViewportScale = 0.2; // TODO: make configurable
43 private double iconScale = 0.5;
44 private int borderWidth = 20; // TODO: make configurable
45 private String position = NORTHEAST; // TODO: make configurable
46 private String resizeBehavior = RESIZE_SHRINK_ONLY;
47 private Texture iconTexture = null;
48 private Point locationCenter = null;
49 private boolean showTilt = false;
51 public CompassLayer()
53 this.setOpacity(0.8); // TODO: make configurable
56 public CompassLayer(String iconFilePath)
58 this.setIconFilePath(iconFilePath);
59 this.setOpacity(0.8); // TODO: make configurable
62 /**
63 * Returns the layer's current icon file path.
65 * @return the icon file path
67 public String getIconFilePath()
69 return iconFilePath;
72 /**
73 * Sets the compass icon's image location. The layer first searches for this location in the current Java classpath.
74 * If not found then the specified path is assumed to refer to the local file system. found there then the
76 * @param iconFilePath the path to the icon's image file
78 public void setIconFilePath(String iconFilePath)
80 if (iconFilePath == null)
82 String message = WorldWind.retrieveErrMsg("nullValue.IconFilePath");
83 WorldWind.logger().log(java.util.logging.Level.FINE, message);
84 throw new IllegalArgumentException(message);
86 this.iconFilePath = iconFilePath;
89 /**
90 * Returns the layer's compass-to-viewport scale factor.
92 * @return the compass-to-viewport scale factor
94 public double getCompassToViewportScale()
96 return compassToViewportScale;
99 /**
100 * Sets the scale factor applied to the viewport size to determine the displayed size of the compass icon. This
101 * scale factor is used only when the layer's resize behavior is {@link #RESIZE_STRETCH} or {@link
102 * #RESIZE_SHRINK_ONLY}. The icon's width is adjusted to occupy the proportion of the viewport's width indicated by
103 * this factor. The icon's height is adjusted to maintain the compass image's native aspect ratio.
105 * @param compassToViewportScale the compass to viewport scale factor
107 public void setCompassToViewportScale(double compassToViewportScale)
109 this.compassToViewportScale = compassToViewportScale;
113 * Returns the icon scale factor. See {@link #setIconScale(double)} for a description of the scale factor.
115 * @return the current icon scale
117 public double getIconScale()
119 return iconScale;
123 * Sets the scale factor defining the displayed size of the compass icon relative to the icon's width and height in
124 * its image file. Values greater than 1 magify the image, values less than one minify it. If the layer's resize
125 * behavior is other than {@link #RESIZE_KEEP_FIXED_SIZE}, the icon's displayed sized is further affected by the
126 * value specified by {@link #setCompassToViewportScale(double)} and the current viewport size.
128 * @param iconScale the icon scale factor
130 public void setIconScale(double iconScale)
132 this.iconScale = iconScale;
136 * Returns the compass icon's resize behavior.
138 * @return the icon's resize behavior
140 public String getResizeBehavior()
142 return resizeBehavior;
146 * Sets the behavior the layer uses to size the compass icon when the viewport size changes, typically when the
147 * World Wind window is resized. If the value is {@link #RESIZE_KEEP_FIXED_SIZE}, the icon size is kept to the size
148 * specified in its image file scaled by the layer's current icon scale. If the value is {@link #RESIZE_STRETCH},
149 * the icon is resized to have a constant size relative to the current viewport size. If the viewport shrinks the
150 * icon size decreases; if it expands then the icon file enlarges. The relative size is determined by the current
151 * compass-to-viewport scale and by the icon's image file size scaled by the current icon scale. If the value is
152 * {@link #RESIZE_SHRINK_ONLY} (the default), icon sizing behaves as for {@link #RESIZE_STRETCH} but the icon will
153 * not grow larger than the size specified in its image file scaled by the current icon scale.
155 * @param resizeBehavior the desired resize behavior
157 public void setResizeBehavior(String resizeBehavior)
159 this.resizeBehavior = resizeBehavior;
162 public int getBorderWidth()
164 return borderWidth;
168 * Sets the compass icon offset from the viewport border.
170 * @param borderWidth the number of pixels to offset the compass icon from the borders indicated by {@link
171 * #setPosition(String)}.
173 public void setBorderWidth(int borderWidth)
175 this.borderWidth = borderWidth;
179 * Returns the current relative compass icon position.
181 * @return the current compass position
183 public String getPosition()
185 return position;
189 * Sets the relative viewport location to display the compass icon. Can be one of {@link #NORTHEAST} (the default),
190 * {@link #NORTHWEST}, {@link #SOUTHEAST}, or {@link #SOUTHWEST}. These indicate the corner of the viewport to place
191 * the icon.
193 * @param position the desired compass position
195 public void setPosition(String position)
197 if (position == null)
199 String message = WorldWind.retrieveErrMsg("nullValue.CompassPositionIsNull");
200 WorldWind.logger().log(java.util.logging.Level.FINE, message);
201 throw new IllegalArgumentException(message);
203 this.position = position;
206 public Point getLocationCenter()
208 return locationCenter;
211 public void setLocationCenter(Point locationCenter)
213 this.locationCenter = locationCenter;
216 protected void doRender(DrawContext dc)
218 this.drawIcon(dc);
221 public boolean isShowTilt()
223 return showTilt;
226 public void setShowTilt(boolean showTilt)
228 this.showTilt = showTilt;
231 private void drawIcon(DrawContext dc)
233 if (this.iconFilePath == null)
234 return;
236 GL gl = dc.getGL();
238 boolean attribsPushed = false;
239 boolean modelviewPushed = false;
240 boolean projectionPushed = false;
244 gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT
245 | GL.GL_COLOR_BUFFER_BIT
246 | GL.GL_ENABLE_BIT
247 | GL.GL_TEXTURE_BIT
248 | GL.GL_TRANSFORM_BIT
249 | GL.GL_VIEWPORT_BIT
250 | GL.GL_CURRENT_BIT);
251 attribsPushed = true;
253 if (this.iconTexture == null)
254 this.initializeTexture(dc);
256 gl.glEnable(GL.GL_TEXTURE_2D);
257 iconTexture.bind();
259 gl.glColor4d(1d, 1d, 1d, this.getOpacity());
260 gl.glEnable(GL.GL_BLEND);
261 gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
262 gl.glDisable(GL.GL_DEPTH_TEST);
264 double width = this.getScaledIconWidth();
265 double height = this.getScaledIconHeight();
267 // Load a parallel projection with xy dimensions (viewportWidth, viewportHeight)
268 // into the GL projection matrix.
269 java.awt.Rectangle viewport = dc.getView().getViewport();
270 gl.glMatrixMode(javax.media.opengl.GL.GL_PROJECTION);
271 gl.glPushMatrix();
272 projectionPushed = true;
273 gl.glLoadIdentity();
274 double maxwh = width > height ? width : height;
275 gl.glOrtho(0d, viewport.width, 0d, viewport.height, -0.6 * maxwh, 0.6 * maxwh);
277 gl.glMatrixMode(GL.GL_MODELVIEW);
278 gl.glPushMatrix();
279 modelviewPushed = true;
280 gl.glLoadIdentity();
282 double scale = this.computeScale(viewport);
284 Point locationSW = this.computeLocation(viewport, scale);
286 gl.glTranslated(locationSW.x(), locationSW.y(), locationSW.z());
287 gl.glScaled(scale, scale, 1);
289 gl.glTranslated(width / 2, height / 2, 0);
290 if (this.showTilt) // formula contributed by Ty Hayden
291 gl.glRotated(70d * (dc.getView().getPitch().getDegrees() / 90.0), 1d, 0d, 0d);
292 gl.glRotated(dc.getView().getHeading().getDegrees(), 0d, 0d, 1d);
293 gl.glTranslated(-width / 2, -height / 2, 0);
295 TextureCoords texCoords = this.iconTexture.getImageTexCoords();
296 gl.glScaled(width, height, 1d);
297 dc.drawUnitQuad(texCoords);
299 finally
301 if (projectionPushed)
303 gl.glMatrixMode(GL.GL_PROJECTION);
304 gl.glPopMatrix();
306 if (modelviewPushed)
308 gl.glMatrixMode(GL.GL_MODELVIEW);
309 gl.glPopMatrix();
311 if (attribsPushed)
312 gl.glPopAttrib();
316 private double computeScale(java.awt.Rectangle viewport)
318 if (this.resizeBehavior.equals(RESIZE_SHRINK_ONLY))
320 return Math.min(1d, (this.compassToViewportScale) * viewport.width / this.getScaledIconWidth());
322 else if (this.resizeBehavior.equals(RESIZE_STRETCH))
324 return (this.compassToViewportScale) * viewport.width / this.getScaledIconWidth();
326 else if (this.resizeBehavior.equals(RESIZE_KEEP_FIXED_SIZE))
328 return 1d;
330 else
332 return 1d;
336 private double getScaledIconWidth()
338 return this.iconTexture.getWidth() * this.iconScale;
341 private double getScaledIconHeight()
343 return this.iconTexture.getHeight() * this.iconScale;
346 private Point computeLocation(java.awt.Rectangle viewport, double scale)
348 double width = this.getScaledIconWidth();
349 double height = this.getScaledIconHeight();
351 double scaledWidth = scale * width;
352 double scaledHeight = scale * height;
354 double x;
355 double y;
357 if (this.locationCenter != null)
359 x = viewport.getWidth() - scaledWidth / 2 - this.borderWidth;
360 y = viewport.getHeight() - scaledHeight / 2 - this.borderWidth;
362 else if (this.position.equals(NORTHEAST))
364 x = viewport.getWidth() - scaledWidth - this.borderWidth;
365 y = viewport.getHeight() - scaledHeight - this.borderWidth;
367 else if (this.position.equals(SOUTHEAST))
369 x = viewport.getWidth() - scaledWidth - this.borderWidth;
370 y = 0d + this.borderWidth;
372 else if (this.position.equals(NORTHWEST))
374 x = 0d + this.borderWidth;
375 y = viewport.getHeight() - scaledHeight - this.borderWidth;
377 else if (this.position.equals(SOUTHWEST))
379 x = 0d + this.borderWidth;
380 y = 0d + this.borderWidth;
382 else // use North East
384 x = viewport.getWidth() - scaledWidth / 2 - this.borderWidth;
385 y = viewport.getHeight() - scaledHeight / 2 - this.borderWidth;
388 return new gov.nasa.worldwind.geom.Point(x, y, 0);
391 private void initializeTexture(DrawContext dc)
393 if (this.iconTexture != null)
394 return;
398 InputStream iconStream = this.getClass().getResourceAsStream("/" + this.iconFilePath);
399 if (iconStream == null)
401 File iconFile = new File(this.iconFilePath);
402 if (iconFile.exists())
404 iconStream = new FileInputStream(iconFile);
408 this.iconTexture = TextureIO.newTexture(iconStream, true, null);
409 this.iconTexture.bind();
411 catch (IOException e)
413 String msg = WorldWind.retrieveErrMsg(
414 "layers.TrackLayer.IOExceptionDuringInitialization");
415 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
416 throw new WWRuntimeException(msg, e);
419 GL gl = dc.getGL();
420 gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
421 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR);
422 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
423 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
424 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
425 // Enable texture anisotropy, improves "tilted" compass quality.
426 int[] maxAnisotropy = new int[1];
427 gl.glGetIntegerv(GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy, 0);
428 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy[0]);
431 @Override
432 public String toString()
434 return WorldWind.retrieveErrMsg("layers.CompassLayer.Name");