gov.nasa.worldwind.ogc.kml.KMLAbstractContainer 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.event.Message;
import gov.nasa.worldwind.ogc.kml.impl.KMLTraversalContext;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.*;
import gov.nasa.worldwind.util.xml.XMLEventParserContext;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import java.util.*;
/**
* Represents the KML Container element and provides access to its contents.
*
* @author tag
* @version $Id: KMLAbstractContainer.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class KMLAbstractContainer extends KMLAbstractFeature
{
protected ArrayList features = new ArrayList();
/**
* Construct an instance.
*
* @param namespaceURI the qualifying namespace URI. May be null to indicate no namespace qualification.
*/
protected KMLAbstractContainer(String namespaceURI)
{
super(namespaceURI);
}
@Override
protected void doAddEventContent(Object o, XMLEventParserContext ctx, XMLEvent event, Object... args)
throws XMLStreamException
{
if (o instanceof KMLAbstractFeature)
this.addFeature((KMLAbstractFeature) o);
else
super.doAddEventContent(o, ctx, event, args);
}
public List getFeatures()
{
return this.features;
}
public void addFeature(KMLAbstractFeature feature)
{
if (feature != null)
this.features.add(feature);
}
public void removeFeature(KMLAbstractFeature feature)
{
if (feature != null)
this.getFeatures().remove(feature);
}
/**
* Indicates whether this KMLAbstractContainer
is active and should be rendered on the specified
* DrawContext
. This returns true
if this container's visibility
is
* unspecified (null
) or is set to true
.
*
* Regions do not apply directly to KML containers, because a descendant features can override the container's
* Region with its own. Since a descendant Region may be larger or have a less restrictive LOD range than this
* container, we cannot determine the visibility of the entire tree based on this container's Region. A container's
* Region is inherited by any descendants that do not specify a Region, and Region visibility is determined at the
* leaf nodes.
*
* @param tc the current KML traversal context. This parameter is ignored.
* @param dc the draw context. This parameter is ignored.
*
* @return true
if this container should be rendered, otherwise false
.
*/
@Override
protected boolean isFeatureActive(KMLTraversalContext tc, DrawContext dc)
{
return this.getVisibility() == null || this.getVisibility();
}
/**
* Pre-renders the KML features held by this KMLAbstractContainer
.
*
* Pushes this container's Region on the KML traversal context's region stack before rendering the features, and
* pops the Region off the stack afterward. Descendant features use the KML traversal context's region stack to
* inherit Regions from parent containers.
*
* @param tc the current KML traversal context.
* @param dc the current draw context.
*/
@Override
protected void doPreRender(KMLTraversalContext tc, DrawContext dc)
{
this.beginRendering(tc, dc);
try
{
this.preRenderFeatures(tc, dc);
}
finally
{
this.endRendering(tc, dc);
}
}
/**
* Renders the KML features held by this KMLAbstractContainer
.
*
* Pushes this container's Region on the KML traversal context's region stack before rendering the features, and
* pops the Region off the stack afterward. Descendant features use the KML traversal context's region stack to
* inherit Regions from parent containers.
*
* @param tc the current KML traversal context.
* @param dc the current draw context.
*/
@Override
protected void doRender(KMLTraversalContext tc, DrawContext dc)
{
this.beginRendering(tc, dc);
try
{
this.renderBalloon(tc, dc);
this.renderFeatures(tc, dc);
}
finally
{
this.endRendering(tc, dc);
}
}
/**
* Prepares this KML container for rendering. This pushes this container's Region on the KML traversal context's
* region stack. Descendant features use the KML traversal context's region stack to inherit Regions from parent
* containers. This must be followed by a call to endRendering
.
*
* @param tc the current KML traversal context.
* @param dc the current draw context.
*/
@SuppressWarnings({"UnusedDeclaration"})
protected void beginRendering(KMLTraversalContext tc, DrawContext dc)
{
if (this.getRegion() != null)
tc.pushRegion(this.getRegion());
}
/**
* Restores any rendering state changed during rendering. This pops this container's Region off the KML traversal
* context's region stack to restore the previous container's Region (if any). This must be preceded by a call to
* beginRendering
.
*
* @param tc the current KML traversal context.
* @param dc the current draw context.
*/
@SuppressWarnings({"UnusedDeclaration"})
protected void endRendering(KMLTraversalContext tc, DrawContext dc)
{
if (this.getRegion() != null)
tc.popRegion();
}
/**
* PreRenders this KML container's list of KML features, in the order they appear in the list. This does nothing if
* the list of features is empty.
*
* @param tc the current KML traversal context.
* @param dc the current draw context.
*/
protected void preRenderFeatures(KMLTraversalContext tc, DrawContext dc)
{
List containers = new ArrayList();
// PreRender non-container child features first, and containers second. This ensures that features closer to the
// root are rendered before features deeper in the tree. In the case of an image pyramid of GroundOverlays,
// this causes the deeper nested overlays (which are typically more detailed) to render on top of the more
// general overlay that is higher in the tree.
for (KMLAbstractFeature feature : this.getFeatures())
{
if (feature instanceof KMLAbstractContainer)
containers.add(feature);
else
feature.preRender(tc, dc);
}
// Now preRender the containers
for (KMLAbstractFeature feature : containers)
{
feature.preRender(tc, dc);
}
}
/**
* Draws this KML container's list of KML features, in the order they appear in the list. This does nothing if the
* list of features is empty.
*
* @param tc the current KML traversal context.
* @param dc the current draw context.
*/
protected void renderFeatures(KMLTraversalContext tc, DrawContext dc)
{
List containers = new ArrayList();
// Render non-container child features first, and containers second. This ensures that features closer to the
// root are rendered before features deeper in the tree. In the case of an image pyramid of GroundOverlays,
// this causes the deeper nested overlays (which are typically more detailed) to render on top of the more
// general overlay that is higher in the tree.
for (KMLAbstractFeature feature : this.getFeatures())
{
if (feature instanceof KMLAbstractContainer)
containers.add(feature);
else
feature.render(tc, dc);
}
// Now render the containers
for (KMLAbstractFeature feature : containers)
{
feature.render(tc, dc);
}
}
@Override
public void applyChange(KMLAbstractObject sourceValues)
{
if (!(sourceValues instanceof KMLAbstractContainer))
{
String message = Logging.getMessage("KML.InvalidElementType", sourceValues.getClass().getName());
Logging.logger().warning(message);
throw new IllegalArgumentException(message);
}
super.applyChange(sourceValues);
KMLAbstractContainer sourceContainer = (KMLAbstractContainer) sourceValues;
if (sourceContainer.getFeatures() != null && sourceContainer.getFeatures().size() > 0)
this.mergeFeatures(sourceContainer);
}
/**
* Merge a list of incoming features with the current list. If an incoming feature has the same ID as an existing
* one, replace the existing one, otherwise add the incoming one.
*
* @param sourceContainer the incoming container of features.
*/
protected void mergeFeatures(KMLAbstractContainer sourceContainer)
{
// Make a copy of the existing list so we can modify it as we traverse.
List featuresListCopy = new ArrayList(this.getFeatures().size());
Collections.copy(featuresListCopy, this.getFeatures());
for (KMLAbstractFeature sourceFeature : sourceContainer.getFeatures())
{
String id = sourceFeature.getId();
if (!WWUtil.isEmpty(id))
{
for (KMLAbstractFeature existingFeature : featuresListCopy)
{
String currentId = existingFeature.getId();
if (!WWUtil.isEmpty(currentId) && currentId.equals(id))
this.getFeatures().remove(existingFeature);
}
}
this.getFeatures().add(sourceFeature);
}
}
@Override
public void onMessage(Message msg)
{
for (KMLAbstractFeature feature : this.getFeatures())
{
feature.onMessage(msg);
}
super.onMessage(msg);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy