Implement C++ read

This commit is contained in:
Victor Shcherb 2011-10-29 16:57:27 +02:00
parent 99029a0785
commit d8bf714a03
15 changed files with 1093 additions and 13569 deletions

View file

@ -34,7 +34,7 @@ public class BinaryInspector {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
inspector(args); inspector(args);
// test cases show info // test cases show info
//inspector(new String[]{"/home/victor/projects/OsmAnd/data/osm-gen/saved/Belarus-newzooms-new-rt.obf"}); // inspector(new String[]{"/home/victor/projects/OsmAnd/temp/Belarus_europe.obf"});
// inspector(new String[]{"-v","C:\\Users\\tpd\\osmand\\Housenumbers.obf"}); // inspector(new String[]{"-v","C:\\Users\\tpd\\osmand\\Housenumbers.obf"});

View file

@ -56,9 +56,9 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH) \
$(ANDROID_FOLDER)/frameworks/base/include $(ANDROID_FOLDER)/frameworks/base/include
LOCAL_CPP_EXTENSION := .cpp LOCAL_CPP_EXTENSION := .cpp
LOCAL_SRC_FILES := common.cpp \ LOCAL_SRC_FILES := common.cpp mapObjects.cpp \
renderRules.cpp rendering.cpp \ renderRules.cpp rendering.cpp \
proto/osmand_odb.pb.cpp binaryRead.cpp binaryRead.cpp
LOCAL_CFLAGS := -Wall -g -DGOOGLE_PROTOBUF_NO_RTTI LOCAL_CFLAGS := -Wall -g -DGOOGLE_PROTOBUF_NO_RTTI
# in that case libskia_2.2.so should be in NDK folder to be properly built # in that case libskia_2.2.so should be in NDK folder to be properly built

View file

