globeannotation.java

来自「world wind java sdk 源码」· Java 代码 · 共 357 行

JAVA
357
字号
/*
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.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.util.*;

import javax.media.opengl.GL;
import java.awt.*;

/**
 * Represent a text label attached to a Position on the globe and its rendering attributes.
 * @author Patrick Murris
 * @version $Id: GlobeAnnotation.java 10542 2009-04-27 17:28:30Z dcollins $
 * @see AbstractAnnotation
 * @see AnnotationAttributes
 */
public class GlobeAnnotation extends AbstractAnnotation implements Locatable, Movable
{
    private Position position;

    /**
     * Creates a <code>GlobeAnnotation</code> with the given text, at the given globe <code>Position</code>.
     * @param text the annotation text.
     * @param position the annotation <code>Position</code>.
     */
    public GlobeAnnotation(String text, Position position)
    {
        this.init(text, position, null, null);
    }

    /**
     * Creates a <code>GlobeAnnotation</code> with the given text, at the given globe <code>Position</code>.
     * Specifiy the <code>Font</code> to be used.
     * @param text the annotation text.
     * @param position the annotation <code>Position</code>.
     * @param font the <code>Font</code> to use.
     */
    public GlobeAnnotation(String text, Position position, Font font)
    {
        this.init(text, position, font, null);
    }

    /**
     * Creates a <code>GlobeAnnotation</code> with the given text, at the given globe <code>Position</code>.
     * Specifiy the <code>Font</code> and text <code>Color</code> to be used.
     * @param text the annotation text.
     * @param position the annotation <code>Position</code>.
     * @param font the <code>Font</code> to use.
     * @param textColor the text <code>Color</code>.
     */
    public GlobeAnnotation(String text, Position position, Font font, Color textColor)
    {
        this.init(text, position, font, textColor);
    }

