src.gov.nasa.worldwind.pick.PickSupport 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.pick;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.Layer;
import gov.nasa.worldwind.render.DrawContext;
import javax.media.opengl.*;
import java.awt.*;
import java.util.*;
/**
* @author tag
* @version $Id: PickSupport.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class PickSupport
{
/**
* The picked objects currently registered with this PickSupport, represented as a map of color codes to picked
* objects. This maps provides constant time access to a picked object when its color code is known.
*/
protected Map pickableObjects = new HashMap();
/**
* Indicates the minimum and maximum color code associated with the picked objects in the pickableObjects map.
* Initially null
, indicating that the minimum and maximum color codes are unknown.
*/
protected int[] minAndMaxColorCodes;
public void clearPickList()
{
this.getPickableObjects().clear();
this.minAndMaxColorCodes = null; // Reset the min and max color codes.
}
public void addPickableObject(int colorCode, Object o, Position position, boolean isTerrain)
{
this.getPickableObjects().put(colorCode, new PickedObject(colorCode, o, position, isTerrain));
this.adjustExtremeColorCodes(colorCode);
}
public void addPickableObject(int colorCode, Object o, Position position)
{
this.getPickableObjects().put(colorCode, new PickedObject(colorCode, o, position, false));
this.adjustExtremeColorCodes(colorCode);
}
public void addPickableObject(int colorCode, Object o)
{
this.getPickableObjects().put(colorCode, new PickedObject(colorCode, o));
this.adjustExtremeColorCodes(colorCode);
}
public void addPickableObject(PickedObject po)
{
this.getPickableObjects().put(po.getColorCode(), po);
this.adjustExtremeColorCodes(po.getColorCode());
}
public PickedObject getTopObject(DrawContext dc, Point pickPoint)
{
if (this.getPickableObjects().isEmpty())
return null;
int colorCode = this.getTopColor(dc, pickPoint);
if (colorCode == 0) // getTopColor returns 0 if the pick point selects the clear color.
return null;
PickedObject pickedObject = getPickableObjects().get(colorCode);
if (pickedObject == null)
return null;
return pickedObject;
}
/**
* Adds picked object registered with this PickSupport that are drawn at the specified pick point or intersect the
* draw context's pick rectangle to the draw context's list of picked objects. This clears any registered picked
* objects upon returning.
*
* If this pick point is null
, this ignores the pick point and does not attempt to determine which
* picked objects are drawn there. If the draw context's pick rectangle is null
, this ignores the pick
* rectangle and does not attempt to determine which picked objects intersect it. This does nothing if no picked
* objects are currently registered with this PickSupport.
*
* @param dc the draw context which receives the picked object.
* @param pickPoint the point in AWT screen coordinates.
* @param layer the layer associated with the picked object.
*
* @return the picked object added to the draw context, or null
if no picked object is drawn at the
* specified point.
*/
public PickedObject resolvePick(DrawContext dc, Point pickPoint, Layer layer)
{
// Avoid performing any additional work there are no picked objects registered with this PickSupport.
if (this.getPickableObjects().isEmpty())
return null;
PickedObject po = null;
// Resolve the object at the pick point, if any, adding it to the draw context's list of objects at the pick
// point. If any object is at the pick point we return it. Note that the pick point can be null when the pick
// rectangle is specified but the pick point is not.
if (pickPoint != null)
po = this.doResolvePick(dc, pickPoint, layer);
// Resolve the objects in the pick rectangle, if any, adding them to the draw context's list of objects
// intersecting the pick rectangle. Note that the pick rectangle can be null when the pick point is specified
// but the pick rectangle is not.
if (dc.getPickRectangle() != null && !dc.getPickRectangle().isEmpty())
this.doResolvePick(dc, dc.getPickRectangle(), layer);
this.clearPickList();
return po;
}
/**
* Adds a picked object registered with this PickSupport that is drawn at the specified point in AWT screen
* coordinates (if one exists) to the draw context's list of picked objects.
*
* @param dc the draw context which receives the picked object.
* @param pickPoint the point in AWT screen coordinates.
* @param layer the layer associated with the picked object.
*
* @return the picked object added to the draw context, or null
if no picked object is drawn at the
* specified point.
*/
protected PickedObject doResolvePick(DrawContext dc, Point pickPoint, Layer layer)
{
PickedObject pickedObject = this.getTopObject(dc, pickPoint);
if (pickedObject != null)
{
if (layer != null)
pickedObject.setParentLayer(layer);
dc.addPickedObject(pickedObject);
}
return pickedObject;
}
/**
* Adds all picked objects that are registered with this PickSupport and intersect the specified rectangle in AWT
* screen coordinates (if any) to the draw context's list of picked objects.
*
* @param dc the draw context which receives the picked objects.
* @param pickRect the rectangle in AWT screen coordinates.
* @param layer the layer associated with the picked objects.
*/
protected void doResolvePick(DrawContext dc, Rectangle pickRect, Layer layer)
{
// Get the unique pick colors in the specified screen rectangle. Use the minimum and maximum color codes to cull
// the number of colors that the draw context must consider with identifying the unique pick colors in the
// specified rectangle.
int[] colorCodes = dc.getPickColorsInRectangle(pickRect, this.minAndMaxColorCodes);
if (colorCodes == null || colorCodes.length == 0)
return;
// Lookup the pickable object (if any) for each unique color code appearing in the pick rectangle. Each picked
// object that corresponds to a picked color is added to the draw context.
for (int colorCode : colorCodes)
{
if (colorCode == 0) // This should never happen, but we check anyway.
continue;
PickedObject po = this.getPickableObjects().get(colorCode);
if (po == null)
continue;
if (layer != null)
po.setParentLayer(layer);
dc.addObjectInPickRectangle(po);
}
}
/**
* Returns the framebuffer RGB color for a point in AWT screen coordinates, formatted as a pick color code. The red,
* green, and blue components are each stored as an 8-bit unsigned integer, and packed into bits 0-23 of the
* returned integer as follows: bits 16-23 are red, bits 8-15 are green, and bits 0-7 are blue. This format is
* consistent with the RGB integers used to create the pick colors.
*
* This returns 0 if the point is null
, if the point contains the clear color, or if the point is
* outside the draw context's drawable area.
*
* @param dc the draw context to return a color for.
* @param pickPoint the point to return a color for, in AWT screen coordinates.
*
* @return the RGB color corresponding to the specified point.
*/
public int getTopColor(DrawContext dc, Point pickPoint)
{
// This method's implementation has been moved into DrawContext.getPickColor in order to consolidate this logic
// into one place. We've left this method here to avoid removing an interface that applications may rely on.
return pickPoint != null ? dc.getPickColorAtPoint(pickPoint) : 0;
}
public void beginPicking(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
gl.glPushAttrib(GL2.GL_ENABLE_BIT | GL2.GL_CURRENT_BIT);
gl.glDisable(GL.GL_DITHER);
gl.glDisable(GL2.GL_LIGHTING);
gl.glDisable(GL2.GL_FOG);
gl.glDisable(GL.GL_BLEND);
gl.glDisable(GL.GL_TEXTURE_2D);
if (dc.isDeepPickingEnabled())
gl.glDisable(GL.GL_DEPTH_TEST);
}
public void endPicking(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
gl.glPopAttrib();
}
protected Map getPickableObjects()
{
return this.pickableObjects;
}
/**
* Adjust this PickSupport's minimum and maximum color codes by decreasing and increasing each extreme,
* respectively, according to the specified code. If the minimum and maximum color codes are unknown, both the
* minimum and maximum color codes are set to the specified code.
*
* @param colorCode the code used to adjust the current min and max codes.
*/
protected void adjustExtremeColorCodes(int colorCode)
{
if (this.minAndMaxColorCodes == null)
this.minAndMaxColorCodes = new int[] {colorCode, colorCode};
else
{
if (this.minAndMaxColorCodes[0] > colorCode)
this.minAndMaxColorCodes[0] = colorCode;
if (this.minAndMaxColorCodes[1] < colorCode)
this.minAndMaxColorCodes[1] = colorCode;
}
}
/**
* Indicates whether two picked objects refer to the same user object.
*
* @param a the first picked object.
* @param b the second picked object.
*
* @return true if both objects are not null and they refer to the same user object, otherwise false.
*/
public static boolean areSelectionsTheSame(PickedObject a, PickedObject b)
{
return a != null && b != null && a.getObject() == b.getObject();
}
}