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}