src.gov.nasa.worldwind.render.airspaces.PolyArc 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.airspaces;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.*;
import java.util.*;
/**
* @author tag
* @version $Id: PolyArc.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class PolyArc extends Polygon
{
protected static final int DEFAULT_SLICES = 32;
protected static final int MINIMAL_GEOMETRY_SLICES = 8;
private double radius = 1.0;
private Angle leftAzimuth = Angle.ZERO;
private Angle rightAzimuth = Angle.ZERO;
// Geometry.
private int slices = DEFAULT_SLICES;
private ArrayList polyArcLocations = new ArrayList();
private ArrayList edgeFlags = new ArrayList();
public PolyArc(List locations, double radius, Angle leftAzimuth, Angle rightAzimuth)
{
super(locations);
if (radius < 0.0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "radius=" + radius);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (leftAzimuth == null)
{
String message = "nullValue.LeftAzimuthIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (rightAzimuth == null)
{
String message = "nullValue.RightAzimuthIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.radius = radius;
this.leftAzimuth = leftAzimuth;
this.rightAzimuth = rightAzimuth;
this.makeDefaultDetailLevels();
}
public PolyArc(List locations)
{
super(locations);
this.makeDefaultDetailLevels();
}
public PolyArc(AirspaceAttributes attributes)
{
super(attributes);
this.makeDefaultDetailLevels();
}
public PolyArc()
{
this.makeDefaultDetailLevels();
}
private void makeDefaultDetailLevels()
{
List levels = new ArrayList();
double[] ramp = ScreenSizeDetailLevel.computeDefaultScreenSizeRamp(5);
DetailLevel level;
level = new ScreenSizeDetailLevel(ramp[0], "Detail-Level-0");
level.setValue(SLICES, 32);
level.setValue(SUBDIVISIONS, 3);
level.setValue(DISABLE_TERRAIN_CONFORMANCE, false);
levels.add(level);
level = new ScreenSizeDetailLevel(ramp[1], "Detail-Level-1");
level.setValue(SLICES, 26);
level.setValue(SUBDIVISIONS, 3);
level.setValue(DISABLE_TERRAIN_CONFORMANCE, false);
levels.add(level);
level = new ScreenSizeDetailLevel(ramp[2], "Detail-Level-2");
level.setValue(SLICES, 20);
level.setValue(SUBDIVISIONS, 2);
level.setValue(DISABLE_TERRAIN_CONFORMANCE, false);
levels.add(level);
level = new ScreenSizeDetailLevel(ramp[3], "Detail-Level-3");
level.setValue(SLICES, 14);
level.setValue(SUBDIVISIONS, 1);
level.setValue(DISABLE_TERRAIN_CONFORMANCE, false);
levels.add(level);
level = new ScreenSizeDetailLevel(ramp[4], "Detail-Level-4");
level.setValue(SLICES, 8);
level.setValue(SUBDIVISIONS, 0);
level.setValue(DISABLE_TERRAIN_CONFORMANCE, true);
levels.add(level);
this.setDetailLevels(levels);
}
public double getRadius()
{
return this.radius;
}
public void setRadius(double radius)
{
if (radius < 0.0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "radius=" + radius);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.radius = radius;
}
public Angle[] getAzimuths()
{
Angle[] array = new Angle[2];
array[0] = this.leftAzimuth;
array[1] = this.rightAzimuth;
return array;
}
public void setAzimuths(Angle leftAzimuth, Angle rightAzimuth)
{
if (leftAzimuth == null)
{
String message = "nullValue.LeftAzimuthIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (rightAzimuth == null)
{
String message = "nullValue.RightAzimuthIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.leftAzimuth = leftAzimuth;
this.rightAzimuth = rightAzimuth;
}
protected int getSlices()
{
return this.slices;
}
protected void setSlices(int slices)
{
if (slices < 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "slices=" + slices);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.slices = slices;
}
@Override
protected List computeMinimalGeometry(Globe globe, double verticalExaggeration)
{
if (this.getLocationList() == null)
return null;
ArrayList arcLocations = new ArrayList();
ArrayList arcFlags = new ArrayList();
this.makePolyArcLocations(globe, this.getLocationList(), 8, arcLocations, arcFlags);
ArrayList tessellatedLocations = new ArrayList();
this.makeTessellatedLocations(globe, MINIMAL_GEOMETRY_SUBDIVISIONS, arcLocations, tessellatedLocations);
ArrayList points = new ArrayList();
this.makeExtremePoints(globe, verticalExaggeration, tessellatedLocations, points);
return points;
}
//**************************************************************//
//******************** Geometry Rendering ********************//
//**************************************************************//
protected double[] computeAngles()
{
Angle startAngle = this.normalizedAzimuth(this.leftAzimuth);
Angle stopAngle = this.normalizedAzimuth(this.rightAzimuth);
Angle sweepAngle;
if (startAngle.compareTo(stopAngle) <= 0)
sweepAngle = stopAngle.subtract(startAngle);
else
sweepAngle = Angle.POS360.subtract(startAngle).add(stopAngle);
double[] array = new double[3];
array[0] = startAngle.radians;
array[1] = stopAngle.radians;
array[2] = sweepAngle.radians;
return array;
}
protected void doRenderGeometry(DrawContext dc, String drawStyle)
{
int slices = this.slices;
if (this.isEnableLevelOfDetail())
{
DetailLevel level = this.computeDetailLevel(dc);
Object o = level.getValue(SLICES);
if (o != null && o instanceof Integer)
slices = (Integer) o;
}
this.polyArcLocations.clear();
this.edgeFlags.clear();
this.makePolyArcLocations(dc.getGlobe(), this.getLocationList(), slices, this.polyArcLocations, this.edgeFlags);
this.doRenderGeometry(dc, drawStyle, this.polyArcLocations, this.edgeFlags);
}
private void makePolyArcLocations(Globe globe, List locations, int slices,
List polyArcLocations, List edgeFlags)
{
int locationCount = locations.size();
if (locationCount > 0)
{
// Create arc locations. These are guaranteed to be in clockwise order about the first location.
double[] angles = this.computeAngles();
double radius = this.radius;
LatLon first = locations.get(0);
int arcCount = this.getArcVertexCount(slices);
LatLon[] arcLocations = new LatLon[arcCount];
this.makeArc(globe, first, radius, slices, angles[0], angles[2], arcLocations);
for (int i = 0; i < arcCount; i++)
{
polyArcLocations.add(arcLocations[i]);
edgeFlags.add(false);
}
// Enable edge flags for the first and last poly arc locations.
if (edgeFlags.size() > 1)
{
edgeFlags.set(0, true);
edgeFlags.set(edgeFlags.size() - 1, true);
}
// Add the remaining polygon locations (skipping the first). These winding order of these locations is
// checked, then they are added in counter-clockwise order about the first location.
if (locationCount > 1)
{
GeometryBuilder gb = this.getGeometryBuilder();
Vec4[] polyPoints = new Vec4[locationCount + 1];
Matrix[] polyTransform = new Matrix[1];
int polyCount = this.computeCartesianPolygon(globe, locations, null, polyPoints, null, polyTransform);
int polyWinding = gb.computePolygonWindingOrder2(0, polyCount, polyPoints);
if (polyWinding == GeometryBuilder.COUNTER_CLOCKWISE)
{
for (int i = 1; i < locationCount; i++)
{
polyArcLocations.add(locations.get(i));
edgeFlags.add(true);
}
}
else // (polyWinding == GeometryBuilder.CLOCKWISE)
{
for (int i = locationCount - 1; i >= 1; i--)
{
polyArcLocations.add(locations.get(i));
edgeFlags.add(true);
}
}
}
}
}
private int getArcVertexCount(int slices)
{
return slices + 1;
}
private void makeArc(Globe globe, LatLon center, double radius, int slices, double start, double sweep,
LatLon[] locations)
{
int count = this.getArcVertexCount(slices);
Matrix transform = globe.computeSurfaceOrientationAtPosition(center.getLatitude(), center.getLongitude(), 0.0);
Vec4[] points = new Vec4[count];
this.makeArc(radius, slices, start, sweep, transform, points);
for (int i = 0; i < count; i++)
{
Position pos = globe.computePositionFromPoint(points[i]);
locations[i] = new LatLon(pos.getLatitude(), pos.getLongitude());
}
}
private void makeArc(double radius, int slices, double start, double sweep, Matrix transform, Vec4[] points)
{
double aStep = sweep / (double) slices;
for (int i = 0; i <= slices; i++)
{
double a = start + i * aStep;
double x = Math.sin(a);
double y = Math.cos(a);
points[i] = new Vec4(x * radius, y * radius, 0.0);
points[i] = points[i].transformBy4(transform);
}
}
private Angle normalizedAzimuth(Angle azimuth)
{
double degrees = azimuth.degrees;
double normalizedDegrees = degrees < 0.0 ? degrees + 360.0 : (degrees >= 360.0 ? degrees - 360.0 : degrees);
return Angle.fromDegrees(normalizedDegrees);
}
//**************************************************************//
//******************** END Geometry Rendering *****************//
//**************************************************************//
@Override
protected void doGetRestorableState(RestorableSupport rs, RestorableSupport.StateObject context)
{
super.doGetRestorableState(rs, context);
rs.addStateValueAsDouble(context, "leftAzimuthDegrees", this.leftAzimuth.degrees);
rs.addStateValueAsDouble(context, "rightAzimuthDegrees", this.rightAzimuth.degrees);
rs.addStateValueAsDouble(context, "radius", this.radius);
}
@Override
protected void doRestoreState(RestorableSupport rs, RestorableSupport.StateObject context)
{
super.doRestoreState(rs, context);
Double d = rs.getStateValueAsDouble(context, "radius");
if (d != null)
this.setRadius(d);
Double la = rs.getStateValueAsDouble(context, "leftAzimuthDegrees");
if (la == null)
la = this.leftAzimuth.degrees;
Double ra = rs.getStateValueAsDouble(context, "rightAzimuthDegrees");
if (ra == null)
ra = this.rightAzimuth.degrees;
this.setAzimuths(Angle.fromDegrees(la), Angle.fromDegrees(ra));
}
}