gov.nasa.worldwind.render.ExtrudedPolygon 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.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 com.jogamp.opengl.*;
import com.jogamp.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.
*
* When drawn on a 2D globe, this shape uses a {@link SurfacePolygon} to represent itself. Cap texture is not supported
* in this case.
*
* @author tag
* @version $Id: ExtrudedPolygon.java 2111 2014-06-30 18:09:45Z 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 extends LatLon> 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 extends LatLon> 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 extends LatLon> 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 extends LatLon> 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 extends LatLon> 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 extends Position> 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 extends Position> 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 extends LatLon> 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 extends LatLon> 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 extends LatLon> getOuterBoundary()
{
return this.outerBoundary();
}
/**
* Returns a reference to the outer boundary of this polygon.
*
* @return this polygon's outer boundary.
*/
protected List extends LatLon> 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 extends LatLon> 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 extends LatLon> 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 extends LatLon> 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 extends LatLon> fillBoundary(Iterable extends LatLon> 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 extends LatLon> 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 extends LatLon> 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
© 2015 - 2024 Weber Informatics LLC | Privacy Policy