basicannotationrenderer.java
来自「world wind java sdk 源码」· Java 代码 · 共 404 行
JAVA
404 行
/*
Copyright (C) 2001, 2006, 2007 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.render;
import gov.nasa.worldwind.Locatable;
import gov.nasa.worldwind.exception.WWRuntimeException;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.layers.*;
import gov.nasa.worldwind.pick.PickSupport;
import gov.nasa.worldwind.terrain.SectorGeometryList;
import gov.nasa.worldwind.util.*;
import javax.media.opengl.GL;
import java.awt.*;
import java.util.Iterator;
import java.util.logging.Level;
/**
* Basic implementation of AnnotationRenderer. Process Annotation rendering as OrderedRenderable objects batch.
*
* @author Patrick Murris
* @version $Id: BasicAnnotationRenderer.java 10542 2009-04-27 17:28:30Z dcollins $
* @see AbstractAnnotation
* @see AnnotationAttributes
* @see AnnotationLayer
*/
public class BasicAnnotationRenderer implements AnnotationRenderer
{
private PickSupport pickSupport = new PickSupport();
private static boolean isAnnotationValid(Annotation annotation, boolean checkPosition)
{
if (annotation == null || annotation.getText() == null)
return false;
//noinspection RedundantIfStatement,SimplifiableIfStatement
if (checkPosition && annotation instanceof Locatable)
return ((Locatable)annotation).getPosition() != null;
return true;
}
public void pick(DrawContext dc, Iterable<Annotation> annotations, Point pickPoint, Layer layer)
{
this.drawMany(dc, annotations, layer);
}
public void pick(DrawContext dc, Annotation annotation, Vec4 annotationPoint, java.awt.Point pickPoint, Layer layer)
{
if (!isAnnotationValid(annotation, false))
return;
this.drawOne(dc, annotation, annotationPoint, layer);
}
public void render(DrawContext dc, Iterable<Annotation> annotations)
{
this.drawMany(dc, annotations, null);
}
public void render(DrawContext dc, Annotation annotation, Vec4 annotationPoint)
{
if (!isAnnotationValid(annotation, false))
return;
this.drawOne(dc, annotation, annotationPoint, null);
}
private void drawMany(DrawContext dc, Iterable<Annotation> annotations, Layer layer)
{
if (dc == null)
{
String msg = Logging.getMessage("nullValue.DrawContextIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (dc.getVisibleSector() == null)
return;
SectorGeometryList geos = dc.getSurfaceGeometry();
//noinspection RedundantIfStatement
if (geos == null)
return;
if (annotations == null)
{
String msg = Logging.getMessage("nullValue.AnnotationIterator");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
Iterator<Annotation> iterator = annotations.iterator();
if (!iterator.hasNext())
return;
while (iterator.hasNext())
{
Annotation annotation = iterator.next();
if (!isAnnotationValid(annotation, true))
continue;
if (!annotation.getAttributes().isVisible())
continue;
// TODO: cull annotations that are beyound the horizon or outside the view frustrum
double eyeDistance = 1;
if (annotation instanceof Locatable)
{
// Determine Cartesian position from the surface geometry if the annotation is near the surface,
// otherwise draw it from the globe.
Vec4 annotationPoint = getAnnotationDrawPoint(dc, annotation);
if (annotationPoint == null)
continue;
eyeDistance = annotation.isAlwaysOnTop() ? 0 : dc.getView().getEyePoint().distanceTo3(annotationPoint);
}
// The annotations aren't drawn here, but added to the ordered queue to be drawn back-to-front.
dc.addOrderedRenderable(new OrderedAnnotation(annotation, layer, eyeDistance));
}
}
private void drawOne(DrawContext dc, Annotation annotation, Vec4 annotationPoint, Layer layer)
{
if (dc == null)
{
String msg = Logging.getMessage("nullValue.DrawContextIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (dc.getVisibleSector() == null)
return;
SectorGeometryList geos = dc.getSurfaceGeometry();
//noinspection RedundantIfStatement
if (geos == null)
return;
if (!annotation.getAttributes().isVisible())
return;
double eyeDistance = 1;
if (annotation instanceof Locatable)
{
if (annotationPoint == null)
{
Position pos = ((Locatable)annotation).getPosition();
if (!dc.getVisibleSector().contains(pos.getLatitude(), pos.getLongitude()))
return;
// Determine Cartesian position from the surface geometry if the annotation is near the surface,
// otherwise draw it from the globe.
annotationPoint = getAnnotationDrawPoint(dc, annotation);
if (annotationPoint == null)
return;
}
if (!dc.getView().getFrustumInModelCoordinates().contains(annotationPoint))
return;
double horizon = dc.getView().computeHorizonDistance();
eyeDistance = annotation.isAlwaysOnTop() ? 0 : dc.getView().getEyePoint().distanceTo3(annotationPoint);
if (eyeDistance > horizon)
return;
}
// The annotation isn't drawn here, but added to the ordered queue to be drawn back-to-front.
dc.addOrderedRenderable(new OrderedAnnotation(annotation, layer, eyeDistance));
}
/**
* Get the final Vec4 point at which an annotation will be drawn. If the annotation Position elevation
* is lower then the highest elevation on the globe, it will be drawn above the ground using its elevation as an
* offset. Otherwise, the original elevation will be used.
* @param dc the current DrawContext.
* @param annotation the annotation
* @return the annotation draw cartesian point
*/
public Vec4 getAnnotationDrawPoint(DrawContext dc, Annotation annotation)
{
Vec4 drawPoint = null;
if(annotation instanceof Locatable)
{
Position pos = ((Locatable)annotation).getPosition();
if (pos.getElevation() < dc.getGlobe().getMaxElevation())
drawPoint = dc.getSurfaceGeometry().getSurfacePoint(pos.getLatitude(), pos.getLongitude(), pos.getElevation());
if (drawPoint == null)
drawPoint = dc.getGlobe().computePointFromPosition(pos);
}
return drawPoint;
}
private class OrderedAnnotation implements OrderedRenderable
{
Annotation annotation;
double eyeDistance;
Layer layer;
OrderedAnnotation(Annotation annotation, double eyeDistance)
{
this.annotation = annotation;
this.eyeDistance = eyeDistance;
}
OrderedAnnotation(Annotation annotation, Layer layer, double eyeDistance)
{
this.annotation = annotation;
this.eyeDistance = eyeDistance;
this.layer = layer;
}
public double getDistanceFromEye()
{
return this.eyeDistance;
}
public void render(DrawContext dc)
{
OGLStackHandler stackHandler = new OGLStackHandler();
BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
try
{
this.annotation.renderNow(dc);
// Draw as many as we can in a batch to save ogl state switching.
while (dc.getOrderedRenderables().peek() instanceof OrderedAnnotation)
{
OrderedAnnotation oa = (OrderedAnnotation) dc.getOrderedRenderables().poll();
oa.annotation.renderNow(dc);
}
}
catch (WWRuntimeException e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
}
catch (Exception e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
}
finally
{
BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
}
}
public void pick(DrawContext dc, java.awt.Point pickPoint)
{
OGLStackHandler stackHandler = new OGLStackHandler();
BasicAnnotationRenderer.this.pickSupport.clearPickList();
BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
try
{
this.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
this.annotation.renderNow(dc);
// Draw as many as we can in a batch to save ogl state switching.
while (dc.getOrderedRenderables().peek() instanceof OrderedAnnotation)
{
OrderedAnnotation oa = (OrderedAnnotation) dc.getOrderedRenderables().poll();
oa.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
oa.annotation.renderNow(dc);
}
}
catch (WWRuntimeException e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
}
catch (Exception e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
}
finally
{
BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
BasicAnnotationRenderer.this.pickSupport.resolvePick(dc, pickPoint, this.layer);
BasicAnnotationRenderer.this.pickSupport.clearPickList(); // to ensure entries can be garbage collected
}
}
}
private void beginDrawAnnotations(DrawContext dc, OGLStackHandler stackHandler)
{
GL gl = dc.getGL();
OGLStateSupport stateSupport = new OGLStateSupport();
stateSupport.setEnableAlphaTest(true);
stateSupport.setEnableBlending(!dc.isPickingMode());
stateSupport.setColorMode(OGLStateSupport.COLOR_PREMULTIPLIED_ALPHA);
int attributeMask = stateSupport.getAttributeBits()
| GL.GL_COLOR_BUFFER_BIT // for alpha test func and ref, and blend
| GL.GL_CURRENT_BIT // for current color
| GL.GL_DEPTH_BUFFER_BIT // for depth test, depth mask and depth func
| GL.GL_ENABLE_BIT // for enable/disable changes
| GL.GL_HINT_BIT // for line smoothing hint
| GL.GL_LINE_BIT // for line width, line stipple
| GL.GL_TEXTURE_BIT // for texture env
| GL.GL_TRANSFORM_BIT // for matrix mode
| GL.GL_VIEWPORT_BIT; // for viewport, depth range
stackHandler.pushAttrib(gl, attributeMask);
// Load a parallel projection with dimensions (viewportWidth, viewportHeight)
stackHandler.pushProjectionIdentity(gl);
int[] viewport = new int[4];
gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
gl.glOrtho(0d, viewport[2], 0d, viewport[3], -1d, 1d);
// Push identity matrices on the texture and modelview matrix stacks. Leave the matrix mode as modelview.
stackHandler.pushTextureIdentity(gl);
stackHandler.pushModelviewIdentity(gl);
// Apply the depth buffer but don't change it.
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthMask(false);
// Disable lighting and backface culling.
gl.glDisable(GL.GL_LIGHTING);
gl.glDisable(GL.GL_CULL_FACE);
// Enable the alpha test, enable blending, apply the blending func.
stateSupport.apply(gl);
if (dc.isPickingMode())
{
this.pickSupport.beginPicking(dc);
}
}
private void endDrawAnnotations(DrawContext dc, OGLStackHandler stackHandler)
{
GL gl = dc.getGL();
if (dc.isPickingMode())
{
this.pickSupport.endPicking(dc);
}
stackHandler.pop(gl);
}
//
//
// //-- Collision avoidance ---------------------------------------------------
// ArrayList<Rectangle> usedRectangles = new ArrayList<Rectangle>();
// Point defaultDrawOffset = new Point(-10, 20);
//
// // Try to find a free rectangular space around a point
// // TODO: Fix me
// private Point computeOffset(Point point, Dimension dimension)
// {
// Point offset = this.defaultDrawOffset;
// Rectangle r = new Rectangle(point.x + offset.x - dimension.width / 2,
// point.y + offset.y + dimension.height,
// dimension.width, dimension.height);
// double radius = 20;
// Angle angle = Angle.ZERO;
// int step = 0;
// int angleStep = 1;
// while(rectangleIntersectsUsed(r))
// {
// // Give up after some number of tries
// if(step++ > 100)
// {
// usedRectangles.clear();
// return this.defaultDrawOffset;
// }
//
// // Increment angle and radius
// int a = 90 + (10 * (angleStep / 2) * (angleStep % 2 == 0 ? 1 : -1));
// if(Math.abs(a) <= 10)
// {
// angleStep = 1;
// radius += 50;
// }
// else
// angleStep++;
//
// // Compute new rectangle
// angle = Angle.fromDegrees(a);
// offset.x = (int)(radius * angle.cos());
// offset.y = (int)(radius * angle.sin());
// r.setBounds(point.x + offset.x - dimension.width / 2,
// point.y + offset.y + dimension.height,
// dimension.width, dimension.height);
// }
//
// // Keep track of used rectangle
// this.usedRectangles.add(r);
//
// return offset;
// }
//
// // Test if a rectangle intersects one of the previously used rectangles
// private boolean rectangleIntersectsUsed(Rectangle r)
// {
// for(Rectangle ur : this.usedRectangles)
// if(r.intersects(ur))
// return true;
// return false;
// }
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?