src.gov.nasa.worldwind.formats.shapefile.ShapefileRecordPolygon Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of worldwindx Show documentation
Show all versions of worldwindx Show documentation
World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.
/*
* 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.formats.shapefile;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.ogc.kml.impl.KMLExportUtil;
import gov.nasa.worldwind.util.*;
import javax.xml.stream.*;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;
/**
* Represents a Shapefile record with a polygon shape type. Polygon shapes represent an connected sequence of four or
* more x,y coordinate pairs that form a closed loop. Polygon shapes may contain multiple rings, where each ring is a
* closed loop of four or more points. Rings defining a filled part of a polygon have a clockwise winding order, while
* rings defining holes in the polygon have a counter-clockwise winding order.
*
* Polygons may have optional z-coordinates or m-coordinates that accompany each coordinate pair. If a Polygon has
* z-coordinates, then {@link #getZValues()}
returns a non-null
array of values. If a Polygon
* has m-coordinates, then {@link #getMValues()}
returns a non-null
array of values.
*
* @author Patrick Murris
* @version $Id: ShapefileRecordPolygon.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class ShapefileRecordPolygon extends ShapefileRecordPolyline
{
/** {@inheritDoc} */
public ShapefileRecordPolygon(Shapefile shapeFile, ByteBuffer buffer)
{
super(shapeFile, buffer);
}
/**
* Export the record to KML as a {@code } element. If the polygon has a "height" attribute it will be
* exported as an extruded polygon.
*
* @param xmlWriter XML writer to receive the generated KML.
*
* @throws javax.xml.stream.XMLStreamException
* If an exception occurs while writing the KML
* @throws java.io.IOException If an exception occurs while exporting the data.
*/
@Override
public void exportAsKML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException
{
Iterable outerBoundary = null;
List> innerBoundaries = new ArrayList>();
// If the polygon has a "height" attribute, export as an extruded polygon.
Double height = ShapefileUtils.extractHeightAttribute(this);
for (int i = 0; i < this.getNumberOfParts(); i++)
{
// Although the shapefile spec says that inner and outer boundaries can be listed in any order, it's
// assumed here that inner boundaries are at least listed adjacent to their outer boundary, either
// before or after it. The below code accumulates inner boundaries into the polygon until an
// outer boundary comes along. If the outer boundary comes before the inner boundaries, the inner
// boundaries are added to the polygon until another outer boundary comes along, at which point a new
// polygon is started.
VecBuffer buffer = this.getCompoundPointBuffer().subBuffer(i);
if (WWMath.computeWindingOrderOfLocations(buffer.getLocations()).equals(AVKey.CLOCKWISE))
{
if (outerBoundary == null)
{
outerBoundary = buffer.getLocations();
}
else
{
this.exportPolygonAsKML(xmlWriter, outerBoundary, innerBoundaries, height);
outerBoundary = this.getCompoundPointBuffer().getLocations();
innerBoundaries.clear();
}
}
else
{
innerBoundaries.add(buffer.getLocations());
}
}
if (outerBoundary != null && outerBoundary.iterator().hasNext())
{
this.exportPolygonAsKML(xmlWriter, outerBoundary, innerBoundaries, height);
}
}
protected void exportPolygonAsKML(XMLStreamWriter xmlWriter, Iterable outerBoundary,
List> innerBoundaries, Double height) throws IOException, XMLStreamException
{
xmlWriter.writeStartElement("Placemark");
xmlWriter.writeStartElement("name");
xmlWriter.writeCharacters(Integer.toString(this.getRecordNumber()));
xmlWriter.writeEndElement();
xmlWriter.writeStartElement("Polygon");
String altitudeMode;
if (height != null)
{
xmlWriter.writeStartElement("extrude");
xmlWriter.writeCharacters("1");
xmlWriter.writeEndElement();
altitudeMode = "absolute";
}
else
{
altitudeMode = "clampToGround";
height = 0.0;
}
xmlWriter.writeStartElement("altitudeMode");
xmlWriter.writeCharacters(altitudeMode);
xmlWriter.writeEndElement();
xmlWriter.writeStartElement("outerBoundaryIs");
KMLExportUtil.exportBoundaryAsLinearRing(xmlWriter, outerBoundary, height);
xmlWriter.writeEndElement(); // outerBoundaryIs
for (Iterable innerBoundary : innerBoundaries)
{
xmlWriter.writeStartElement("innerBoundaryIs");
KMLExportUtil.exportBoundaryAsLinearRing(xmlWriter, innerBoundary, height);
xmlWriter.writeEndElement(); // innerBoundaryIs
}
xmlWriter.writeEndElement(); // Polygon
xmlWriter.writeEndElement(); // Placemark
xmlWriter.flush();
}
}