    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}