From 868786eefdc0b34fb1cc7c2f1eacc67958a61b00 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 27 May 2012 12:18:46 +0200 Subject: [PATCH] Fix bug with multipolygons --- .../src/net/osmand/data/MapAlgorithms.java | 25 +++--- .../preparation/BinaryMapIndexWriter.java | 28 +++---- .../osmand/data/preparation/IndexCreator.java | 1 - .../preparation/IndexVectorMapCreator.java | 9 +- .../src/net/osmand/render/default.render.xml | 3 +- OsmAnd/res/values/strings.xml | 2 +- .../plus/activities/LocalIndexHelper.java | 4 +- .../plus/render/MapRenderRepositories.java | 83 ++++++++++--------- Osmand-kernel/osmand/src/binaryRead.cpp | 14 ++-- Osmand-kernel/osmand/src/multipolygons.cpp | 31 +++---- 10 files changed, 105 insertions(+), 95 deletions(-) diff --git a/DataExtractionOSM/src/net/osmand/data/MapAlgorithms.java b/DataExtractionOSM/src/net/osmand/data/MapAlgorithms.java index bd039c602b..99372023a4 100644 --- a/DataExtractionOSM/src/net/osmand/data/MapAlgorithms.java +++ b/DataExtractionOSM/src/net/osmand/data/MapAlgorithms.java @@ -285,9 +285,14 @@ public class MapAlgorithms { } } + + + private static long combine2Points(int x, int y) { + return (((long) x ) <<32) | ((long)y ); + } /** - * outx,outy are the coordinates out of the box - * inx,iny are the coordinates from the box + * outx,outy are the coordinates out of the box + * inx,iny are the coordinates from the box (NOT IMPORTANT in/out, just one should be in second out) * @return -1 if there is no instersection or x<<32 | y */ public static long calculateIntersection(int inx, int iny, int outx, int outy, int leftX, int rightX, int bottomY, int topY) { @@ -299,7 +304,7 @@ public class MapAlgorithms { if (leftX <= tx && tx <= rightX) { bx = tx; by = topY; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } if (outy > bottomY && iny <= bottomY) { @@ -307,7 +312,7 @@ public class MapAlgorithms { if (leftX <= tx && tx <= rightX) { bx = tx; by = bottomY; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } if (outx < leftX && inx >= leftX) { @@ -315,7 +320,7 @@ public class MapAlgorithms { if (ty >= topY && ty <= bottomY) { by = ty; bx = leftX; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } @@ -324,7 +329,7 @@ public class MapAlgorithms { if (ty >= topY && ty <= bottomY) { by = ty; bx = rightX; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } @@ -335,7 +340,7 @@ public class MapAlgorithms { if (leftX <= tx && tx <= rightX) { bx = tx; by = topY; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } if (outy < bottomY && iny >= bottomY) { @@ -343,7 +348,7 @@ public class MapAlgorithms { if (leftX <= tx && tx <= rightX) { bx = tx; by = bottomY; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } if (outx > leftX && inx <= leftX) { @@ -351,7 +356,7 @@ public class MapAlgorithms { if (ty >= topY && ty <= bottomY) { by = ty; bx = leftX; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } @@ -360,7 +365,7 @@ public class MapAlgorithms { if (ty >= topY && ty <= bottomY) { by = ty; bx = rightX; - return (((long) bx) << 32) | ((long) by); + return combine2Points(bx, by); } } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java b/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java index 24d20a47e5..ebe8d76632 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/BinaryMapIndexWriter.java @@ -359,19 +359,19 @@ public class BinaryMapIndexWriter { MapData.Builder data = MapData.newBuilder(); // calculate size mapDataBuf.clear(); - int pcalcx = pleft; - int pcalcy = ptop; + int pcalcx = (pleft >> SHIFT_COORDINATES); + int pcalcy = (ptop >> SHIFT_COORDINATES); for (int i = 0; i < coordinates.length / 8; i++) { int x = Algoritms.parseIntFromBytes(coordinates, i * 8); int y = Algoritms.parseIntFromBytes(coordinates, i * 8 + 4); - int tx = (x - pcalcx) >> SHIFT_COORDINATES; - int ty = (y - pcalcy) >> SHIFT_COORDINATES; + int tx = (x >> SHIFT_COORDINATES) - pcalcx; + int ty = (y >> SHIFT_COORDINATES) - pcalcy; writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(tx)); writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(ty)); - pcalcx = pcalcx + (tx << SHIFT_COORDINATES); - pcalcy = pcalcy + (ty << SHIFT_COORDINATES); + pcalcx = pcalcx + tx ; + pcalcy = pcalcy + ty ; } COORDINATES_SIZE += CodedOutputStream.computeRawVarint32Size(mapDataBuf.size()) + CodedOutputStream.computeTagSize(MapData.COORDINATES_FIELD_NUMBER) + mapDataBuf.size(); @@ -383,8 +383,8 @@ public class BinaryMapIndexWriter { if (innerPolygonTypes != null && innerPolygonTypes.length > 0) { mapDataBuf.clear(); - pcalcx = pleft; - pcalcy = ptop; + pcalcx = (pleft >> SHIFT_COORDINATES); + pcalcy = (ptop >> SHIFT_COORDINATES); for (int i = 0; i < innerPolygonTypes.length / 8; i++) { int x = Algoritms.parseIntFromBytes(innerPolygonTypes, i * 8); int y = Algoritms.parseIntFromBytes(innerPolygonTypes, i * 8 + 4); @@ -393,17 +393,17 @@ public class BinaryMapIndexWriter { data.addPolygonInnerCoordinates(ByteString.copyFrom(mapDataBuf.toArray())); mapDataBuf.clear(); } - pcalcx = pleft; - pcalcy = ptop; + pcalcx = (pleft >> SHIFT_COORDINATES); + pcalcy = (ptop >> SHIFT_COORDINATES); } else { - int tx = (x - pcalcx) >> SHIFT_COORDINATES; - int ty = (y - pcalcy) >> SHIFT_COORDINATES; + int tx = (x >> SHIFT_COORDINATES) - pcalcx; + int ty = (y >> SHIFT_COORDINATES) - pcalcy; writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(tx)); writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(ty)); - pcalcx = pcalcx + (tx << SHIFT_COORDINATES); - pcalcy = pcalcy + (ty << SHIFT_COORDINATES); + pcalcx = pcalcx + tx ; + pcalcy = pcalcy + ty ; } } } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java index 342f9ddf15..c2083e3070 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java @@ -743,7 +743,6 @@ public class IndexCreator { public static void main(String[] args) throws IOException, SAXException, SQLException, InterruptedException { - long time = System.currentTimeMillis(); IndexCreator creator = new IndexCreator(new File("/home/victor/projects/OsmAnd/data/osm-gen/")); //$NON-NLS-1$ creator.setIndexMap(true); diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java index bde99fbb58..787fe287da 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java @@ -96,9 +96,11 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { boolean inner = "inner".equals(entities.get(es)); //$NON-NLS-1$ if (!inner) { outerFound = true; - for (String t : es.getTagKeySet()) { - e.putTag(t, es.getTag(t)); - } + // This is incorrect (it should be intersection of all boundaries) + // Currently it causes an issue with coastline (if one line is coastline) +// for (String t : es.getTagKeySet()) { +// e.putTag(t, es.getTag(t)); +// } break; } } @@ -518,7 +520,6 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { if (hasMulti) { TIntArrayList set = multiPolygonsWays.get(e.getId()); typeUse.removeAll(set); - continue; } if (typeUse.isEmpty()) { continue; diff --git a/DataExtractionOSM/src/net/osmand/render/default.render.xml b/DataExtractionOSM/src/net/osmand/render/default.render.xml index 5f67adb5a9..3c0d9397fe 100644 --- a/DataExtractionOSM/src/net/osmand/render/default.render.xml +++ b/DataExtractionOSM/src/net/osmand/render/default.render.xml @@ -195,8 +195,7 @@ - - + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index e11a35d4d2..c5012b0419 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -4,7 +4,7 @@ Disclaimer : If you are going to translate strings, please make sure : 1. There is no duplicate strings by name - 2. Every apostrophe is started with quote (look others). + 2. Every apostrophe (quote) is preceded by a backslash (see others). If you are making/correcting english translations make sure : 1. All your modified/created strings are in the top of the file (to make easier find what's translated). --> diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java index 21e4e0269a..10a08c5ab5 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java @@ -206,10 +206,10 @@ public class LocalIndexHelper { Map loadedMaps = app.getResourceManager().getIndexFileNames(); List result = new ArrayList(); - loadTilesData(settings.extendOsmandPath(ResourceManager.TILES_PATH), result, false, loadTask); - loadTilesData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, false, loadTask); loadObfData(settings.extendOsmandPath(ResourceManager.MAPS_PATH), result, false, loadTask, loadedMaps); loadObfData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, true, loadTask, loadedMaps); + loadTilesData(settings.extendOsmandPath(ResourceManager.TILES_PATH), result, false, loadTask); + loadTilesData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, false, loadTask); loadPoiData(settings.extendOsmandPath(ResourceManager.POI_PATH), result, false, loadTask); loadPoiData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, true, loadTask); loadVoiceData(settings.extendOsmandPath(ResourceManager.VOICE_PATH), result, false, loadTask); diff --git a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java index 67949a2e8d..a55209b9c3 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java +++ b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java @@ -401,18 +401,16 @@ public class MapRenderRepositories { if(!coastLines.isEmpty()) { long ms = System.currentTimeMillis(); - List pcoastlines = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom, - basemapCoastLines.isEmpty()); - addBasemapCoastlines = pcoastlines.isEmpty() || zoom <= BASEMAP_ZOOM; - tempResult.addAll(pcoastlines); + boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom, + basemapCoastLines.isEmpty(), true, tempResult); + addBasemapCoastlines = !coastlinesWereAdded || zoom <= BASEMAP_ZOOM; coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )"; } if(addBasemapCoastlines){ - addBasemapCoastlines = false; long ms = System.currentTimeMillis(); - List pcoastlines = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom, true); - addBasemapCoastlines = pcoastlines.isEmpty(); - tempResult.addAll(pcoastlines); + boolean coastlinesWereAdded = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom, + true, true, tempResult); + addBasemapCoastlines = !coastlinesWereAdded; coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )"; } if(addBasemapCoastlines && mi != null){ @@ -673,11 +671,11 @@ public class MapRenderRepositories { } /// MULTI POLYGONS (coastline) - private List processCoastlines(List coastLines, int leftX, int rightX, - int bottomY, int topY, int zoom, boolean showIncompleted) { + // returns true if coastlines were added! + private boolean processCoastlines(List coastLines, int leftX, int rightX, + int bottomY, int topY, int zoom, boolean doNotAddIfIncompleted, boolean addDebugIncompleted, List result) { List completedRings = new ArrayList(); List uncompletedRings = new ArrayList(); - List result = new ArrayList(coastLines.size()); MapIndex mapIndex = null; long dbId = 0; for (BinaryMapDataObject o : coastLines) { @@ -694,7 +692,7 @@ public class MapRenderRepositories { int y = py; boolean pinside = leftX <= x && x <= rightX && y >= topY && y <= bottomY; if (pinside) { - coordinates.add((((long) x) << 32) | ((long) y)); + coordinates.add(combine2Points(x, y)); } for (int i = 1; i < len; i++) { x = o.getPoint31XTile(i); @@ -713,18 +711,29 @@ public class MapRenderRepositories { combineMultipolygonLine(completedRings, uncompletedRings, coordinates); } if (completedRings.size() == 0 && uncompletedRings.size() == 0) { - return result; + return false; } if (uncompletedRings.size() > 0) { unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom); } - if(!showIncompleted && uncompletedRings.size() > 0){ - result.clear(); - return result; - + long mask = 0xffffffffl; + // draw uncompleted for debug purpose + for (int i = 0; i < uncompletedRings.size(); i++) { + TLongList ring = uncompletedRings.get(i); + int[] coordinates = new int[ring.size() * 2]; + for (int j = 0; j < ring.size(); j++) { + coordinates[j * 2] = (int) (ring.get(j) >> 32); + coordinates[j * 2 + 1] = (int) (ring.get(j) & mask); + } + BinaryMapDataObject o = new BinaryMapDataObject(coordinates, new int[] { mapIndex.coastlineBrokenEncodingType }, null, dbId); + o.setMapIndex(mapIndex); + result.add(o); + } + if(!doNotAddIfIncompleted && uncompletedRings.size() > 0){ + return false; } boolean clockwiseFound = false; - long mask = 0xffffffffl; + for (int i = 0; i < completedRings.size(); i++) { TLongList ring = completedRings.get(i); int[] coordinates = new int[ring.size() * 2]; @@ -741,18 +750,6 @@ public class MapRenderRepositories { result.add(o); } - // draw uncompleted for debug purpose - for (int i = 0; i < uncompletedRings.size(); i++) { - TLongList ring = uncompletedRings.get(i); - int[] coordinates = new int[ring.size() * 2]; - for (int j = 0; j < ring.size(); j++) { - coordinates[j * 2] = (int) (ring.get(j) >> 32); - coordinates[j * 2 + 1] = (int) (ring.get(j) & mask); - } - BinaryMapDataObject o = new BinaryMapDataObject(coordinates, new int[] { mapIndex.coastlineBrokenEncodingType}, null, dbId); - o.setMapIndex(mapIndex); - result.add(o); - } if (!clockwiseFound && uncompletedRings.size() == 0) { // add complete water tile BinaryMapDataObject o = new BinaryMapDataObject(new int[] { leftX, topY, rightX, topY, rightX, bottomY, leftX, bottomY, leftX, @@ -762,23 +759,27 @@ public class MapRenderRepositories { result.add(o); } - return result; + return true; } - + + private boolean eq(long i1, long i2){ + return i1 == i2; + } + private void combineMultipolygonLine(List completedRings, List incompletedRings, TLongList coordinates) { if (coordinates.size() > 0) { - if (coordinates.get(0) == coordinates.get(coordinates.size() - 1)) { + if (eq(coordinates.get(0), coordinates.get(coordinates.size() - 1))) { completedRings.add(coordinates); } else { boolean add = true; for (int k = 0; k < incompletedRings.size();) { boolean remove = false; TLongList i = incompletedRings.get(k); - if (coordinates.get(0) == i.get(i.size() - 1)) { + if (eq(coordinates.get(0), i.get(i.size() - 1))) { i.addAll(coordinates.subList(1, coordinates.size())); remove = true; coordinates = i; - } else if (coordinates.get(coordinates.size() - 1) == i.get(0)) { + } else if (eq(coordinates.get(coordinates.size() - 1), i.get(0))) { coordinates.addAll(i.subList(1, i.size())); remove = true; } @@ -787,7 +788,7 @@ public class MapRenderRepositories { } else { k++; } - if (coordinates.get(0) == coordinates.get(coordinates.size() - 1)) { + if (eq(coordinates.get(0), coordinates.get(coordinates.size() - 1))) { completedRings.add(coordinates); add = false; break; @@ -958,6 +959,10 @@ public class MapRenderRepositories { return res; } + private static long combine2Points(int x, int y) { + return (((long) x ) <<32) | ((long)y ); + } + private boolean calculateLineCoordinates(boolean inside, int x, int y, boolean pinside, int px, int py, int leftX, int rightX, int bottomY, int topY, TLongList coordinates) { boolean lineEnded = false; @@ -966,19 +971,19 @@ public class MapRenderRepositories { long is = MapAlgorithms.calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY); if (is == -1) { // it is an error (!) - is = (((long) px) << 32) | ((long) py); + is = combine2Points(px, py); } coordinates.add(is); lineEnded = true; } else { - coordinates.add((((long) x) << 32) | ((long) y)); + coordinates.add(combine2Points(x, y)); } } else { long is = MapAlgorithms.calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY); if (inside) { // assert is != -1; coordinates.add(is); - coordinates.add((((long) x) << 32) | ((long) y)); + coordinates.add(combine2Points(x, y)); } else if (is != -1) { int bx = (int) (is >> 32); int by = (int) (is & 0xffffffff); diff --git a/Osmand-kernel/osmand/src/binaryRead.cpp b/Osmand-kernel/osmand/src/binaryRead.cpp index 467fdeefa6..4331f299df 100644 --- a/Osmand-kernel/osmand/src/binaryRead.cpp +++ b/Osmand-kernel/osmand/src/binaryRead.cpp @@ -784,17 +784,15 @@ ResultPublisher* searchObjectsForRendering(SearchQuery* q, bool skipDuplicates, bool addBasemapCoastlines = true; bool emptyData = q->zoom > BASEMAP_ZOOM && tempResult.empty() && coastLines.empty(); if (!coastLines.empty()) { - std::vector pcoastlines; - processCoastlines(coastLines, q->left, q->right, q->bottom, q->top, q->zoom, basemapCoastLines.empty(), pcoastlines); - addBasemapCoastlines = pcoastlines.empty() || q->zoom <= BASEMAP_ZOOM; - tempResult.insert(tempResult.end(), pcoastlines.begin(), pcoastlines.end()); + bool coastlinesWereAdded = processCoastlines(coastLines, q->left, q->right, q->bottom, q->top, q->zoom, + basemapCoastLines.empty(), true, tempResult); + addBasemapCoastlines = !coastlinesWereAdded || q->zoom <= BASEMAP_ZOOM; } if (addBasemapCoastlines) { addBasemapCoastlines = false; - std::vector pcoastlines; - processCoastlines(basemapCoastLines, q->left, q->right, q->bottom, q->top, q->zoom, true, pcoastlines); - addBasemapCoastlines = pcoastlines.empty(); - tempResult.insert(tempResult.end(), pcoastlines.begin(), pcoastlines.end()); + bool coastlinesWereAdded = processCoastlines(basemapCoastLines, q->left, q->right, q->bottom, q->top, q->zoom, + true, true, tempResult); + addBasemapCoastlines = !coastlinesWereAdded; } // processCoastlines always create new objects deleteObjects(basemapCoastLines); diff --git a/Osmand-kernel/osmand/src/multipolygons.cpp b/Osmand-kernel/osmand/src/multipolygons.cpp index 59c94b667a..f7b63ceb7f 100644 --- a/Osmand-kernel/osmand/src/multipolygons.cpp +++ b/Osmand-kernel/osmand/src/multipolygons.cpp @@ -4,12 +4,12 @@ #include "multipolygons.h" #include "osmand_log.h" -void processCoastlines(std::vector& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom, - bool showIncompleted, std::vector& res) { +// returns true if coastlines were added! +bool processCoastlines(std::vector& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom, + bool showIfThereIncompleted, bool addDebugIncompleted, std::vector& res) { std::vector completedRings; std::vector uncompletedRings; std::vector::iterator val = coastLines.begin(); - res.reserve(coastLines.size()); long long dbId = 0; for (; val != coastLines.end(); val++) { MapDataObject* o = *val; @@ -44,14 +44,23 @@ void processCoastlines(std::vector& coastLines, int leftX, int combineMultipolygonLine(completedRings, uncompletedRings, *cs); } if (completedRings.size() == 0 && uncompletedRings.size() == 0) { - return; + return false; } if (uncompletedRings.size() > 0) { unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom); } - if (!showIncompleted && uncompletedRings.size() > 0) { - res.clear(); - return; + if (addDebugIncompleted) { + // draw uncompleted for debug purpose + for (int i = 0; i < uncompletedRings.size(); i++) { + MapDataObject* o = new MapDataObject(); + o->points = uncompletedRings[i]; + o->types.push_back(tag_value("natural", "coastline_broken")); + res.push_back(o); + } + + } + if (!showIfThereIncompleted && uncompletedRings.size() > 0) { + return false; } bool clockwiseFound = false; for (int i = 0; i < completedRings.size(); i++) { @@ -69,13 +78,6 @@ void processCoastlines(std::vector& coastLines, int leftX, int res.push_back(o); } - // draw uncompleted for debug purpose - for (int i = 0; i < uncompletedRings.size(); i++) { - MapDataObject* o = new MapDataObject(); - o->points = uncompletedRings[i]; - o->types.push_back(tag_value("natural", "coastline_broken")); - //res.push_back(o); - } if (!clockwiseFound && uncompletedRings.size() == 0) { // add complete water tile MapDataObject* o = new MapDataObject(); @@ -90,6 +92,7 @@ void processCoastlines(std::vector& coastLines, int leftX, int res.push_back(o); } + return true; } // Copied from MapAlgorithms