src.gov.nasa.worldwind.render.ExtrudedPolygon 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.render;
import com.jogamp.common.nio.Buffers;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.cache.ShapeDataCache;
import gov.nasa.worldwind.exception.WWRuntimeException;
import gov.nasa.worldwind.geom.Box;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.ogc.kml.impl.KMLExportUtil;
import gov.nasa.worldwind.terrain.Terrain;
import gov.nasa.worldwind.util.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.GLU;
import javax.xml.stream.*;
import java.io.*;
import java.nio.*;
import java.util.*;
/**
* A multi-sided 3D shell formed by a base polygon in latitude and longitude extruded from the terrain to either a
* specified height or an independent height per location. The base polygon may be complex with multiple internal but
* not intersecting contours.
*
* Extruded polygon boundaries may be specified using either {@link LatLon} locations or {@link Position} positions, but
* all the shape's boundary vertices must be the same type.
*
* Extruded polygons may optionally be textured. Textures may be applied to both the faces of the outer and inner
* boundaries or just the outer boundaries. Texture can also be applied independently to the cap. Standard lighting is
* optionally applied. Texture source images are lazily retrieved and loaded. This can cause a brief period in which the
* texture is not displayed while it is retrieved from disk or network.
*
* ExtrudedPolygon
side faces and cap have independent attributes for both normal and highlighted drawing.
*
* When specifying a single height (altitude mode {@link WorldWind#CONSTANT}, the height is relative to a reference
* location designated by one of the specified polygon locations in the outer boundary. The default reference location
* is the first one in the polygon's outer boundary. An alternative location may be specified by calling {@link
* #setReferenceLocation(LatLon)}. The extruded polygon is capped with a plane at the specified height and tangent to
* the ellipsoid at the reference location. Since locations other than the reference location may resolve to points at
* elevations other than that at the reference location, the distances from those points to the cap are adjusted so that
* the adjacent sides precisely meet the cap. When specifying polygons using a single height, only the latitudes and
* longitudes of polygon boundary positions must be specified.
*
* Independent per-location heights may be specified via the altitude field of {@link Position}s defining the
* polygon's inner and outer boundaries. Depending on the specified altitude mode, the position altitudes may be
* interpreted as altitudes relative to mean sea level or altitudes above the ground at the associated latitude and
* longitude locations.
*
* Boundaries are required to be closed, their first location must be equal to their last location. Boundaries that are
* not closed are explicitly closed by this shape when they are specified.
*
* Extruded polygons are safe to share among World Windows. They should not be shared among layers in the same World
* Window.
*
* In order to support simultaneous use of this shape with multiple globes (windows), this shape maintains a cache of
* data computed relative to each globe. During rendering, the data for the currently active globe, as indicated in the
* draw context, is made current. Subsequently called methods rely on the existence of this current data cache entry.
*
* @author tag
* @version $Id: ExtrudedPolygon.java 1857 2014-03-06 00:22:52Z tgaskins $
*/
public class ExtrudedPolygon extends AbstractShape
{
/** The default interior color for sides. */
protected static final Material DEFAULT_SIDES_INTERIOR_MATERIAL = Material.LIGHT_GRAY;
/** The default altitude mode. */
protected static final int DEFAULT_ALTITUDE_MODE = WorldWind.CONSTANT;
/** The attributes used if attributes are not specified. */
protected static final ShapeAttributes defaultSideAttributes;
protected double baseDepth;
static
{
defaultSideAttributes = new BasicShapeAttributes();
defaultSideAttributes.setInteriorMaterial(DEFAULT_SIDES_INTERIOR_MATERIAL);
}
/** The ShapeData
class holds globe-specific data for this shape. */
protected static class ShapeData extends AbstractShapeData implements Iterable
{
/** The boundary locations of the associated shape. Copied from that shape during construction. */
protected List boundaries = new ArrayList();
/** A buffer holding the Cartesian cap vertices of all the shape's boundaries. */
protected FloatBuffer capVertexBuffer;
/** A buffer holding the cap normals of all the shape's boundaries. */
protected FloatBuffer capNormalBuffer;
/** A buffer holding the Cartesian vertices of all the shape's side vertices. */
protected FloatBuffer sideVertexBuffer;
/** A buffer holding the side normals of all the shape's boundaries. */
protected FloatBuffer sideNormalBuffer;
/** A buffer holding the texture coordinates of all the shape's faces. Non-null only when texture is applied. */
protected FloatBuffer sideTextureCoordsBuffer;
// Tessellation fields
/** This shape's tessellation. */
protected GLUTessellatorSupport.CollectIndexListsCallback cb;
/**
* The indices identifying the cap vertices in a shape data's vertex buffer. Determined when this shape is
* tessellated, which occurs only once unless the shape's boundaries are re-specified.
*/
protected IntBuffer capFillIndices;
/** Slices of capFillIndices
, one per boundary. */
protected List capFillIndexBuffers;
/** Indicates whether a tessellation error occurred. No more attempts to tessellate will be made if set to true. */
protected boolean tessellationError = false;
/**
* Constructs an instance using the boundaries of a specified extruded polygon.
*
* @param dc the current draw context.
* @param shape this shape.
*/
public ShapeData(DrawContext dc, ExtrudedPolygon shape)
{
super(dc, shape.minExpiryTime, shape.maxExpiryTime);
if (shape.boundaries.size() < 1)
{
// add a placeholder for the outer boundary
this.boundaries.add(new ExtrudedBoundaryInfo(new ArrayList()));
return;
}
// Copy the shape's boundaries.
for (List boundary : shape.boundaries)
{
this.boundaries.add(new ExtrudedBoundaryInfo(boundary));
}
// Copy the shape's side texture references.
this.copySideTextureReferences(shape);
}
protected void copySideTextureReferences(ExtrudedPolygon shape)
{
if (shape.sideTextures != null)
{
for (int i = 0; i < this.boundaries.size() && i < shape.sideTextures.size(); i++)
{
ExtrudedBoundaryInfo ebi = this.boundaries.get(i);
if (ebi != null)
this.boundaries.get(i).sideTextures = shape.sideTextures.get(i);
}
}
}
/**
* Returns the outer boundary information for this shape data.
*
* @return this shape data's outer boundary information.
*/
protected ExtrudedBoundaryInfo getOuterBoundaryInfo()
{
return this.boundaries.get(0);
}
/**
* Iterates over the boundary information of this shape data.
*
* @return an iterator over this shape data's boundary info.
*/
public Iterator iterator()
{
return this.boundaries.iterator();
}
}
@Override
protected AbstractShapeData createCacheEntry(DrawContext dc)
{
return new ShapeData(dc, this);
}
/**
* Indicates the currently active shape data.
*
* @return the currently active shape data.
*/
protected ShapeData getCurrent()
{
return (ShapeData) this.getCurrentData();
}
/**
* Holds globe-specific information for each contour of the polygon. This class is meant only to be used as a way to
* group per-boundary information in globe-specific ShapeData
.
*/
protected static class ExtrudedBoundaryInfo
{
/** The boundary vertices. This is merely a reference to the paren't shape's boundaries. */
protected List locations;
/** The number of faces in the boundary. (The number of positions - 1.) */
protected int faceCount;
/** The vertices defining the boundary's cap. */
protected Vec4[] capVertices;
/** The vertices defining the boundary's base. These are always on the terrain. */
protected Vec4[] baseVertices;
/** Indices identifying the cap vertices in the vertex buffer. */
protected IntBuffer capFillIndices;
/** Indices identifying the cap edges in the vertex buffer. */
protected IntBuffer capEdgeIndices;
/** A buffer holding the vertices defining the boundary's cap. */
protected FloatBuffer capVertexBuffer;
/** A buffer holding the boundary cap's vertex normals. Non-null only when lighting is applied. */
protected FloatBuffer capNormalBuffer;
/** The indices identifying the boundary's side faces in the side-vertex buffer. */
protected IntBuffer sideIndices;
/** The indices identifying the boundary's edge indices in the side-vertex buffer. */
protected IntBuffer sideEdgeIndices;
/** A buffer holding the side vertices. These are passed to OpenGL. */
protected FloatBuffer sideVertexBuffer;
/** A buffer holding per-vertex normals. Non-null only when lighting is applied. */
protected FloatBuffer sideNormalBuffer;
/** The textures to apply to this boundary, one per face. */
protected List sideTextures;
/**
* The texture coordinates to use when applying side textures, a coordinate pair for each of 4 corners. These
* are globe-specific because they account for the varying positions of the base on the terrain. (The cap
* texture coordinates are not globe-specific.)
*/
protected FloatBuffer sideTextureCoords;
/**
* Constructs a boundary info instance for a specified boundary.
*
* @param locations the boundary locations. Only this reference is kept; the boundaries are not copied.
*/
public ExtrudedBoundaryInfo(List locations)
{
this.locations = locations;
this.faceCount = locations.size() - 1;
}
}
// This static hash map holds the vertex indices that define the shape geometry. Their contents depend only on the
// number of locations in the source polygon, so they can be reused by all shapes with the same location count.
protected static HashMap capEdgeIndexBuffers = new HashMap();
protected static HashMap sideFillIndexBuffers = new HashMap();
protected static HashMap sideEdgeIndexBuffers = new HashMap();
/** Indicates the number of vertices that must be present in order for VBOs to be used to render this shape. */
protected static final int VBO_THRESHOLD = Configuration.getIntegerValue(AVKey.VBO_THRESHOLD, 30);
/**
* The location of each vertex in this shape's boundaries. There is one list per boundary. There is always an entry
* for the outer boundary, but its list is empty if an outer boundary has not been specified.
*/
protected List> boundaries;
/** The total number of locations in all boundaries. */
protected int totalNumLocations;
/** The total number of faces in all this shape's boundaries. */
protected int totalFaceCount;
/** This shape's height. Default is 1. */
protected double height = 1;
/** The attributes to use when drawing this shape's sides. */
protected ShapeAttributes sideAttributes;
/** The attributes to use when drawing this shape's sides in highlight mode. */
protected ShapeAttributes sideHighlightAttributes;
/** The currently active side attributes, derived from the specified attributes. Current only during rendering. */
protected ShapeAttributes activeSideAttributes = new BasicShapeAttributes();
/** This shape's side textures. */
protected List> sideTextures;
/** This shape's cap texture. */
protected WWTexture capTexture;
/** This shape's cap texture coordinates. */
protected FloatBuffer capTextureCoords;
/** Indicates whether the cap should be drawn. */
protected boolean enableCap = true;
/** Indicates whether the sides should be drawn. */
protected boolean enableSides = true;
// Intersection fields
/** The terrain used in the most recent intersection calculations. */
protected Terrain previousIntersectionTerrain;
/** The globe state key for the globe used in the most recent intersection calculation. */
protected Object previousIntersectionGlobeStateKey;
/** The shape data used for the previous intersection calculation. */
protected ShapeData previousIntersectionShapeData;
/** Constructs an extruded polygon with an empty outer boundary and a default height of 1 meter. */
public ExtrudedPolygon()
{
this.boundaries = new ArrayList>();
this.boundaries.add(new ArrayList()); // placeholder for outer boundary
}
/**
* Constructs an extruded polygon of a specified height and an empty outer boundary.
*
* @param height the shape height, in meters. May be null, in which case a height of 1 is used. The height is used
* only when the altitude mode is {@link WorldWind#CONSTANT}, which is the default for this shape.
*/
public ExtrudedPolygon(Double height)
{
this(); // to initialize the instance
this.setHeight(height);
}
/**
* Constructs an extruded polygon for a specified list of outer boundary locations and a height.
*
* @param corners the list of locations defining this extruded polygon's outer boundary.
* @param height the shape height, in meters. May be null, in which case a height of 1 is used. The height is used
* only when the altitude mode is {@link WorldWind#CONSTANT}, which is the default for this shape.
*
* @throws IllegalArgumentException if the location list is null or the height is specified but less than or equal
* to zero.
*/
public ExtrudedPolygon(Iterable corners, Double height)
{
this(); // to initialize the instance
if (corners == null)
{
String message = Logging.getMessage("nullValue.IterableIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (height != null && height <= 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "height <= 0");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.setOuterBoundary(corners, height);
}
/**
* Constructs an extruded polygon from an outer boundary, a height, and images for its outer faces.
*
* @param corners the list of locations defining this polygon's outer boundary.
* @param height the shape height, in meters. May be null, in which case a height of 1 is used. The height is
* used only when the altitude mode is {@link WorldWind#CONSTANT}, which is the default for this
* shape.
* @param imageSources images to apply to the polygon's outer faces. One image for each face must be included. May
* also be null.
*
* @throws IllegalArgumentException if the location list is null or the height is specified but less than or equal
* to zero.
*/
public ExtrudedPolygon(Iterable corners, double height, Iterable imageSources)
{
this(corners, height);
if (imageSources != null)
{
this.sideTextures = new ArrayList>();
this.sideTextures.add(this.fillImageList(imageSources));
}
}
/**
* Constructs an extruded polygon from an outer boundary.
*
* @param corners the list of outer boundary positions -- latitude longitude and altitude. The altitude mode
* determines whether the positions are considered relative to mean sea level (they are "absolute")
* or the ground elevation at the associated latitude and longitude.
*
* @throws IllegalArgumentException if the position list is null.
*/
public ExtrudedPolygon(Iterable corners)
{
this(corners, 1d); // the height field is ignored when positions are specified, so any value will do
}
/**
* Constructs an extruded polygon from an outer boundary specified with position heights.
*
* @param corners the list of positions -- latitude longitude and altitude -- defining the polygon's outer boundary.
* The altitude mode determines whether the positions are considered relative to mean sea level (they
* are "absolute") or the ground elevation at the associated latitude and longitude.
*
* @throws IllegalArgumentException if the position list is null.
*/
public ExtrudedPolygon(Position.PositionList corners)
{
this(corners.list, 1d); // the height field is ignored when positions are specified, so any value will do
}
/**
* Constructs an extruded polygon from an outer boundary and apply specified textures to its outer faces.
*
* @param corners the list of positions -- latitude longitude and altitude -- defining the polygon. The
* altitude mode determines whether the positions are considered relative to mean sea level
* (they are "absolute") or the ground elevation at the associated latitude and longitude.
* @param imageSources textures to apply to the polygon's outer faces. One texture for each face must be included.
* May also be null.
*
* @throws IllegalArgumentException if the position list is null.
*/
public ExtrudedPolygon(Iterable corners, Iterable imageSources)
{
this(corners);
if (imageSources != null)
{
this.sideTextures = new ArrayList>();
this.sideTextures.add(this.fillImageList(imageSources));
}
}
protected void initialize()
{
// Overridden to specify a default altitude mode unique to extruded polygons.
this.altitudeMode = DEFAULT_ALTITUDE_MODE;
}
protected void reset()
{
// Assumes that the boundary lists have already been established.
for (List locations : this.boundaries)
{
if (locations == null || locations.size() < 3)
continue;
if (!WWMath.computeWindingOrderOfLocations(locations).equals(AVKey.COUNTER_CLOCKWISE))
Collections.reverse(locations);
}
this.totalNumLocations = this.countLocations();
this.previousIntersectionShapeData = null;
this.previousIntersectionTerrain = null;
this.previousIntersectionGlobeStateKey = null;
super.reset(); // removes all shape-data cache entries
}
/**
* Counts the total number of locations in this polygon's boundaries, not including positions introduced by
* extrusion.
*
* @return the number of locations in the polygon boundaries.
*/
protected int countLocations()
{
int count = 0;
for (List locations : this.boundaries)
{
count += locations.size();
}
this.totalFaceCount = count - this.boundaries.size();
return count;
}
/**
* Returns the list of locations or positions defining this polygon's outer boundary.
*
* @return this polygon's positions.
*/
public Iterable getOuterBoundary()
{
return this.outerBoundary();
}
/**
* Returns a reference to the outer boundary of this polygon.
*
* @return this polygon's outer boundary.
*/
protected List outerBoundary()
{
return this.boundaries.get(0);
}
/**
* Indicates whether this shape's outer boundary exists and has more than two points.
*
* @return true if the outer boundary is valid, otherwise false.s
*/
protected boolean isOuterBoundaryValid()
{
return this.boundaries.size() > 0 && this.boundaries.get(0).size() > 2;
}
/**
* Specifies the latitude and longitude of the locations defining the outer boundary of this polygon. To specify
* altitudes, pass {@link Position}s rather than {@link LatLon}s. The shape's height is not modified.
*
* @param corners the outer boundary locations.
*
* @throws IllegalArgumentException if the location list is null or contains fewer than three locations.
*/
public void setOuterBoundary(Iterable corners)
{
this.setOuterBoundary(corners, this.getHeight());
}
/**
* Specifies the latitudes, longitudes and outer-boundary images for the outer boundary of this polygon. To specify
* altitudes, pass {@link Position}s rather than {@link LatLon}s.
*
* @param corners the polygon locations.
* @param imageSources images to apply to the outer faces. One image must be specified for each face. May be null.
*
* @throws IllegalArgumentException if the location list is null.
*/
public void setOuterBoundary(Iterable corners, Iterable imageSources)
{
this.setOuterBoundary(corners);
if (imageSources == null && this.sideTextures == null)
return;
// Must install or replace the side textures
if (this.sideTextures == null)
this.sideTextures = new ArrayList>();
// Add or replace the first element, the outer boundary's element, in the list of side textures.
List textures = this.fillImageList(imageSources);
this.sideTextures.set(0, textures);
// Update the shape cache
for (ShapeDataCache.ShapeDataCacheEntry entry : this.shapeDataCache)
{
ShapeData sd = (ShapeData) entry;
if (sd.boundaries != null)
sd.copySideTextureReferences(this);
}
}
/**
* Specifies the latitude and longitude of the outer boundary locations defining this polygon, and optionally the
* extruded polygon's height. To specify altitudes for each boundary location, pass {@link Position}s rather than
* {@link LatLon}s, but those altitudes are used only when the shape's altitude mode is {@link WorldWind#ABSOLUTE}.
*
* @param corners the outer boundary locations.
* @param height the shape height, in meters.
*
* @throws IllegalArgumentException if the location list is null or contains fewer than three locations.
*/
public void setOuterBoundary(Iterable corners, Double height)
{
if (corners == null)
{
String message = Logging.getMessage("nullValue.IterableIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.getBoundaries().set(0, this.fillBoundary(corners));
if (height != null)
this.height = height;
this.reset();
}
protected List fillBoundary(Iterable corners)
{
ArrayList list = new ArrayList();
for (LatLon corner : corners)
{
if (corner != null)
list.add(corner);
}
if (list.size() < 3)
{
String message = Logging.getMessage("generic.InsufficientPositions");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// Close the list if not already closed.
if (list.size() > 0 && !list.get(0).equals(list.get(list.size() - 1)))
list.add(list.get(0));
list.trimToSize();
return list;
}
/**
* Add an inner boundary to this polygon.
*
* @param corners the boundary's locations.
*
* @throws IllegalArgumentException if the location list is null or contains fewer than three locations.
*/
public void addInnerBoundary(Iterable corners)
{
if (corners == null)
{
String message = Logging.getMessage("nullValue.LocationInListIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.getBoundaries().add(this.fillBoundary(corners));
this.reset();
}
/**
* Add an inner boundary to this polygon and specify images to apply to each of the boundary's faces. Specify {@link
* LatLon}s to use the polygon's single height, or {@link Position}s, to include individual altitudes.
*
* @param corners the boundary's locations.
* @param imageSources images to apply to the boundary's faces. One image must be specified for each face. May be
* null.
*
* @throws IllegalArgumentException if the location list is null.
*/
public void addInnerBoundary(Iterable corners, Iterable imageSources)
{
if (corners == null)
{
String message = Logging.getMessage("nullValue.LocationInListIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.getBoundaries().add(this.fillBoundary(corners));
if (imageSources != null)
{
if (this.sideTextures == null)
{
this.sideTextures = new ArrayList>();
this.sideTextures.add(new ArrayList()); // placeholder for outer boundary
}
this.sideTextures.add(this.fillImageList(imageSources));
}
this.reset();
}
/**
* Returns this shape's boundaries.
*
* @return this shape's boundaries.
*/
protected List> getBoundaries()
{
return this.boundaries;
}
/**
* Creates texture object for a boundary's image sources.
*
* @param imageSources the images to apply for this boundary.
*
* @return the list of texture objects, or null if the imageSources
argument is null.
*/
protected List fillImageList(Iterable imageSources)
{
if (imageSources == null)
return null;
ArrayList textures = new ArrayList();
for (Object source : imageSources)
{
if (source != null)
textures.add(this.makeTexture(source));
else
textures.add(null);
}
textures.trimToSize();
return textures;
}
/**
* Returns this extruded polygon's cap image.
*
* @return the texture image source, or null if no source has been specified.
*/
public Object getCapImageSource()
{
return this.capTexture != null ? this.capTexture.getImageSource() : null;
}
/**
* Specifies the image to apply to this extruded polygon's cap.
*
* @param imageSource the image source. May be a {@link String} identifying a file path or URL, a {@link File}, or
* a {@link java.net.URL}.
* @param texCoords the (s, t) texture coordinates aligning the image to the polygon. There must be one texture
* coordinate pair, (s, t), for each location in the polygon's outer boundary.
* @param texCoordCount the number of texture coordinates, (s, v) pairs, specified.
*
* @throws IllegalArgumentException if the image source is not null and either the texture coordinates are null or
* inconsistent with the specified texture-coordinate count, or there are fewer
* than three texture coordinate pairs.
*/
public void setCapImageSource(Object imageSource, float[] texCoords, int texCoordCount)
{
if (imageSource == null)
{
this.capTexture = null;
this.capTextureCoords = null;
return;
}
if (texCoords == null)
{
String message = Logging.getMessage("generic.ListIsEmpty");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (texCoordCount < 3 || texCoords.length < 2 * texCoordCount)
{
String message = Logging.getMessage("generic.InsufficientPositions");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.capTexture = this.makeTexture(imageSource);
// Determine whether the tex-coord list needs to be closed.
boolean closeIt = texCoords[0] != texCoords[texCoordCount - 2] || texCoords[1] != texCoords[texCoordCount - 1];
this.capTextureCoords = Buffers.newDirectFloatBuffer(2 * (texCoordCount + (closeIt ? 1 : 0)));
for (int i = 0; i < 2 * texCoordCount; i++)
{
this.capTextureCoords.put(texCoords[i]);
}
if (closeIt)
{
this.capTextureCoords.put(this.capTextureCoords.get(0));
this.capTextureCoords.put(this.capTextureCoords.get(1));
}
}
/**
* Returns the texture coordinates for this polygon's cap.
*
* @return the texture coordinates, or null if no cap texture coordinates have been specified.
*/
public float[] getTextureCoords()
{
if (this.capTextureCoords == null)
return null;
float[] retCoords = new float[this.capTextureCoords.limit()];
this.capTextureCoords.get(retCoords, 0, retCoords.length);
return retCoords;
}
/**
* Get the texture applied to this extruded polygon's cap.
*
* @return The texture, or null if there is no texture or the texture is not yet available.
*/
protected WWTexture getCapTexture()
{
return this.capTexture;
}
/**
* Returns the height of this extruded polygon.
*
* @return the height originally specified, in meters.
*/
public double getHeight()
{
return height;
}
/**
* Specifies the height of this extruded polygon.
*
* @param height the height, in meters.
*
* @throws IllegalArgumentException if the height is less than or equal to zero.
*/
public void setHeight(double height)
{
if (this.height == height)
return;
if (height <= 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "height <= 0");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.height = height;
this.reset();
}
/**
* Indicates whether the cap of this extruded polygon is drawn.
*
* @return true to draw the cap, otherwise false.
*/
public boolean isEnableCap()
{
return enableCap;
}
/**
* Specifies whether the cap of this extruded polygon is drawn.
*
* @param enableCap true to draw the cap, otherwise false.
*/
public void setEnableCap(boolean enableCap)
{
this.enableCap = enableCap;
}
/**
* Indicates whether the sides of this extruded polygon are drawn.
*
* @return true to draw the sides, otherwise false.
*/
public boolean isEnableSides()
{
return enableSides;
}
/**
* Specifies whether to draw the sides of this extruded polygon.
*
* @param enableSides true to draw the sides, otherwise false.
*/
public void setEnableSides(boolean enableSides)
{
this.enableSides = enableSides;
}
/**
* Returns the attributes applied to this polygon's side faces.
*
* @return this polygon's side attributes.
*/
public ShapeAttributes getSideAttributes()
{
return this.sideAttributes;
}
/**
* Specifies the attributes applied to this polygon's side faces.
*
* @param attributes this polygon's side attributes.
*
* @throws IllegalArgumentException if attributes
is null.
*/
public void setSideAttributes(ShapeAttributes attributes)
{
if (attributes == null)
{
String message = "nullValue.AttributesIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.sideAttributes = attributes;
}
/**
* Returns the attributes applied to this polygon's cap.
*
* @return this polygon's cap attributes.
*/
public ShapeAttributes getCapAttributes()
{
return this.getAttributes();
}
/**
* Specifies the attributes applied to this polygon's cap.
*
* @param attributes this polygon's cap attributes.
*
* @throws IllegalArgumentException if attributes
is null.
*/
public void setCapAttributes(ShapeAttributes attributes)
{
this.setAttributes(attributes);
}
/**
* Returns the highlight attributes applied to this polygon's side faces.
*
* @return this polygon's side highlight attributes.
*/
public ShapeAttributes getSideHighlightAttributes()
{
return sideHighlightAttributes;
}
/**
* Specifies the highlight attributes applied to this polygon's side faces.
*
* @param attributes this polygon's side highlight attributes.
*
* @throws IllegalArgumentException if attributes
is null.
*/
public void setSideHighlightAttributes(ShapeAttributes attributes)
{
if (attributes == null)
{
String message = "nullValue.AttributesIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.sideHighlightAttributes = attributes;
}
/**
* Returns the highlight attributes applied to this polygon's cap.
*
* @return this polygon's cap highlight attributes.
*/
public ShapeAttributes getCapHighlightAttributes()
{
return this.getHighlightAttributes();
}
/**
* Specifies the highlight attributes applied to this polygon's cap.
*
* @param attributes this polygon's cap highlight attributes.
*
* @throws IllegalArgumentException if attributes
is null.
*/
public void setCapHighlightAttributes(ShapeAttributes attributes)
{
this.setHighlightAttributes(attributes);
}
/**
* Each time this polygon is rendered the appropriate attributes for the current mode are determined. This method
* returns the resolved attributes.
*
* @return the currently active attributes for this polygon's side faces.
*/
protected ShapeAttributes getActiveSideAttributes()
{
return this.activeSideAttributes;
}
/**
* Each time this polygon is rendered the appropriate attributes for the current mode are determined. This method
* returns the resolved attributes.
*
* @return the currently active attributes for this polygon's cap.
*/
protected ShapeAttributes getActiveCapAttributes()
{
return this.getActiveAttributes();
}
public Sector getSector()
{
if (this.sector == null && this.outerBoundary().size() > 2)
this.sector = Sector.boundingSector(this.getOuterBoundary());
return this.sector;
}
/**
* Indicates the location to use as a reference location for computed geometry.
*
* @return the reference location, or null if no reference location has been specified.
*
* @see #getReferencePosition()
*/
public LatLon getReferenceLocation()
{
return this.getReferencePosition();
}
/**
* Specifies the location to use as a reference location for computed geometry. This value should typically be left
* to the default, which is the first location in the extruded polygon's outer boundary.
*
* @param referenceLocation the reference location. May be null, in which case the first location of the outer
* boundary is the reference location.
*
* @see #setReferencePosition(gov.nasa.worldwind.geom.Position)
*/
public void setReferenceLocation(LatLon referenceLocation)
{
if (referenceLocation == null)
{
String message = Logging.getMessage("nullValue.LocationIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.referencePosition = new Position(referenceLocation, 0);
}
/**
* Indicates the position used as a reference position for this extruded polygon's computed geometry.
*
* @return the reference position, or null if no reference position has been specified.
*/
public Position getReferencePosition()
{
if (this.referencePosition != null)
return this.referencePosition;
if (this.boundaries.size() > 0 && this.outerBoundary().size() > 0)
{
if (this.outerBoundary().get(0) instanceof Position)
this.referencePosition = (Position) this.outerBoundary().get(0);
else
this.referencePosition = new Position(this.outerBoundary().get(0), 0);
}
return this.referencePosition;
}
/**
* Returns this object's base depth.
*
* @return This object's base depth, in meters.
*
* @see #setBaseDepth(double)
*/
public double getBaseDepth()
{
return baseDepth;
}
/**
* Specifies a depth below the terrain at which to place this extruded polygon's base vertices. This value does not
* affect the height of the extruded polygon nor the position of its cap. It positions the base vertices such that
* they are the specified distance below the terrain. The default value is zero, therefore the base vertices are
* position on the terrain.
*
* @param baseDepth the depth in meters to position the base vertices below the terrain. Specify positive values to
* position the base vertices below the terrain. (Negative values position the base vertices above
* the terrain.)
*/
public void setBaseDepth(double baseDepth)
{
this.baseDepth = baseDepth;
}
/**
* Returns this extruded polygon's side images.
*
* @return a collection of lists each identifying the image sources for the associated outer or inner polygon
* boundary.
*/
public List> getImageSources()
{
if (this.sideTextures == null)
return null;
boolean hasTextures = false;
for (List textures : this.sideTextures)
{
if (textures != null && textures.size() > 0)
{
hasTextures = true;
break;
}
}
if (!hasTextures)
return null;
List> imageSources = new ArrayList>(this.getBoundaries().size());
for (List textures : this.sideTextures)
{
if (textures == null)
{
imageSources.add(null);
}
else
{
ArrayList