diff --git a/DataExtractionOSM/src/net/osmand/ToDoConstants.java b/DataExtractionOSM/src/net/osmand/ToDoConstants.java index f5068abc59..a3e01aec22 100644 --- a/DataExtractionOSM/src/net/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/net/osmand/ToDoConstants.java @@ -12,8 +12,8 @@ public class ToDoConstants { // Map QuadTree (skip small areas!!!) // Routing index !! - - // Identify coastline areas and pure ocean areas !!! + + // Identify coastline areas and pure ocean areas !!! Show high zoom level for coatline if coastline is broken // TODO Delete/Extract the code with multipolygons ! (coastline)) // Render : different texts support render.xml diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryInspector.java b/DataExtractionOSM/src/net/osmand/binary/BinaryInspector.java index 3cbe5c1ec8..0fd92bd223 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryInspector.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryInspector.java @@ -46,13 +46,7 @@ public class BinaryInspector { public static void main(String[] args) throws IOException { inspector(args); // test cases show info -// inspector(new String[]{"/home/victor/projects/OsmAnd/temp/Belarus_europe.obf"}); -// inspector(new String[]{"-v","C:\\Users\\tpd\\osmand\\Housenumbers.obf"}); - //inspector(new String[]{"/home/victor/projects/OsmAnd/data/osm-gen/saved/Belarus-newzooms-new-rt.obf"}); -// inspector(new String[]{"/home/victor/projects/OsmAnd/download/spain/Spain_europe_1_small.obf"}); - inspector(new String[]{"-vpoi", "/home/victor/projects/OsmAnd/data/osm-gen/10m_coastline_out.obf" - /*"/home/victor/projects/OsmAnd/data/osm-gen/Luxembourg.obf"*/}); - + inspector(new String[]{"/home/victor/projects/OsmAnd/data/osm-gen/basemap_coastlines"}); // test case extract parts @@ -519,7 +513,7 @@ public class BinaryInspector { continue; // throw new NullPointerException("Type " + obj.getAdditionalTypes()[j] + "was not found"); } - b.append(pair.toSimpleString()+"("+types[j]+")"); + b.append(pair.toSimpleString()+" ("+types[j]+")"); } b.append("]"); if(obj.getAdditionalTypes() != null && obj.getAdditionalTypes().length > 0){ diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapDataObject.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapDataObject.java index 09b9b2c9bb..32ac81af6c 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapDataObject.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapDataObject.java @@ -57,6 +57,13 @@ public class BinaryMapDataObject { return objectNames; } + public void putObjectName(int type, String name){ + if(objectNames == null){ + objectNames = new TIntObjectHashMap(); + } + objectNames.put(type, name); + } + public int[][] getPolygonInnerCoordinates() { return polygonInnerCoordinates; } diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java index 4618695448..48afc2cc95 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java @@ -60,6 +60,7 @@ public class BinaryMapIndexReader { private int version; private long dateCreated; // keep them immutable inside + private boolean basemap = false; private List mapIndexes = new ArrayList(); private List poiIndexes = new ArrayList(); private List addressIndexes = new ArrayList(); @@ -72,6 +73,8 @@ public class BinaryMapIndexReader { private final BinaryMapPoiReaderAdapter poiAdapter; private final BinaryMapAddressReaderAdapter addressAdapter; + private static String BASEMAP_NAME = "basemap"; + public BinaryMapIndexReader(final RandomAccessFile raf) throws IOException { this(raf, false); @@ -90,6 +93,7 @@ public class BinaryMapIndexReader { addressIndexes = new ArrayList(referenceToSameFile.addressIndexes); transportIndexes = new ArrayList(referenceToSameFile.transportIndexes); indexes = new ArrayList(referenceToSameFile.indexes); + basemap = referenceToSameFile.basemap; } public BinaryMapIndexReader(final RandomAccessFile raf, boolean readOnlyMapData) throws IOException { @@ -136,6 +140,7 @@ public class BinaryMapIndexReader { mapIndex.filePointer = codedIS.getTotalBytesRead(); int oldLimit = codedIS.pushLimit(mapIndex.length); readMapIndex(mapIndex); + basemap = basemap || mapIndex.isBaseMap(); codedIS.popLimit(oldLimit); codedIS.seek(mapIndex.filePointer + mapIndex.length); mapIndexes.add(mapIndex); @@ -215,6 +220,14 @@ public class BinaryMapIndexReader { return indexes; } + public List getMapIndexes() { + return mapIndexes; + } + + public boolean isBasemap() { + return basemap; + } + public boolean containsMapData(){ return mapIndexes.size() > 0; } @@ -668,6 +681,13 @@ public class BinaryMapIndexReader { case MapDataBox.TOP_FIELD_NUMBER : tree.top = codedIS.readSInt32() + atop; break; + case MapDataBox.OCEAN_FIELD_NUMBER : + if(codedIS.readBool()) { + tree.ocean = Boolean.TRUE; + } else { + tree.ocean = Boolean.FALSE; + } + break; case MapDataBox.SHIFTTOMAPDATA_FIELD_NUMBER : tree.mapDataBlock = readInt() + tree.filePointer; break; @@ -852,7 +872,12 @@ public class BinaryMapIndexReader { foundSubtrees.add(current); break; case MapDataBox.OCEAN_FIELD_NUMBER : - current.ocean = codedIS.readBool(); + if(codedIS.readBool()) { + current.ocean = Boolean.TRUE; + } else { + current.ocean = Boolean.FALSE; + } + req.publishOceanTile(current.ocean); break; case MapDataBox.BOXES_FIELD_NUMBER : // left, ... already initialized @@ -860,8 +885,8 @@ public class BinaryMapIndexReader { child.length = readInt(); child.filePointer = codedIS.getTotalBytesRead(); int oldLimit = codedIS.pushLimit(child.length); - if(current.ocean){ - child.ocean = true; + if(current.ocean != null ){ + child.ocean = current.ocean; } searchMapTreeBounds(child, current, req, foundSubtrees); codedIS.popLimit(oldLimit); @@ -1228,6 +1253,9 @@ public class BinaryMapIndexReader { public static class SearchRequest { private List searchResults = new ArrayList(); + private boolean land = false; + private boolean ocean = false; + private ResultMatcher resultMatcher; // 31 zoom tiles @@ -1276,6 +1304,14 @@ public class BinaryMapIndexReader { return false; } + protected void publishOceanTile(boolean ocean){ + if(ocean) { + this.ocean = true; + } else { + this.land = true; + } + } + public List getSearchResults() { return searchResults; } @@ -1294,11 +1330,21 @@ public class BinaryMapIndexReader { return false; } + public boolean isOcean() { + return ocean; + } + + public boolean isLand() { + return land; + } + public void clearSearchResults(){ // recreate whole list to allow GC collect old data searchResults = new ArrayList(); cacheCoordinates.clear(); cacheTypes.clear(); + land = false; + ocean = false; numberOfVisitedObjects = 0; numberOfAcceptedObjects = 0; numberOfReadSubtrees = 0; @@ -1331,8 +1377,13 @@ public class BinaryMapIndexReader { } public void finishInitializingTags() { - coastlineBrokenEncodingType = decodingRules.size() * 2 + 1; + int free = decodingRules.size() * 2 + 1; + coastlineBrokenEncodingType = free++; initMapEncodingRule(0, coastlineBrokenEncodingType, "natural", "coastline_broken"); + if(landEncodingType == -1){ + landEncodingType = free++; + initMapEncodingRule(0, landEncodingType, "natural", "land"); + } } private void initMapEncodingRule(int type, int id, String tag, String val) { @@ -1366,7 +1417,10 @@ public class BinaryMapIndexReader { } } } - + + public boolean isBaseMap(){ + return name != null && name.toLowerCase().contains(BASEMAP_NAME); + } } public static class TagValuePair { @@ -1455,7 +1509,7 @@ public class BinaryMapIndexReader { int length = 0; long mapDataBlock = 0; - boolean ocean = false; + Boolean ocean = null; int left = 0; int right = 0; @@ -1482,6 +1536,12 @@ public class BinaryMapIndexReader { return filePointer; } + @Override + public String toString(){ + return "Top Lat " + ((float) MapUtils.get31LatitudeY(top)) + " lon " + ((float) MapUtils.get31LongitudeX(left)) + + " Bottom lat " + ((float) MapUtils.get31LatitudeY(bottom)) + " lon " + ((float) MapUtils.get31LongitudeX(right)); + } + } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java b/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java index 68ebc3ed7e..31361a93eb 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java @@ -196,7 +196,6 @@ public class BinaryMapIndexWriter { codedOutStream.writeInt32(OsmandOdb.OsmAndMapIndex.MapRootLevel.RIGHT_FIELD_NUMBER, rightX); codedOutStream.writeInt32(OsmandOdb.OsmAndMapIndex.MapRootLevel.TOP_FIELD_NUMBER, topY); codedOutStream.writeInt32(OsmandOdb.OsmAndMapIndex.MapRootLevel.BOTTOM_FIELD_NUMBER, bottomY); - stackBounds.push(new Bounds(leftX, rightX, topY, bottomY)); } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/CoastlineProcessor.java b/DataExtractionOSM/src/net/osmand/data/preparation/CoastlineProcessor.java index 663aaa1041..8d6ce75926 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/CoastlineProcessor.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/CoastlineProcessor.java @@ -9,7 +9,6 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; @@ -17,14 +16,12 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import javax.xml.stream.XMLStreamException; import net.osmand.Algoritms; import net.osmand.binary.OsmandOdb.MapData; import net.osmand.binary.OsmandOdb.MapDataBlock; -import net.osmand.binary.OsmandOdb.MapDataBlock.Builder; import net.osmand.data.MapAlgorithms; import net.osmand.data.preparation.MapZooms.MapZoomPair; import net.osmand.osm.Entity; @@ -54,20 +51,21 @@ public class CoastlineProcessor { public static final byte TILE_ZOOMLEVEL = 12; private static final byte BITMASK = 0x3; private static final int BITS_COUNT = (1 << TILE_ZOOMLEVEL) * (1 << TILE_ZOOMLEVEL); - + private BitSet seaTileInfo = new BitSet(BITS_COUNT); + private BitSet landTileInfo = new BitSet(BITS_COUNT); private final int zoomWaySmothness; private final MapRenderingTypes renderingTypes; private final MapZooms mapZooms; private final Log logMapDataWarn; - private SimplisticQuadTree quadTree; + private SimplisticQuadTree[] quadTrees; private static class SimplisticQuadTree { - public boolean ocean; - public boolean land; int zoom; int x; int y; + boolean ocean; + boolean land; public SimplisticQuadTree(int x, int y, int zoom) { this.x = x; @@ -76,7 +74,8 @@ public class CoastlineProcessor { } SimplisticQuadTree[] children = null; - List coastlines = null; + Map> coastlines = null; + public SimplisticQuadTree[] getAllChildren(){ initChildren(); @@ -87,11 +86,23 @@ public class CoastlineProcessor { return children != null; } - public void addCoastline(Way w){ + public void addCoastline(MapZoomPair p, Way w){ + if(coastlines == null) { - coastlines = new ArrayList(); + coastlines = new LinkedHashMap>(); } - coastlines.add(w); + if(!coastlines.containsKey(p)){ + coastlines.put(p, new ArrayList()); + } + coastlines.get(p).add(w); + } + + public boolean coastlinesDefined(MapZoomPair p){ + return coastlines != null && coastlines.get(p) != null; + } + + public List getCoastlines(MapZoomPair p) { + return coastlines.get(p); } public SimplisticQuadTree getOrCreateSubTree(int x, int y, int zm) { @@ -127,10 +138,15 @@ public class CoastlineProcessor { this.mapZooms = mapZooms; this.renderingTypes = renderingTypes; this.zoomWaySmothness = zoomWaySmothness; - quadTree = constructTilesQuadTree(); + constructBitSetInfo(); + quadTrees = new SimplisticQuadTree[mapZooms.getLevels().size()]; + for (int i=0;i< mapZooms.getLevels().size(); i++) { + MapZoomPair p = mapZooms.getLevels().get(i); + quadTrees[i] = constructTilesQuadTree(Math.min(p.getMaxZoom() - 1, 1)); + } } - private void constructBitSetInfo(BitSet seaTileInfo , BitSet landTileInfo) { + private void constructBitSetInfo() { try { InputStream stream = CoastlineProcessor.class.getResourceAsStream("oceantiles_12.dat.bz2"); @@ -167,7 +183,7 @@ public class CoastlineProcessor { } } - private boolean isWaterTile(BitSet seaTileInfo, int x, int y, int zoom) { + private boolean isWaterTile(int x, int y, int zoom) { if (zoom >= TILE_ZOOMLEVEL) { int x1 = x >> (zoom - TILE_ZOOMLEVEL); int y1 = y >> (zoom - TILE_ZOOMLEVEL); @@ -190,7 +206,7 @@ public class CoastlineProcessor { } } - private boolean isLandTile(BitSet landTileInfo, int x, int y, int zoom) { + private boolean isLandTile(int x, int y, int zoom) { if (zoom >= TILE_ZOOMLEVEL) { int x1 = x >> (zoom - TILE_ZOOMLEVEL); int y1 = y >> (zoom - TILE_ZOOMLEVEL); @@ -213,83 +229,75 @@ public class CoastlineProcessor { } } - public SimplisticQuadTree constructTilesQuadTree(){ + public SimplisticQuadTree constructTilesQuadTree(int maxZoom){ SimplisticQuadTree rootTree = new SimplisticQuadTree(0, 0, 0); - BitSet seaTileInfo = new BitSet(BITS_COUNT); - BitSet landTileInfo = new BitSet(BITS_COUNT); - constructBitSetInfo(seaTileInfo, landTileInfo); + int baseZoom = 4; int tiles = 1 << baseZoom; ArrayList toVisit = new ArrayList(); - int cnt = 0; for (int x = 0; x < tiles; x++) { for (int y = 0; y < tiles; y++) { toVisit.add(rootTree.getOrCreateSubTree(x, y, baseZoom)); } } - int ntc = 0; - for (int zoom = baseZoom; zoom <= TILE_ZOOMLEVEL && !toVisit.isEmpty(); zoom++) { - cnt = 0; + initializeQuadTree(rootTree, baseZoom, maxZoom, toVisit); + return rootTree; + + } + + protected ArrayList initializeQuadTree(SimplisticQuadTree rootTree, int baseZoom, int maxZoom, + ArrayList toVisit) { + for (int zoom = baseZoom; zoom <= maxZoom && !toVisit.isEmpty(); zoom++) { ArrayList newToVisit = new ArrayList(); for (SimplisticQuadTree subtree : toVisit) { int x = subtree.x; int y = subtree.y; - if (isWaterTile(seaTileInfo, x, y, zoom)) { - cnt++; + if (isWaterTile(x, y, zoom)) { rootTree.getOrCreateSubTree(x, y, zoom).ocean = true; - } else if (isLandTile(landTileInfo, x, y, zoom)) { + } else if (isLandTile(x, y, zoom)) { rootTree.getOrCreateSubTree(x, y, zoom).land = true; - cnt++; } else if(zoom < TILE_ZOOMLEVEL){ SimplisticQuadTree[] vis = rootTree.getOrCreateSubTree(x, y, zoom).getOrCreateSubTree(x, y, zoom) .getAllChildren(); for (SimplisticQuadTree t : vis) { newToVisit.add(t); } - } else { - ntc ++; } } -// System.out.println(" Zoom " + zoom + " count " + cnt); toVisit = newToVisit; } -// System.out.println("Not covered " + ntc + " from " + (float) ntc / ((1 << TILE_ZOOMLEVEL) * (1< refs = new LinkedHashMap(); - writeBinaryMapTree(simplisticQuadTree, writer, refs); + int i = 0; + for (MapZoomPair p : mapZooms.getLevels()) { + // write map levels and map index + writer.startWriteMapLevelIndex(p.getMinZoom(), p.getMaxZoom(), 0, (1 << 31) - 1, 0, (1 << 31) - 1); - // without data blocks - writeBinaryMapBlock(simplisticQuadTree, writer, refs); + Map refs = new LinkedHashMap(); + writeBinaryMapTree(quadTrees[i], writer, refs, p); - writer.endWriteMapLevelIndex(); + // without data blocks + writeBinaryMapBlock(quadTrees[i], writer, refs, p); + writer.endWriteMapLevelIndex(); + i++; + } writer.endWriteMapIndex(); writer.flush(); } private void writeBinaryMapBlock(SimplisticQuadTree simplisticQuadTree, BinaryMapIndexWriter writer, - Map refs) throws IOException { + Map refs, MapZoomPair p) throws IOException { Iterator> it = refs.entrySet().iterator(); TIntArrayList type = new TIntArrayList(); type.add(renderingTypes.getCoastlineRuleType().getTargetId()); @@ -299,10 +307,12 @@ public class CoastlineProcessor { MapDataBlock.Builder dataBlock = MapDataBlock.newBuilder(); SimplisticQuadTree quad = e.getKey(); - for (Way w : quad.coastlines) { + for (Way w : quad.getCoastlines(p)) { dataBlock.setBaseId(w.getId()); + List res = new ArrayList(); + MapAlgorithms.simplifyDouglasPeucker(w.getNodes(), p.getMaxZoom() - 2 + 8 + zoomWaySmothness, 3, res); ByteArrayOutputStream bcoordinates = new ByteArrayOutputStream(); - for (Node n : w.getNodes()) { + for (Node n : res) { if (n != null) { int y = MapUtils.get31TileNumberY(n.getLatitude()); int x = MapUtils.get31TileNumberX(n.getLongitude()); @@ -323,34 +333,40 @@ public class CoastlineProcessor { } private void writeBinaryMapTree(SimplisticQuadTree quadTree, BinaryMapIndexWriter writer, - Map refs) throws IOException { + Map refs, MapZoomPair p) throws IOException { int xL = (quadTree.x) << (31 - quadTree.zoom); - int xR = (quadTree.x + 1) << (31 - quadTree.zoom) - 1; + int xR = ((quadTree.x + 1) << (31 - quadTree.zoom)) - 1; int yT = (quadTree.y) << (31 - quadTree.zoom); - int yB = (quadTree.y + 1) << (31 - quadTree.zoom) - 1; - BinaryFileReference ref = writer.startMapTreeElement(xL, xR, yT, yB, false, - quadTree.ocean, quadTree.land); + int yB = ((quadTree.y + 1) << (31 - quadTree.zoom)) - 1; + boolean defined = quadTree.coastlinesDefined(p); + boolean ocean = false; + boolean land = false; + if (!defined) { + ocean = quadTree.ocean || isWaterTile(quadTree.x, quadTree.y, quadTree.zoom); + land = quadTree.land || isLandTile(quadTree.x, quadTree.y, quadTree.zoom); + } + BinaryFileReference ref = writer.startMapTreeElement(xL, xR, yT, yB, defined, ocean, land); if (ref != null) { refs.put(quadTree, ref); } - + if (quadTree.areChildrenDefined()) { SimplisticQuadTree[] allChildren = quadTree.getAllChildren(); for (SimplisticQuadTree ch : allChildren) { - writeBinaryMapTree(ch, writer, refs); + writeBinaryMapTree(ch, writer, refs, p); } } writer.endWriteMapTreeElement(); - + } public void processCoastline(Way e) { -// for(MapZoomPair p : mapZooms.getLevels()) { renderingTypes.getCoastlineRuleType().updateFreq(); - MapZoomPair p = mapZooms.getLevels().get(mapZooms.getLevels().size() - 1); - { - int z = (p.getMinZoom() + p.getMaxZoom()) / 2; + int ij = 0; + for(MapZoomPair p : mapZooms.getLevels()) { + SimplisticQuadTree quadTree = quadTrees[ij++]; + int z = Math.min((p.getMinZoom() + p.getMaxZoom()) / 2, p.getMinZoom() + 3); List ns = e.getNodes(); if(ns.size() < 2) { return; @@ -380,20 +396,29 @@ public class CoastlineProcessor { int nx31 = MapUtils.get31TileNumberX(next.getLongitude()); int ny31 = MapUtils.get31TileNumberY(next.getLatitude()); // increase boundaries to drop into another tile - int leftX = (tilex << (31 - z)) - 1; + int leftX = (tilex << (31 - z)) - 1; int rightX = (tilex + 1) << (31 - z); - if( rightX < 0 ){ + if (rightX < 0) { rightX = Integer.MAX_VALUE; } - int topY = (tiley << (31 - z)) - 1; + int topY = (tiley << (31 - z)) - 1; int bottomY = (tiley + 1) << (31 - z); - if( bottomY < 0 ){ + if (bottomY < 0) { bottomY = Integer.MAX_VALUE; } - + long inter = MapAlgorithms.calculateIntersection(px31, py31, nx31, ny31, leftX, rightX, bottomY, topY); int cy31 = (int) inter; int cx31 = (int) (inter >> 32l); + if (inter == -1) { + cx31 = nx31; + cy31 = ny31; + i++; + logMapDataWarn.warn("Can't find intersection for " + MapUtils.get31LongitudeX(px31) + "," + + MapUtils.get31LatitudeY(py31) + " - " + +MapUtils.get31LongitudeX(nx31) + "," + + MapUtils.get31LatitudeY(ny31)); + } + prevNode = new Node(MapUtils.get31LatitudeY(cy31), MapUtils.get31LongitudeX(cx31), -1000); px31 = cx31; py31 = cy31; @@ -409,16 +434,16 @@ public class CoastlineProcessor { System.err.println("Tile " + tilex + " / " + tiley + " at " + z + " can not be found"); } } - quad.addCoastline(w); - } + quad.addCoastline(p, w); + } } } - ///////////////////////////// OLD CODE /////////////////////////////// + ///////////////////////////// NOT USED CODE TO DELETE /////////////////////////////// public void processCoastlineOld(Way e) { WayChain chain = null; diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java index 3af551d030..16c23e15aa 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java @@ -641,7 +641,10 @@ public class IndexCreator { // creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/luxembourg.osm.pbf"), // creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/cuba2.osm.bz2"), // new ConsoleProgressImplementation(1), null, zooms, rt, log); - zooms = MapZooms.parseZooms("1-5;6-14"); + // ;6-8;9-14 + zooms = MapZooms.parseZooms("1-3;4-6;7-9;10-14"); + creator.setRegionName("basemap"); + creator.setMapFileName("basemap_coastlines.obf"); creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/basemap/10m_coastline_out.osm"), new ConsoleProgressImplementation(1), null, zooms, rt, log); diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java index a08f149fa4..f86521978d 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java @@ -98,7 +98,6 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { } public void indexMapRelationsAndMultiPolygons(Entity e, OsmDbAccessorContext ctx) throws SQLException { -// indexHighwayRestrictions(e, ctx); indexMultiPolygon(e, ctx); } @@ -558,7 +557,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { closePreparedStatements(mapBinaryStat, mapLowLevelBinaryStat); mapConnection.commit(); if(COASTLINE_PROCESS) { - coastlineProcessor.writeCoastlinesFile(writer); + coastlineProcessor.writeCoastlinesFile(writer, regionName); return; } try { diff --git a/DataExtractionOSM/src/net/osmand/render/default.render.xml b/DataExtractionOSM/src/net/osmand/render/default.render.xml index 3e90749b9a..05c86e3631 100644 --- a/DataExtractionOSM/src/net/osmand/render/default.render.xml +++ b/DataExtractionOSM/src/net/osmand/render/default.render.xml @@ -355,6 +355,8 @@ + + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index c86c63b51e..8ca177574b 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -180,7 +180,7 @@ \n\t\'To compass\' - Map will continuously be aligned with device compass reading \n\tHint: To quickly change between rotation by compass and the one you selected in settings, you can simply tap on the compass needle in map view. - No offline vector map present for this location.\n\t\n\tYou can download one in \'Settings\' -> \'Offline data\', or switch to online maps via \'Settings\' -> \'Map configuration\'. + No offline vector map present for this location. You can download one in Settings (Offline data), or switch to online maps. Download successful.\n\t\n\tTo use activate \'Settings\' -> \'Map configuration\' -> \'Offline vector maps\'. Day/Night Mode diff --git a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java index 81ead92ed2..88fb42c5cf 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java +++ b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java @@ -59,12 +59,12 @@ public class MapRenderRepositories { private final static Log log = LogUtil.getLog(MapRenderRepositories.class); private final Context context; + private final static int BASEMAP_ZOOM = 7; private Handler handler; private Map files = new LinkedHashMap(); private Set nativeFiles = new HashSet(); private OsmandRenderer renderer; - private static String BASEMAP_NAME = "basemap"; // lat/lon box of requested vector data private RectF cObjectsBox = new RectF(); @@ -229,8 +229,8 @@ public class MapRenderRepositories { } public boolean basemapExists() { - for (String f : files.keySet()) { - if (f.toLowerCase().contains(BASEMAP_NAME)) { + for (BinaryMapIndexReader f : files.values()) { + if (f.isBasemap()) { return true; } } @@ -245,21 +245,9 @@ public class MapRenderRepositories { int bottomY = MapUtils.get31TileNumberY(dataBox.bottom); int topY = MapUtils.get31TileNumberY(dataBox.top); long now = System.currentTimeMillis(); - // search lower level zooms only in basemap for now :) before it was intersection of maps on zooms 5-7 - boolean basemapSearch = false; - if (zoom <= 7) { - for (String f : files.keySet()) { - if (f.toLowerCase().contains(BASEMAP_NAME)) { - basemapSearch = true; - break; - } - } - } + // TODO coastline/land tiles NativeSearchResult resultHandler = null; for (String mapName : files.keySet()) { - if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) { - continue; - } BinaryMapIndexReader reader = files.get(mapName); if(!reader.containsMapData(leftX, topY, rightX, bottomY, zoom)) { continue; @@ -301,10 +289,12 @@ public class MapRenderRepositories { } try { int count = 0; - ArrayList tempList = new ArrayList(); + ArrayList tempResult = new ArrayList(); + ArrayList basemapResult = new ArrayList(); System.gc(); // to clear previous objects TLongSet ids = new TLongHashSet(); List coastLines = new ArrayList(); + List basemapCoastLines = new ArrayList(); int leftX = MapUtils.get31TileNumberX(cLeftLongitude); int rightX = MapUtils.get31TileNumberX(cRightLongitude); int bottomY = MapUtils.get31TileNumberY(cBottomLatitude); @@ -340,56 +330,81 @@ public class MapRenderRepositories { if (zoom > 16) { searchFilter = null; } - // search lower level zooms only in basemap for now :) before it was intersection of maps on zooms 5-7 - boolean basemapSearch = false; - if (zoom <= 7) { - for (String f : files.keySet()) { - if (f.toLowerCase().contains(BASEMAP_NAME)) { - basemapSearch = true; - break; - } - } - } - - for (String mapName : files.keySet()) { - if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) { - continue; - } - - BinaryMapIndexReader c = files.get(mapName); - searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter); + boolean ocean = false; + MapIndex mi = null; + searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter); + for (BinaryMapIndexReader c : files.values()) { + searchRequest.clearSearchResults(); List res = c.searchMapIndex(searchRequest); - for (BinaryMapDataObject r : res) { - if (PerformanceFlags.checkForDuplicateObjectIds) { - if (ids.contains(r.getId()) && r.getId() > 0) { - // do not add object twice - continue; + for (BinaryMapDataObject r : res) { + if (PerformanceFlags.checkForDuplicateObjectIds) { + if (ids.contains(r.getId()) && r.getId() > 0) { + // do not add object twice + continue; + } + ids.add(r.getId()); } - ids.add(r.getId()); - } - count++; + count++; - if(r.containsType(r.getMapIndex().coastlineEncodingType)){ - coastLines.add(r); - } else { - // do not mess coastline and other types - tempList.add(r); + if (r.containsType(r.getMapIndex().coastlineEncodingType)) { + if(c.isBasemap()){ + basemapCoastLines.add(r); + } else { + coastLines.add(r); + } + } else { + // do not mess coastline and other types + if(c.isBasemap()){ + basemapResult.add(r); + } else { + tempResult.add(r); + } + } + if (checkWhetherInterrupted()) { + return false; + } } - if (checkWhetherInterrupted()) { - return false; - } - + + if(searchRequest.isOcean() ){ + mi = c.getMapIndexes().get(0); + ocean = true; + } else if(searchRequest.isLand()) { + mi = c.getMapIndexes().get(0); } } String coastlineTime = ""; + boolean addBasemapCoastlines = zoom <= BASEMAP_ZOOM; + boolean emptyData = zoom > BASEMAP_ZOOM && tempResult.isEmpty() && coastLines.isEmpty() ; + if(!coastLines.isEmpty()) { long ms = System.currentTimeMillis(); - - List pcoastlines = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom); - tempList.addAll(pcoastlines); + List pcoastlines = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom, + basemapCoastLines.isEmpty()); + addBasemapCoastlines = pcoastlines.isEmpty() || addBasemapCoastlines; + tempResult.addAll(pcoastlines); + coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )"; + } else if(basemapCoastLines.isEmpty() && mi != null){ + BinaryMapDataObject o = new BinaryMapDataObject(new int[] { leftX, topY, rightX, topY, rightX, bottomY, leftX, bottomY, leftX, + topY }, new int[] { ocean ? mi.coastlineEncodingType : (mi.landEncodingType) }, null, -1); + o.setMapIndex(mi); + tempResult.add(o); + } + if(addBasemapCoastlines){ + long ms = System.currentTimeMillis(); + List pcoastlines = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom, true); + tempResult.addAll(pcoastlines); coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )"; } + if(emptyData && tempResult.size() > 0){ + BinaryMapDataObject o = tempResult.get(0); + o.putObjectName(o.getMapIndex().nameEncodingType, context.getString(R.string.switch_to_raster_map_to_see)); + } + if(zoom <= BASEMAP_ZOOM || tempResult.isEmpty()) { + tempResult.addAll(basemapResult); + } + + if (count > 0) { log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$ cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom)); @@ -397,7 +412,7 @@ public class MapRenderRepositories { } - cObjects = tempList; + cObjects = tempResult; cObjectsBox = dataBox; } catch (IOException e) { log.debug("Search failed", e); //$NON-NLS-1$ @@ -484,6 +499,7 @@ public class MapRenderRepositories { } else { cNativeObjects = null; loaded = loadVectorData(dataBox, requestedBox.getZoom(), renderingReq, nightMode); + } if (!loaded || checkWhetherInterrupted()) { return; @@ -629,7 +645,7 @@ public class MapRenderRepositories { /// MULTI POLYGONS (coastline) private List processCoastlines(List coastLines, int leftX, int rightX, - int bottomY, int topY, int zoom) { + int bottomY, int topY, int zoom, boolean showIncompleted) { List completedRings = new ArrayList(); List uncompletedRings = new ArrayList(); List result = new ArrayList(coastLines.size()); @@ -673,6 +689,11 @@ public class MapRenderRepositories { if (uncompletedRings.size() > 0) { unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom); } + if(!showIncompleted && uncompletedRings.size() > 0){ + result.clear(); + return result; + + } boolean clockwiseFound = false; long mask = 0xffffffffl; for (int i = 0; i < completedRings.size(); i++) { diff --git a/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java b/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java index 1cb4d885f7..906c8615bb 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java +++ b/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java @@ -2,7 +2,6 @@ package net.osmand.plus.render; import net.osmand.access.AccessibleToast; import net.osmand.osm.MapUtils; -import net.osmand.plus.R; import net.osmand.plus.ResourceManager; import net.osmand.plus.RotatedTileBox; import net.osmand.plus.views.BaseMapLayer; @@ -14,7 +13,6 @@ import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; -import android.widget.Toast; public class MapVectorLayer extends BaseMapLayer { @@ -104,14 +102,6 @@ public class MapVectorLayer extends BaseMapLayer { pixRect.set(-view.getWidth() / 3, -view.getHeight() / 4, 4 * view.getWidth() / 3, 5 * view.getHeight() / 4); updateRotatedTileBox(); resourceManager.updateRendererMap(rotatedTileBox); - // does it slow down Map refreshing ? - // Arguments : 1. Map request to read data slows whole process // 2. It works in operating memory - if (warningToSwitchMapShown < 3) { - if (!resourceManager.getRenderer().containsLatLonMapData(view.getLatitude(), view.getLongitude(), view.getZoom())) { - AccessibleToast.makeText(view.getContext(), R.string.switch_to_raster_map_to_see, Toast.LENGTH_LONG).show(); - warningToSwitchMapShown++; - } - } } }