Small improvements
This commit is contained in:
parent
d8bf714a03
commit
1a2f38a916
14 changed files with 726 additions and 99 deletions
|
@ -14,6 +14,7 @@
|
|||
#include "renderRules.h"
|
||||
#include "common.h"
|
||||
#include "mapObjects.h"
|
||||
#include "multipolygons.h"
|
||||
#include "proto/osmand_odb.pb.h"
|
||||
|
||||
char errorMsg[1024];
|
||||
|
@ -61,7 +62,10 @@ struct SearchQuery {
|
|||
int top;
|
||||
int bottom;
|
||||
int zoom;
|
||||
SearchResult* res;
|
||||
std::vector< MapDataObject*> result;
|
||||
|
||||
jobject o;
|
||||
jfieldID interruptedField;
|
||||
|
||||
std::vector<std::pair<int, int> > cacheCoordinates;
|
||||
std::vector<int> cacheTypes;
|
||||
|
@ -71,17 +75,15 @@ struct SearchQuery {
|
|||
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) {
|
||||
SearchQuery(int l, int r, int t, int b, RenderingRuleSearchRequest* req, jobject o, jfieldID interruptedField) :
|
||||
req(req), left(l), right(r), top(t), bottom(b), o(o), interruptedField(interruptedField) {
|
||||
numberOfAcceptedObjects = numberOfVisitedObjects = 0;
|
||||
numberOfAcceptedSubtrees = numberOfReadSubtrees = 0;
|
||||
interrupted = false;
|
||||
}
|
||||
|
||||
bool isCancelled(){
|
||||
return interrupted;
|
||||
return globalEnv()->GetBooleanField(o, interruptedField);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -110,7 +112,7 @@ struct MapIndex {
|
|||
uint32 length;
|
||||
int filePointer;
|
||||
std::string name;
|
||||
std::hash_map<int, std::pair<std::string, std::string> > decodingRules;
|
||||
std::hash_map<int, tag_value > decodingRules;
|
||||
vector<MapRoot> levels;
|
||||
};
|
||||
|
||||
|
@ -393,7 +395,7 @@ 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,
|
||||
MapDataObject* 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)) {
|
||||
|
@ -468,7 +470,7 @@ BaseMapDataObject* readMapDataObject(io::CodedInputStream* input, int left, int
|
|||
if (mask != RenderingRulesStorage::POINT_RULES) {
|
||||
type = type & MASK_10;
|
||||
}
|
||||
std::pair<std::string, std::string> pair = root->decodingRules[type];
|
||||
tag_value pair = root->decodingRules[type];
|
||||
if (r != NULL && !accept) {
|
||||
if(mask == RenderingRulesStorage::MULTI_POLYGON_TYPE){
|
||||
mask = RenderingRulesStorage::POLYGON_RULES;
|
||||
|
@ -589,11 +591,11 @@ bool searchMapTreeBounds(io::CodedInputStream* input, int pleft, int pright, int
|
|||
input->ReadVarint32(&length);
|
||||
int oldLimit = input->PushLimit(length);
|
||||
if (lastIndexResult == -1) {
|
||||
lastIndexResult = req->res->result.size();
|
||||
lastIndexResult = req->result.size();
|
||||
}
|
||||
BaseMapDataObject* mapObject = readMapDataObject(input, cleft, cright, ctop, cbottom, req, root);
|
||||
MapDataObject* mapObject = readMapDataObject(input, cleft, cright, ctop, cbottom, req, root);
|
||||
if (mapObject != NULL) {
|
||||
req->res->result.push_back(mapObject);
|
||||
req->result.push_back(mapObject);
|
||||
}
|
||||
input->Skip(input->BytesUntilLimit());
|
||||
input->PopLimit(oldLimit);
|
||||
|
@ -618,10 +620,10 @@ bool searchMapTreeBounds(io::CodedInputStream* input, int pleft, int pright, int
|
|||
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);
|
||||
for (uint32 i = lastIndexResult; i < req->result.size(); i++) {
|
||||
BaseMapDataObject* rs = req->result.at(i);
|
||||
rs->id += baseId;
|
||||
// TODO restrictions are not supported
|
||||
// restrictions are not supported
|
||||
// if (rs.restrictions != null) {
|
||||
// for (int j = 0; j < rs.restrictions.length; j++) {
|
||||
// rs.restrictions[j] += baseId;
|
||||
|
@ -640,8 +642,8 @@ bool searchMapTreeBounds(io::CodedInputStream* input, int pleft, int pright, int
|
|||
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);
|
||||
for (uint32 i = lastIndexResult; i < req->result.size(); i++) {
|
||||
BaseMapDataObject* rs = req->result.at(i);
|
||||
if (rs->stringId != BaseMapDataObject::UNDEFINED_STRING) {
|
||||
rs->name = stringTable.at(rs->stringId);
|
||||
}
|
||||
|
@ -685,7 +687,8 @@ void searchMapData(io::CodedInputStream* input, MapRoot* root, MapIndex* ind, Se
|
|||
|
||||
extern "C" JNIEXPORT jint JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_searchObjectsForRendering(JNIEnv* ienv,
|
||||
jobject obj, jint sleft, jint sright, jint stop, jint sbottom, jint zoom, jstring mapName,
|
||||
jobject renderingRuleSearchRequest, bool skipDuplicates, jint searchResult) {
|
||||
jobject renderingRuleSearchRequest, bool skipDuplicates, jint searchResult, jobject objInterrupted) {
|
||||
// TODO skipDuplicates not supported
|
||||
setGlobalEnv(ienv);
|
||||
SearchResult* result = (SearchResult*) searchResult;
|
||||
if(result == NULL) {
|
||||
|
@ -698,7 +701,10 @@ extern "C" JNIEXPORT jint JNICALL Java_net_osmand_plus_render_NativeOsmandLibrar
|
|||
}
|
||||
BinaryMapFile* file = i->second;
|
||||
RenderingRuleSearchRequest* req = initSearchRequest(renderingRuleSearchRequest);
|
||||
SearchQuery q(sleft,sright, stop, sbottom, req, result);
|
||||
jclass clObjInterrupted = globalEnv()->GetObjectClass(objInterrupted);
|
||||
jfieldID interruptedField = getFid(clObjInterrupted, "interrupted", "Z");
|
||||
globalEnv()->DeleteLocalRef(clObjInterrupted);
|
||||
SearchQuery q(sleft,sright, stop, sbottom, req, objInterrupted, interruptedField);
|
||||
|
||||
fseek(file->f, 0, 0);
|
||||
io::FileInputStream input(fileno(file->f));
|
||||
|
@ -724,11 +730,25 @@ extern "C" JNIEXPORT jint JNICALL Java_net_osmand_plus_render_NativeOsmandLibrar
|
|||
}
|
||||
}
|
||||
}
|
||||
// if(result->result.size() > 0) {
|
||||
result->result.insert(result->result.end(), q.result.begin(), q.result.end());
|
||||
std::map<tagValueType, std::vector<MapDataObject*> > multyPolygons;
|
||||
std::vector<MapDataObject*>::iterator mdo = q.result.begin();
|
||||
for(;mdo!= q.result.end(); mdo++) {
|
||||
for(size_t j = 0; j<(*mdo)->types.size(); j++) {
|
||||
int type = (*mdo)->types.at(j);
|
||||
if((type & 0x3) == RenderingRulesStorage::MULTI_POLYGON_TYPE) {
|
||||
tagValueType tagValue((*mdo)->tagValues.at(j), type);
|
||||
multyPolygons[tagValue].push_back(*mdo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proccessMultiPolygons(multyPolygons, q.left, q.right, q.bottom, q.top, q.zoom, result->result);
|
||||
if(q.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;
|
||||
}
|
||||
|
|
|
@ -223,6 +223,7 @@ void copyRenderingContext(jobject orc, RenderingContext* rc)
|
|||
rc->shadowLevelMin = globalEnv()->GetIntField( orc, getFid( RenderingContextClass, "shadowLevelMin", "I" ) );
|
||||
rc->shadowLevelMax = globalEnv()->GetIntField( orc, getFid( RenderingContextClass, "shadowLevelMax", "I" ) );
|
||||
rc->androidContext = globalEnv()->GetObjectField(orc, getFid( RenderingContextClass, "ctx", "Landroid/content/Context;"));
|
||||
rc->lastRenderedKey = 0;
|
||||
|
||||
rc->originalRC = orc;
|
||||
|
||||
|
@ -236,6 +237,8 @@ void mergeRenderingContext(jobject orc, RenderingContext* rc)
|
|||
globalEnv()->SetIntField( orc, getFid(RenderingContextClass, "visible", "I" ) , rc->visible);
|
||||
globalEnv()->SetIntField( orc, getFid(RenderingContextClass, "allObjects", "I" ) , rc->allObjects);
|
||||
globalEnv()->SetIntField( orc, getFid(RenderingContextClass, "textRenderingTime", "I" ) , rc->textRendering.getElapsedTime());
|
||||
globalEnv()->SetIntField( orc, getFid(RenderingContextClass, "lastRenderedKey", "I" ) , rc->lastRenderedKey);
|
||||
|
||||
globalEnv()->DeleteLocalRef(rc->androidContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -128,9 +128,11 @@ struct RenderingContext {
|
|||
int pointInsideCount;
|
||||
int visible;
|
||||
int allObjects;
|
||||
int lastRenderedKey;
|
||||
watcher textRendering;
|
||||
watcher nativeOperations;
|
||||
|
||||
|
||||
// use to calculate points
|
||||
float calcX;
|
||||
float calcY;
|
||||
|
|
|
@ -149,4 +149,14 @@ void unloadJniMapObjects()
|
|||
globalEnv()->DeleteGlobalRef( TagValuePairClass );
|
||||
}
|
||||
|
||||
int getNegativeWayLayer(int type) {
|
||||
int i = (3 & (type >> 12));
|
||||
if (i == 1) {
|
||||
return -1;
|
||||
} else if (i == 2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*_OSMAND_MAP_OBJECTS*/
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
typedef std::pair<std::string, std::string> tag_value;
|
||||
typedef std::pair<int, int> int_pair;
|
||||
|
||||
class BaseMapDataObject
|
||||
{
|
||||
|
||||
|
@ -35,17 +38,18 @@ public:
|
|||
std::string value;
|
||||
std::vector< std::string > names;
|
||||
int layer;
|
||||
std::vector< std::vector< std::pair<int, int> > > points;
|
||||
std::vector< std::vector< int_pair> > points;
|
||||
};
|
||||
|
||||
|
||||
class MapDataObject : public BaseMapDataObject
|
||||
{
|
||||
public:
|
||||
MapDataObject() : BaseMapDataObject(MAP_DATA_OBJECT) { }
|
||||
|
||||
std::vector< int> types;
|
||||
std::vector< std::pair<int, int> > points;
|
||||
std::vector< std::pair<std::string, std::string> > tagValues;
|
||||
std::vector< int_pair > points;
|
||||
std::vector< tag_value > tagValues;
|
||||
int highwayAttributes;
|
||||
};
|
||||
|
||||
|
@ -58,4 +62,7 @@ void loadJniMapObjects();
|
|||
|
||||
void unloadJniMapObjects();
|
||||
|
||||
// 0 - normal, -1 - under, 1 - bridge,over
|
||||
int getNegativeWayLayer(int type);
|
||||
|
||||
#endif /*_OSMAND_MAP_OBJECTS_H*/
|
||||
|
|
605
OsmAnd/jni/osmand/multipolygons.h
Normal file
605
OsmAnd/jni/osmand/multipolygons.h
Normal file
|
@ -0,0 +1,605 @@
|
|||
|
||||
#include <android/log.h>
|
||||
#include <stdio.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <hash_map>
|
||||
|
||||
|
||||
#include "renderRules.h"
|
||||
#include "common.h"
|
||||
#include "mapObjects.h"
|
||||
|
||||
#define INT_MAX 0x7fffffff /* max value for an int */
|
||||
#define INT_MIN (-0x7fffffff-1) /* min value for an int */
|
||||
|
||||
char textMsg[1024] ;
|
||||
struct tagValueType {
|
||||
int type;
|
||||
std::string tag;
|
||||
std::string value;
|
||||
|
||||
tagValueType(tag_value t, int type) : type(type) {
|
||||
tag = t.first;
|
||||
value = t.second;
|
||||
}
|
||||
|
||||
};
|
||||
bool operator==(const tagValueType& __x, const tagValueType& __y) {
|
||||
return __x.type == __y.type;
|
||||
}
|
||||
bool operator<(const tagValueType& __x, const tagValueType& __y) {
|
||||
return __x.type < __y.type;
|
||||
}
|
||||
/// !!! Fuly copied from MapRenderRepositories.java, should be carefully synchroinized
|
||||
bool isClockwiseWay(std::vector<int_pair>& c) ;
|
||||
bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX,
|
||||
int bottomY, int topY, std::vector<int_pair>& coordinates);
|
||||
|
||||
void processMultipolygonLine(std::vector<std::vector<int_pair> >& completedRings, std::vector<std::vector<int_pair> >& incompletedRings,
|
||||
std::vector<std::string> &completedRingsNames, std::vector<std::string> &incompletedRingsNames, std::vector<int_pair> & coordinates, std::string name);
|
||||
|
||||
void unifyIncompletedRings(std::vector<std::vector<int_pair> >& incompletedRings, std::vector<std::vector<int_pair> >& completedRings, std::vector<std::string> &completedRingNames,
|
||||
std::vector<std::string> &incompletedRingNames, int leftX, int rightX, int bottomY, int topY, long dbId, int zoom);
|
||||
|
||||
MultiPolygonObject* processMultiPolygon(int leftX, int rightX, int bottomY, int topY,
|
||||
std::vector<std::vector<int_pair > >& completedRings, std::vector<std::vector<int_pair> >& incompletedRings,
|
||||
std::vector<std::string>& completedRingNames, std::vector<std::string>& incompletedRingNames,
|
||||
const tagValueType& type, std::vector<MapDataObject* > & directList, std::vector<MapDataObject*>& inverselist,
|
||||
int zoom) {
|
||||
MultiPolygonObject* pl = new MultiPolygonObject();
|
||||
// delete direction last bit (to not show point)
|
||||
pl->tag = type.tag;
|
||||
pl->value = type.value;
|
||||
pl->layer = getNegativeWayLayer(type.type);
|
||||
long long dbId = 0;
|
||||
for (int km = 0; km < 2; km++) {
|
||||
std::vector<MapDataObject* >::iterator o = (km == 0 ? directList.begin() : inverselist.begin());
|
||||
std::vector<MapDataObject* >::iterator oEnd = (km == 0 ? directList.end() : inverselist.end());
|
||||
for (; o != oEnd; o++) {
|
||||
int len = (*o)->points.size();
|
||||
if (len < 2) {
|
||||
continue;
|
||||
}
|
||||
dbId = (*o)->id >> 1;
|
||||
std::vector<int_pair> coordinates;
|
||||
int_pair p = (*o)->points.at(km == 0 ? 0 : len - 1);
|
||||
int px = p.first;
|
||||
int py = p.second;
|
||||
int x = p.first;
|
||||
int y = p.second;
|
||||
bool pinside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
|
||||
if (pinside) {
|
||||
coordinates.push_back(int_pair(x, y));
|
||||
}
|
||||
for (int i = 1; i < len; i++) {
|
||||
int_pair cp = (*o)->points.at(km == 0 ? i : len - i - 1);
|
||||
x = cp.first;
|
||||
y = cp.second;
|
||||
bool inside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
|
||||
bool lineEnded = calculateLineCoordinates(inside, x, y, pinside, px, py, leftX, rightX, bottomY, topY,
|
||||
coordinates);
|
||||
if (lineEnded) {
|
||||
processMultipolygonLine(completedRings, incompletedRings, completedRingNames, incompletedRingNames,
|
||||
coordinates, (*o)->name);
|
||||
// create new line if it goes outside
|
||||
coordinates.clear();
|
||||
}
|
||||
px = x;
|
||||
py = y;
|
||||
pinside = inside;
|
||||
}
|
||||
processMultipolygonLine(completedRings, incompletedRings, completedRingNames, incompletedRingNames,
|
||||
coordinates, (*o)->name);
|
||||
}
|
||||
}
|
||||
if (completedRings.size() == 0 && incompletedRings.size() == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (incompletedRings.size() > 0) {
|
||||
unifyIncompletedRings(incompletedRings, completedRings, completedRingNames, incompletedRingNames, leftX, rightX,
|
||||
bottomY, topY, dbId, zoom);
|
||||
} else {
|
||||
// due to self intersection small objects (for low zooms check only coastline)
|
||||
if (zoom >= 13 || ("natural" == type.tag && "coastline" == type.value)) {
|
||||
bool clockwiseFound = false;
|
||||
std::vector<std::vector<int_pair> > ::iterator c = completedRings.begin();
|
||||
for (; c != completedRings.end(); c++) {
|
||||
if (isClockwiseWay(*c)) {
|
||||
clockwiseFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!clockwiseFound) {
|
||||
// add whole bound
|
||||
std::vector<int_pair> whole;
|
||||
whole.push_back(int_pair(leftX, topY));
|
||||
whole.push_back(int_pair(rightX, topY));
|
||||
whole.push_back(int_pair(leftX, bottomY));
|
||||
whole.push_back(int_pair(rightX, bottomY));
|
||||
completedRings.push_back(whole);
|
||||
__android_log_print(ANDROID_LOG_INFO, "net.osmand", "!!! Isolated island !!!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pl->names = completedRingNames;
|
||||
pl->points = completedRings;
|
||||
return pl;
|
||||
}
|
||||
|
||||
static std::vector<MapDataObject*> EMPTY_LIST;
|
||||
void proccessMultiPolygons(std::map<tagValueType, std::vector<MapDataObject*> >& multyPolygons, int leftX,
|
||||
int rightX, int bottomY, int topY, int zoom, std::vector<BaseMapDataObject*>& listPolygons) {
|
||||
std::vector<std::vector<int_pair> > completedRings;
|
||||
std::vector<std::vector<int_pair> > incompletedRings;
|
||||
std::vector<std::string> completedRingNames;
|
||||
std::vector<std::string> incompletedRingNames;
|
||||
std::map<tagValueType, std::vector<MapDataObject*> >::iterator val = multyPolygons.begin();
|
||||
for (; val != multyPolygons.end(); val++) {
|
||||
std::vector<MapDataObject*>* directList;
|
||||
std::vector<MapDataObject*>* inverselist;
|
||||
if (((val->first.type >> 15) & 1) == 1) {
|
||||
tagValueType directType = val->first;
|
||||
directType.type = val->first.type & ((1 << 15) - 1);
|
||||
if (multyPolygons.find(directType) == multyPolygons.end()) {
|
||||
inverselist = &val->second;
|
||||
directList = &EMPTY_LIST;
|
||||
} else {
|
||||
// continue on inner boundaries
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
tagValueType inverseType = val->first;
|
||||
inverseType.type = val->first.type | (1 << 15);
|
||||
directList = &val->second;
|
||||
inverselist = &multyPolygons[inverseType];
|
||||
}
|
||||
completedRings.clear();
|
||||
incompletedRings.clear();
|
||||
completedRingNames.clear();
|
||||
incompletedRingNames.clear();
|
||||
|
||||
sprintf(textMsg, "Process multipolygon %s %s direct list %d rev %d", val->first.tag.c_str(), val->first.value.c_str(), directList->size(), inverselist->size());
|
||||
__android_log_print(ANDROID_LOG_INFO, "net.osmand", textMsg);
|
||||
MultiPolygonObject* pl = processMultiPolygon(leftX, rightX, bottomY, topY, completedRings, incompletedRings,
|
||||
completedRingNames, incompletedRingNames, val->first, *directList, *inverselist, zoom);
|
||||
if (pl != NULL) {
|
||||
listPolygons.push_back(pl);
|
||||
} else {
|
||||
__android_log_print(ANDROID_LOG_INFO, "net.osmand", "Multipolygon skipped");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from MapAlgorithms
|
||||
int ray_intersect_x(int prevX, int prevY, int x, int y, int middleY) {
|
||||
// prev node above line
|
||||
// x,y node below line
|
||||
if (prevY > y) {
|
||||
int tx = prevX;
|
||||
int ty = prevY;
|
||||
x = prevX;
|
||||
y = prevY;
|
||||
prevX = tx;
|
||||
prevY = ty;
|
||||
}
|
||||
if (y == middleY || prevY == middleY) {
|
||||
middleY -= 1;
|
||||
}
|
||||
if (prevY > middleY || y < middleY) {
|
||||
return INT_MIN;
|
||||
} else {
|
||||
if (y == prevY) {
|
||||
// the node on the boundary !!!
|
||||
return x;
|
||||
}
|
||||
// that tested on all cases (left/right)
|
||||
double rx = x + ((double) middleY - y) * ((double) x - prevX) / (((double) y - prevY));
|
||||
return (int) rx;
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from MapAlgorithms
|
||||
bool isClockwiseWay(std::vector<int_pair>& c) {
|
||||
if (c.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// calculate middle Y
|
||||
long middleY = 0;
|
||||
for (size_t i = 0; i < c.size(); i++) {
|
||||
middleY += c.at(i).second;
|
||||
}
|
||||
middleY /= (long) c.size();
|
||||
|
||||
double clockwiseSum = 0;
|
||||
|
||||
bool firstDirectionUp = false;
|
||||
int previousX = INT_MIN;
|
||||
int firstX = INT_MIN;
|
||||
|
||||
int prevX = c.at(0).first;
|
||||
int prevY = c.at(0).second;
|
||||
|
||||
for (size_t i = 1; i < c.size(); i++) {
|
||||
int x = c.at(i).first;
|
||||
int y = c.at(i).second;
|
||||
int rX = ray_intersect_x(prevX, prevY, x, y, (int) middleY);
|
||||
if (rX != INT_MIN) {
|
||||
bool skipSameSide = (y <= middleY) == (prevY <= middleY);
|
||||
if (skipSameSide) {
|
||||
continue;
|
||||
}
|
||||
bool directionUp = prevY >= middleY;
|
||||
if (firstX == INT_MIN) {
|
||||
firstDirectionUp = directionUp;
|
||||
firstX = rX;
|
||||
} else {
|
||||
bool clockwise = (!directionUp) == (previousX < rX);
|
||||
if (clockwise) {
|
||||
clockwiseSum += abs(previousX - rX);
|
||||
} else {
|
||||
clockwiseSum -= abs(previousX - rX);
|
||||
}
|
||||
}
|
||||
previousX = rX;
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstX != INT_MIN) {
|
||||
bool clockwise = (!firstDirectionUp) == (previousX < firstX);
|
||||
if (clockwise) {
|
||||
clockwiseSum += abs(previousX - firstX);
|
||||
} else {
|
||||
clockwiseSum -= abs(previousX - firstX);
|
||||
}
|
||||
}
|
||||
|
||||
return clockwiseSum >= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void processMultipolygonLine(std::vector<std::vector<int_pair> >& completedRings, std::vector<std::vector<int_pair> >& incompletedRings,
|
||||
std::vector<std::string> &completedRingsNames,
|
||||
std::vector<std::string> &incompletedRingsNames, std::vector<int_pair> & coordinates, std::string name) {
|
||||
if (coordinates.size() > 0) {
|
||||
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
|
||||
completedRings.push_back(coordinates);
|
||||
completedRingsNames.push_back(name);
|
||||
} else {
|
||||
bool add = true;
|
||||
for (size_t k = 0; k < incompletedRings.size();) {
|
||||
bool remove = false;
|
||||
std::vector<int_pair> i = incompletedRings.at(k);
|
||||
std::string oldName = incompletedRingsNames.at(k);
|
||||
if (coordinates.at(0) == i.at(i.size() - 1)) {
|
||||
std::vector<int_pair>::iterator tit = coordinates.begin();
|
||||
i.insert(i.end(), ++tit, coordinates.end());
|
||||
remove = true;
|
||||
coordinates = i;
|
||||
} else if (coordinates.at(coordinates.size() - 1) == i.at(0)) {
|
||||
std::vector<int_pair>::iterator tit = i.begin();
|
||||
coordinates.insert(coordinates.end(), ++tit, i.end());
|
||||
remove = true;
|
||||
}
|
||||
if (remove) {
|
||||
std::vector<std::vector<int_pair> >::iterator ti = incompletedRings.begin();
|
||||
ti += k;
|
||||
incompletedRings.erase(ti);
|
||||
std::vector<std::string> :: iterator tis = incompletedRingsNames.begin();
|
||||
tis += k;
|
||||
incompletedRingsNames.erase(tis);
|
||||
} else {
|
||||
k++;
|
||||
}
|
||||
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
|
||||
completedRings.push_back(coordinates);
|
||||
if (oldName.length() > 0) {
|
||||
completedRingsNames.push_back(oldName);
|
||||
} else {
|
||||
completedRingsNames.push_back(name);
|
||||
}
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
incompletedRings.push_back(coordinates);
|
||||
incompletedRingsNames.push_back(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int safelyAddDelta(int number, int delta) {
|
||||
int res = number + delta;
|
||||
if (delta > 0 && res < number) {
|
||||
return INT_MAX;
|
||||
} else if (delta < 0 && res > number) {
|
||||
return INT_MIN;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void unifyIncompletedRings(std::vector<std::vector<int_pair> >& incompletedRings, std::vector<std::vector<int_pair> >& completedRings,
|
||||
std::vector<std::string> &completedRingNames, std::vector<std::string> & incompletedRingsNames,
|
||||
int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) {
|
||||
std::set<int> nonvisitedRings;
|
||||
std::vector<std::vector<int_pair> >::iterator ir = incompletedRings.begin();
|
||||
std::vector<std::string>::iterator irs = incompletedRingsNames.begin();
|
||||
int j = 0;
|
||||
for (j = 0; ir != incompletedRings.end(); ir++, irs++, j++) {
|
||||
int x = ir->at(0).first;
|
||||
int y = ir->at(0).second;
|
||||
int sx = x;
|
||||
int sy = y;
|
||||
bool st = y == topY || x == rightX || y == bottomY || x == leftX;
|
||||
bool end = sy == topY || sx == rightX || sy == bottomY || sx == leftX;
|
||||
// something goes wrong
|
||||
// These exceptions are used to check logic about processing multipolygons
|
||||
// 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) {
|
||||
// TODO message
|
||||
// float dx = (float) MapUtils.get31LongitudeX(x);
|
||||
// float dsx = (float) MapUtils.get31LongitudeX(sx);
|
||||
// float dy = (float) MapUtils.get31LatitudeY(y);
|
||||
// float dsy = (float) MapUtils.get31LatitudeY(sy);
|
||||
// String str;
|
||||
// if (!end) {
|
||||
// str = " Start point (to close) not found : end_x = {0}, end_y = {1}, start_x = {2}, start_y = {3} : bounds {4} {5} - {6} {7}"; //$NON-NLS-1$
|
||||
// System.err
|
||||
// .println(MessageFormat.format(dbId + str, dx, dy, dsx, dsy, leftX + "", topY + "", rightX + "", bottomY + "")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
||||
// }
|
||||
// if (!st) {
|
||||
// str = " End not found : end_x = {0}, end_y = {1}, start_x = {2}, start_y = {3} : bounds {4} {5} - {6} {7}"; //$NON-NLS-1$
|
||||
// System.err
|
||||
// .println(MessageFormat.format(dbId + str, dx, dy, dsx, dsy, leftX + "", topY + "", rightX + "", bottomY + "")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
||||
// }
|
||||
__android_log_print(ANDROID_LOG_INFO, "net.osmand", "Error processing multipolygon");
|
||||
} else {
|
||||
nonvisitedRings.insert(j);
|
||||
}
|
||||
}
|
||||
ir = incompletedRings.begin();
|
||||
irs = incompletedRingsNames.begin();
|
||||
for (j = 0; ir != incompletedRings.end(); ir++, irs++, j++) {
|
||||
if (nonvisitedRings.find(j) == nonvisitedRings.end()) {
|
||||
continue;
|
||||
}
|
||||
int x = ir->at(ir->size() - 1).first;
|
||||
int y = ir->at(ir->size() - 1).second;
|
||||
// 31 - (zoom + 8)
|
||||
const int EVAL_DELTA = 6 << (23 - zoom);
|
||||
const int UNDEFINED_MIN_DIFF = -1 - EVAL_DELTA;
|
||||
while (true) {
|
||||
int st = 0; // st already checked to be one of the four
|
||||
if (y == topY) {
|
||||
st = 0;
|
||||
} else if (x == rightX) {
|
||||
st = 1;
|
||||
} else if (y == bottomY) {
|
||||
st = 2;
|
||||
} else if (x == leftX) {
|
||||
st = 3;
|
||||
}
|
||||
int nextRingIndex = -1;
|
||||
// BEGIN go clockwise around rectangle
|
||||
for (int h = st; h < st + 4; h++) {
|
||||
|
||||
// BEGIN find closest nonvisited start (including current)
|
||||
int mindiff = UNDEFINED_MIN_DIFF;
|
||||
std::vector<std::vector<int_pair> >::iterator cni = incompletedRings.begin();
|
||||
int cnik = 0;
|
||||
for (;cni != incompletedRings.end(); cni++, cnik ++) {
|
||||
if (nonvisitedRings.find(cnik) == nonvisitedRings.end()) {
|
||||
continue;
|
||||
}
|
||||
int csx = cni->at(0).first;
|
||||
int csy = cni->at(0).second;
|
||||
if (h % 4 == 0) {
|
||||
// top
|
||||
if (csy == topY && csx >= safelyAddDelta(x, -EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (csx - x) <= mindiff) {
|
||||
mindiff = (csx - x);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
} else if (h % 4 == 1) {
|
||||
// right
|
||||
if (csx == rightX && csy >= safelyAddDelta(y, -EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (csy - y) <= mindiff) {
|
||||
mindiff = (csy - y);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
} else if (h % 4 == 2) {
|
||||
// bottom
|
||||
if (csy == bottomY && csx <= safelyAddDelta(x, EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (x - csx) <= mindiff) {
|
||||
mindiff = (x - csx);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
} else if (h % 4 == 3) {
|
||||
// left
|
||||
if (csx == leftX && csy <= safelyAddDelta(y, EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (y - csy) <= mindiff) {
|
||||
mindiff = (y - csy);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // END find closest start (including current)
|
||||
|
||||
// we found start point
|
||||
if (mindiff != UNDEFINED_MIN_DIFF) {
|
||||
break;
|
||||
} else {
|
||||
if (h % 4 == 0) {
|
||||
// top
|
||||
y = topY;
|
||||
x = rightX;
|
||||
} else if (h % 4 == 1) {
|
||||
// right
|
||||
y = bottomY;
|
||||
x = rightX;
|
||||
} else if (h % 4 == 2) {
|
||||
// bottom
|
||||
y = bottomY;
|
||||
x = leftX;
|
||||
} else if (h % 4 == 3) {
|
||||
y = topY;
|
||||
x = leftX;
|
||||
}
|
||||
ir->push_back(int_pair(x, y));
|
||||
}
|
||||
|
||||
} // END go clockwise around rectangle
|
||||
if (nextRingIndex == -1) {
|
||||
// it is impossible (current start should always be found)
|
||||
} else if (nextRingIndex == j) {
|
||||
ir->push_back(ir->at(0));
|
||||
nonvisitedRings.erase(j);
|
||||
break;
|
||||
} else {
|
||||
std::vector<int_pair> p = incompletedRings.at(nextRingIndex);
|
||||
ir->insert(ir->end(), p.begin(), p.end());
|
||||
nonvisitedRings.erase(nextRingIndex);
|
||||
// get last point and start again going clockwise
|
||||
x = ir->at(ir->size() - 1).first;
|
||||
y = ir->at(ir->size() - 1).second;
|
||||
}
|
||||
}
|
||||
|
||||
completedRings.push_back(*ir);
|
||||
completedRingNames.push_back(*irs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return -1 if there is no instersection or x<<32 | y
|
||||
*/
|
||||
bool calculateIntersection(int x, int y, int px, int py, int leftX, int rightX, int bottomY, int topY, int_pair& b) {
|
||||
// firstly try to search if the line goes in
|
||||
if (py < topY && y >= topY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = topY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (py > bottomY && y <= bottomY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = bottomY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (px < leftX && x >= leftX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = leftX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
if (px > rightX && x <= rightX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = rightX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// try to search if point goes out
|
||||
if (py > topY && y <= topY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = topY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (py < bottomY && y >= bottomY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = bottomY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (px > leftX && x <= leftX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = leftX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
if (px < rightX && x >= rightX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = rightX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (px == rightX || px == leftX || py == topY || py == bottomY) {
|
||||
b.first = px;
|
||||
b.second = py;
|
||||
// return true;
|
||||
// Is it right? to not return anything?
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX,
|
||||
int bottomY, int topY, std::vector<int_pair>& coordinates) {
|
||||
bool lineEnded = false;
|
||||
int_pair b(x, y);
|
||||
if (pinside) {
|
||||
if (!inside) {
|
||||
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
|
||||
if (!is) {
|
||||
b.first = px;
|
||||
b.second = py;
|
||||
}
|
||||
coordinates.push_back(b);
|
||||
lineEnded = true;
|
||||
} else {
|
||||
coordinates.push_back(b);
|
||||
}
|
||||
} else {
|
||||
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
|
||||
if (inside) {
|
||||
// assert is != -1;
|
||||
coordinates.push_back(b);
|
||||
int_pair n(x, y);
|
||||
coordinates.push_back(n);
|
||||
} else if (is) {
|
||||
coordinates.push_back(b);
|
||||
calculateIntersection(x, y, b.first, b.second, leftX, rightX, bottomY, topY, b);
|
||||
coordinates.push_back(b);
|
||||
lineEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
return lineEnded;
|
||||
}
|
|
@ -293,6 +293,14 @@ RenderingRuleSearchRequest::RenderingRuleSearchRequest(jobject rrs) :
|
|||
clearState();
|
||||
}
|
||||
|
||||
RenderingRuleSearchRequest::~RenderingRuleSearchRequest() {
|
||||
delete PROPS;
|
||||
delete[] fvalues;
|
||||
delete[] values;
|
||||
delete[] savedFvalues;
|
||||
delete[] savedValues;
|
||||
}
|
||||
|
||||
int RenderingRuleSearchRequest::getIntPropertyValue(RenderingRuleProperty* prop) {
|
||||
if (prop == NULL) {
|
||||
return 0;
|
||||
|
|
|
@ -204,6 +204,8 @@ private :
|
|||
public:
|
||||
RenderingRuleSearchRequest(jobject rrs);
|
||||
|
||||
~RenderingRuleSearchRequest();
|
||||
|
||||
int getIntPropertyValue(RenderingRuleProperty* prop);
|
||||
|
||||
int getIntPropertyValue(RenderingRuleProperty* prop, int def);
|
||||
|
|
|
@ -407,8 +407,11 @@ void drawMultiPolygon(MultiPolygonObject* mapObject,RenderingRuleSearchRequest*
|
|||
|
||||
NAT_COUNT(rc, cv->drawPath(path, *paint));
|
||||
// for test purpose
|
||||
// render.strokeWidth = 1.5f;
|
||||
// render.color = Color.BLACK;
|
||||
// paint->setStyle(SkPaint::kStroke_Style);
|
||||
// paint->setStrokeWidth(2);
|
||||
// paint->setPathEffect(NULL);
|
||||
// paint->setColor(BLACK_COLOR);
|
||||
// NAT_COUNT(rc, cv->drawPath(path, *paint));
|
||||
if (updatePaint(req, paint, 1, 0, rc)) {
|
||||
NAT_COUNT(rc, cv->drawPath(path, *paint));
|
||||
}
|
||||
|
@ -504,17 +507,6 @@ void drawPoint(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* c
|
|||
|
||||
}
|
||||
|
||||
// 0 - normal, -1 - under, 1 - bridge,over
|
||||
int getNegativeWayLayer(int type) {
|
||||
int i = (3 & (type >> 12));
|
||||
if (i == 1) {
|
||||
return -1;
|
||||
} else if (i == 2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drawObject(RenderingContext* rc, BaseMapDataObject* mapObject, SkCanvas* cv, RenderingRuleSearchRequest* req,
|
||||
SkPaint* paint, int l, int renderText, int drawOnlyShadow) {
|
||||
rc->allObjects++;
|
||||
|
@ -679,8 +671,8 @@ void doRendering(std::vector <BaseMapDataObject* > mapDataObjects, SkCanvas* can
|
|||
BaseMapDataObject* mapObject = mapDataObjects.at(ind);
|
||||
// show text only for main type
|
||||
drawObject(rc, mapObject, canvas, req, paint, l, l == 0, false);
|
||||
|
||||
}
|
||||
rc->lastRenderedKey = *ks;
|
||||
if (rc->interrupted()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -410,9 +410,7 @@ bool intersect(SkRect tRect, float tRot, TextDrawInfo* s)
|
|||
}
|
||||
|
||||
bool intersect(TextDrawInfo* t, TextDrawInfo* s) {
|
||||
// TODO
|
||||
return t->bounds.intersect(s->bounds);
|
||||
// return intersect(t->bounds, t->pathRotate, s);
|
||||
return intersect(t->bounds, t->pathRotate, s);
|
||||
}
|
||||
std::vector<TextDrawInfo*> search;
|
||||
bool findTextIntersection(SkCanvas* cv, RenderingContext* rc, quad_tree<TextDrawInfo*>& boundIntersections, TextDrawInfo* text,
|
||||
|
@ -435,7 +433,7 @@ bool findTextIntersection(SkCanvas* cv, RenderingContext* rc, quad_tree<TextDraw
|
|||
}
|
||||
|
||||
// for text purposes
|
||||
// drawTestBox(cv, &text->bounds, text->pathRotate, paintIcon, text->text, NULL/*paintText*/);
|
||||
drawTestBox(cv, &text->bounds, text->pathRotate, paintIcon, text->text, NULL/*paintText*/);
|
||||
boundIntersections.query_in_box(text->bounds, search);
|
||||
for (uint i = 0; i < search.size(); i++) {
|
||||
TextDrawInfo* t = search.at(i);
|
||||
|
|
Binary file not shown.
|
@ -83,7 +83,7 @@ public class MapRenderRepositories {
|
|||
private RotatedTileBox bmpLocation = null;
|
||||
// already rendered bitmap
|
||||
private Bitmap bmp;
|
||||
|
||||
// Field used in C++
|
||||
private boolean interrupted = false;
|
||||
private RenderingContext currentRenderingContext;
|
||||
private SearchRequest<BinaryMapDataObject> searchRequest;
|
||||
|
@ -260,7 +260,7 @@ public class MapRenderRepositories {
|
|||
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);
|
||||
PerformanceFlags.checkForDuplicateObjectIds, resultHandler, this);
|
||||
if (checkWhetherInterrupted()) {
|
||||
NativeOsmandLibrary.deleteSearchResult(resultHandler);
|
||||
return false;
|
||||
|
@ -518,8 +518,11 @@ public class MapRenderRepositories {
|
|||
currentRenderingContext.ended = true;
|
||||
if (checkWhetherInterrupted()) {
|
||||
// revert if it was interrupted
|
||||
// (be smart a bit do not revert if road already drawn)
|
||||
if(currentRenderingContext.lastRenderedKey < 35) {
|
||||
this.bmp = this.prevBmp;
|
||||
this.bmpLocation = this.prevBmpLocation;
|
||||
}
|
||||
currentRenderingContext = null;
|
||||
return;
|
||||
}
|
||||
|
@ -749,7 +752,7 @@ public class MapRenderRepositories {
|
|||
continue;
|
||||
}
|
||||
boolean directionUp = prevY >= middleY;
|
||||
if (firstX == -Integer.MIN_VALUE) {
|
||||
if (firstX == Integer.MIN_VALUE) {
|
||||
firstDirectionUp = directionUp;
|
||||
firstX = rX;
|
||||
} else {
|
||||
|
@ -765,8 +768,7 @@ public class MapRenderRepositories {
|
|||
prevY = y;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstX != -360) {
|
||||
if (firstX != Integer.MIN_VALUE) {
|
||||
boolean clockwise = (!firstDirectionUp) == (previousX < firstX);
|
||||
if (clockwise) {
|
||||
clockwiseSum += Math.abs(previousX - firstX);
|
||||
|
@ -806,38 +808,6 @@ public class MapRenderRepositories {
|
|||
}
|
||||
}
|
||||
|
||||
// NOT WORKING GOOD !
|
||||
private boolean isClockwiseWayOld(TLongList c) {
|
||||
double angle = 0;
|
||||
double prevAng = 0;
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
int mask = 0xffffffff;
|
||||
for (int i = 0; i < c.size(); i++) {
|
||||
int x = (int) (c.get(i) >> 32);
|
||||
int y = (int) (c.get(i) & mask);
|
||||
if (i >= 1) {
|
||||
double ang = Math.atan2(py - y, x - px);
|
||||
if (i > 1) {
|
||||
double delta = (ang - prevAng);
|
||||
if (delta < -Math.PI) {
|
||||
delta += 2 * Math.PI;
|
||||
} else if (delta > Math.PI) {
|
||||
delta -= 2 * Math.PI;
|
||||
}
|
||||
angle += delta;
|
||||
prevAng = ang;
|
||||
} else {
|
||||
prevAng = ang;
|
||||
}
|
||||
}
|
||||
px = x;
|
||||
py = y;
|
||||
|
||||
}
|
||||
return angle < 0;
|
||||
}
|
||||
|
||||
private void processMultipolygonLine(List<TLongList> completedRings, List<TLongList> incompletedRings,
|
||||
List<String> completedRingsNames, List<String> incompletedRingsNames, TLongList coordinates, String name) {
|
||||
if (coordinates.size() > 0) {
|
||||
|
|
|
@ -26,13 +26,16 @@ public class NativeOsmandLibrary {
|
|||
* @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) {
|
||||
public static NativeSearchResult searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom, String mapName,
|
||||
RenderingRuleSearchRequest request, boolean skipDuplicates, NativeSearchResult searchResultHandler,
|
||||
Object objectWithInterruptedField) {
|
||||
if (searchResultHandler == null) {
|
||||
return new NativeSearchResult(searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates, 0));
|
||||
return new NativeSearchResult(searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates,
|
||||
0, objectWithInterruptedField));
|
||||
} else {
|
||||
int res = searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates, searchResultHandler.nativeHandler);
|
||||
if(res == searchResultHandler.nativeHandler){
|
||||
int res = searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, mapName, request, skipDuplicates,
|
||||
searchResultHandler.nativeHandler, objectWithInterruptedField);
|
||||
if (res == searchResultHandler.nativeHandler) {
|
||||
return searchResultHandler;
|
||||
}
|
||||
return new NativeSearchResult(res);
|
||||
|
@ -70,6 +73,6 @@ public class NativeOsmandLibrary {
|
|||
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);
|
||||
private static native int searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom, String mapnaem,
|
||||
RenderingRuleSearchRequest request, boolean skipDuplicates, int searchResultHandler, Object objectWithInterruptedField);
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ public class OsmandRenderer {
|
|||
int visible = 0;
|
||||
int allObjects = 0;
|
||||
int textRenderingTime = 0;
|
||||
int lastRenderedKey = 0;
|
||||
|
||||
// use to calculate points
|
||||
PointF tempPoint = new PointF();
|
||||
|
@ -228,7 +229,10 @@ public class OsmandRenderer {
|
|||
}
|
||||
|
||||
|
||||
public Bitmap generateNewBitmapNative(RenderingContext rc, NativeSearchResult searchResultHandler, Bitmap bmp, boolean useEnglishNames,
|
||||
/**
|
||||
* @return if map could be replaced
|
||||
*/
|
||||
public void 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) {
|
||||
|
@ -253,11 +257,9 @@ public class OsmandRenderer {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
|
||||
}
|
||||
|
||||
public Bitmap generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames,
|
||||
public void generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames,
|
||||
RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList, int defaultColor) {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
|
@ -305,7 +307,7 @@ public class OsmandRenderer {
|
|||
shadowDrawn = true;
|
||||
}
|
||||
if (rc.interrupted) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
TIntArrayList list = orderMap.get(keys[k]);
|
||||
|
@ -319,6 +321,7 @@ public class OsmandRenderer {
|
|||
drawObj(obj, render, cv, rc, l, l == 0, false);
|
||||
objCount++;
|
||||
}
|
||||
rc.lastRenderedKey = keys[k];
|
||||
if (objCount > 25) {
|
||||
notifyListeners(notifyList);
|
||||
objCount = 0;
|
||||
|
@ -341,7 +344,7 @@ public class OsmandRenderer {
|
|||
|
||||
}
|
||||
|
||||
return bmp;
|
||||
return;
|
||||
}
|
||||
|
||||
private void notifyListenersWithDelay(final RenderingContext rc, final List<IMapDownloaderCallback> notifyList, final Handler h) {
|
||||
|
@ -441,7 +444,7 @@ public class OsmandRenderer {
|
|||
}
|
||||
|
||||
if (rc.interrupted) {
|
||||
return null;
|
||||
return orderMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -783,8 +786,12 @@ public class OsmandRenderer {
|
|||
}
|
||||
canvas.drawPath(path, paint);
|
||||
// for test purpose
|
||||
// render.strokeWidth = 1.5f;
|
||||
// render.color = Color.BLACK;
|
||||
// paint.setStyle(Style.STROKE);
|
||||
// paint.setStrokeWidth(1.5f);
|
||||
// paint.setColor(Color.BLACK);
|
||||
// paint.setPathEffect(null);
|
||||
// canvas.drawPath(path, paint);
|
||||
|
||||
if (updatePaint(render, paint, 1, false, rc)) {
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue