Calculate box correctly

This commit is contained in:
Victor Shcherb 2011-10-26 00:23:35 +02:00
parent 91810f52d5
commit 00280553a6
6 changed files with 167 additions and 85 deletions

View file

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

View file

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

View file

@ -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<TextDrawInfo*> search;
bool findTextIntersection(SkCanvas* cv, RenderingContext* rc, quad_tree<TextDrawInfo*>& 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<TextDrawInfo*> boundsIntersect(r, 5, 0.7);
quad_tree<TextDrawInfo*> 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);

Binary file not shown.

View file

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

View file

@ -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<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames,
RenderingRuleSearchRequest render, List<IMapDownloaderCallback> notifyList, int defaultColor, boolean nativeRendering) {
RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> 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<IMapDownloaderCallback> 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;