Add text size property, improve text rendering

This commit is contained in:
Victor Shcherb 2011-07-14 10:18:14 +02:00
parent d8abd5beb9
commit 5d18bbd92e
7 changed files with 207 additions and 139 deletions

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?> <?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources> <resources>
<string name="map_text_size_descr">Select text size for names on the map</string>
<string name="map_text_size">Text size</string>
<string name="trace_rendering">Rendering debug info</string> <string name="trace_rendering">Rendering debug info</string>
<string name="trace_rendering_descr">Show rendering performance data for debugging purposes</string> <string name="trace_rendering_descr">Show rendering performance data for debugging purposes</string>
<string name="tip_recent_changes">Recent changes</string> <string name="tip_recent_changes">Recent changes</string>

View file

@ -22,6 +22,7 @@
android:dialogMessage="@string/modify_transparency" android:title="@string/map_transparency" android:summary="@string/map_transparency_descr"/> android:dialogMessage="@string/modify_transparency" android:title="@string/map_transparency" android:summary="@string/map_transparency_descr"/>
<CheckBoxPreference android:summary="@string/continuous_rendering_descr" android:title="@string/continuous_rendering" <CheckBoxPreference android:summary="@string/continuous_rendering_descr" android:title="@string/continuous_rendering"
android:key="use_step_by_step_rendering" /> android:key="use_step_by_step_rendering" />
<ListPreference android:key="map_text_size" android:title="@string/map_text_size" android:summary="@string/map_text_size_descr"/>
<CheckBoxPreference android:key="use_high_res_maps" android:title="@string/use_high_res_maps" android:summary="@string/use_high_res_maps_descr"></CheckBoxPreference> <CheckBoxPreference android:key="use_high_res_maps" android:title="@string/use_high_res_maps" android:summary="@string/use_high_res_maps_descr"></CheckBoxPreference>
<CheckBoxPreference android:summary="@string/trace_rendering_descr" android:title="@string/trace_rendering" <CheckBoxPreference android:summary="@string/trace_rendering_descr" android:title="@string/trace_rendering"

View file