@ -6,16 +6,19 @@
#include <stdio.h> #include <stdio.h>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <hash_map>
#include "google/protobuf/io/zero_copy_stream_impl.h" #include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/wire_format_lite.h" #include "google/protobuf/wire_format_lite.h"
#include "google/protobuf/wire_format_lite.cc" #include "google/protobuf/wire_format_lite.cc"
#include "google/protobuf/wire_format.h"
#include "renderRules.h"
#include "common.h" #include "common.h"
#include "mapObjects.h"
#include "proto/osmand_odb.pb.h" #include "proto/osmand_odb.pb.h"
char errorMsg[1024]; char errorMsg[1024];
#define INT_MAX 0x7fffffff /* max value for an int */ #define INT_MAX 0x7fffffff /* max value for an int */
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
using namespace google::protobuf; using namespace google::protobuf;
using namespace google::protobuf::internal; using namespace google::protobuf::internal;
@ -24,16 +27,16 @@ std::map<std::string, BinaryMapFile*> openFiles;
inline bool readInt(io::CodedInputStream* input, uint32* sz) { inline bool readInt(io::CodedInputStream* input, uint32* sz) {
uint8 buf[4]; uint8 buf[4];
if(!input->ReadRaw(buf, 4)){ if (!input->ReadRaw(buf, 4)) {
return false; return false;
} }
*sz = ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0)); *sz = ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0));
return true; return true;
} }
bool skipFixed32(io::CodedInputStream* input){ bool skipFixed32(io::CodedInputStream* input) {
uint32 sz; uint32 sz;
if(!readInt(input, &sz)) { if (!readInt(input, &sz)) {
return false; return false;
} }
return input->Skip(sz); return input->Skip(sz);
@ -44,26 +47,267 @@ bool skipUnknownFields(io::CodedInputStream* input, int tag) {
if (!skipFixed32(input)) { if (!skipFixed32(input)) {
return false; return false;
} }
} else if (!WireFormat::SkipField(input, tag, NULL)) { } else if (!WireFormatLite::SkipField(input, tag)) {
return false; return false;
} }
return true; return true;
} }
struct BinaryMapFile { struct SearchQuery {
io::FileInputStream* input; RenderingRuleSearchRequest* req;
std::string inputName; int left;
int right;
int top;
int bottom;
int zoom;
SearchResult* res;
~BinaryMapFile() { std::vector<std::pair<int, int> > cacheCoordinates;
input->Close(); std::vector<int> cacheTypes;
delete input; std::vector<std::pair< std::string, std::string> > cacheTagValues;
int numberOfVisitedObjects;
int numberOfAcceptedObjects;
int numberOfReadSubtrees;
int numberOfAcceptedSubtrees;
bool interrupted;
SearchQuery(int l, int r, int t, int b, RenderingRuleSearchRequest* req, SearchResult* res) :
req(req), left(l), right(r), top(t), bottom(b), res(res) {
numberOfAcceptedObjects = numberOfVisitedObjects = 0;
numberOfAcceptedSubtrees = numberOfReadSubtrees = 0;
interrupted = false;
}
bool isCancelled(){
return interrupted;
} }
}; };
struct MapTreeBounds {
uint32 length;
int filePointer;
int left ;
int right ;
int top ;
int bottom;
};
struct MapRoot {
uint32 length;
int filePointer;
int minZoom ;
int maxZoom ;
int left ;
int right ;
int top ;
int bottom;
vector<MapTreeBounds> bounds;
};
struct MapIndex {
uint32 length;
int filePointer;
std::string name;
std::hash_map<int, std::pair<std::string, std::string> > decodingRules;
vector<MapRoot> levels;
};
struct BinaryMapFile {
std::string inputName;
vector<MapIndex> mapIndexes;
FILE* f;
~BinaryMapFile() {
fclose(f);
}
};
bool readMapTreeBounds(io::CodedInputStream* input, MapTreeBounds* tree, MapRoot* root) {
int init = 0;
int tag;
while ((tag = input->ReadTag()) != 0) {
switch (WireFormatLite::GetTagFieldNumber(tag)) {
case MapTree::kLeftFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &tree->left)));
tree->left += root->left;
break;
}
case MapTree::kRightFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &tree->right)));
tree->right += root->right;
break;
}
case MapTree::kTopFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &tree->top)));
tree->top += root->top;
break;
}
case MapTree::kBottomFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &tree->bottom)));
tree->bottom += root->bottom;
break;
}
default: {
if (WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
if (!skipUnknownFields(input, tag)) {
return false;
}
break;
}
}
if (init == 0xf) {
return true;
}
}
return true;
}
bool readMapLevel(io::CodedInputStream* input, MapRoot* root) {
int tag;
while ((tag = input->ReadTag()) != 0) {
switch (WireFormatLite::GetTagFieldNumber(tag)) {
case MapRootLevel::kMaxZoomFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &root->maxZoom)));
break;
}
case MapRootLevel::kMinZoomFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &root->minZoom)));
break;
}
case MapRootLevel::kBottomFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &root->bottom)));
break;
}
case MapRootLevel::kTopFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &root->top)));
break;
}
case MapRootLevel::kLeftFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &root->left)));
break;
}
case MapRootLevel::kRightFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &root->right)));
break;
}
case MapRootLevel::kRootFieldNumber: {
MapTreeBounds mapBounds;
readInt(input, &mapBounds.length);
mapBounds.filePointer = input->getTotalBytesRead();
int oldLimit = input->PushLimit(mapBounds.length);
readMapTreeBounds(input, &mapBounds, root);
input->Skip(input->BytesUntilLimit());
input->PopLimit(oldLimit);
root->bounds.push_back(mapBounds);
break;
}
default: {
if (WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
if (!skipUnknownFields(input, tag)) {
return false;
}
break;
}
}
}
return true;
}
bool readMapEncodingRule(io::CodedInputStream* input, MapIndex* index) {
int tag;
std::string tagS;
std::string value;
uint32 type = 0;
uint32 subtype = 0;
while ((tag = input->ReadTag()) != 0) {
switch (WireFormatLite::GetTagFieldNumber(tag)) {
case MapEncodingRule::kValueFieldNumber: {
DO_((WireFormatLite::ReadString(input, &value)));
break;
}
case MapEncodingRule::kTagFieldNumber: {
DO_((WireFormatLite::ReadString(input, &tagS)));
break;
}
case MapEncodingRule::kTypeFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &type)));
break;
}
case MapEncodingRule::kSubtypeFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &subtype)));
break;
}
default: {
if (WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
if (!skipUnknownFields(input, tag)) {
return false;
}
break;
}
}
}
int ind = ((subtype << 5) | type);
// Special case for check to not replace primary with primary_link
if(index->decodingRules.find(ind) == index->decodingRules.end()) {
index->decodingRules[ind] = std::pair < std::string, std::string > (tagS, value);
}
return true;
}
bool readMapIndex(io::CodedInputStream* input, MapIndex* mapIndex) {
uint32 tag;
while ((tag = input->ReadTag()) != 0) {
switch (WireFormatLite::GetTagFieldNumber(tag)) {
case OsmAndMapIndex::kNameFieldNumber: {
DO_((WireFormatLite::ReadString(input, &mapIndex->name)));
break;
}
case OsmAndMapIndex::kRulesFieldNumber: {
int len;
WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &len);
int oldLimit = input->PushLimit(len);
readMapEncodingRule(input, mapIndex);
input->PopLimit(oldLimit);
break;
}
case OsmAndMapIndex::kLevelsFieldNumber: {
MapRoot mapLevel;
readInt(input, &mapLevel.length);
mapLevel.filePointer = input->getTotalBytesRead();
int oldLimit = input->PushLimit(mapLevel.length);
readMapLevel(input, &mapLevel);
input->PopLimit(oldLimit);
input->Seek(mapLevel.filePointer + mapLevel.length);
mapIndex->levels.push_back(mapLevel);
break;
}
default: {
if (WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
if (!skipUnknownFields(input, tag)) {
return false;
}
break;
}
}
}
return true;
}
//display google::protobuf::internal::WireFormatLite::GetTagWireType(tag) //display google::protobuf::internal::WireFormatLite::GetTagWireType(tag)
// display google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag) // display google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)
bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) { bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
uint32 tag; uint32 tag;
uint32 version = -1; uint32 version = -1;
uint32 versionConfirm = -2; uint32 versionConfirm = -2;
@ -74,10 +318,17 @@ bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &version))); DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &version)));
break; break;
} }
// case OsmAndStructure::kMapIndexFieldNumber : { case OsmAndStructure::kMapIndexFieldNumber: {
// // TODO MapIndex mapIndex;
// break; readInt(input, &mapIndex.length);
// } mapIndex.filePointer = input->getTotalBytesRead();
int oldLimit = input->PushLimit(mapIndex.length);
readMapIndex(input, &mapIndex);
input->PopLimit(oldLimit);
input->Seek(mapIndex.filePointer + mapIndex.length);
file->mapIndexes.push_back(mapIndex);
break;
}
case OsmAndStructure::kVersionConfirmFieldNumber: { case OsmAndStructure::kVersionConfirmFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &versionConfirm))); DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &versionConfirm)));
break; break;
@ -89,7 +340,6 @@ bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
if (!skipUnknownFields(input, tag)) { if (!skipUnknownFields(input, tag)) {
return false; return false;
} }
break; break;
} }
} }
@ -99,28 +349,398 @@ bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
"Corrupted file. It should be ended as it starts with version"); "Corrupted file. It should be ended as it starts with version");
return false; return false;
} }
#undef DO_
return true; return true;
} }
void loadJniBinaryRead() { void loadJniBinaryRead() {
} }
extern "C" extern "C" JNIEXPORT void JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_deleteSearchResult(JNIEnv* ienv,
JNIEXPORT jboolean JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_initBinaryMapFile(JNIEnv* ienv, jobject obj, jint searchResult) {
setGlobalEnv(ienv);
SearchResult* result = (SearchResult*) searchResult;
if(result != NULL){
delete result;
}
}
bool readStringTable(io::CodedInputStream* input, std::vector<std::string>& list) {
uint32 tag;
while ((tag = input->ReadTag()) != 0) {
switch (WireFormatLite::GetTagFieldNumber(tag)) {
case StringTable::kSFieldNumber: {
std::string s;
WireFormatLite::ReadString(input, &s);
list.push_back(s);
break;
}
default: {
if (WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) {
return false;
}
if (!skipUnknownFields(input, tag)) {
return false;
}
break;
}
}
}
return true;
}
static const int SHIFT_COORDINATES = 5;
static const int MASK_TO_READ = ~((1 << SHIFT_COORDINATES) - 1);
static const int MASK_10 = (1 << 10) - 1;
BaseMapDataObject* readMapDataObject(io::CodedInputStream* input, int left, int right, int top, int bottom, SearchQuery* req,
MapIndex* root) {
uint32 tag = input->ReadTag();
if (MapData::kCoordinatesFieldNumber != WireFormatLite::GetTagFieldNumber(tag)) {
return NULL;
}
req->cacheCoordinates.clear();
uint32 size;
input->ReadVarint32(&size);
int old = input->PushLimit(size);
int px = left & MASK_TO_READ;
int py = top & MASK_TO_READ;
bool contains = false;
int minX = INT_MAX;
int maxX = 0;
int minY = INT_MAX;
int maxY = 0;
req->numberOfVisitedObjects++;
int x;
int y;
while (input->BytesUntilLimit() > 0) {
if (!WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &x)) {
return NULL;
}
if (!WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &y)) {
return NULL;
}
x = (x << SHIFT_COORDINATES) + px;
y = (y << SHIFT_COORDINATES) + py;
req->cacheCoordinates.push_back(std::pair<int, int>(x, y));
px = x;
py = y;
if (!contains && req->left <= x && req->right >= x && req->top <= y && req->bottom >= y) {
contains = true;
}
if (!contains) {
minX = min(minX, x);
maxX = max(maxX, x);
minY = min(minY, y);
maxY = max(maxY, y);
}
}
if (!contains) {
if (maxX >= req->left && minX <= req->right && minY <= req->bottom && maxY >= req->top) {
contains = true;
}
}
input->PopLimit(old);
if (!contains) {
return NULL;
}
// READ types
tag = input->ReadTag();
if (MapData::kTypesFieldNumber != WireFormatLite::GetTagFieldNumber(tag)) {
return NULL;
}
req->cacheTypes.clear();
req->cacheTagValues.clear();
uint32 sizeL;
input->ReadVarint32(&sizeL);
unsigned char* buff = new unsigned char[sizeL];
if (!input->ReadRaw(buff, sizeL)) {
return NULL;
}
bool accept = false;
RenderingRuleSearchRequest* r = req->req;
for (uint32 i = 0; i < sizeL / 2; i++) {
int s = (((int) buff[i * 2 + 1]) << 8) | buff[i * 2];
int mask = s & 3;
int type = s >> 2;
if (mask != RenderingRulesStorage::POINT_RULES) {
type = type & MASK_10;
}
std::pair<std::string, std::string> pair = root->decodingRules[type];
if (r != NULL && !accept) {
if(mask == RenderingRulesStorage::MULTI_POLYGON_TYPE){
mask = RenderingRulesStorage::POLYGON_RULES;
}
r->setIntFilter(r->props()->R_MINZOOM, req->zoom);
r->setStringFilter(r->props()->R_TAG, pair.first);
r->setStringFilter(r->props()->R_VALUE, pair.second);
accept |= r->search(mask, false);
if (mask == RenderingRulesStorage::POINT_RULES && !accept) {
r->setStringFilter(r->props()->R_TAG, pair.first);
r->setStringFilter(r->props()->R_VALUE, pair.second);
accept |= r->search(RenderingRulesStorage::TEXT_RULES, false);
}
} else {
accept = true;
}
req->cacheTagValues.push_back(pair);
req->cacheTypes.push_back(s);
}
delete buff;
if (!accept) {
return NULL;
}
req->numberOfAcceptedObjects++;
MapDataObject* dataObject = new MapDataObject();
dataObject->points = req->cacheCoordinates;
dataObject->types = req->cacheTypes;
dataObject->tagValues = req->cacheTagValues;
while ((tag = input->ReadTag()) != 0) {
switch (WireFormatLite::GetTagFieldNumber(tag)) {
//case MapData::kRestrictionsFieldNumber : {
//sizeL = codedIS.readRawVarint32();
//TLongArrayList list = new TLongArrayList();
//old = codedIS.pushLimit(sizeL);
//while(codedIS.getBytesUntilLimit() > 0){
//list.add(codedIS.readSInt64());
//}
//codedIS.popLimit(old);
//dataObject.restrictions = list.toArray();
//break; }
case MapData::kHighwayMetaFieldNumber:
WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(input, &dataObject->highwayAttributes);
break;
case MapData::kIdFieldNumber:
WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_SINT64>(input, &dataObject->id);
break;
case MapData::kStringIdFieldNumber:
WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &dataObject->stringId);
break;
default: {
if (WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) {
return false;
}
if (!skipUnknownFields(input, tag)) {
return false;
}
break;
}
}
}
return dataObject;
}
bool searchMapTreeBounds(io::CodedInputStream* input, int pleft, int pright, int ptop, int pbottom, SearchQuery* req, MapIndex* root) {
int init = 0;
int lastIndexResult = -1;
int cright = 0;
int cleft = 0;
int ctop = 0;
int cbottom = 0;
int tag;
req->numberOfReadSubtrees++;
while ((tag = input->ReadTag()) != 0) {
if (req->isCancelled()) {
return false;
}
if (init == 0xf) {
init = 0;
// coordinates are init
if (cright < req->left || cleft > req->right || ctop > req->bottom || cbottom < req->top) {
return false;
} else {
req->numberOfAcceptedSubtrees++;
}
}
switch (WireFormatLite::GetTagFieldNumber(tag)) {
// required uint32 version = 1;
case MapTree::kLeftFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &cleft)));
cleft += pleft;
init |= 1;
break;
}
case MapTree::kRightFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &cright)));
cright += pright;
init |= 2;
break;
}
case MapTree::kTopFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &ctop)));
ctop += ptop;
init |= 4;
break;
}
case MapTree::kBottomFieldNumber: {
DO_((WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(input, &cbottom)));
cbottom += pbottom;
init |= 8;
break;
}
case MapTree::kLeafsFieldNumber: {
uint32 length;
input->ReadVarint32(&length);
int oldLimit = input->PushLimit(length);
if (lastIndexResult == -1) {
lastIndexResult = req->res->result.size();
}
BaseMapDataObject* mapObject = readMapDataObject(input, cleft, cright, ctop, cbottom, req, root);
if (mapObject != NULL) {
req->res->result.push_back(mapObject);
}
input->Skip(input->BytesUntilLimit());
input->PopLimit(oldLimit);
break;
}
case MapTree::kSubtreesFieldNumber: {
uint32 length;
readInt(input, &length);
// int filePointer = input->getTotalBytesRead();
int oldLimit = input->PushLimit(length);
searchMapTreeBounds(input, cleft, cright, ctop, cbottom, req, root);
input->Skip(input->BytesUntilLimit());
input->PopLimit(oldLimit);
// input->Seek(filePointer + length);
if (lastIndexResult >= 0) {
return false;
}
break;
}
case MapTree::kOldbaseIdFieldNumber:
case MapTree::kBaseIdFieldNumber: {
uint64 baseId;
input->ReadVarint64(&baseId);
if (lastIndexResult != -1) {
for (uint32 i = lastIndexResult; i < req->res->result.size(); i++) {
BaseMapDataObject* rs = req->res->result.at(i);
rs->id += baseId;
// TODO restrictions are not supported
// if (rs.restrictions != null) {
// for (int j = 0; j < rs.restrictions.length; j++) {
// rs.restrictions[j] += baseId;
// }
// }
}
}
break;
}
case MapTree::kStringTableFieldNumber:
case MapTree::kOldstringTableFieldNumber: {
uint32 length;
input->ReadVarint32(&length);
int oldLimit = input->PushLimit(length);
std::vector<std::string> stringTable;
readStringTable(input, stringTable);
input->PopLimit(oldLimit);
if (lastIndexResult != -1) {
for (uint32 i = lastIndexResult; i < req->res->result.size(); i++) {
BaseMapDataObject* rs = req->res->result.at(i);
if (rs->stringId != BaseMapDataObject::UNDEFINED_STRING) {
rs->name = stringTable.at(rs->stringId);
}
}
}
break;
}
default: {
if (WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
if (!skipUnknownFields(input, tag)) {
return false;
}
break;
}
}
}
return true;
}
void searchMapData(io::CodedInputStream* input, MapRoot* root, MapIndex* ind, SearchQuery* req) {
// search
for (std::vector<MapTreeBounds>::iterator i = root->bounds.begin();
i != root->bounds.end(); i++) {
if (req->isCancelled()) {
return;
}
if (i->right < req->left || i->left > req->right || i->top > req->bottom || i->bottom < req->top) {
continue;
}
input->Seek(i->filePointer);
int oldLimit = input->PushLimit(i->length);
searchMapTreeBounds(input, root->left, root->right, root->top, root->bottom, req, ind);
input->PopLimit(oldLimit);
}
}
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) {
setGlobalEnv(ienv);
SearchResult* result = (SearchResult*) searchResult;
if(result == NULL) {
result = new SearchResult();
}
std::string map = getString(mapName);
std::map<std::string, BinaryMapFile*>::iterator i = openFiles.find(map);
if(i == openFiles.end()) {
return (jint) result;
}
BinaryMapFile* file = i->second;
RenderingRuleSearchRequest* req = initSearchRequest(renderingRuleSearchRequest);
SearchQuery q(sleft,sright, stop, sbottom, req, result);
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.zoom = zoom;
for(vector<MapIndex>::iterator mapIndex = file->mapIndexes.begin();
mapIndex != file->mapIndexes.end(); mapIndex++) {
for (vector<MapRoot>::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(result->result.size() > 0) {
sprintf(errorMsg, "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());
__android_log_print(ANDROID_LOG_INFO, "net.osmand", errorMsg);
// }
delete req;
return (jint)result;
}
extern "C" JNIEXPORT jboolean JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_initBinaryMapFile(JNIEnv* ienv,
jobject obj, jobject path) { jobject obj, jobject path) {
// Verify that the version of the library that we linked against is // Verify that the version of the library that we linked against is
setGlobalEnv(ienv); setGlobalEnv(ienv);
const char* utf = ienv->GetStringUTFChars((jstring)path, NULL); const char* utf = ienv->GetStringUTFChars((jstring) path, NULL);
std::string inputName(utf); std::string inputName(utf);
ienv->ReleaseStringUTFChars((jstring)path, utf); ienv->ReleaseStringUTFChars((jstring) path, utf);
__android_log_print(ANDROID_LOG_ERROR, "net.osmand", inputName.c_str());
// std::string inputName = getString((jstring) path);
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
std::map<std::string, BinaryMapFile*>::iterator iterator; std::map<std::string, BinaryMapFile*>::iterator iterator;
if ((iterator = openFiles.find(inputName)) != openFiles.end()) { if ((iterator = openFiles.find(inputName)) != openFiles.end()) {
@ -134,10 +754,11 @@ JNIEXPORT jboolean JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_initB
__android_log_print(ANDROID_LOG_WARN, "net.osmand", errorMsg); __android_log_print(ANDROID_LOG_WARN, "net.osmand", errorMsg);
return false; return false;
} }
BinaryMapFile* mapFile = new BinaryMapFile(); BinaryMapFile* mapFile = new BinaryMapFile();
mapFile->input = new io::FileInputStream(fileno(file)); mapFile->f = file;
io::CodedInputStream cis (mapFile->input); io::FileInputStream input(fileno(file));
input.SetCloseOnDelete(false);
io::CodedInputStream cis(&input);
cis.SetTotalBytesLimit(INT_MAX, INT_MAX >> 2); cis.SetTotalBytesLimit(INT_MAX, INT_MAX >> 2);
if (!initMapStructure(&cis, mapFile)) { if (!initMapStructure(&cis, mapFile)) {
sprintf(errorMsg, "File not initialised : %s", inputName.c_str()); sprintf(errorMsg, "File not initialised : %s", inputName.c_str());
@ -151,4 +772,5 @@ JNIEXPORT jboolean JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_initB
return true; return true;
} }
#undef DO_
#endif #endif

View file

@ -0,0 +1,152 @@
#ifndef _OSMAND_MAP_OBJECTS
#define _OSMAND_MAP_OBJECTS
#include <jni.h>
#include <vector>
#include "common.h"
#include "mapObjects.h"
jclass MultiPolygonClass;
jmethodID MultiPolygon_getTag;
jmethodID MultiPolygon_getValue;
jmethodID MultiPolygon_getLayer;
jmethodID MultiPolygon_getPoint31XTile;
jmethodID MultiPolygon_getPoint31YTile;
jmethodID MultiPolygon_getBoundsCount;
jmethodID MultiPolygon_getBoundPointsCount;
jmethodID MultiPolygon_getName;
jclass BinaryMapDataObjectClass;
jmethodID BinaryMapDataObject_getPointsLength;
jmethodID BinaryMapDataObject_getPoint31YTile;
jmethodID BinaryMapDataObject_getPoint31XTile;
jmethodID BinaryMapDataObject_getHighwayAttributes;
jmethodID BinaryMapDataObject_getTypes;
jmethodID BinaryMapDataObject_getName;
jmethodID BinaryMapDataObject_getTagValue;
jclass TagValuePairClass;
jfieldID TagValuePair_tag;
jfieldID TagValuePair_value;
std::vector <BaseMapDataObject* > marshalObjects(jobjectArray binaryMapDataObjects)
{
std::vector<BaseMapDataObject*> v;
const size_t size = globalEnv()->GetArrayLength(binaryMapDataObjects);
size_t i = 0;
for (; i < size; i++) {
jobject binaryMapDataObject = (jobject) globalEnv()->GetObjectArrayElement(binaryMapDataObjects, i);
if (globalEnv()->IsInstanceOf(binaryMapDataObject, MultiPolygonClass)) {
MultiPolygonObject* o = new MultiPolygonObject();
v.push_back((BaseMapDataObject* )o);
o->layer = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getLayer);
o->tag = getStringMethod(binaryMapDataObject, MultiPolygon_getTag);
o->value = getStringMethod(binaryMapDataObject, MultiPolygon_getValue);
int boundsCount = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getBoundsCount);
for (int ji = 0; ji < boundsCount; ji++) {
int cnt = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getBoundPointsCount, ji);
std::vector<std::pair<int, int> > vs;
for (int js = 0; js < cnt; js++) {
int xt = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getPoint31XTile, js, ji);
int yt = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getPoint31YTile, js, ji);
vs.push_back( std::pair<int, int> (xt, yt) );
}
o->points.push_back(vs);
o->names.push_back(getStringMethod(binaryMapDataObject, MultiPolygon_getName, ji));
}
} else {
jintArray types = (jintArray) globalEnv()->CallObjectMethod(binaryMapDataObject, BinaryMapDataObject_getTypes);
if (types != NULL) {
MapDataObject* o = new MapDataObject();
jint sizeTypes = globalEnv()->GetArrayLength(types);
jint* els = globalEnv()->GetIntArrayElements(types, NULL);
int j = 0;
for (; j < sizeTypes; j++) {
int wholeType = els[j];
o->types.push_back(wholeType);
jobject pair = globalEnv()->CallObjectMethod(binaryMapDataObject, BinaryMapDataObject_getTagValue, j);
if (pair != NULL) {
std::string tag = getStringField(pair, TagValuePair_tag);
std::string value = getStringField(pair, TagValuePair_value);
o->tagValues.push_back( std::pair<std:: string, std::string>(tag, value));
globalEnv()->DeleteLocalRef(pair);
} else {
o->tagValues.push_back( std::pair<std:: string, std::string>(EMPTY_STRING, EMPTY_STRING));
}
}
jint sizePoints = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getPointsLength);
for (j = 0; j < sizePoints; j++) {
int tx = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getPoint31XTile, j);
int ty = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getPoint31YTile, j);
o->points.push_back(std::pair<int, int>(tx, ty));
}
o->name = getStringMethod(binaryMapDataObject, BinaryMapDataObject_getName);
o->highwayAttributes = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getHighwayAttributes);
globalEnv()->ReleaseIntArrayElements(types, els, JNI_ABORT);
globalEnv()->DeleteLocalRef(types);
v.push_back((BaseMapDataObject* )o);
}
}
globalEnv()->DeleteLocalRef(binaryMapDataObject);
}
return v;
}
void deleteObjects(std::vector <BaseMapDataObject* > & v)
{
for(size_t i = 0; i< v.size(); i++)
{
delete v.at(i);
}
v.clear();
}
void loadJniMapObjects()
{
MultiPolygonClass = globalRef(globalEnv()->FindClass("net/osmand/osm/MultyPolygon"));
MultiPolygon_getTag = globalEnv()->GetMethodID(MultiPolygonClass, "getTag", "()Ljava/lang/String;");
MultiPolygon_getValue = globalEnv()->GetMethodID(MultiPolygonClass, "getValue", "()Ljava/lang/String;");
MultiPolygon_getName = globalEnv()->GetMethodID(MultiPolygonClass, "getName", "(I)Ljava/lang/String;");
MultiPolygon_getLayer = globalEnv()->GetMethodID(MultiPolygonClass, "getLayer", "()I");
MultiPolygon_getPoint31XTile = globalEnv()->GetMethodID(MultiPolygonClass, "getPoint31XTile", "(II)I");
MultiPolygon_getPoint31YTile = globalEnv()->GetMethodID(MultiPolygonClass, "getPoint31YTile", "(II)I");
MultiPolygon_getBoundsCount = globalEnv()->GetMethodID(MultiPolygonClass, "getBoundsCount", "()I");
MultiPolygon_getBoundPointsCount = globalEnv()->GetMethodID(MultiPolygonClass, "getBoundPointsCount", "(I)I");
BinaryMapDataObjectClass = globalRef(globalEnv()->FindClass("net/osmand/binary/BinaryMapDataObject"));
BinaryMapDataObject_getPointsLength = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getPointsLength", "()I");
BinaryMapDataObject_getPoint31YTile = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getPoint31YTile", "(I)I");
BinaryMapDataObject_getPoint31XTile = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getPoint31XTile", "(I)I");
BinaryMapDataObject_getHighwayAttributes = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getHighwayAttributes", "()I");
BinaryMapDataObject_getTypes = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getTypes", "()[I");
BinaryMapDataObject_getName = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getName", "()Ljava/lang/String;");
BinaryMapDataObject_getTagValue = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getTagValue",
"(I)Lnet/osmand/binary/BinaryMapIndexReader$TagValuePair;");
TagValuePairClass = globalRef(globalEnv()->FindClass("net/osmand/binary/BinaryMapIndexReader$TagValuePair"));
TagValuePair_tag = globalEnv()->GetFieldID(TagValuePairClass, "tag", "Ljava/lang/String;");
TagValuePair_value = globalEnv()->GetFieldID(TagValuePairClass, "value", "Ljava/lang/String;");
}
void unloadJniMapObjects()
{
globalEnv()->DeleteGlobalRef( MultiPolygonClass );
globalEnv()->DeleteGlobalRef( BinaryMapDataObjectClass );
globalEnv()->DeleteGlobalRef( TagValuePairClass );
}
#endif /*_OSMAND_MAP_OBJECTS*/

