All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.ogc.kml.impl.KMLSurfaceImageImpl 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.ogc.kml.impl;

import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.ogc.kml.*;
import gov.nasa.worldwind.ogc.kml.gx.GXLatLongQuad;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.*;

import java.awt.*;
import java.io.IOException;
import java.util.List;

/**
 * @author pabercrombie
 * @version $Id: KMLSurfaceImageImpl.java 1551 2013-08-17 18:00:09Z pabercrombie $
 */
public class KMLSurfaceImageImpl extends SurfaceImage implements KMLRenderable
{
    protected KMLGroundOverlay parent;

    protected boolean attributesResolved;

    /** Indicates that the source texture has been resolved and loaded. */
    protected boolean textureResolved;
    /** Indicates the time at which the image source was specified. */
    protected long iconRetrievalTime;

    /**
     * Flag to indicate the rotation must be applied to the SurfaceImage. Rotation is applied the first time that the
     * image is rendered.
     */
    protected boolean mustApplyRotation;

    /**
     * Create an screen image.
     *
     * @param tc      the current {@link KMLTraversalContext}.
     * @param overlay the Overlay element containing.
     *
     * @throws NullPointerException     if the traversal context is null.
     * @throws IllegalArgumentException if the parent overlay or the traversal context is null.
     */
    public KMLSurfaceImageImpl(KMLTraversalContext tc, KMLGroundOverlay overlay)
    {
        this.parent = overlay;

        if (tc == null)
        {
            String msg = Logging.getMessage("nullValue.TraversalContextIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        if (overlay == null)
        {
            String msg = Logging.getMessage("nullValue.ParentIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        // Positions are specified either as a kml:LatLonBox or a gx:LatLonQuad
        KMLLatLonBox box = overlay.getLatLonBox();
        if (box != null)
        {
            Sector sector = KMLUtil.createSectorFromLatLonBox(box);
            this.initializeGeometry(sector);

            // Check to see if a rotation is provided. The rotation will be applied when the image is rendered, because
            // how the rotation is performed depends on the globe.
            Double rotation = box.getRotation();
            if (rotation != null)
            {
                this.mustApplyRotation = true;
            }
        }
        else
        {
            GXLatLongQuad latLonQuad = overlay.getLatLonQuad();
            if (latLonQuad != null && latLonQuad.getCoordinates() != null)
            {
                this.initializeGeometry(latLonQuad.getCoordinates().list);
            }
        }

        // Apply opacity to the surface image
        String colorStr = overlay.getColor();
        if (!WWUtil.isEmpty(colorStr))
        {
            Color color = WWUtil.decodeColorABGR(colorStr);
            int alpha = color.getAlpha();

            this.setOpacity((double) alpha / 255);
        }

        this.setPickEnabled(false);
    }

    public void preRender(KMLTraversalContext tc, DrawContext dc)
    {
        if (this.mustResolveHref()) // resolve the href to either a local file or a remote URL
        {
            String path = this.resolveHref();

            // Evict the resource from the file store if there is a cached resource older than the icon update time.
            // This prevents fetching a stale resource out of the cache when the Icon is updated.
            this.parent.getRoot().evictIfExpired(path, this.iconRetrievalTime);

            this.setImageSource(path, this.getCorners());
            this.iconRetrievalTime = System.currentTimeMillis();
            this.textureResolved = false;
        }

        // Set the Icon's expiration time the first time that the image is rendered after the texture has been retrieved.
        // The expiration time comes from the HTTP headers, so we can't do this until the resource is available.
        boolean mustSetExpiration = !this.textureResolved && this.sourceTexture != null
            && this.sourceTexture.isTextureCurrent(dc);
        if (mustSetExpiration)
        {
            String path = this.resolveHref();

            // Query the KMLRoot for the expiration time.
            long expiration = this.parent.getRoot().getExpiration(path);

            // Set the Icon's expiration. This has no effect if the refreshMode is not onExpire.
            this.parent.getIcon().setExpirationTime(expiration);
            this.textureResolved = true;
        }

        // Apply rotation the first time the overlay is rendered
        if (this.mustApplyRotation)
        {
            this.applyRotation(dc);
            this.mustApplyRotation = false;
        }

        super.preRender(dc);
    }

    /**
     * Indicates whether or not the image source needs to be resolved. The source needs to be resolved when the KMLIcon
     * is updated.
     *
     * @return True if the image source must be resolved.
     */
    protected boolean mustResolveHref()
    {
        KMLIcon icon = this.parent.getIcon();
        //noinspection SimplifiableIfStatement
        if (icon == null || icon.getHref() == null)
            return false;

        // Resolve the reference if the image hasn't been retrieved, or if the link has expired.
        return this.getImageSource() == null || icon.getUpdateTime() > this.iconRetrievalTime;
    }

    /**
     * Resolve the HREF in this overlay's Icon element against the KML root.
     *
     * @return The resolved path to the image source.
     */
    protected String resolveHref()
    {
        // The icon reference may be to a support file within a KMZ file, so check for that. If it's not, then just
        // let the normal SurfaceImage code resolve the reference.
        String href = this.parent.getIcon().getHref();
        String localAddress = null;
        try
        {
            localAddress = this.parent.getRoot().getSupportFilePath(href);
        }
        catch (IOException ignored)
        {
        }

        return localAddress != null ? localAddress : href;
    }

    /** {@inheritDoc} */
    public void render(KMLTraversalContext tc, DrawContext dc)
    {
        // We've already resolved the SurfaceImage's attributes during the preRender pass. During the render pass we
        // simply draw the SurfaceImage.
        super.render(dc);
    }

    /**
     * Apply a rotation to the corner points of the overlay.
     *
     * @param dc Current draw context.
     */
    protected void applyRotation(DrawContext dc)
    {
        KMLLatLonBox box = this.parent.getLatLonBox();
        if (box != null)
        {
            Double rotation = box.getRotation();
            if (rotation != null)
            {
                List corners = KMLUtil.rotateSector(dc.getGlobe(), this.getSector(),
                    Angle.fromDegrees(rotation));
                this.setCorners(corners);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy