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