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