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}