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