View file

@ -1,45 +1,33 @@
#ifndef _OSMAND_MAP_OBJECTS_H
#define _OSMAND_MAP_OBJECTS_H
#include <jni.h> #include <jni.h>
#include <vector> #include <vector>
#include <string>
#include "common.h" #include "common.h"
jclass MultiPolygonClass;
jmethodID MultiPolygon_getTag;
jmethodID MultiPolygon_getValue;
jmethodID MultiPolygon_getLayer;
jmethodID MultiPolygon_getPoint31XTile;
jmethodID MultiPolygon_getPoint31YTile;
jmethodID MultiPolygon_getBoundsCount;
jmethodID MultiPolygon_getBoundPointsCount;
jmethodID MultiPolygon_getName;
jclass BinaryMapDataObjectClass;
jmethodID BinaryMapDataObject_getPointsLength;
jmethodID BinaryMapDataObject_getPoint31YTile;
jmethodID BinaryMapDataObject_getPoint31XTile;
jmethodID BinaryMapDataObject_getHighwayAttributes;
jmethodID BinaryMapDataObject_getTypes;
jmethodID BinaryMapDataObject_getName;
jmethodID BinaryMapDataObject_getTagValue;
jclass TagValuePairClass;
jfieldID TagValuePair_tag;
jfieldID TagValuePair_value;
class BaseMapDataObject class BaseMapDataObject
{ {
public : public :
static const unsigned int UNDEFINED_STRING = 0x7fffffff;
const int type; const int type;
static const int MAP_DATA_OBJECT = 1; static const int MAP_DATA_OBJECT = 1;
static const int MULTI_POLYGON = 2; static const int MULTI_POLYGON = 2;
long long id;
unsigned int stringId;
std::string name;
protected : protected :
BaseMapDataObject(int t) : type(t) { } BaseMapDataObject(int t) : type(t), id(0), stringId(UNDEFINED_STRING){ }
}; };
class MultiPolygonObject : BaseMapDataObject struct SearchResult {
std::vector< BaseMapDataObject*> result;
};
class MultiPolygonObject : public BaseMapDataObject
{ {
public: public:
MultiPolygonObject() : BaseMapDataObject(MULTI_POLYGON) { } MultiPolygonObject() : BaseMapDataObject(MULTI_POLYGON) { }
@ -50,12 +38,11 @@ public:
std::vector< std::vector< std::pair<int, int> > > points; std::vector< std::vector< std::pair<int, int> > > points;
}; };
class MapDataObject : BaseMapDataObject class MapDataObject : public BaseMapDataObject
{ {
public: public:
MapDataObject() : BaseMapDataObject(MAP_DATA_OBJECT) { } MapDataObject() : BaseMapDataObject(MAP_DATA_OBJECT) { }
std::string name;
std::vector< int> types; std::vector< int> types;
std::vector< std::pair<int, int> > points; std::vector< std::pair<int, int> > points;
std::vector< std::pair<std::string, std::string> > tagValues; std::vector< std::pair<std::string, std::string> > tagValues;
@ -63,118 +50,12 @@ public:
}; };
std::vector <BaseMapDataObject* > marshalObjects(jobjectArray binaryMapDataObjects) std::vector <BaseMapDataObject* > marshalObjects(jobjectArray binaryMapDataObjects);
{
std::vector<BaseMapDataObject*> v;
const size_t size = globalEnv()->GetArrayLength(binaryMapDataObjects); void deleteObjects(std::vector <BaseMapDataObject* > & v);
size_t i = 0;
for (; i < size; i++) {
jobject binaryMapDataObject = (jobject) globalEnv()->GetObjectArrayElement(binaryMapDataObjects, i);
if (globalEnv()->IsInstanceOf(binaryMapDataObject, MultiPolygonClass)) {
MultiPolygonObject* o = new MultiPolygonObject();
v.push_back((BaseMapDataObject* )o);
o->layer = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getLayer);
o->tag = getStringMethod(binaryMapDataObject, MultiPolygon_getTag);
o->value = getStringMethod(binaryMapDataObject, MultiPolygon_getValue);
int boundsCount = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getBoundsCount); void loadJniMapObjects();
for (int ji = 0; ji < boundsCount; ji++) {
int cnt = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getBoundPointsCount, ji);
std::vector<std::pair<int, int> > vs;
for (int js = 0; js < cnt; js++) {
int xt = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getPoint31XTile, js, ji);
int yt = globalEnv()->CallIntMethod(binaryMapDataObject, MultiPolygon_getPoint31YTile, js, ji);
vs.push_back( std::pair<int, int> (xt, yt) );
}
o->points.push_back(vs); void unloadJniMapObjects();
o->names.push_back(getStringMethod(binaryMapDataObject, MultiPolygon_getName, ji));
}
#endif /*_OSMAND_MAP_OBJECTS_H*/
} else {
jintArray types = (jintArray) globalEnv()->CallObjectMethod(binaryMapDataObject, BinaryMapDataObject_getTypes);
if (types != NULL) {
MapDataObject* o = new MapDataObject();
jint sizeTypes = globalEnv()->GetArrayLength(types);
jint* els = globalEnv()->GetIntArrayElements(types, NULL);
int j = 0;
for (; j < sizeTypes; j++) {
int wholeType = els[j];
o->types.push_back(wholeType);
jobject pair = globalEnv()->CallObjectMethod(binaryMapDataObject, BinaryMapDataObject_getTagValue, j);
if (pair != NULL) {
std::string tag = getStringField(pair, TagValuePair_tag);
std::string value = getStringField(pair, TagValuePair_value);
o->tagValues.push_back( std::pair<std:: string, std::string>(tag, value));
globalEnv()->DeleteLocalRef(pair);
} else {
o->tagValues.push_back( std::pair<std:: string, std::string>(EMPTY_STRING, EMPTY_STRING));
}
}
jint sizePoints = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getPointsLength);
for (j = 0; j < sizePoints; j++) {
int tx = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getPoint31XTile, j);
int ty = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getPoint31YTile, j);
o->points.push_back(std::pair<int, int>(tx, ty));
}
o->name = getStringMethod(binaryMapDataObject, BinaryMapDataObject_getName);
o->highwayAttributes = globalEnv()->CallIntMethod(binaryMapDataObject, BinaryMapDataObject_getHighwayAttributes);
globalEnv()->ReleaseIntArrayElements(types, els, JNI_ABORT);
globalEnv()->DeleteLocalRef(types);
v.push_back((BaseMapDataObject* )o);
}
}
globalEnv()->DeleteLocalRef(binaryMapDataObject);
}
return v;
}
void deleteObjects(std::vector <BaseMapDataObject* > & v)
{
for(size_t i = 0; i< v.size(); i++)
{
delete v.at(i);
}
v.clear();
}
void loadJniMapObjects()
{
MultiPolygonClass = globalRef(globalEnv()->FindClass("net/osmand/osm/MultyPolygon"));
MultiPolygon_getTag = globalEnv()->GetMethodID(MultiPolygonClass, "getTag", "()Ljava/lang/String;");
MultiPolygon_getValue = globalEnv()->GetMethodID(MultiPolygonClass, "getValue", "()Ljava/lang/String;");
MultiPolygon_getName = globalEnv()->GetMethodID(MultiPolygonClass, "getName", "(I)Ljava/lang/String;");
MultiPolygon_getLayer = globalEnv()->GetMethodID(MultiPolygonClass, "getLayer", "()I");
MultiPolygon_getPoint31XTile = globalEnv()->GetMethodID(MultiPolygonClass, "getPoint31XTile", "(II)I");
MultiPolygon_getPoint31YTile = globalEnv()->GetMethodID(MultiPolygonClass, "getPoint31YTile", "(II)I");
MultiPolygon_getBoundsCount = globalEnv()->GetMethodID(MultiPolygonClass, "getBoundsCount", "()I");
MultiPolygon_getBoundPointsCount = globalEnv()->GetMethodID(MultiPolygonClass, "getBoundPointsCount", "(I)I");
BinaryMapDataObjectClass = globalRef(globalEnv()->FindClass("net/osmand/binary/BinaryMapDataObject"));
BinaryMapDataObject_getPointsLength = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getPointsLength", "()I");
BinaryMapDataObject_getPoint31YTile = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getPoint31YTile", "(I)I");
BinaryMapDataObject_getPoint31XTile = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getPoint31XTile", "(I)I");
BinaryMapDataObject_getHighwayAttributes = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getHighwayAttributes", "()I");
BinaryMapDataObject_getTypes = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getTypes", "()[I");
BinaryMapDataObject_getName = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getName", "()Ljava/lang/String;");
BinaryMapDataObject_getTagValue = globalEnv()->GetMethodID(BinaryMapDataObjectClass, "getTagValue",
"(I)Lnet/osmand/binary/BinaryMapIndexReader$TagValuePair;");
TagValuePairClass = globalRef(globalEnv()->FindClass("net/osmand/binary/BinaryMapIndexReader$TagValuePair"));
TagValuePair_tag = globalEnv()->GetFieldID(TagValuePairClass, "tag", "Ljava/lang/String;");
TagValuePair_value = globalEnv()->GetFieldID(TagValuePairClass, "value", "Ljava/lang/String;");
}
void unloadJniMapObjects()
{
globalEnv()->DeleteGlobalRef( MultiPolygonClass );
globalEnv()->DeleteGlobalRef( BinaryMapDataObjectClass );
globalEnv()->DeleteGlobalRef( TagValuePairClass );
}

File diff suppressed because it is too large Load diff

View file

@ -64,6 +64,9 @@ private:
void initRules(); void initRules();
public: public:
// No rules for multipolygon !!!
const static int MULTI_POLYGON_TYPE = 0;
const static int POINT_RULES = 1; const static int POINT_RULES = 1;
const static int LINE_RULES = 2; const static int LINE_RULES = 2;
const static int POLYGON_RULES = 3; const static int POLYGON_RULES = 3;

View file

@ -699,7 +699,7 @@ void doRendering(std::vector <BaseMapDataObject* > mapDataObjects, SkCanvas* can
extern "C" { extern "C" {
#endif #endif
JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering( JNIEnv* ienv, JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering( JNIEnv* ienv,
jobject obj, jobject renderingContext, jobjectArray binaryMapDataObjects, jobject bmpObj, jobject obj, jobject renderingContext, jint searchResult, jobject bmpObj,
jboolean useEnglishNames, jobject renderingRuleSearchRequest, jint defaultColor) { jboolean useEnglishNames, jobject renderingRuleSearchRequest, jint defaultColor) {
setGlobalEnv(ienv); setGlobalEnv(ienv);
SkBitmap* bmp = getNativeBitmap(bmpObj); SkBitmap* bmp = getNativeBitmap(bmpObj);
@ -710,17 +710,15 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
SkPaint* paint = new SkPaint; SkPaint* paint = new SkPaint;
paint->setAntiAlias(true); paint->setAntiAlias(true);
__android_log_print(ANDROID_LOG_WARN, "net.osmand", "Initializing rendering"); __android_log_print(ANDROID_LOG_WARN, "net.osmand", "Initializing rendering");
watcher initObjects; watcher initObjects;
initObjects.start(); initObjects.start();
RenderingRuleSearchRequest* req = initSearchRequest(renderingRuleSearchRequest); RenderingRuleSearchRequest* req = initSearchRequest(renderingRuleSearchRequest);
RenderingContext rc; RenderingContext rc;
copyRenderingContext(renderingContext, &rc); copyRenderingContext(renderingContext, &rc);
std::vector <BaseMapDataObject* > mapDataObjects = marshalObjects(binaryMapDataObjects); SearchResult* result = ((SearchResult*) searchResult);
// std::vector <BaseMapDataObject* > mapDataObjects = marshalObjects(binaryMapDataObjects);
__android_log_print(ANDROID_LOG_WARN, "net.osmand", "Rendering image"); __android_log_print(ANDROID_LOG_WARN, "net.osmand", "Rendering image");
@ -729,7 +727,9 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
// Main part do rendering // Main part do rendering
rc.nativeOperations.start(); rc.nativeOperations.start();
doRendering(mapDataObjects, canvas, paint, req, &rc); if(result != NULL) {
doRendering(result->result, canvas, paint, req, &rc);
}
rc.nativeOperations.pause(); rc.nativeOperations.pause();
mergeRenderingContext(renderingContext, &rc); mergeRenderingContext(renderingContext, &rc);
@ -739,17 +739,14 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
delete paint; delete paint;
delete canvas; delete canvas;
delete req; delete req;
deleteObjects(mapDataObjects); // deleteObjects(mapDataObjects);
#ifdef DEBUG_NAT_OPERATIONS #ifdef DEBUG_NAT_OPERATIONS
sprintf(debugMessage, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime()); sprintf(debugMessage, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
#else #else
sprintf(debugMessage, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime()); sprintf(debugMessage, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
#endif #endif
jstring result = globalEnv()->NewStringUTF( debugMessage); return globalEnv()->NewStringUTF( debugMessage);
// unloadLibrary();
return result;
} }
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -26,27 +26,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_CPP_EXTENSION := .cc LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES) \ LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES) \
google/protobuf/stubs/strutil.cc \ google/protobuf/io/zero_copy_stream_impl.cc
google/protobuf/stubs/strutil.h \
google/protobuf/stubs/substitute.cc \
google/protobuf/stubs/substitute.h \
google/protobuf/stubs/structurally_valid.cc \
google/protobuf/descriptor.cc \
google/protobuf/descriptor.pb.cc \
google/protobuf/descriptor_database.cc \
google/protobuf/dynamic_message.cc \
google/protobuf/extension_set_heavy.cc \
google/protobuf/generated_message_reflection.cc \
google/protobuf/message.cc \
google/protobuf/reflection_ops.cc \
google/protobuf/service.cc \
google/protobuf/text_format.cc \
google/protobuf/unknown_field_set.cc \
google/protobuf/wire_format.cc \
google/protobuf/io/gzip_stream.cc \
google/protobuf/io/printer.cc \
google/protobuf/io/tokenizer.cc \
google/protobuf/io/zero_copy_stream_impl.cc \
LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_C_INCLUDES := $(LOCAL_PATH)

View file

@ -151,6 +151,19 @@ void CodedInputStream::PrintTotalBytesLimitError() {
"in google/protobuf/io/coded_stream.h."; "in google/protobuf/io/coded_stream.h.";
} }
// Osmand change : Seeks in the file
bool CodedInputStream::Seek(int filePointer) {
if(filePointer >= getTotalBytesRead()) {
return Skip(filePointer - getTotalBytesRead());
} else {
buffer_ = NULL;
buffer_end_ = NULL;
input_->BackUp(total_bytes_read_ - filePointer);
total_bytes_read_ -= filePointer;
return Refresh();
}
}
bool CodedInputStream::Skip(int count) { bool CodedInputStream::Skip(int count) {
if (count < 0) return false; // security: count is often user-supplied if (count < 0) return false; // security: count is often user-supplied
@ -392,6 +405,11 @@ uint32 CodedInputStream::ReadTagFallback() {
} }
} }
// Osmand change ::
int CodedInputStream::getTotalBytesRead() {
return total_bytes_read_ - (buffer_end_ - buffer_);
}
bool CodedInputStream::ReadVarint64Slow(uint64* value) { bool CodedInputStream::ReadVarint64Slow(uint64* value) {
// Slow path: This read might cross the end of the buffer, so we // Slow path: This read might cross the end of the buffer, so we
// need to check and refresh the buffer if and when it does. // need to check and refresh the buffer if and when it does.

View file

@ -162,6 +162,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// occurs. // occurs.
bool Skip(int count); bool Skip(int count);
// Osmand change : Seeks in the file
bool Seek(int filePointer);
// Sets *data to point directly at the unread part of the CodedInputStream's // Sets *data to point directly at the unread part of the CodedInputStream's
// underlying buffer, and *size to the size of that buffer, but does not // underlying buffer, and *size to the size of that buffer, but does not
// advance the stream's current position. This will always either produce // advance the stream's current position. This will always either produce
@ -300,6 +303,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// stack is hit, or -1 if no limits are in place. // stack is hit, or -1 if no limits are in place.
int BytesUntilLimit(); int BytesUntilLimit();
// osmand change : totally bytes read
int getTotalBytesRead();
// Total Bytes Limit ----------------------------------------------- // Total Bytes Limit -----------------------------------------------
// To prevent malicious users from sending excessively large messages // To prevent malicious users from sending excessively large messages
// and causing integer overflows or memory exhaustion, CodedInputStream // and causing integer overflows or memory exhaustion, CodedInputStream

Binary file not shown.

View file

@ -37,6 +37,7 @@ import net.osmand.plus.OsmandSettings.CommonPreference;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.RotatedTileBox; import net.osmand.plus.RotatedTileBox;
import net.osmand.plus.activities.OsmandApplication; import net.osmand.plus.activities.OsmandApplication;
import net.osmand.plus.render.NativeOsmandLibrary.NativeSearchResult;
import net.osmand.plus.render.OsmandRenderer.RenderingContext; import net.osmand.plus.render.OsmandRenderer.RenderingContext;
import net.osmand.render.RenderingRuleProperty; import net.osmand.render.RenderingRuleProperty;
import net.osmand.render.RenderingRuleSearchRequest; import net.osmand.render.RenderingRuleSearchRequest;
@ -67,6 +68,7 @@ public class MapRenderRepositories {
private RectF cObjectsBox = new RectF(); private RectF cObjectsBox = new RectF();
// cached objects in order to render rotation without reloading data from db // cached objects in order to render rotation without reloading data from db
private List<BinaryMapDataObject> cObjects = new LinkedList<BinaryMapDataObject>(); private List<BinaryMapDataObject> cObjects = new LinkedList<BinaryMapDataObject>();
private NativeSearchResult cNativeObjects = null;
// currently rendered box (not the same as already rendered) // currently rendered box (not the same as already rendered)
// this box is checked for interrupted process or // this box is checked for interrupted process or
@ -227,6 +229,50 @@ public class MapRenderRepositories {
} }
return false; return false;
} }
private boolean loadVectorDataNative(RectF dataBox, final int zoom, final RenderingRuleSearchRequest renderingReq) {
int leftX = MapUtils.get31TileNumberX(dataBox.left);
int rightX = MapUtils.get31TileNumberX(dataBox.right);
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;
}
}
}
NativeSearchResult resultHandler = null;
for (String mapName : files.keySet()) {
if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) {
continue;
}
if (!nativeFiles.contains(mapName)) {
nativeFiles.add(mapName);
if (!NativeOsmandLibrary.initBinaryMapFile(mapName)) {
continue;
}
log.debug("Native resource " + mapName + " initialized"); //$NON-NLS-1$ //$NON-NLS-2$
}
resultHandler = NativeOsmandLibrary.searchObjectsForRendering(leftX, rightX, topY, bottomY, zoom, mapName,renderingReq,
PerformanceFlags.checkForDuplicateObjectIds, resultHandler);
if (checkWhetherInterrupted()) {
NativeOsmandLibrary.deleteSearchResult(resultHandler);
return false;
}
}
cNativeObjects = resultHandler;
cObjectsBox = dataBox;
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
dataBox.bottom, dataBox.top, dataBox.left, dataBox.right, zoom));
log.info(String.format("Native search done in %s ms. ", System.currentTimeMillis() - now)); //$NON-NLS-1$
return true;
}
private boolean loadVectorData(RectF dataBox, final int zoom, final RenderingRuleSearchRequest renderingReq, final boolean nightMode) { private boolean loadVectorData(RectF dataBox, final int zoom, final RenderingRuleSearchRequest renderingReq, final boolean nightMode) {
double cBottomLatitude = dataBox.bottom; double cBottomLatitude = dataBox.bottom;
@ -234,7 +280,6 @@ public class MapRenderRepositories {
double cLeftLongitude = dataBox.left; double cLeftLongitude = dataBox.left;
double cRightLongitude = dataBox.right; double cRightLongitude = dataBox.right;
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (files.isEmpty()) { if (files.isEmpty()) {
@ -302,15 +347,7 @@ public class MapRenderRepositories {
if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) { if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) {
continue; continue;
} }
if(prefs.NATIVE_RENDERING.get()){
if (!nativeFiles.contains(mapName)) {
nativeFiles.add(mapName);
if (!NativeOsmandLibrary.initBinaryMapFile(mapName)) {
continue;
}
log.debug("Native resource " + mapName + " initialized"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
BinaryMapIndexReader c = files.get(mapName); BinaryMapIndexReader c = files.get(mapName);
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter); searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter);
List<BinaryMapDataObject> res = c.searchMapIndex(searchRequest); List<BinaryMapDataObject> res = c.searchMapIndex(searchRequest);
@ -420,7 +457,7 @@ public class MapRenderRepositories {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (cObjectsBox.left > dataBox.left || cObjectsBox.top > dataBox.top || cObjectsBox.right < dataBox.right if (cObjectsBox.left > dataBox.left || cObjectsBox.top > dataBox.top || cObjectsBox.right < dataBox.right
|| cObjectsBox.bottom < dataBox.bottom) { || cObjectsBox.bottom < dataBox.bottom || prefs.NATIVE_RENDERING.get() == (cNativeObjects == null)) {
// increase data box in order for rotate // increase data box in order for rotate
if ((dataBox.right - dataBox.left) > (dataBox.top - dataBox.bottom)) { if ((dataBox.right - dataBox.left) > (dataBox.top - dataBox.bottom)) {
double wi = (dataBox.right - dataBox.left) * .2; double wi = (dataBox.right - dataBox.left) * .2;
@ -432,7 +469,14 @@ public class MapRenderRepositories {
dataBox.bottom -= hi; dataBox.bottom -= hi;
} }
validateLatLonBox(dataBox); validateLatLonBox(dataBox);
boolean loaded = loadVectorData(dataBox, requestedBox.getZoom(), renderingReq, nightMode); boolean loaded;
if(prefs.NATIVE_RENDERING.get()) {
cObjects = new LinkedList<BinaryMapDataObject>();
loaded = loadVectorDataNative(dataBox, requestedBox.getZoom(), renderingReq);
} else {
cNativeObjects = null;
loaded = loadVectorData(dataBox, requestedBox.getZoom(), renderingReq, nightMode);
}
if (!loaded || checkWhetherInterrupted()) { if (!loaded || checkWhetherInterrupted()) {
return; return;
} }
@ -462,9 +506,14 @@ public class MapRenderRepositories {
this.prevBmpLocation = this.bmpLocation; this.prevBmpLocation = this.bmpLocation;
this.bmp = bmp; this.bmp = bmp;
this.bmpLocation = tileRect; this.bmpLocation = tileRect;
renderer.generateNewBitmap(currentRenderingContext, cObjects, bmp, prefs.USE_ENGLISH_NAMES.get(), renderingReq, if(app.getSettings().NATIVE_RENDERING.get()) {
notifyList, storage.getBgColor(nightMode), app.getSettings().NATIVE_RENDERING.get()); renderer.generateNewBitmapNative(currentRenderingContext, cNativeObjects, bmp, prefs.USE_ENGLISH_NAMES.get(), renderingReq,
notifyList, storage.getBgColor(nightMode));
} else {
renderer.generateNewBitmap(currentRenderingContext, cObjects, bmp, prefs.USE_ENGLISH_NAMES.get(), renderingReq,
notifyList, storage.getBgColor(nightMode));
}
String renderingDebugInfo = currentRenderingContext.renderingDebugInfo; String renderingDebugInfo = currentRenderingContext.renderingDebugInfo;
currentRenderingContext.ended = true; currentRenderingContext.ended = true;
if (checkWhetherInterrupted()) { if (checkWhetherInterrupted()) {
@ -846,9 +895,9 @@ public class MapRenderRepositories {
int sy = (int) (i.get(0) & mask); int sy = (int) (i.get(0) & mask);
boolean st = y == topY || x == rightX || y == bottomY || x == leftX; boolean st = y == topY || x == rightX || y == bottomY || x == leftX;
boolean end = sy == topY || sx == rightX || sy == bottomY || sx == leftX; boolean end = sy == topY || sx == rightX || sy == bottomY || sx == leftX;
// something wrong here // something goes wrong
// These exceptions are used to check logic about processing multipolygons // These exceptions are used to check logic about processing multipolygons
// However in map data this situation could happen with broken multipolygons (so it would data causes app error) // However this situation could happen because of broken multipolygons (so it should data causes app error)
// that's why these exceptions could be replaced with return; statement. // that's why these exceptions could be replaced with return; statement.
if (!end || !st) { if (!end || !st) {
float dx = (float) MapUtils.get31LongitudeX(x); float dx = (float) MapUtils.get31LongitudeX(x);

View file

@ -1,24 +1,75 @@
package net.osmand.plus.render; package net.osmand.plus.render;
import net.osmand.binary.BinaryMapDataObject;
import net.osmand.plus.render.OsmandRenderer.RenderingContext; import net.osmand.plus.render.OsmandRenderer.RenderingContext;
import net.osmand.render.RenderingRuleSearchRequest; import net.osmand.render.RenderingRuleSearchRequest;
import android.graphics.Bitmap; import android.graphics.Bitmap;
public class NativeOsmandLibrary { public class NativeOsmandLibrary {
static { static {
System.loadLibrary("osmand"); System.loadLibrary("osmand");
} }
public static void preloadLibrary() {} public static void preloadLibrary() {
}
public static native String generateRendering(RenderingContext rc, BinaryMapDataObject[] objects, Bitmap bmp, public static String generateRendering(RenderingContext rc, NativeSearchResult searchResultHandler, Bitmap bmp,
boolean useEnglishNames, RenderingRuleSearchRequest render, int defaultColor); boolean useEnglishNames, RenderingRuleSearchRequest render, int defaultColor) {
if (searchResultHandler == null) {
return "Error searchresult = null";
}
return generateRendering(rc, searchResultHandler.nativeHandler, bmp, useEnglishNames, render, defaultColor);
}
/**
* @param searchResultHandle
* - must be null if there is no need to append to previous results returns native handle to results
*/
public static NativeSearchResult searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom,
String mapName, RenderingRuleSearchRequest request, boolean skipDuplicates, NativeSearchResult searchResultHandler) {
if (searchResultHandler == null) {
return new NativeSearchResult(searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates, 0));
} else {
int res = searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates, searchResultHandler.nativeHandler);
if(res == searchResultHandler.nativeHandler){
return searchResultHandler;
}
return new NativeSearchResult(res);
}
}
public static void deleteSearchResult(NativeSearchResult searchResultHandler) {
if (searchResultHandler.nativeHandler != 0) {
deleteSearchResult(searchResultHandler.nativeHandler);
searchResultHandler.nativeHandler = 0;
}
}
public static class NativeSearchResult {
private int nativeHandler;
private NativeSearchResult(int nativeHandler) {
this.nativeHandler = nativeHandler;
}
@Override
protected void finalize() throws Throwable {
if (nativeHandler != 0) {
super.finalize();
}
deleteSearchResult(nativeHandler);
}
}
private static native void deleteSearchResult(int searchResultHandle);
public static native boolean initBinaryMapFile(String filePath); public static native boolean initBinaryMapFile(String filePath);
private static native String generateRendering(RenderingContext rc, int searchResultHandler, Bitmap bmp, 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);
} }

View file

@ -18,6 +18,7 @@ import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
import net.osmand.data.MapTileDownloader.IMapDownloaderCallback; import net.osmand.data.MapTileDownloader.IMapDownloaderCallback;
import net.osmand.osm.MapRenderingTypes; import net.osmand.osm.MapRenderingTypes;
import net.osmand.osm.MultyPolygon; import net.osmand.osm.MultyPolygon;
import net.osmand.plus.render.NativeOsmandLibrary.NativeSearchResult;
import net.osmand.render.RenderingRuleProperty; import net.osmand.render.RenderingRuleProperty;
import net.osmand.render.RenderingRuleSearchRequest; import net.osmand.render.RenderingRuleSearchRequest;
import net.osmand.render.RenderingRulesStorage; import net.osmand.render.RenderingRulesStorage;
@ -227,8 +228,37 @@ public class OsmandRenderer {
} }
public Bitmap generateNewBitmapNative(RenderingContext rc, NativeSearchResult searchResultHandler, Bitmap bmp, boolean useEnglishNames,
RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList, int defaultColor) {
long now = System.currentTimeMillis();
if (rc.width > 0 && rc.height > 0 && searchResultHandler != null) {
// init rendering context
rc.tileDivisor = (int) (1 << (31 - rc.zoom));
rc.cosRotateTileSize = FloatMath.cos((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
rc.density = dm.density;
try {
if(Looper.getMainLooper() != null){
final Handler h = new Handler(Looper.getMainLooper());
notifyListenersWithDelay(rc, notifyList, h);
}
String res = NativeOsmandLibrary.generateRendering(rc, searchResultHandler, bmp, useEnglishNames, render, defaultColor);
rc.ended = true;
notifyListeners(notifyList);
long time = System.currentTimeMillis() - now;
rc.renderingDebugInfo = String.format("Rendering done in %s (%s text) ms\n"
+ "(%s points, %s points inside, %s objects visile from %s)\n" + res,//$NON-NLS-1$
time, rc.textRenderingTime, rc.pointCount, rc.pointInsideCount, rc.visible, rc.allObjects);
} catch (Exception e) {
e.printStackTrace();
}
}
return bmp;
}
public Bitmap generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames, public Bitmap generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames,
RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList, int defaultColor, boolean nativeRendering) { RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList, int defaultColor) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (objects != null && !objects.isEmpty() && rc.width > 0 && rc.height > 0) { if (objects != null && !objects.isEmpty() && rc.width > 0 && rc.height > 0) {
@ -238,96 +268,77 @@ public class OsmandRenderer {
rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE; rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
rc.density = dm.density; rc.density = dm.density;
if (!nativeRendering) { // fill area
// fill area Canvas cv = new Canvas(bmp);
Canvas cv = new Canvas(bmp); if (defaultColor != 0) {
if(defaultColor != 0){ paintFillEmpty.setColor(defaultColor);
paintFillEmpty.setColor(defaultColor);
}
cv.drawRect(0, 0, bmp.getWidth(), bmp.getHeight(), paintFillEmpty);
// put in order map
TIntObjectHashMap<TIntArrayList> orderMap = sortObjectsByProperOrder(rc, objects, render);
int objCount = 0;
int[] keys = orderMap.keys();
Arrays.sort(keys);
boolean shadowDrawn = false;
for (int k = 0; k < keys.length; k++) {
if (!shadowDrawn && keys[k] >= rc.shadowLevelMin && keys[k] <= rc.shadowLevelMax && rc.shadowRenderingMode > 1) {
for (int ki = k; ki < keys.length; ki++) {
if (keys[ki] > rc.shadowLevelMax || rc.interrupted) {
break;
}
TIntArrayList list = orderMap.get(keys[ki]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
// show text only for main type
drawObj(obj, render, cv, rc, l, l == 0, true);
objCount++;
}
}
shadowDrawn = true;
}
if (rc.interrupted) {
return null;
}
TIntArrayList list = orderMap.get(keys[k]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
// show text only for main type
drawObj(obj, render, cv, rc, l, l == 0, false);
objCount++;
}
if (objCount > 25) {
notifyListeners(notifyList);
objCount = 0;
}
}
long beforeIconTextTime = System.currentTimeMillis() - now;
notifyListeners(notifyList);
drawIconsOverCanvas(rc, cv);
notifyListeners(notifyList);
drawTextOverCanvas(rc, cv, useEnglishNames);
long time = System.currentTimeMillis() - now;
rc.renderingDebugInfo = String.format("Rendering done in %s (%s text) ms\n"
+ "(%s points, %s points inside, %s objects visile from %s)",//$NON-NLS-1$
time, time - beforeIconTextTime, rc.pointCount, rc.pointInsideCount, rc.visible, rc.allObjects);
log.info(rc.renderingDebugInfo);
} else {
BinaryMapDataObject[] array = objects.toArray(new BinaryMapDataObject[objects.size()]);
try {
if(Looper.getMainLooper() != null){
final Handler h = new Handler(Looper.getMainLooper());
notifyListenersWithDelay(rc, notifyList, h);
}
String res = NativeOsmandLibrary.generateRendering(rc, array, bmp, useEnglishNames, render, defaultColor);
rc.ended = true;
notifyListeners(notifyList);
long time = System.currentTimeMillis() - now;
rc.renderingDebugInfo = String.format("Rendering done in %s (%s text) ms\n"
+ "(%s points, %s points inside, %s objects visile from %s)\n" + res,//$NON-NLS-1$
time, rc.textRenderingTime, rc.pointCount, rc.pointInsideCount, rc.visible, rc.allObjects);
} catch (Exception e) {
e.printStackTrace();
}
} }
cv.drawRect(0, 0, bmp.getWidth(), bmp.getHeight(), paintFillEmpty);
// put in order map
TIntObjectHashMap<TIntArrayList> orderMap = sortObjectsByProperOrder(rc, objects, render);
int objCount = 0;
int[] keys = orderMap.keys();
Arrays.sort(keys);
boolean shadowDrawn = false;
for (int k = 0; k < keys.length; k++) {
if (!shadowDrawn && keys[k] >= rc.shadowLevelMin && keys[k] <= rc.shadowLevelMax && rc.shadowRenderingMode > 1) {
for (int ki = k; ki < keys.length; ki++) {
if (keys[ki] > rc.shadowLevelMax || rc.interrupted) {
break;
}
TIntArrayList list = orderMap.get(keys[ki]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
// show text only for main type
drawObj(obj, render, cv, rc, l, l == 0, true);
objCount++;
}
}
shadowDrawn = true;
}
if (rc.interrupted) {
return null;
}
TIntArrayList list = orderMap.get(keys[k]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
// show text only for main type
drawObj(obj, render, cv, rc, l, l == 0, false);
objCount++;
}
if (objCount > 25) {
notifyListeners(notifyList);
objCount = 0;
}
}
long beforeIconTextTime = System.currentTimeMillis() - now;
notifyListeners(notifyList);
drawIconsOverCanvas(rc, cv);
notifyListeners(notifyList);
drawTextOverCanvas(rc, cv, useEnglishNames);
long time = System.currentTimeMillis() - now;
rc.renderingDebugInfo = String.format("Rendering done in %s (%s text) ms\n"
+ "(%s points, %s points inside, %s objects visile from %s)",//$NON-NLS-1$
time, time - beforeIconTextTime, rc.pointCount, rc.pointInsideCount, rc.visible, rc.allObjects);
log.info(rc.renderingDebugInfo);
} }
return bmp; return bmp;