gov.nasa.worldwind.layers.IconLayer Maven / Gradle / Ivy
The newest version!
/*
* 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.globes.GlobeStateKey;
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 2140 2014-07-10 18:56:05Z 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 fields enable the render pass to use the same non-culled icons computed by the pick pass.
protected HashMap> lastActiveIconsLists = new HashMap>(1);
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;
// Use the active icons computed in the pick pass.
Set lastActiveIcons = this.lastActiveIconsLists.get(dc.getGlobe().getGlobeStateKey());
this.lastActiveIconsLists.remove(dc.getGlobe().getGlobeStateKey()); // remove it on re-use
if (lastActiveIcons != null && this.frameId == dc.getFrameTimeStamp())
return lastActiveIcons;
if (!this.isRegionCulling())
return this.icons;
SectorGeometryList sgList = dc.getSurfaceGeometry();
if (sgList == null || sgList.size() == 0)
return Collections.emptyList();
lastActiveIcons = this.icons.getItemsInRegions(sgList, new HashSet());
this.lastActiveIconsLists.put(dc.getGlobe().getGlobeStateKey(), lastActiveIcons);
this.frameId = dc.getFrameTimeStamp();
return 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");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy