Implement C++ read
This commit is contained in:
parent
99029a0785
commit
d8bf714a03
15 changed files with 1093 additions and 13569 deletions
|
@ -34,7 +34,7 @@ public class BinaryInspector {
|
|||
public static void main(String[] args) throws IOException {
|
||||
inspector(args);
|
||||
// test cases show info
|
||||
//inspector(new String[]{"/home/victor/projects/OsmAnd/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"});
|
||||
|
||||
|
||||
|
|
|
@ -56,9 +56,9 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH) \
|
|||
$(ANDROID_FOLDER)/frameworks/base/include
|
||||
|
||||
LOCAL_CPP_EXTENSION := .cpp
|
||||
LOCAL_SRC_FILES := common.cpp \
|
||||
LOCAL_SRC_FILES := common.cpp mapObjects.cpp \
|
||||
renderRules.cpp rendering.cpp \
|
||||
proto/osmand_odb.pb.cpp binaryRead.cpp
|
||||
binaryRead.cpp
|
||||
|
||||
LOCAL_CFLAGS := -Wall -g -DGOOGLE_PROTOBUF_NO_RTTI
|
||||
# in that case libskia_2.2.so should be in NDK folder to be properly built
|
||||
|
|
|
@ -6,16 +6,19 @@
|
|||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <hash_map>
|
||||
#include "google/protobuf/io/zero_copy_stream_impl.h"
|
||||
#include "google/protobuf/wire_format_lite.h"
|
||||
#include "google/protobuf/wire_format_lite.cc"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
|
||||
#include "renderRules.h"
|
||||
#include "common.h"
|
||||
#include "mapObjects.h"
|
||||
#include "proto/osmand_odb.pb.h"
|
||||
|
||||
char errorMsg[1024];
|
||||
#define INT_MAX 0x7fffffff /* max value for an int */
|
||||
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
|
||||
using namespace google::protobuf;
|
||||
using namespace google::protobuf::internal;
|
||||
|
||||
|
@ -24,16 +27,16 @@ std::map<std::string, BinaryMapFile*> openFiles;
|
|||
|
||||
inline bool readInt(io::CodedInputStream* input, uint32* sz) {
|
||||
uint8 buf[4];
|
||||
if(!input->ReadRaw(buf, 4)){
|
||||
if (!input->ReadRaw(buf, 4)) {
|
||||
return false;
|
||||
}
|
||||
*sz = ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skipFixed32(io::CodedInputStream* input){
|
||||
bool skipFixed32(io::CodedInputStream* input) {
|
||||
uint32 sz;
|
||||
if(!readInt(input, &sz)) {
|
||||
if (!readInt(input, &sz)) {
|
||||
return false;
|
||||
}
|
||||
return input->Skip(sz);
|
||||
|
@ -44,26 +47,267 @@ bool skipUnknownFields(io::CodedInputStream* input, int tag) {
|
|||
if (!skipFixed32(input)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!WireFormat::SkipField(input, tag, NULL)) {
|
||||
} else if (!WireFormatLite::SkipField(input, tag)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct BinaryMapFile {
|
||||
io::FileInputStream* input;
|
||||
std::string inputName;
|
||||
struct SearchQuery {
|
||||
RenderingRuleSearchRequest* req;
|
||||
int left;
|
||||
int right;
|
||||
int top;
|
||||
int bottom;
|
||||
int zoom;
|
||||
SearchResult* res;
|
||||
|
||||
~BinaryMapFile() {
|
||||
input->Close();
|
||||
delete input;
|
||||
std::vector<std::pair<int, int> > cacheCoordinates;
|
||||
std::vector<int> cacheTypes;
|
||||
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::GetTagFieldNumber(tag)
|
||||
bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
|
||||
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
|
||||
uint32 tag;
|
||||
uint32 version = -1;
|
||||
uint32 versionConfirm = -2;
|
||||
|
@ -74,10 +318,17 @@ bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
|
|||
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &version)));
|
||||
break;
|
||||
}
|
||||
// case OsmAndStructure::kMapIndexFieldNumber : {
|
||||
// // TODO
|
||||
// break;
|
||||
// }
|
||||
case OsmAndStructure::kMapIndexFieldNumber: {
|
||||
MapIndex mapIndex;
|
||||
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: {
|
||||
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &versionConfirm)));
|
||||
break;
|
||||
|
@ -89,7 +340,6 @@ bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
|
|||
if (!skipUnknownFields(input, tag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -99,28 +349,398 @@ bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
|
|||
"Corrupted file. It should be ended as it starts with version");
|
||||
return false;
|
||||
}
|
||||
#undef DO_
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void loadJniBinaryRead() {
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_initBinaryMapFile(JNIEnv* ienv,
|
||||
extern "C" JNIEXPORT void JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_deleteSearchResult(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) {
|
||||
// Verify that the version of the library that we linked against is
|
||||
setGlobalEnv(ienv);
|
||||
const char* utf = ienv->GetStringUTFChars((jstring)path, NULL);
|
||||
const char* utf = ienv->GetStringUTFChars((jstring) path, NULL);
|
||||
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;
|
||||
std::map<std::string, BinaryMapFile*>::iterator iterator;
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
BinaryMapFile* mapFile = new BinaryMapFile();
|
||||
mapFile->input = new io::FileInputStream(fileno(file));
|
||||
io::CodedInputStream cis (mapFile->input);
|
||||
mapFile->f = file;
|
||||
io::FileInputStream input(fileno(file));
|
||||
input.SetCloseOnDelete(false);
|
||||
io::CodedInputStream cis(&input);
|
||||
cis.SetTotalBytesLimit(INT_MAX, INT_MAX >> 2);
|
||||
if (!initMapStructure(&cis, mapFile)) {
|
||||
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;
|
||||
}
|
||||
|
||||
#undef DO_
|
||||
#endif
|
||||
|
|
152
OsmAnd/jni/osmand/mapObjects.cpp
Normal file
152
OsmAnd/jni/osmand/mapObjects.cpp
Normal 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*/
|
|
@ -1,45 +1,33 @@
|
|||
#ifndef _OSMAND_MAP_OBJECTS_H
|
||||
#define _OSMAND_MAP_OBJECTS_H
|
||||
|
||||
#include <jni.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
public :
|
||||
static const unsigned int UNDEFINED_STRING = 0x7fffffff;
|
||||
const int type;
|
||||
static const int MAP_DATA_OBJECT = 1;
|
||||
static const int MULTI_POLYGON = 2;
|
||||
long long id;
|
||||
unsigned int stringId;
|
||||
std::string name;
|
||||
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:
|
||||
MultiPolygonObject() : BaseMapDataObject(MULTI_POLYGON) { }
|
||||
|
@ -50,12 +38,11 @@ public:
|
|||
std::vector< std::vector< std::pair<int, int> > > points;
|
||||
};
|
||||
|
||||
class MapDataObject : BaseMapDataObject
|
||||
class MapDataObject : public BaseMapDataObject
|
||||
{
|
||||
public:
|
||||
MapDataObject() : BaseMapDataObject(MAP_DATA_OBJECT) { }
|
||||
|
||||
std::string name;
|
||||
std::vector< int> types;
|
||||
std::vector< std::pair<int, int> > points;
|
||||
std::vector< std::pair<std::string, std::string> > tagValues;
|
||||
|
@ -63,118 +50,12 @@ public:
|
|||
};
|
||||
|
||||
|
||||
std::vector <BaseMapDataObject* > marshalObjects(jobjectArray binaryMapDataObjects)
|
||||
{
|
||||
std::vector<BaseMapDataObject*> v;
|
||||
std::vector <BaseMapDataObject* > marshalObjects(jobjectArray binaryMapDataObjects);
|
||||
|
||||
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);
|
||||
void deleteObjects(std::vector <BaseMapDataObject* > & v);
|
||||
|
||||
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) );
|
||||
}
|
||||
void loadJniMapObjects();
|
||||
|
||||
o->points.push_back(vs);
|
||||
o->names.push_back(getStringMethod(binaryMapDataObject, MultiPolygon_getName, ji));
|
||||
}
|
||||
void unloadJniMapObjects();
|
||||
|
||||
|
||||
|
||||
} 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_H*/
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -64,6 +64,9 @@ private:
|
|||
void initRules();
|
||||
|
||||
public:
|
||||
// No rules for multipolygon !!!
|
||||
const static int MULTI_POLYGON_TYPE = 0;
|
||||
|
||||
const static int POINT_RULES = 1;
|
||||
const static int LINE_RULES = 2;
|
||||
const static int POLYGON_RULES = 3;
|
||||
|
|
|
@ -699,7 +699,7 @@ void doRendering(std::vector <BaseMapDataObject* > mapDataObjects, SkCanvas* can
|
|||
extern "C" {
|
||||
#endif
|
||||
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) {
|
||||
setGlobalEnv(ienv);
|
||||
SkBitmap* bmp = getNativeBitmap(bmpObj);
|
||||
|
@ -710,17 +710,15 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
|
|||
|
||||
SkPaint* paint = new SkPaint;
|
||||
paint->setAntiAlias(true);
|
||||
|
||||
__android_log_print(ANDROID_LOG_WARN, "net.osmand", "Initializing rendering");
|
||||
watcher initObjects;
|
||||
initObjects.start();
|
||||
|
||||
|
||||
RenderingRuleSearchRequest* req = initSearchRequest(renderingRuleSearchRequest);
|
||||
|
||||
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");
|
||||
|
@ -729,7 +727,9 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
|
|||
|
||||
// Main part do rendering
|
||||
rc.nativeOperations.start();
|
||||
doRendering(mapDataObjects, canvas, paint, req, &rc);
|
||||
if(result != NULL) {
|
||||
doRendering(result->result, canvas, paint, req, &rc);
|
||||
}
|
||||
rc.nativeOperations.pause();
|
||||
|
||||
mergeRenderingContext(renderingContext, &rc);
|
||||
|
@ -739,17 +739,14 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
|
|||
delete paint;
|
||||
delete canvas;
|
||||
delete req;
|
||||
deleteObjects(mapDataObjects);
|
||||
// deleteObjects(mapDataObjects);
|
||||
|
||||
#ifdef DEBUG_NAT_OPERATIONS
|
||||
sprintf(debugMessage, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
|
||||
#else
|
||||
sprintf(debugMessage, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
|
||||
#endif
|
||||
jstring result = globalEnv()->NewStringUTF( debugMessage);
|
||||
|
||||
// unloadLibrary();
|
||||
return result;
|
||||
return globalEnv()->NewStringUTF( debugMessage);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -26,27 +26,7 @@ LOCAL_MODULE_TAGS := optional
|
|||
LOCAL_CPP_EXTENSION := .cc
|
||||
|
||||
LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES) \
|
||||
google/protobuf/stubs/strutil.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 \
|
||||
google/protobuf/io/zero_copy_stream_impl.cc
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
|
||||
|
|
|
@ -151,6 +151,19 @@ void CodedInputStream::PrintTotalBytesLimitError() {
|
|||
"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) {
|
||||
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) {
|
||||
// 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.
|
||||
|
|
|
@ -162,6 +162,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
// occurs.
|
||||
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
|
||||
// underlying buffer, and *size to the size of that buffer, but does not
|
||||
// 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.
|
||||
int BytesUntilLimit();
|
||||
|
||||
// osmand change : totally bytes read
|
||||
int getTotalBytesRead();
|
||||
|
||||
// Total Bytes Limit -----------------------------------------------
|
||||
// To prevent malicious users from sending excessively large messages
|
||||
// and causing integer overflows or memory exhaustion, CodedInputStream
|
||||
|
|
Binary file not shown.
|
@ -37,6 +37,7 @@ import net.osmand.plus.OsmandSettings.CommonPreference;
|
|||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.RotatedTileBox;
|
||||
import net.osmand.plus.activities.OsmandApplication;
|
||||
import net.osmand.plus.render.NativeOsmandLibrary.NativeSearchResult;
|
||||
import net.osmand.plus.render.OsmandRenderer.RenderingContext;
|
||||
import net.osmand.render.RenderingRuleProperty;
|
||||
import net.osmand.render.RenderingRuleSearchRequest;
|
||||
|
@ -67,6 +68,7 @@ public class MapRenderRepositories {
|
|||
private RectF cObjectsBox = new RectF();
|
||||
// cached objects in order to render rotation without reloading data from db
|
||||
private List<BinaryMapDataObject> cObjects = new LinkedList<BinaryMapDataObject>();
|
||||
private NativeSearchResult cNativeObjects = null;
|
||||
|
||||
// currently rendered box (not the same as already rendered)
|
||||
// this box is checked for interrupted process or
|
||||
|
@ -227,6 +229,50 @@ public class MapRenderRepositories {
|
|||
}
|
||||
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) {
|
||||
double cBottomLatitude = dataBox.bottom;
|
||||
|
@ -234,7 +280,6 @@ public class MapRenderRepositories {
|
|||
double cLeftLongitude = dataBox.left;
|
||||
double cRightLongitude = dataBox.right;
|
||||
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
|
@ -302,15 +347,7 @@ public class MapRenderRepositories {
|
|||
if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) {
|
||||
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);
|
||||
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter);
|
||||
List<BinaryMapDataObject> res = c.searchMapIndex(searchRequest);
|
||||
|
@ -420,7 +457,7 @@ public class MapRenderRepositories {
|
|||
long now = System.currentTimeMillis();
|
||||
|
||||
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
|
||||
if ((dataBox.right - dataBox.left) > (dataBox.top - dataBox.bottom)) {
|
||||
double wi = (dataBox.right - dataBox.left) * .2;
|
||||
|
@ -432,7 +469,14 @@ public class MapRenderRepositories {
|
|||
dataBox.bottom -= hi;
|
||||
}
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
|
@ -462,9 +506,14 @@ public class MapRenderRepositories {
|
|||
this.prevBmpLocation = this.bmpLocation;
|
||||
this.bmp = bmp;
|
||||
this.bmpLocation = tileRect;
|
||||
|
||||
renderer.generateNewBitmap(currentRenderingContext, cObjects, bmp, prefs.USE_ENGLISH_NAMES.get(), renderingReq,
|
||||
notifyList, storage.getBgColor(nightMode), app.getSettings().NATIVE_RENDERING.get());
|
||||
|
||||
if(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;
|
||||
currentRenderingContext.ended = true;
|
||||
if (checkWhetherInterrupted()) {
|
||||
|
@ -846,9 +895,9 @@ public class MapRenderRepositories {
|
|||
int sy = (int) (i.get(0) & mask);
|
||||
boolean st = y == topY || x == rightX || y == bottomY || x == 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
|
||||
// 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.
|
||||
if (!end || !st) {
|
||||
float dx = (float) MapUtils.get31LongitudeX(x);
|
||||
|
|
|
@ -1,24 +1,75 @@
|
|||
package net.osmand.plus.render;
|
||||
|
||||
|
||||
import net.osmand.binary.BinaryMapDataObject;
|
||||
import net.osmand.plus.render.OsmandRenderer.RenderingContext;
|
||||
import net.osmand.render.RenderingRuleSearchRequest;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public class NativeOsmandLibrary {
|
||||
|
||||
|
||||
static {
|
||||
System.loadLibrary("osmand");
|
||||
}
|
||||
|
||||
public static void preloadLibrary() {}
|
||||
|
||||
|
||||
public static native String generateRendering(RenderingContext rc, BinaryMapDataObject[] objects, Bitmap bmp,
|
||||
boolean useEnglishNames, RenderingRuleSearchRequest render, int defaultColor);
|
||||
|
||||
|
||||
|
||||
public static void preloadLibrary() {
|
||||
}
|
||||
|
||||
public static String generateRendering(RenderingContext rc, NativeSearchResult searchResultHandler, Bitmap bmp,
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
|
|||
import net.osmand.data.MapTileDownloader.IMapDownloaderCallback;
|
||||
import net.osmand.osm.MapRenderingTypes;
|
||||
import net.osmand.osm.MultyPolygon;
|
||||
import net.osmand.plus.render.NativeOsmandLibrary.NativeSearchResult;
|
||||
import net.osmand.render.RenderingRuleProperty;
|
||||
import net.osmand.render.RenderingRuleSearchRequest;
|
||||
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,
|
||||
RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList, int defaultColor, boolean nativeRendering) {
|
||||
RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList, int defaultColor) {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
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.density = dm.density;
|
||||
|
||||
if (!nativeRendering) {
|
||||
// fill area
|
||||
Canvas cv = new Canvas(bmp);
|
||||
if(defaultColor != 0){
|
||||
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();
|
||||
}
|
||||
// fill area
|
||||
Canvas cv = new Canvas(bmp);
|
||||
if (defaultColor != 0) {
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
return bmp;
|
||||
|
|
Loading…
Reference in a new issue