From 05d50bd54cbb2a15d817b71f9c3acdea3cae62e0 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sat, 28 Apr 2012 18:37:20 +0200 Subject: [PATCH] Add map processing --- OsmAnd/jni/osmand/binaryRead.cpp | 194 +++++++++++++----- OsmAnd/jni/osmand/mapObjects.h | 16 +- OsmAnd/jni/osmand/multipolygons.h | 25 +-- .../plus/render/MapRenderRepositories.java | 24 +-- .../plus/render/NativeOsmandLibrary.java | 23 +-- 5 files changed, 171 insertions(+), 111 deletions(-) diff --git a/OsmAnd/jni/osmand/binaryRead.cpp b/OsmAnd/jni/osmand/binaryRead.cpp index a5e4e2d91c..82f3b3c631 100644 --- a/OsmAnd/jni/osmand/binaryRead.cpp +++ b/OsmAnd/jni/osmand/binaryRead.cpp @@ -16,6 +16,7 @@ #include "renderRules.h" #include "common.h" #include "mapObjects.h" +#include "multipolygons.h" //#include "multipolygons.h" #include "proto/osmand_odb.pb.h" @@ -24,6 +25,7 @@ using namespace google::protobuf; using namespace google::protobuf::internal; static const int MAP_VERSION = 2; +static const int BASEMAP_ZOOM = 11; @@ -187,6 +189,11 @@ struct BinaryMapFile { std::string inputName; vector mapIndexes; FILE* f; + bool basemap; + + bool isBasemap(){ + return basemap; + } ~BinaryMapFile() { fclose(f); @@ -410,6 +417,7 @@ bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) { input->PopLimit(oldLimit); input->Seek(mapIndex.filePointer + mapIndex.length); file->mapIndexes.push_back(mapIndex); + file->basemap = file->basemap || mapIndex.name.find("basemap") != string::npos; break; } case OsmAndStructure::kVersionConfirmFieldNumber: { @@ -443,9 +451,6 @@ extern "C" JNIEXPORT void JNICALL Java_net_osmand_plus_render_NativeOsmandLibrar jobject obj, jint searchResult) { SearchResult* result = (SearchResult*) searchResult; if(result != NULL){ - deleteObjects(result->basemapCoastLines); - deleteObjects(result->result); - deleteObjects(result->coastLines); deleteObjects(result->result); delete result; } @@ -850,74 +855,149 @@ void searchMapData(io::CodedInputStream* input, MapRoot* root, MapIndex* ind, Se } -extern "C" JNIEXPORT jint JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_searchObjectsForRendering(JNIEnv* ienv, - jobject obj, jint sleft, jint sright, jint stop, jint sbottom, jint zoom, jstring mapName, - jobject renderingRuleSearchRequest, bool skipDuplicates, jint searchResult, jobject objInterrupted) { - // TODO skipDuplicates not supported - SearchResult* result = (SearchResult*) searchResult; - if(result == NULL) { - result = new SearchResult(); - } - std::string map = getString(ienv, mapName); - std::map::iterator i = openFiles.find(map); - if(i == openFiles.end()) { - return (jint) result; - } - BinaryMapFile* file = i->second; + + + +extern "C" JNIEXPORT jint JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_searchNativeObjectsForRendering(JNIEnv* ienv, + jobject obj, jint sleft, jint sright, jint stop, jint sbottom, jint zoom, jobject renderingRuleSearchRequest, bool skipDuplicates, jobject objInterrupted) { RenderingRuleSearchRequest* req = initSearchRequest(ienv, renderingRuleSearchRequest); jclass clObjInterrupted = ienv->GetObjectClass(objInterrupted); jfieldID interruptedField = getFid(ienv, clObjInterrupted, "interrupted", "Z"); ienv->DeleteLocalRef(clObjInterrupted); + SearchQuery q(sleft,sright, stop, sbottom, req, objInterrupted, interruptedField, ienv); q.zoom = zoom; - fseek(file->f, 0, 0); - io::FileInputStream input(fileno(file->f)); - input.SetCloseOnDelete(false); - io::CodedInputStream cis(&input); - cis.SetTotalBytesLimit(INT_MAX, INT_MAX >> 2); - if(req != NULL){ - req->clearState(); - } + SearchResult* searchRes = new SearchResult(); + std::map::iterator i = openFiles.begin(); + std::hash_set ids; + int count = 0; + bool ocean = false; + std::vector< MapDataObject* > tempResult; + std::vector< MapDataObject* > basemapResult; + std::vector< MapDataObject* > coastLines; + std::vector< MapDataObject* > basemapCoastLines; - for(vector::iterator mapIndex = file->mapIndexes.begin(); - mapIndex != file->mapIndexes.end(); mapIndex++) { - for (vector::iterator mapLevel = mapIndex->levels.begin(); mapLevel != mapIndex->levels.end(); - mapLevel++) { - if (q.isCancelled()) { - break; - } - if(mapLevel->minZoom <= zoom && mapLevel->maxZoom >= zoom) { - if(mapLevel->right >= q.left && q.right >= mapLevel->left && - mapLevel->bottom >= q.top && q.bottom >= mapLevel->top) { - searchMapData(&cis, mapLevel, mapIndex, &q); + for (; i != openFiles.end() && !q.isCancelled(); i++) { + BinaryMapFile* file = i->second; + fseek(file->f, 0, 0); + io::FileInputStream input(fileno(file->f)); + input.SetCloseOnDelete(false); + io::CodedInputStream cis(&input); + cis.SetTotalBytesLimit(INT_MAX, INT_MAX >> 2); + if (req != NULL) { + req->clearState(); + } + q.result.clear(); + for (vector::iterator mapIndex = file->mapIndexes.begin(); mapIndex != file->mapIndexes.end(); + mapIndex++) { + for (vector::iterator mapLevel = mapIndex->levels.begin(); mapLevel != mapIndex->levels.end(); + mapLevel++) { + if (q.isCancelled()) { + break; + } + if (mapLevel->minZoom <= zoom && mapLevel->maxZoom >= zoom) { + if (mapLevel->right >= q.left && q.right >= mapLevel->left && mapLevel->bottom >= q.top + && q.bottom >= mapLevel->top) { + searchMapData(&cis, mapLevel, mapIndex, &q); + } } } } + if (!q.isCancelled()) { + std::vector::iterator r = q.result.begin(); + tempResult.reserve(q.result.size() + tempResult.size()); + for (; r != q.result.end(); r++) { + if (skipDuplicates && (*r)->id > 0) { + if (ids.find((*r)->id) != ids.end()) { + continue; + } + ids.insert((*r)->id); + } + } + count++; + if ((*r)->contains("natural", "coastline")) { + if (i->second->isBasemap()) { + basemapCoastLines.push_back(*r); + } else { + coastLines.push_back(*r); + } + } else { + // do not mess coastline and other types + if (i->second->isBasemap()) { + basemapResult.push_back(*r); + } else { + tempResult.push_back(*r); + } + } + + if (q.ocean) { + ocean = true; + } + } + } - result->result.insert(result->result.end(), q.result.begin(), q.result.end()); - // FIXME process multi polygons -// std::map > multyPolygons; -// std::vector::iterator mdo = q.result.begin(); -// for(;mdo!= q.result.end(); mdo++) { -// for(size_t j = 0; j<(*mdo)->types.size(); j++) { -// int type = (*mdo)->types.at(j); -// if((type & 0x3) == RenderingRulesStorage::MULTI_POLYGON_TYPE) { -// tagValueType tagValue((*mdo)->tagValues.at(j), type); -// multyPolygons[tagValue].push_back(*mdo); -// } -// } -// } -// -// proccessMultiPolygons(multyPolygons, q.left, q.right, q.bottom, q.top, q.zoom, result->result); - __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Search : tree - read( %d), accept( %d), objs - visit( %d), accept(%d), in result(%d) ", q.numberOfReadSubtrees, - q.numberOfAcceptedSubtrees, q.numberOfVisitedObjects, q.numberOfAcceptedObjects, result->result.size()); - if(q.result.size() > 0) { - __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Search : tree - read( %d), accept( %d), objs - visit( %d), accept(%d), in result(%d) ", q.numberOfReadSubtrees, - q.numberOfAcceptedSubtrees, q.numberOfVisitedObjects, q.numberOfAcceptedObjects, result->result.size()); + if (q.isCancelled()) { + deleteObjects(coastLines); + deleteObjects(tempResult); + deleteObjects(basemapCoastLines); + deleteObjects(basemapResult); + } else { + bool addBasemapCoastlines = true; + bool emptyData = zoom > BASEMAP_ZOOM && tempResult.empty() && coastLines.empty(); + + if (!coastLines.empty()) { + // TODO suspicious memory leak? + std::vector< MapDataObject* > pcoastlines; + processCoastlines(coastLines, sleft, sright, sbottom, stop, zoom, + basemapCoastLines.empty(), pcoastlines); + addBasemapCoastlines = pcoastlines.empty() || zoom <= BASEMAP_ZOOM; + tempResult.insert(tempResult.end(), pcoastlines.begin(), pcoastlines.end()); + } + if (addBasemapCoastlines) { + addBasemapCoastlines = false; + // TODO suspicious memory leak? + std::vector< MapDataObject* > pcoastlines; + processCoastlines(basemapCoastLines, sleft, sright, sbottom, + stop, zoom, true, pcoastlines); + addBasemapCoastlines = pcoastlines.empty(); + tempResult.insert(tempResult.end(), pcoastlines.begin(), pcoastlines.end()); + } + if (addBasemapCoastlines) { + MapDataObject* o = new MapDataObject(); + o->points.push_back(int_pair(sleft, stop)); + o->points.push_back(int_pair(sright, stop)); + o->points.push_back(int_pair(sright, sbottom)); + o->points.push_back(int_pair(sleft, sbottom)); + o->points.push_back(int_pair(sleft, stop)); + if (ocean) { + o->types.push_back(tag_value("natural", "coastline")); + } else { + o->types.push_back(tag_value("natural", "land")); + } + tempResult.push_back(o); + } + if (emptyData) { + // message + // avoid overflow int errors + MapDataObject* o = new MapDataObject(); + o->points.push_back(int_pair(sleft + (sright - sleft) / 2, stop + (sbottom - stop) / 2 )); + o->types.push_back(tag_value("natural", "coastline")); + // TODO string + o->objectNames["name"]="Switch To See"; + tempResult.push_back(o); + } + if (zoom <= BASEMAP_ZOOM || emptyData) { + tempResult.insert(tempResult.end(), basemapResult.begin(), basemapResult.end()); + } + searchRes->result.insert(searchRes->result.end(), tempResult.begin(), tempResult.end()); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, + "Search : tree - read( %d), accept( %d), objs - visit( %d), accept(%d), in result(%d) ", + q.numberOfReadSubtrees, q.numberOfAcceptedSubtrees, q.numberOfVisitedObjects, q.numberOfAcceptedObjects, + searchRes->result.size()); } delete req; - return (jint)result; + return (jint)searchRes; } extern "C" JNIEXPORT void JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_closeBinaryMapFile(JNIEnv* ienv, diff --git a/OsmAnd/jni/osmand/mapObjects.h b/OsmAnd/jni/osmand/mapObjects.h index 94600742cb..8aa483d3a0 100644 --- a/OsmAnd/jni/osmand/mapObjects.h +++ b/OsmAnd/jni/osmand/mapObjects.h @@ -46,6 +46,17 @@ public: return false; } + bool contains(std::string key, std::string val) { + std::vector::iterator it = types.begin(); + while (it != types.end()) { + if (it->first == key) { + return it->second == val; + } + it++; + } + return false; + } + int getSimpleLayer() { std::vector::iterator it = additionalTypes.begin(); while (it != additionalTypes.end()) { @@ -69,11 +80,6 @@ public: struct SearchResult { std::vector< MapDataObject* > result; int count; - std::vector< MapDataObject* > tempResult; - std::vector< MapDataObject* > basemapResult; - std::vector< MapDataObject* > coastLines; - std::vector< MapDataObject* > basemapCoastLines; - }; diff --git a/OsmAnd/jni/osmand/multipolygons.h b/OsmAnd/jni/osmand/multipolygons.h index e9011c20c2..e983db72be 100644 --- a/OsmAnd/jni/osmand/multipolygons.h +++ b/OsmAnd/jni/osmand/multipolygons.h @@ -10,23 +10,6 @@ #include "common.h" #include "mapObjects.h" -struct tagValueType { - int type; - std::string tag; - std::string value; - - tagValueType(tag_value t, int type) : type(type) { - tag = t.first; - value = t.second; - } - -}; -bool operator==(const tagValueType& __x, const tagValueType& __y) { - return __x.type == __y.type; -} -bool operator<(const tagValueType& __x, const tagValueType& __y) { - return __x.type < __y.type; -} /// !!! Fuly copied from MapRenderRepositories.java, should be carefully synchroinized bool isClockwiseWay(std::vector& c) ; bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX, @@ -38,6 +21,8 @@ void processMultipolygonLine(std::vector >& completedRings void unifyIncompletedRings(std::vector >& incompletedRings, std::vector >& completedRings, std::vector &completedRingNames, std::vector &incompletedRingNames, int leftX, int rightX, int bottomY, int topY, long dbId, int zoom); + + MapDataObject* processMultiPolygon(int leftX, int rightX, int bottomY, int topY, std::vector >& completedRings, std::vector >& incompletedRings, std::vector& completedRingNames, std::vector& incompletedRingNames, @@ -125,6 +110,12 @@ MapDataObject* processMultiPolygon(int leftX, int rightX, int bottomY, int topY, return pl; } + +void processCoastlines(std::vector& coastLines, int leftX, int rightX, + int bottomY, int topY, int zoom, bool showIncompleted, std::vector& res) { + +} + static std::vector EMPTY_LIST; void proccessMultiPolygons(std::map >& multyPolygons, int leftX, int rightX, int bottomY, int topY, int zoom, std::vector& listPolygons) { diff --git a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java index 62c779d277..00fb7c68a8 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java +++ b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java @@ -267,8 +267,7 @@ public class MapRenderRepositories { int topY = MapUtils.get31TileNumberY(dataBox.top); long now = System.currentTimeMillis(); - // additionally initialize - NativeSearchResult resultHandler = null; + // check that everything is initialized for (String mapName : files.keySet()) { if (!nativeFiles.contains(mapName)) { nativeFiles.add(mapName); @@ -279,19 +278,14 @@ public class MapRenderRepositories { } } - // TODO coastline/land tiles - for (String mapName : files.keySet()) { - BinaryMapIndexReader reader = files.get(mapName); - if(!reader.containsMapData(leftX, topY, rightX, bottomY, zoom)) { - continue; - } - - resultHandler = library.searchObjectsForRendering(leftX, rightX, topY, bottomY, zoom, mapName, renderingReq, - PerformanceFlags.checkForDuplicateObjectIds, resultHandler, this); - if (checkWhetherInterrupted()) { - library.deleteSearchResult(resultHandler); - return false; - } + NativeSearchResult resultHandler = library.searchObjectsForRendering(leftX, rightX, topY, bottomY, zoom, renderingReq, + PerformanceFlags.checkForDuplicateObjectIds, this); + if (checkWhetherInterrupted()) { + library.deleteSearchResult(resultHandler); + return false; + } + if(cNativeObjects != null) { + library.deleteSearchResult(cNativeObjects); } cNativeObjects = resultHandler; cObjectsBox = dataBox; diff --git a/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java b/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java index 2a54dd92dc..b687e10d1e 100644 --- a/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java +++ b/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java @@ -99,21 +99,10 @@ public class NativeOsmandLibrary { * @param searchResultHandle * - must be null if there is no need to append to previous results returns native handle to results */ - public NativeSearchResult searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom, String mapName, - RenderingRuleSearchRequest request, boolean skipDuplicates, NativeSearchResult searchResultHandler, - Object objectWithInterruptedField) { - if (searchResultHandler == null) { - return new NativeSearchResult(searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates, - 0, objectWithInterruptedField)); - } else { - int res = searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates, - searchResultHandler.nativeHandler, objectWithInterruptedField); - if (res == searchResultHandler.nativeHandler) { - return searchResultHandler; - } - return new NativeSearchResult(res); - } - + public NativeSearchResult searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom, + RenderingRuleSearchRequest request, boolean skipDuplicates, Object objectWithInterruptedField) { + return new NativeSearchResult(searchNativeObjectsForRendering(sleft, sright, stop, sbottom, zoom, request, skipDuplicates, + objectWithInterruptedField)); } public void deleteSearchResult(NativeSearchResult searchResultHandler) { @@ -170,8 +159,8 @@ public class NativeOsmandLibrary { Bitmap bitmap, boolean useEnglishNames, RenderingRuleSearchRequest render, int defaultColor); - private static native int searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom, String mapnaem, - RenderingRuleSearchRequest request, boolean skipDuplicates, int searchResultHandler, Object objectWithInterruptedField); + private static native int searchNativeObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom, + RenderingRuleSearchRequest request, boolean skipDuplicates, Object objectWithInterruptedField); public static native int getCpuCount(); public static native boolean cpuHasNeonSupport();