    /**
     * Creates a <code>GlobeAnnotation</code> with the given text, at the given globe <code>Position</code>.
     * Specify the default {@link AnnotationAttributes} set.
     * @param text the annotation text.
     * @param position the annotation <code>Position</code>.
     * @param defaults the default {@link AnnotationAttributes} set.
     */
    public GlobeAnnotation(String text, Position position, AnnotationAttributes defaults)
    {
        if (text == null)
        {
            String message = Logging.getMessage("nullValue.StringIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        if (position == null)
        {
            String message = Logging.getMessage("nullValue.PositionIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        if (defaults == null)
        {
            String message = Logging.getMessage("nullValue.AnnotationAttributesIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        this.setText(text);
        this.position = position;
        this.getAttributes().setDefaults(defaults);
    }

    private void init(String text, Position position, Font font, Color textColor)
    {
        if (text == null)
        {
            String message = Logging.getMessage("nullValue.StringIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        if (position == null)
        {
            String message = Logging.getMessage("nullValue.PositionIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        this.setText(text);
        this.position = position;
        this.getAttributes().setFont(font);
        this.getAttributes().setTextColor(textColor);
    }

    public Position getPosition()
    {
        return this.position;
    }

    public void setPosition(Position position)
    {
        this.position = position;
    }

    public void move(Position position)
    {
        if (position == null)
        {
            String msg = Logging.getMessage("nullValue.PositionIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        this.position = this.position.add(position);
    }

    public void moveTo(Position position)
    {
        if (position == null)
        {
            String msg = Logging.getMessage("nullValue.PositionIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        this.position = position;
    }

    public Position getReferencePosition()
    {
        return this.position;
    }
    
    //**************************************************************//
    //********************  Rendering  *****************************//
    //**************************************************************//

    protected void doRenderNow(DrawContext dc)
    {
        if (dc.isPickingMode() && this.getPickSupport() == null)
            return;

        Vec4 point = dc.getAnnotationRenderer().getAnnotationDrawPoint(dc, this);
        if (point == null)
            return;

        if (dc.getView().getFrustumInModelCoordinates().getNear().distanceTo(point) < 0)
            return;

        Vec4 screenPoint = dc.getView().project(point);
        if (screenPoint == null)
            return;

        java.awt.Dimension size = this.getPreferredSize(dc);
        Position pos = dc.getGlobe().computePositionFromPoint(point);

        // Determine scale and opacity factors based on distance from eye vs the distance to the look at point.
        double lookAtDistance = this.computeLookAtDistance(dc);
        double eyeDistance = dc.getView().getEyePoint().distanceTo3(point);
        double distanceFactor = Math.sqrt(lookAtDistance / eyeDistance);
        double scale = WWMath.clamp(distanceFactor,
            this.attributes.getDistanceMinScale(), this.attributes.getDistanceMaxScale());
        double opacity = WWMath.clamp(distanceFactor,
            this.attributes.getDistanceMinOpacity(), 1);

        this.setDepthFunc(dc, screenPoint);
        this.drawTopLevelAnnotation(dc, (int) screenPoint.x, (int) screenPoint.y, size.width, size.height, scale,
            opacity, pos);
    }

    protected double computeLookAtDistance(DrawContext dc)
    {
        // TODO: cache lookAtDistance for one frame cycle

        View view = dc.getView();

        // Get point in the middle of the screen
        Position groundPos = view.computePositionFromScreenPoint(
            view.getViewport().getCenterX(), view.getViewport().getCenterY());

        // Return eye altitude if no point found
        if (groundPos == null)
        {
            return view.getEyePosition().getElevation();
        }

        // Compute distance from eye to the position in the middle of the screen
        return view.getEyePoint().distanceTo3(dc.getGlobe().computePointFromPosition(groundPos));
    }

    protected void setDepthFunc(DrawContext dc, Vec4 screenPoint)
    {
        GL gl = dc.getGL();

        Position eyePos = dc.getView().getEyePosition();
        if (eyePos == null)
        {
            gl.glDepthFunc(GL.GL_ALWAYS);
            return;
        }

        double altitude = eyePos.getElevation();
        if (altitude < (dc.getGlobe().getMaxElevation() * dc.getVerticalExaggeration()))
        {
            double depth = screenPoint.z - (8d * 0.00048875809d);
            depth = depth < 0d ? 0d : (depth > 1d ? 1d : depth);
            gl.glDepthFunc(GL.GL_LESS);
            gl.glDepthRange(depth, depth);
        }
        else if (screenPoint.z >= 1d)
        {
            gl.glDepthFunc(GL.GL_EQUAL);
            gl.glDepthRange(1d, 1d);
        }
        else
        {
            gl.glDepthFunc(GL.GL_ALWAYS);
        }
    }

    //**************************************************************//
    //********************  Restorable State  **********************//
    //**************************************************************//

    /**
     * Returns an XML state document String describing the public attributes of this GlobeAnnotation.
     *
     * @return XML state document string describing this GlobeAnnotation.
     */
    public String getRestorableState()
    {
        RestorableSupport restorableSupport = null;

        // Try to parse the superclass' xml state document, if it defined one.
        String superStateInXml = super.getRestorableState();
        if (superStateInXml != null)
        {
            try
            {
                restorableSupport = RestorableSupport.parse(superStateInXml);
            }
            catch (Exception e)
            {
                // Parsing the document specified by the superclass failed.
                String message = Logging.getMessage("generic.ExceptionAttemptingToParseStateXml", superStateInXml);
                Logging.logger().severe(message);
            }
        }

        // Create our own state document from scratch.
        if (restorableSupport == null)
            restorableSupport = RestorableSupport.newRestorableSupport();
        // Creating a new RestorableSupport failed. RestorableSupport logged the problem, so just return null.
        if (restorableSupport == null)
            return null;

        // Save the position property only if all parts (latitude, longitude, and elevation) can be saved.
        // We will not save a partial position (for example, just the elevation).
        if (this.position != null
            && this.position.getLatitude() != null
            && this.position.getLongitude() != null)
        {
            RestorableSupport.StateObject positionStateObj = restorableSupport.addStateObject("position");
            if (positionStateObj != null)
            {
                restorableSupport.addStateValueAsDouble(positionStateObj, "latitude", 
                        this.position.getLatitude().degrees);
                restorableSupport.addStateValueAsDouble(positionStateObj, "longitude",
                        this.position.getLongitude().degrees);
                restorableSupport.addStateValueAsDouble(positionStateObj, "elevation",
                        this.position.getElevation());
            }
        }

        return restorableSupport.getStateAsXml();
    }

    /**
     * Restores publicly settable attribute values found in the specified XML state document String. The
     * document specified by <code>stateInXml</code> must be a well formed XML document String, or this will throw an
     * IllegalArgumentException. Unknown structures in <code>stateInXml</code> are benign, because they will
     * simply be ignored.
     *
     * @param stateInXml an XML document String describing a GlobeAnnotation.
     * @throws IllegalArgumentException If <code>stateInXml</code> is null, or if <code>stateInXml</code> is not
     *                                  a well formed XML document String.
     */
    public void restoreState(String stateInXml)
    {
        if (stateInXml == null)
        {
            String message = Logging.getMessage("nullValue.StringIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        // Allow the superclass to restore it's state.
        try
        {
            super.restoreState(stateInXml);
        }
        catch (Exception e)
        {
            // Superclass will log the exception.
        }

        RestorableSupport restorableSupport;
        try
        {
            restorableSupport = RestorableSupport.parse(stateInXml);
        }
        catch (Exception e)
        {
            // Parsing the document specified by stateInXml failed.
            String message = Logging.getMessage("generic.ExceptionAttemptingToParseStateXml", stateInXml);
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message, e);
        }

        // Restore the position property only if all parts are available.
        // We will not restore a partial position (for example, just the latitude).
        RestorableSupport.StateObject positionStateObj = restorableSupport.getStateObject("position");
        if (positionStateObj != null)
        {
            Double latitudeState = restorableSupport.getStateValueAsDouble(positionStateObj, "latitude");
            Double longitudeState = restorableSupport.getStateValueAsDouble(positionStateObj, "longitude");
            Double elevationState = restorableSupport.getStateValueAsDouble(positionStateObj, "elevation");
            if (latitudeState != null && elevationState != null)
                setPosition(Position.fromDegrees(latitudeState, longitudeState, elevationState));
        }
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?