Resolved the problem with Layer="-1" caused by PathEffect

This commit is contained in:
seeebek 2011-10-09 22:01:31 +03:00 committed by Victor Shcherb
parent 8a32b94f21
commit df0cfd3cb9

View file

@ -47,17 +47,17 @@ import android.view.WindowManager;
public class OsmandRenderer {
private static final Log log = LogUtil.getLog(OsmandRenderer.class);
private final int clFillScreen = Color.rgb(241, 238, 232);
private TextPaint paintText;
private Paint paint;
private Paint paintFillEmpty;
private Paint paintIcon;
public static final int TILE_SIZE = 256;
private Map<String, PathEffect> dashEffect = new LinkedHashMap<String, PathEffect>();
private Map<Integer, Shader> shaders = new LinkedHashMap<Integer, Shader>();
private Map<Integer, Bitmap> cachedIcons = new LinkedHashMap<Integer, Bitmap>();
@ -65,17 +65,16 @@ public class OsmandRenderer {
private final Context context;
private DisplayMetrics dm;
private int[] shadowarray;
private int shadownum;
private static class TextDrawInfo {
public TextDrawInfo(String text){
this.text = text;
}
public void fillProperties(RenderingContext rc, float centerX, float centerY){
this.centerX = centerX + rc.textDx;
this.centerY = centerY + rc.textDy;
@ -106,37 +105,37 @@ public class OsmandRenderer {
int textOrder = 20;
}
private static class IconDrawInfo {
float x = 0;
float y = 0;
int resId;
}
/*package*/ static class RenderingContext {
public boolean interrupted = false;
public boolean nightMode = false;
public boolean highResMode = false;
public float mapTextSize = 1;
List<TextDrawInfo> textToDraw = new ArrayList<TextDrawInfo>();
List<IconDrawInfo> iconsToDraw = new ArrayList<IconDrawInfo>();
float leftX;
float topY;
int width;
int height;
int zoom;
float rotate;
float tileDivisor;
// debug purpose
int pointCount = 0;
int pointInsideCount = 0;
int visible = 0;
int allObjects = 0;
// use to calculate points
PointF tempPoint = new PointF();
float cosRotateTileSize;
@ -156,15 +155,16 @@ public class OsmandRenderer {
boolean textBold;
int textShield = 0;
int textOrder = -1;
String renderingDebugInfo;
String renderingDebugInfo;
RenderingPaintProperties main = new RenderingPaintProperties();
RenderingPaintProperties second = new RenderingPaintProperties();
RenderingPaintProperties third = new RenderingPaintProperties();
RenderingPaintProperties[] adds = null;
public void clearText() {
showAnotherText = null;
showTextOnPath = false;
@ -179,10 +179,10 @@ public class OsmandRenderer {
textBold = false;
textShield = 0;
}
}
/* package*/ static class RenderingPaintProperties {
int color;
float strokeWidth;
@ -192,7 +192,7 @@ public class OsmandRenderer {
PathEffect pathEffect;
Shader shader;
Cap cap;
public void emptyLine(){
color = 0;
strokeWidth = 0;
@ -203,7 +203,7 @@ public class OsmandRenderer {
shadowColor = 0;
shadowRadius = 0;
}
public void updatePaint(Paint p){
p.setStyle(fillArea ? Style.FILL_AND_STROKE : Style.STROKE);
p.setColor(color);
@ -218,7 +218,7 @@ public class OsmandRenderer {
p.setPathEffect(pathEffect);
}
}
public void emptyArea(){
color = 0;
strokeWidth = 0;
@ -230,7 +230,7 @@ public class OsmandRenderer {
shadowRadius = 0;
}
}
public OsmandRenderer(Context context) {
this.context = context;
@ -255,7 +255,7 @@ public class OsmandRenderer {
WindowManager wmgr = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wmgr.getDefaultDisplay().getMetrics(dm);
}
public PathEffect getDashEffect(String dashes){
if(!dashEffect.containsKey(dashes)){
String[] ds = dashes.split("_"); //$NON-NLS-1$
@ -267,7 +267,7 @@ public class OsmandRenderer {
}
return dashEffect.get(dashes);
}
public Shader getShader(int resId){
if(shaders.get(resId) == null){
Shader sh = new BitmapShader(
@ -276,19 +276,19 @@ public class OsmandRenderer {
}
return shaders.get(resId);
}
private void put(TFloatObjectHashMap<TIntArrayList> map, Float k, int v, int init){
if(!map.containsKey(k)){
map.put(k, new TIntArrayList());
}
map.get(k).add(v);
}
public Bitmap generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames,
BaseOsmandRender renderer, List<IMapDownloaderCallback> notifyList) {
long now = System.currentTimeMillis();
// fill area
Canvas cv = new Canvas(bmp);
if(renderer != null){
@ -298,7 +298,7 @@ public class OsmandRenderer {
}
}
cv.drawRect(0, 0, bmp.getWidth(), bmp.getHeight(), paintFillEmpty);
// put in order map
int sz = objects.size();
int init = sz / 4;
@ -337,45 +337,45 @@ public class OsmandRenderer {
}
}
}
if (objects != null && !objects.isEmpty() && rc.width > 0 && rc.height > 0) {
// init rendering context
rc.tileDivisor = (int) (1 << (31 - rc.zoom));
rc.cosRotateTileSize = FloatMath.cos((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
//int shadow = 0; // no shadow (minumum CPU)
//int shadow = 1; // classic shadow (the implementaton in master)
//int shadow = 2; // blur shadow (most CPU, but still reasonable)
int shadow = 3; // solid border (CPU use like classic version or even smaller)
boolean repeat = false;
float[] keys = orderMap.keys();
Arrays.sort(keys);
int objCount = 0;
shadowarray = new int[keys.length];
shadownum = 0;
for (int k = 0; k < keys.length; k++) {
if(repeat == true && shadowarray[shadownum] == k){
shadownum++;
continue;
}
TIntArrayList list = orderMap.get(keys[k]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
// show text only for main type
drawObj(obj, renderer, cv, rc, l, l == 0, shadow, k);
objCount++;
// show text only for main type
drawObj(obj, renderer, cv, rc, l, l == 0, shadow, k);
objCount++;
}
if(objCount > 25){
notifyListeners(notifyList);
@ -384,7 +384,7 @@ public class OsmandRenderer {
if(rc.interrupted){
return null;
}
// order = 57 should be set as limit for shadows
if(keys[k] > 57 && repeat == false && shadow > 1){
shadow = 0;
@ -395,9 +395,9 @@ public class OsmandRenderer {
}
notifyListeners(notifyList);
long beforeIconTextTime = System.currentTimeMillis() - now;
int skewConstant = (int) getDensityValue(rc, 16);
int iconsW = rc.width / skewConstant ;
int iconsH = rc.height / skewConstant;
int[] alreadyDrawnIcons = new int[iconsW * iconsH / 32];
@ -436,9 +436,9 @@ public class OsmandRenderer {
"(%s points, %s points inside, %s objects visile from %s)",//$NON-NLS-1$
time, time - beforeIconTextTime,rc.pointCount, rc.pointInsideCount, rc.visible, rc.allObjects);
log.info(rc.renderingDebugInfo);
}
return bmp;
}
@ -462,7 +462,7 @@ public class OsmandRenderer {
}
}
private final static boolean findAllTextIntersections = true;
private float getDensityValue(RenderingContext rc, float val) {
if (rc.highResMode && dm.density > 1) {
return val * dm.density * rc.mapTextSize;
@ -480,7 +480,7 @@ public class OsmandRenderer {
public int compare(RectF object1, RectF object2) {
return Float.compare(object1.left, object2.left);
}
};
// 1. Sort text using text order
@ -503,8 +503,8 @@ public class OsmandRenderer {
if(useEnglishNames){
text.text = Junidecode.unidecode(text.text);
}
// sest text size before finding intersection (it is used there)
float textSize = getDensityValue(rc, text.textSize);
paintText.setTextSize(textSize);
@ -512,14 +512,14 @@ public class OsmandRenderer {
paintText.setColor(text.textColor);
// align center y
text.centerY += (-paintText.ascent());
// calculate if there is intersection
boolean intersects = findTextIntersection(rc, boundsNotPathIntersect, boundsPathIntersect, c, text);
if(intersects){
continue nextText;
}
if(text.drawOnPath != null){
if(text.textShadow > 0){
paintText.setColor(Color.WHITE);
@ -544,7 +544,7 @@ public class OsmandRenderer {
, paintIcon);
}
}
drawWrappedText(cv, text, textSize);
}
}
@ -556,7 +556,7 @@ public class OsmandRenderer {
// set maximum for all text
text.textWrap = 40;
}
if(text.text.length() > text.textWrap){
int start = 0;
int end = text.text.length();
@ -584,13 +584,13 @@ public class OsmandRenderer {
limit += (start - pos) - 1;
}
line++;
}
} else {
drawTextOnCanvas(cv, text.text, text.centerX, text.centerY, paintText, text.textShadow);
}
}
private void drawTextOnCanvas(Canvas cv, String text, float centerX, float centerY, Paint paint, float textShadow){
if(textShadow > 0){
int c = paintText.getColor();
@ -605,18 +605,18 @@ public class OsmandRenderer {
}
cv.drawText(text, centerX, centerY, paint);
}
private boolean findTextIntersection(RenderingContext rc, List<RectF> boundsNotPathIntersect, List<RectF> boundsPathIntersect,
Comparator<RectF> c, TextDrawInfo text) {
boolean horizontalWayDisplay = (text.pathRotate > 45 && text.pathRotate < 135) || (text.pathRotate > 225 && text.pathRotate < 315);
// text.minDistance = 0;
float textWidth = paintText.measureText(text.text) + (!horizontalWayDisplay ? 0 : text.minDistance);
// Paint.ascent is negative, so negate it.
// Paint.ascent is negative, so negate it.
int ascent = (int) Math.ceil(-paintText.ascent());
int descent = (int) Math.ceil(paintText.descent());
float textHeight = ascent + descent + (horizontalWayDisplay ? 0 : text.minDistance) + getDensityValue(rc, 5);
RectF bounds = new RectF();
if(text.drawOnPath == null || horizontalWayDisplay){
bounds.set(text.centerX - textWidth / 2, text.centerY - textHeight / 2 ,
@ -661,9 +661,9 @@ public class OsmandRenderer {
st = 0;
}
// test functionality
// cv.drawRect(bounds, paint);
// cv.drawText(text.text.substring(0, Math.min(5, text.text.length())), bounds.centerX(), bounds.centerY(), paint);
// cv.drawRect(bounds, paint);
// cv.drawText(text.text.substring(0, Math.min(5, text.text.length())), bounds.centerX(), bounds.centerY(), paint);
for (int j = st; j < e; j++) {
RectF b = boundsIntersect.get(j);
float x = Math.min(bounds.right, b.right) - Math.max(b.left, bounds.left);
@ -673,21 +673,21 @@ public class OsmandRenderer {
}
}
// store in list sorted by left boundary
// if(text.minDistance > 0){
// if (verticalText) {
// bounds.set(bounds.left + text.minDistance / 2, bounds.top,
// bounds.right - text.minDistance / 2, bounds.bottom);
// } else {
// bounds.set(bounds.left, bounds.top + text.minDistance / 2, bounds.right,
// bounds.bottom - text.minDistance / 2);
// }
// }
boundsIntersect.add(index, bounds);
// if(text.minDistance > 0){
// if (verticalText) {
// bounds.set(bounds.left + text.minDistance / 2, bounds.top,
// bounds.right - text.minDistance / 2, bounds.bottom);
// } else {
// bounds.set(bounds.left, bounds.top + text.minDistance / 2, bounds.right,
// bounds.bottom - text.minDistance / 2);
// }
// }
boundsIntersect.add(index, bounds);
}
return false;
}
protected void drawObj(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, int l, boolean renderText
, int shadow, int index) {
rc.allObjects++;
@ -715,8 +715,8 @@ public class OsmandRenderer {
}
}
private PointF calcPoint(BinaryMapDataObject o, int ind, RenderingContext rc){
rc.pointCount ++;
float tx = o.getPoint31XTile(ind) / rc.tileDivisor;
@ -732,7 +732,7 @@ public class OsmandRenderer {
}
return rc.tempPoint;
}
private PointF calcMultiPolygonPoint(MultyPolygon o, int i, int b, RenderingContext rc){
rc.pointCount ++;
float tx = o.getPoint31XTile(i, b)/ rc.tileDivisor;
@ -749,16 +749,16 @@ public class OsmandRenderer {
return rc.tempPoint;
}
public void clearCachedResources(){
cachedIcons.clear();
shaders.clear();
}
private void drawMultiPolygon(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc) {
String tag = ((MultyPolygon)obj).getTag();
String value = ((MultyPolygon)obj).getValue();
@ -768,7 +768,7 @@ public class OsmandRenderer {
rc.main.emptyArea();
rc.second.emptyLine();
rc.main.color = Color.rgb(245, 245, 245);
boolean rendered = render.renderPolygon(tag, value, rc.zoom, rc, this, rc.nightMode);
if(!rendered){
return;
@ -799,18 +799,18 @@ public class OsmandRenderer {
rc.main.updatePaint(paint);
canvas.drawPath(path, paint);
// for test purpose
// rc.second.strokeWidth = 1.5f;
// rc.second.color = Color.BLACK;
// rc.second.strokeWidth = 1.5f;
// rc.second.color = Color.BLACK;
if (rc.second.strokeWidth != 0) {
rc.second.updatePaint(paint);
canvas.drawPath(path, paint);
}
}
private void drawPolygon(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair) {
if(render == null || pair == null){
return;
}
@ -821,7 +821,7 @@ public class OsmandRenderer {
rc.main.emptyArea();
rc.second.emptyLine();
// rc.main.color = Color.rgb(245, 245, 245);
boolean rendered = render.renderPolygon(pair.tag, pair.value, zoom, rc, this, rc.nightMode);
if(!rendered){
return;
@ -889,13 +889,13 @@ public class OsmandRenderer {
rc.textToDraw.add(info);
}
}
private void drawPoint(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair, boolean renderText) {
if(render == null || pair == null){
return;
}
Integer resId = render.getPointIcon(pair.tag, pair.value, rc.zoom, rc.nightMode);
String name = null;
if (renderText) {
@ -916,7 +916,7 @@ public class OsmandRenderer {
ps.x /= len;
ps.y /= len;
}
if(resId != null && resId != 0){
IconDrawInfo ico = new IconDrawInfo();
ico.x = ps.x;
@ -927,34 +927,56 @@ public class OsmandRenderer {
if (name != null) {
drawPointText(render, rc, pair, ps.x, ps.y, name);
}
}
private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int shadowRadius, int index){
// option shadow = 1 ,2 don't need any changes in first draw
// option shadow = 0 without any shadows
if(shadow == 0) paint.setShadowLayer(0, 0, 0, 0);
// option shadow = 3 with solid border
if(shadow == 3){
paint.setShadowLayer(0, 0, 0, 0);
paint.setStrokeWidth(paint.getStrokeWidth() + 2);
paint.setColor(0xffbababa);
}
canvas.drawPath(path, paint);
//check for shadow and save index in array
if(shadowRadius > 0 && shadow > 1){
if(shadownum == 0){
shadowarray[shadownum] = index;
shadownum++;
private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int shadowRadius, int index){
//if(paint.getStrokeCap() == Paint.Cap.ROUND)paint.setStrokeCap(Paint.Cap.SQUARE);
//if(paint.getStrokeCap() == Paint.Cap.ROUND)paint.setStrokeCap(Paint.Cap.BUTT);
if(paint.getPathEffect() != null){
paint.setStrokeCap(Paint.Cap.BUTT);
}
// no shadow
if(shadow == 0){
paint.setShadowLayer(0, 0, 0, 0);
canvas.drawPath(path, paint);
}
//classic ugly shadows
if(shadow == 1){
canvas.drawPath(path, paint);
}
// blurred shadows
if(shadow == 2){
if(paint.getPathEffect() == null) paint.setColor(0xffffffff);
canvas.drawPath(path, paint);
}
// option shadow = 3 with solid border
if(shadow == 3 && shadowRadius > 0){
paint.setShadowLayer(0, 0, 0, 0);
paint.setStrokeWidth(paint.getStrokeWidth() + 2);
if(paint.getPathEffect() == null) paint.setColor(0xffbababa);
canvas.drawPath(path, paint);
}
//check for shadow and save index in array
if(shadowRadius > 0 && shadow > 1){
if(shadownum == 0){
shadowarray[shadownum] = index;
shadownum++;
}
if (shadowarray[shadownum-1] != index){
shadowarray[shadownum] = index;
shadownum++;
shadowarray[shadownum] = index;
shadownum++;
}
}
}
private void drawPolyline(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair, int layer,
int shadow, int index) {
if(render == null || pair == null){
@ -975,10 +997,10 @@ private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int sh
if(rc.zoom >= 16 && "highway".equals(pair.tag) && MapRenderingTypes.isOneWayWay(obj.getHighwayAttributes())){ //$NON-NLS-1$
rc.adds = getOneWayProperties();
}
rc.visible++;
Path path = null;
float pathRotate = 0;
float roadLength = 0;
@ -989,7 +1011,7 @@ private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int sh
float yMid = 0;
PointF middlePoint = new PointF();
int middle = obj.getPointsLength() / 2;
for (int i = 0; i < length ; i++) {
PointF p = calcPoint(obj, i, rc);
if(i == 0 || i == length -1){
@ -1058,9 +1080,9 @@ private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int sh
text.fillProperties(rc, middlePoint.x, middlePoint.y);
text.pathRotate = pathRotate;
rc.textToDraw.add(text);
}
if(name != null && name.trim().length() > 0){
rc.clearText();
name = render.renderObjectText(name, pair.tag, pair.value, rc, false, rc.nightMode);
@ -1093,7 +1115,7 @@ private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int sh
}
}
}
}
}
}
@ -1112,28 +1134,28 @@ private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int sh
oneWay[0].color = 0xff6c70d5;
oneWay[0].strokeWidth = 1;
oneWay[0].pathEffect = arrowDashEffect1;
oneWay[1] = new RenderingPaintProperties();
oneWay[1].emptyLine();
oneWay[1].color = 0xff6c70d5;
oneWay[1].strokeWidth = 2;
oneWay[1].pathEffect = arrowDashEffect2;
oneWay[2] = new RenderingPaintProperties();
oneWay[2].emptyLine();
oneWay[2].color = 0xff6c70d5;
oneWay[2].strokeWidth = 3;
oneWay[2].pathEffect = arrowDashEffect3;
oneWay[3] = new RenderingPaintProperties();
oneWay[3].emptyLine();
oneWay[3].color = 0xff6c70d5;
oneWay[3].strokeWidth = 4;
oneWay[3].pathEffect = arrowDashEffect4;
}
return oneWay;
}
}