/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package sec.web.render;
import sec.geo.GeoPoint;
import sec.geo.kml.KmlOptions;
import sec.geo.kml.KmlRenderer;
import sec.geo.kml.XsltCoordinateWrapper;
import sec.geo.shape.Cake;
import sec.geo.shape.Radarc;
import sec.geo.shape.Route;
import sec.geo.shape.Track;
import sec.web.exceptions.InvalidNumberOfPointsException;
import sec.geo.utilities.StringBuilder;
/**
* Responsible for generating the KML for all 3D shapes. This
*
*
* @author stephen.pinizzotto
*/
@SuppressWarnings({"unused"})
public class Shape3DHandler {
// constants for the available shape types that can
// be generated into KML
public static final String CYLINDER = "CYLINDER-------";
public static final String ORBIT = "ORBIT----------";
public static final String ROUTE = "ROUTE----------";
public static final String POLYGON = "POLYGON--------";
public static final String RADARC = "RADARC---------";
public static final String POLYARC = "POLYARC--------";
public static final String CAKE = "CAKE-----------";
public static final String TRACK = "TRACK----------";
// Attribute names of the 3D shapes
public static final String ATTRIBUTES = "attributes";
public static final String MIN_ALT = "minalt";
public static final String MAX_ALT = "maxalt";
public static final String RADIUS1 = "radius1";
public static final String RADIUS2 = "radius2";
public static final String LEFT_AZIMUTH = "leftAzimuth";
public static final String RIGHT_AZIMUTH = "rightAzimuth";
// Arbitrary default values of attributes
public static final double MIN_ALT_DEFAULT = 0.0D;
public static final double MAX_ALT_DEFAULT = 100.0D;
public static final double RADIUS1_DEFAULT = 50.0D;
public static final double RADIUS2_DEFAULT = 100.0D;
public static final double LEFT_AZIMUTH_DEFAULT = 0.0D;
public static final double RIGHT_AZIMUTH_DEFAULT = 90.0D;
public static final String DEFAULT_ATTRIBUTES = "[{radius1:"
+ RADIUS1_DEFAULT + ",radius2:"
+ RADIUS2_DEFAULT + ",minalt:"
+ MIN_ALT_DEFAULT + ",maxalt:"
+ MAX_ALT_DEFAULT + ",rightAzimuth:"
+ RIGHT_AZIMUTH_DEFAULT + ",leftAzimuth:"
+ LEFT_AZIMUTH_DEFAULT + "}]";
// Error messages
public static final String ERR_ATTRIBUTES_NOT_FORMATTED = "{\"type\":\"error\","
+ "\"error\":\"The attribute paramaters are not formatted "
+ "correctly";
public static final String ERR_COORDINATES_NOT_FORMATTED = "{\"type\":\"error\",\""
+ "error\":\"There was an error creating the Symbol - the "
+ "coordinates were not formatted correctly";
public static final String ERR_GENERAL_ERROR = "{\"type\":\"error\",\"error\""
+ ":\"There was an error creating the Symbol - An unknown error "
+ "occurred. Please refer to the stack trace";
public static final String ERR_INVALID_NUMBER_POINTS_ERROR = "{\"type\":\""
+ "error\","
+ "\"error\":\"Not enough points were passed in to create a "
+ "graphic.";
/**
* Generates the KML for a 3D symbol. Symbol should include the all the
* attributes and information required by the KML for output.
*
* @param name The user displayed name for the symbol. Users will use this
* to identify with the symbol.
* @param id An internally used unique id that developers can use to
* uniquely distinguish this symbol from others.
* @param shapeType A 15 character ID of the type of symbol to draw.
* @param description A brief description of what the symbol represents.
* Generic text that does not require any format.
* @param color The fill color of the graphic
* @param altitudeMode Indicates whether the symbol should interpret
* altitudes as above sea level or above ground level. Options are
* "relativeToGround" (from surface of earth), "absolute" (sea level),
* "relativeToSeaFloor" (from the bottom of major bodies of water).
* @param controlPoints The vertices of the shape. The number of required
* vertices varies based on the shapeType of the symbol. The simplest shape
* requires at least one point. Shapes that require more points than
* required will ignore extra points. Format for numbers is as follows:
* <br/><br/>
* "x,y,z [x,y,z ]..."
* @param attributes A JSON A JSON array holding the parameters for the
* shape. Attributes should be of the following format: <br/><br/>
* <tr><code>{"attributes":[{"<i>attribute1</i>":<i>value</i>,...},{<i>[optional]</i>]}</code></tr>
* @return A KML string that represents a placemark for the 3D shape
*/
public static String render3dSymbol(String name, String id, String shapeType,
String description, String lineColor, String fillColor, String altitudeMode,
String controlPoints,
SymbolModifiers attributes) {
String result = "";
KmlOptions.AltitudeMode convertedAltitudeMode = KmlOptions.AltitudeMode.RELATIVE_TO_GROUND;
// Convert altitude mode to an enum that we understand. If it does not
// understand or is "", then convert to ALTITUDE_RELATIVE_TO_GROUND.
if (!altitudeMode.equals(""))
{
convertedAltitudeMode = KmlOptions.AltitudeMode.fromString(altitudeMode);
}
if (shapeType.equals(CYLINDER)) {
result = buildCylinder(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else if (shapeType.equals(ORBIT)) {
result = buildOrbit(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else if (shapeType.equals(RADARC)) {
result = buildRadarc(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else if (shapeType.equals(POLYARC)) {
result = buildPolyArc(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else if (shapeType.equals(ROUTE)) {
result = buildRoute(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else if (shapeType.equals(POLYGON)) {
result = buildPolygon(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else if (shapeType.equals(CAKE)) {
result = buildCake(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else if (shapeType.equals(TRACK)) {
result = buildTrack(controlPoints, id, name, description, lineColor, fillColor, convertedAltitudeMode, attributes);
} else {
StringBuilder sb = new StringBuilder();
sb.append("Given shape type \""+shapeType+"\" does not match any of the available shape types.");
sb.append("\n");
sb.append("Available Types: ");
sb.append(CYLINDER+"\n");
sb.append(ORBIT+"\n");
sb.append(ROUTE+"\n");
sb.append(POLYGON+"\n");
sb.append(RADARC+"\n");
sb.append(POLYARC+"\n");
sb.append(CAKE+"\n");
sb.append(TRACK);
System.out.println(sb.toString());
}
//System.out.println(result);
//System.out.println("Render3DSymbolExited");
return result;
}
/**
* Builds a 3d Polygon with elevation.
*
* @param controlPoints
* @param attributes
* @return
*/
public static String buildPolygon(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
StringBuilder output = new StringBuilder();
String pointArrayStringList = "";
try {
// Get the points of the icons. For the polyarc we need only
// one point, the pivot point, then the rest of the points for the
// polygon.
String[] latlons = controlPoints.split(" ");
if (latlons.length >= 2) {
// Build the polyarc
pointArrayStringList = XsltCoordinateWrapper.getPolygonKml(
latlons, id, name, description, lineColor, fillColor, altitudeMode,
attributes.X_ALTITUDE_DEPTH.get(0),
attributes.X_ALTITUDE_DEPTH.get(1));
} else {
// throw illegal number of points exception
throw new InvalidNumberOfPointsException();
}
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
/**
* Builds a cylinder given a point. Can also apply a radius size and an
* altitude for lower and upper boundaries.
* @param controlPoints
* @param attributes
* @return
*/
public static String buildCylinder(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
StringBuilder output = new StringBuilder();
String pointArrayStringList = "";
// variables for the cylinder position
double pivotx = 0.0D;
double pivoty = 0.0D;
try {
// Get the points of the icons. For the cylinder we need only
// one point. Ignore any more than the first point.
String[] latlons = controlPoints.split(" ");
if (latlons.length > 0) {
String[] pivot = latlons[0].split(",");
if (pivot.length >= 2) {
pivotx = Double.parseDouble(pivot[0]);
pivoty = Double.parseDouble(pivot[1]);
} else {
throw new NumberFormatException();
}
} else {
// throw an illegal number of points exception
throw new InvalidNumberOfPointsException();
}
// Build the cylinder
pointArrayStringList = XsltCoordinateWrapper.getCircleKml(pivotx,
pivoty, id, name, description, lineColor, fillColor, altitudeMode,
attributes.AM_DISTANCE.get(0),
attributes.X_ALTITUDE_DEPTH.get(0),
attributes.X_ALTITUDE_DEPTH.get(1));
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
public static String buildKml(String[] coords, String id, String name, String lineColor, String fillColor) {
StringBuilder kml = new StringBuilder();
kml.append("<Placemark>");
kml.append("<name>");
kml.append(name);
kml.append("</name>");
kml.append("<id>");
kml.append(id);
kml.append("</id>");
kml.append("<Style>");
kml.append("<PolyStyle>");
kml.append("<color>");
kml.append(fillColor);
kml.append("</color>");
kml.append("</PolyStyle>");
kml.append("<LineStyle>");
kml.append(lineColor);
kml.append("</LineStyle>");
kml.append("</Style>");
kml.append("<MultiGeometry>");
for (String s : coords) {
kml.append("<Polygon>");
kml.append("<extrude>0</extrude>");
kml.append("<altitudeMode>relativeToGround</altitudeMode>");
kml.append("<outerBoundaryIs>");
kml.append("<LinearRing>");
kml.append("<coordinates>");
kml.append(s);
kml.append("</coordinates>");
kml.append("</LinearRing>");
kml.append("</outerBoundaryIs>");
kml.append("</Polygon>");
}
kml.append("</MultiGeometry>");
kml.append("</Placemark>");
return kml.toString();
}
/**
* Build an Orbit graphic.
*
* @param controlPoints
* @param attributes
* @return
*/
public static String buildOrbit(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
StringBuilder output = new StringBuilder();
String pointArrayStringList = "";
// variables for the cylinder position
double point1x = 0.0D;
double point1y = 0.0D;
double point2x = 0.0D;
double point2y = 0.0D;
try {
// Get the points of the icons. For the cylinder we need only
// one point. Ignore any more than the first point.
String[] latlons = controlPoints.split(" ");
if (latlons.length > 1) {
String[] point1 = latlons[0].split(",");
if (point1.length >= 2) {
point1x = Double.parseDouble(point1[0]); // x value
point1y = Double.parseDouble(point1[1]); // y value
} else {
throw new NumberFormatException();
}
String[] point2 = latlons[1].split(",");
if (point2.length >= 2) {
point2x = Double.parseDouble(point2[0]); // x value
point2y = Double.parseDouble(point2[1]); // y value
} else {
throw new NumberFormatException();
}
} else {
// throw invalid number of points exception
throw new InvalidNumberOfPointsException();
}
// Build the orbit
pointArrayStringList = XsltCoordinateWrapper.getOrbitKml(point1x, point1y,
point2x, point2y, id, name, description, lineColor, fillColor, altitudeMode, attributes.AM_DISTANCE.get(0), attributes.X_ALTITUDE_DEPTH.get(0), attributes.X_ALTITUDE_DEPTH.get(1));
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
/**
* Builds the Radarc graphic
*
* @param controlPoints
* @param attributes
* @return
*/
public static String buildRadarc(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
StringBuilder output = new StringBuilder();
String pointArrayStringList = "";
// variables for the cylinder position
double pivotx = 0.0D;
double pivoty = 0.0D;
try {
// Get the points of the icons. For the radarc we need only
// one point. Ignore any more than the first point.
String[] latlons = controlPoints.split(" ");
if (latlons.length > 0) {
String[] pivot = latlons[0].split(",");
if (pivot.length >= 2) {
pivotx = Double.parseDouble(pivot[0]);
pivoty = Double.parseDouble(pivot[1]);
} else {
throw new NumberFormatException();
}
} else {
// throw invalid number of points exception
throw new InvalidNumberOfPointsException();
}
// Build the orbit
pointArrayStringList = XsltCoordinateWrapper.getRadarcKml(pivotx, pivoty,
id, name, description, lineColor, fillColor, altitudeMode,
attributes.AM_DISTANCE.get(0),
attributes.AM_DISTANCE.get(1),
attributes.AN_AZIMUTH.get(0),
attributes.AN_AZIMUTH.get(1),
attributes.X_ALTITUDE_DEPTH.get(0),
attributes.X_ALTITUDE_DEPTH.get(1));
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
/**
* Builds the PolyArc graphic
*
* @param controlPoints
* @param attributes
* @return
*/
public static String buildPolyArc(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
StringBuilder output = new StringBuilder();
String pointArrayStringList = "";
// variables for the cylinder position
double pivotx = 0.0D;
double pivoty = 0.0D;
try {
// Get the points of the icons. For the polyarc we need only
// one point, the pivot point, then the rest of the points for the
// polygon.
String[] latlons = controlPoints.split(" ");
if (latlons.length >= 3) {
String[] pivot = latlons[0].split(",");
if (pivot.length >= 2) {
pivotx = Double.parseDouble(pivot[0]);
pivoty = Double.parseDouble(pivot[1]);
} else {
throw new NumberFormatException();
}
int length = latlons.length - 1;
String[] points = new String[length];
System.arraycopy(latlons, 1, points, 0, length);
// Build the polyarc
pointArrayStringList = XsltCoordinateWrapper.getPolyarcKml(points,
pivotx, pivoty, id, name, description, lineColor, fillColor, altitudeMode,
attributes.AM_DISTANCE.get(0),
attributes.AN_AZIMUTH.get(0), attributes.AN_AZIMUTH.get(1),
attributes.X_ALTITUDE_DEPTH.get(0), attributes.X_ALTITUDE_DEPTH.get(1));
} else {
// illegal number of points exception
throw new InvalidNumberOfPointsException();
}
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
/**
* Builds a route graphic.
* @param controlPoints
* @param attributes
* @return
*/
public static String buildRoute(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
String pointArrayStringList = "";
double width;
double leftWidth;
double rightWidth;
try {
// Get the points of the icons. For the polyarc we need only
// one point, the pivot point, then the rest of the points for the
// polygon.
String[] latlons = controlPoints.split(" ");
if (latlons.length >= 2) {
width = attributes.AM_DISTANCE.get(0);
leftWidth = width / 2;
rightWidth = width / 2;
// Build the polyarc
pointArrayStringList = XsltCoordinateWrapper.getRouteKml(latlons,
id, name, description, lineColor, fillColor, altitudeMode,
leftWidth, rightWidth, attributes.X_ALTITUDE_DEPTH.get(0), attributes.X_ALTITUDE_DEPTH.get(1));
} else {
// illegal number of points exception
throw new InvalidNumberOfPointsException();
}
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
/**
* Builds a cake graphic--multiple radarcs stacked on top of each other.
* <br/>
* This graphic can take up to 6 attributes. "radius1" is the max radius,
* "radius2" is the min radius, "minalt", "maxalt", "leftAzimuth", and
* "rightAzimuth"
*
* @param controlPoints
* @param attributes
* @return
*/
public static String buildCake(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
StringBuilder output = new StringBuilder();
String pointArrayStringList = "";
// Creat a new cake to begin adding layers to.
Cake letThemEat = new Cake();
// variables for the cylinder position
double pivotx = 0.0D;
double pivoty = 0.0D;
// Used to store all the polygons for the cakelayers
//Set<KmlPolygon> combinedCakeLayers = null;
// Used to generate the points
KmlRenderer kmlRender = new KmlRenderer();
try {
// Get the points of graphic.
String[] latlons = controlPoints.split(" ");
int numberOfPoints = latlons.length;
if (numberOfPoints > 0) {
//get the pivot point for this graphics.
// all cake layers will use this pivot point for its
//origin.
String[] pivotString = latlons[0].split(",");
if (pivotString.length >= 2) {
pivotx = Double.parseDouble(pivotString[0]);
pivoty = Double.parseDouble(pivotString[1]);
letThemEat.setPivot(new GeoPoint(pivotx, pivoty));
} else {
throw new NumberFormatException();
}
int attributesArrayLength = attributes.X_ALTITUDE_DEPTH.size();
for (int i = 0; i < attributesArrayLength; i++) {
// Create a new cake layer and set its pivot point.
Radarc layerCake = new Radarc();
layerCake.setAltitudeMode(altitudeMode);
layerCake.setPivot(new GeoPoint(pivotx, pivoty));
layerCake.setMinRadius(attributes.AM_DISTANCE.get(i));
layerCake.setRadius(attributes.AM_DISTANCE.get(i + 1));
layerCake.setMinAltitude(attributes.X_ALTITUDE_DEPTH.get(i));
layerCake.setMaxAltitude(attributes.X_ALTITUDE_DEPTH.get(i + 1));
layerCake.setLeftAzimuthDegrees(attributes.AN_AZIMUTH.get(i));
layerCake.setRightAzimuthDegrees(attributes.AN_AZIMUTH.get(i + 1));
i++;
letThemEat.addLayer(layerCake);
}
pointArrayStringList = kmlRender.getCakeKml(letThemEat, id, name, description, lineColor, fillColor);
} else {
// if not enough points throw exception
throw new InvalidNumberOfPointsException();
}
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
/**
* Builds a track graphic composed of multiple routes
*
* @param controlPoints
* @param attributes
* @return
*/
public static String buildTrack(String controlPoints, String id,
String name, String description, String lineColor, String fillColor, KmlOptions.AltitudeMode altitudeMode,
SymbolModifiers attributes) {
String pointArrayStringList = "";
// generates the points for the track.
KmlRenderer kmlRender = new KmlRenderer();
try {
// Get the points of graphic.
String[] latlons = controlPoints.split(" ");
int numberOfPoints = latlons.length;
//ensure enough values in distance and altitude arrays for the number of points M. Deutch 4-15-15
int numAM=attributes.AM_DISTANCE.size();
int numX=attributes.X_ALTITUDE_DEPTH.size();
double nextToLastAlt=attributes.X_ALTITUDE_DEPTH.get(numX-2);
double lastAlt=attributes.X_ALTITUDE_DEPTH.get(numX-1);
double lastWidth=attributes.AM_DISTANCE.get(numAM-1);
int delta=2*(numberOfPoints-1)-numAM; //one width per segment
delta=2*(numberOfPoints-1)-numX; //two alts per segment
int j=0;
if(delta>0)
for(j=0;j<delta;j++)
attributes.AM_DISTANCE.add(lastWidth);
int k=0;
while(k<delta)
{
attributes.X_ALTITUDE_DEPTH.add(nextToLastAlt);
attributes.X_ALTITUDE_DEPTH.add(lastAlt);
k+=2;
}
// Ensure the track has an appropriate amount of points.
if (numberOfPoints >= 2) {
Track track = new Track();
for (int i = 0; i < numberOfPoints - 1; i++) {
// Create a new route from first point to the next point.
Route route = new Route();
route.setAltitudeMode(altitudeMode);
String[] point1String = latlons[i].split(",");
String[] point2String = latlons[i + 1].split(",");
double point1lon = 0.0D;
double point1lat = 0.0D;
double point2lon = 0.0D;
double point2lat = 0.0D;
if (point1String.length >= 2) {
point1lon = Double.parseDouble(point1String[0]);
point1lat = Double.parseDouble(point1String[1]);
} else {
throw new NumberFormatException();
}
if (point2String.length >= 2) {
point2lon = Double.parseDouble(point2String[0]);
point2lat = Double.parseDouble(point2String[1]);
} else {
throw new NumberFormatException();
}
route.addPoint(new GeoPoint(point1lon, point1lat));
route.addPoint(new GeoPoint(point2lon, point2lat));
route.setLeftWidth(attributes.AM_DISTANCE.get(2 * i));
route.setRightWidth(attributes.AM_DISTANCE.get(2 * i + 1));
route.setMinAltitude(attributes.X_ALTITUDE_DEPTH.get(2 * i));
route.setMaxAltitude(attributes.X_ALTITUDE_DEPTH.get(2 * i + 1));
// Add the route to our track
track.addRoute(route);
}
pointArrayStringList = kmlRender.getKml(track, id, name, description, lineColor, fillColor);
} else {
//throw invalid number of points exception
throw new InvalidNumberOfPointsException();
}
} catch (Exception e) {
pointArrayStringList = "";
}
return pointArrayStringList;
}
}