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

src.gov.nasa.worldwind.render.SurfacePolyline Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show 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.render;

import gov.nasa.worldwind.Exportable;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.ogc.kml.KMLConstants;
import gov.nasa.worldwind.ogc.kml.impl.KMLExportUtil;
import gov.nasa.worldwind.util.*;

import javax.xml.stream.*;
import java.io.*;
import java.util.*;

import static gov.nasa.worldwind.ogc.kml.impl.KMLExportUtil.kmlBoolean;

/**
 * @author dcollins
 * @version $Id: SurfacePolyline.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class SurfacePolyline extends AbstractSurfaceShape implements Exportable
{
    protected boolean closed;
    protected Iterable locations;

    /** Constructs a new surface polyline with the default attributes and no locations. */
    public SurfacePolyline()
    {
    }

    /**
     * Constructs a new surface polyline with the specified normal (as opposed to highlight) attributes and no
     * locations. Modifying the attribute reference after calling this constructor causes this shape's appearance to
     * change accordingly.
     *
     * @param normalAttrs the normal attributes. May be null, in which case default attributes are used.
     */
    public SurfacePolyline(ShapeAttributes normalAttrs)
    {
        super(normalAttrs);
    }

    /**
     * Constructs a new surface polyline with the default attributes and the specified iterable of locations.
     * 

* Note: If fewer than two locations is specified, no polyline is drawn. * * @param iterable the polyline locations. * * @throws IllegalArgumentException if the locations iterable is null. */ public SurfacePolyline(Iterable iterable) { if (iterable == null) { String message = Logging.getMessage("nullValue.IterableIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.locations = iterable; } /** * Constructs a new surface polyline with the specified normal (as opposed to highlight) attributes and the * specified iterable of locations. Modifying the attribute reference after calling this constructor causes this * shape's appearance to change accordingly. *

* Note: If fewer than two locations is specified, no polyline is drawn. * * @param normalAttrs the normal attributes. May be null, in which case default attributes are used. * @param iterable the polyline locations. * * @throws IllegalArgumentException if the locations iterable is null. */ public SurfacePolyline(ShapeAttributes normalAttrs, Iterable iterable) { super(normalAttrs); if (iterable == null) { String message = Logging.getMessage("nullValue.IterableIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.locations = iterable; } public boolean isClosed() { return this.closed; } public void setClosed(boolean closed) { this.closed = closed; this.onShapeChanged(); // Potentially causes the shape's geometry to change. } public Iterable getLocations(Globe globe) { return this.getLocations(); } public Iterable getLocations() { return this.locations; } public void setLocations(Iterable iterable) { if (iterable == null) { String message = Logging.getMessage("nullValue.IterableIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.locations = iterable; this.onShapeChanged(); } public Position getReferencePosition() { if (this.locations == null) return null; Iterator iterator = this.locations.iterator(); if (!iterator.hasNext()) return null; return new Position(iterator.next(), 0); } protected List> createGeometry(Globe globe, SurfaceTileDrawContext sdc) { if (this.locations == null) return null; ArrayList drawLocations = new ArrayList(); double edgeIntervalsPerDegree = this.computeEdgeIntervalsPerDegree(sdc); this.generateIntermediateLocations(this.locations, edgeIntervalsPerDegree, this.isClosed(), drawLocations); if (drawLocations.size() < 2) return null; ArrayList> geom = new ArrayList>(); geom.add(drawLocations); return geom; } protected void doMoveTo(Position oldReferencePosition, Position newReferencePosition) { if (this.locations == null) return; ArrayList newLocations = new ArrayList(); for (LatLon ll : this.locations) { Angle heading = LatLon.greatCircleAzimuth(oldReferencePosition, ll); Angle pathLength = LatLon.greatCircleDistance(oldReferencePosition, ll); newLocations.add(LatLon.greatCircleEndPosition(newReferencePosition, heading, pathLength)); } this.setLocations(newLocations); } protected void drawInterior(DrawContext dc, SurfaceTileDrawContext sdc) { // Intentionally left blank; SurfacePolyline does not render an interior. } /** {@inheritDoc} Overridden to treat the shape as an open path if the polyline is not closed. */ @Override protected boolean canContainPole() { return this.isClosed(); } //**************************************************************// //******************** Restorable State ***********************// //**************************************************************// protected void doGetRestorableState(RestorableSupport rs, RestorableSupport.StateObject context) { super.doGetRestorableState(rs, context); Iterable iterable = this.getLocations(); if (iterable != null) rs.addStateValueAsLatLonList(context, "locationList", iterable); rs.addStateValueAsBoolean(context, "closed", this.isClosed()); } protected void doRestoreState(RestorableSupport rs, RestorableSupport.StateObject context) { super.doRestoreState(rs, context); Iterable iterable = rs.getStateValueAsLatLonList(context, "locationList"); if (iterable != null) this.setLocations(iterable); Boolean b = rs.getStateValueAsBoolean(context, "closed"); if (b != null) this.setClosed(b); } protected void legacyRestoreState(RestorableSupport rs, RestorableSupport.StateObject context) { super.legacyRestoreState(rs, context); List locations = rs.getStateValueAsLatLonList(context, "locations"); if (locations != null) this.setLocations(locations); } //**************************************************************// //************************* Export *****************************// //**************************************************************// /** * Export the polyline to KML as a {@code } element. The {@code output} object will receive the data. * This object must be one of: java.io.Writer java.io.OutputStream javax.xml.stream.XMLStreamWriter * * @param output Object to receive the generated KML. * * @throws XMLStreamException If an exception occurs while writing the KML * @throws IOException if an exception occurs while exporting the data. * @see #export(String, Object) */ protected void exportAsKML(Object output) throws IOException, XMLStreamException { XMLStreamWriter xmlWriter = null; XMLOutputFactory factory = XMLOutputFactory.newInstance(); boolean closeWriterWhenFinished = true; if (output instanceof XMLStreamWriter) { xmlWriter = (XMLStreamWriter) output; closeWriterWhenFinished = false; } else if (output instanceof Writer) { xmlWriter = factory.createXMLStreamWriter((Writer) output); } else if (output instanceof OutputStream) { xmlWriter = factory.createXMLStreamWriter((OutputStream) output); } if (xmlWriter == null) { String message = Logging.getMessage("Export.UnsupportedOutputObject"); Logging.logger().warning(message); throw new IllegalArgumentException(message); } xmlWriter.writeStartElement("Placemark"); String property = (String) getValue(AVKey.DISPLAY_NAME); if (property != null) { xmlWriter.writeStartElement("name"); xmlWriter.writeCharacters(property); xmlWriter.writeEndElement(); } xmlWriter.writeStartElement("visibility"); xmlWriter.writeCharacters(kmlBoolean(this.isVisible())); xmlWriter.writeEndElement(); String shortDescription = (String) getValue(AVKey.SHORT_DESCRIPTION); if (shortDescription != null) { xmlWriter.writeStartElement("Snippet"); xmlWriter.writeCharacters(shortDescription); xmlWriter.writeEndElement(); } String description = (String) getValue(AVKey.BALLOON_TEXT); if (description != null) { xmlWriter.writeStartElement("description"); xmlWriter.writeCharacters(description); xmlWriter.writeEndElement(); } final ShapeAttributes normalAttributes = getAttributes(); final ShapeAttributes highlightAttributes = getHighlightAttributes(); // Write style map if (normalAttributes != null || highlightAttributes != null) { xmlWriter.writeStartElement("StyleMap"); KMLExportUtil.exportAttributesAsKML(xmlWriter, KMLConstants.NORMAL, normalAttributes); KMLExportUtil.exportAttributesAsKML(xmlWriter, KMLConstants.HIGHLIGHT, highlightAttributes); xmlWriter.writeEndElement(); // StyleMap } // Write geometry xmlWriter.writeStartElement("LineString"); xmlWriter.writeStartElement("extrude"); xmlWriter.writeCharacters("0"); xmlWriter.writeEndElement(); xmlWriter.writeStartElement("tessellate"); xmlWriter.writeCharacters("1"); xmlWriter.writeEndElement(); xmlWriter.writeStartElement("altitudeMode"); xmlWriter.writeCharacters("clampToGround"); xmlWriter.writeEndElement(); xmlWriter.writeStartElement("coordinates"); for (LatLon position : this.getLocations()) { xmlWriter.writeCharacters(Double.toString(position.getLongitude().getDegrees())); xmlWriter.writeCharacters(","); xmlWriter.writeCharacters(Double.toString(position.getLatitude().getDegrees())); xmlWriter.writeCharacters(" "); } xmlWriter.writeEndElement(); // coordinates xmlWriter.writeEndElement(); // LineString xmlWriter.writeEndElement(); // Placemark xmlWriter.flush(); if (closeWriterWhenFinished) xmlWriter.close(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy