Small improvements

This commit is contained in:
Victor Shcherb 2011-10-30 00:57:40 +02:00
parent d8bf714a03
commit 1a2f38a916
14 changed files with 726 additions and 99 deletions

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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*/

View file

@ -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*/

View 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;
}

View file

@ -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;

View file

@ -204,6 +204,8 @@ private :
public:
RenderingRuleSearchRequest(jobject rrs);
~RenderingRuleSearchRequest();
int getIntPropertyValue(RenderingRuleProperty* prop);
int getIntPropertyValue(RenderingRuleProperty* prop, int def);

View file

@ -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;
}

View file

@ -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.

View file

@ -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;
@ -517,9 +517,12 @@ public class MapRenderRepositories {
String renderingDebugInfo = currentRenderingContext.renderingDebugInfo;
currentRenderingContext.ended = true;
if (checkWhetherInterrupted()) {
// revert if it was interrupted
this.bmp = this.prevBmp;
this.bmpLocation = this.prevBmpLocation;
// 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) {

View file

@ -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);
}

View file

@ -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;
}
}
}
@ -782,9 +785,13 @@ public class OsmandRenderer {
}
}
canvas.drawPath(path, paint);
// for test purpose
// render.strokeWidth = 1.5f;
// render.color = Color.BLACK;
// for test purpose
// 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);
}