diff options
| author | Bananeweizen <bananeweizen@gmx.de> | 2012-03-10 21:46:32 +0100 |
|---|---|---|
| committer | Bananeweizen <bananeweizen@gmx.de> | 2012-03-10 21:46:32 +0100 |
| commit | 491fdefaf2ab8adff5c62898fa00f9af2220b214 (patch) | |
| tree | 9091734e7f8786b8fcc5f1adc3cf23e822c9eae8 /main | |
| parent | d40313cf48a9956487afd2b591b34d588bb4ae82 (diff) | |
| download | cgeo-491fdefaf2ab8adff5c62898fa00f9af2220b214.zip cgeo-491fdefaf2ab8adff5c62898fa00f9af2220b214.tar.gz cgeo-491fdefaf2ab8adff5c62898fa00f9af2220b214.tar.bz2 | |
fix #1262: icon decoding does not work well
Diffstat (limited to 'main')
3 files changed, 183 insertions, 131 deletions
diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java index 7780ba2..127b773 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java @@ -30,8 +30,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * GC.com/Groundspeak (GS) specific stuff @@ -47,25 +45,6 @@ public class GCBase { protected final static long GC_BASE31 = 31; protected final static long GC_BASE16 = 16; - // Pixel colors in tile - private final static int BORDER_GRAY = 0x5F5F5F; - private final static int DARK_GREEN = 0x316013; // Tradi 14 - private final static int LIGHT_GREEN = 0x80AF64; // Tradi 13 - private final static int DARK_BLUE = 0x243C97; // Mystery - private final static int YELLOW = 0xFFDE19; // Multi 14,13 - private final static int FOUND = 0xFBEA5D; // Found - - // Offset inside cache icon - private final static int POSX_TRADI = 7; - private final static int POSY_TRADI = -12; - private final static int POSX_MULTI = 5; // for orange 8 - private final static int POSY_MULTI = -9; // for orange 10 - private final static int POSX_MYSTERY = 5; - private final static int POSY_MYSTERY = -13; - private final static int POSX_FOUND = 10; - private final static int POSY_FOUND = -8; - - private final static Pattern PATTERN_JSON_KEY = Pattern.compile("[^\\d]*" + "(\\d+),\\s*(\\d+)" + "[^\\d]*"); // (12, 34) /** * Searches the view port on the live map with Strategy.AUTO * @@ -235,7 +214,7 @@ public class GCBase { for (int i = 1; i < keys.length(); i++) { // index 0 is empty String key = keys.getString(i); if (StringUtils.isNotBlank(key)) { - int[] xy = splitJSONKey(key); + UTFGridPosition pos = UTFGridPosition.fromString(key); JSONArray dataForKey = dataObject.getJSONArray(key); for (int j = 0; j < dataForKey.length(); j++) { JSONObject cacheInfo = dataForKey.getJSONObject(j); @@ -245,14 +224,10 @@ public class GCBase { List<UTFGridPosition> listOfPositions = positions.get(id); if (listOfPositions == null) { listOfPositions = new ArrayList<UTFGridPosition>(); + positions.put(id, listOfPositions); } - /* - * Optimization - * UTFGridPosition pos = keyPositions.get(key); - */ - UTFGridPosition pos = new UTFGridPosition(xy[0], xy[1]); + listOfPositions.add(pos); - positions.put(id, listOfPositions); } } } @@ -269,9 +244,9 @@ public class GCBase { cache.setCoords(tile.getCoord(xy)); if (strategy.flags.contains(StrategyFlag.PARSE_TILES)) { if (tile.getZoomlevel() >= 14) { - parseMapPNG14(cache, bitmap, xy); + IconDecoder.parseMapPNG14(cache, bitmap, xy); } else { - parseMapPNG13(cache, bitmap, xy); + IconDecoder.parseMapPNG13(cache, bitmap, xy); } } else { cache.setType(CacheType.UNKNOWN); @@ -287,89 +262,6 @@ public class GCBase { return searchResult; } - // Try to get the cache type from the PNG image for a tile */ - public static void parseMapPNG14(cgCache cache, Bitmap bitmap, UTFGridPosition xy) { - int x = xy.getX() * 4 + 2; - int y = xy.getY() * 4 + 2; - int countX = 0; - int countY = 0; - - // search for left border - while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != BORDER_GRAY) { - if (--x < 0 || ++countX > 20) { - return; - } - } - // search for bottom border - while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != 0x000000) { - if (++y >= Tile.TILE_SIZE || ++countY > 20) { - return; - } - } - - try { - if ((bitmap.getPixel(x + POSX_TRADI, y + POSY_TRADI) & 0x00FFFFFF) == DARK_GREEN) { - cache.setType(CacheType.TRADITIONAL); - return; - } - if ((bitmap.getPixel(x + POSX_MYSTERY, y + POSY_MYSTERY) & 0x00FFFFFF) == DARK_BLUE) { - cache.setType(CacheType.MYSTERY); - return; - } - if ((bitmap.getPixel(x + POSX_MULTI, y + POSY_MULTI) & 0x00FFFFFF) == YELLOW) { - cache.setType(CacheType.MULTI); - return; - } - if ((bitmap.getPixel(x + POSX_FOUND, y + POSY_FOUND) & 0x00FFFFFF) == FOUND) { - cache.setFound(true); - return; - } - } catch (IllegalArgumentException e) { - // intentionally left blank - } - - return; - } - - // Try to get the cache type from the PNG image for a tile */ - public static void parseMapPNG13(cgCache cache, Bitmap bitmap, UTFGridPosition xy) { - - int x = xy.getX() * 4 + 2; - int y = xy.getY() * 4 + 2; - int countY = 0; - - // search for top border - while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != BORDER_GRAY) { - if (--y < 0 || ++countY > 12) { - return; - } - } - - try { - int color = bitmap.getPixel(x, y + 2) & 0x00FFFFFF; - - switch (color) { - case LIGHT_GREEN: - cache.setType(CacheType.TRADITIONAL); - return; - case YELLOW: - cache.setType(CacheType.MULTI); - return; - } - if ((color | 0x00FFFF) == 0x00FFFF) { // BLUE - cache.setType(CacheType.MYSTERY); - return; - } - // Found consists out of too many different colors - } - catch (IllegalArgumentException e) { - // intentionally left blank - } - - return; - } - - /** * Calculate needed tiles for the given viewport @@ -478,22 +370,4 @@ public class GCBase { return new String[] { userSession, sessionToken }; } - /** - * @param key - * Key in the format (xx, xx) - * @return - */ - static int[] splitJSONKey(String key) { - final Matcher matcher = PATTERN_JSON_KEY.matcher(key); - try { - if (matcher.matches()) { - final int x = Integer.parseInt(matcher.group(1)); - final int y = Integer.parseInt(matcher.group(2)); - return new int[] { x, y }; - } - } catch (NumberFormatException e) { - } - return new int[] { 0, 0 }; - } - } diff --git a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java new file mode 100644 index 0000000..2935ef0 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java @@ -0,0 +1,156 @@ +package cgeo.geocaching.connector.gc; + +import cgeo.geocaching.cgCache; +import cgeo.geocaching.enumerations.CacheType; + +import android.graphics.Bitmap; + +/** + * icon decoder for cache icons + * + */ +public abstract class IconDecoder { + + private static final int[] OFFSET_X = new int[] { 0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2 }; + private static final int[] OFFSET_Y = new int[] { 0, 0, 1, 1, 1, 0, -1, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2 }; + + /** + * The icon decoder walks a spiral around the center pixel position of the cache + * and searches for characteristic colors. + * + * @param cache + * @param bitmap + * @param xy + */ + public static void parseMapPNG13(final cgCache cache, Bitmap bitmap, UTFGridPosition xy) { + final int xCenter = xy.getX() * 4 + 2; + final int yCenter = xy.getY() * 4 + 2; + final int bitmapWidth = bitmap.getWidth(); + final int bitmapHeight = bitmap.getHeight(); + + int countMulti = 0; + int countFound = 0; + + for (int i = 0; i < OFFSET_X.length; i++) { + + // assert that we are still in the tile + final int x = xCenter + OFFSET_X[i]; + if (x < 0 || x >= bitmapWidth) { + continue; + } + + final int y = yCenter + OFFSET_Y[i]; + if (y < 0 || y >= bitmapHeight) { + continue; + } + + int color = bitmap.getPixel(x, y) & 0x00FFFFFF; + + // transparent pixels are not interesting + if (color == 0) { + continue; + } + + int red = (color & 0xFF0000) >> 16; + int green = (color & 0xFF00) >> 8; + int blue = color & 0xFF; + + // these are quite sure, so one pixel is enough for matching + if (green > 0x80 && green > red && green > blue) { + cache.setType(CacheType.TRADITIONAL); + return; + } + if (blue > 0x80 && blue > red && blue > green) { + cache.setType(CacheType.MYSTERY); + return; + } + if (red > 0x90 && blue < 0x10 && green < 0x10) { + cache.setType(CacheType.EVENT); + return; + } + + // next two are hard to distinguish, therefore we sample all pixels of the spiral + if (red > 0xFA && green > 0xD0) { + countMulti++; + } + if (red < 0xF3 && red > 0xa0 && green > 0x20 && blue < 0x80) { + countFound++; + } + } + + // now check whether we are sure about found/multi + if (countFound > countMulti && countFound >= 2) { + cache.setFound(true); + } + if (countMulti > countFound && countMulti >= 5) { + cache.setType(CacheType.MULTI); + } + } + + // Pixel colors in tile + private final static int COLOR_BORDER_GRAY = 0x5F5F5F; + private final static int COLOR_TRADITIONAL = 0x316013; + private final static int COLOR_MYSTERY = 0x243C97; + private final static int COLOR_MULTI = 0xFFDE19; + private final static int COLOR_FOUND = 0xFBEA5D; + + // Offset inside cache icon + private final static int POSX_TRADI = 7; + private final static int POSY_TRADI = -12; + private final static int POSX_MULTI = 5; // for orange 8 + private final static int POSY_MULTI = -9; // for orange 10 + private final static int POSX_MYSTERY = 5; + private final static int POSY_MYSTERY = -13; + private final static int POSX_FOUND = 10; + private final static int POSY_FOUND = -8; + + /** + * For level 14 find the borders of the icons and then use a single pixel and color to match. + * + * @param cache + * @param bitmap + * @param xy + */ + public static void parseMapPNG14(cgCache cache, Bitmap bitmap, UTFGridPosition xy) { + int x = xy.getX() * 4 + 2; + int y = xy.getY() * 4 + 2; + + // search for left border + int countX = 0; + while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != COLOR_BORDER_GRAY) { + if (--x < 0 || ++countX > 20) { + return; + } + } + // search for bottom border + int countY = 0; + while ((bitmap.getPixel(x, y) & 0x00FFFFFF) != 0x000000) { + if (++y >= Tile.TILE_SIZE || ++countY > 20) { + return; + } + } + + try { + if ((bitmap.getPixel(x + POSX_TRADI, y + POSY_TRADI) & 0x00FFFFFF) == COLOR_TRADITIONAL) { + cache.setType(CacheType.TRADITIONAL); + return; + } + if ((bitmap.getPixel(x + POSX_MYSTERY, y + POSY_MYSTERY) & 0x00FFFFFF) == COLOR_MYSTERY) { + cache.setType(CacheType.MYSTERY); + return; + } + if ((bitmap.getPixel(x + POSX_MULTI, y + POSY_MULTI) & 0x00FFFFFF) == COLOR_MULTI) { + cache.setType(CacheType.MULTI); + return; + } + if ((bitmap.getPixel(x + POSX_FOUND, y + POSY_FOUND) & 0x00FFFFFF) == COLOR_FOUND) { + cache.setFound(true); + return; + } + } catch (IllegalArgumentException e) { + // intentionally left blank + } + + return; + } +} diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java index e88a425..1aae560 100644 --- a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java +++ b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java @@ -1,5 +1,8 @@ package cgeo.geocaching.connector.gc; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Representation of a position inside an UTFGrid @@ -11,6 +14,7 @@ public final class UTFGridPosition { public final int x; public final int y; + private final static Pattern PATTERN_JSON_KEY = Pattern.compile("[^\\d]*" + "(\\d+),\\s*(\\d+)" + "[^\\d]*"); // (12, 34) public UTFGridPosition(final int x, final int y) { assert x >= 0 && x <= UTFGrid.GRID_MAXX : "x outside bounds"; @@ -28,4 +32,22 @@ public final class UTFGridPosition { return y; } + /** + * @param key + * Key in the format (xx, xx) + * @return + */ + static UTFGridPosition fromString(String key) { + final Matcher matcher = UTFGridPosition.PATTERN_JSON_KEY.matcher(key); + try { + if (matcher.matches()) { + final int x = Integer.parseInt(matcher.group(1)); + final int y = Integer.parseInt(matcher.group(2)); + return new UTFGridPosition(x, y); + } + } catch (NumberFormatException e) { + } + return new UTFGridPosition(0, 0); + } + } |
