2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
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
.*;
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";
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";
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";
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;
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
63 * Returns the layer's current icon file path.
65 * @return the icon file path
67 public String
getIconFilePath()
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
;
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
;
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()
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()
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()
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
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
)
221 public boolean isShowTilt()
226 public void setShowTilt(boolean showTilt
)
228 this.showTilt
= showTilt
;
231 private void drawIcon(DrawContext dc
)
233 if (this.iconFilePath
== null)
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
248 | GL
.GL_TRANSFORM_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
);
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
);
272 projectionPushed
= true;
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
);
279 modelviewPushed
= true;
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
);
301 if (projectionPushed
)
303 gl
.glMatrixMode(GL
.GL_PROJECTION
);
308 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
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
))
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
;
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)
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
);
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]);
432 public String
toString()
434 return WorldWind
.retrieveErrMsg("layers.CompassLayer.Name");