add more labels as they fit at current scale

This commit is contained in:
Hannes Janetzek 2013-01-17 12:03:04 +01:00
parent 5c36b204ce
commit 3c990b3289
3 changed files with 168 additions and 146 deletions

View File

@ -14,9 +14,9 @@
*/ */
package org.oscim.renderer; package org.oscim.renderer;
import org.oscim.core.Tile;
import org.oscim.renderer.layer.TextItem; import org.oscim.renderer.layer.TextItem;
import org.oscim.theme.renderinstruction.Text; import org.oscim.theme.renderinstruction.Text;
import org.oscim.utils.GeometryUtils;
public final class WayDecorator { public final class WayDecorator {
// /** // /**
@ -27,7 +27,7 @@ public final class WayDecorator {
// /** // /**
// * Minimum distance in pixels before the way name is repeated. // * Minimum distance in pixels before the way name is repeated.
// */ // */
// private static final int DISTANCE_BETWEEN_WAY_NAMES = 500; private static final int DISTANCE_BETWEEN_WAY_NAMES = 100;
// /** // /**
// * Distance in pixels to skip from both ends of a segment. // * Distance in pixels to skip from both ends of a segment.
@ -104,95 +104,118 @@ public final class WayDecorator {
TextItem t = null; TextItem t = null;
// calculate the way name length plus some margin of safety // calculate the way name length plus some margin of safety
float wayNameWidth = -1; float wayNameWidth = -1;
float minWidth = 100; float minWidth = Tile.TILE_SIZE / 10;
int skipPixels = 0; int skipPixels = 0;
// get the first way point coordinates // get the first way point coordinates
int previousX = (int) coordinates[pos + 0]; int prevX = (int) coordinates[pos + 0];
int previousY = (int) coordinates[pos + 1]; int prevY = (int) coordinates[pos + 1];
if (string.equals("Filip Road")) {
System.out.println("blub");
}
// find way segments long enough to draw the way name on them // find way segments long enough to draw the way name on them
for (int i = pos + 2; i < pos + len; i += 2) { for (int i = pos + 2; i < pos + len; i += 2) {
// get the current way point coordinates // get the current way point coordinates
int currentX = (int) coordinates[i]; int curX = (int) coordinates[i];
int currentY = (int) coordinates[i + 1]; int curY = (int) coordinates[i + 1];
// calculate the length of the current segment (Euclidian distance) // calculate the length of the current segment (Euclidian distance)
float diffX = currentX - previousX; float vx = prevX - curX;
float diffY = currentY - previousY; float vy = prevY - curY;
float a = (float) Math.sqrt(vx * vx + vy * vy);
vx /= a;
vy /= a;
for (int j = i + 2; j < pos + len; j += 2) { int last = i;
int nextX = (int) coordinates[j]; int nextX = 0, nextY = 0;
int nextY = (int) coordinates[j + 1];
if (diffY == 0) { // add additional segments if possible
if ((currentY - nextY) != 0) for (int j = last + 2; j < pos + len; j += 2) {
nextX = (int) coordinates[j];
nextY = (int) coordinates[j + 1];
float wx = curX - nextX;
float wy = curY - nextY;
a = (float) Math.sqrt(wx * wx + wy * wy);
wx /= a;
wy /= a;
float ux = vx + wx;
float uy = vy + wy;
float diff = wx * uy - wy * ux;
if (diff > 0.1 || diff < -0.1)
break; break;
currentX = nextX; last = j;
currentY = nextY; curX = nextX;
continue; curY = nextY;
} else if ((currentY - nextY) == 0)
break;
float diff = diffX / diffY -
(float) (currentX - nextX) / (currentY - nextY);
// skip segments with corners
if (diff >= 0.1f || diff <= -0.1f)
break;
currentX = nextX;
currentY = nextY;
}
diffX = currentX - previousX;
diffY = currentY - previousY;
if (diffX < 0)
diffX = -diffX;
if (diffY < 0)
diffY = -diffY;
if (diffX + diffY < minWidth) {
previousX = currentX;
previousY = currentY;
continue; continue;
} }
if (wayNameWidth > 0 && diffX + diffY < wayNameWidth) { vx = curX - prevX;
previousX = currentX; vy = curY - prevY;
previousY = currentY;
if (vx < 0)
vx = -vx;
if (vy < 0)
vy = -vy;
// minimum segment to label
if (vx + vy < minWidth) {
// restart from next node
prevX = (int) coordinates[i];
prevY = (int) coordinates[i + 1];
continue; continue;
} }
double segmentLengthInPixel = Math.sqrt(diffX * diffX + diffY * diffY); // compare against max segment length
if (wayNameWidth > 0 && vx + vy < wayNameWidth) {
// restart from next node
prevX = (int) coordinates[i];
prevY = (int) coordinates[i + 1];
continue;
}
double segmentLength = Math.sqrt(vx * vx + vy * vy);
if (skipPixels > 0) { if (skipPixels > 0) {
skipPixels -= segmentLengthInPixel; skipPixels -= segmentLength;
} else if (segmentLengthInPixel > minWidth) { } else if (segmentLength < minWidth) {
// restart from next node
prevX = (int) coordinates[i];
prevY = (int) coordinates[i + 1];
continue;
}
if (wayNameWidth < 0) { if (wayNameWidth < 0) {
wayNameWidth = text.paint.measureText(string); wayNameWidth = text.paint.measureText(string);
} }
if (segmentLengthInPixel > wayNameWidth * 0.80) { if (segmentLength < wayNameWidth * 0.50) {
// restart from next node
prevX = (int) coordinates[i];
prevY = (int) coordinates[i + 1];
continue;
}
float s = (wayNameWidth + 25) / (float) segmentLengthInPixel; float s = wayNameWidth / (float) segmentLength;
int width, height; int width, height;
int x1, y1, x2, y2; int x1, y1, x2, y2;
if (previousX < currentX) { if (prevX < curX) {
x1 = previousX; x1 = prevX;
y1 = previousY; y1 = prevY;
x2 = currentX; x2 = curX;
y2 = currentY; y2 = curY;
} else { } else {
x1 = currentX; x1 = curX;
y1 = currentY; y1 = curY;
x2 = previousX; x2 = prevX;
y2 = previousY; y2 = prevY;
} }
// estimate position of text on path // estimate position of text on path
@ -204,47 +227,41 @@ public final class WayDecorator {
y2 = y2 - (int) (height - s * height); y2 = y2 - (int) (height - s * height);
y1 = y1 + (int) (height - s * height); y1 = y1 + (int) (height - s * height);
short top = (short) (y1 < y2 ? y1 : y2); // short top = (short) (y1 < y2 ? y1 : y2);
short bot = (short) (y1 < y2 ? y2 : y1); // short bot = (short) (y1 < y2 ? y2 : y1);
// boolean intersects = false;
//
// for (TextItem t2 = items; t2 != null; t2 = t2.next) {
//
// // check crossings
// if (GeometryUtils.lineIntersect(x1, y1, x2, y2, t2.x1, t2.y1,
// t2.x2, t2.y2)) {
// intersects = true;
// break;
// }
//
// // check overlapping labels of road with more than one
// // way
// short top2 = t2.y1 < t2.y2 ? t2.y1 : t2.y2;
// short bot2 = t2.y1 < t2.y2 ? t2.y2 : t2.y1;
//
// if (x1 - 10 < t2.x2 && t2.x1 - 10 < x2 && top - 10 < bot2
// && top2 - 10 < bot) {
//
// if (t2.string.equals(string)) {
// intersects = true;
// break;
// }
// }
// }
//
// if (intersects) {
// previousX = (int) coordinates[pos + i];
// previousY = (int) coordinates[pos + i + 1];
// continue;
// }
boolean intersects = false;
for (TextItem t2 = items; t2 != null; t2 = t2.next) {
// check crossings
if (GeometryUtils.lineIntersect(x1, y1, x2, y2, t2.x1, t2.y1,
t2.x2, t2.y2)) {
intersects = true;
break;
}
// check overlapping labels of road with more than one
// way
short top2 = t2.y1 < t2.y2 ? t2.y1 : t2.y2;
short bot2 = t2.y1 < t2.y2 ? t2.y2 : t2.y1;
if (x1 - 10 < t2.x2 && t2.x1 - 10 < x2 && top - 10 < bot2
&& top2 - 10 < bot) {
if (t2.string.equals(string)) {
intersects = true;
break;
}
}
}
if (intersects) {
previousX = (int) coordinates[pos + i];
previousY = (int) coordinates[pos + i + 1];
continue;
}
// if (t == null)
t = TextItem.get(); t = TextItem.get();
// t = new TextItem(x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2,
// string,
// text, wayNameWidth);
t.x = x1 + (x2 - x1) / 2f; t.x = x1 + (x2 - x1) / 2f;
t.y = y1 + (y2 - y1) / 2f; t.y = y1 + (y2 - y1) / 2f;
t.string = string; t.string = string;
@ -254,19 +271,18 @@ public final class WayDecorator {
t.y1 = (short) y1; t.y1 = (short) y1;
t.x2 = (short) x2; t.x2 = (short) x2;
t.y2 = (short) y2; t.y2 = (short) y2;
t.length = (short) segmentLength;
t.next = items; t.next = items;
items = t; items = t;
// skipPixels = DISTANCE_BETWEEN_WAY_NAMES; skipPixels = DISTANCE_BETWEEN_WAY_NAMES;
return items;
}
}
// skip to last
i = last;
// store the previous way point coordinates // store the previous way point coordinates
previousX = currentX; prevX = curX;
previousY = currentY; prevY = curY;
} }
return items; return items;
} }

View File

@ -84,6 +84,6 @@ public class TextItem {
public Text text; public Text text;
public float width; public float width;
public short x1, y1, x2, y2; public short x1, y1, x2, y2;
public short length;
// public byte placement // public byte placement
} }

View File

@ -138,14 +138,13 @@ public class TextOverlay extends RenderOverlay {
for (TextItem ti = t.labels; ti != null; ti = ti.next) { for (TextItem ti = t.labels; ti != null; ti = ti.next) {
if (ti2 == null)
ti2 = TextItem.get();
ti2.move(ti, dx, dy, scale);
boolean overlaps = false; boolean overlaps = false;
if (ti.text.caption) { if (ti.text.caption) {
if (ti2 == null)
ti2 = TextItem.get();
ti2.move(ti, dx, dy, scale);
int tx = (int) (ti2.x); int tx = (int) (ti2.x);
int ty = (int) (ti2.y); int ty = (int) (ti2.y);
int tw = (int) (ti2.width / 2); int tw = (int) (ti2.width / 2);
@ -169,6 +168,13 @@ public class TextOverlay extends RenderOverlay {
} }
} else { } else {
if (ti.width > ti.length * scale) {
continue;
}
if (ti2 == null)
ti2 = TextItem.get();
ti2.move(ti, dx, dy, scale);
if (cos * (ti.x2 - ti.x1) - sin * (ti.y2 - ti.y1) < 0) { if (cos * (ti.x2 - ti.x1) - sin * (ti.y2 - ti.y1) < 0) {
// flip label upside-down // flip label upside-down
ti2.x1 = (short) ((ti.x2 * scale + dx)); ti2.x1 = (short) ((ti.x2 * scale + dx));