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 {
|
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"});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
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 <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
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue