Calculate text collisions properly
This commit is contained in:
parent
6f9fdb2b18
commit
4fd9f75b69
6 changed files with 107 additions and 53 deletions
|
@ -8,6 +8,14 @@
|
|||
#include <SkPath.h>
|
||||
#include <SkBitmap.h>
|
||||
|
||||
//#define DEBUG_NAT_OPERATIONS
|
||||
|
||||
#ifdef DEBUG_NAT_OPERATIONS
|
||||
#define NAT_COUNT(rc, op) rc->nativeOperations.pause(); op; rc->nativeOperations.start()
|
||||
#else
|
||||
#define NAT_COUNT(rc, op) op;
|
||||
#endif
|
||||
|
||||
|
||||
JNIEnv* env;
|
||||
const std::string EMPTY_STRING;
|
||||
|
@ -72,32 +80,56 @@ jfieldID getFid(jclass cls,const char* fieldName, const char* sig )
|
|||
return env->GetFieldID( cls, fieldName, sig);
|
||||
}
|
||||
|
||||
class timer {
|
||||
class watcher {
|
||||
int elapsedTime;
|
||||
timeval startInit;
|
||||
timeval endInit;
|
||||
bool enableFlag;
|
||||
// timeval startInit;
|
||||
// timeval endInit;
|
||||
timespec startInit;
|
||||
timespec endInit;
|
||||
bool run;
|
||||
|
||||
|
||||
public:
|
||||
timer() {
|
||||
watcher() {
|
||||
elapsedTime = 0;
|
||||
enableFlag = true;
|
||||
}
|
||||
void enable(){
|
||||
enableFlag = true;
|
||||
}
|
||||
void disable(){
|
||||
pause();
|
||||
enableFlag = false;
|
||||
}
|
||||
void start() {
|
||||
if(!enableFlag){
|
||||
return;
|
||||
}
|
||||
if (!run) {
|
||||
gettimeofday(&startInit, NULL);
|
||||
clock_gettime(CLOCK_MONOTONIC, &startInit);
|
||||
// gettimeofday(&startInit, NULL);
|
||||
}
|
||||
run = true;
|
||||
}
|
||||
void pause() {
|
||||
if (run) {
|
||||
gettimeofday(&endInit, NULL);
|
||||
elapsedTime += (endInit.tv_sec * 1000 + endInit.tv_usec / 1000)
|
||||
- (startInit.tv_sec * 1000 + startInit.tv_usec / 1000);
|
||||
if (!run) {
|
||||
return;
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &endInit );
|
||||
// gettimeofday(&endInit, NULL);
|
||||
int sec = endInit.tv_sec - startInit.tv_sec;
|
||||
if(sec > 0){
|
||||
elapsedTime += 1e9 * sec;
|
||||
}
|
||||
elapsedTime += endInit.tv_nsec - startInit.tv_nsec ;
|
||||
// elapsedTime += (endInit.tv_sec * 1000 + endInit.tv_usec / 1000)
|
||||
// - (startInit.tv_sec * 1000 + startInit.tv_usec / 1000);
|
||||
run = false;
|
||||
}
|
||||
int getElapsedTime() {
|
||||
pause();
|
||||
return elapsedTime;
|
||||
return elapsedTime / 1e6;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -126,8 +158,8 @@ struct RenderingContext {
|
|||
int pointInsideCount;
|
||||
int visible;
|
||||
int allObjects;
|
||||
timer textRendering;
|
||||
timer nativeOperations;
|
||||
watcher textRendering;
|
||||
watcher nativeOperations;
|
||||
|
||||
// use to calculate points
|
||||
float calcX;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "textdraw.cpp"
|
||||
#include "mapObjects.cpp"
|
||||
|
||||
#define NAT_COUNT(rc, op) rc->nativeOperations.pause(); op; rc->nativeOperations.start()
|
||||
|
||||
char debugMessage[1024];
|
||||
|
||||
|
@ -210,6 +209,9 @@ void drawPointText(RenderingRuleSearchRequest* req, RenderingContext* rc, std::s
|
|||
if (req->getIntPropertyValue(req->props()->R_TEXT_SIZE) > 0) {
|
||||
TextDrawInfo* text = new TextDrawInfo(ref);
|
||||
fillTextProperties(text, req, xText, yText);
|
||||
if (path != NULL) {
|
||||
text->path = new SkPath(*path);
|
||||
}
|
||||
rc->textToDraw.push_back(text);
|
||||
}
|
||||
}
|
||||
|
@ -692,16 +694,6 @@ std::hash_map<int, std::vector<int> > sortObjectsByProperOrder(std::vector <Base
|
|||
return orderMap;
|
||||
}
|
||||
|
||||
int objCount = 0;
|
||||
void objectDrawn(bool notify = false)
|
||||
{
|
||||
if (objCount++ > 25) {
|
||||
// TODO notification
|
||||
//notifyListeners(notifyList);
|
||||
objCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void doRendering(std::vector <BaseMapDataObject* > mapDataObjects, SkCanvas* canvas, SkPaint* paint,
|
||||
RenderingRuleSearchRequest* req, RenderingContext* rc) {
|
||||
// put in order map
|
||||
|
@ -731,7 +723,6 @@ void doRendering(std::vector <BaseMapDataObject* > mapDataObjects, SkCanvas* can
|
|||
|
||||
// show text only for main type
|
||||
drawObject(rc, mapObject, canvas, req, paint, l, l == 0, true);
|
||||
objectDrawn();
|
||||
}
|
||||
}
|
||||
shadowDrawn = true;
|
||||
|
@ -746,8 +737,6 @@ 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);
|
||||
objCount++;
|
||||
objectDrawn();
|
||||
|
||||
}
|
||||
if (rc->interrupted()) {
|
||||
|
@ -756,11 +745,9 @@ void doRendering(std::vector <BaseMapDataObject* > mapDataObjects, SkCanvas* can
|
|||
|
||||
}
|
||||
|
||||
objectDrawn(true);
|
||||
drawIconsOverCanvas(rc, canvas);
|
||||
|
||||
rc->textRendering.start();
|
||||
objectDrawn(true);
|
||||
drawTextOverCanvas(rc, canvas);
|
||||
rc->textRendering.pause();
|
||||
}
|
||||
|
@ -786,7 +773,7 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
|
|||
paint->setAntiAlias(true);
|
||||
|
||||
__android_log_print(ANDROID_LOG_WARN, "net.osmand", "Initializing rendering");
|
||||
timer initObjects;
|
||||
watcher initObjects;
|
||||
initObjects.start();
|
||||
|
||||
|
||||
|
@ -815,8 +802,11 @@ JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera
|
|||
delete req;
|
||||
deleteObjects(mapDataObjects);
|
||||
|
||||
sprintf(debugMessage, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(),
|
||||
rc.nativeOperations.getElapsedTime());
|
||||
#ifdef DEBUG_NAT_OPERATIONS
|
||||
sprintf(debugMessage, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
|
||||
#else
|
||||
sprintf(debugMessage, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
|
||||
#endif
|
||||
jstring result = env->NewStringUTF( debugMessage);
|
||||
|
||||
// unloadLibrary();
|
||||
|
|
|
@ -191,16 +191,10 @@ void drawWrappedText(RenderingContext* rc, SkCanvas* cv, TextDrawInfo* text, flo
|
|||
pos++;
|
||||
}
|
||||
if(lastSpace == -1) {
|
||||
rc->nativeOperations.pause();
|
||||
drawTextOnCanvas(cv, text->text.substr(start, pos),
|
||||
text->centerX, text->centerY + line * (textSize + 2), paintText, text->textShadow);
|
||||
rc->nativeOperations.start();
|
||||
NAT_COUNT(rc, drawTextOnCanvas(cv, text->text.substr(start, pos), text->centerX, text->centerY + line * (textSize + 2), paintText, text->textShadow));
|
||||
start = pos;
|
||||
} else {
|
||||
rc->nativeOperations.pause();
|
||||
drawTextOnCanvas(cv, text->text.substr(start, lastSpace),
|
||||
text->centerX, text->centerY + line * (textSize + 2), paintText, text->textShadow);
|
||||
rc->nativeOperations.start();
|
||||
NAT_COUNT(rc, drawTextOnCanvas(cv, text->text.substr(start, lastSpace), text->centerX, text->centerY + line * (textSize + 2), paintText, text->textShadow));
|
||||
start = lastSpace + 1;
|
||||
limit += (start - pos) - 1;
|
||||
}
|
||||
|
@ -208,20 +202,31 @@ void drawWrappedText(RenderingContext* rc, SkCanvas* cv, TextDrawInfo* text, flo
|
|||
|
||||
}
|
||||
} else {
|
||||
rc->nativeOperations.pause();
|
||||
drawTextOnCanvas(cv, text->text, text->centerX, text->centerY, paintText, text->textShadow);
|
||||
rc->nativeOperations.start();
|
||||
NAT_COUNT(rc, drawTextOnCanvas(cv, text->text, text->centerX, text->centerY, paintText, text->textShadow));
|
||||
}
|
||||
}
|
||||
|
||||
bool calculatePathToRotate(RenderingContext* rc, TextDrawInfo* p) {
|
||||
// TODO rotate bounds for shields?
|
||||
if (!p->drawOnPath || p->path == NULL) {
|
||||
if(p->path == NULL) {
|
||||
return true;
|
||||
}
|
||||
int len = p->path->countPoints();
|
||||
SkPoint points[len];
|
||||
p->path->getPoints(points, len);
|
||||
if (!p->drawOnPath) {
|
||||
// simply calculate rotation of path used for shields
|
||||
p->vOffset -= p->textSize / 2 - 1;
|
||||
float px = 0;
|
||||
float py = 0;
|
||||
for (int i = 1; i < len; i++) {
|
||||
px += points[i].fX - points[i - 1].fX;
|
||||
py += points[i].fY - points[i - 1].fY;
|
||||
}
|
||||
if (px != 0 || py != 0) {
|
||||
p->pathRotate = std::atan2(py, px) * 180 / M_PI;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool inverse = false;
|
||||
float roadLength = 0;
|
||||
|
@ -229,7 +234,11 @@ bool calculatePathToRotate(RenderingContext* rc, TextDrawInfo* p) {
|
|||
float visibleRoadLength = 0;
|
||||
float textw = p->bounds.width();
|
||||
int i;
|
||||
int startVisible = 1;
|
||||
int startVisible = 0;
|
||||
std::vector<float> distances;
|
||||
distances.resize(roadLength, 0);
|
||||
|
||||
float normalTextLen = 1.5 * textw;
|
||||
for (i = 0; i < len; i++) {
|
||||
bool inside = points[i].fX >= 0 && points[i].fX <= rc->width &&
|
||||
points[i].fY >= 0 && points[i].fY <= rc->height;
|
||||
|
@ -237,18 +246,20 @@ bool calculatePathToRotate(RenderingContext* rc, TextDrawInfo* p) {
|
|||
float d = std::sqrt(
|
||||
(points[i].fX - points[i - 1].fX) * (points[i].fX - points[i - 1].fX)
|
||||
+ (points[i].fY - points[i - 1].fY) * (points[i].fY - points[i - 1].fY));
|
||||
distances.push_back(d);
|
||||
roadLength += d;
|
||||
if(inside) {
|
||||
visibleRoadLength += d;
|
||||
if(!prevInside) {
|
||||
startVisible = i - 1;
|
||||
}
|
||||
} else if(!prevInside) {
|
||||
if(visibleRoadLength >= 1.5 * textw) {
|
||||
} else if(prevInside) {
|
||||
if(visibleRoadLength >= normalTextLen) {
|
||||
break;
|
||||
}
|
||||
visibleRoadLength = 0;
|
||||
}
|
||||
|
||||
}
|
||||
prevInside = inside;
|
||||
}
|
||||
|
@ -257,9 +268,27 @@ bool calculatePathToRotate(RenderingContext* rc, TextDrawInfo* p) {
|
|||
}
|
||||
int startInd = 0;
|
||||
int endInd = len;
|
||||
if(textw < visibleRoadLength) {
|
||||
startInd = startVisible - 1;
|
||||
|
||||
if(textw < visibleRoadLength && i - startVisible > 1) {
|
||||
startInd = startVisible;
|
||||
endInd = i;
|
||||
// display long road name in center
|
||||
if (visibleRoadLength > 3 * textw) {
|
||||
bool ch ;
|
||||
do {
|
||||
ch = false;
|
||||
if(endInd - startInd > 2 && visibleRoadLength - distances[startInd] > normalTextLen){
|
||||
visibleRoadLength -= distances.at(startInd);
|
||||
startInd++;
|
||||
ch = true;
|
||||
}
|
||||
if(endInd - startInd > 2 && visibleRoadLength - distances[endInd - 2] > normalTextLen){
|
||||
visibleRoadLength -= distances.at(endInd - 2);
|
||||
endInd--;
|
||||
ch = true;
|
||||
}
|
||||
} while(ch);
|
||||
}
|
||||
}
|
||||
// shrink path to display more text
|
||||
if (startInd > 0 || endInd < len) {
|
||||
|
@ -369,10 +398,12 @@ bool findTextIntersection(SkCanvas* cv, RenderingContext* rc, quad_tree<TextDraw
|
|||
|
||||
SkRect boundsSearch = text->bounds;
|
||||
float v = -getDensityValue(rc, std::max(5.0f, text->minDistance));
|
||||
// TODO min distance different !
|
||||
boundsSearch.inset(v, v);
|
||||
|
||||
// for text purposes
|
||||
// drawTestBox(cv, text, paintIcon, paintText);
|
||||
|
||||
boundIntersections.query_in_box(boundsSearch, search);
|
||||
for (uint i = 0; i < search.size(); i++) {
|
||||
TextDrawInfo* t = search.at(i);
|
||||
|
@ -436,6 +467,9 @@ void drawTextOverCanvas(RenderingContext* rc, SkCanvas* cv) {
|
|||
// calculate if there is intersection
|
||||
bool intersects = findTextIntersection(cv, rc, boundsIntersect, text, &paintText, &paintIcon);
|
||||
if (!intersects) {
|
||||
if(rc->interrupted()){
|
||||
return;
|
||||
}
|
||||
if (text->drawOnPath && text->path != NULL) {
|
||||
if (text->textShadow > 0) {
|
||||
paintText.setColor(WHITE_COLOR);
|
||||
|
|
Binary file not shown.
|
@ -448,9 +448,7 @@ public class MapRenderRepositories {
|
|||
renderer.generateNewBitmap(currentRenderingContext, cObjects, bmp, prefs.USE_ENGLISH_NAMES.get(), renderingReq,
|
||||
notifyList, storage.getBgColor(nightMode), app.getSettings().NATIVE_RENDERING.get());
|
||||
String renderingDebugInfo = currentRenderingContext.renderingDebugInfo;
|
||||
if(currentRenderingContext != null) {
|
||||
currentRenderingContext.ended = true;
|
||||
}
|
||||
currentRenderingContext.ended = true;
|
||||
if (checkWhetherInterrupted()) {
|
||||
currentRenderingContext = null;
|
||||
return;
|
||||
|
|
|
@ -44,7 +44,6 @@ import android.graphics.Paint.Style;
|
|||
import android.graphics.Shader.TileMode;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.text.TextPaint;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.FloatMath;
|
||||
|
@ -320,6 +319,7 @@ public class OsmandRenderer {
|
|||
}
|
||||
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$
|
||||
|
|
Loading…
Reference in a new issue