001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.cubemap; 003 004import java.util.HashMap; 005import java.util.Map; 006import java.util.stream.Stream; 007 008import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties; 009import org.openstreetmap.josm.tools.I18n; 010import org.openstreetmap.josm.tools.Logging; 011 012public class CubemapUtils { 013 014 public enum CubefaceType { 015 ONE(1), 016 FOUR(4), 017 SIXTEEN(16); 018 019 private final int value; 020 private static Map<Integer, CubefaceType> map = new HashMap<>(); 021 022 private CubefaceType(int value) { 023 this.value = value; 024 } 025 026 static { 027 for (CubefaceType cubefaceType : CubefaceType.values()) { 028 map.put(cubefaceType.value, cubefaceType); 029 } 030 } 031 032 public static CubefaceType valueOf(int cubefaceType) { 033 return (CubefaceType) map.get(cubefaceType); 034 } 035 036 public int getValue() { 037 return value; 038 } 039 } 040 041 public static enum CubemapFaces { 042 FRONT("01"), 043 RIGHT("02"), 044 BACK("03"), 045 LEFT("10"), 046 UP("11"), 047 DOWN("12"); 048 049 public static Stream<CubemapFaces> stream() { 050 return Stream.of(CubemapFaces.values()); 051 } 052 053 private final String value; 054 055 CubemapFaces(String value) { 056 this.value = value; 057 } 058 059 public String getValue() { 060 return value; 061 } 062 } 063 064 public static Map<String[],String> directionConversion = new HashMap<>(); 065 066 // numerical base for decimal conversion (quaternary in the case of Streetside) 067 private static final int NUM_BASE = 4; 068 public static final String IMPORTED_ID = "00000000"; 069 public static final int NUM_SIDES = 6; 070 071 public static Map<String,String> rowCol2StreetsideCellAddressMap = null; 072 073 // Intialize utility map for storing row to Streetside cell number conversions 074 static { 075 076 CubemapUtils.rowCol2StreetsideCellAddressMap = new HashMap<>(); 077 CubemapUtils.rowCol2StreetsideCellAddressMap.put("00","00"); 078 CubemapUtils.rowCol2StreetsideCellAddressMap.put("01","01"); 079 CubemapUtils.rowCol2StreetsideCellAddressMap.put("02","10"); 080 CubemapUtils.rowCol2StreetsideCellAddressMap.put("03","11"); 081 CubemapUtils.rowCol2StreetsideCellAddressMap.put("10","02"); 082 CubemapUtils.rowCol2StreetsideCellAddressMap.put("11","03"); 083 CubemapUtils.rowCol2StreetsideCellAddressMap.put("12","12"); 084 CubemapUtils.rowCol2StreetsideCellAddressMap.put("13","13"); 085 CubemapUtils.rowCol2StreetsideCellAddressMap.put("20","20"); 086 CubemapUtils.rowCol2StreetsideCellAddressMap.put("21","21"); 087 CubemapUtils.rowCol2StreetsideCellAddressMap.put("22","30"); 088 CubemapUtils.rowCol2StreetsideCellAddressMap.put("23","31"); 089 CubemapUtils.rowCol2StreetsideCellAddressMap.put("30","22"); 090 CubemapUtils.rowCol2StreetsideCellAddressMap.put("31","23"); 091 CubemapUtils.rowCol2StreetsideCellAddressMap.put("32","32"); 092 CubemapUtils.rowCol2StreetsideCellAddressMap.put("33","33"); 093 } 094 095 public static String convertDecimal2Quaternary(long inputNum) { 096 String res = null; 097 final StringBuilder sb = new StringBuilder(); 098 099 while (inputNum > 0) { 100 sb.append(inputNum % CubemapUtils.NUM_BASE); 101 inputNum /= CubemapUtils.NUM_BASE; 102 } 103 104 sb.append("0"); 105 res = sb.reverse().toString(); 106 107 return res; 108 } 109 110 public static String convertQuaternary2Decimal(String inputNum) { 111 int len = inputNum.length(); 112 int power = 1; // Initialize power of base 113 int num = 0; // Initialize result 114 int base = 4; // This could be used for any base, not just quad 115 116 // Decimal equivalent is str[len-1]*1 + 117 // str[len-1]*base + str[len-1]*(base^2) + ... 118 for (int i = len - 1; i >= 0; i--) { 119 // A digit in input number must be 120 // less than number's base 121 int current = Integer.valueOf(String.valueOf(inputNum.substring(i,i+1))); 122 if ( current >= 4) { 123 Logging.error(I18n.tr("Invalid bubbleId {0}", inputNum)); 124 return "-1"; 125 } 126 127 num += Integer.valueOf(inputNum.charAt(i)).intValue() * power; 128 power = power * base; 129 } 130 131 return Integer.toString(num); 132 } 133 134 public static String getFaceNumberForCount(int count) { 135 final String res; 136 137 switch (count) { 138 case 0: 139 res = CubemapFaces.FRONT.getValue(); 140 break; 141 case 1: 142 res = CubemapFaces.RIGHT.getValue(); 143 break; 144 case 2: 145 res = CubemapFaces.BACK.getValue(); 146 break; 147 case 3: 148 res = CubemapFaces.LEFT.getValue(); 149 break; 150 case 4: 151 res = CubemapFaces.UP.getValue(); 152 break; 153 case 5: 154 res = CubemapFaces.DOWN.getValue(); 155 break; 156 default: 157 res = null; 158 break; 159 } 160 return res; 161 } 162 163 public static int getTileWidth() { 164 // 4-tiled cubemap imagery has a 2-pixel overlap; 16-tiled has a 1-pixel 165 // overlap 166 if (!StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) { 167 return 255; 168 } else { 169 return 254; 170 } 171 } 172 173 public static int getTileHeight() { 174 // 4-tiled cubemap imagery has a 2-pixel overlap; 16-tiled has a 1-pixel 175 // overlap 176 if(!StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) { 177 return 255; 178 } else { 179 return 254; 180 } 181 } 182 183 public static int getCount4FaceNumber(String faceString) { 184 185 final int tileAddress; 186 187 switch (faceString) { 188 // back 189 case "03": tileAddress = 0; 190 break; 191 // down 192 case "12": tileAddress = 1; 193 break; 194 // front 195 case "01": tileAddress = 2; 196 break; 197 // left 198 case "10": tileAddress = 3; 199 break; 200 // right 201 case "02": tileAddress = 4; 202 break; 203 // up 204 case "11": tileAddress = 5; 205 break; 206 default: tileAddress = 6; 207 break; 208 } 209 210 return tileAddress; 211 } 212 213 public static String getFaceIdFromTileId(String tileId) { 214 // magic numbers - the face id is contained in the 16th and 17th positions 215 return tileId.substring(16, 18); 216 } 217 218 public static String msToString(long ms) { 219 long totalSecs = ms/1000; 220 long hours = (totalSecs / 3600); 221 long mins = (totalSecs / 60) % 60; 222 long secs = totalSecs % 60; 223 String minsString = (mins == 0) 224 ? "00" 225 : ((mins < 10) 226 ? "0" + mins 227 : "" + mins); 228 String secsString = (secs == 0) 229 ? "00" 230 : ((secs < 10) 231 ? "0" + secs 232 : "" + secs); 233 if (hours > 0) 234 return hours + ":" + minsString + ":" + secsString; 235 else if (mins > 0) 236 return mins + ":" + secsString; 237 else return ":" + secsString; 238 } 239 240 public static String convertDoubleCountNrto16TileNr(String countNr) { 241 String tileAddress; 242 243 switch (countNr) { 244 case "00": tileAddress = "00"; 245 break; 246 case "01": tileAddress = "01"; 247 break; 248 case "02": tileAddress = "10"; 249 break; 250 case "03": tileAddress = "11"; 251 break; 252 case "10": tileAddress = "02"; 253 break; 254 case "11": tileAddress = "03"; 255 break; 256 case "12": tileAddress = "12"; 257 break; 258 case "13": tileAddress = "13"; 259 break; 260 case "20": tileAddress = "20"; 261 break; 262 case "21": tileAddress = "21"; 263 break; 264 case "22": tileAddress = "30"; 265 break; 266 case "23": tileAddress = "31"; 267 break; 268 case "30": tileAddress = "22"; 269 break; 270 case "31": tileAddress = "23"; 271 break; 272 case "32": tileAddress = "32"; 273 break; 274 case "33": tileAddress = "33"; 275 break; 276 // shouldn't happen 277 default: tileAddress = null; 278 break; 279 } 280 281 return tileAddress; 282 } 283}