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 + -
显示快捷键?