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
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 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                if (StreetsideProperties.DEBUGING_ENABLED.get()) {
103      logger.debug(MessageFormat.format("convertDecimal2Quaternary input: {0}", Long.toString(inputNum)));
104                }
105
106                while (inputNum > 0) {
107                        sb.append(inputNum % CubemapUtils.NUM_BASE);
108                        inputNum /= CubemapUtils.NUM_BASE;
109                }
110
111                res = sb.reverse().toString();
112
113                if (StreetsideProperties.DEBUGING_ENABLED.get()) {
114      logger.debug(MessageFormat.format("convertDecimal2Quaternary output: {0}", res));
115                }
116
117                return res;
118        }
119
120        public static String convertQuaternary2Decimal(String inputNum) {
121
122          final String res;
123
124          if (StreetsideProperties.DEBUGING_ENABLED.get()) {
125      logger.debug(MessageFormat.format("convertQuaternary2Decimal input: {0}", inputNum));
126    }
127
128          int len = inputNum.length();
129    int power = 1;
130    int num = 0;
131    int i;
132
133    for (i = len - 1; i >= 0; i--)
134    {
135        if (Integer.parseInt(inputNum.substring(i,i+1)) >= CubemapUtils.NUM_BASE)
136        {
137           logger.error("Error converting quadkey " + inputNum + " to decimal.");
138           return "000000000";
139        }
140
141        num += Integer.parseInt(inputNum.substring(i,i+1)) * power;
142        power = power * CubemapUtils.NUM_BASE;
143    }
144
145                res = Integer.toString(num);
146
147                if (StreetsideProperties.DEBUGING_ENABLED.get()) {
148      logger.debug(MessageFormat.format("convertQuaternary2Decimal output: {0}", res));
149    }
150
151                return res;
152        }
153
154        public static String getFaceNumberForCount(int count) {
155                final String res;
156
157                switch (count) {
158                case 0:
159                        res = CubemapFaces.FRONT.getValue();
160                        break;
161                case 1:
162                        res = CubemapFaces.RIGHT.getValue();
163                        break;
164                case 2:
165                        res = CubemapFaces.BACK.getValue();
166                        break;
167                case 3:
168                        res = CubemapFaces.LEFT.getValue();
169                        break;
170                case 4:
171                        res = CubemapFaces.UP.getValue();
172                        break;
173                case 5:
174                        res = CubemapFaces.DOWN.getValue();
175                        break;
176                default:
177                        res = null;
178                        break;
179                }
180                return res;
181        }
182
183        public static int getTileWidth() {
184                // 4-tiled cubemap imagery has a 2-pixel overlap; 16-tiled has a 1-pixel
185                // overlap
186                if (!StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) {
187                        return 255;
188                } else {
189                        return 254;
190                }
191        }
192
193        public static int getTileHeight() {
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 getCount4FaceNumber(String faceString) {
204
205                final int tileAddress;
206
207                switch (faceString) {
208        // back
209                case "03":  tileAddress = 0;
210                 break;
211        // down
212        case "12":  tileAddress = 1;
213                 break;
214        // front
215        case "01":  tileAddress = 2;
216                 break;
217        // left
218        case "10":  tileAddress = 3;
219                 break;
220        // right
221        case "02":  tileAddress = 4;
222                 break;
223        // up
224        case "11":  tileAddress = 5;
225                 break;
226        default: tileAddress = 6;
227                 break;
228                }
229
230                return tileAddress;
231        }
232
233        public static String getFaceIdFromTileId(String tileId) {
234                // magic numbers - the face id is contained in the 16th and 17th positions
235                return tileId.substring(16, 18);
236        }
237
238        public static String convertDoubleCountNrto16TileNr(String countNr) {
239                String tileAddress;
240
241                switch (countNr) {
242        case "00":  tileAddress = "00";
243                 break;
244        case "01":  tileAddress = "01";
245                 break;
246        case "02":  tileAddress = "10";
247                 break;
248        case "03":  tileAddress = "11";
249                 break;
250        case "10":  tileAddress = "02";
251                 break;
252        case "11":  tileAddress = "03";
253                 break;
254        case "12":  tileAddress = "12";
255                 break;
256        case "13":  tileAddress = "13";
257                 break;
258        case "20":  tileAddress = "20";
259                 break;
260        case "21":  tileAddress = "21";
261                 break;
262        case "22":  tileAddress = "30";
263                 break;
264        case "23":  tileAddress = "31";
265                        break;
266        case "30":  tileAddress = "22";
267           break;
268        case "31":  tileAddress = "23";
269           break;
270        case "32":  tileAddress = "32";
271           break;
272        case "33":  tileAddress = "33";
273           break;
274        // shouldn't happen
275        default: tileAddress = null;
276                 break;
277                }
278
279                return tileAddress;
280        }
281}