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

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

import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.event.Message;
import gov.nasa.worldwind.ogc.kml.impl.*;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.util.xml.XMLEventParserContext;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import java.util.*;

/**
 * Represents the KML Placemark element and provides access to its contents.
 *
 * @author tag
 * @version $Id: KMLPlacemark.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class KMLPlacemark extends KMLAbstractFeature
{
    protected KMLAbstractGeometry geometry;
    protected List renderables;

    /**
     * Construct an instance.
     *
     * @param namespaceURI the qualifying namespace URI. May be null to indicate no namespace qualification.
     */
    public KMLPlacemark(String namespaceURI)
    {
        super(namespaceURI);
    }

    @Override
    protected void doAddEventContent(Object o, XMLEventParserContext ctx, XMLEvent event, Object... args)
        throws XMLStreamException
    {
        if (o instanceof KMLAbstractGeometry)
            this.setGeometry((KMLAbstractGeometry) o);
        else
            super.doAddEventContent(o, ctx, event, args);
    }

    protected void setGeometry(KMLAbstractGeometry geometry)
    {
        this.geometry = geometry;
    }

    /**
     * Returns the placemark's geometry element.
     *
     * @return the placemark's geometry element, or null if there is none.
     */
    public KMLAbstractGeometry getGeometry()
    {
        return this.geometry;
    }

    public KMLSimpleData getSimpleData() // Included for test purposes only
    {
        return (KMLSimpleData) this.getField("SimpleData");
    }

    /**
     * Returns the {@link gov.nasa.worldwind.ogc.kml.impl.KMLRenderable}s of this placemark.
     *
     * @return the placemark's renderables, or null if the placemark has no renderables.
     */
    public List getRenderables()
    {
        return this.renderables;
    }

    protected void addRenderable(KMLRenderable r)
    {
        if (r != null)
            this.getRenderables().add(r);
    }

    /**
     * Pre-renders the placemark geometry represented by this KMLPlacemark. This initializes the placemark
     * geometry if necessary, prior to pre-rendering.
     *
     * @param tc the current KML traversal context.
     * @param dc the current draw context.
     */
    @Override
    protected void doPreRender(KMLTraversalContext tc, DrawContext dc)
    {
        if (this.getRenderables() == null)
            this.initializeGeometry(tc, this.getGeometry());

        List rs = this.getRenderables();
        if (rs != null)
        {
            for (KMLRenderable r : rs)
            {
                r.preRender(tc, dc);
            }
        }
    }

    /**
     * Renders the placemark geometry represented by this KMLGroundOverlay.
     *
     * @param tc the current KML traversal context.
     * @param dc the current draw context.
     */
    @Override
    protected void doRender(KMLTraversalContext tc, DrawContext dc)
    {
        // We've already initialized the placemark's renderables during the preRender pass. Render the placemark's
        // renderable list without any further preparation.

        List rs = this.getRenderables();
        if (rs != null)
        {
            for (KMLRenderable r : rs)
            {
                r.render(tc, dc);
            }
        }

        // Render the feature balloon (if any)
        this.renderBalloon(tc, dc);
    }

    protected void initializeGeometry(KMLTraversalContext tc, KMLAbstractGeometry geom)
    {
        if (geom == null)
            return;

        if (this.getRenderables() == null)
            this.renderables = new ArrayList(1); // most common case is one renderable

        if (geom instanceof KMLPoint)
            this.addRenderable(this.selectPointRenderable(tc, geom));
        else if (geom instanceof KMLLinearRing) // since LinearRing is a subclass of LineString, this test must precede
            this.addRenderable(this.selectLinearRingRenderable(tc, geom));
        else if (geom instanceof KMLLineString)
            this.addRenderable(this.selectLineStringRenderable(tc, geom));
        else if (geom instanceof KMLPolygon)
            this.addRenderable(this.selectPolygonRenderable(tc, geom));
        else if (geom instanceof KMLMultiGeometry)
        {
            List geoms = ((KMLMultiGeometry) geom).geometries;
            if (geoms != null)
            {
                for (KMLAbstractGeometry g : geoms)
                {
                    this.initializeGeometry(tc, g); // recurse
                }
            }
        }
        else if (geom instanceof KMLModel)
            this.addRenderable(this.selectModelRenderable(tc, geom));
    }

    protected KMLRenderable selectModelRenderable(KMLTraversalContext tc, KMLAbstractGeometry geom)
    {
        return new KMLModelPlacemarkImpl(tc, this, geom);
    }

    protected KMLRenderable selectPointRenderable(KMLTraversalContext tc, KMLAbstractGeometry geom)
    {
        KMLPoint shape = (KMLPoint) geom;

        if (shape.getCoordinates() == null)
            return null;

        return new KMLPointPlacemarkImpl(tc, this, geom);
    }

    protected KMLRenderable selectLineStringRenderable(KMLTraversalContext tc, KMLAbstractGeometry geom)
    {
        KMLLineString shape = (KMLLineString) geom;

        if (shape.getCoordinates() == null)
            return null;

        return new KMLLineStringPlacemarkImpl(tc, this, geom);
    }

    protected KMLRenderable selectLinearRingRenderable(KMLTraversalContext tc, KMLAbstractGeometry geom)
    {
        KMLLinearRing shape = (KMLLinearRing) geom;

        if (shape.getCoordinates() == null)
            return null;

        KMLLineStringPlacemarkImpl impl = new KMLLineStringPlacemarkImpl(tc, this, geom);
        if (impl.getAltitudeMode() == WorldWind.CLAMP_TO_GROUND) // See note in google's version of KML spec
            impl.setPathType(AVKey.GREAT_CIRCLE);

        return impl;
    }

    protected KMLRenderable selectPolygonRenderable(KMLTraversalContext tc, KMLAbstractGeometry geom)
    {
        KMLPolygon shape = (KMLPolygon) geom;

        if (shape.getOuterBoundary().getCoordinates() == null)
            return null;

        if ("clampToGround".equals(shape.getAltitudeMode()) || !this.isValidAltitudeMode(shape.getAltitudeMode()))
            return new KMLSurfacePolygonImpl(tc, this, geom);
        else if (shape.isExtrude())
            return new KMLExtrudedPolygonImpl(tc, this, geom);
        else
            return new KMLPolygonImpl(tc, this, geom);
    }

    /**
     * Indicates whether or not an altitude mode equals one of the altitude modes defined in the KML specification.
     *
     * @param altMode Altitude mode test.
     *
     * @return True if {@code altMode} is one of "clampToGround", "relativeToGround", or "absolute".
     */
    protected boolean isValidAltitudeMode(String altMode)
    {
        return "clampToGround".equals(altMode)
            || "relativeToGround".equals(altMode)
            || "absolute".equals(altMode);
    }

    @Override
    public void applyChange(KMLAbstractObject sourceValues)
    {
        if (!(sourceValues instanceof KMLPlacemark))
        {
            String message = Logging.getMessage("KML.InvalidElementType", sourceValues.getClass().getName());
            Logging.logger().warning(message);
            throw new IllegalArgumentException(message);
        }

        super.applyChange(sourceValues);

        KMLPlacemark placemark = (KMLPlacemark) sourceValues;

        if (placemark.getGeometry() != null) // the geometry changed so nullify the cached renderables
        {
            this.setGeometry(placemark.getGeometry());
            this.renderables = null;
        }

        if (placemark.hasStyle())
        {
            Message msg = new Message(KMLAbstractObject.MSG_STYLE_CHANGED, placemark);

            if (this.renderables != null)
            {
                for (KMLRenderable renderable : this.renderables)
                {
                    renderable.onMessage(msg);
                }
            }
        }
    }

    @Override
    public void onChange(Message msg)
    {
        if (KMLAbstractObject.MSG_GEOMETRY_CHANGED.equals(msg.getName()))
        {
            this.renderables = null;
        }
        else if (KMLAbstractObject.MSG_STYLE_CHANGED.equals(msg.getName()))
        {
            for (KMLRenderable renderable : this.renderables)
            {
                renderable.onMessage(msg);
            }
        }

        super.onChange(msg);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy