diff --git a/OsmAnd/jni/osmand/common.cpp b/OsmAnd/jni/osmand/common.cpp index c80e38112f..f3962e1f8a 100644 --- a/OsmAnd/jni/osmand/common.cpp +++ b/OsmAnd/jni/osmand/common.cpp @@ -31,14 +31,13 @@ public : TextDrawInfo(std::string itext) { text = itext; - drawOnPath = NULL; + drawOnPath = false; + path = NULL; + pathRotate = 0; } - SkPath* drawOnPath; SkRect bounds; - float vOffset ; float centerX; float centerY; - float pathRotate; float textSize ; float minDistance ; @@ -49,9 +48,15 @@ public : std::string shieldRes; int textOrder; + bool drawOnPath; + SkPath* path; + float pathRotate; + float vOffset ; + float hOffset ; + ~TextDrawInfo() { - if (drawOnPath != NULL) { - delete drawOnPath; + if (path != NULL) { + delete path; } } }; diff --git a/OsmAnd/jni/osmand/rendering.cpp b/OsmAnd/jni/osmand/rendering.cpp index 9a91fd97d2..9a67556b8e 100644 --- a/OsmAnd/jni/osmand/rendering.cpp +++ b/OsmAnd/jni/osmand/rendering.cpp @@ -187,10 +187,7 @@ int updatePaint(RenderingRuleSearchRequest* req, SkPaint* paint, int ind, int ar } void drawPointText(RenderingRuleSearchRequest* req, RenderingContext* rc, std::string tag, std::string value, - float xText, float yText, std::string name, - // line text properties - SkPath* path, float pathRotate, float roadLength, float xCenter, float yCenter, - SkPaint* paintText) + float xText, float yText, std::string name, SkPath* path) { if (name.at(0) == REF_CHAR) { std::string ref = name.substr(1); @@ -223,29 +220,16 @@ void drawPointText(RenderingRuleSearchRequest* req, RenderingContext* rc, std::s req->setBooleanFilter(req->props()->R_REF, false); if (req->searchRule(RenderingRulesStorage::TEXT_RULES) && req->getIntPropertyValue(req->props()->R_TEXT_SIZE) > 0) { - if (path == NULL || req->getIntPropertyValue(req->props()->R_TEXT_ON_PATH, 0) == 0) { - TextDrawInfo* info = new TextDrawInfo(name); - fillTextProperties(info, req, xText, yText); - rc->textToDraw.push_back(info); - } else { - paintText->setTextSize(req->getIntPropertyValue(req->props()->R_TEXT_SIZE) > 0); - if (paintText->measureText(name.c_str(), name.size()) < roadLength) { - TextDrawInfo* text = new TextDrawInfo(name); - fillTextProperties(text, req, xCenter / 2, yCenter / 2); - text->pathRotate = pathRotate; - text->drawOnPath = new SkPath(*path); - int strokeWidth = req->getIntPropertyValue(req->props()->R_TEXT_SIZE); - text->vOffset = strokeWidth / 2 - 1; - rc->textToDraw.push_back(text); - } + TextDrawInfo* info = new TextDrawInfo(name); + info->drawOnPath = (path != NULL) && (req->getIntPropertyValue(req->props()->R_TEXT_ON_PATH, 0) > 0); + if (path != NULL) { + info->path = new SkPath(*path); } - } + fillTextProperties(info, req, xText, yText); + rc->textToDraw.push_back(info); + } } -void drawPointText(RenderingRuleSearchRequest* req, RenderingContext* rc, std::string tag, std::string value, - float xText, float yText, std::string name){ - drawPointText(req, rc, tag, value, xText, yText, name, NULL, 0, 0, 0, 0, NULL); -} void drawPolylineShadow(SkCanvas* cv, SkPaint* paint, RenderingContext* rc, SkPath* path, int shadowColor, int shadowRadius) { @@ -340,42 +324,18 @@ void drawPolyline(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas rc->visible++; SkPath path; int i = 0; - float pathRotate = 0; - float roadLength = 0; - bool inverse = false; - float xPrev = 0; - float yPrev = 0; - float xMid = 0; - float yMid = 0; SkPoint middlePoint; int middle = length / 2; for (; i < length; i++) { calcPoint(mObj, i, rc); - if(i == 0 || i == length -1){ - xMid += rc->calcX; - yMid += rc->calcY; - } if (i == 0) { path.moveTo(rc->calcX, rc->calcY); } else { - roadLength += std::sqrt((rc->calcX - xPrev) * (rc->calcX - xPrev) + - (rc->calcY - yPrev) * (rc->calcY - yPrev)); if(i == middle){ middlePoint.set(rc->calcX, rc->calcY); - float rot = - std::atan2(rc->calcX - xPrev, rc->calcY - yPrev) * 180 / M_PI; - if (rot < 0) { - rot += 360; - } - if (rot < 180) { - rot += 180; - inverse = true; - } - pathRotate = (float) rot; } path.lineTo(rc->calcX, rc->calcY); } - xPrev = rc->calcX; - yPrev = rc->calcY; } if (i > 0) { if (drawOnlyShadow) { @@ -394,21 +354,8 @@ void drawPolyline(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas drawOneWayPaints(cv, &path); } if (!drawOnlyShadow && mObj->name.length() > 0) { - if (inverse) { - path.rewind(); - bool st = true; - for (i = length - 1; i >= 0; i--) { - calcPoint(mObj, i, rc); - if (st) { - st = false; - path.moveTo(rc->calcX, rc->calcY); - } else { - path.lineTo(rc->calcX, rc->calcY); - } - } - } drawPointText(req, rc,pair.first, pair.second, middlePoint.fX, middlePoint.fY, mObj->name, - &path, pathRotate, roadLength, xMid, yMid, paint); + &path); } } } @@ -448,7 +395,7 @@ void drawMultiPolygon(MultiPolygonObject* mapObject,RenderingRuleSearchRequest* if (cnt > 0) { std::string name = mapObject->names.at(i); if (name.length() > 0) { - drawPointText(req, rc, mapObject->tag, mapObject->value, xText / cnt, yText / cnt, name); + drawPointText(req, rc, mapObject->tag, mapObject->value, xText / cnt, yText / cnt, name, NULL); } } } @@ -501,7 +448,7 @@ void drawPolygon(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* } std::string name = mObj->name; if (name.length() > 0) { - drawPointText(req, rc, tag, value, xText / length, yText / length, name); + drawPointText(req, rc, tag, value, xText / length, yText / length, name, NULL); } } @@ -547,7 +494,7 @@ void drawPoint(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* c rc->iconsToDraw.push_back(ico); } if (name.length() > 0) { - drawPointText(req, rc, tag, value, px, py, name); + drawPointText(req, rc, tag, value, px, py, name, NULL); } } diff --git a/OsmAnd/jni/osmand/textdraw.cpp b/OsmAnd/jni/osmand/textdraw.cpp index 12509d154f..14a610e490 100644 --- a/OsmAnd/jni/osmand/textdraw.cpp +++ b/OsmAnd/jni/osmand/textdraw.cpp @@ -208,26 +208,128 @@ void drawWrappedText(SkCanvas* cv, TextDrawInfo* text, float textSize, SkPaint& } } +bool calculatePathToRotate(TextDrawInfo* p) { + // TODO rotate bounds for shields? + if (!p->drawOnPath || p->path == NULL) { + return true; + } + uint len = p->path->countPoints(); + bool inverse = false; + float roadLength = 0; + SkPoint points[len]; + p->path->getPoints(points, len); + // calculate vector of the road (px, py) + float px = 0; + float py = 0; + // TODO path outside (big zoom) + for (uint i = 0; i < len; i++) { + if (i > 0) { + roadLength += 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)); + px += points[i].fX - points[i - 1].fX; + py += points[i].fY - points[i - 1].fY; + } + + } + if (p->bounds.width() >= roadLength) { + return false; + } + float scale = 0.5f; + float plen = std::sqrt(px * px + py * py); + // vector ox,oy orthogonal to px,py to measure height + float ox = -py; + float oy = px; + if(plen > 0) { + float rot = std::atan2(py, px) * 180 / M_PI; + if (rot < 0) rot += 360; + if (rot > 90 && rot < 270) { + rot += 180; + inverse = true; + } + p->pathRotate = rot; + scale = (1 - p->bounds.width() / plen) / 2; + ox *= (p->bounds.height() / plen) / 2; + oy *= (p->bounds.height() / plen) / 2; + } + + + p->centerX = points[0].fX + scale * px + ox; + p->centerY = points[0].fY + scale * py + oy; + p->vOffset = p->textSize / 2 - 1; + // TODO ? + p->hOffset = 0; + + + if (inverse) { + SkPath* path = new SkPath; + for (int i = len - 1; i >= 0; i--) { + if (i == (int)(len - 1)) { + path->moveTo(points[i].fX, points[i].fY); + } else { + path->lineTo(points[i].fX, points[i].fY); + } + } + if (p->path != NULL) { + delete p->path; + } + p->path = path; + } + return true; +} + +void drawTestBox(SkCanvas* cv, TextDrawInfo* text, SkPaint* paintIcon, SkPaint* paintText) +{ + cv->save(); + cv->translate(text->bounds.centerX(),text->bounds.centerY()); + cv->rotate(text->pathRotate); + SkRect r = SkRect::MakeLTRB(-text->bounds.width()/2, -text->bounds.height()/2, + text->bounds.width()/2, text->bounds.height()/2); + cv->drawRect(r, *paintIcon); + if (paintText != NULL) { + cv->drawText(text->text.data(), text->text.length(), r.centerX(), r.centerY(), + *paintText); + } + cv->restore(); +} + +bool intersect(TextDrawInfo* t, TextDrawInfo* s) +{ + // TODO rotation + return t->bounds.intersect(s->bounds); +} + std::vector search; bool findTextIntersection(SkCanvas* cv, RenderingContext* rc, quad_tree& boundIntersections, TextDrawInfo* text, SkPaint* paintText, SkPaint* paintIcon) { - // TODO direction of path - //bool horizontalWayDisplay = (text->pathRotate > 45 && text->pathRotate < 135) - // || (text->pathRotate > 225 && text->pathRotate < 315); paintText->measureText(text->text.c_str(), text->text.length(), &text->bounds); + // make wider text->bounds.inset(-getDensityValue(rc, 3), -getDensityValue(rc, 10)); - text->bounds.offset(text->centerX, text->centerY); - text->bounds.offset(-text->bounds.width()/2, 0); + + bool display = calculatePathToRotate(text); + if (!display) { + return true; + } + + if(!text->drawOnPath) { + text->bounds.offset(text->centerX, text->centerY); + // shift to match alignment + text->bounds.offset(-text->bounds.width()/2, 0); + } else { + text->bounds.offset(text->centerX - text->bounds.width()/2, text->centerY - text->bounds.height()/2); + } + SkRect boundsSearch = text->bounds; float v = -getDensityValue(rc, std::max(5.0f, text->minDistance)); boundsSearch.inset(v, v); + //TODO remove - // cv->drawRect(text->bounds, *paintIcon); + drawTestBox(cv, text, paintIcon, paintText); boundIntersections.query_in_box(boundsSearch, search); for (uint i = 0; i < search.size(); i++) { TextDrawInfo* t = search.at(i); - if (text->bounds.intersect(t->bounds)) { + if (intersect(text, t)) { return true; } else if (boundsSearch.intersect(t->bounds) && t->text == text->text) { return true; @@ -247,7 +349,7 @@ SkTypeface* serif = SkTypeface::CreateFromName("Droid Serif", SkTypeface::kNorma void drawTextOverCanvas(RenderingContext* rc, SkCanvas* cv) { SkRect r = SkRect::MakeLTRB(0, 0, rc->width, rc->height); r.inset(-100, -100); - quad_tree boundsIntersect(r, 5, 0.7); + quad_tree boundsIntersect(r, 4, 0.6); SkPaint paintIcon; paintIcon.setStyle(SkPaint::kStroke_Style); @@ -287,20 +389,20 @@ void drawTextOverCanvas(RenderingContext* rc, SkCanvas* cv) { // calculate if there is intersection bool intersects = findTextIntersection(cv, rc, boundsIntersect, text, &paintText, &paintIcon); if (!intersects) { - if (text->drawOnPath != NULL) { + if (text->drawOnPath && text->path != NULL) { if (text->textShadow > 0) { paintText.setColor(WHITE_COLOR); paintText.setStyle(SkPaint::kStroke_Style); paintText.setStrokeWidth(2 + text->textShadow); - cv->drawTextOnPathHV(text->text.c_str(), text->text.length(), *text->drawOnPath, 0, + cv->drawTextOnPathHV(text->text.c_str(), text->text.length(), *text->path, text->hOffset, text->vOffset, paintText); // reset paintText.setStyle(SkPaint::kFill_Style); paintText.setStrokeWidth(2); paintText.setColor(text->textColor); } - cv->drawTextOnPathHV(text->text.c_str(), text->text.length(), *text->drawOnPath, 0, text->vOffset, - paintText); + cv->drawTextOnPathHV(text->text.c_str(), text->text.length(), *text->path, text->hOffset, + text->vOffset, paintText); } else { if (text->shieldRes.length() > 0) { SkBitmap* ico = getCachedBitmap(rc, text->shieldRes); diff --git a/OsmAnd/libs/armeabi/libosmand.so b/OsmAnd/libs/armeabi/libosmand.so index 48b48a2d13..3dc1a47135 100755 Binary files a/OsmAnd/libs/armeabi/libosmand.so and b/OsmAnd/libs/armeabi/libosmand.so differ diff --git a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java index c20f73dc37..244d16e434 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java +++ b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java @@ -448,6 +448,9 @@ 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; + } if (checkWhetherInterrupted()) { currentRenderingContext = null; return; @@ -488,7 +491,10 @@ public class MapRenderRepositories { Toast.makeText(context, R.string.rendering_out_of_memory, Toast.LENGTH_SHORT).show(); } }); - + } finally { + if(currentRenderingContext != null) { + currentRenderingContext.ended = true; + } } } diff --git a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java index a213a9b355..c144e3d24d 100644 --- a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java +++ b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java @@ -42,6 +42,9 @@ import android.graphics.Paint.Align; import android.graphics.Paint.Cap; 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; @@ -162,6 +165,8 @@ public class OsmandRenderer { int shadowLevelMax = 0; String renderingDebugInfo; + + boolean ended = false; } public OsmandRenderer(Context context) { @@ -224,7 +229,7 @@ public class OsmandRenderer { public Bitmap generateNewBitmap(RenderingContext rc, List objects, Bitmap bmp, boolean useEnglishNames, - RenderingRuleSearchRequest render, List notifyList, int defaultColor, boolean nativeRendering) { + RenderingRuleSearchRequest render, final List notifyList, int defaultColor, boolean nativeRendering) { long now = System.currentTimeMillis(); if (objects != null && !objects.isEmpty() && rc.width > 0 && rc.height > 0) { @@ -309,7 +314,12 @@ public class OsmandRenderer { } else { BinaryMapDataObject[] array = objects.toArray(new BinaryMapDataObject[objects.size()]); try { + if(Looper.getMainLooper() != null){ + final Handler h = new Handler(Looper.getMainLooper()); + notifyListenersWithDelay(rc, notifyList, h); + } String res = NativeOsmandLibrary.generateRendering(rc, array, bmp, useEnglishNames, render, defaultColor); + rc.ended = true; 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$ @@ -323,6 +333,18 @@ public class OsmandRenderer { return bmp; } + private void notifyListenersWithDelay(final RenderingContext rc, final List notifyList, final Handler h) { + h.postDelayed(new Runnable() { + @Override + public void run() { + if(!rc.ended) { + notifyListeners(notifyList); + notifyListenersWithDelay(rc, notifyList, h); + } + } + }, 700); + } + private void drawIconsOverCanvas(RenderingContext rc, Canvas cv) { int skewConstant = (int) getDensityValue(rc, 16); int iconsW = rc.width / skewConstant;