@ -299,6 +299,29 @@ public class OsmandSettings {
} }
private class FloatPreference extends CommonPreference<Float> {
private FloatPreference(String id, float defaultValue, boolean global) {
super(id, global, defaultValue);
}
private FloatPreference(String id, float defaultValue, boolean global, boolean cache) {
super(id, global, cache, defaultValue);
}
@Override
protected Float getValue(SharedPreferences prefs, Float defaultValue) {
return prefs.getFloat(getId(), defaultValue);
}
@Override
protected boolean setValue(SharedPreferences prefs, Float val) {
return prefs.edit().putFloat(getId(), val).commit();
}
}
private class StringPreference extends CommonPreference<String> { private class StringPreference extends CommonPreference<String> {
private StringPreference(String id, String defaultValue, boolean global) { private StringPreference(String id, String defaultValue, boolean global) {
@ -373,6 +396,10 @@ public class OsmandSettings {
public final OsmandPreference<Boolean> USE_HIGH_RES_MAPS = public final OsmandPreference<Boolean> USE_HIGH_RES_MAPS =
new BooleanPreference("use_high_res_maps", false, false, true); new BooleanPreference("use_high_res_maps", false, false, true);
// this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<Float> MAP_TEXT_SIZE =
new FloatPreference("map_text_size", 1.0f, false, true);
// this value string is synchronized with settings_pref.xml preference name // this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<Boolean> SHOW_POI_OVER_MAP = public final OsmandPreference<Boolean> SHOW_POI_OVER_MAP =

View file

@ -226,6 +226,13 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
} }
registerListPreference(osmandSettings.MAX_LEVEL_TO_DOWNLOAD_TILE, screen, entries, intValues); registerListPreference(osmandSettings.MAX_LEVEL_TO_DOWNLOAD_TILE, screen, entries, intValues);
Float[] floatValues = new Float[] {0.3f, 0.5f, 0.7f, 0.8f, 1.0f, 1.2f, 1.3f, 1.5f, 2.0f, 2.5f};
entries = new String[floatValues.length];
for (int i = 0; i < floatValues.length; i++) {
entries[i] = floatValues[i] +"";
}
registerListPreference(osmandSettings.MAP_TEXT_SIZE, screen, entries, floatValues);
startZoom = 1; startZoom = 1;
endZoom = 18; endZoom = 18;
entries = new String[endZoom - startZoom + 1]; entries = new String[endZoom - startZoom + 1];

View file

@ -385,6 +385,7 @@ public class MapRenderRepositories {
currentRenderingContext.height = (int) (requestedBox.getTileHeight() * OsmandRenderer.TILE_SIZE); currentRenderingContext.height = (int) (requestedBox.getTileHeight() * OsmandRenderer.TILE_SIZE);
currentRenderingContext.nightMode = nightMode; currentRenderingContext.nightMode = nightMode;
currentRenderingContext.highResMode = prefs.USE_HIGH_RES_MAPS.get(); currentRenderingContext.highResMode = prefs.USE_HIGH_RES_MAPS.get();
currentRenderingContext.mapTextSize = prefs.MAP_TEXT_SIZE.get();
if (checkWhetherInterrupted()) { if (checkWhetherInterrupted()) {
return; return;
} }

View file

@ -107,6 +107,7 @@ public class OsmandRenderer {
public boolean interrupted = false; public boolean interrupted = false;
public boolean nightMode = false; public boolean nightMode = false;
public boolean highResMode = false; public boolean highResMode = false;
public float mapTextSize = 1;
List<TextDrawInfo> textToDraw = new ArrayList<TextDrawInfo>(); List<TextDrawInfo> textToDraw = new ArrayList<TextDrawInfo>();
List<IconDrawInfo> iconsToDraw = new ArrayList<IconDrawInfo>(); List<IconDrawInfo> iconsToDraw = new ArrayList<IconDrawInfo>();
@ -153,6 +154,7 @@ public class OsmandRenderer {
RenderingPaintProperties[] adds = null; RenderingPaintProperties[] adds = null;
public void clearText() { public void clearText() {
showAnotherText = null; showAnotherText = null;
showTextOnPath = false; showTextOnPath = false;
@ -226,6 +228,7 @@ public class OsmandRenderer {
paintText = new TextPaint(); paintText = new TextPaint();
paintText.setStyle(Style.FILL); paintText.setStyle(Style.FILL);
paintText.setStrokeWidth(1);
paintText.setColor(Color.BLACK); paintText.setColor(Color.BLACK);
paintText.setTextAlign(Align.CENTER); paintText.setTextAlign(Align.CENTER);
paintText.setTypeface(Typeface.create("Droid Serif", Typeface.NORMAL)); //$NON-NLS-1$ paintText.setTypeface(Typeface.create("Droid Serif", Typeface.NORMAL)); //$NON-NLS-1$
@ -414,9 +417,9 @@ public class OsmandRenderer {
private float getDensityValue(RenderingContext rc, float val) { private float getDensityValue(RenderingContext rc, float val) {
if (rc.highResMode) { if (rc.highResMode) {
return val * dm.density; return val * dm.density * rc.mapTextSize;
} else { } else {
return val; return val * rc.mapTextSize;
} }
} }
@ -431,9 +434,6 @@ public class OsmandRenderer {
} }
}; };
paint.setStyle(Style.STROKE);
paint.setTextSize(10);
paint.setColor(Color.BLACK);
nextText: for (int i = 0; i < size; i++) { nextText: for (int i = 0; i < size; i++) {
TextDrawInfo text = rc.textToDraw.get(i); TextDrawInfo text = rc.textToDraw.get(i);
@ -447,27 +447,127 @@ public class OsmandRenderer {
if(useEnglishNames){ if(useEnglishNames){
text.text = Junidecode.unidecode(text.text); text.text = Junidecode.unidecode(text.text);
} }
RectF bounds = new RectF();
if(!rc.highResMode){
paintText.setTextSize(getDensityValue(rc, text.textSize)); // sest text size before finding intersection (it is used there)
} else { float textSize = getDensityValue(rc, text.textSize);
paintText.setTextSize(text.textSize); paintText.setTextSize(textSize);
}
paintText.setFakeBoldText(text.bold); paintText.setFakeBoldText(text.bold);
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);
paintText.setStyle(Style.STROKE);
paintText.setStrokeWidth(2 + text.textShadow);
cv.drawTextOnPath(text.text, text.drawOnPath, 0, text.vOffset, paintText);
// reset
paintText.setStyle(Style.FILL);
paintText.setStrokeWidth(2);
paintText.setColor(text.textColor);
}
cv.drawTextOnPath(text.text, text.drawOnPath, 0, text.vOffset, paintText);
} else {
if (text.shieldRes != 0) {
if (cachedIcons.get(text.shieldRes) == null) {
cachedIcons.put(text.shieldRes, BitmapFactory.decodeResource(context.getResources(), text.shieldRes));
}
Bitmap ico = cachedIcons.get(text.shieldRes);
if (ico != null) {
cv.drawBitmap(ico, text.centerX - ico.getWidth() / 2 - 0.5f, text.centerY
- ico.getHeight() / 2 - getDensityValue(rc, 4.5f)
, paintIcon);
}
}
drawWrappedText(cv, text, textSize);
}
}
}
}
private void drawWrappedText(Canvas cv, TextDrawInfo text, float textSize) {
if(text.textWrap == 0){
// set maximum for all text
text.textWrap = 40;
}
if(text.text.length() > text.textWrap){
int start = 0;
int end = text.text.length();
int lastSpace = -1;
int line = 0;
int pos = 0;
int limit = 0;
while(pos < end){
lastSpace = -1;
limit += text.textWrap;
while(pos < limit && pos < end){
if(!Character.isLetterOrDigit(text.text.charAt(pos))){
lastSpace = pos;
}
pos++;
}
if(lastSpace == -1){
drawTextOnCanvas(cv, text.text.substring(start, pos),
text.centerX, text.centerY + line * (textSize + 2), paintText, text.textShadow);
start = pos;
} else {
drawTextOnCanvas(cv, text.text.substring(start, lastSpace),
text.centerX, text.centerY + line * (textSize + 2), paintText, text.textShadow);
start = lastSpace + 1;
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();
paintText.setStyle(Style.STROKE);
paintText.setColor(Color.WHITE);
paintText.setStrokeWidth(2 + textShadow);
cv.drawText(text, centerX, centerY, paint);
cv.drawText(text, centerX, centerY, paint);
// reset
paintText.setStrokeWidth(2);
paintText.setStyle(Style.FILL);
paintText.setColor(c);
}
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); boolean horizontalWayDisplay = (text.pathRotate > 45 && text.pathRotate < 135) || (text.pathRotate > 225 && text.pathRotate < 315);
float mes = paintText.measureText(text.text) + (!horizontalWayDisplay ? 0 : text.minDistance); 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 ascent = (int) Math.ceil(-paintText.ascent());
int descent = (int) Math.ceil(paintText.descent()); int descent = (int) Math.ceil(paintText.descent());
float textHeight = ascent + descent + (horizontalWayDisplay ? 0 : text.minDistance) + getDensityValue(rc, 5); float textHeight = ascent + descent + (horizontalWayDisplay ? 0 : text.minDistance) + getDensityValue(rc, 5);
RectF bounds = new RectF();
if(text.drawOnPath == null || horizontalWayDisplay){ if(text.drawOnPath == null || horizontalWayDisplay){
bounds.set(text.centerX - mes / 2, text.centerY - textHeight / 2 , bounds.set(text.centerX - textWidth / 2, text.centerY - textHeight / 2 ,
text.centerX + mes / 2 , text.centerY + textHeight / 2 ); text.centerX + textWidth / 2 , text.centerY + textHeight / 2 );
} else { } else {
bounds.set(text.centerX - textHeight / 2, text.centerY - mes / 2, bounds.set(text.centerX - textHeight / 2, text.centerY - textWidth / 2,
text.centerX + textHeight / 2 , text.centerY + mes / 2); text.centerX + textHeight / 2 , text.centerY + textWidth / 2);
} }
List<RectF> boundsIntersect = text.drawOnPath == null || findAllTextIntersections? List<RectF> boundsIntersect = text.drawOnPath == null || findAllTextIntersections?
boundsNotPathIntersect : boundsPathIntersect; boundsNotPathIntersect : boundsPathIntersect;
@ -513,7 +613,7 @@ public class OsmandRenderer {
float x = Math.min(bounds.right, b.right) - Math.max(b.left, bounds.left); float x = Math.min(bounds.right, b.right) - Math.max(b.left, bounds.left);
float y = Math.min(bounds.bottom, b.bottom) - Math.max(b.top, bounds.top); float y = Math.min(bounds.bottom, b.bottom) - Math.max(b.top, bounds.top);
if ((x > diff && y > diff2) || (x > diff2 && y > diff)) { if ((x > diff && y > diff2) || (x > diff2 && y > diff)) {
continue nextText; return true;
} }
} }
// store in list sorted by left boundary // store in list sorted by left boundary
@ -528,77 +628,7 @@ public class OsmandRenderer {
// } // }
boundsIntersect.add(index, bounds); boundsIntersect.add(index, bounds);
} }
return false;
// Shadow layer
// paintText.setShadowLayer(text.textShadow, 0, 0, Color.WHITE);
// if(text.textShadow > 0){
// paintText.setColor(Color.WHITE);
// paintText.setTextSize(text.textSize + text.textShadow * 2);
// if(text.drawOnPath != null){
// cv.drawTextOnPath(text.text, text.drawOnPath, 0, text.vOffset, paintText);
// } else {
// cv.drawText(text.text, text.centerX, text.centerY, paintText);
// }
// paintText.setTextSize(text.textSize);
// }
paintText.setColor(text.textColor);
if(text.drawOnPath != null){
cv.drawTextOnPath(text.text, text.drawOnPath, 0, text.vOffset, paintText);
} else {
if(text.textWrap == 0){
// set maximum for all text
text.textWrap = 40;
}
if(text.shieldRes != 0){
if(cachedIcons.get(text.shieldRes) == null){
cachedIcons.put(text.shieldRes, BitmapFactory.decodeResource(context.getResources(), text.shieldRes));
}
Bitmap ico = cachedIcons.get(text.shieldRes);
if (ico != null) {
cv.drawBitmap(ico, text.centerX - ico.getWidth() / 2 - getDensityValue(rc, 0.5f),
text.centerY - text.textSize / 2 - getDensityValue(rc, 6.5f),
paintIcon);
}
}
if(text.text.length() > text.textWrap){
int start = 0;
int end = text.text.length();
int lastSpace = -1;
int line = 0;
int pos = 0;
int limit = 0;
while(pos < end){
lastSpace = -1;
limit += text.textWrap;
while(pos < limit && pos < end){
if(!Character.isLetterOrDigit(text.text.charAt(pos))){
lastSpace = pos;
}
pos++;
}
if(lastSpace == -1){
cv.drawText(text.text.substring(start, pos),
text.centerX, text.centerY + line * (text.textSize + 2), paintText);
start = pos;
} else {
cv.drawText(text.text.substring(start, lastSpace),
text.centerX, text.centerY + line * (text.textSize + 2), paintText);
start = lastSpace + 1;
limit += (start - pos) - 1;
}
line++;
}
} else {
cv.drawText(text.text, text.centerX, text.centerY, paintText);
}
}
}
}
} }