001package armyc2.c5isr.web.render.utilities; 002 003import armyc2.c5isr.renderer.utilities.DrawRules; 004import armyc2.c5isr.renderer.utilities.MSInfo; 005import armyc2.c5isr.renderer.utilities.MSLookup; 006import armyc2.c5isr.renderer.utilities.MilStdAttributes; 007import armyc2.c5isr.graphics2d.Point2D; 008import armyc2.c5isr.renderer.utilities.Modifiers; 009 010import java.io.PrintWriter; 011import java.io.StringWriter; 012import java.io.Writer; 013import java.util.HashMap; 014import java.util.Locale; 015import java.util.Map; 016 017/** 018 * 019* 020 */ 021@SuppressWarnings("unused") 022public class JavaRendererUtilities { 023 024 public static final String HOSTILE_FILL_COLOR = "FFFF8080"; 025 public static final String FRIENDLY_FILL_COLOR = "FF80E0FF"; 026 public static final String NEUTRAL_FILL_COLOR = "FFAAFFAA"; 027 public static final String UNKNOWN_FILL_COLOR = "FFFFFF80"; 028 029 /** 030 * Converts ARGB string format to the Google used ABGR string format. Google 031 * reverses the blue and red positioning. 032 * 033 * @param rgbString A color string of the format AARRGGBB in hex value. 034 * @return the reverse of the input string in hex. The format should now be 035 * AABBGGRR 036 */ 037 public static String ARGBtoABGR(String rgbString) { 038 if(rgbString.length()==6) 039 { 040 String s="FF"; 041 rgbString=s.concat(rgbString); 042 } 043 044 String bgrString = rgbString.toUpperCase(Locale.US); 045 046 if(rgbString.length() == 8) 047 { 048 char[] c = rgbString.toCharArray(); 049 char temp1 = c[2]; 050 char temp2 = c[3]; 051 c[2] = c[6]; 052 c[3] = c[7]; 053 c[6] = temp1; 054 c[7] = temp2; 055 bgrString = new String(c); 056 } 057 else if(rgbString.length() == 6) 058 { 059 char[] c = rgbString.toCharArray(); 060 char temp1 = c[0]; 061 char temp2 = c[1]; 062 c[0] = c[4]; 063 c[1] = c[5]; 064 c[4] = temp1; 065 c[5] = temp2; 066 bgrString = "FF" + new String(c); 067 //bgrString = "FF" + bgrString; 068 } 069 else 070 { 071 System.err.println("JavaRendererUtilties.ARGBtoABGR(): " + "\"" + String.valueOf(rgbString) + "\" is not a 6 or 8 character String in the format of RRGGBB or AARRGGBB"); 072 } 073 074 return bgrString; 075 } 076 077 /** 078 * Returns a symbolId with just the identifiable symbol Id pieces. All 079 * variable information is returned as '*'. For example, a boundary, 080 * "GFGPGLB----KUSX" returns "G*G*GLB---****X"; 081 * 082 * @param symbolCode A 15 character symbol ID. 083 * @return The normalized SymbolCode. 084 * @deprecated 085 */ 086 public static String normalizeSymbolCode(String symbolCode) { 087 088 String newSymbolCode = symbolCode; 089 090 if (symbolCode.startsWith("G") || symbolCode.startsWith("S")) { 091 // Remove Affiliation 092 newSymbolCode = newSymbolCode.substring(0, 1) + '*' + newSymbolCode.substring(2); 093 // Remove planned/present field 094 newSymbolCode = newSymbolCode.substring(0, 3) + '*' + newSymbolCode.substring(4); 095 // Remove echelon, special code and country codes 096 newSymbolCode = newSymbolCode.substring(0, 10) + "****" + newSymbolCode.substring(14); 097 } 098 099 // If a unit replace last character with *. 100 if (symbolCode.startsWith("S")) { 101 newSymbolCode = newSymbolCode.substring(0, 14) + '*'; 102 } 103 104 return newSymbolCode; 105 } 106 107 public static void addAltModeToModifiersString(Map<String,String> attributes, String altMode) 108 { 109 if(altMode.equals("relativeToGround")) 110 attributes.put(MilStdAttributes.AltitudeMode, "AGL"); 111 else if(altMode.equals("absolute")) 112 attributes.put(MilStdAttributes.AltitudeMode, "AMSL"); 113 } 114 115 /** 116 * 117 * @param SymbolInfo something like 118 * "SymbolID?LineColor=0x000000&FillColor=0xFFFFFF&size=35" 119 */ 120 public static Map<String, String> createParameterMapFromURL(String SymbolInfo) { 121 Map<String, String> modifiers = new HashMap<String, String>(); 122 String symbolID = null; 123 String parameters = null; 124 String key = null; 125 String value = null; 126 String arrParameters[] = null; 127 String arrKeyValue[] = null; 128 String temp = null; 129 int questionIndex = SymbolInfo.lastIndexOf('?'); 130 131 try { 132 if (questionIndex == -1) { 133 symbolID = java.net.URLDecoder.decode(SymbolInfo, "UTF-8"); 134 } else { 135 symbolID = java.net.URLDecoder.decode(SymbolInfo.substring(0, questionIndex), "UTF-8"); 136 } 137 138 } catch (Exception exc) { 139 System.err.println("Error parsing SymbolID"); 140 System.err.println(exc.getMessage()); 141 } 142 143 try { //build a map for the other createMilstdSymbol function to use 144 //to build a milstd symbol. 145 if (questionIndex > 0 && (questionIndex + 1 < SymbolInfo.length())) { 146 parameters = SymbolInfo.substring(questionIndex + 1, SymbolInfo.length()); 147 arrParameters = parameters.split("&"); 148 int n = arrParameters.length; 149 //for(int i = 0; i < arrParameters.length; i++) 150 for (int i = 0; i < n; i++) { 151 arrKeyValue = arrParameters[i].split("="); 152 if (arrKeyValue.length == 2 && arrKeyValue[1] != null && arrKeyValue[1].equals("") == false) { 153 154 key = arrKeyValue[0]; 155 value = arrKeyValue[1]; 156 157 temp = java.net.URLDecoder.decode(value, "UTF-8"); 158 modifiers.put(key.toUpperCase(), temp); 159 160 //System.out.println("key: " + key + " value: " + temp); 161 } 162 } 163 } 164 } catch (Exception exc) { 165 System.err.println("Error parsing \"" + key.toUpperCase() + "\" parameter from URL"); 166 System.err.println(exc.getMessage()); 167 } 168 return modifiers; 169 } 170 171 /* 172 * Try to turn a bad code into something renderable. 173 * 174 * @param symbolID 175 * @return 176 * @deprecated use SymbolUtilties.reconcileSymbolID() 9/5/2013 177 */ 178 /*public static String ReconcileSymbolID(String symbolID) { 179 StringBuilder sb = new StringBuilder(""); 180 char codingScheme = symbolID.charAt(0); 181 182 if (symbolID.length() < 15) { 183 while (symbolID.length() < 15) { 184 symbolID += "-"; 185 } 186 } 187 if (symbolID.length() > 15) { 188 symbolID = symbolID.substring(0, 14); 189 } 190 191 if (symbolID != null && symbolID.length() == 15) { 192 if (codingScheme == 'S' || //warfighting 193 codingScheme == 'I' ||//sigint 194 codingScheme == 'O' ||//stability operation 195 codingScheme == 'E')//emergency management 196 { 197 sb.append(codingScheme); 198 199 if (SymbolUtilities.hasValidAffiliation(symbolID) == false) { 200 sb.append('U'); 201 } else { 202 sb.append(symbolID.charAt(1)); 203 } 204 205 if (SymbolUtilities.hasValidBattleDimension(symbolID) == false) { 206 sb.append('Z'); 207 sb.replace(0, 1, "S"); 208 } else { 209 sb.append(symbolID.charAt(2)); 210 } 211 212 if (SymbolUtilities.hasValidStatus(symbolID) == false) { 213 sb.append('P'); 214 } else { 215 sb.append(symbolID.charAt(3)); 216 } 217 218 sb.append("------"); 219 sb.append(symbolID.substring(10, 15)); 220 221 } else if (codingScheme == 'G')//tactical 222 { 223 sb.append(codingScheme); 224 225 if (SymbolUtilities.hasValidAffiliation(symbolID) == false) { 226 sb.append('U'); 227 } else { 228 sb.append(symbolID.charAt(1)); 229 } 230 231 sb.append('G'); 232 233 if (SymbolUtilities.hasValidStatus(symbolID) == false) { 234 sb.append('P'); 235 } else { 236 sb.append(symbolID.charAt(3)); 237 } 238 239 sb.append("GPP---");//return an action point 240 sb.append(symbolID.substring(10, 15)); 241 242 } else if (codingScheme == 'W')//weather 243 {//no default weather graphic 244 return "SUZP-----------";//unknown 245 } else//bad codingScheme 246 { 247 sb.append('S'); 248 if (SymbolUtilities.hasValidAffiliation(symbolID) == false) { 249 sb.append('U'); 250 } else { 251 sb.append(symbolID.charAt(1)); 252 } 253 254 if (SymbolUtilities.hasValidBattleDimension(symbolID) == false) { 255 sb.append('Z'); 256 } else { 257 sb.append(symbolID.charAt(2)); 258 } 259 260 if (SymbolUtilities.hasValidStatus(symbolID) == false) { 261 sb.append('P'); 262 } else { 263 sb.append(symbolID.charAt(3)); 264 } 265 266 sb.append("------"); 267 sb.append(symbolID.substring(10, 15)); 268 } 269 } else { 270 return "SUZP-----------";//unknown 271 } 272 273 return sb.toString(); 274 275 }//*/ 276 277 public static boolean is3dSymbol(String symbolCode) { 278 try { 279 MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolCode); 280 int drawRule = msi.getDrawRule(); 281 return drawRule == DrawRules.AREA1 282 || drawRule == DrawRules.AREA10 283 || drawRule == DrawRules.RECTANGULAR1 284 || drawRule == DrawRules.CIRCULAR1 285 || drawRule == DrawRules.CORRIDOR1; 286 } catch (Exception e) { 287 System.err.println(e.getMessage()); 288 } 289 return false; 290 } 291 292 /** 293 * Determines if a String represents a valid number 294 * 295 * @param text 296 * @return "1.56" == true, "1ab" == false 297 */ 298 public static boolean isNumber(String text) { 299 if (text != null && text.matches("((-|\\+)?[0-9]+(\\.[0-9]+)?)+")) { 300 return true; 301 } else { 302 return false; 303 } 304 } 305 306 /** 307 * Takes a throwable and puts it's stacktrace into a string. 308 * 309 * @param thrown 310 * @return 311 */ 312 public static String getStackTrace(Throwable thrown) { 313 try { 314 Writer writer = new StringWriter(); 315 PrintWriter printWriter = new PrintWriter(writer); 316 thrown.printStackTrace(printWriter); 317 return writer.toString(); 318 } catch (Exception exc) { 319 //System.out.println("JavaRendererUtilties.getStackTrace()"); 320 //return "Error - couldn't retrieve stack trace"; 321 return ""; 322 } 323 } 324 325 public static Point2D getEndPointWithAngle(Point2D ptStart, 326 //Point2D pt1, 327 //Point2D pt2, 328 double angle, 329 double distance) { 330 double newX = 0; 331 double newY = 0; 332 Point2D pt = new Point2D.Double(); 333 try { 334 //first get the angle psi between pt0 and pt1 335 double psi = 0;//Math.atan((pt1.y - pt0.y) / (pt1.x - pt0.x)); 336 //double psi = Math.atan((ptStart.getY() - ptStart.getY()) / (ptStart.getX() - (ptStart.getX()+100))); 337 //convert alpha to radians 338 double alpha1 = Math.PI * angle / 180; 339 340 //theta is the angle of extension from the x axis 341 double theta = psi + alpha1; 342 //dx is the x extension from pt2 343 double dx = distance * Math.cos(theta); 344 //dy is the y extension form pt2 345 double dy = distance * Math.sin(theta); 346 newX = ptStart.getX() + dx; 347 newY = ptStart.getY() + dy; 348 349 pt.setLocation(newX, newY); 350 } catch (Exception exc) { 351 System.out.println(exc.getMessage()); 352 exc.printStackTrace(); 353 } 354 return pt; 355 } 356 357 /** 358 * 359 * @param latitude1 360 * @param longitude1 361 * @param latitude2 362 * @param longitude2 363 * @param unitOfMeasure meters, kilometers, miles, feet, yards, nautical, 364 * nautical miles. 365 * @return 366 */ 367 public static double measureDistance(double latitude1, double longitude1, double latitude2, double longitude2, String unitOfMeasure) { 368 // latitude1,latitude2 = latitude, longitude1,longitude2 = longitude 369 //Radius is 6378.1 (km), 3963.1 (mi), 3443.9 (nm 370 371 double distance = -1, 372 rad; 373 374 String uom = unitOfMeasure.toLowerCase(); 375 376 if (uom.equals("meters")) { 377 rad = 6378137; 378 } else if (uom.equals("kilometers")) { 379 rad = 6378.137; 380 } else if (uom.equals("miles")) { 381 rad = 3963.1; 382 } else if (uom.equals("feet")) { 383 rad = 20925524.9; 384 } else if (uom.equals("yards")) { 385 rad = 6975174.98; 386 } else if (uom.equals("nautical")) { 387 rad = 3443.9; 388 } else if (uom.equals("nautical miles")) { 389 rad = 3443.9; 390 } else { 391 return -1.0; 392 } 393 394 latitude1 = latitude1 * (Math.PI / 180); 395 latitude2 = latitude2 * (Math.PI / 180); 396 longitude1 = longitude1 * (Math.PI / 180); 397 longitude2 = longitude2 * (Math.PI / 180); 398 distance = (Math.acos(Math.cos(latitude1) * Math.cos(longitude1) * Math.cos(latitude2) * Math.cos(longitude2) + Math.cos(latitude1) * Math.sin(longitude1) * Math.cos(latitude2) * Math.sin(longitude2) + Math.sin(latitude1) * Math.sin(latitude2)) * rad); 399 400 return distance; 401 } 402}