diff --git a/src/main/java/armyc2/c5isr/JavaLineArray/TacticalLines.java b/src/main/java/armyc2/c5isr/JavaLineArray/TacticalLines.java index ed23c7d..5a45495 100644 --- a/src/main/java/armyc2/c5isr/JavaLineArray/TacticalLines.java +++ b/src/main/java/armyc2/c5isr/JavaLineArray/TacticalLines.java @@ -28,6 +28,13 @@ public final class TacticalLines { @Deprecated public static final int BS_BBOX=15000004; + public static final int BS_ORBIT = 16000001; + public static final int BS_ROUTE = 16000002; + public static final int BS_RADARC = 16000003; + public static final int BS_POLYARC = 16000004; + public static final int BS_CAKE = 16000005; + public static final int BS_TRACK = 16000006; + public static final int PZ = 22138000; public static final int LZ = 22137000; public static final int DZ = 22135000; @@ -155,8 +162,8 @@ public final class TacticalLines { public static final int ASR_ONEWAY = 25330401; public static final int ASR_ALT = 25330403; public static final int ASR_TWOWAY = 25330402; - public static final int ROUTE_ONEWAY = 25330501; - public static final int ROUTE_ALT = 25330502; + public static final int TRAFFIC_ROUTE_ONEWAY = 25330501; + public static final int TRAFFIC_ROUTE_ALT = 25330502; public static final int BEARING = 26400000; public static final int BEARING_EW = 220101; public static final int BEARING_J = 220107; @@ -496,7 +503,7 @@ public final class TacticalLines { public static final int GENERIC_AREA = 25120700; public static final int HOL = 25141800; public static final int BHL = 2514190; - public static final int ROUTE = 25330500; + public static final int TRAFFIC_ROUTE = 25330500; public static final int FPOL = 25344100; public static final int RPOL = 25344200; diff --git a/src/main/java/armyc2/c5isr/JavaLineArray/arraysupport.java b/src/main/java/armyc2/c5isr/JavaLineArray/arraysupport.java index cbfadac..1bc06a5 100644 --- a/src/main/java/armyc2/c5isr/JavaLineArray/arraysupport.java +++ b/src/main/java/armyc2/c5isr/JavaLineArray/arraysupport.java @@ -2929,8 +2929,8 @@ private static ArrayList GetLineArray2Double(TGLight tg, case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: nCounter = (int) vblSaveCounter; pLinePoints[vblSaveCounter - 1].style = 5; for (j = 0; j < vblSaveCounter - 1; j++) { @@ -2965,7 +2965,7 @@ private static ArrayList GetLineArray2Double(TGLight tg, nCounter++; } - if (lineType == TacticalLines.MSR_ALT || lineType == TacticalLines.ASR_ALT || lineType == TacticalLines.ROUTE_ALT) { + if (lineType == TacticalLines.MSR_ALT || lineType == TacticalLines.ASR_ALT || lineType == TacticalLines.TRAFFIC_ROUTE_ALT) { lineutility.GetArrowHead4Double(pt3, pt2, (int) d, (int) d, pArrowPoints, 0); diff --git a/src/main/java/armyc2/c5isr/JavaLineArray/countsupport.java b/src/main/java/armyc2/c5isr/JavaLineArray/countsupport.java index af397c0..59d71ed 100644 --- a/src/main/java/armyc2/c5isr/JavaLineArray/countsupport.java +++ b/src/main/java/armyc2/c5isr/JavaLineArray/countsupport.java @@ -323,7 +323,7 @@ protected static int GetCountersDouble(TGLight tg, break; case TacticalLines.MSR_ALT: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE_ALT: count = vblCounter * 9; break; case TacticalLines.MSR_TWOWAY: @@ -332,7 +332,7 @@ protected static int GetCountersDouble(TGLight tg, break; case TacticalLines.MSR_ONEWAY: case TacticalLines.ASR_ONEWAY: - case TacticalLines.ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: count = vblCounter * 6; break; case TacticalLines.WF: diff --git a/src/main/java/armyc2/c5isr/JavaTacticalRenderer/Modifier2.java b/src/main/java/armyc2/c5isr/JavaTacticalRenderer/Modifier2.java index 989a4d8..a5e0202 100644 --- a/src/main/java/armyc2/c5isr/JavaTacticalRenderer/Modifier2.java +++ b/src/main/java/armyc2/c5isr/JavaTacticalRenderer/Modifier2.java @@ -513,9 +513,9 @@ private static String GetCenterLabel(TGLight tg) { case TacticalLines.ASR_ALT: label = "ASR"; break; - case TacticalLines.ROUTE: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: label = "ROUTE"; break; case TacticalLines.LDLC: @@ -1980,9 +1980,9 @@ public static void AddModifiersGeo(TGLight tg, case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: case TacticalLines.DHA_REVD: case TacticalLines.DHA: case TacticalLines.KILL_ZONE: @@ -2738,17 +2738,17 @@ public static void AddModifiersGeo(TGLight tg, break; case TacticalLines.MSR_ONEWAY: case TacticalLines.ASR_ONEWAY: - case TacticalLines.ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: case TacticalLines.MSR_TWOWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.MSR_ALT: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE_ALT: stringWidth = (int) (1.5 * (double) metrics.stringWidth(label + TSpace + tg.get_Name())); double arrowOffset = 10 * DPIScaleFactor; if (linetype == TacticalLines.MSR_TWOWAY || linetype == TacticalLines.ASR_TWOWAY) arrowOffset = 25 * DPIScaleFactor; - boolean isAlt = linetype == TacticalLines.MSR_ALT || linetype == TacticalLines.ASR_ALT || linetype == TacticalLines.ROUTE_ALT; + boolean isAlt = linetype == TacticalLines.MSR_ALT || linetype == TacticalLines.ASR_ALT || linetype == TacticalLines.TRAFFIC_ROUTE_ALT; if (isAlt) { stringWidth2 = (int) (1.5 * (double) metrics.stringWidth("ALT")); if (stringWidth2 > stringWidth) { @@ -2874,7 +2874,7 @@ public static void AddModifiersGeo(TGLight tg, break; case TacticalLines.MSR: case TacticalLines.ASR: - case TacticalLines.ROUTE: + case TacticalLines.TRAFFIC_ROUTE: //AddIntegralModifier(tg, label + tg.get_Name(), aboveMiddle, -1*csFactor, middleSegment, middleSegment + 1,false); foundSegment = false; //acevedo - 11/30/2017 - adding option to render only 2 labels. diff --git a/src/main/java/armyc2/c5isr/JavaTacticalRenderer/clsUtility.java b/src/main/java/armyc2/c5isr/JavaTacticalRenderer/clsUtility.java index 926e205..52ad21c 100644 --- a/src/main/java/armyc2/c5isr/JavaTacticalRenderer/clsUtility.java +++ b/src/main/java/armyc2/c5isr/JavaTacticalRenderer/clsUtility.java @@ -885,9 +885,9 @@ public static boolean LinesWithFill(int linetype) case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: result = true; break; default: @@ -1196,11 +1196,15 @@ public static boolean IsChange1Area(int lineType) { case TacticalLines.RANGE_FAN_FILL: case TacticalLines.RANGE_FAN_SECTOR: case TacticalLines.RADAR_SEARCH: + case TacticalLines.BS_RADARC: + case TacticalLines.BS_CAKE: case TacticalLines.PAA_RECTANGULAR: case TacticalLines.RECTANGULAR_TARGET: case TacticalLines.FSA_RECTANGULAR: case TacticalLines.SHIP_AOI_RECTANGULAR: case TacticalLines.DEFENDED_AREA_RECTANGULAR: + case TacticalLines.BS_ROUTE: + case TacticalLines.BS_TRACK: case TacticalLines.FFA_RECTANGULAR: case TacticalLines.RFA_RECTANGULAR: case TacticalLines.NFA_RECTANGULAR: @@ -1216,6 +1220,8 @@ public static boolean IsChange1Area(int lineType) { case TacticalLines.TVAR_RECTANGULAR: case TacticalLines.KILLBOXBLUE_RECTANGULAR: case TacticalLines.KILLBOXPURPLE_RECTANGULAR: + case TacticalLines.BS_ORBIT: + case TacticalLines.BS_POLYARC: return true; default: return false; @@ -1533,8 +1539,8 @@ public static void FilterVerticalSegments(TGLight tg) case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: case TacticalLines.ATWALL: break; default: @@ -1937,7 +1943,7 @@ public static HashMap getMSRSegmentColors(TGLight tg) { case TacticalLines.MSR: case TacticalLines.ASR: - case TacticalLines.ROUTE: + case TacticalLines.TRAFFIC_ROUTE: case TacticalLines.BOUNDARY: if(tg.get_H()==null || tg.get_H().isEmpty()) return null; @@ -1979,7 +1985,7 @@ public static HashMap getMSRSegmentColorStrings(TGLight tg) switch (linetype) { case TacticalLines.MSR: case TacticalLines.ASR: - case TacticalLines.ROUTE: + case TacticalLines.TRAFFIC_ROUTE: case TacticalLines.BOUNDARY: if (tg.get_H() == null || tg.get_H().isEmpty()) return null; @@ -2033,7 +2039,7 @@ public static void reviseHModifier(ArrayListoriginalPixels, { case TacticalLines.ASR: case TacticalLines.MSR: - case TacticalLines.ROUTE: + case TacticalLines.TRAFFIC_ROUTE: case TacticalLines.BOUNDARY: break; default: diff --git a/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer.java b/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer.java index 291ad11..0908a07 100644 --- a/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer.java +++ b/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer.java @@ -7,7 +7,6 @@ import armyc2.c5isr.JavaLineArray.POINT2; import java.awt.*; -import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; @@ -323,6 +322,112 @@ else if(AM.size()==2) tg.set_AN(strAN); } } + if (lineType == TacticalLines.BS_CAKE) { + ArrayList AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE); + ArrayList AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH); + if (AM != null) { + StringBuilder strAM = new StringBuilder(); + for (j = 0; j < AM.size(); j++) { + strAM.append(AM.get(j).toString()); + if (j < AM.size() - 1) { + strAM.append(","); + } + } + tg.set_AM(strAM.toString()); + } + if (AN != null) { + StringBuilder strAN = new StringBuilder(); + for (j = 0; j < AN.size(); j++) { + strAN.append(AN.get(j)); + if (j < AN.size() - 1) { + strAN.append(","); + } + } + tg.set_AN(strAN.toString()); + } + if (AM != null && AN != null) { + int numSectors = AN.size() / 2; + double left = 0; + double right = 0; + double min = 0; + double max = 0; + //construct left,right,min,max from the arraylists + StringBuilder strLeftRightMinMax = new StringBuilder(); + for (j = 0; j < numSectors; j++) { + left = AN.get(2 * j); + right = AN.get(2 * j + 1); + min = AM.get(2 * j); + max = AM.get(2 * j + 1); + strLeftRightMinMax.append(left).append(",").append(right).append(",").append(min).append(",").append(max); + if (j < numSectors - 1) { + strLeftRightMinMax.append(","); + } + + } + int len = strLeftRightMinMax.length(); + String c = strLeftRightMinMax.substring(len - 1, len); + if (c.equals(",")) { + strLeftRightMinMax = new StringBuilder(strLeftRightMinMax.substring(0, len - 1)); + } + tg.set_LRMM(strLeftRightMinMax.toString()); + } + } + if (lineType == TacticalLines.BS_RADARC) { + ArrayList AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE); + ArrayList AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH); + if (AM != null) { + StringBuilder strAM = new StringBuilder(); + for (j = 0; j < AM.size() && j < 2; j++) { + strAM.append(AM.get(j).toString()); + if (j < AM.size() - 1) { + strAM.append(","); + } + } + tg.set_AM(strAM.toString()); + } + if (AN != null) { + StringBuilder strAN = new StringBuilder(); + for (j = 0; j < AN.size() && j < 2; j++) { + strAN.append(AN.get(j)); + if (j < AN.size() - 1) { + strAN.append(","); + } + } + tg.set_AN(strAN.toString()); + } + if (AM != null && AN != null) { + double left = 0; + double right = 0; + double min = 0; + double max = 0; + //construct left,right,min,max from the arraylists + String strLeftRightMinMax = ""; + left = AN.get(0); + right = AN.get(1); + min = AM.get(0); + max = AM.get(1); + strLeftRightMinMax += left + "," + right + "," + min + "," + max; + tg.set_LRMM(strLeftRightMinMax); + } + } + if (lineType == TacticalLines.BS_POLYARC) { + ArrayList AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE); + ArrayList AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH); + if (AM != null && AM.size() > 0) { + String strAM = AM.get(0).toString(); + tg.set_AM(strAM); + } + if (AN != null) { + StringBuilder strAN = new StringBuilder(); + for (j = 0; j < AN.size() && j < 2; j++) { + strAN.append(AN.get(j)); + if (j < AN.size() - 1) { + strAN.append(","); + } + } + tg.set_AN(strAN.toString()); + } + } switch (lineType) { case TacticalLines.BBS_AREA: case TacticalLines.BBS_LINE: @@ -338,6 +443,9 @@ else if(AM.size()==2) switch (lineType) { case TacticalLines.PBS_CIRCLE: case TacticalLines.BBS_POINT: + case TacticalLines.BS_ROUTE: + case TacticalLines.BS_TRACK: + case TacticalLines.BS_ORBIT: ArrayList AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE); if (AM != null && AM.size() > 0) { String strAM = Double.toString(AM.get(0)); @@ -352,6 +460,19 @@ else if(AM.size()==2) default: break; } + if (lineType == TacticalLines.BS_TRACK) { + ArrayList AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE); + if (AM != null) { + StringBuilder strAM = new StringBuilder(); + for (j = 0; j < AM.size(); j++) { + strAM.append(AM.get(j).toString()); + if (j < AM.size() - 1) { + strAM.append(","); + } + } + tg.set_AM(strAM.toString()); + } + } if (lineType == TacticalLines.PBS_RECTANGLE || lineType == TacticalLines.PBS_SQUARE) { ArrayList AM = milStd.getModifiers_AM_AN_X(Modifiers.AM_DISTANCE); ArrayList AN = milStd.getModifiers_AM_AN_X(Modifiers.AN_AZIMUTH); @@ -2068,11 +2189,11 @@ public static int getCMLineType(int version, int entityCode) { case 310800: return TacticalLines.CSA; case 330500: - return TacticalLines.ROUTE; + return TacticalLines.TRAFFIC_ROUTE; case 330501: - return TacticalLines.ROUTE_ONEWAY; + return TacticalLines.TRAFFIC_ROUTE_ONEWAY; case 330502: - return TacticalLines.ROUTE_ALT; + return TacticalLines.TRAFFIC_ROUTE_ALT; case 344100: return TacticalLines.FPOL; case 344200: diff --git a/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer2.java b/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer2.java index eb0fc47..0993edd 100644 --- a/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer2.java +++ b/src/main/java/armyc2/c5isr/RenderMultipoints/clsRenderer2.java @@ -45,7 +45,7 @@ private static void getMSRShapes(TGLight tg, try { int linetype=tg.get_LineType(); - if(linetype != TacticalLines.MSR && linetype != TacticalLines.ASR && linetype != TacticalLines.ROUTE) + if(linetype != TacticalLines.MSR && linetype != TacticalLines.ASR && linetype != TacticalLines.TRAFFIC_ROUTE) return; HashMap hmap= clsUtility.getMSRSegmentColors(tg); @@ -297,7 +297,7 @@ else if(bolMeTOC>0) if (CELineArray.CIsChannel(lineType) == 0) { - if(lineType==TacticalLines.ASR || lineType==TacticalLines.MSR || lineType==TacticalLines.ROUTE) + if(lineType==TacticalLines.ASR || lineType==TacticalLines.MSR || lineType==TacticalLines.TRAFFIC_ROUTE) { getMSRShapes(tg,shapes); } @@ -314,7 +314,7 @@ else if(bolMeTOC>0) //set CELineArray.shapes properties if(bolMeTOC<=0) { - if(lineType!=TacticalLines.ASR && lineType!=TacticalLines.MSR && lineType!=TacticalLines.ROUTE) + if(lineType!=TacticalLines.ASR && lineType!=TacticalLines.MSR && lineType!=TacticalLines.TRAFFIC_ROUTE) clsUtility.SetShapeProperties(tg,shapes,bi); } diff --git a/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtility.java b/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtility.java index 152b594..2df5182 100644 --- a/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtility.java +++ b/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtility.java @@ -460,9 +460,9 @@ protected static boolean addModifiersBeforeClipping(TGLight tg) case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: case TacticalLines.HCONVOY: case TacticalLines.CONVOY: case TacticalLines.MFP: @@ -911,7 +911,7 @@ protected static void RemoveDuplicatePoints(TGLight tg) case TacticalLines.BOUNDARY: case TacticalLines.MSR: case TacticalLines.ASR: - case TacticalLines.ROUTE: + case TacticalLines.TRAFFIC_ROUTE: String strH=tg.get_H(); if(strH != null && !strH.isEmpty()) { diff --git a/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityCPOF.java b/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityCPOF.java index c756539..8f35df0 100644 --- a/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityCPOF.java +++ b/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityCPOF.java @@ -14,7 +14,8 @@ import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.util.ArrayList; +import java.util.*; + import armyc2.c5isr.JavaLineArray.Shape2; import armyc2.c5isr.renderer.utilities.ErrorLogger; import armyc2.c5isr.renderer.utilities.RendererException; @@ -23,9 +24,6 @@ import armyc2.c5isr.JavaTacticalRenderer.clsMETOC; import armyc2.c5isr.renderer.utilities.SymbolUtilities; -import java.util.Map; -import java.util.HashMap; - /** * CPOF utility functions taken from JavaLineArrayCPOF * @@ -85,7 +83,7 @@ private static void GetNumericFields(TGLight tg, POINT2 pt1 = new POINT2(0, 0); radius.value = new double[1]; width.value = new double[1]; - attitude.value = new double[1]; + attitude.value = new double[2]; length.value = new double[1]; switch (lineType) { case TacticalLines.CIRCULAR: @@ -191,6 +189,7 @@ private static void GetNumericFields(TGLight tg, case TacticalLines.KILLBOXBLUE_RECTANGULAR: case TacticalLines.KILLBOXPURPLE_RECTANGULAR: case TacticalLines.RECTANGULAR_TARGET: + case TacticalLines.BS_ORBIT: if (tg.LatLongs.size() >= 2) { //get the length and the attitude in mils pt0 = tg.LatLongs.get(0); @@ -202,6 +201,14 @@ private static void GetNumericFields(TGLight tg, width.value[0] = Double.parseDouble(tg.get_AM()); } break; + case TacticalLines.BS_POLYARC: + if (SymbolUtilities.isNumber(tg.get_AM())) { + length.value[0] = Double.parseDouble(tg.get_AM()); + } + String[] an = tg.get_AN().split(","); + attitude.value[0] = Double.parseDouble(an[0]); + attitude.value[1] = Double.parseDouble(an[1]); + break; default: break; } @@ -376,6 +383,139 @@ protected static boolean Change1TacticalAreas(TGLight tg, tg.Pixels.add(pt00); break; + case TacticalLines.BS_ORBIT: + ptTemp = mdlGeodesic.geodesic_coordinate(pt0, width.value[0] / 2, attitude.value[0] - 90); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + + ptTemp = mdlGeodesic.geodesic_coordinate(pt1, width.value[0] / 2, attitude.value[0] - 90); + pPoints = new POINT2[3]; + pPoints[0] = new POINT2(pt1); + pPoints[1] = new POINT2(ptTemp); + pPoints[2] = new POINT2(ptTemp); + ArrayList pPoints2 = mdlGeodesic.GetGeodesicArc(pPoints); + for (j = 0; j < pPoints2.size() / 2; j++) { + ptTemp = clsUtilityCPOF.PointLatLongToPixels(pPoints2.get(j), converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + } + + ptTemp = mdlGeodesic.geodesic_coordinate(pt0, width.value[0] / 2, attitude.value[0] + 90); + pPoints[0] = new POINT2(pt0); + pPoints[1] = new POINT2(ptTemp); + pPoints[2] = new POINT2(ptTemp); + pPoints2 = mdlGeodesic.GetGeodesicArc(pPoints); + for (j = 0; j < pPoints2.size() / 2; j++) { + ptTemp = clsUtilityCPOF.PointLatLongToPixels(pPoints2.get(j), converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + } + break; + case TacticalLines.BS_ROUTE: + ArrayList am = new ArrayList<>(Arrays.asList(tg.get_AM().split(","))); + while (am.size() < tg.LatLongs.size() - 1) { + am.add(am.get(am.size() - 1)); + } + for (int i = 0; i < tg.LatLongs.size() - 1; i++) { + ref a12 = new ref(); + ref a21 = new ref(); + pt0 = tg.LatLongs.get(i); + pt1 = tg.LatLongs.get(i + 1); + double widthVal = 0; + double attitudeVal = 0; + + mdlGeodesic.geodesic_distance(pt0, pt1, a12, a21); + attitudeVal = a12.value[0]; + + if (SymbolUtilities.isNumber(am.get(i))) { + widthVal = Double.parseDouble(am.get(i)); + } + + //get the upper left corner + pt00 = mdlGeodesic.geodesic_coordinate(pt0, widthVal / 2, attitudeVal - 90); + pt00 = clsUtilityCPOF.PointLatLongToPixels(pt00, converter); + + pt00.style = 0; + tg.Pixels.add(pt00); + + //second corner (clockwise from center) + ptTemp = mdlGeodesic.geodesic_coordinate(pt0, widthVal / 2, attitudeVal + 90); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + + //third corner (clockwise from center) + ptTemp = mdlGeodesic.geodesic_coordinate(pt1, widthVal / 2, attitudeVal + 90); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + + //fourth corner (clockwise from center) + ptTemp = mdlGeodesic.geodesic_coordinate(pt1, widthVal / 2, attitudeVal - 90); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + + pt00 = new POINT2(pt00); + pt00.style = 5; + tg.Pixels.add(pt00); + } + break; + case TacticalLines.BS_TRACK: + am = new ArrayList<>(Arrays.asList(tg.get_AM().split(","))); + while (am.size() < tg.LatLongs.size() - 1) { + am.add(am.get(am.size() - 1)); + } + for (int i = 0; i < tg.LatLongs.size() - 1; i++) { + ref a12 = new ref(); + ref a21 = new ref(); + pt0 = tg.LatLongs.get(i); + pt1 = tg.LatLongs.get(i + 1); + double leftWidth = 0; + double rightWidth = 0; + double attitudeVal = 0; + + mdlGeodesic.geodesic_distance(pt0, pt1, a12, a21); + attitudeVal = a12.value[0]; + + if (SymbolUtilities.isNumber(am.get(2 * i))) { + leftWidth = Double.parseDouble(am.get(2 * i)); + } + if (SymbolUtilities.isNumber(am.get(2 * i + 1))) { + rightWidth = Double.parseDouble(am.get(2 * i + 1)); + } + + //get the upper left corner + pt00 = mdlGeodesic.geodesic_coordinate(pt0, leftWidth, attitudeVal - 90); + pt00 = clsUtilityCPOF.PointLatLongToPixels(pt00, converter); + + pt00.style = 0; + tg.Pixels.add(pt00); + + //second corner (clockwise from center) + ptTemp = mdlGeodesic.geodesic_coordinate(pt0, rightWidth, attitudeVal + 90); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + + //third corner (clockwise from center) + ptTemp = mdlGeodesic.geodesic_coordinate(pt1, rightWidth, attitudeVal + 90); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + + //fourth corner (clockwise from center) + ptTemp = mdlGeodesic.geodesic_coordinate(pt1, leftWidth, attitudeVal - 90); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + ptTemp.style = 0; + tg.Pixels.add(ptTemp); + + pt00 = new POINT2(pt00); + pt00.style = 5; + tg.Pixels.add(pt00); + } + break; case TacticalLines.RECTANGULAR_TARGET: POINT2[] pts = new POINT2[4]; // 4 Corners @@ -506,7 +646,7 @@ protected static boolean Change1TacticalAreas(TGLight tg, pPoints[1] = new POINT2(ptTemp); pPoints[2] = new POINT2(ptTemp); - ArrayList pPoints2 = mdlGeodesic.GetGeodesicArc(pPoints); + pPoints2 = mdlGeodesic.GetGeodesicArc(pPoints); POINT2 ptTemp2 = null; //fill pixels and latlongs for (j = 0; j < pPoints2.size(); j++) //was 103 @@ -532,11 +672,42 @@ protected static boolean Change1TacticalAreas(TGLight tg, RangeFanOrientation(tg, lineType, converter); break; case TacticalLines.RADAR_SEARCH: + case TacticalLines.BS_RADARC: + case TacticalLines.BS_CAKE: GetSectorRangeFan(tg, converter); break; case TacticalLines.RANGE_FAN_FILL: //circular range fan calls Change1TacticalAreas twice GetSectorRangeFan(tg, converter); break; + case TacticalLines.BS_POLYARC: + // Polyarc points should be counterclockwise + if (clsUtilityCPOF.CalculateSignedAreaOfPolygon(tg.LatLongs) < 0) { + ptTemp = tg.LatLongs.remove(0); + Collections.reverse(tg.LatLongs); + tg.LatLongs.add(0, ptTemp); + } + + ArrayList pPointsArc = new ArrayList(); + pPoints2 = new ArrayList(); + pPoints2.add(pt0); + pPoints2.add(mdlGeodesic.geodesic_coordinate(pt0, length.value[0], attitude.value[0])); + pPoints2.add(mdlGeodesic.geodesic_coordinate(pt0, length.value[0], attitude.value[1])); + mdlGeodesic.GetGeodesicArc2(pPoints2, pPointsArc); + + for (int i = 0; i < pPointsArc.size(); i++) { + ptTemp = new POINT2(pPointsArc.get(i)); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + tg.Pixels.add(ptTemp); + } + + for (int i = 1; i < tg.LatLongs.size(); i++) { + ptTemp = new POINT2(tg.LatLongs.get(i)); + ptTemp = clsUtilityCPOF.PointLatLongToPixels(ptTemp, converter); + tg.Pixels.add(ptTemp); + } + + tg.Pixels.add(tg.Pixels.get(0)); + break; default: return false; } @@ -664,7 +835,7 @@ else if(fill) if (currentPt.style == 5 || currentPt.style == 10) { beginLine = true; //unless there are doubled points with style=5 - if (linetype == TacticalLines.RANGE_FAN_FILL && k < tg.Pixels.size() - 1) { + if ((linetype == TacticalLines.RANGE_FAN_FILL || linetype == TacticalLines.BS_ROUTE || linetype == TacticalLines.BS_TRACK || linetype == TacticalLines.BS_CAKE) && k < tg.Pixels.size() - 1) { shapes.add(shape); shape = new Shape2(Shape2.SHAPE_TYPE_POLYLINE); } @@ -1436,8 +1607,8 @@ public static Boolean canClipPoints(TGLight tg) { case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: case TacticalLines.DHA_REVD: case TacticalLines.DHA: case TacticalLines.KILL_ZONE: @@ -1452,7 +1623,7 @@ public static Boolean canClipPoints(TGLight tg) { return true; case TacticalLines.MSR: //post clip these so there are identical points regardless whether segment data is set 10-5-16 case TacticalLines.ASR: - case TacticalLines.ROUTE: + case TacticalLines.TRAFFIC_ROUTE: case TacticalLines.BOUNDARY: return false; default: @@ -1559,9 +1730,9 @@ protected static boolean LinesWithSeparateFill(int linetype, ArrayList s case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: //undo any fill Shape2 shape = null; if (shapes != null && shapes.size() > 0) { @@ -1965,8 +2136,8 @@ private static boolean segmentAnticipatedLine(TGLight tg) { case TacticalLines.ASR_ONEWAY: case TacticalLines.ASR_TWOWAY: case TacticalLines.ASR_ALT: - case TacticalLines.ROUTE_ONEWAY: - case TacticalLines.ROUTE_ALT: + case TacticalLines.TRAFFIC_ROUTE_ONEWAY: + case TacticalLines.TRAFFIC_ROUTE_ALT: //added because of segment data 4-22-13 //removed from this case block since we now post-clip these because of segment color data 10-5-16 // case TacticalLines.MSR: @@ -2406,4 +2577,21 @@ protected static void SegmentGeoPoints(TGLight tg, } } + /** + * Calculating the signed area will tell you which direction the points are going. + * Negative = Clock-wise, Positive = counter clock-wise + * A = 1/2 * (x1*y2 - x2*y1 + x2*y3 - x3*y2 + ... + xn*y1 - x1*yn) + */ + static double CalculateSignedAreaOfPolygon(ArrayList coords) { + double signedArea = 0; + final int len = coords.size(); + for (int i = 0; i < len; i++) { + double x1 = coords.get(i).x; + double y1 = coords.get(i).y; + double x2 = coords.get((i + 1) % len).x; + double y2 = coords.get((i + 1) % len).y; + signedArea += (x1 * y2 - x2 * y1); + } + return signedArea / 2; + } } diff --git a/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityGE.java b/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityGE.java index 3a6b997..77e3071 100644 --- a/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityGE.java +++ b/src/main/java/armyc2/c5isr/RenderMultipoints/clsUtilityGE.java @@ -1134,7 +1134,7 @@ protected static boolean segmentColorsSet(TGLight tg) case TacticalLines.BOUNDARY: case TacticalLines.MSR: case TacticalLines.ASR: - case TacticalLines.ROUTE: + case TacticalLines.TRAFFIC_ROUTE: break; default: return false; diff --git a/src/main/java/armyc2/c5isr/renderer/utilities/SymbolUtilities.java b/src/main/java/armyc2/c5isr/renderer/utilities/SymbolUtilities.java index 1687bd2..409e0a2 100644 --- a/src/main/java/armyc2/c5isr/renderer/utilities/SymbolUtilities.java +++ b/src/main/java/armyc2/c5isr/renderer/utilities/SymbolUtilities.java @@ -1810,6 +1810,12 @@ public static boolean isBasicShape(int linetype) { case TacticalLines.BBS_POINT: case TacticalLines.BBS_RECTANGLE: case TacticalLines.BS_BBOX: + case TacticalLines.BS_ROUTE: + case TacticalLines.BS_TRACK: + case TacticalLines.BS_RADARC: + case TacticalLines.BS_CAKE: + case TacticalLines.BS_ORBIT: + case TacticalLines.BS_POLYARC: return true; default: return false; diff --git a/src/main/java/armyc2/c5isr/web/render/MultiPointHandler.java b/src/main/java/armyc2/c5isr/web/render/MultiPointHandler.java index d214057..b5a83c4 100644 --- a/src/main/java/armyc2/c5isr/web/render/MultiPointHandler.java +++ b/src/main/java/armyc2/c5isr/web/render/MultiPointHandler.java @@ -180,7 +180,7 @@ private static Point2D getControlPoint(ArrayList geoCoords) { * @return the upper left corner of the MBR containing the geographic * coordinates */ - private static Point2D getGeoUL(ArrayList geoCoords) { + static Point2D getGeoUL(ArrayList geoCoords) { Point2D ptGeo = null; try { int j = 0; @@ -229,7 +229,7 @@ private static Point2D getGeoUL(ArrayList geoCoords) { } return ptGeo; } - private static String getBboxFromCoords(ArrayList geoCoords) { + static String getBboxFromCoords(ArrayList geoCoords) { //var ptGeo = null; String bbox = null; try { @@ -282,7 +282,7 @@ private static String getBboxFromCoords(ArrayList geoCoords) { return bbox; } - private static boolean crossesIDL(ArrayList geoCoords) { + static boolean crossesIDL(ArrayList geoCoords) { boolean result = false; Point2D pt2d = getControlPoint(geoCoords); double left = pt2d.getX(); @@ -422,7 +422,7 @@ public static Boolean ShouldClipSymbol(String symbolID) { * @param origScale * @return */ - private static double getReasonableScale(String bbox, double origScale) { + static double getReasonableScale(String bbox, double origScale) { try { String[] bounds = bbox.split(","); double left = Double.valueOf(bounds[0]); @@ -721,7 +721,7 @@ public static String RenderSymbol(String id, if(textColor==null) textColor=mSymbol.getLineColor(); - jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor); + jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, mSymbol.get_WasClipped()); jsonOutput.append(jsonContent); } else if (format == WebRenderer.OUTPUT_FORMAT_GEOJSON) { @@ -1303,7 +1303,7 @@ public static String RenderSymbol2D(String id, if(textColor==null) textColor=mSymbol.getLineColor(); - jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor); + jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, mSymbol.get_WasClipped()); jsonOutput.append(jsonContent); } else if (format == WebRenderer.OUTPUT_FORMAT_GEOJSON) { jsonOutput.append("{\"type\":\"FeatureCollection\",\"features\":"); @@ -1550,7 +1550,7 @@ private static SymbolInfo MilStdSymbolToSymbolInfo(MilStdSymbol symbol) { * @param symbol An existing MilStdSymbol * @return */ - private static boolean populateModifiers(Map saModifiers, Map saAttributes, MilStdSymbol symbol) { + static boolean populateModifiers(Map saModifiers, Map saAttributes, MilStdSymbol symbol) { Map modifiers = new HashMap<>(); Map attributes = saAttributes; @@ -1814,28 +1814,29 @@ else if(symbol.getLineColor()==null) } - private static String KMLize(String id, String name, - String description, - String symbolCode, - ArrayList shapes, - ArrayList modifiers, - IPointConversion ipc, - boolean normalize, Color textColor) { - + private static String KMLize(String id, + String name, + String description, + String symbolCode, + ArrayList shapes, + ArrayList modifiers, + IPointConversion ipc, + boolean normalize, + Color textColor, + boolean wasClipped) { java.lang.StringBuilder kml = new java.lang.StringBuilder(); - ShapeInfo tempModifier = null; - - String cdataStart = ""; - int len = shapes.size(); - kml.append(""); - kml.append("" + cdataStart + name + cdataEnd + ""); + kml.append(""); + kml.append("").append(name).append(""); kml.append("1"); + kml.append("").append(description).append(""); + kml.append(""); + kml.append("").append(symbolCode).append(""); + kml.append("").append(wasClipped).append(""); + kml.append(""); for (int i = 0; i < len; i++) { - - String shapesToAdd = ShapeToKMLString(name, description, symbolCode, shapes.get(i), ipc, normalize); + String shapesToAdd = ShapeToKMLString(shapes.get(i), ipc, normalize); kml.append(shapesToAdd); } @@ -1920,7 +1921,7 @@ private static String JSONize(ArrayList shapes, ArrayList return jstr; } - private static Color getIdealTextBackgroundColor(Color fgColor) { + static Color getIdealTextBackgroundColor(Color fgColor) { //ErrorLogger.LogMessage("SymbolDraw","getIdealtextBGColor", "in function", Level.SEVERE); try { //an array of three elements containing the @@ -2258,7 +2259,7 @@ private static String ImageToGeoJSONString(ShapeInfo shapeInfo, IPointConversion return JSONed.toString(); } - private static String bitmapToString(BufferedImage bitmap) { + static String bitmapToString(BufferedImage bitmap) { /*final int COMPRESSION_QUALITY = 100; String encodedImage; ByteArrayOutputStream byteArrayBitmapStream = new ByteArrayOutputStream(); @@ -2366,6 +2367,9 @@ private static Boolean normalizePoints(ArrayList shape, IPointCo return normalize; } + /** + * @deprecated + */ private static Boolean IsOnePointSymbolCode(String symbolCode) { String basicCode = SymbolUtilities.getBasicSymbolID(symbolCode); //TODO: Revisit for basic shapes @@ -2381,33 +2385,18 @@ private static Boolean IsOnePointSymbolCode(String symbolCode) { return false; } - private static String ShapeToKMLString(String name, - String description, - String symbolCode, - ShapeInfo shapeInfo, - IPointConversion ipc, - boolean normalize) { - + private static String ShapeToKMLString(ShapeInfo shapeInfo, + IPointConversion ipc, + boolean normalize) { java.lang.StringBuilder kml = new java.lang.StringBuilder(); - Color lineColor = null; Color fillColor = null; String googleLineColor = null; String googleFillColor = null; - - //String lineStyleId = "lineColor"; - BasicStroke stroke = null; int lineWidth = 4; - symbolCode = JavaRendererUtilities.normalizeSymbolCode(symbolCode); - - String cdataStart = ""; - - kml.append("");//(""); - kml.append("" + cdataStart + "" + name + "
" + "\n" + description + cdataEnd + "
"); - //kml.append(""); + + ArrayList> shapesArray = shapeInfo.getPolylines3D(); + int len = shapesArray.size(); + kml.append(""); + + for (int i = 0; i < len; i++) { + ArrayList shape = shapesArray.get(i); + normalize = normalizePoints(shape, ipc); + if (lineColor != null && fillColor == null) { + kml.append(""); + kml.append("1"); + kml.append("").append(altitudeMode).append(""); + kml.append(""); + int n = shape.size(); + //for (int j = 0; j < shape.size(); j++) + for (int j = 0; j < n; j++) { + Point3D coord = shape.get(j); + Point2D geoCoord = ipc.PixelsToGeo(coord); + if (normalize) { + geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); + } + + double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; + double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; + double altitude = coord.getZ(); + + kml.append(longitude); + kml.append(","); + kml.append(latitude); + kml.append(","); + kml.append(altitude); + if (j < shape.size() - 1) kml.append(" "); + } + + kml.append(""); + kml.append(""); + } + + if (fillColor != null) { + + if (i == 0) { + kml.append(""); + kml.append("1"); + kml.append("").append(altitudeMode).append(""); + } + //kml.append(""); + if (i == 1 && len > 1) { + kml.append(""); + } else { + kml.append(""); + } + kml.append(""); + kml.append(""); + + int n = shape.size(); + //for (int j = 0; j < shape.size(); j++) + for (int j = 0; j < n; j++) { + Point3D coord = shape.get(j); + Point2D geoCoord = ipc.PixelsToGeo(coord); + + double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; + double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; + double altitude = coord.getZ(); + + //fix for fill crossing DTL + if (normalize) { + if (longitude > 0) { + longitude -= 360; + } + } + + kml.append(longitude); + kml.append(","); + kml.append(latitude); + kml.append(","); + kml.append(altitude); + if (j < shape.size() - 1) kml.append(" "); + } + + kml.append(""); + kml.append(""); + if (i == 1 && len > 1) { + kml.append(""); + } else { + kml.append(""); + } + if (i == len - 1) { + kml.append(""); + } + } + } + + kml.append(""); + kml.append("
"); + + return kml.toString(); + } + + private static String LabelToKMLString(ShapeInfo3D shapeInfo, + IPointConversion ipc, + boolean normalize, + Color textColor, + String altitudeMode) { + java.lang.StringBuilder kml = new java.lang.StringBuilder(); + + //Point2D coord = (Point2D) new Point2D.Double(shapeInfo.getGlyphPosition().getX(), shapeInfo.getGlyphPosition().getY()); + Point3D coord = new Point3D(shapeInfo.getModifierPosition().getX(), shapeInfo.getModifierPosition().getY(), shapeInfo.getModifierPosition().getZ()); + Point2D geoCoord = ipc.PixelsToGeo(coord); + //M. Deutch 9-26-11 + if (normalize) { + geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); + } + double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; + double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; + double altitude = coord.getZ(); + long angle = Math.round(shapeInfo.getModifierAngle()); + + String text = shapeInfo.getModifierString(); + + String cdataStart = ""; + + String color = Integer.toHexString(textColor.getRGB()); + color = JavaRendererUtilities.ARGBtoABGR(color); + float kmlScale = RendererSettings.getInstance().getKMLLabelScale(); + + if (kmlScale > 0 && text != null && text.equals("") == false) { + kml.append("");//(""); + kml.append("").append(cdataStart).append(text).append(cdataEnd).append(""); + kml.append(""); + kml.append(""); + kml.append("0"); + kml.append("").append(altitudeMode).append(""); + kml.append(""); + kml.append(longitude); + kml.append(","); + kml.append(latitude); + kml.append(","); + kml.append(altitude); + kml.append(""); + kml.append(""); + kml.append(""); + } else { + return ""; + } + + return kml.toString(); + } + + + private static String GeoJSONize(ArrayList shapes, + ArrayList modifiers, + IPointConversion ipc, + boolean normalize, + Color textColor, + Color textBackgroundColor) { + + ShapeInfo3D tempModifier = null; + StringBuilder fc = new StringBuilder();//JSON feature collection + + fc.append("["); + + int len = shapes.size(); + for (int i = 0; i < len; i++) { + + String shapesToAdd = ShapeToGeoJSONString(shapes.get(i), ipc, normalize); + if (shapesToAdd.length() > 0) { + fc.append(shapesToAdd); + if (i < len - 1) { + fc.append(","); + } + } + } + + int len2 = modifiers.size(); + + for (int j = 0; j < len2; j++) { + tempModifier = modifiers.get(j); + + String modifiersToAdd = null; + if (modifiers.get(j).getModifierImage() != null) { + modifiersToAdd = ImageToGeoJSONString(tempModifier, ipc, normalize); + } else { + modifiersToAdd = LabelToGeoJSONString(tempModifier, ipc, normalize, textColor, textBackgroundColor); + } + if (modifiersToAdd.length() > 0) { + if (fc.length() > 1) fc.append(","); + fc.append(modifiersToAdd); + } + } + fc.append("]"); + String GeoJSON = fc.toString(); + return GeoJSON; + } + + private static String ShapeToGeoJSONString(ShapeInfo3D shapeInfo, IPointConversion ipc, boolean normalize) { + StringBuilder JSONed = new StringBuilder(); + StringBuilder properties = new StringBuilder(); + StringBuilder geometry = new StringBuilder(); + String geometryType = null; + String sda = null; + /* + NOTE: Google Earth / KML colors are backwards. + They are ordered Alpha,Blue,Green,Red, not Red,Green,Blue,Aplha like the rest of the world + * */ + Color lineColor = shapeInfo.getLineColor(); + Color fillColor = shapeInfo.getFillColor(); + + if (shapeInfo.getShapeType() == ShapeInfo.SHAPE_TYPE_FILL || fillColor != null || shapeInfo.getPatternFillImage() != null) { + geometryType = "\"Polygon\""; + } else //if(shapeInfo.getShapeType() == ShapeInfo.SHAPE_TYPE_POLYLINE) + { + geometryType = "\"MultiLineString\""; + } + + BasicStroke stroke = null; + stroke = shapeInfo.getStroke(); + int lineWidth = 4; + + if (stroke != null) { + lineWidth = (int) stroke.getLineWidth(); + } + + //generate JSON properties for feature + properties.append("\"properties\":{"); + properties.append("\"label\":\"\","); + if (lineColor != null) { + properties.append("\"strokeColor\":\"").append(RendererUtilities.colorToHexString(lineColor, false)).append("\","); + properties.append("\"lineOpacity\":").append(String.valueOf(lineColor.getAlpha() / 255f)).append(","); + } + if (fillColor != null) { + properties.append("\"fillColor\":\"").append(RendererUtilities.colorToHexString(fillColor, false)).append("\","); + properties.append("\"fillOpacity\":").append(String.valueOf(fillColor.getAlpha() / 255f)).append(","); + } + if (shapeInfo.getPatternFillImage() != null) { + properties.append("\"fillPattern\":\"").append(MultiPointHandler.bitmapToString(shapeInfo.getPatternFillImage())).append("\","); + } + if (stroke.getDashArray() != null) { + sda = "\"strokeDasharray\":" + Arrays.toString(stroke.getDashArray()) + ","; + properties.append(sda); + } + + int lineCap = stroke.getEndCap(); + properties.append("\"lineCap\":").append(lineCap).append(","); + + String strokeWidth = String.valueOf(lineWidth); + properties.append("\"strokeWidth\":").append(strokeWidth).append(","); + properties.append("\"strokeWeight\":").append(strokeWidth); + properties.append("},"); + + + properties.append("\"style\":{"); + if (lineColor != null) { + properties.append("\"stroke\":\"").append(RendererUtilities.colorToHexString(lineColor, false)).append("\","); + properties.append("\"line-opacity\":").append(String.valueOf(lineColor.getAlpha() / 255f)).append(","); + } + if (fillColor != null) { + properties.append("\"fill\":\"").append(RendererUtilities.colorToHexString(fillColor, false)).append("\","); + properties.append("\"fill-opacity\":").append(String.valueOf(fillColor.getAlpha() / 255f)).append(","); + } + if (stroke.getDashArray() != null) { + float[] da = stroke.getDashArray(); + sda = String.valueOf(da[0]); + if (da.length > 1) { + for (int i = 1; i < da.length; i++) { + sda = sda + " " + String.valueOf(da[i]); + } + } + sda = "\"stroke-dasharray\":\"" + sda + "\","; + properties.append(sda); + sda = null; + } + + if (lineCap == BasicStroke.CAP_SQUARE) properties.append("\"stroke-linecap\":\"square\","); + else if (lineCap == BasicStroke.CAP_ROUND) + properties.append("\"stroke-linecap\":\"round\","); + else if (lineCap == BasicStroke.CAP_BUTT) properties.append("\"stroke-linecap\":\"butt\","); + + strokeWidth = String.valueOf(lineWidth); + properties.append("\"stroke-width\":").append(strokeWidth); + properties.append("}"); + + + //generate JSON geometry for feature + geometry.append("\"geometry\":{\"type\":"); + geometry.append(geometryType); + geometry.append(",\"coordinates\":["); + + ArrayList> shapesArray = shapeInfo.getPolylines3D(); + + for (int i = 0; i < shapesArray.size(); i++) { + ArrayList pointList = shapesArray.get(i); + + normalize = normalizePoints(pointList, ipc); + + geometry.append("["); + + //System.out.println("Pixel Coords:"); + for (int j = 0; j < pointList.size(); j++) { + Point3D coord = pointList.get(j); + Point2D geoCoord = ipc.PixelsToGeo(coord); + //M. Deutch 9-27-11 + if (normalize) { + geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); + } + double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; + double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; + double altitude = coord.getZ(); + + //fix for fill crossing DTL + if (normalize && fillColor != null) { + if (longitude > 0) { + longitude -= 360; + } + } + + //diagnostic M. Deutch 10-18-11 + //set the point as geo so that the + //coord.setLocation(longitude, latitude); + coord = new Point3D(longitude, latitude, altitude); + pointList.set(j, coord); + //end section + + geometry.append("["); + geometry.append(longitude); + geometry.append(","); + geometry.append(latitude); + geometry.append(","); + geometry.append(altitude); + geometry.append("]"); + + if (j < (pointList.size() - 1)) { + geometry.append(","); + } + } + + geometry.append("]"); + + if (i < (shapesArray.size() - 1)) { + geometry.append(","); + } + } + geometry.append("]}"); + + JSONed.append("{\"type\":\"Feature\","); + JSONed.append(properties.toString()); + JSONed.append(","); + JSONed.append(geometry.toString()); + JSONed.append("}"); + + return JSONed.toString(); + } + + private static String ImageToGeoJSONString(ShapeInfo3D shapeInfo, IPointConversion ipc, boolean normalize) { + StringBuilder JSONed = new StringBuilder(); + + //AffineTransform at = shapeInfo.getAffineTransform(); + //Point2D coord = (Point2D)new Point2D.Double(at.getTranslateX(), at.getTranslateY()); + //Point2D coord = (Point2D) new Point2D.Double(shapeInfo.getGlyphPosition().getX(), shapeInfo.getGlyphPosition().getY()); + Point3D coord = new Point3D(shapeInfo.getModifierPosition().getX(), shapeInfo.getModifierPosition().getY(), shapeInfo.getModifierPosition().getZ()); + Point2D geoCoord = ipc.PixelsToGeo(coord); + //M. Deutch 9-27-11 + if (normalize) { + geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); + } + double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; + double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; + double altitude = coord.getZ(); + double angle = shapeInfo.getModifierAngle(); + coord.setLocation(longitude, latitude); + + //diagnostic M. Deutch 10-18-11 + shapeInfo.setGlyphPosition(coord); + + BufferedImage image = shapeInfo.getModifierImage(); + + RendererSettings RS = RendererSettings.getInstance(); + + if (image != null) { + + JSONed.append("{\"type\":\"Feature\",\"properties\":{\"image\":\""); + JSONed.append(MultiPointHandler.bitmapToString(image)); + JSONed.append("\",\"rotation\":"); + JSONed.append(angle); + JSONed.append(",\"angle\":"); + JSONed.append(angle); + JSONed.append("},"); + JSONed.append("\"geometry\":{\"type\":\"Point\",\"coordinates\":["); + JSONed.append(longitude); + JSONed.append(","); + JSONed.append(latitude); + JSONed.append(","); + JSONed.append(altitude); + JSONed.append("]"); + JSONed.append("}}"); + + } else { + return ""; + } + + return JSONed.toString(); + } + + private static String LabelToGeoJSONString(ShapeInfo3D shapeInfo, IPointConversion ipc, boolean normalize, Color textColor, Color textBackgroundColor) { + StringBuilder JSONed = new StringBuilder(); + + Color outlineColor = SymbolDraw.getIdealTextBackgroundColor(textColor); + if (textBackgroundColor != null) { + outlineColor = textBackgroundColor; + } + + //AffineTransform at = shapeInfo.getAffineTransform(); + //Point2D coord = (Point2D)new Point2D.Double(at.getTranslateX(), at.getTranslateY()); + //Point2D coord = (Point2D) new Point2D.Double(shapeInfo.getGlyphPosition().getX(), shapeInfo.getGlyphPosition().getY()); + Point3D coord = new Point3D(shapeInfo.getModifierPosition().getX(), shapeInfo.getModifierPosition().getY(), shapeInfo.getModifierPosition().getZ()); + Point2D geoCoord = ipc.PixelsToGeo(coord); + //M. Deutch 9-27-11 + if (normalize) { + geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); + } + double latitude = Math.round(geoCoord.getY() * 100000000.0) / 100000000.0; + double longitude = Math.round(geoCoord.getX() * 100000000.0) / 100000000.0; + double altitude = coord.getZ(); + double angle = shapeInfo.getModifierAngle(); + coord.setLocation(longitude, latitude); + + //diagnostic M. Deutch 10-18-11 + shapeInfo.setGlyphPosition(coord); + + String text = shapeInfo.getModifierString(); + + int justify = shapeInfo.getTextJustify(); + String strJustify = "left"; + if (justify == 0) strJustify = "left"; + else if (justify == 1) strJustify = "center"; + else if (justify == 2) strJustify = "right"; + + + RendererSettings RS = RendererSettings.getInstance(); + + if (text != null && text.equals("") == false) { + + JSONed.append("{\"type\":\"Feature\",\"properties\":{\"label\":\""); + JSONed.append(text); + JSONed.append("\",\"pointRadius\":0,\"fontColor\":\""); + JSONed.append(RendererUtilities.colorToHexString(textColor, false)); + JSONed.append("\",\"fontSize\":\""); + JSONed.append(String.valueOf(RS.getMPLabelFont().getSize())).append("pt\""); + JSONed.append(",\"fontFamily\":\""); + JSONed.append(RS.getMPLabelFont().getName()); + JSONed.append(", sans-serif"); + + if (RS.getMPLabelFont().getStyle() == Font.BOLD) { + JSONed.append("\",\"fontWeight\":\"bold\""); + } else { + JSONed.append("\",\"fontWeight\":\"normal\""); + } + + //JSONed.append(",\"labelAlign\":\"lm\""); + JSONed.append(",\"labelAlign\":\""); + JSONed.append(strJustify); + JSONed.append("\",\"labelBaseline\":\"alphabetic"); + JSONed.append("\",\"labelXOffset\":0"); + JSONed.append(",\"labelYOffset\":0"); + JSONed.append(",\"labelOutlineColor\":\""); + JSONed.append(RendererUtilities.colorToHexString(outlineColor, false)); + JSONed.append("\",\"labelOutlineWidth\":"); + JSONed.append("4"); + JSONed.append(",\"rotation\":"); + JSONed.append(angle); + JSONed.append(",\"angle\":"); + JSONed.append(angle); + JSONed.append("},"); + + JSONed.append("\"geometry\":{\"type\":\"Point\",\"coordinates\":["); + JSONed.append(longitude); + JSONed.append(","); + JSONed.append(latitude); + JSONed.append(","); + JSONed.append(altitude); + JSONed.append("]"); + JSONed.append("}}"); + + } else { + return ""; + } + + return JSONed.toString(); + } + + /** + * copy of {@link MultiPointHandler#normalizePoints(ArrayList, IPointConversion)} with Point3D + */ + static Boolean normalizePoints(ArrayList shape, IPointConversion ipc) { + ArrayList geoCoords = new ArrayList(); + int n = shape.size(); + //for (int j = 0; j < shape.size(); j++) + for (int j = 0; j < n; j++) { + Point2D coord = shape.get(j); + Point2D geoCoord = ipc.PixelsToGeo(coord); + geoCoord = MultiPointHandler.NormalizeCoordToGECoord(geoCoord); + double latitude = geoCoord.getY(); + double longitude = geoCoord.getX(); + Point2D pt2d = new Point2D.Double(longitude, latitude); + geoCoords.add(pt2d); + } + Boolean normalize = MultiPointHandler.crossesIDL(geoCoords); + return normalize; + } +} diff --git a/src/main/java/armyc2/c5isr/web/render/WebRenderer.java b/src/main/java/armyc2/c5isr/web/render/WebRenderer.java index e9f9fe3..b546fca 100644 --- a/src/main/java/armyc2/c5isr/web/render/WebRenderer.java +++ b/src/main/java/armyc2/c5isr/web/render/WebRenderer.java @@ -5,6 +5,7 @@ import armyc2.c5isr.renderer.utilities.*; +import armyc2.c5isr.web.render.utilities.Basic3DShapes; import armyc2.c5isr.web.render.utilities.JavaRendererUtilities; import java.awt.*; @@ -66,7 +67,7 @@ private static synchronized void init() { /** - * Renders all multi-point symbols, creating KML that can be used to draw + * Renders all multi-point symbols, creating KML, GeoJSON or SVG that can be used to draw * it on a Google map. Multipoint symbols cannot be draw the same * at different scales. For instance, graphics with arrow heads will need to * redraw arrowheads when you zoom in on it. Similarly, graphics like a @@ -101,8 +102,8 @@ private static synchronized void init() { * @param modifiers {@link Map}, keyed using constants from Modifiers. * Pass in comma delimited String for modifiers with multiple values like AM, AN & X * @param attributes {@link Map}, keyed using constants from MilStdAttributes. - * @param format An enumeration: 2 for GeoJSON. - * @return A JSON string representation of the graphic. + * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG} + * @return A KML, GeoJSON or SVG string representation of the graphic. */ public static String RenderSymbol(String id, String name, String description, String symbolCode, String controlPoints, String altitudeMode, @@ -112,36 +113,38 @@ public static String RenderSymbol(String id, String name, String description, JavaRendererUtilities.addAltModeToModifiersString(attributes,altitudeMode); + if (!altitudeMode.equals("clampToGround") + && (format == WebRenderer.OUTPUT_FORMAT_KML || format == WebRenderer.OUTPUT_FORMAT_GEOJSON) + && JavaRendererUtilities.is3dSymbol(symbolCode) + && modifiers.get(Modifiers.X_ALTITUDE_DEPTH) != null) { + output = RenderMilStd3dSymbol(id, name, description, symbolCode, controlPoints, altitudeMode, scale, bbox, modifiers, attributes, format); + } - output = MultiPointHandler.RenderSymbol(id, name, description, symbolCode, controlPoints, - scale, bbox, modifiers, attributes, format); - - //DEBUGGING - if(ErrorLogger.getLevel().intValue() <= Level.FINER.intValue()) - { - System.out.println(""); - StringBuilder sb = new StringBuilder(); - sb.append("\nID: " + id + "\n"); - sb.append("Name: " + name + "\n"); - sb.append("Description: " + description + "\n"); - sb.append("SymbolID: " + symbolCode + "\n"); - sb.append("Scale: " + String.valueOf(scale) + "\n"); - sb.append("BBox: " + bbox + "\n"); - sb.append("Coords: " + controlPoints + "\n"); - sb.append("Modifiers: " + modifiers + "\n"); - ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", sb.toString(),Level.FINER); - } - if(ErrorLogger.getLevel().intValue() <= Level.FINEST.intValue()) - { - String briefOutput = output.replaceAll("", "
\n"); - briefOutput = output.replaceAll("(?s)]*>.*?", ""); - ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", "Output:\n" + briefOutput,Level.FINEST); - } + if (output.isEmpty()) { + output = MultiPointHandler.RenderSymbol(id, name, description, symbolCode, controlPoints, + scale, bbox, modifiers, attributes, format); - - + //DEBUGGING + if (ErrorLogger.getLevel().intValue() <= Level.FINER.intValue()) { + System.out.println(""); + StringBuilder sb = new StringBuilder(); + sb.append("\nID: ").append(id).append("\n"); + sb.append("Name: ").append(name).append("\n"); + sb.append("Description: ").append(description).append("\n"); + sb.append("SymbolID: ").append(symbolCode).append("\n"); + sb.append("Scale: ").append(String.valueOf(scale)).append("\n"); + sb.append("BBox: ").append(bbox).append("\n"); + sb.append("Coords: ").append(controlPoints).append("\n"); + sb.append("Modifiers: ").append(modifiers).append("\n"); + ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", sb.toString(), Level.FINER); + } + if (ErrorLogger.getLevel().intValue() <= Level.FINEST.intValue()) { + String briefOutput = output.replaceAll("", "\n"); + briefOutput = output.replaceAll("(?s)]*>.*?", ""); + ErrorLogger.LogMessage("WebRenderer", "RenderSymbol", "Output:\n" + briefOutput, Level.FINEST); + } + } } catch (Exception ea) { - output = "{\"type\":'error',error:'There was an error creating the MilStdSymbol - " + ea.toString() + "'}"; ErrorLogger.LogException("WebRenderer", "RenderSymbol", ea, Level.WARNING); } @@ -154,7 +157,7 @@ public static String RenderSymbol(String id, String name, String description, /** - * Renders all multi-point symbols, creating KML or JSON for the user to + * Renders all multi-point symbols, creating KML, GeoJSON or SVG for the user to * parse and render as they like. * This function requires the bounding box to help calculate the new * locations. @@ -178,8 +181,8 @@ public static String RenderSymbol(String id, String name, String description, * @param modifiers {@link Map}, keyed using constants from Modifiers. * Pass in comma delimited String for modifiers with multiple values like AM, AN & X * @param attributes {@link Map}, keyed using constants from MilStdAttributes. - * @param format An enumeration: 2 for GeoJSON. - * @return A JSON (1) or KML (0) string representation of the graphic. + * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG} + * @return A KML, GeoJSON or SVG string representation of the graphic. */ public static String RenderSymbol2D(String id, String name, String description, String symbolCode, String controlPoints, int pixelWidth, int pixelHeight, String bbox, Map modifiers, @@ -199,6 +202,76 @@ public static String RenderSymbol2D(String id, String name, String description, return output; } + /** + * Renders all 3d multi-point symbols, creating KML or GeoJSON that can be + * used to draw it on a Google map. + * 3D version of RenderSymbol() + * + * @param id A unique identifier used to identify the symbol by Google map. + * The id will be the folder name that contains the graphic. + * @param name a string used to display to the user as the name of the + * graphic being created. + * @param description a brief description about the graphic being made and + * what it represents. + * @param symbolCode A 20-30 digit symbolID corresponding to one of the + * graphics in the MIL-STD-2525D + * @param controlPoints The vertices of the graphics that make up the + * graphic. Passed in the format of a string, using decimal degrees + * separating lat and lon by a comma, separating coordinates by a space. + * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..." + * @param altitudeMode Indicates whether the symbol should interpret + * altitudes as above sea level or above ground level. Options are + * "clampToGround", "relativeToGround" (from surface of earth), "absolute" + * (sea level), "relativeToSeaFloor" (from the bottom of major bodies of + * water). + * @param scale A number corresponding to how many meters one meter of our + * map represents. A value "50000" would mean 1:50K which means for every + * meter of our map it represents 50000 meters of real world distance. + * @param bbox The viewable area of the map. Passed in the format of a + * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required + * but can speed up rendering in some cases. + * example: "-50.4,23.6,-42.2,24.2" + * @param modifiers keyed using constants from Modifiers. + * Pass in comma delimited String for modifiers with multiple values like AM, AN & X + * @param attributes keyed using constants from MilStdAttributes. + * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG} + * @return A KML, GeoJSON or SVG string representation of the graphic. + */ + public static String RenderMilStd3dSymbol(String id, String name, String description, + String symbolCode, String controlPoints, String altitudeMode, + double scale, String bbox, Map modifiers, Map attributes, int format) { + String output = ""; + try { + + output = Shape3DHandler.RenderMilStd3dSymbol(id, name, description, symbolCode, controlPoints, altitudeMode, + scale, bbox, modifiers, attributes, format); + + //DEBUGGING + if (ErrorLogger.getLevel().intValue() <= Level.FINER.intValue()) { + System.out.println(""); + StringBuilder sb = new StringBuilder(); + sb.append("\nID: ").append(id).append("\n"); + sb.append("Name: ").append(name).append("\n"); + sb.append("Description: ").append(description).append("\n"); + sb.append("SymbolID: ").append(symbolCode).append("\n"); + sb.append("Scale: ").append(String.valueOf(scale)).append("\n"); + sb.append("BBox: ").append(bbox).append("\n"); + sb.append("Coords: ").append(controlPoints).append("\n"); + sb.append("Modifiers: ").append(modifiers).append("\n"); + ErrorLogger.LogMessage("WebRenderer", "RenderMilStd3dSymbol", sb.toString(), Level.FINER); + } + if (ErrorLogger.getLevel().intValue() <= Level.FINEST.intValue()) { + String briefOutput = output.replaceAll("", "\n"); + briefOutput = output.replaceAll("(?s)]*>.*?", ""); + ErrorLogger.LogMessage("WebRenderer", "RenderMilStd3dSymbol", "Output:\n" + briefOutput, Level.FINEST); + } + } catch (Exception ea) { + output = "{\"type\":'error',error:'There was an error creating the 3D MilStdSymbol - " + ea.toString() + "'}"; + ErrorLogger.LogException("WebRenderer", "RenderMilStd3dSymbol", ea, Level.WARNING); + } + return output; + } + /** * Renders all MilStd 2525 multi-point symbols, creating MilStdSymbol that contains the @@ -227,11 +300,7 @@ public static String RenderSymbol2D(String id, String name, String description, * lat and lon by a comma, separating coordinates by a space. The * following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..." * @param altitudeMode - * Indicates whether the symbol should interpret altitudes as - * above sea level or above ground level. Options are - * "clampToGround", "relativeToGround" (from surface of earth), - * "absolute" (sea level), "relativeToSeaFloor" (from the bottom - * of major bodies of water). + * ignored * @param scale * A number corresponding to how many meters one meter of our map * represents. A value "50000" would mean 1:50K which means for @@ -313,11 +382,7 @@ public static MilStdSymbol RenderMultiPointAsMilStdSymbol(String id, String name * lat and lon by a comma, separating coordinates by a space. The * following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..." * @param altitudeMode - * Indicates whether the symbol should interpret altitudes as - * above sea level or above ground level. Options are - * "clampToGround", "relativeToGround" (from surface of earth), - * "absolute" (sea level), "relativeToSeaFloor" (from the bottom - * of major bodies of water). + * ignored * @param scale * A number corresponding to how many meters one meter of our map * represents. A value "50000" would mean 1:50K which means for @@ -356,7 +421,7 @@ public static MilStdSymbol RenderBasicShapeAsMilStdSymbol(String id, String name } /** - * Renders multipoint basic shapes, creating KML that can be used to draw + * Renders multipoint basic shapes, creating KML, GeoJSON or SVG that can be used to draw * it on a Google map. * @param id A unique identifier used to identify the symbol by Google map. * The id will be the folder name that contains the graphic. @@ -369,11 +434,7 @@ public static MilStdSymbol RenderBasicShapeAsMilStdSymbol(String id, String name * graphic. Passed in the format of a string, using decimal degrees * separating lat and lon by a comma, separating coordinates by a space. * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..." - * @param altitudeMode Indicates whether the symbol should interpret - * altitudes as above sea level or above ground level. Options are - * "clampToGround", "relativeToGround" (from surface of earth), "absolute" - * (sea level), "relativeToSeaFloor" (from the bottom of major bodies of - * water). + * @param altitudeMode ignored * @param scale A number corresponding to how many meters one meter of our * map represents. A value "50000" would mean 1:50K which means for every * meter of our map it represents 50000 meters of real world distance. @@ -384,15 +445,14 @@ public static MilStdSymbol RenderBasicShapeAsMilStdSymbol(String id, String name * @param modifiers keyed using constants from Modifiers. * Pass in comma delimited String for modifiers with multiple values like AM, AN & X * @param attributes keyed using constants from MilStdAttributes. - * @param format An enumeration: 2 for GeoJSON. - * @return A JSON string representation of the graphic. + * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link WebRenderer#OUTPUT_FORMAT_GEOJSON} or {@link WebRenderer#OUTPUT_FORMAT_GEOSVG} + * @return A KML, GeoJSON or SVG string representation of the graphic. */ public static String RenderBasicShape(String id, String name, String description, int basicShapeType, String controlPoints, String altitudeMode, double scale, String bbox, Map modifiers, Map attributes, int format) { String output = ""; try { - JavaRendererUtilities.addAltModeToModifiersString(attributes, altitudeMode); if (SymbolUtilities.isBasicShape(basicShapeType)) output = MultiPointHandler.RenderBasicShape(id, name, description, basicShapeType, controlPoints, scale, bbox, modifiers, attributes, format); @@ -402,4 +462,52 @@ public static String RenderBasicShape(String id, String name, String description } return output; } + + /** + * Renders basic 3D shapes, creating KML or GeoJSON that can be used to draw + * it on a Google map. + * @param id A unique identifier used to identify the symbol by Google map. + * The id will be the folder name that contains the graphic. + * @param name a string used to display to the user as the name of the + * graphic being created. + * @param description a brief description about the graphic being made and + * what it represents. + * @param basicShapeType {@link Basic3DShapes} + * @param controlPoints The vertices of the graphics that make up the + * graphic. Passed in the format of a string, using decimal degrees + * separating lat and lon by a comma, separating coordinates by a space. + * The following format shall be used "x1,y1[,z1] [xn,yn[,zn]]..." + * @param altitudeMode Indicates whether the symbol should interpret + * altitudes as above sea level or above ground level. Options are + * "clampToGround", "relativeToGround" (from surface of earth), "absolute" + * (sea level), "relativeToSeaFloor" (from the bottom of major bodies of + * water). + * @param scale A number corresponding to how many meters one meter of our + * map represents. A value "50000" would mean 1:50K which means for every + * meter of our map it represents 50000 meters of real world distance. + * @param bbox The viewable area of the map. Passed in the format of a + * string "lowerLeftX,lowerLeftY,upperRightX,upperRightY." Not required + * but can speed up rendering in some cases. + * example: "-50.4,23.6,-42.2,24.2" + * @param modifiers {@link Map}, keyed using constants from Modifiers. + * Pass in comma delimited String for modifiers with multiple values like AM, AN & X + * @param attributes {@link Map}, keyed using constants from MilStdAttributes. + * @param format {@link WebRenderer#OUTPUT_FORMAT_KML}, {@link #OUTPUT_FORMAT_GEOJSON} + * @return A KML or GeoJSON string representation of the graphic. + */ + public static String RenderBasic3DShape(String id, String name, String description, int basicShapeType, + String controlPoints, String altitudeMode, + double scale, String bbox, Map modifiers, Map attributes, int format) { + String output = ""; + try { + JavaRendererUtilities.addAltModeToModifiersString(attributes, altitudeMode); + if (SymbolUtilities.isBasicShape(basicShapeType)) + output = Shape3DHandler.RenderBasic3DShape(id, name, description, basicShapeType, controlPoints, altitudeMode, + scale, bbox, modifiers, attributes, format); + } catch (Exception ea) { + output = "{\"type\":'error',error:'There was an error creating the 3D MilStdSymbol - " + ea.toString() + "'}"; + ErrorLogger.LogException("WebRenderer", "RenderBasic3DShape", ea, Level.WARNING); + } + return output; + } } diff --git a/src/main/java/armyc2/c5isr/web/render/utilities/Basic3DShapes.java b/src/main/java/armyc2/c5isr/web/render/utilities/Basic3DShapes.java new file mode 100644 index 0000000..36c57cd --- /dev/null +++ b/src/main/java/armyc2/c5isr/web/render/utilities/Basic3DShapes.java @@ -0,0 +1,67 @@ +package armyc2.c5isr.web.render.utilities; + +import armyc2.c5isr.renderer.utilities.Modifiers; +import armyc2.c5isr.JavaLineArray.TacticalLines; + + +public class Basic3DShapes { + /** + * Anchor Points: This shape requires one anchor point + *

+ * Modifiers: radius ({@link Modifiers#AM_DISTANCE}), and min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int CYLINDER = TacticalLines.PBS_CIRCLE; + + /** + * Anchor Points: This shape requires two anchor points + *

+ * Modifiers: width ({@link Modifiers#AM_DISTANCE}), and min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int ORBIT = TacticalLines.BS_ORBIT; + + /** + * Anchor Points: This shape requires at least two anchor points + *

+ * Modifiers: width ({@link Modifiers#AM_DISTANCE}), and min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int ROUTE = TacticalLines.BS_ROUTE; + + /** + * Anchor Points: This shape requires at least three anchor points + *

+ * Modifiers: min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int POLYGON = TacticalLines.BS_AREA; + + /** + * Anchor Points: This shape requires one anchor point + *

+ * Modifiers: min radius and max radius ({@link Modifiers#AM_DISTANCE}), left and right azimuth ({@link Modifiers#AN_AZIMUTH}), and min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int RADARC = TacticalLines.BS_RADARC; + + /** + * Anchor Points: This shape requires at least three anchor points + *

+ * Modifiers: radius ({@link Modifiers#AM_DISTANCE}), left and right azimuth ({@link Modifiers#AN_AZIMUTH}), and min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int POLYARC = TacticalLines.BS_POLYARC; + + /** + * A collection of radarcs + *

+ * Anchor Points: This shape requires one anchor point + *

+ * Modifiers (for each radarc): min radius and max radius ({@link Modifiers#AM_DISTANCE}), left and right azimuth ({@link Modifiers#AN_AZIMUTH}), and min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int CAKE = TacticalLines.BS_CAKE; + + /** + * A collection of routes + *

+ * Anchor Points: This shape requires at least two anchor points + *

+ * Modifiers (for each segment): left and right width ({@link Modifiers#AM_DISTANCE}), and min and max altitude ({@link Modifiers#X_ALTITUDE_DEPTH}). + */ + public static final int TRACK = TacticalLines.BS_TRACK; +} \ No newline at end of file diff --git a/src/main/java/armyc2/c5isr/web/render/utilities/JavaRendererUtilities.java b/src/main/java/armyc2/c5isr/web/render/utilities/JavaRendererUtilities.java index ddf91b1..68c6e2a 100644 --- a/src/main/java/armyc2/c5isr/web/render/utilities/JavaRendererUtilities.java +++ b/src/main/java/armyc2/c5isr/web/render/utilities/JavaRendererUtilities.java @@ -1,8 +1,7 @@ package armyc2.c5isr.web.render.utilities; -import armyc2.c5isr.renderer.utilities.MilStdAttributes; -import armyc2.c5isr.renderer.utilities.Modifiers; +import armyc2.c5isr.renderer.utilities.*; import java.awt.geom.Point2D; @@ -273,61 +272,19 @@ public static Map createParameterMapFromURL(String SymbolInfo) { }//*/ - /** - * Checks symbolID and if the relevant modifiers are present - * - * @param symbolCode - * @param modifiers - * @return - * @deprecated - */ - public static boolean is3dSymbol(String symbolCode, Map modifiers) { - boolean returnValue = false; - + public static boolean is3dSymbol(String symbolCode) { try { - String symbolId = symbolCode.substring(4, 10); - - if (symbolId.equals("ACAI--") || // Airspace Coordination Area Irregular - symbolId.equals("ACAR--") || // Airspace Coordination Area Rectangular - symbolId.equals("ACAC--") || // Airspace Coordination Area Circular - symbolId.equals("AKPC--") || // Kill box circular - symbolId.equals("AKPR--") || // Kill box rectangular - symbolId.equals("AKPI--") || // Kill box irregular - symbolId.equals("ALC---") || // Air corridor - symbolId.equals("ALM---") || // - symbolId.equals("ALS---") || // SAAFR - symbolId.equals("ALU---") || // UAV - symbolId.equals("ALL---") || // Low level transit route - symbolId.equals("AAR---") - || symbolId.equals("AAF---") - || symbolId.equals("AAH---") - || symbolId.equals("AAM---") || // MEZ - symbolId.equals("AAML--") || // LOMEZ - symbolId.equals("AAMH--")) { - - try { - if (modifiers != null) { - - // These guys store array values. Put in appropriate data strucutre - // for MilStdSymbol. - if (modifiers.containsKey(Modifiers.X_ALTITUDE_DEPTH)) { - String[] altitudes = modifiers.get(Modifiers.X_ALTITUDE_DEPTH).split(","); - if (altitudes.length < 2) { - returnValue = false; - } else { - returnValue = true; - } - } - - } - } catch (Exception exc) { - System.err.println(exc.getMessage()); - } - } + MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolCode); + int drawRule = msi.getDrawRule(); + return drawRule == DrawRules.AREA1 + || drawRule == DrawRules.AREA10 + || drawRule == DrawRules.RECTANGULAR1 + || drawRule == DrawRules.CIRCULAR1 + || drawRule == DrawRules.CORRIDOR1; } catch (Exception e) { System.err.println(e.getMessage()); } - return returnValue; + return false; } /** diff --git a/src/main/java/armyc2/c5isr/web/render/utilities/Point3D.java b/src/main/java/armyc2/c5isr/web/render/utilities/Point3D.java new file mode 100644 index 0000000..0dfe932 --- /dev/null +++ b/src/main/java/armyc2/c5isr/web/render/utilities/Point3D.java @@ -0,0 +1,26 @@ +package armyc2.c5isr.web.render.utilities; + +import java.awt.geom.Point2D; + +public class Point3D extends Point2D.Double { + public double z; + + public Point3D() { + super(); + } + + public Point3D(Point2D pt, double z) { + super(pt.getX(), pt.getY()); + this.z = z; + } + + public Point3D(double x, double y, double z) { + super(x, y); + this.z = z; + + } + + public double getZ() { + return this.z; + } +} diff --git a/src/main/java/armyc2/c5isr/web/render/utilities/ShapeInfo3D.java b/src/main/java/armyc2/c5isr/web/render/utilities/ShapeInfo3D.java new file mode 100644 index 0000000..9505fb2 --- /dev/null +++ b/src/main/java/armyc2/c5isr/web/render/utilities/ShapeInfo3D.java @@ -0,0 +1,44 @@ +package armyc2.c5isr.web.render.utilities; + +import java.util.ArrayList; + +import java.awt.geom.Point2D; + +import armyc2.c5isr.renderer.utilities.ShapeInfo; + +public class ShapeInfo3D extends ShapeInfo { + private Point3D _ModifierPosition3D = null; + private ArrayList> _Polylines3D = null; + + public void setModifierPosition(Point3D value) { + this._ModifierPosition3D = value; + } + + @Override + public Point3D getModifierPosition() { + return this._ModifierPosition3D; + } + + /** + * @deprecated use {@link ShapeInfo3D#getPolylines3D()} + */ + @Override + public ArrayList> getPolylines() { + return null; + } + + /** + * @deprecated use {@link ShapeInfo3D#setPolylines3D(ArrayList>)} + */ + @Override + public void setPolylines(ArrayList> value) { + } + + public ArrayList> getPolylines3D() { + return this._Polylines3D; + } + + public void setPolylines3D(ArrayList> value) { + this._Polylines3D = value; + } +}