package net.osmand.binary; import gnu.trove.list.array.TIntArrayList; import gnu.trove.set.hash.TIntHashSet; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader.MapIndex; import net.osmand.binary.BinaryMapIndexReader.SearchFilter; import net.osmand.binary.BinaryMapIndexReader.SearchRequest; import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.render.RenderingRulesStorage; import net.osmand.util.MapUtils; public class BinaryMapIndexFilter { private final BinaryMapIndexReader reader; public BinaryMapIndexFilter(File file) throws IOException{ reader = new BinaryMapIndexReader(new RandomAccessFile(file.getPath(), "r"), file); } private static class Stat { int pointCount = 0; int totalCount = 0; int wayCount = 0; int polygonCount = 0; int polygonBigSize = 0; @Override public String toString() { return " ways " + wayCount + " polygons " + polygonCount + " points " + pointCount + " total " + totalCount +"\n"+ " polygons big size " + polygonBigSize; } } private double calculateArea(BinaryMapDataObject o, int zoom){ double sum = 0; for(int i=0; i< o.getPointsLength(); i++){ double x = MapUtils.getTileNumberX(zoom + 8, MapUtils.get31LongitudeX(o.getPoint31XTile(i))); int prev = i == 0 ? o.getPointsLength() - 1 : i -1; int next = i == o.getPointsLength() - 1 ? 0 : i + 1; double y1 = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(prev))); double y2 = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(next))); sum += x * (y1 - y2); } return Math.abs(sum); } private double calculateLength(BinaryMapDataObject o, int zoom){ double sum = 0; for(int i=1; i< o.getPointsLength(); i++){ double x = MapUtils.getTileNumberX(zoom + 8, MapUtils.get31LongitudeX(o.getPoint31XTile(i))); double y = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(i))); double x2 = MapUtils.getTileNumberX(zoom + 8, MapUtils.get31LongitudeX(o.getPoint31XTile(i - 1))); double y2 = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(i - 1))); sum += Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); } return Math.abs(sum); } private int tilesCovers(BinaryMapDataObject o, int zoom, TIntHashSet set){ set.clear(); for(int i=0; i< o.getPointsLength(); i++){ int x = (int) MapUtils.getTileNumberX(zoom, MapUtils.get31LongitudeX(o.getPoint31XTile(i))); int y = (int) MapUtils.getTileNumberY(zoom, MapUtils.get31LatitudeY(o.getPoint31YTile(i))); int val = ((x << 16) | y); set.add(val); } return set.size(); } private Stat process(final int zoom) throws IOException { final Stat stat = new Stat(); final Map<TagValuePair, Integer> map = new HashMap<TagValuePair, Integer>(); SearchFilter sf = new SearchFilter() { @Override public boolean accept(TIntArrayList types, MapIndex index) { boolean polygon = false; boolean polyline = false; for (int j = 0; j < types.size(); j++) { int wholeType = types.get(j); TagValuePair pair = index.decodeType(wholeType); if (pair != null) { int t = wholeType & 3; if (t == RenderingRulesStorage.POINT_RULES) { stat.pointCount++; } else if (t == RenderingRulesStorage.LINE_RULES) { stat.wayCount++; polyline = true; } else { polygon = true; stat.polygonCount++; if (!map.containsKey(pair)) { map.put(pair, 0); } map.put(pair, map.get(pair) + 1); } } } stat.totalCount++; return polyline; } }; ResultMatcher<BinaryMapDataObject> matcher = new ResultMatcher<BinaryMapDataObject>() { TIntHashSet set = new TIntHashSet(); @Override public boolean isCancelled() { return false; } @Override public boolean publish(BinaryMapDataObject object) { // double area = calculateArea(object, zoom); double len = calculateLength(object, zoom); if(/*tilesCovers(object, zoom, set) >= 2 && */ len > 100){ stat.polygonBigSize ++; if(stat.polygonBigSize % 10000 == 0){ return true; } } return false; } }; SearchRequest<BinaryMapDataObject> req = BinaryMapIndexReader.buildSearchRequest(0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, zoom, sf, matcher); List<BinaryMapDataObject> result = reader.searchMapIndex(req); ArrayList<TagValuePair> list = new ArrayList<TagValuePair>(map.keySet()); Collections.sort(list, new Comparator<TagValuePair>() { @Override public int compare(TagValuePair o1, TagValuePair o2) { return -map.get(o1) + map.get(o2); } }); for(TagValuePair tp : list){ Integer i = map.get(tp); if(i > 10){ // System.out.println(tp.toString() + " " + i); } } for(BinaryMapDataObject obj : result){ System.out.println("id " + (obj.getId() >> 3) + " " + calculateArea(obj, zoom)); } return stat; } public static void main(String[] iargs) throws IOException { BinaryMapIndexFilter filter = new BinaryMapIndexFilter(new File("")); for (int i = 10; i <= 14; i++) { Stat st = filter.process(i); System.out.println(i + " zoom -> " + st); } } }