src.gov.nasa.worldwind.layers.IconLayer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of worldwindx Show documentation
Show all versions of worldwindx Show documentation
World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.layers;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.terrain.SectorGeometryList;
import gov.nasa.worldwind.util.*;
import java.util.*;
/**
* The IconLayer
class manages a collection of {@link gov.nasa.worldwind.render.WWIcon} objects for
* rendering and picking. IconLayer
delegates to its internal {@link gov.nasa.worldwind.render.IconRenderer}
* for rendering and picking operations.
*
* @author tag
* @version $Id: IconLayer.java 1935 2014-04-15 19:25:18Z tgaskins $
* @see gov.nasa.worldwind.render.WWIcon
* @see gov.nasa.worldwind.render.IconRenderer
*/
public class IconLayer extends AbstractLayer
{
protected final BasicQuadTree icons = new BasicQuadTree(8, Sector.FULL_SPHERE, null, false);
protected Iterable iconsOverride;
protected IconRenderer iconRenderer = new IconRenderer();
private Pedestal pedestal;
private boolean regionCulling = true;
// These enable the render pass to use the same non-culled icons computed by the pick pass.
protected Set lastActiveIcons;
protected long frameId;
/** Creates a new IconLayer
with an empty collection of Icons. */
public IconLayer()
{
}
/**
* Adds the specified icon
to this layer's internal collection. If this layer's internal collection has
* been overridden with a call to {@link #setIcons}, this will throw an exception.
*
* @param icon Icon to add.
*
* @throws IllegalArgumentException If icon
is null.
* @throws IllegalStateException If a custom Iterable has been specified by a call to setIcons
.
*/
public void addIcon(WWIcon icon)
{
if (icon == null)
{
String msg = Logging.getMessage("nullValue.Icon");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (this.iconsOverride != null)
{
String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable");
Logging.logger().severe(msg);
throw new IllegalStateException(msg);
}
this.icons.add(icon, icon.getPosition().asDegreesArray());
}
/**
* Adds the contents of the specified icons
to this layer's internal collection. If this layer's
* internal collection has been overriden with a call to {@link #setIcons}, this will throw an exception.
*
* @param icons Icons to add.
*
* @throws IllegalArgumentException If icons
is null.
* @throws IllegalStateException If a custom Iterable has been specified by a call to setIcons
.
*/
public void addIcons(Iterable icons)
{
if (icons == null)
{
String msg = Logging.getMessage("nullValue.IterableIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (this.iconsOverride != null)
{
String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable");
Logging.logger().severe(msg);
throw new IllegalStateException(msg);
}
for (WWIcon icon : icons)
{
// Internal list of icons does not accept null values.
if (icon != null)
this.icons.add(icon, icon.getPosition().asDegreesArray());
}
}
/**
* Removes the specified icon
from this layer's internal collection, if it exists. If this layer's
* internal collection has been overriden with a call to {@link #setIcons}, this will throw an exception.
*
* @param icon Icon to remove.
*
* @throws IllegalArgumentException If icon
is null.
* @throws IllegalStateException If a custom Iterable has been specified by a call to setIcons
.
*/
public void removeIcon(WWIcon icon)
{
if (icon == null)
{
String msg = Logging.getMessage("nullValue.Icon");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (this.iconsOverride != null)
{
String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable");
Logging.logger().severe(msg);
throw new IllegalStateException(msg);
}
this.icons.remove(icon);
}
/**
* Clears the contents of this layer's internal Icon collection. If this layer's internal collection has been
* overridden with a call to {@link #setIcons}, this will throw an exception.
*
* @throws IllegalStateException If a custom Iterable has been specified by a call to setIcons
.
*/
public void removeAllIcons()
{
if (this.iconsOverride != null)
{
String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable");
Logging.logger().severe(msg);
throw new IllegalStateException(msg);
}
this.clearIcons();
}
protected void clearIcons()
{
if (this.icons != null)
this.icons.clear();
}
/**
* Returns the Iterable of Icons currently in use by this layer. If the caller has specified a custom Iterable via
* {@link #setIcons}, this will returns a reference to that Iterable. If the caller passed setIcons
a
* null parameter, or if setIcons
has not been called, this returns a view of this layer's internal
* collection of Icons. The view has no definitive order and may contain duplicate entries.
*
* @return Iterable of currently active Icons.
*/
public Iterable getIcons()
{
if (this.iconsOverride != null)
return this.iconsOverride;
if (this.icons != null)
return this.icons;
return Collections.emptyList();
}
/**
* Indicates whether the layer culls icons whose latitude-longitude location is outside the visible terrain area.
* See {@link #setRegionCulling(boolean)} for a fuller description of region culling.
*
* @return regionCulling true if region culling is performed, otherwise false.
*/
public boolean isRegionCulling()
{
return this.regionCulling;
}
/**
* Indicates whether the layer culls icons whose latitude-longitude location is outside the visible terrain area.
* This typically provides better performance when some icons are not in view. However, it might remove icons at
* high altitude over the horizon.
*
* @param regionCulling true if region culling is performed, otherwise false.
*/
public void setRegionCulling(boolean regionCulling)
{
this.regionCulling = regionCulling;
}
/**
* Returns the Iterable of currently active Icons. If the caller has specified a custom Iterable via {@link
* #setIcons}, this will returns a reference to that Iterable. If the caller passed setIcons
a null
* parameter, or if setIcons
has not been called, this returns a view of this layer's internal
* collection of Icons, culled to eliminate those outside the current sector geometry.
*
* @param dc a current DrawContext.
*
* @return Iterable of currently active Icons.
*/
protected Iterable getActiveIcons(DrawContext dc)
{
if (this.iconsOverride != null)
return this.iconsOverride;
if (this.lastActiveIcons != null && this.frameId == dc.getFrameTimeStamp())
return this.lastActiveIcons;
this.lastActiveIcons = null;
if (!this.isRegionCulling())
return this.icons;
SectorGeometryList sgList = dc.getSurfaceGeometry();
if (sgList == null || sgList.size() == 0)
return Collections.emptyList();
this.lastActiveIcons = this.icons.getItemsInRegions(sgList, new HashSet());
this.frameId = dc.getFrameTimeStamp();
return this.lastActiveIcons;
}
/**
* Overrides the collection of currently active Icons with the specified iconIterable
. This layer will
* maintain a reference to iconIterable
strictly for picking and rendering. This layer will not modify
* the Iterable reference. However, this will clear the internal collection of Icons, and will prevent any
* modification to its contents via addIcon, addIcons, or removeIcons
.
*
* If the specified iconIterable
is null, this layer will revert to maintaining its internal
* collection.
*
* @param iconIterable Iterable to use instead of this layer's internal collection, or null to use this layer's
* internal collection.
*/
public void setIcons(Iterable iconIterable)
{
this.iconsOverride = iconIterable;
// Clear the internal collection of Icons.
clearIcons();
}
/**
* Returns the Pedestal
used by this layers internal IconRenderer
.
*
* @return Pedestal
used by this layers internal IconRenderer
.
*/
public Pedestal getPedestal()
{
return pedestal;
}
/**
* Sets the Pedestal
used by this layers internal IconRenderer
.
*
* @param pedestal Pedestal
to be used by this layers internal IconRenderer
.
*/
public void setPedestal(Pedestal pedestal)
{
this.pedestal = pedestal;
}
/**
* Indicates whether horizon clipping is performed.
*
* @return true
if horizon clipping is performed, otherwise false
.
*
* @see #setHorizonClippingEnabled(boolean)
*/
public boolean isHorizonClippingEnabled()
{
return this.iconRenderer.isHorizonClippingEnabled();
}
/**
* Indicates whether to render icons beyond the horizon. If view culling is enabled, the icon is also tested for
* view volume inclusion. The default is false
, horizon clipping is not performed.
*
* @param horizonClippingEnabled true
if horizon clipping should be performed, otherwise
* false
.
*
* @see #setViewClippingEnabled(boolean)
*/
public void setHorizonClippingEnabled(boolean horizonClippingEnabled)
{
this.iconRenderer.setHorizonClippingEnabled(horizonClippingEnabled);
}
/**
* Indicates whether view volume clipping is performed.
*
* @return true
if view volume clipping is performed, otherwise false
.
*
* @see #setViewClippingEnabled(boolean)
*/
public boolean isViewClippingEnabled()
{
return this.iconRenderer.isViewClippingEnabled();
}
/**
* Indicates whether to render icons outside the view volume. This is primarily to control icon visibility beyond
* the far view clipping plane. Some important use cases demand that clipping not be performed. If horizon clipping
* is enabled, the icon is also tested for horizon clipping. The default is false
, view volume clipping
* is not performed.
*
* @param viewClippingEnabled true
if view clipping should be performed, otherwise false
.
*
* @see #setHorizonClippingEnabled(boolean)
*/
public void setViewClippingEnabled(boolean viewClippingEnabled)
{
this.iconRenderer.setViewClippingEnabled(viewClippingEnabled);
}
/**
* Indicates whether picking volume clipping is performed.
*
* @return true
if picking volume clipping is performed, otherwise false
.
*
* @see #setViewClippingEnabled(boolean)
*/
public boolean isPickFrustumClippingEnabled()
{
return this.iconRenderer.isPickFrustumClippingEnabled();
}
/**
* Indicates whether to render icons outside the picking volume when in pick mode. This increases performance by
* only drawing the icons within the picking volume when picking is enabled. Some important use cases demand that
* clipping not be performed. The default is false
, picking volume clipping is not performed.
*
* @param pickFrustumClippingEnabled true
if picking clipping should be performed, otherwise
* false
.
*/
public void setPickFrustumClippingEnabled(boolean pickFrustumClippingEnabled)
{
this.iconRenderer.setPickFrustumClippingEnabled(pickFrustumClippingEnabled);
}
/**
* Indicates whether an icon's elevation is treated as an offset from the terrain or an absolute elevation above sea
* level.
*
* @return true
if icon elevations are treated as absolute, false
if they're treated as
* offsets from the terrain.
*/
public boolean isAlwaysUseAbsoluteElevation()
{
return this.iconRenderer.isAlwaysUseAbsoluteElevation();
}
/**
* Normally, an icon's elevation is treated as an offset from the terrain when it is less than the globe's maximum
* elevation. Setting #setAlwaysUseAbsoluteElevation to true
causes the elevation to be treated as an
* absolute elevation above sea level.
*
* @param alwaysUseAbsoluteElevation true
to treat icon elevations as absolute, false
to
* treat them as offsets from the terrain.
*/
public void setAlwaysUseAbsoluteElevation(boolean alwaysUseAbsoluteElevation)
{
this.iconRenderer.setAlwaysUseAbsoluteElevation(alwaysUseAbsoluteElevation);
}
/**
* Opacity is not applied to layers of this type. The icon image is assumed to indicates its opacity.
*
* @param opacity the current opacity value, which is ignored by this layer.
*/
@Override
public void setOpacity(double opacity)
{
super.setOpacity(opacity);
}
/**
* Returns the layer's opacity value, which is ignored by this layer the icon's image is assumed to indicate its
* opacity.
*
* @return The layer opacity, a value between 0 and 1.
*/
@Override
public double getOpacity()
{
return super.getOpacity();
}
/**
* Indicates whether icons are picked as a batch and therefore a {@link gov.nasa.worldwind.event.SelectEvent} will
* contain only one icon from the layer. Batch picking is much faster than individual picking, so this attribute
* should be used judiciously.
*
* @return true if batch picking is allowed, otherwise false.
*
* @see #setAllowBatchPicking(boolean)
*/
public boolean isAllowBatchPicking()
{
return this.iconRenderer.isAllowBatchPicking();
}
/**
* Specifies whether batch picking is allowed. If so, a {@link gov.nasa.worldwind.event.SelectEvent} from the layer
* will contain only one icon even if several overlapping icons are at the pick point. Batch picking is much faster
* than individual picking so the default value is true.
*
* @param allowBatchPicking true if batch picking is allowed, otherwise false.
*/
public void setAllowBatchPicking(boolean allowBatchPicking)
{
this.iconRenderer.setAllowBatchPicking(allowBatchPicking);
}
@Override
protected void doPick(DrawContext dc, java.awt.Point pickPoint)
{
this.iconRenderer.setPedestal(this.pedestal);
this.iconRenderer.pick(dc, getActiveIcons(dc), pickPoint, this);
}
@Override
protected void doRender(DrawContext dc)
{
this.iconRenderer.setPedestal(this.pedestal);
this.iconRenderer.render(dc, getActiveIcons(dc));
}
@Override
public String toString()
{
return Logging.getMessage("layers.IconLayer.Name");
}
}